feature: new collections

This commit is contained in:
Benno Tielen 2024-08-23 16:20:50 +02:00
parent 66f9e07111
commit f645c01ac0
12 changed files with 626 additions and 108 deletions

View file

@ -1,4 +1,5 @@
import { CollectionConfig } from 'payload' import { CollectionConfig } from 'payload'
import { isAdminOrEmployee } from '@/collections/access/admin'
export const Churches: CollectionConfig = { export const Churches: CollectionConfig = {
slug: 'church', slug: 'church',
@ -33,5 +34,8 @@ export const Churches: CollectionConfig = {
}, },
access: { access: {
read: () => true, read: () => true,
create: isAdminOrEmployee(),
update: isAdminOrEmployee(),
delete: isAdminOrEmployee(),
}, },
} }

View file

@ -0,0 +1,62 @@
import { CollectionConfig } from 'payload'
import { isAdminOrEmployee } from '@/collections/access/admin'
export const Employees: CollectionConfig = {
slug: 'employees',
labels: {
singular: {
de: 'Mitarbeiter',
},
plural: 'Mitarbeiter',
},
fields: [
{
name: 'photo',
label: {
de: 'Foto',
},
type: 'upload',
relationTo: 'media',
},
{
name: 'name',
type: 'text',
label: {
de: 'Name',
},
required: true,
},
{
name: 'occupation',
type: 'text',
label: {
de: 'Tätigkeit',
},
required: true,
},
{
name: 'email',
type: 'email',
label: {
de: 'Email',
},
},
{
name: 'telephone',
type: 'text',
label: {
de: 'Telefon',
},
required: false,
},
],
admin: {
useAsTitle: 'name',
},
access: {
read: () => true,
create: isAdminOrEmployee(),
update: isAdminOrEmployee(),
delete: isAdminOrEmployee(),
},
}

122
src/collections/Events.ts Normal file
View file

@ -0,0 +1,122 @@
import { CollectionConfig } from 'payload'
import { isAdminOrEmployee } from '@/collections/access/admin'
export const Events: CollectionConfig = {
slug: 'event',
labels: {
singular: {
de: 'Veranstaltung',
},
plural: {
de: 'Veranstaltungen',
},
},
fields: [
{
name: 'photo',
label: {
de: 'Foto',
},
type: 'upload',
relationTo: 'media',
},
{
name: 'title',
type: 'text',
required: true,
label: {
de: 'Titel',
},
},
{
name: 'datum',
type: 'date',
required: true,
label: {
de: 'Datum',
},
admin: {
date: {
pickerAppearance: 'dayAndTime',
},
},
},
{
name: 'parish',
type: 'relationship',
relationTo: 'parish',
hasMany: true,
label: {
de: 'Gemeinde',
},
validate: (value, options) => {
let user = options.req.user
if (!user) {
return 'You are not allowed to do this'
}
if (user.roles === 'user' && value) {
return 'Sie sind nur erlaubt Veranstaltungen für Gruppen zu erstellen.'
}
return true
},
},
{
name: 'group',
type: 'relationship',
relationTo: 'group',
label: {
de: 'Gruppe',
},
validate: (value, options) => {
let user = options.req.user
if (!user) {
return 'You are not allowed to do this'
}
if (user.roles === 'user') {
if (!user.groups || (user.groups && !user.groups.includes(value))) {
return 'Sie können nur Veranstaltungen für Ihre eigene Gruppen erstellen!'
}
}
return true
},
},
{
name: 'shortDescription',
type: 'textarea',
required: true,
label: {
de: 'Kurzumschreibung',
},
},
{
name: 'description',
type: 'richText',
required: true,
label: {
de: 'Umschreibung',
},
},
{
name: 'cancelled',
type: 'checkbox',
required: true,
label: {
de: 'Abgesagt',
},
defaultValue: false,
},
],
admin: {
useAsTitle: 'title',
},
access: {
read: () => true,
delete: isAdminOrEmployee(),
},
}

66
src/collections/Groups.ts Normal file
View file

@ -0,0 +1,66 @@
import { CollectionConfig } from 'payload'
import { isAdminOrEmployee } from '@/collections/access/admin'
export const Groups: CollectionConfig = {
slug: 'group',
labels: {
singular: {
de: 'Gruppe',
},
plural: {
de: 'Gruppen',
},
},
fields: [
{
name: 'photo',
label: {
de: 'Foto',
},
type: 'upload',
relationTo: 'media',
},
{
name: 'name',
type: 'text',
label: {
de: 'Name',
},
required: true,
},
{
name: 'description',
type: 'textarea',
label: {
de: 'Umschreibung',
},
required: true,
},
],
admin: {
useAsTitle: 'name',
},
access: {
read: () => true,
create: isAdminOrEmployee(),
update: ({ req, id }) => {
if (!req.user) {
return false
}
if (
req.user.roles === 'user' &&
id &&
req.user.groups?.find(
(group) =>
group === id || (typeof group === 'object' && group.id === id),
) === undefined
) {
return false
}
return true
},
delete: isAdminOrEmployee(),
},
}

91
src/collections/Parish.ts Normal file
View file

@ -0,0 +1,91 @@
import { CollectionConfig } from 'payload'
import { isAdmin, isAdminOrEmployee } from '@/collections/access/admin'
export const Parish: CollectionConfig = {
slug: 'parish',
labels: {
singular: {
de: 'Gemeinde',
},
plural: {
de: 'Gemeinden',
},
},
fields: [
{
name: 'name',
label: {
de: 'Name',
},
type: 'text',
required: true,
},
{
name: 'churches',
label: {
de: 'Kirchengebäuden',
},
type: 'relationship',
relationTo: 'church',
hasMany: true,
required: true,
admin: {
allowCreate: false,
},
},
{
name: 'employees',
label: {
de: 'Mitarbeiter',
},
type: 'relationship',
relationTo: 'employees',
hasMany: true,
required: true,
},
{
name: 'contact',
label: {
de: 'Kontaktinformation',
},
type: 'textarea',
required: true,
admin: {
rows: 10,
},
},
{
name: 'title',
label: {
de: 'Titel',
},
type: 'text',
required: true,
},
{
name: 'description',
label: {
de: 'Umschreibung',
},
type: 'textarea',
required: true,
admin: {
rows: 15,
},
},
{
name: 'photo',
type: 'upload',
relationTo: 'media',
},
],
admin: {
useAsTitle: 'name',
},
access: {
read: () => true,
create: isAdmin(),
update: isAdminOrEmployee(),
delete: isAdmin(),
},
}

View file

@ -1,4 +1,5 @@
import { CollectionConfig } from 'payload' import { CollectionConfig } from 'payload'
import { isAdminOrEmployee } from '@/collections/access/admin'
export const Testimony: CollectionConfig = { export const Testimony: CollectionConfig = {
slug: 'testimony', slug: 'testimony',
@ -52,5 +53,8 @@ export const Testimony: CollectionConfig = {
], ],
access: { access: {
read: () => true, read: () => true,
create: isAdminOrEmployee(),
update: isAdminOrEmployee(),
delete: isAdminOrEmployee(),
}, },
} }

View file

@ -1,4 +1,5 @@
import type { CollectionConfig } from 'payload' import type { CollectionConfig } from 'payload'
import { isAdminOrEmployee } from '@/collections/access/admin'
export const Users: CollectionConfig = { export const Users: CollectionConfig = {
slug: 'users', slug: 'users',
@ -7,7 +8,61 @@ export const Users: CollectionConfig = {
}, },
auth: true, auth: true,
fields: [ fields: [
// Email added by default {
// Add more fields as needed name: 'name',
label: {
de: 'Name',
},
type: 'text',
required: true,
defaultValue: '',
},
{
name: 'roles',
label: {
de: 'Rolle',
},
type: 'select',
required: true,
options: [
{
value: 'user',
label: 'Gläubiger',
},
{
value: 'employee',
label: 'Mitarbeiter',
},
{
value: 'admin',
label: 'Administrator',
},
], ],
defaultValue: 'user',
access: {
// Do not allow to upgrade role
create: ({ req, data }) => {
return !(req.user?.roles !== 'admin' && data?.roles === 'admin')
},
update: ({ req, data }) => {
return !(req.user?.roles !== 'admin' && data?.roles === 'admin')
},
},
},
{
name: 'groups',
label: {
de: 'Mitgliedschaft',
},
type: 'relationship',
relationTo: 'group',
hasMany: true,
maxDepth: 0,
},
],
access: {
create: isAdminOrEmployee(),
update: isAdminOrEmployee(),
delete: isAdminOrEmployee(),
},
} }

View file

@ -1,4 +1,5 @@
import { CollectionConfig } from 'payload' import { CollectionConfig } from 'payload'
import { isAdminOrEmployee } from '@/collections/access/admin'
export const Worship: CollectionConfig = { export const Worship: CollectionConfig = {
slug: 'worship', slug: 'worship',
@ -82,5 +83,8 @@ export const Worship: CollectionConfig = {
], ],
access: { access: {
read: () => true, read: () => true,
create: isAdminOrEmployee(),
update: isAdminOrEmployee(),
delete: isAdminOrEmployee(),
}, },
} }

View file

@ -0,0 +1,17 @@
import type { Access } from 'payload'
export const isAdmin =
(): Access =>
({ req: { user } }) => {
return user?.roles === 'admin'
}
export const isAdminOrEmployee =
(): Access =>
({ req: { user } }) => {
if (!user) {
return false
}
return user.roles === 'admin' || user.roles === 'employee'
}

View file

@ -69,7 +69,7 @@ export const HomeBanner = forwardRef<HomeBannerHandle, HomeBannerProps>(
context.shadowBlur = 10 context.shadowBlur = 10
context.shadowColor = 'white' context.shadowColor = 'white'
setTimeout(() => drawStar(context), i * 100); setTimeout(() => drawStar(context), i * 100)
} }
} }
}, [drawStar, stars]) }, [drawStar, stars])

View file

@ -8,162 +8,241 @@
export interface Config { export interface Config {
auth: { auth: {
users: UserAuthOperations; users: UserAuthOperations
}; }
collections: { collections: {
users: User; parish: Parish
media: Media; church: Church
worship: Worship; worship: Worship
church: Church; event: Event
testimony: Testimony; group: Group
'payload-preferences': PayloadPreference; employees: Employee
'payload-migrations': PayloadMigration; testimony: Testimony
}; users: User
media: Media
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
db: { db: {
defaultIDType: string; defaultIDType: string
}; }
globals: {}; globals: {}
locale: null; locale: null
user: User & { user: User & {
collection: 'users'; collection: 'users'
}; }
} }
export interface UserAuthOperations { export interface UserAuthOperations {
forgotPassword: { forgotPassword: {
email: string; email: string
password: string; password: string
}; }
login: { login: {
email: string; email: string
password: string; password: string
}; }
registerFirstUser: { registerFirstUser: {
email: string; email: string
password: string; password: string
}; }
unlock: { unlock: {
email: string; email: string
password: string; password: string
}; }
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users". * via the `definition` "parish".
*/ */
export interface User { export interface Parish {
id: string; id: string
updatedAt: string; name: string
createdAt: string; churches: (string | Church)[]
email: string; employees: (string | Employee)[]
resetPasswordToken?: string | null; contact: string
resetPasswordExpiration?: string | null; title: string
salt?: string | null; description: string
hash?: string | null; photo?: string | Media | null
loginAttempts?: number | null; updatedAt: string
lockUntil?: string | null; createdAt: string
password?: string | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media".
*/
export interface Media {
id: string;
alt: string;
updatedAt: string;
createdAt: string;
url?: string | null;
thumbnailURL?: string | null;
filename?: string | null;
mimeType?: string | null;
filesize?: number | null;
width?: number | null;
height?: number | null;
focalX?: number | null;
focalY?: number | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "worship".
*/
export interface Worship {
id: string;
date: string;
location: string | Church;
type: 'MASS' | 'FAMILY' | 'WORD';
cancelled: boolean;
title?: string | null;
description?: string | null;
updatedAt: string;
createdAt: string;
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "church". * via the `definition` "church".
*/ */
export interface Church { export interface Church {
id: string; id: string
name: string; name: string
address: string; address: string
updatedAt: string; updatedAt: string
createdAt: string; createdAt: string
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "employees".
*/
export interface Employee {
id: string
photo?: string | Media | null
name: string
occupation: string
email?: string | null
telephone?: string | null
updatedAt: string
createdAt: string
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media".
*/
export interface Media {
id: string
alt: string
updatedAt: string
createdAt: string
url?: string | null
thumbnailURL?: string | null
filename?: string | null
mimeType?: string | null
filesize?: number | null
width?: number | null
height?: number | null
focalX?: number | null
focalY?: number | null
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "worship".
*/
export interface Worship {
id: string
date: string
location: string | Church
type: 'MASS' | 'FAMILY' | 'WORD'
cancelled: boolean
title?: string | null
description?: string | null
updatedAt: string
createdAt: string
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "event".
*/
export interface Event {
id: string
photo?: string | Media | null
title: string
datum: string
parish?: (string | Parish)[] | null
group?: (string | null) | Group
shortDescription: string
description: {
root: {
type: string
children: {
type: string
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
}
cancelled: boolean
updatedAt: string
createdAt: string
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "group".
*/
export interface Group {
id: string
photo?: string | Media | null
name: string
description: string
updatedAt: string
createdAt: string
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "testimony". * via the `definition` "testimony".
*/ */
export interface Testimony { export interface Testimony {
id: string; id: string
testimony: string; testimony: string
name: string; name: string
occupation?: string | null; occupation?: string | null
category: 'EUCHARIST'; category: 'EUCHARIST'
updatedAt: string; updatedAt: string
createdAt: string; createdAt: string
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string
name: string
roles: 'user' | 'employee' | 'admin'
groups?: (string | Group)[] | null
updatedAt: string
createdAt: string
email: string
resetPasswordToken?: string | null
resetPasswordExpiration?: string | null
salt?: string | null
hash?: string | null
loginAttempts?: number | null
lockUntil?: string | null
password?: string | null
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences". * via the `definition` "payload-preferences".
*/ */
export interface PayloadPreference { export interface PayloadPreference {
id: string; id: string
user: { user: {
relationTo: 'users'; relationTo: 'users'
value: string | User; value: string | User
}; }
key?: string | null; key?: string | null
value?: value?:
| { | {
[k: string]: unknown; [k: string]: unknown
} }
| unknown[] | unknown[]
| string | string
| number | number
| boolean | boolean
| null; | null
updatedAt: string; updatedAt: string
createdAt: string; createdAt: string
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-migrations". * via the `definition` "payload-migrations".
*/ */
export interface PayloadMigration { export interface PayloadMigration {
id: string; id: string
name?: string | null; name?: string | null
batch?: number | null; batch?: number | null
updatedAt: string; updatedAt: string
createdAt: string; createdAt: string
} }
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth". * via the `definition` "auth".
*/ */
export interface Auth { export interface Auth {
[k: string]: unknown; [k: string]: unknown
} }
declare module 'payload' { declare module 'payload' {
export interface GeneratedTypes extends Config {} export interface GeneratedTypes extends Config {}
} }

View file

@ -12,6 +12,10 @@ import { Worship } from '@/collections/Worship'
import { Churches } from '@/collections/Churches' import { Churches } from '@/collections/Churches'
import { de } from '@payloadcms/translations/languages/de' import { de } from '@payloadcms/translations/languages/de'
import { Testimony } from '@/collections/Testimony' import { Testimony } from '@/collections/Testimony'
import { Parish } from '@/collections/Parish'
import { Employees } from '@/collections/Employees'
import { Groups } from '@/collections/Groups'
import { Events } from '@/collections/Events'
const filename = fileURLToPath(import.meta.url) const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename) const dirname = path.dirname(filename)
@ -20,7 +24,17 @@ export default buildConfig({
admin: { admin: {
user: Users.slug, user: Users.slug,
}, },
collections: [Users, Media, Worship, Churches, Testimony], collections: [
Parish,
Churches,
Worship,
Events,
Groups,
Employees,
Testimony,
Users,
Media,
],
editor: lexicalEditor(), editor: lexicalEditor(),
secret: process.env.PAYLOAD_SECRET || '', secret: process.env.PAYLOAD_SECRET || '',
typescript: { typescript: {