Skip to content

Commit 6ba5c0e

Browse files
committed
Implement role-based access control middleware and role management routes
- Added roleMiddleware for permission and role checks. - Created role management routes for CRUD operations on roles. - Implemented schemas for role creation and updates using Zod. - Developed user management routes with ownership checks and role assignments. - Integrated roleService for database interactions related to roles. - Enhanced userService to manage user roles and permissions.
1 parent b0d0474 commit 6ba5c0e

File tree

14 files changed

+2172
-1
lines changed

14 files changed

+2172
-1
lines changed

services/backend/ROLES.md

Lines changed: 443 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
CREATE TABLE `roles` (
2+
`id` text PRIMARY KEY NOT NULL,
3+
`name` text NOT NULL,
4+
`description` text,
5+
`permissions` text NOT NULL,
6+
`is_system_role` integer DEFAULT false NOT NULL,
7+
`created_at` integer NOT NULL,
8+
`updated_at` integer NOT NULL
9+
);
10+
--> statement-breakpoint
11+
CREATE UNIQUE INDEX `roles_name_unique` ON `roles` (`name`);
12+
--> statement-breakpoint
13+
ALTER TABLE `authUser` ADD `role_id` text REFERENCES roles(id);
14+
--> statement-breakpoint
15+
16+
-- Insert default roles
17+
INSERT INTO `roles` (`id`, `name`, `description`, `permissions`, `is_system_role`, `created_at`, `updated_at`) VALUES
18+
('global_admin', 'Global Administrator', 'Full system access with user management capabilities', '["users.list","users.view","users.edit","users.delete","users.create","roles.manage","system.admin"]', 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),
19+
('global_user', 'Global User', 'Standard user with basic profile access', '["profile.view","profile.edit"]', 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000);
20+
--> statement-breakpoint
21+
22+
-- Update existing users to have global_user role (all users since role_id starts as NULL)
23+
UPDATE `authUser` SET `role_id` = 'global_user';
24+
--> statement-breakpoint
25+
26+
-- Make the first user (by creation order) a global admin
27+
UPDATE `authUser`
28+
SET `role_id` = 'global_admin'
29+
WHERE `id` = (
30+
SELECT `id` FROM `authUser`
31+
ORDER BY `id` ASC
32+
LIMIT 1
33+
);
Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
{
2+
"version": "6",
3+
"dialect": "sqlite",
4+
"id": "81b17e83-19db-4690-9e61-43db4ad20479",
5+
"prevId": "299fd8bd-0b6d-4a21-8570-067f6a9c2579",
6+
"tables": {
7+
"authKey": {
8+
"name": "authKey",
9+
"columns": {
10+
"id": {
11+
"name": "id",
12+
"type": "text",
13+
"primaryKey": true,
14+
"notNull": true,
15+
"autoincrement": false
16+
},
17+
"user_id": {
18+
"name": "user_id",
19+
"type": "text",
20+
"primaryKey": false,
21+
"notNull": true,
22+
"autoincrement": false
23+
},
24+
"primary_key": {
25+
"name": "primary_key",
26+
"type": "text",
27+
"primaryKey": false,
28+
"notNull": true,
29+
"autoincrement": false
30+
},
31+
"hashed_password": {
32+
"name": "hashed_password",
33+
"type": "text",
34+
"primaryKey": false,
35+
"notNull": false,
36+
"autoincrement": false
37+
},
38+
"expires": {
39+
"name": "expires",
40+
"type": "integer",
41+
"primaryKey": false,
42+
"notNull": false,
43+
"autoincrement": false
44+
}
45+
},
46+
"indexes": {},
47+
"foreignKeys": {
48+
"authKey_user_id_authUser_id_fk": {
49+
"name": "authKey_user_id_authUser_id_fk",
50+
"tableFrom": "authKey",
51+
"tableTo": "authUser",
52+
"columnsFrom": [
53+
"user_id"
54+
],
55+
"columnsTo": [
56+
"id"
57+
],
58+
"onDelete": "cascade",
59+
"onUpdate": "no action"
60+
}
61+
},
62+
"compositePrimaryKeys": {},
63+
"uniqueConstraints": {},
64+
"checkConstraints": {}
65+
},
66+
"authSession": {
67+
"name": "authSession",
68+
"columns": {
69+
"id": {
70+
"name": "id",
71+
"type": "text",
72+
"primaryKey": true,
73+
"notNull": true,
74+
"autoincrement": false
75+
},
76+
"user_id": {
77+
"name": "user_id",
78+
"type": "text",
79+
"primaryKey": false,
80+
"notNull": true,
81+
"autoincrement": false
82+
},
83+
"expires_at": {
84+
"name": "expires_at",
85+
"type": "integer",
86+
"primaryKey": false,
87+
"notNull": true,
88+
"autoincrement": false
89+
}
90+
},
91+
"indexes": {},
92+
"foreignKeys": {
93+
"authSession_user_id_authUser_id_fk": {
94+
"name": "authSession_user_id_authUser_id_fk",
95+
"tableFrom": "authSession",
96+
"tableTo": "authUser",
97+
"columnsFrom": [
98+
"user_id"
99+
],
100+
"columnsTo": [
101+
"id"
102+
],
103+
"onDelete": "cascade",
104+
"onUpdate": "no action"
105+
}
106+
},
107+
"compositePrimaryKeys": {},
108+
"uniqueConstraints": {},
109+
"checkConstraints": {}
110+
},
111+
"authUser": {
112+
"name": "authUser",
113+
"columns": {
114+
"id": {
115+
"name": "id",
116+
"type": "text",
117+
"primaryKey": true,
118+
"notNull": true,
119+
"autoincrement": false
120+
},
121+
"username": {
122+
"name": "username",
123+
"type": "text",
124+
"primaryKey": false,
125+
"notNull": true,
126+
"autoincrement": false
127+
},
128+
"email": {
129+
"name": "email",
130+
"type": "text",
131+
"primaryKey": false,
132+
"notNull": true,
133+
"autoincrement": false
134+
},
135+
"auth_type": {
136+
"name": "auth_type",
137+
"type": "text",
138+
"primaryKey": false,
139+
"notNull": true,
140+
"autoincrement": false
141+
},
142+
"first_name": {
143+
"name": "first_name",
144+
"type": "text",
145+
"primaryKey": false,
146+
"notNull": false,
147+
"autoincrement": false
148+
},
149+
"last_name": {
150+
"name": "last_name",
151+
"type": "text",
152+
"primaryKey": false,
153+
"notNull": false,
154+
"autoincrement": false
155+
},
156+
"github_id": {
157+
"name": "github_id",
158+
"type": "text",
159+
"primaryKey": false,
160+
"notNull": false,
161+
"autoincrement": false
162+
},
163+
"hashed_password": {
164+
"name": "hashed_password",
165+
"type": "text",
166+
"primaryKey": false,
167+
"notNull": false,
168+
"autoincrement": false
169+
},
170+
"role_id": {
171+
"name": "role_id",
172+
"type": "text",
173+
"primaryKey": false,
174+
"notNull": false,
175+
"autoincrement": false,
176+
"default": "'global_user'"
177+
}
178+
},
179+
"indexes": {
180+
"authUser_username_unique": {
181+
"name": "authUser_username_unique",
182+
"columns": [
183+
"username"
184+
],
185+
"isUnique": true
186+
},
187+
"authUser_email_unique": {
188+
"name": "authUser_email_unique",
189+
"columns": [
190+
"email"
191+
],
192+
"isUnique": true
193+
},
194+
"authUser_github_id_unique": {
195+
"name": "authUser_github_id_unique",
196+
"columns": [
197+
"github_id"
198+
],
199+
"isUnique": true
200+
}
201+
},
202+
"foreignKeys": {
203+
"authUser_role_id_roles_id_fk": {
204+
"name": "authUser_role_id_roles_id_fk",
205+
"tableFrom": "authUser",
206+
"tableTo": "roles",
207+
"columnsFrom": [
208+
"role_id"
209+
],
210+
"columnsTo": [
211+
"id"
212+
],
213+
"onDelete": "no action",
214+
"onUpdate": "no action"
215+
}
216+
},
217+
"compositePrimaryKeys": {},
218+
"uniqueConstraints": {},
219+
"checkConstraints": {}
220+
},
221+
"roles": {
222+
"name": "roles",
223+
"columns": {
224+
"id": {
225+
"name": "id",
226+
"type": "text",
227+
"primaryKey": true,
228+
"notNull": true,
229+
"autoincrement": false
230+
},
231+
"name": {
232+
"name": "name",
233+
"type": "text",
234+
"primaryKey": false,
235+
"notNull": true,
236+
"autoincrement": false
237+
},
238+
"description": {
239+
"name": "description",
240+
"type": "text",
241+
"primaryKey": false,
242+
"notNull": false,
243+
"autoincrement": false
244+
},
245+
"permissions": {
246+
"name": "permissions",
247+
"type": "text",
248+
"primaryKey": false,
249+
"notNull": true,
250+
"autoincrement": false
251+
},
252+
"is_system_role": {
253+
"name": "is_system_role",
254+
"type": "integer",
255+
"primaryKey": false,
256+
"notNull": true,
257+
"autoincrement": false,
258+
"default": false
259+
},
260+
"created_at": {
261+
"name": "created_at",
262+
"type": "integer",
263+
"primaryKey": false,
264+
"notNull": true,
265+
"autoincrement": false
266+
},
267+
"updated_at": {
268+
"name": "updated_at",
269+
"type": "integer",
270+
"primaryKey": false,
271+
"notNull": true,
272+
"autoincrement": false
273+
}
274+
},
275+
"indexes": {
276+
"roles_name_unique": {
277+
"name": "roles_name_unique",
278+
"columns": [
279+
"name"
280+
],
281+
"isUnique": true
282+
}
283+
},
284+
"foreignKeys": {},
285+
"compositePrimaryKeys": {},
286+
"uniqueConstraints": {},
287+
"checkConstraints": {}
288+
},
289+
"users": {
290+
"name": "users",
291+
"columns": {
292+
"id": {
293+
"name": "id",
294+
"type": "text",
295+
"primaryKey": true,
296+
"notNull": true,
297+
"autoincrement": false
298+
},
299+
"email": {
300+
"name": "email",
301+
"type": "text",
302+
"primaryKey": false,
303+
"notNull": true,
304+
"autoincrement": false
305+
},
306+
"name": {
307+
"name": "name",
308+
"type": "text",
309+
"primaryKey": false,
310+
"notNull": false,
311+
"autoincrement": false
312+
},
313+
"created_at": {
314+
"name": "created_at",
315+
"type": "integer",
316+
"primaryKey": false,
317+
"notNull": true,
318+
"autoincrement": false
319+
},
320+
"updated_at": {
321+
"name": "updated_at",
322+
"type": "integer",
323+
"primaryKey": false,
324+
"notNull": true,
325+
"autoincrement": false
326+
}
327+
},
328+
"indexes": {
329+
"users_email_unique": {
330+
"name": "users_email_unique",
331+
"columns": [
332+
"email"
333+
],
334+
"isUnique": true
335+
}
336+
},
337+
"foreignKeys": {},
338+
"compositePrimaryKeys": {},
339+
"uniqueConstraints": {},
340+
"checkConstraints": {}
341+
}
342+
},
343+
"views": {},
344+
"enums": {},
345+
"_meta": {
346+
"schemas": {},
347+
"tables": {},
348+
"columns": {}
349+
},
350+
"internal": {
351+
"indexes": {}
352+
}
353+
}

0 commit comments

Comments
 (0)