Skip to content

Commit b8e7c34

Browse files
committed
CMS: Admins
1 parent 98ac118 commit b8e7c34

8 files changed

Lines changed: 139 additions & 61 deletions

File tree

client/src/cms/access/admin.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,11 @@ import type { Access, FieldAccess } from "payload";
33
export const adminAccess: Access = ({ req: { user } }) => {
44
if (!user) return false;
55

6-
if (user.role === "admin") return true;
7-
8-
return false;
6+
return user.collection === "admins";
97
};
108

119
export const fieldAdminAccess: FieldAccess = ({ req: { user } }) => {
1210
if (!user) return false;
1311

14-
if (user.role === "admin") return true;
15-
16-
return false;
12+
return user.collection === "admins";
1713
};

client/src/cms/access/user.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export const userAccess: Access = ({ req: { user } }) => {
55
return false;
66
}
77

8-
if (user.role === "admin") {
8+
if (user.collection === "admins") {
99
return true;
1010
}
1111

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { CollectionConfig, getPayload } from "payload";
2+
3+
import config from "@payload-config";
4+
5+
import { logout } from "@payloadcms/next/auth";
6+
7+
export const Admins: CollectionConfig = {
8+
slug: "admins",
9+
admin: {
10+
useAsTitle: "email",
11+
},
12+
auth: true,
13+
hooks: {
14+
// When the user is logged in with a non-admin user (users collection), they are asked to log
15+
// out by Payload by clicking on a “Log out” button. Unfortunately, this button does not work
16+
// and simply brings the user back to the same page.
17+
// To work around this, the hook below automatically logs out the user when performing any
18+
// admins-related operation. The user will still be presented a page that tells them to log out
19+
// first, but if they reload or click the button, they are at least shown the login form.
20+
beforeOperation: [
21+
async ({ req }) => {
22+
const payload = await getPayload({ config });
23+
const { user } = await payload.auth({ headers: req.headers });
24+
25+
if (user?.collection === "users") {
26+
await logout({ config });
27+
}
28+
},
29+
],
30+
},
31+
fields: [
32+
// Email added by default
33+
// Add more fields as needed
34+
],
35+
};
Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import type { CollectionConfig } from "payload";
22

3-
import { adminAccess, fieldAdminAccess } from "@/cms/access/admin";
3+
import { adminAccess } from "@/cms/access/admin";
44
import { anyoneAccess } from "@/cms/access/anyone";
55
import { userAccess } from "@/cms/access/user";
6-
import { protectRole } from "@/cms/hooks/auth";
76

87
export const Users: CollectionConfig = {
98
slug: "users",
@@ -20,27 +19,5 @@ export const Users: CollectionConfig = {
2019
fields: [
2120
// Email added by default
2221
// Add more fields as needed
23-
{
24-
name: "role",
25-
type: "select",
26-
required: true,
27-
defaultValue: "user",
28-
options: [
29-
{
30-
label: "Admin",
31-
value: "admin",
32-
},
33-
{
34-
label: "User",
35-
value: "user",
36-
},
37-
],
38-
access: {
39-
update: fieldAdminAccess,
40-
},
41-
hooks: {
42-
beforeChange: [protectRole],
43-
},
44-
},
4522
],
4623
};

client/src/cms/hooks/auth.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.

client/src/containers/auth/sign-up.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ export function SignupForm({ ...props }: React.ComponentProps<typeof Card>) {
4444
data: {
4545
email: value.email,
4646
password: value.password,
47-
role: "user",
4847
},
4948
})
5049
.then(() => {

client/src/payload-types.ts

Lines changed: 96 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,12 @@ export type SupportedTimezones =
6363

6464
export interface Config {
6565
auth: {
66+
admins: AdminAuthOperations;
6667
users: UserAuthOperations;
6768
};
6869
blocks: {};
6970
collections: {
71+
admins: Admin;
7072
users: User;
7173
media: Media;
7274
reports: Report;
@@ -76,6 +78,7 @@ export interface Config {
7678
};
7779
collectionsJoins: {};
7880
collectionsSelect: {
81+
admins: AdminsSelect<false> | AdminsSelect<true>;
7982
users: UsersSelect<false> | UsersSelect<true>;
8083
media: MediaSelect<false> | MediaSelect<true>;
8184
reports: ReportsSelect<false> | ReportsSelect<true>;
@@ -89,14 +92,36 @@ export interface Config {
8992
globals: {};
9093
globalsSelect: {};
9194
locale: null;
92-
user: User & {
93-
collection: 'users';
94-
};
95+
user:
96+
| (Admin & {
97+
collection: 'admins';
98+
})
99+
| (User & {
100+
collection: 'users';
101+
});
95102
jobs: {
96103
tasks: unknown;
97104
workflows: unknown;
98105
};
99106
}
107+
export interface AdminAuthOperations {
108+
forgotPassword: {
109+
email: string;
110+
password: string;
111+
};
112+
login: {
113+
email: string;
114+
password: string;
115+
};
116+
registerFirstUser: {
117+
email: string;
118+
password: string;
119+
};
120+
unlock: {
121+
email: string;
122+
password: string;
123+
};
124+
}
100125
export interface UserAuthOperations {
101126
forgotPassword: {
102127
email: string;
@@ -115,13 +140,36 @@ export interface UserAuthOperations {
115140
password: string;
116141
};
117142
}
143+
/**
144+
* This interface was referenced by `Config`'s JSON-Schema
145+
* via the `definition` "admins".
146+
*/
147+
export interface Admin {
148+
id: number;
149+
updatedAt: string;
150+
createdAt: string;
151+
email: string;
152+
resetPasswordToken?: string | null;
153+
resetPasswordExpiration?: string | null;
154+
salt?: string | null;
155+
hash?: string | null;
156+
loginAttempts?: number | null;
157+
lockUntil?: string | null;
158+
sessions?:
159+
| {
160+
id: string;
161+
createdAt?: string | null;
162+
expiresAt: string;
163+
}[]
164+
| null;
165+
password?: string | null;
166+
}
118167
/**
119168
* This interface was referenced by `Config`'s JSON-Schema
120169
* via the `definition` "users".
121170
*/
122171
export interface User {
123172
id: number;
124-
role: 'admin' | 'user';
125173
updatedAt: string;
126174
createdAt: string;
127175
email: string;
@@ -250,6 +298,10 @@ export interface Report {
250298
export interface PayloadLockedDocument {
251299
id: number;
252300
document?:
301+
| ({
302+
relationTo: 'admins';
303+
value: number | Admin;
304+
} | null)
253305
| ({
254306
relationTo: 'users';
255307
value: number | User;
@@ -263,10 +315,15 @@ export interface PayloadLockedDocument {
263315
value: number | Report;
264316
} | null);
265317
globalSlug?: string | null;
266-
user: {
267-
relationTo: 'users';
268-
value: number | User;
269-
};
318+
user:
319+
| {
320+
relationTo: 'admins';
321+
value: number | Admin;
322+
}
323+
| {
324+
relationTo: 'users';
325+
value: number | User;
326+
};
270327
updatedAt: string;
271328
createdAt: string;
272329
}
@@ -276,10 +333,15 @@ export interface PayloadLockedDocument {
276333
*/
277334
export interface PayloadPreference {
278335
id: number;
279-
user: {
280-
relationTo: 'users';
281-
value: number | User;
282-
};
336+
user:
337+
| {
338+
relationTo: 'admins';
339+
value: number | Admin;
340+
}
341+
| {
342+
relationTo: 'users';
343+
value: number | User;
344+
};
283345
key?: string | null;
284346
value?:
285347
| {
@@ -304,12 +366,33 @@ export interface PayloadMigration {
304366
updatedAt: string;
305367
createdAt: string;
306368
}
369+
/**
370+
* This interface was referenced by `Config`'s JSON-Schema
371+
* via the `definition` "admins_select".
372+
*/
373+
export interface AdminsSelect<T extends boolean = true> {
374+
updatedAt?: T;
375+
createdAt?: T;
376+
email?: T;
377+
resetPasswordToken?: T;
378+
resetPasswordExpiration?: T;
379+
salt?: T;
380+
hash?: T;
381+
loginAttempts?: T;
382+
lockUntil?: T;
383+
sessions?:
384+
| T
385+
| {
386+
id?: T;
387+
createdAt?: T;
388+
expiresAt?: T;
389+
};
390+
}
307391
/**
308392
* This interface was referenced by `Config`'s JSON-Schema
309393
* via the `definition` "users_select".
310394
*/
311395
export interface UsersSelect<T extends boolean = true> {
312-
role?: T;
313396
updatedAt?: T;
314397
createdAt?: T;
315398
email?: T;

client/src/payload.config.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import sharp from "sharp";
1111

1212
import { env } from "@/env.mjs";
1313

14+
import { Admins } from "@/cms/collections/Admins";
1415
import { Media } from "@/cms/collections/Media";
1516
import { Reports } from "@/cms/collections/Reports";
1617
import { Users } from "@/cms/collections/Users";
@@ -20,12 +21,12 @@ const dirname = path.dirname(filename);
2021

2122
export default buildConfig({
2223
admin: {
23-
user: Users.slug,
24+
user: Admins.slug,
2425
importMap: {
2526
baseDir: path.resolve(dirname),
2627
},
2728
},
28-
collections: [Users, Media, Reports],
29+
collections: [Admins, Users, Media, Reports],
2930
db: postgresAdapter({
3031
pool: {
3132
connectionString: process.env.DATABASE_URL || "",
@@ -40,6 +41,7 @@ export default buildConfig({
4041
typescript: {
4142
outputFile: path.resolve(dirname, "payload-types.ts"),
4243
},
44+
4345
sharp,
4446
plugins: [
4547
// storage-adapter-placeholder

0 commit comments

Comments
 (0)