fix: user roles
This commit is contained in:
parent
9b674343f8
commit
02cd209493
15 changed files with 146 additions and 88 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from 'payload'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { hide, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { nextSunday } from '@/utils/sunday'
|
||||
|
||||
export const Announcements: CollectionConfig = {
|
||||
|
|
@ -46,6 +46,9 @@ export const Announcements: CollectionConfig = {
|
|||
required: true
|
||||
}
|
||||
],
|
||||
admin: {
|
||||
hidden: hide
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
create: isAdminOrEmployee(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from 'payload'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { hide, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { ParagraphBlock } from '@/collections/blocks/Paragraph'
|
||||
import { DocumentBlock } from '@/collections/blocks/Document'
|
||||
import { ContactformBlock } from '@/collections/blocks/Contactform'
|
||||
|
|
@ -62,7 +62,8 @@ export const Blog: CollectionConfig = {
|
|||
},
|
||||
],
|
||||
admin: {
|
||||
useAsTitle: 'title'
|
||||
useAsTitle: 'title',
|
||||
hidden: hide
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from 'payload'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { hide, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
|
||||
export const Churches: CollectionConfig = {
|
||||
slug: 'church',
|
||||
|
|
@ -31,6 +31,7 @@ export const Churches: CollectionConfig = {
|
|||
],
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
hidden: hide
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from 'payload'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { hide, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
|
||||
export const ContactPerson: CollectionConfig = {
|
||||
slug: 'contactPerson',
|
||||
|
|
@ -38,7 +38,8 @@ export const ContactPerson: CollectionConfig = {
|
|||
}
|
||||
],
|
||||
admin: {
|
||||
useAsTitle: "name"
|
||||
useAsTitle: "name",
|
||||
hidden: hide
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { CollectionConfig } from 'payload'
|
||||
import { hide, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
|
||||
export const Documents: CollectionConfig = {
|
||||
slug: 'documents',
|
||||
|
|
@ -12,8 +13,13 @@ export const Documents: CollectionConfig = {
|
|||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
update: isAdminOrEmployee(),
|
||||
delete: isAdminOrEmployee()
|
||||
},
|
||||
fields: [],
|
||||
admin: {
|
||||
hidden: hide
|
||||
},
|
||||
upload: {
|
||||
mimeTypes: ['application/pdf']
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { CollectionConfig } from 'payload'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { stringify } from 'qs-esm'
|
||||
import { Event, Group, User } from '@/payload-types'
|
||||
|
||||
export const Events: CollectionConfig = {
|
||||
slug: 'event',
|
||||
|
|
@ -12,14 +13,6 @@ export const Events: CollectionConfig = {
|
|||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'photo',
|
||||
label: {
|
||||
de: 'Foto',
|
||||
},
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
|
|
@ -67,7 +60,7 @@ export const Events: CollectionConfig = {
|
|||
return 'You are not allowed to do this'
|
||||
}
|
||||
|
||||
if (user.roles === 'user' && value) {
|
||||
if (user.roles === 'user' && value && value.length > 0) {
|
||||
return 'Sie sind nur erlaubt Veranstaltungen für Gruppen zu erstellen.'
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +75,20 @@ export const Events: CollectionConfig = {
|
|||
label: {
|
||||
de: 'Gruppe',
|
||||
},
|
||||
validate: (value: any, options: { req: { user: any } }) => {
|
||||
access: {
|
||||
update: ({req: { user}, data}) => {
|
||||
if(user && (user.roles == "admin" || user.roles =="employee")) {
|
||||
return true
|
||||
}
|
||||
|
||||
if(hasGroup(user, data)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
},
|
||||
validate: (value, options: { req: { user: any } }) => {
|
||||
let user = options.req.user
|
||||
|
||||
if (!user) {
|
||||
|
|
@ -90,8 +96,16 @@ export const Events: CollectionConfig = {
|
|||
}
|
||||
|
||||
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!'
|
||||
if(!Array.isArray(value) || value.length === 0) {
|
||||
return 'Sie müssen die Veranstaltung verknüpfen mit ihrer Gruppe.'
|
||||
}
|
||||
|
||||
if(!Array.isArray(user.groups) || user.groups.length === 0) {
|
||||
return "Sie sind kein Mitglied einer Gruppe, und können deswegen keine Veranstaltung erstellen."
|
||||
}
|
||||
|
||||
if(!value.every(id => user.groups.includes(id))) {
|
||||
return "Sie sind nur berechtigt Veranstaltungen für ihrer Gruppe zu erstellen"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -131,8 +145,19 @@ export const Events: CollectionConfig = {
|
|||
de: "Anmeldelink"
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'photo',
|
||||
label: {
|
||||
de: 'Foto',
|
||||
},
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
},
|
||||
{
|
||||
name: 'flyer',
|
||||
label: {
|
||||
de: "Flyer (PDF)"
|
||||
},
|
||||
type: 'upload',
|
||||
relationTo: 'documents'
|
||||
},
|
||||
|
|
@ -160,6 +185,70 @@ export const Events: CollectionConfig = {
|
|||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
delete: isAdminOrEmployee(),
|
||||
// admins and employees can delete, others only if they are member of the group
|
||||
delete: async ({ req: { user }, id }) => {
|
||||
if (!user) {
|
||||
return false
|
||||
}
|
||||
|
||||
if(user.roles === 'admin' || user.roles === 'employee')
|
||||
return true
|
||||
|
||||
if(typeof id !== 'string') {
|
||||
return false
|
||||
}
|
||||
|
||||
const event = await fetchEvent(id)
|
||||
if (hasGroup(user, event)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have
|
||||
* - a user
|
||||
* - data with groups
|
||||
* - the user is member of one of the groups
|
||||
*
|
||||
* @param user
|
||||
* @param data
|
||||
*/
|
||||
const hasGroup = (user: null | User , data: Partial<any> | undefined) => {
|
||||
return user
|
||||
&& user.roles === 'user'
|
||||
&& data
|
||||
&& Array.isArray(data.group)
|
||||
&& data.group.length > 0
|
||||
&& data.group.some((group: string | Group) => {
|
||||
if (!Array.isArray(user.groups)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof group === "string")
|
||||
return user.groups.includes(group)
|
||||
else
|
||||
return user.groups.includes(group.id)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch event
|
||||
* @param id
|
||||
*/
|
||||
const fetchEvent = async (id: string): Promise<undefined|Event> => {
|
||||
const stringifiedQuery = stringify(
|
||||
{
|
||||
select: {
|
||||
group: true,
|
||||
},
|
||||
},
|
||||
{ addQueryPrefix: true },
|
||||
)
|
||||
const res = await fetch(`http://localhost:3000/api/event/${id}${stringifiedQuery}`);
|
||||
if (!res.ok) return undefined
|
||||
return res.json()
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from 'payload'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { hide, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
|
||||
export const Highlight: CollectionConfig = {
|
||||
slug: 'highlight',
|
||||
|
|
@ -62,7 +62,8 @@ export const Highlight: CollectionConfig = {
|
|||
}
|
||||
],
|
||||
admin: {
|
||||
useAsTitle: 'text'
|
||||
useAsTitle: 'text',
|
||||
hidden: hide
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from 'payload'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { hide, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { nextSunday } from '@/utils/sunday'
|
||||
|
||||
export const LiturgicalCalendar: CollectionConfig = {
|
||||
|
|
@ -46,6 +46,9 @@ export const LiturgicalCalendar: CollectionConfig = {
|
|||
required: true
|
||||
}
|
||||
],
|
||||
admin: {
|
||||
hidden: hide
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
create: isAdminOrEmployee(),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import type { CollectionConfig } from 'payload'
|
||||
import { Media as MediaType } from '../payload-types'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
|
||||
export const Media: CollectionConfig = {
|
||||
slug: 'media',
|
||||
access: {
|
||||
read: () => true,
|
||||
update: isAdminOrEmployee(),
|
||||
delete: isAdminOrEmployee()
|
||||
},
|
||||
admin: {
|
||||
listSearchableFields: ['search']
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from 'payload'
|
||||
import { isAdmin, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { hide, isAdmin, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
|
||||
export const Parish: CollectionConfig = {
|
||||
slug: 'parish',
|
||||
|
|
@ -131,6 +131,7 @@ export const Parish: CollectionConfig = {
|
|||
],
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
hidden: hide
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from 'payload'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { hide, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
|
||||
export const PopesPrayerIntentions: CollectionConfig = {
|
||||
slug: 'popePrayerIntentions',
|
||||
|
|
@ -100,6 +100,7 @@ export const PopesPrayerIntentions: CollectionConfig = {
|
|||
],
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
hidden: hide
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { CollectionConfig } from 'payload'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { isAdmin, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
|
||||
export const Users: CollectionConfig = {
|
||||
slug: 'users',
|
||||
|
|
@ -69,8 +69,9 @@ export const Users: CollectionConfig = {
|
|||
},
|
||||
],
|
||||
access: {
|
||||
read: isAdminOrEmployee(),
|
||||
create: isAdminOrEmployee(),
|
||||
update: isAdminOrEmployee(),
|
||||
delete: isAdminOrEmployee(),
|
||||
delete: isAdmin(),
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from 'payload'
|
||||
import { isAdminOrEmployee } from '@/collections/access/admin'
|
||||
import { hide, isAdminOrEmployee } from '@/collections/access/admin'
|
||||
|
||||
export const Worship: CollectionConfig = {
|
||||
slug: 'worship',
|
||||
|
|
@ -101,7 +101,8 @@ export const Worship: CollectionConfig = {
|
|||
],
|
||||
admin: {
|
||||
defaultColumns: ["date", 'location', 'type', 'celebrant'],
|
||||
listSearchableFields: ['date', 'location']
|
||||
listSearchableFields: ['date', 'location'],
|
||||
hidden: hide
|
||||
},
|
||||
access: {
|
||||
read: () => true,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { Access } from 'payload'
|
||||
import type { Access, ClientUser } from 'payload'
|
||||
|
||||
export const isAdmin =
|
||||
(): Access =>
|
||||
|
|
@ -15,3 +15,5 @@ export const isAdminOrEmployee =
|
|||
|
||||
return user.roles === 'admin' || user.roles === 'employee'
|
||||
}
|
||||
|
||||
export const hide = (args: { user: ClientUser }) => args.user && args.user.roles === "user"
|
||||
|
|
@ -6,65 +6,10 @@
|
|||
* and re-run `payload generate:types` to regenerate this file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Supported timezones in IANA format.
|
||||
*
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "supportedTimezones".
|
||||
*/
|
||||
export type SupportedTimezones =
|
||||
| 'Pacific/Midway'
|
||||
| 'Pacific/Niue'
|
||||
| 'Pacific/Honolulu'
|
||||
| 'Pacific/Rarotonga'
|
||||
| 'America/Anchorage'
|
||||
| 'Pacific/Gambier'
|
||||
| 'America/Los_Angeles'
|
||||
| 'America/Tijuana'
|
||||
| 'America/Denver'
|
||||
| 'America/Phoenix'
|
||||
| 'America/Chicago'
|
||||
| 'America/Guatemala'
|
||||
| 'America/New_York'
|
||||
| 'America/Bogota'
|
||||
| 'America/Caracas'
|
||||
| 'America/Santiago'
|
||||
| 'America/Buenos_Aires'
|
||||
| 'America/Sao_Paulo'
|
||||
| 'Atlantic/South_Georgia'
|
||||
| 'Atlantic/Azores'
|
||||
| 'Atlantic/Cape_Verde'
|
||||
| 'Europe/London'
|
||||
| 'Europe/Berlin'
|
||||
| 'Africa/Lagos'
|
||||
| 'Europe/Athens'
|
||||
| 'Africa/Cairo'
|
||||
| 'Europe/Moscow'
|
||||
| 'Asia/Riyadh'
|
||||
| 'Asia/Dubai'
|
||||
| 'Asia/Baku'
|
||||
| 'Asia/Karachi'
|
||||
| 'Asia/Tashkent'
|
||||
| 'Asia/Calcutta'
|
||||
| 'Asia/Dhaka'
|
||||
| 'Asia/Almaty'
|
||||
| 'Asia/Jakarta'
|
||||
| 'Asia/Bangkok'
|
||||
| 'Asia/Shanghai'
|
||||
| 'Asia/Singapore'
|
||||
| 'Asia/Tokyo'
|
||||
| 'Asia/Seoul'
|
||||
| 'Australia/Sydney'
|
||||
| 'Pacific/Guam'
|
||||
| 'Pacific/Noumea'
|
||||
| 'Pacific/Auckland'
|
||||
| 'Pacific/Fiji';
|
||||
|
||||
export interface Config {
|
||||
auth: {
|
||||
users: UserAuthOperations;
|
||||
};
|
||||
blocks: {};
|
||||
collections: {
|
||||
parish: Parish;
|
||||
church: Church;
|
||||
|
|
@ -399,7 +344,6 @@ export interface Highlight {
|
|||
*/
|
||||
export interface Event {
|
||||
id: string;
|
||||
photo?: (string | null) | Media;
|
||||
title: string;
|
||||
date: string;
|
||||
location: string | Location;
|
||||
|
|
@ -409,6 +353,7 @@ export interface Event {
|
|||
shortDescription: string;
|
||||
description: string;
|
||||
rsvpLink?: string | null;
|
||||
photo?: (string | null) | Media;
|
||||
flyer?: (string | null) | Document;
|
||||
cancelled: boolean;
|
||||
isRecurring: boolean;
|
||||
|
|
@ -814,7 +759,6 @@ export interface HighlightSelect<T extends boolean = true> {
|
|||
* via the `definition` "event_select".
|
||||
*/
|
||||
export interface EventSelect<T extends boolean = true> {
|
||||
photo?: T;
|
||||
title?: T;
|
||||
date?: T;
|
||||
location?: T;
|
||||
|
|
@ -824,6 +768,7 @@ export interface EventSelect<T extends boolean = true> {
|
|||
shortDescription?: T;
|
||||
description?: T;
|
||||
rsvpLink?: T;
|
||||
photo?: T;
|
||||
flyer?: T;
|
||||
cancelled?: T;
|
||||
isRecurring?: T;
|
||||
|
|
|
|||
Loading…
Reference in a new issue