@tiddlywiki/mws 0.0.12 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/server.d.ts +923 -0
- package/dist/server.js +1763 -1415
- package/dist/server.js.map +1 -1
- package/editions/mws-docs/tiddlers/$__StoryList.tid +3 -3
- package/editions/mws-docs/tiddlers/MWS and SQLite.md +11 -0
- package/editions/mws-docs/tiddlers/Request Server.md +20 -0
- package/editions/mws-docs/tiddlers/Request Server.md.meta +5 -0
- package/package.json +16 -10
- package/prisma/schema.prisma +1 -0
- package/react-user-mgmt/package-lock.json +76 -321
- package/react-user-mgmt/package.json +2 -5
- package/react-user-mgmt/public/chunk-YALWN5OT.js +2 -0
- package/react-user-mgmt/public/chunk-YALWN5OT.js.map +7 -0
- package/react-user-mgmt/public/esm-QKDFEP3B.js +3 -0
- package/react-user-mgmt/public/esm-QKDFEP3B.js.map +7 -0
- package/react-user-mgmt/public/index.html +1 -26
- package/react-user-mgmt/public/main.js +68 -109
- package/react-user-mgmt/public/main.js.map +4 -4
- package/react-user-mgmt/public/stats.css +597 -0
- package/react-user-mgmt/public/stats.html +59 -0
- package/react-user-mgmt/public/stats.js +2013 -0
- package/react-user-mgmt/public/stats.json +1 -0
- package/react-user-mgmt/public/stats.svg +4 -0
- package/react-user-mgmt/tsconfig.json +3 -0
- package/dist/server.cjs +0 -16677
- package/dist/server.cjs.map +0 -1
- package/src/StateObject.ts +0 -316
- package/src/commander.ts +0 -417
- package/src/commands/divider.ts +0 -20
- package/src/commands/index.ts +0 -24
- package/src/commands/mws-init-store.ts +0 -77
- package/src/commands/mws-listen.ts +0 -136
- package/src/commands/mws-load-archive.ts +0 -281
- package/src/commands/mws-load-plugin-bags.ts +0 -151
- package/src/commands/mws-load-tiddlers.ts +0 -37
- package/src/commands/mws-load-wiki-folder.ts +0 -124
- package/src/commands/mws-render-tiddlywiki5.ts +0 -55
- package/src/commands/mws-save-archive.ts +0 -111
- package/src/commands/mws-save-tiddler-text.ts +0 -33
- package/src/commands/tests-complete.ts +0 -21
- package/src/global.ts +0 -247
- package/src/routes/TiddlerStore.ts +0 -722
- package/src/routes/bag-file-server.ts +0 -340
- package/src/routes/cache.ts +0 -25
- package/src/routes/index.ts +0 -138
- package/src/routes/managers/index.ts +0 -17
- package/src/routes/managers/manager-recipes.ts +0 -438
- package/src/routes/managers/manager-users.ts +0 -201
- package/src/routes/managers/router-tiddlers.ts +0 -313
- package/src/routes/router.ts +0 -429
- package/src/routes/services/PasswordService.ts +0 -178
- package/src/routes/services/attachments.ts +0 -259
- package/src/routes/services/sessions.ts +0 -166
- package/src/routes/tw-test.ts +0 -65
- package/src/server.ts +0 -151
- package/src/setupDevServer.ts +0 -71
- package/src/streamer.ts +0 -430
- package/src/tiddlywiki.ts +0 -94
- package/src/utils/data-checks.ts +0 -172
- package/src/utils/index.ts +0 -4
- package/src/utils/rootRoute.ts +0 -237
- package/src/utils/utils.ts +0 -403
- package/src/utils/zodAssert.ts +0 -269
- /package/prisma/{migrations/notes.md → notes.md} +0 -0
|
@@ -1,438 +0,0 @@
|
|
|
1
|
-
import { registerZodRoutes, SiteConfig, zodManage, RouterKeyMap, RouterRouteMap } from "../router";
|
|
2
|
-
import { DataChecks } from "../../utils";
|
|
3
|
-
import { AuthUser } from "../services/sessions";
|
|
4
|
-
|
|
5
|
-
// https://crates.io/crates/indradb
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export const RecipeKeyMap: RouterKeyMap<RecipeManager, true> = {
|
|
9
|
-
index_json: true,
|
|
10
|
-
|
|
11
|
-
bag_create: true,
|
|
12
|
-
bag_update: true,
|
|
13
|
-
bag_upsert: true,
|
|
14
|
-
bag_delete: true,
|
|
15
|
-
bag_acl_update: true,
|
|
16
|
-
|
|
17
|
-
recipe_create: true,
|
|
18
|
-
recipe_update: true,
|
|
19
|
-
recipe_upsert: true,
|
|
20
|
-
recipe_delete: true,
|
|
21
|
-
recipe_acl_update: true,
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export type RecipeManagerMap = RouterRouteMap<RecipeManager>;
|
|
26
|
-
|
|
27
|
-
export class RecipeManager {
|
|
28
|
-
|
|
29
|
-
static defineRoutes(root: rootRoute, config: SiteConfig) {
|
|
30
|
-
registerZodRoutes(root, new RecipeManager(config), Object.keys(RecipeKeyMap));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
checks: DataChecks;
|
|
34
|
-
|
|
35
|
-
constructor(private config: SiteConfig) {
|
|
36
|
-
const { allowAnonReads, allowAnonWrites } = config;
|
|
37
|
-
this.checks = new DataChecks({ allowAnonReads, allowAnonWrites })
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
index_json = zodManage(z => z.undefined(), async (state, prisma) => {
|
|
41
|
-
|
|
42
|
-
const { isAdmin, user_id, username, role_ids } = state.user;
|
|
43
|
-
|
|
44
|
-
const OR = this.checks.getBagWhereACL({ permission: "READ", user_id, role_ids });
|
|
45
|
-
|
|
46
|
-
const bagList = await prisma.bags.findMany({
|
|
47
|
-
include: {
|
|
48
|
-
_count: isAdmin ? undefined : {
|
|
49
|
-
select: {
|
|
50
|
-
acl: {
|
|
51
|
-
where: {
|
|
52
|
-
permission: "ADMIN",
|
|
53
|
-
role_id: { in: role_ids }
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
acl: true,
|
|
59
|
-
},
|
|
60
|
-
where: isAdmin ? undefined : { OR }
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
const recipeList = await prisma.recipes.findMany({
|
|
64
|
-
include: {
|
|
65
|
-
recipe_bags: {
|
|
66
|
-
select: { bag_id: true, position: true, with_acl: true, },
|
|
67
|
-
orderBy: { position: "asc" }
|
|
68
|
-
},
|
|
69
|
-
acl: true,
|
|
70
|
-
_count: isAdmin ? undefined : {
|
|
71
|
-
select: {
|
|
72
|
-
acl: {
|
|
73
|
-
where: {
|
|
74
|
-
permission: "ADMIN",
|
|
75
|
-
role_id: { in: role_ids }
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
where: isAdmin ? undefined : { recipe_bags: { every: { bag: { OR } } } }
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
const userListUser = !isAdmin && await prisma.users.findMany({
|
|
85
|
-
select: { user_id: true, username: true }
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
const userListAdmin = !!isAdmin && await prisma.users.findMany({
|
|
89
|
-
select: { user_id: true, username: true, email: true, roles: true, last_login: true, created_at: true }
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const roleList = await prisma.roles.findMany();
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
bagList,
|
|
96
|
-
recipeList,
|
|
97
|
-
isAdmin,
|
|
98
|
-
user_id,
|
|
99
|
-
userListUser,
|
|
100
|
-
userListAdmin,
|
|
101
|
-
roleList,
|
|
102
|
-
username,
|
|
103
|
-
isLoggedIn: state.user.isLoggedIn,
|
|
104
|
-
allowAnonReads: state.config.allowAnonReads,
|
|
105
|
-
allowAnonWrites: state.config.allowAnonWrites,
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
recipe_create = zodManage(z => z.object({
|
|
110
|
-
recipe_name: z.string(),
|
|
111
|
-
description: z.string(),
|
|
112
|
-
bag_names: z.array(z.object({ bag_name: z.string(), with_acl: z.boolean() })),
|
|
113
|
-
owner_id: z.prismaField("Recipes", "owner_id", "number", true).optional(),
|
|
114
|
-
isCreate: z.literal(true).default(true),
|
|
115
|
-
}), async (state, prisma) => {
|
|
116
|
-
return await this.recipeCreateOrUpdate(state.data, prisma, state.user);
|
|
117
|
-
});
|
|
118
|
-
recipe_update = zodManage(z => z.object({
|
|
119
|
-
recipe_name: z.string(),
|
|
120
|
-
description: z.string(),
|
|
121
|
-
bag_names: z.array(z.object({ bag_name: z.string(), with_acl: z.boolean() })),
|
|
122
|
-
owner_id: z.prismaField("Recipes", "owner_id", "number", true).optional(),
|
|
123
|
-
isCreate: z.literal(false).default(false),
|
|
124
|
-
}), async (state, prisma) => {
|
|
125
|
-
return await this.recipeCreateOrUpdate(state.data, prisma, state.user);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
recipe_upsert = zodManage(z => z.object({
|
|
129
|
-
recipe_name: z.string(),
|
|
130
|
-
description: z.string(),
|
|
131
|
-
bag_names: z.array(z.object({ bag_name: z.string(), with_acl: z.boolean() })),
|
|
132
|
-
owner_id: z.prismaField("Recipes", "owner_id", "number", true).optional(),
|
|
133
|
-
isCreate: z.boolean(),
|
|
134
|
-
}), async (state, prisma) => {
|
|
135
|
-
return await this.recipeCreateOrUpdate(state.data, prisma, state.user);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
bag_create = zodManage(z => z.object({
|
|
139
|
-
bag_name: z.string(),
|
|
140
|
-
description: z.string(),
|
|
141
|
-
is_plugin: z.boolean(),
|
|
142
|
-
owner_id: z.prismaField("Bags", "owner_id", "number", true).optional(),
|
|
143
|
-
isCreate: z.literal(true).default(true),
|
|
144
|
-
}), async (state, prisma) => {
|
|
145
|
-
return await this.bagCreateOrUpdate(state.data, prisma, state.user);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
bag_update = zodManage(z => z.object({
|
|
149
|
-
bag_name: z.string(),
|
|
150
|
-
description: z.string(),
|
|
151
|
-
is_plugin: z.boolean(),
|
|
152
|
-
owner_id: z.prismaField("Bags", "owner_id", "number", true).optional(),
|
|
153
|
-
isCreate: z.literal(false).default(false),
|
|
154
|
-
}), async (state, prisma) => {
|
|
155
|
-
return await this.bagCreateOrUpdate(state.data, prisma, state.user);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
bag_upsert = zodManage(z => z.object({
|
|
159
|
-
bag_name: z.string(),
|
|
160
|
-
description: z.string(),
|
|
161
|
-
is_plugin: z.boolean(),
|
|
162
|
-
owner_id: z.prismaField("Bags", "owner_id", "number", true).optional(),
|
|
163
|
-
isCreate: z.boolean(),
|
|
164
|
-
}), async (state, prisma) => {
|
|
165
|
-
return await this.bagCreateOrUpdate(state.data, prisma, state.user);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
async recipeCreateOrUpdate({ bag_names, description, owner_id, recipe_name, isCreate }: {
|
|
169
|
-
recipe_name: string,
|
|
170
|
-
description: string,
|
|
171
|
-
bag_names: { bag_name: string, with_acl: boolean }[],
|
|
172
|
-
owner_id?: number | null,
|
|
173
|
-
isCreate: boolean,
|
|
174
|
-
}, prisma: PrismaTxnClient, user: AuthUser) {
|
|
175
|
-
const existing = await prisma.recipes.findUnique({ where: { recipe_name }, });
|
|
176
|
-
|
|
177
|
-
this.assertCreateOrUpdate({ user, type: "recipe", isCreate, owner_id, existing, });
|
|
178
|
-
|
|
179
|
-
const { isAdmin, user_id } = user;
|
|
180
|
-
|
|
181
|
-
const OR = this.checks.getWhereACL({ permission: "ADMIN", user_id, });
|
|
182
|
-
|
|
183
|
-
const bags = new Map(
|
|
184
|
-
await prisma.bags.findMany({
|
|
185
|
-
where: { bag_name: { in: bag_names.map(e => e.bag_name) } },
|
|
186
|
-
}).then(bags => bags.map(bag => [bag.bag_name as string, bag]))
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
const missing = bag_names.filter(e => !bags.has(e.bag_name));
|
|
190
|
-
if (missing.length) throw "Some bags not found: " + JSON.stringify(missing);
|
|
191
|
-
|
|
192
|
-
const bagsAcl = new Map(
|
|
193
|
-
await prisma.bags.findMany({
|
|
194
|
-
where: { bag_name: { in: bag_names.map(e => e.bag_name) }, OR },
|
|
195
|
-
}).then(bags => bags.map(bag => [bag.bag_name as string, bag]))
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
const createBags = bag_names.map((bag, position) => ({
|
|
199
|
-
bag_id: bags.get(bag.bag_name)!.bag_id,
|
|
200
|
-
with_acl: bagsAcl && bagsAcl.has(bag.bag_name) && bag.with_acl,
|
|
201
|
-
position,
|
|
202
|
-
}));
|
|
203
|
-
|
|
204
|
-
if (existing) {
|
|
205
|
-
await prisma.recipes.update({
|
|
206
|
-
where: { recipe_name },
|
|
207
|
-
data: {
|
|
208
|
-
description,
|
|
209
|
-
owner_id: isAdmin ? owner_id : undefined,
|
|
210
|
-
recipe_bags: {
|
|
211
|
-
deleteMany: {},
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
await prisma.recipes.update({
|
|
216
|
-
where: { recipe_name },
|
|
217
|
-
data: {
|
|
218
|
-
recipe_bags: {
|
|
219
|
-
create: createBags
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
return existing;
|
|
224
|
-
} else {
|
|
225
|
-
|
|
226
|
-
return await prisma.recipes.create({
|
|
227
|
-
data: {
|
|
228
|
-
recipe_name,
|
|
229
|
-
description,
|
|
230
|
-
recipe_bags: { create: createBags },
|
|
231
|
-
owner_id: isAdmin ? owner_id : user_id
|
|
232
|
-
},
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
async bagCreateOrUpdate({ bag_name, description, is_plugin, owner_id, isCreate }: {
|
|
238
|
-
bag_name: string,
|
|
239
|
-
description: string,
|
|
240
|
-
is_plugin: boolean,
|
|
241
|
-
owner_id?: number | null,
|
|
242
|
-
isCreate: boolean,
|
|
243
|
-
}, prisma: PrismaTxnClient, user: AuthUser) {
|
|
244
|
-
const existing = await prisma.bags.findUnique({
|
|
245
|
-
where: { bag_name },
|
|
246
|
-
select: { owner_id: true }
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
this.assertCreateOrUpdate({ type: "bag", isCreate, owner_id, existing, user });
|
|
250
|
-
|
|
251
|
-
const { isAdmin, user_id } = user;
|
|
252
|
-
|
|
253
|
-
return await prisma.bags.upsert({
|
|
254
|
-
where: { bag_name },
|
|
255
|
-
update: {
|
|
256
|
-
description,
|
|
257
|
-
is_plugin,
|
|
258
|
-
owner_id: isAdmin ? owner_id : undefined //undefined leaves the value as-is
|
|
259
|
-
},
|
|
260
|
-
create: {
|
|
261
|
-
bag_name,
|
|
262
|
-
description,
|
|
263
|
-
is_plugin,
|
|
264
|
-
owner_id: isAdmin ? owner_id : user_id
|
|
265
|
-
},
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
assertCreateOrUpdate({
|
|
272
|
-
existing, isCreate, owner_id, type, user
|
|
273
|
-
}: {
|
|
274
|
-
user: AuthUser,
|
|
275
|
-
isCreate: boolean,
|
|
276
|
-
owner_id?: number | null,
|
|
277
|
-
existing: { owner_id: PrismaField<"Users", "user_id"> | null } | null
|
|
278
|
-
type: "recipe" | "bag"
|
|
279
|
-
}) {
|
|
280
|
-
// check user_id just to be safe because we depend on it for an additional check here and elsewhere
|
|
281
|
-
// user_id 0 is also not a valid user_id and only used for anonymous users
|
|
282
|
-
if (!user.isLoggedIn || !user.user_id)
|
|
283
|
-
throw "User not authenticated";
|
|
284
|
-
|
|
285
|
-
const { isAdmin, user_id } = user;
|
|
286
|
-
|
|
287
|
-
if (!isAdmin && owner_id !== undefined)
|
|
288
|
-
throw "owner_id is only valid for admins";
|
|
289
|
-
|
|
290
|
-
if (existing && isCreate)
|
|
291
|
-
throw `A ${type} with this name already exists`;
|
|
292
|
-
|
|
293
|
-
if (existing && !isAdmin && existing.owner_id !== user_id)
|
|
294
|
-
throw `User does not own the ${type} and is not an admin`;
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
recipe_delete = zodManage(z => z.object({
|
|
299
|
-
recipe_name: z.string(),
|
|
300
|
-
}), async (state, prisma) => {
|
|
301
|
-
const { recipe_name } = state.data;
|
|
302
|
-
|
|
303
|
-
if (!state.user.isLoggedIn) throw "User not authenticated";
|
|
304
|
-
|
|
305
|
-
const recipe = await prisma.recipes.findUnique({
|
|
306
|
-
where: { recipe_name },
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
if (!recipe) throw "Recipe not found";
|
|
310
|
-
|
|
311
|
-
const { isAdmin, user_id } = state.user;
|
|
312
|
-
|
|
313
|
-
if (!isAdmin && recipe.owner_id !== user_id)
|
|
314
|
-
throw "User does not own the recipe and is not an admin";
|
|
315
|
-
|
|
316
|
-
await prisma.recipes.delete({
|
|
317
|
-
where: { recipe_name }
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
return null;
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
bag_delete = zodManage(z => z.object({
|
|
324
|
-
bag_name: z.string(),
|
|
325
|
-
}), async (state, prisma) => {
|
|
326
|
-
const { bag_name } = state.data;
|
|
327
|
-
|
|
328
|
-
if (!state.user.isLoggedIn) throw "User not authenticated";
|
|
329
|
-
|
|
330
|
-
const bag = await prisma.bags.findUnique({
|
|
331
|
-
where: { bag_name },
|
|
332
|
-
include: { _count: { select: { tiddlers: true } } }
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
if (!bag) throw "Bag not found";
|
|
336
|
-
|
|
337
|
-
const { isAdmin, user_id } = state.user;
|
|
338
|
-
|
|
339
|
-
if (!isAdmin && bag.owner_id !== user_id)
|
|
340
|
-
throw "User does not own the bag and is not an admin";
|
|
341
|
-
|
|
342
|
-
if (bag._count.tiddlers)
|
|
343
|
-
throw "Bag has tiddlers added and can no longer be deleted.";
|
|
344
|
-
|
|
345
|
-
await prisma.bags.delete({
|
|
346
|
-
where: { bag_name }
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
return null;
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
// Partial<{
|
|
353
|
-
// role_id: number | null;
|
|
354
|
-
// permission: "READ" | "WRITE" | "ADMIN";
|
|
355
|
-
// }>[]
|
|
356
|
-
recipe_acl_update = zodManage(z => z.object({
|
|
357
|
-
recipe_name: z.prismaField("Recipes", "recipe_name", "string"),
|
|
358
|
-
acl: z.array(z.object({
|
|
359
|
-
role_id: z.number().nullable(),
|
|
360
|
-
permission: z.enum(["READ", "WRITE", "ADMIN"]),
|
|
361
|
-
})),
|
|
362
|
-
}), async (state, prisma) => {
|
|
363
|
-
const { recipe_name, acl } = state.data;
|
|
364
|
-
|
|
365
|
-
if (!state.user.isLoggedIn) throw "User not authenticated";
|
|
366
|
-
|
|
367
|
-
const recipe = await prisma.recipes.findUnique({
|
|
368
|
-
where: { recipe_name }
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
if (!recipe) throw "Recipe not found";
|
|
372
|
-
|
|
373
|
-
const { isAdmin, user_id } = state.user;
|
|
374
|
-
|
|
375
|
-
if (!isAdmin && recipe.owner_id !== user_id)
|
|
376
|
-
throw "User does not own the recipe and is not an admin";
|
|
377
|
-
|
|
378
|
-
const distinct = new Set(acl.map(acl => JSON.stringify([acl.role_id, acl.permission])));
|
|
379
|
-
|
|
380
|
-
const { recipe_id } = recipe;
|
|
381
|
-
|
|
382
|
-
await prisma.recipeAcl.deleteMany({
|
|
383
|
-
where: { recipe_id }
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
await prisma.recipeAcl.createMany({
|
|
387
|
-
data: Array.from(distinct).map(e => {
|
|
388
|
-
const [role_id, permission] = JSON.parse(e);
|
|
389
|
-
return { recipe_id, role_id, permission };
|
|
390
|
-
})
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
return null;
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
bag_acl_update = zodManage(z => z.object({
|
|
397
|
-
bag_name: z.prismaField("Bags", "bag_name", "string"),
|
|
398
|
-
acl: z.array(z.object({
|
|
399
|
-
role_id: z.number().nullable(),
|
|
400
|
-
permission: z.enum(["READ", "WRITE", "ADMIN"]),
|
|
401
|
-
})),
|
|
402
|
-
}), async (state, prisma) => {
|
|
403
|
-
const { bag_name, acl } = state.data;
|
|
404
|
-
|
|
405
|
-
if (!state.user.isLoggedIn) throw "User not authenticated";
|
|
406
|
-
|
|
407
|
-
const bag = await prisma.bags.findUnique({
|
|
408
|
-
where: { bag_name },
|
|
409
|
-
include: { acl: true }
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
if (!bag) throw "Bag not found";
|
|
413
|
-
|
|
414
|
-
const { isAdmin, user_id } = state.user;
|
|
415
|
-
|
|
416
|
-
if (!isAdmin && bag.owner_id !== user_id)
|
|
417
|
-
throw "User does not own the bag and is not an admin";
|
|
418
|
-
|
|
419
|
-
const distinct = new Set(acl.map(acl => JSON.stringify([acl.role_id, acl.permission])));
|
|
420
|
-
|
|
421
|
-
const { bag_id } = bag;
|
|
422
|
-
|
|
423
|
-
await prisma.bagAcl.deleteMany({
|
|
424
|
-
where: { bag_id }
|
|
425
|
-
});
|
|
426
|
-
|
|
427
|
-
await prisma.bagAcl.createMany({
|
|
428
|
-
data: Array.from(distinct).map(e => {
|
|
429
|
-
const [role_id, permission] = JSON.parse(e);
|
|
430
|
-
return { bag_id, role_id, permission };
|
|
431
|
-
})
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
return null;
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
}
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import { registerZodRoutes, SiteConfig, zodManage, RouterKeyMap, RouterRouteMap } from "../router";
|
|
2
|
-
|
|
3
|
-
export const UserKeyMap: RouterKeyMap<UserManager, true> = {
|
|
4
|
-
user_edit_data: true,
|
|
5
|
-
user_create: true,
|
|
6
|
-
user_delete: true,
|
|
7
|
-
user_list: true,
|
|
8
|
-
user_update: true,
|
|
9
|
-
user_update_password: true,
|
|
10
|
-
role_create: true,
|
|
11
|
-
role_update: true,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type UserManagerMap = RouterRouteMap<UserManager>;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export class UserManager {
|
|
18
|
-
static defineRoutes(root: rootRoute, config: SiteConfig) {
|
|
19
|
-
registerZodRoutes(root, new UserManager(), Object.keys(UserKeyMap));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
user_edit_data = zodManage(z => z.object({
|
|
23
|
-
user_id: z.prismaField("Users", "user_id", "number")
|
|
24
|
-
}), async (state, prisma) => {
|
|
25
|
-
state.okUser();
|
|
26
|
-
|
|
27
|
-
const { user_id } = state.data;
|
|
28
|
-
|
|
29
|
-
if (!state.user.isAdmin && state.user.user_id !== user_id)
|
|
30
|
-
throw "Non-admins cannot retrieve the profile of other users"
|
|
31
|
-
|
|
32
|
-
const user = await prisma.users.findUnique({
|
|
33
|
-
where: { user_id },
|
|
34
|
-
select: {
|
|
35
|
-
user_id: true,
|
|
36
|
-
username: true,
|
|
37
|
-
email: true,
|
|
38
|
-
roles: true,
|
|
39
|
-
last_login: true,
|
|
40
|
-
created_at: true,
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
if (!user) throw "User not found";
|
|
45
|
-
|
|
46
|
-
const allRoles = await prisma.roles.findMany({
|
|
47
|
-
select: {
|
|
48
|
-
role_id: true,
|
|
49
|
-
role_name: true,
|
|
50
|
-
description: true,
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
return { user, allRoles }
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
user_list = zodManage(z => z.undefined(), async (state, prisma) => {
|
|
58
|
-
|
|
59
|
-
state.okAdmin();
|
|
60
|
-
|
|
61
|
-
const res = await prisma.users.findMany({
|
|
62
|
-
select: {
|
|
63
|
-
user_id: true,
|
|
64
|
-
username: true,
|
|
65
|
-
email: true,
|
|
66
|
-
roles: true,
|
|
67
|
-
last_login: true,
|
|
68
|
-
created_at: true,
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
return res.map(e => ({
|
|
72
|
-
...e,
|
|
73
|
-
last_login: e.last_login?.toISOString(),
|
|
74
|
-
created_at: e.created_at.toISOString(),
|
|
75
|
-
}));
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
user_create = zodManage(z => z.object({
|
|
80
|
-
username: z.string(),
|
|
81
|
-
email: z.string(),
|
|
82
|
-
role_id: z.prismaField("Roles", "role_id", "number", false),
|
|
83
|
-
}), async (state, prisma) => {
|
|
84
|
-
const { username, email, role_id } = state.data;
|
|
85
|
-
|
|
86
|
-
state.okAdmin();
|
|
87
|
-
|
|
88
|
-
const user = await prisma.users.create({
|
|
89
|
-
data: { username, email, password: "", roles: { connect: { role_id } } },
|
|
90
|
-
select: { user_id: true, created_at: true }
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
return user;
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
user_update = zodManage(z => z.object({
|
|
97
|
-
user_id: z.number(),
|
|
98
|
-
username: z.string(),
|
|
99
|
-
email: z.string(),
|
|
100
|
-
role_id: z.prismaField("Roles", "role_id", "number").optional(),
|
|
101
|
-
}), async (state, prisma) => {
|
|
102
|
-
const { user_id, username, email, role_id } = state.data;
|
|
103
|
-
|
|
104
|
-
state.okAdmin();
|
|
105
|
-
|
|
106
|
-
if (state.user.user_id === user_id) throw "Admin cannot update themselves";
|
|
107
|
-
|
|
108
|
-
await prisma.users.update({
|
|
109
|
-
where: { user_id },
|
|
110
|
-
data: { username, email, roles: { set: [{ role_id }] } }
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
return null;
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
user_delete = zodManage(z => z.object({
|
|
118
|
-
user_id: z.number(),
|
|
119
|
-
}), async (state, prisma) => {
|
|
120
|
-
const { user_id } = state.data;
|
|
121
|
-
|
|
122
|
-
state.okAdmin();
|
|
123
|
-
|
|
124
|
-
if (state.user.user_id === user_id) throw "Admin cannot delete themselves";
|
|
125
|
-
|
|
126
|
-
const bags = await prisma.bags.count({ where: { owner_id: user_id } });
|
|
127
|
-
|
|
128
|
-
if (bags) throw "User owns bags and cannot be deleted";
|
|
129
|
-
|
|
130
|
-
await prisma.users.delete({ where: { user_id } });
|
|
131
|
-
|
|
132
|
-
return null;
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
user_update_password = zodManage(z => z.object({
|
|
137
|
-
user_id: z.prismaField("Users", "user_id", "number"),
|
|
138
|
-
registrationRequest: z.string().optional(),
|
|
139
|
-
registrationRecord: z.string().optional(),
|
|
140
|
-
}), async (state, prisma) => {
|
|
141
|
-
const { user_id, registrationRecord, registrationRequest } = state.data;
|
|
142
|
-
|
|
143
|
-
state.okUser();
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (state.user.user_id !== user_id && !state.user.isAdmin)
|
|
147
|
-
throw "You must be an admin to update another user's password";
|
|
148
|
-
|
|
149
|
-
const userExists = await prisma.users.count({ where: { user_id } });
|
|
150
|
-
if (!userExists) throw "User does not exist";
|
|
151
|
-
|
|
152
|
-
if (registrationRequest) {
|
|
153
|
-
return state.PasswordService.createRegistrationResponse({
|
|
154
|
-
userID: user_id,
|
|
155
|
-
registrationRequest
|
|
156
|
-
});
|
|
157
|
-
} else if (registrationRecord) {
|
|
158
|
-
await prisma.users.update({
|
|
159
|
-
where: { user_id },
|
|
160
|
-
data: { password: registrationRecord }
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return null;
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
role_create = zodManage(z => z.object({
|
|
168
|
-
role_name: z.string(),
|
|
169
|
-
description: z.string(),
|
|
170
|
-
}), async (state, prisma) => {
|
|
171
|
-
const { role_name, description } = state.data;
|
|
172
|
-
|
|
173
|
-
state.okAdmin();
|
|
174
|
-
|
|
175
|
-
return await prisma.roles.create({
|
|
176
|
-
data: { role_name, description }
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
role_update = zodManage(z => z.object({
|
|
182
|
-
role_id: z.prismaField("Roles", "role_id", "number"),
|
|
183
|
-
role_name: z.prismaField("Roles", "role_name", "string"),
|
|
184
|
-
description: z.prismaField("Roles", "description", "string"),
|
|
185
|
-
}), async (state, prisma) => {
|
|
186
|
-
const { role_id, role_name, description } = state.data;
|
|
187
|
-
|
|
188
|
-
state.okUser();
|
|
189
|
-
|
|
190
|
-
if (role_id < 1) throw "Invalid role id";
|
|
191
|
-
if (role_id === 1) throw "Cannot update the admin role";
|
|
192
|
-
if (role_id === 2) throw "Cannot update the user role";
|
|
193
|
-
|
|
194
|
-
return await prisma.roles.update({
|
|
195
|
-
where: { role_id },
|
|
196
|
-
data: { role_name, description }
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
}
|