Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide related fields without read permissions #16832

Merged
merged 14 commits into from Feb 24, 2023
123 changes: 123 additions & 0 deletions app/src/composables/use-permissions.test.ts
@@ -0,0 +1,123 @@
import { createTestingPinia } from '@pinia/testing';
import { setActivePinia } from 'pinia';
import { ref } from 'vue';
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';

beforeEach(() => {
setActivePinia(
createTestingPinia({
createSpy: vi.fn,
stubActions: false,
})
);
});

import { useUserStore } from '@/stores/user';
import { usePermissionsStore } from '@/stores/permissions';
import { usePermissions } from './use-permissions';
import { useCollection } from '@directus/shared/composables';
import { Field } from '@directus/shared/types';

vi.mock('@directus/shared/composables');

const mockUser = {
id: '00000000-0000-0000-0000-000000000000',
role: {
admin_access: false,
id: '00000000-0000-0000-0000-000000000000',
},
};
const mockReadPermissions = {
role: '00000000-0000-0000-0000-000000000000',
permissions: {
_and: [
{
field_a: {
_null: true,
},
},
{
field_b: {
_null: true,
},
},
],
},
validation: null,
presets: null,
fields: ['id', 'start_date', 'end_date'],
collection: 'test',
action: 'read',
};
const mockFields: Field[] = [
{
collection: 'test',
field: 'id',
name: 'id',
type: 'integer',
schema: null,
meta: null,
},
{
collection: 'test',
field: 'name',
name: 'name',
type: 'string',
schema: null,
meta: null,
},
{
collection: 'test',
field: 'start_date',
name: 'start_date',
type: 'timestamp',
schema: null,
meta: null,
},
{
collection: 'test',
field: 'end_date',
name: 'end_date',
type: 'timestamp',
schema: null,
meta: null,
},
];

vi.mock('@/api', () => {
return {
default: {
get: (path: string) => {
if (path === '/permissions') {
return Promise.resolve({
data: { data: [mockReadPermissions] },
});
}

return Promise.reject(new Error(`GET "${path}" is not mocked in this test`));
},
},
};
});

afterEach(() => {
vi.restoreAllMocks();
});

describe('usePermissions', () => {
test('Remove fields without read permissions #16732', async () => {
const userStore = useUserStore();
userStore.currentUser = mockUser as any;

const permissionsStore = usePermissionsStore();
await permissionsStore.hydrate();

vi.mocked(useCollection).mockReturnValue({ info: ref(null), fields: ref(mockFields) } as any);

const { fields } = usePermissions(ref('test'), ref(null), ref(false));
expect(fields.value.length).toBeGreaterThan(0);
for (const field of fields.value) {
expect(mockReadPermissions.fields.includes(field.field)).toBe(true);
}
});
});
6 changes: 6 additions & 0 deletions app/src/composables/use-permissions.ts
Expand Up @@ -59,6 +59,12 @@ export function usePermissions(collection: Ref<string>, item: Ref<any>, isNew: R

const permissions = permissionsStore.getPermissionsForUser(collection.value, isNew.value ? 'create' : 'update');

// remove fields without read permissions so they don't show up in the DOM
const readableFields = permissionsStore.getPermissionsForUser(collection.value, 'read')?.fields;
if (readableFields && readableFields.includes('*') === false) {
fields = fields.filter((field) => readableFields.includes(field.field));
}

if (!permissions) return fields;

if (permissions.fields?.includes('*') === false) {
Expand Down