diff --git a/src/collections/InstructorClientTenantRelations/index.ts b/src/collections/InstructorClientTenantRelations/index.ts new file mode 100644 index 0000000..03cb335 --- /dev/null +++ b/src/collections/InstructorClientTenantRelations/index.ts @@ -0,0 +1,31 @@ +import { CollectionConfig } from "payload"; + +export const InstructorClientTenantRelations: CollectionConfig = { + slug: 'instructorClientTenantRelations', + fields: [ + { + name: 'displayName', + type: 'text', + }, + { + name: 'instructor', + type: 'relationship', + relationTo: 'users', + hasMany: false, + }, + { + name: 'client', + type: 'relationship', + relationTo: 'users', + hasMany: false, + }, + { + name: 'tenant', + type: 'relationship', + relationTo: 'tenants', + hasMany: false, + } + ] +} + +export default InstructorClientTenantRelations diff --git a/src/collections/Users/access/read.ts b/src/collections/Users/access/read.ts index 14ca302..203150c 100644 --- a/src/collections/Users/access/read.ts +++ b/src/collections/Users/access/read.ts @@ -17,6 +17,8 @@ export const readAccess: Access = ({ req, id }) => { } const superAdmin = isSuperAdmin(req.user) + if (superAdmin) return true; + const selectedTenant = getTenantFromCookie( req.headers, getCollectionIDType({ payload: req.payload, collectionSlug: 'tenants' }), @@ -35,10 +37,6 @@ export const readAccess: Access = ({ req, id }) => { } } - if (superAdmin) { - return true - } - return { or: [ { diff --git a/src/collections/Users/index.ts b/src/collections/Users/index.ts index ef1e11c..7e0cbf7 100644 --- a/src/collections/Users/index.ts +++ b/src/collections/Users/index.ts @@ -28,7 +28,7 @@ const defaultTenantArrayField = tenantsArrayField({ { name: 'roles', type: 'select', - defaultValue: ['tenant-viewer'], + defaultValue: ['tenant-client'], hasMany: true, options: ['tenant-admin', 'tenant-client', 'tenant-instructor'], required: true, @@ -76,12 +76,6 @@ export const Users: CollectionConfig = { }, index: true, }, - { - name: 'accessLevel', - type: 'number', - max: UserAccessLevel.FULL_ACCESS, - defaultValue: UserAccessLevel.GUEST, - }, { ...defaultTenantArrayField, admin: { @@ -89,6 +83,18 @@ export const Users: CollectionConfig = { position: 'sidebar', }, }, + { + name: 'clients', + type: 'join', + collection: 'instructorClientTenantRelations', + on: 'instructor', + admin: { + condition: (data) => { + const tenantRoles = data.tenants?.flatMap((t: any) => t.roles) + return tenantRoles.includes('tenant-instructor') + } + }, + } ], timestamps: true, hooks: { diff --git a/src/payload-types.ts b/src/payload-types.ts index bb17c39..62677bd 100644 --- a/src/payload-types.ts +++ b/src/payload-types.ts @@ -86,6 +86,7 @@ export interface Config { habbits: Habbit; habbitEntries: HabbitEntry; schedules: Schedule; + instructorClientTenantRelations: InstructorClientTenantRelation; redirects: Redirect; forms: Form; 'form-submissions': FormSubmission; @@ -95,7 +96,11 @@ export interface Config { 'payload-preferences': PayloadPreference; 'payload-migrations': PayloadMigration; }; - collectionsJoins: {}; + collectionsJoins: { + users: { + clients: 'instructorClientTenantRelations'; + }; + }; collectionsSelect: { pages: PagesSelect | PagesSelect; posts: PostsSelect | PostsSelect; @@ -116,6 +121,7 @@ export interface Config { habbits: HabbitsSelect | HabbitsSelect; habbitEntries: HabbitEntriesSelect | HabbitEntriesSelect; schedules: SchedulesSelect | SchedulesSelect; + instructorClientTenantRelations: InstructorClientTenantRelationsSelect | InstructorClientTenantRelationsSelect; redirects: RedirectsSelect | RedirectsSelect; forms: FormsSelect | FormsSelect; 'form-submissions': FormSubmissionsSelect | FormSubmissionsSelect; @@ -426,7 +432,6 @@ export interface User { id: number; roles?: ('full-access' | 'super-admin' | 'user' | 'guest')[] | null; username?: string | null; - accessLevel?: number | null; tenants?: | { tenant: number | Tenant; @@ -434,6 +439,11 @@ export interface User { id?: string | null; }[] | null; + clients?: { + docs?: (number | InstructorClientTenantRelation)[]; + hasNextPage?: boolean; + totalDocs?: number; + }; updatedAt: string; createdAt: string; email: string; @@ -445,6 +455,19 @@ export interface User { lockUntil?: string | null; password?: string | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "instructorClientTenantRelations". + */ +export interface InstructorClientTenantRelation { + id: number; + displayName?: string | null; + instructor?: (number | null) | User; + client?: (number | null) | User; + tenant?: (number | null) | Tenant; + updatedAt: string; + createdAt: string; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "CallToActionBlock". @@ -1434,6 +1457,10 @@ export interface PayloadLockedDocument { relationTo: 'schedules'; value: number | Schedule; } | null) + | ({ + relationTo: 'instructorClientTenantRelations'; + value: number | InstructorClientTenantRelation; + } | null) | ({ relationTo: 'redirects'; value: number | Redirect; @@ -1783,7 +1810,6 @@ export interface CategoriesSelect { export interface UsersSelect { roles?: T; username?: T; - accessLevel?: T; tenants?: | T | { @@ -1791,6 +1817,7 @@ export interface UsersSelect { roles?: T; id?: T; }; + clients?: T; updatedAt?: T; createdAt?: T; email?: T; @@ -2030,6 +2057,18 @@ export interface SchedulesSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "instructorClientTenantRelations_select". + */ +export interface InstructorClientTenantRelationsSelect { + displayName?: T; + instructor?: T; + client?: T; + tenant?: T; + updatedAt?: T; + createdAt?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "redirects_select". diff --git a/src/payload.config.ts b/src/payload.config.ts index 5e8b204..76be74d 100644 --- a/src/payload.config.ts +++ b/src/payload.config.ts @@ -24,6 +24,7 @@ import { HabbitCategories } from './collections/Habbits/HabbitCategories' import { Habbits } from './collections/Habbits/Habbits' import { HabbitEntries } from './collections/Habbits/HabbitEntry' import { Schedules } from './collections/Schedules' +import InstructorClientTenantRelations from './collections/InstructorClientTenantRelations' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -72,7 +73,7 @@ export default buildConfig({ connectionString: process.env.DATABASE_URI || '', }, }), - collections: [Pages, Posts, Media, Categories, Users, Tenants, Exercises, ExerciseTypes, MuscleGroups, Equipments, Workouts, WorkoutTypes, Ingredients, MealItems, Meals, HabbitCategories, Habbits, HabbitEntries, Schedules], + collections: [Pages, Posts, Media, Categories, Users, Tenants, Exercises, ExerciseTypes, MuscleGroups, Equipments, Workouts, WorkoutTypes, Ingredients, MealItems, Meals, HabbitCategories, Habbits, HabbitEntries, Schedules, InstructorClientTenantRelations], cors: [getServerSideURL()].filter(Boolean), globals: [Header, Footer], plugins: [ diff --git a/src/plugins/index.ts b/src/plugins/index.ts index 39b3b68..033772b 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -14,7 +14,6 @@ import { beforeSyncWithSearch } from '@/search/beforeSync' import { Config, Page, Post, User } from '@/payload-types' import { getServerSideURL } from '@/utilities/getURL' -import { UserAccessLevel } from '@/collections/Users' import { isSuperAdmin } from '@/access/isSuperAdmin' import { getUserTenantIDs } from '@/utilities/getUserTenantIds' @@ -117,7 +116,7 @@ export const plugins: Plugin[] = [ tenantsArrayField: { includeDefaultField: false, }, - userHasAccessToAllTenants: (user: User) => (user.accessLevel || 0) >= UserAccessLevel.SUPER_ADMIN, + userHasAccessToAllTenants: (user: User) => isSuperAdmin(user), tenantField: { access: { read: () => true, @@ -127,7 +126,6 @@ export const plugins: Plugin[] = [ } return getUserTenantIDs(req.user).length > 0 }, - create: () => true, }, }, }),