najm-auth 0.1.11 → 0.1.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.

Potentially problematic release.


This version of najm-auth might be problematic. Click here for more details.

package/dist/index.mjs DELETED
@@ -1,2706 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __decorateClass = (decorators, target, key, kind) => {
4
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
- if (decorator = decorators[i])
7
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
- if (kind && result) __defProp(target, key, result);
9
- return result;
10
- };
11
- var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
12
-
13
- // src/auth/EncryptionService.ts
14
- import { Injectable } from "najm-api";
15
- import bcrypt from "bcrypt";
16
- var EncryptionService = class {
17
- constructor() {
18
- }
19
- async hashPassword(password) {
20
- if (!password) return null;
21
- if (typeof password !== "string" || password.trim().length === 0) {
22
- return null;
23
- }
24
- return bcrypt.hash(password, 10);
25
- }
26
- async comparePassword(password, hashedPassword) {
27
- return bcrypt.compare(password, hashedPassword);
28
- }
29
- };
30
- EncryptionService = __decorateClass([
31
- Injectable()
32
- ], EncryptionService);
33
-
34
- // src/auth/CookieService.ts
35
- import { setCookie, Injectable as Injectable2, deleteCookie } from "najm-api";
36
- import timestring from "timestring";
37
- var CookieService = class {
38
- setRefreshCookie(refreshToken) {
39
- const maxAge = timestring(process.env.REFRESH_EXPIRES_IN, "s");
40
- setCookie("refreshToken", refreshToken, {
41
- httpOnly: false,
42
- sameSite: "Lax",
43
- maxAge,
44
- path: "/api/auth/refresh"
45
- });
46
- }
47
- clearRefreshCookie() {
48
- deleteCookie("refreshToken", {
49
- httpOnly: false,
50
- sameSite: "Lax",
51
- path: "/api/auth/refresh",
52
- maxAge: 0
53
- });
54
- }
55
- };
56
- CookieService = __decorateClass([
57
- Injectable2()
58
- ], CookieService);
59
-
60
- // src/auth/AuthController.ts
61
- import { Controller, Get, Post, Params, Body, User, t } from "najm-api";
62
-
63
- // src/roles/RoleGuards.ts
64
- import { Injectable as Injectable3, Headers, createGuard, GuardParams, Ctx } from "najm-api";
65
- var ROLES = {
66
- ADMIN: "admin",
67
- PRINCIPAL: "principal",
68
- ACCOUNTING: "accounting",
69
- SECRETARY: "secretary",
70
- TEACHER: "teacher",
71
- STUDENT: "student",
72
- PARENT: "parent"
73
- };
74
- var ROLE_GROUPS = {
75
- ADMINISTRATORS: [ROLES.ADMIN, ROLES.PRINCIPAL],
76
- FINANCIAL: [ROLES.ADMIN, ROLES.ACCOUNTING],
77
- STAFF: [ROLES.ADMIN, ROLES.PRINCIPAL, ROLES.ACCOUNTING, ROLES.SECRETARY, ROLES.TEACHER],
78
- END_USERS: [ROLES.STUDENT, ROLES.PARENT],
79
- ALL: [ROLES.ADMIN, ROLES.PRINCIPAL, ROLES.ACCOUNTING, ROLES.SECRETARY, ROLES.TEACHER, ROLES.STUDENT, ROLES.PARENT]
80
- };
81
- var RoleChecker = class {
82
- isInGroup(userRole, group) {
83
- return group.includes(userRole?.toLowerCase());
84
- }
85
- isAdministrator(userRole) {
86
- return this.isInGroup(userRole, ROLE_GROUPS.ADMINISTRATORS);
87
- }
88
- isStaff(userRole) {
89
- return this.isInGroup(userRole, ROLE_GROUPS.STAFF);
90
- }
91
- hasAnyRole(userRole, roles) {
92
- return roles.includes(userRole?.toLowerCase());
93
- }
94
- hasExactRole(userRole, requiredRole) {
95
- return userRole?.toLowerCase() === requiredRole?.toLowerCase();
96
- }
97
- };
98
- RoleChecker = __decorateClass([
99
- Injectable3()
100
- ], RoleChecker);
101
- var RoleGuards = class {
102
- constructor(roleChecker, tokenService) {
103
- this.roleChecker = roleChecker;
104
- this.tokenService = tokenService;
105
- }
106
- async isAuth(auth, ctx) {
107
- const user = await this.tokenService.storeUserInCache(auth, ctx);
108
- return !!user;
109
- }
110
- async hasRoles(auth, ctx, roles) {
111
- try {
112
- const user = await this.tokenService.storeUserInCache(auth, ctx);
113
- if (!user?.role) return false;
114
- const roleArray = Array.isArray(roles) ? roles : [roles];
115
- return this.roleChecker.hasAnyRole(user.role, roleArray);
116
- } catch {
117
- return false;
118
- }
119
- }
120
- };
121
- __decorateClass([
122
- __decorateParam(0, Headers("authorization")),
123
- __decorateParam(1, Ctx())
124
- ], RoleGuards.prototype, "isAuth", 1);
125
- __decorateClass([
126
- __decorateParam(0, Headers("authorization")),
127
- __decorateParam(1, Ctx()),
128
- __decorateParam(2, GuardParams())
129
- ], RoleGuards.prototype, "hasRoles", 1);
130
- RoleGuards = __decorateClass([
131
- Injectable3()
132
- ], RoleGuards);
133
- var isAdmin = () => Role("admin");
134
- var isPrincipal = () => Role("principal");
135
- var isAccounting = () => Role("accounting");
136
- var isSecretary = () => Role("secretary");
137
- var isTeacher = () => Role("teacher");
138
- var isParent = () => Role("parent");
139
- var isStudent = () => Role("student");
140
- var isAdministrator = () => Role("admin", "principal");
141
- var isFinancial = () => Role("admin", "accounting");
142
- var isStaff = () => Role("admin", "principal", "accounting", "secretary", "teacher");
143
- var isAuth = createGuard(RoleGuards, "isAuth");
144
- var Role = (...roles) => createGuard(RoleGuards, "hasRoles")(...roles);
145
-
146
- // src/auth/AuthController.ts
147
- var AuthController = class {
148
- constructor(authService) {
149
- this.authService = authService;
150
- }
151
- async registerUser(body) {
152
- const data = await this.authService.registerUser(body);
153
- return {
154
- data,
155
- message: t("auth.success.register"),
156
- status: "success"
157
- };
158
- }
159
- async loginUser(body) {
160
- const data = await this.authService.loginUser(body);
161
- return {
162
- data,
163
- message: t("auth.success.login"),
164
- status: "success"
165
- };
166
- }
167
- async refreshTokens() {
168
- const data = await this.authService.refreshTokens();
169
- return {
170
- data,
171
- message: t("auth.success.tokenRefreshed"),
172
- status: "success"
173
- };
174
- }
175
- async logoutUser(id) {
176
- const data = await this.authService.logoutUser(id);
177
- return {
178
- data,
179
- message: t("auth.success.logout"),
180
- status: "success"
181
- };
182
- }
183
- async userProfile(user) {
184
- const data = await this.authService.getUserProfile(user);
185
- return {
186
- data,
187
- message: t("users.success.retrieved"),
188
- status: "success"
189
- };
190
- }
191
- async forgotPassword(body) {
192
- const data = await this.authService.forgotPassword(body.email);
193
- return {
194
- data,
195
- message: t("auth.success.passwordReset"),
196
- status: "success"
197
- };
198
- }
199
- };
200
- __decorateClass([
201
- Post("/register"),
202
- __decorateParam(0, Body())
203
- ], AuthController.prototype, "registerUser", 1);
204
- __decorateClass([
205
- Post("/login"),
206
- __decorateParam(0, Body())
207
- ], AuthController.prototype, "loginUser", 1);
208
- __decorateClass([
209
- Get("/refresh")
210
- ], AuthController.prototype, "refreshTokens", 1);
211
- __decorateClass([
212
- Get("/logout/:id"),
213
- __decorateParam(0, Params("id"))
214
- ], AuthController.prototype, "logoutUser", 1);
215
- __decorateClass([
216
- Get("/me"),
217
- isAuth(),
218
- __decorateParam(0, User())
219
- ], AuthController.prototype, "userProfile", 1);
220
- __decorateClass([
221
- Post("/forgot-password"),
222
- isAuth(),
223
- __decorateParam(0, Body())
224
- ], AuthController.prototype, "forgotPassword", 1);
225
- AuthController = __decorateClass([
226
- Controller("/auth")
227
- ], AuthController);
228
-
229
- // src/auth/AuthService.ts
230
- import { t as t2 } from "najm-api";
231
- import { Injectable as Injectable4, getCurrentLanguage } from "najm-api";
232
- var AuthService = class {
233
- constructor(tokenService, userService, userValidator, cookieService) {
234
- this.tokenService = tokenService;
235
- this.userService = userService;
236
- this.userValidator = userValidator;
237
- this.cookieService = cookieService;
238
- }
239
- async registerUser(body) {
240
- return await this.userService.create(body);
241
- }
242
- async loginUser(body) {
243
- const { email, password } = body;
244
- if (!email || !password) {
245
- throw new Error(t2("auth.errors.invalidCredentials"));
246
- }
247
- const existingPassword = await this.userService.getPassword(email);
248
- const { id } = await this.userService.getByEmail(email);
249
- await this.userValidator.checkPasswordValid(password, existingPassword);
250
- const data = await this.tokenService.generateTokens(id);
251
- this.cookieService.setRefreshCookie(data.refreshToken);
252
- return data;
253
- }
254
- async refreshTokens() {
255
- const data = await this.tokenService.refreshTokens();
256
- this.cookieService.setRefreshCookie(data.refreshToken);
257
- return data;
258
- }
259
- async logoutUser(userId) {
260
- await this.userValidator.checkUserExists(userId);
261
- await this.tokenService.revokeToken(userId);
262
- this.cookieService.clearRefreshCookie();
263
- return { data: null, message: t2("auth.success.logout") };
264
- }
265
- async getUserProfile(userData) {
266
- const lang = getCurrentLanguage();
267
- return {
268
- ...userData,
269
- language: lang
270
- };
271
- }
272
- async forgotPassword(email) {
273
- }
274
- };
275
- AuthService = __decorateClass([
276
- Injectable4()
277
- ], AuthService);
278
-
279
- // src/lib/ENUMS.ts
280
- var ENUMS = {
281
- // Core System
282
- userType: {
283
- values: ["admin", "teacher", "student", "parent"],
284
- translationKey: "enums.userType"
285
- },
286
- userStatus: {
287
- values: ["active", "inactive", "pending"],
288
- translationKey: "enums.userStatus"
289
- },
290
- tokenStatus: {
291
- values: ["active", "revoked", "expired"],
292
- translationKey: "enums.tokenStatus"
293
- },
294
- tokenType: {
295
- values: ["access", "refresh"],
296
- translationKey: "enums.tokenType"
297
- },
298
- fileStatus: {
299
- values: ["active", "deleted", "archived"],
300
- translationKey: "enums.fileStatus"
301
- },
302
- // Educational System
303
- gender: {
304
- values: ["M", "F"],
305
- translationKey: "common.gender"
306
- },
307
- studentStatus: {
308
- values: ["active", "inactive", "graduated", "transferred"],
309
- translationKey: "students.status"
310
- },
311
- teacherStatus: {
312
- values: ["active", "inactive", "onLeave"],
313
- translationKey: "teachers.status"
314
- },
315
- employmentType: {
316
- values: ["fullTime", "partTime", "contract", "temporary"],
317
- translationKey: "teachers.employmentType"
318
- },
319
- relationshipType: {
320
- values: ["father", "mother", "guardian", "stepparent", "grandparent", "other"],
321
- translationKey: "parents.relationships"
322
- },
323
- semester: {
324
- values: ["spring", "summer", "fall", "winter"],
325
- translationKey: "academic.semester"
326
- },
327
- classStatus: {
328
- values: ["active", "completed", "cancelled"],
329
- translationKey: "classes.status"
330
- },
331
- sectionStatus: {
332
- values: ["active", "inactive", "archived"],
333
- translationKey: "sections.status"
334
- },
335
- language: {
336
- values: ["en", "fr", "ar", "es"],
337
- translationKey: "common.languages"
338
- },
339
- enrollmentStatus: {
340
- values: ["enrolled", "completed", "dropped", "failed"],
341
- translationKey: "enrollments.status"
342
- },
343
- assignmentStatus: {
344
- values: ["active", "completed", "cancelled"],
345
- translationKey: "assignments.status"
346
- },
347
- calendarSystem: {
348
- values: ["SEMESTER", "TRIMESTER", "QUARTER"],
349
- translationKey: "settings.calendarSystem"
350
- },
351
- // Assessment & Exams
352
- assessmentType: {
353
- values: ["quiz", "assignment", "project", "participation", "test", "presentation"],
354
- translationKey: "assessments.type"
355
- },
356
- assessmentStatus: {
357
- values: ["scheduled", "active", "completed", "cancelled"],
358
- translationKey: "assessments.status"
359
- },
360
- submissionType: {
361
- values: ["online", "paper", "presentation", "practical", "discussion"],
362
- translationKey: "assessments.submissionType"
363
- },
364
- examType: {
365
- values: ["midterm", "final", "standardized"],
366
- translationKey: "exams.type"
367
- },
368
- examSecurity: {
369
- values: ["low", "medium", "high"],
370
- translationKey: "exams.security"
371
- },
372
- examStatus: {
373
- values: ["scheduled", "active", "completed", "cancelled", "rescheduled"],
374
- translationKey: "exams.status"
375
- },
376
- gradeStatus: {
377
- values: ["graded", "pending", "draft", "reviewed"],
378
- translationKey: "grades.status"
379
- },
380
- attendanceStatus: {
381
- values: ["present", "absent", "late", "excused"],
382
- translationKey: "attendance.status"
383
- },
384
- proficiencyLevel: {
385
- values: ["beginner", "intermediate", "advanced", "expert"],
386
- translationKey: "common.proficiencyLevel"
387
- },
388
- dayOfWeek: {
389
- values: ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"],
390
- translationKey: "common.days"
391
- },
392
- // Alerts
393
- alertType: {
394
- values: ["academic", "attendance", "behavioral", "health", "system", "announcement", "reminder", "emergency"],
395
- translationKey: "alerts.type"
396
- },
397
- alertPriority: {
398
- values: ["low", "medium", "high", "critical"],
399
- translationKey: "alerts.priority"
400
- },
401
- alertStatus: {
402
- values: ["active", "acknowledged", "resolved", "dismissed"],
403
- translationKey: "alerts.status"
404
- },
405
- // Fees & Payments
406
- feeTypeStatus: {
407
- values: ["active", "inactive", "archived"],
408
- translationKey: "fees.typeStatus"
409
- },
410
- feeCategory: {
411
- values: ["tuition", "registration", "transport", "cafeteria", "books", "sports", "uniform", "technology", "fieldtrip", "other"],
412
- translationKey: "feeTypes.category"
413
- },
414
- paymentType: {
415
- values: ["recurring", "oneTime"],
416
- translationKey: "payments.type"
417
- },
418
- schedule: {
419
- values: ["monthly", "quarterly", "semester", "annually", "oneTime"],
420
- translationKey: "fees.schedule"
421
- },
422
- feeStatus: {
423
- values: ["pending", "partiallyPaid", "paid", "overdue"],
424
- translationKey: "fees.status"
425
- },
426
- feeInstallmentStatus: {
427
- values: ["pending", "partiallyPaid", "paid", "overdue"],
428
- translationKey: "fees.installmentStatus"
429
- },
430
- paymentMethod: {
431
- values: ["cash", "bankTransfer", "check", "creditCard", "debitCard", "online", "mobilePayment"],
432
- translationKey: "payments.methods"
433
- },
434
- paymentStatus: {
435
- values: ["completed", "pending", "failed", "refunded"],
436
- translationKey: "payments.status"
437
- },
438
- // Events
439
- eventType: {
440
- values: ["academic", "sports", "cultural", "holiday", "exam", "meeting", "workshop", "fieldtrip", "ceremony", "conference", "other"],
441
- translationKey: "events.type"
442
- },
443
- eventStatus: {
444
- values: ["scheduled", "ongoing", "completed", "cancelled", "postponed"],
445
- translationKey: "events.status"
446
- },
447
- eventVisibility: {
448
- values: ["public", "private", "teachers", "students", "parents", "staff"],
449
- translationKey: "events.visibility"
450
- },
451
- participantType: {
452
- values: ["student", "teacher", "parent", "staff"],
453
- translationKey: "events.participantType"
454
- },
455
- // Expenses
456
- expenseCategory: {
457
- values: ["salary", "utilities", "maintenance", "supplies", "equipment", "transport", "food", "security", "cleaning", "insurance", "rent", "tax", "marketing", "training", "technology", "miscellaneous"],
458
- translationKey: "expenses.categories"
459
- },
460
- expenseStatus: {
461
- values: ["pending", "approved", "paid", "rejected", "cancelled"],
462
- translationKey: "expenses.status"
463
- },
464
- // Tracker
465
- trackerMode: {
466
- values: ["tracking", "gprs", "sms", "sleepTime", "sleepShock", "sleepDeep"],
467
- translationKey: "tracker.mode"
468
- },
469
- // Transport
470
- driverStatus: {
471
- values: ["active", "inactive", "onLeave", "suspended"],
472
- translationKey: "transport.driverStatus"
473
- },
474
- vehicleStatus: {
475
- values: ["active", "inactive", "maintenance", "retired"],
476
- translationKey: "transport.vehicleStatus"
477
- },
478
- vehicleType: {
479
- values: ["sedan", "minibus", "fullbus", "shuttle"],
480
- translationKey: "transport.vehicleType"
481
- },
482
- vehicleDocumentType: {
483
- values: ["insurance", "registration", "inspection", "emission", "license"],
484
- translationKey: "transport.documentType"
485
- },
486
- busStatus: {
487
- values: ["active", "inactive", "maintenance", "retired"],
488
- translationKey: "transport.busStatus"
489
- },
490
- refuelStatus: {
491
- values: ["pending", "completed", "cancelled"],
492
- translationKey: "transport.refuelStatus"
493
- },
494
- fuelType: {
495
- values: ["gasoline", "diesel", "electric", "hybrid", "lpg", "cng"],
496
- translationKey: "transport.fuelType"
497
- },
498
- maintenanceType: {
499
- values: ["scheduled", "repair", "inspection", "oilChange", "filterChange", "other"],
500
- translationKey: "transport.maintenanceType"
501
- },
502
- maintenanceStatus: {
503
- values: ["scheduled", "inProgress", "completed", "cancelled", "overdue"],
504
- translationKey: "transport.maintenanceStatus"
505
- },
506
- // Personal
507
- maritalStatus: {
508
- values: ["single", "married", "divorced", "widowed", "separated"],
509
- translationKey: "parents.maritalStatus"
510
- }
511
- };
512
- var getEnumConfig = (enumKey) => ENUMS[enumKey];
513
- var getEnumValues = (enumKey) => ENUMS[enumKey]?.values || [];
514
-
515
- // src/lib/validations.ts
516
- import { z as z2 } from "zod";
517
-
518
- // src/lib/ZodEnum.ts
519
- import { z } from "zod";
520
- var createZodEnum = (enumKey) => {
521
- const values = ENUMS[enumKey]?.values;
522
- if (!values) throw new Error(`Enum ${enumKey} not found`);
523
- return z.enum(values);
524
- };
525
- var userTypeEnum = createZodEnum("userType");
526
- var userStatusEnum = createZodEnum("userStatus");
527
- var tokenStatusEnum = createZodEnum("tokenStatus");
528
- var tokenTypeEnum = createZodEnum("tokenType");
529
- var fileStatusEnum = createZodEnum("fileStatus");
530
- var genderEnum = createZodEnum("gender");
531
- var studentStatusEnum = createZodEnum("studentStatus");
532
- var teacherStatusEnum = createZodEnum("teacherStatus");
533
- var employmentTypeEnum = createZodEnum("employmentType");
534
- var relationshipTypeEnum = createZodEnum("relationshipType");
535
- var semesterEnum = createZodEnum("semester");
536
- var classStatusEnum = createZodEnum("classStatus");
537
- var sectionStatusEnum = createZodEnum("sectionStatus");
538
- var languageEnum = createZodEnum("language");
539
- var enrollmentStatusEnum = createZodEnum("enrollmentStatus");
540
- var assignmentStatusEnum = createZodEnum("assignmentStatus");
541
- var calendarSystemEnum = createZodEnum("calendarSystem");
542
- var assessmentTypeEnum = createZodEnum("assessmentType");
543
- var assessmentStatusEnum = createZodEnum("assessmentStatus");
544
- var submissionTypeEnum = createZodEnum("submissionType");
545
- var examTypeEnum = createZodEnum("examType");
546
- var examSecurityEnum = createZodEnum("examSecurity");
547
- var examStatusEnum = createZodEnum("examStatus");
548
- var gradeStatusEnum = createZodEnum("gradeStatus");
549
- var attendanceStatusEnum = createZodEnum("attendanceStatus");
550
- var proficiencyLevelEnum = createZodEnum("proficiencyLevel");
551
- var dayOfWeekEnum = createZodEnum("dayOfWeek");
552
- var alertTypeEnum = createZodEnum("alertType");
553
- var alertPriorityEnum = createZodEnum("alertPriority");
554
- var alertStatusEnum = createZodEnum("alertStatus");
555
- var feeTypeStatusEnum = createZodEnum("feeTypeStatus");
556
- var paymentTypeEnum = createZodEnum("paymentType");
557
- var scheduleEnum = createZodEnum("schedule");
558
- var feeStatusEnum = createZodEnum("feeStatus");
559
- var feeInstallmentStatusEnum = createZodEnum("feeInstallmentStatus");
560
- var paymentMethodEnum = createZodEnum("paymentMethod");
561
- var paymentStatusEnum = createZodEnum("paymentStatus");
562
- var eventTypeEnum = createZodEnum("eventType");
563
- var eventStatusEnum = createZodEnum("eventStatus");
564
- var eventVisibilityEnum = createZodEnum("eventVisibility");
565
- var participantTypeEnum = createZodEnum("participantType");
566
- var expenseCategoryEnum = createZodEnum("expenseCategory");
567
- var expenseStatusEnum = createZodEnum("expenseStatus");
568
- var trackerModeEnum = createZodEnum("trackerMode");
569
- var driverStatusEnum = createZodEnum("driverStatus");
570
- var vehicleStatusEnum = createZodEnum("vehicleStatus");
571
- var vehicleTypeEnum = createZodEnum("vehicleType");
572
- var vehicleDocumentTypeEnum = createZodEnum("vehicleDocumentType");
573
- var busStatusEnum = createZodEnum("busStatus");
574
- var refuelStatusEnum = createZodEnum("refuelStatus");
575
- var fuelTypeEnum = createZodEnum("fuelType");
576
- var maintenanceTypeEnum = createZodEnum("maintenanceType");
577
- var maintenanceStatusEnum = createZodEnum("maintenanceStatus");
578
- var maritalStatusEnum = createZodEnum("maritalStatus");
579
-
580
- // src/lib/validations.ts
581
- var requiredId = z2.preprocess((val) => val ?? "", z2.string().min(1, "ID is required"));
582
- var optionalId = z2.string().min(1, "ID cannot be empty").nullish().optional();
583
- var emailField = z2.string().email("Invalid email format").or(z2.literal(""));
584
- var phoneField = z2.string().regex(/^[\+]?[1-9][\d]{0,15}$/, "Invalid phone number");
585
- var nameField = z2.string().min(2, "Name must be at least 2 characters").max(100, "Name too long");
586
- var dateField = z2.string().regex(/^(\d{4}-\d{2}-\d{2}|\d{2}\/\d{2}\/\d{4}|\d{2}-\d{2}-\d{2}|\d{2}-\d{2}-\d{4})$/, "Date must be in YYYY-MM-DD, MM/DD/YYYY, DD/MM/YYYY, DD-MM-YY, or DD-MM-YYYY format");
587
- var optionalDateField = z2.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format").nullable().optional();
588
- var timeField = z2.string().regex(/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/, "Time must be in HH:MM format").optional().nullable();
589
- var cinField = z2.string().min(8, "CIN must be at least 8 characters").max(20, "CIN too long");
590
- var addressField = z2.string().max(500, "Address too long").optional();
591
- var academicYearField = z2.string().min(9, "Academic year is required").regex(/^\d{4}-\d{4}$/, "Academic year must be in YYYY-YYYY format");
592
- var num = () => {
593
- const createChainable = (currentSchema) => {
594
- const methods = {
595
- positive: (msg = "Must be positive") => createChainable(currentSchema.refine((val) => val > 0, { message: msg })),
596
- min: (value, msg) => createChainable(currentSchema.refine(
597
- (val) => val >= value,
598
- { message: msg || `Must be at least ${value}` }
599
- )),
600
- max: (value, msg) => createChainable(currentSchema.refine(
601
- (val) => val <= value,
602
- { message: msg || `Cannot exceed ${value}` }
603
- )),
604
- int: (msg = "Must be an integer") => createChainable(currentSchema.refine(
605
- (val) => Number.isInteger(val),
606
- { message: msg }
607
- ))
608
- };
609
- return Object.assign(currentSchema, methods);
610
- };
611
- const isValidNumber = (val) => {
612
- if (val === null || val === void 0 || Number.isNaN(val)) return false;
613
- if (typeof val === "number") return true;
614
- if (typeof val === "string") {
615
- const trimmed = val.trim();
616
- return trimmed !== "" && !isNaN(Number(trimmed));
617
- }
618
- return false;
619
- };
620
- const baseSchema = z2.any().refine(isValidNumber, { message: "Must be a valid number" }).transform((val) => typeof val === "string" ? Number(val) : val);
621
- return createChainable(baseSchema);
622
- };
623
- var userSchema = z2.object({
624
- id: optionalId,
625
- username: nameField.max(50).optional(),
626
- email: emailField,
627
- password: z2.string().min(8, "Password must be at least 8 characters"),
628
- roleId: optionalId,
629
- roleName: nameField.max(50).optional(),
630
- lastLogin: optionalDateField,
631
- image: z2.union([z2.string(), z2.instanceof(File), z2.undefined()]).optional(),
632
- emailVerified: z2.boolean().default(false),
633
- status: userStatusEnum,
634
- createdAt: optionalDateField
635
- });
636
- var roleSchema = z2.object({
637
- id: optionalId,
638
- name: nameField.max(50),
639
- description: z2.string().max(255, "Description too long").optional(),
640
- createdAt: optionalDateField
641
- });
642
- var studentSchema = z2.object({
643
- id: optionalId,
644
- classId: requiredId,
645
- sectionId: requiredId,
646
- studentCode: z2.string(),
647
- name: nameField,
648
- email: emailField,
649
- phone: phoneField.nullish(),
650
- address: addressField,
651
- dateOfBirth: optionalDateField,
652
- gender: genderEnum,
653
- enrollmentDate: dateField,
654
- medicalConditions: z2.string().max(1e3, "Medical conditions description too long").nullish().optional(),
655
- previousSchool: z2.string().max(500, "Previous school name too long").optional().nullable(),
656
- image: z2.union([z2.string(), z2.instanceof(File), z2.null()]).optional(),
657
- status: studentStatusEnum.default("active")
658
- });
659
- var parentSchema = z2.object({
660
- id: optionalId,
661
- name: nameField,
662
- email: emailField.optional(),
663
- phone: phoneField,
664
- gender: genderEnum.optional(),
665
- address: addressField,
666
- dateOfBirth: optionalDateField,
667
- cin: cinField,
668
- occupation: z2.string().max(100, "Occupation too long").optional(),
669
- nationality: z2.string().max(100, "Nationality too long").optional(),
670
- maritalStatus: z2.string().max(50, "Marital status too long").optional(),
671
- relationshipType: relationshipTypeEnum,
672
- image: z2.union([z2.string(), z2.instanceof(File), z2.null()]).optional(),
673
- isEmergencyContact: z2.boolean().optional().default(false),
674
- financialResponsibility: z2.boolean().optional().default(false)
675
- });
676
- var driverSchema = z2.object({
677
- id: optionalId,
678
- name: nameField,
679
- email: emailField,
680
- cin: cinField,
681
- phone: phoneField,
682
- address: addressField,
683
- gender: genderEnum.optional(),
684
- licenseNumber: z2.string().min(5, "License number must be at least 5 characters").max(20, "License number too long"),
685
- licenseType: z2.string().max(10, "License type too long"),
686
- licenseExpiry: dateField,
687
- hireDate: dateField,
688
- salary: num().positive("Salary must be positive").optional(),
689
- yearsOfExperience: num().int().min(0, "Years of experience must be non-negative").optional(),
690
- emergencyContact: nameField.optional(),
691
- emergencyPhone: phoneField.optional(),
692
- image: z2.union([z2.string(), z2.instanceof(File), z2.null()]).optional(),
693
- status: driverStatusEnum.default("active"),
694
- notes: z2.string().max(1e3, "Notes too long").optional().nullable()
695
- });
696
- var teacherPersonalSchema = z2.object({
697
- id: optionalId,
698
- name: nameField,
699
- cin: cinField,
700
- email: emailField,
701
- phone: phoneField,
702
- address: addressField,
703
- gender: genderEnum.optional(),
704
- emergencyContact: nameField.optional(),
705
- emergencyPhone: phoneField,
706
- status: teacherStatusEnum.default("active"),
707
- image: z2.union([z2.string(), z2.instanceof(File), z2.null()]).optional()
708
- });
709
- var teacherProfessionalSchema = z2.object({
710
- specialization: z2.string().max(100, "Specialization too long").optional(),
711
- yearsOfExperience: num().int().min(0, "Years of experience must be non-negative").optional(),
712
- salary: num().positive("Salary must be positive").optional(),
713
- hireDate: dateField,
714
- bankAccount: z2.coerce.string().max(100, { message: "Bank account too long" }).optional(),
715
- employmentType: employmentTypeEnum.optional(),
716
- workloadHours: num().int().min(0, "Workload hours must be non-negative").max(60, "Workload hours cannot exceed 60").optional(),
717
- academicDegrees: z2.string().max(500, "Academic degrees description too long").optional()
718
- });
719
- var assignmentSchema = z2.object({
720
- classId: z2.string().min(1, "Class is required"),
721
- sectionIds: z2.array(z2.string()).min(1, "At least one section is required"),
722
- subjectIds: z2.array(z2.string()).min(1, "At least one subject is required"),
723
- academicYear: z2.string().optional()
724
- });
725
- var assignmentsSchema = z2.object({
726
- assignments: z2.array(assignmentSchema).min(1, "At least one parent is required")
727
- });
728
- var teacherFullSchema = z2.object({
729
- ...teacherPersonalSchema.shape,
730
- ...teacherProfessionalSchema.shape,
731
- ...assignmentsSchema.shape
732
- });
733
- var feeTypeSchema = z2.object({
734
- id: optionalId,
735
- name: z2.string().min(2, "Fee type name must be at least 2 characters").max(100, "Fee type name too long"),
736
- description: z2.string().max(500, "Description too long").optional().nullable(),
737
- category: z2.string(),
738
- amount: num().positive("Amount must be greater than 0").max(1e5, "Amount too large"),
739
- paymentType: paymentTypeEnum.default("recurring"),
740
- status: feeTypeStatusEnum.default("active").optional()
741
- });
742
- var feeSchema = z2.object({
743
- id: optionalId,
744
- studentId: requiredId,
745
- feeTypeId: requiredId,
746
- academicYear: academicYearField.optional(),
747
- status: feeStatusEnum.optional(),
748
- schedule: scheduleEnum,
749
- baseAmount: num().positive("Base amount must be positive").optional(),
750
- grossAmount: num().positive("Gross amount must be positive").optional(),
751
- netAmount: num().optional(),
752
- paidAmount: num().min(0, "Paid amount cannot be negative").optional(),
753
- discountAmount: num().min(0, "Discount cannot be negative").optional(),
754
- discountReason: z2.string().max(500, "Discount reason too long").optional().nullable(),
755
- assignedBy: optionalId.nullable(),
756
- notes: z2.string().max(1e3, "Notes too long").optional().nullable()
757
- });
758
- var bulkFeeItemSchema = feeSchema.omit({ studentId: true });
759
- var bulkFeeFormSchema = z2.object({
760
- studentId: requiredId,
761
- fees: z2.array(bulkFeeItemSchema).min(1, "At least one fee is required")
762
- });
763
- var feeInstallmentSchema = z2.object({
764
- feeId: optionalId,
765
- number: num().int().min(1, "Installment must be at least 1"),
766
- dueDate: dateField,
767
- amount: num().positive("Amount must be greater than 0").max(1e5, "Amount too large"),
768
- paidAmount: num().min(0, "Paid amount cannot be negative").max(1e5, "Amount too large").optional(),
769
- status: feeInstallmentStatusEnum.optional()
770
- });
771
- var feePaymentSchema = z2.object({
772
- studentId: optionalId,
773
- amount: num().positive("Amount must be greater than 0").max(1e5, "Amount too large").optional(),
774
- paymentMethod: paymentMethodEnum,
775
- paymentDate: dateField,
776
- checkNumber: z2.preprocess((val) => val === "" ? null : val, z2.string().max(50, "Check number too long").optional().nullable()),
777
- checkDueDate: z2.preprocess((val) => val === "" ? null : val, optionalDateField.nullable()),
778
- transactionRef: z2.preprocess((val) => val === "" ? null : val, z2.string().max(100, "Transaction reference too long").optional().nullable()),
779
- receiptNumber: z2.preprocess((val) => val === "" ? null : val, z2.string().max(50, "Receipt number too long").optional().nullable()),
780
- status: paymentStatusEnum.default("completed"),
781
- processedBy: optionalId,
782
- notes: z2.preprocess((val) => val === "" ? null : val, z2.string().max(1e3, "Notes too long").optional().nullable()),
783
- allocations: z2.array(z2.object({
784
- feeId: optionalId,
785
- number: z2.number().int().positive("Installment must be a positive number"),
786
- amount: num().positive("Amount must be greater than 0")
787
- })).optional().nullable()
788
- });
789
- var paymentAllocationSchema = z2.object({
790
- paymentId: z2.string().min(1, "Payment ID is required"),
791
- feeId: z2.string().min(1, "Fee ID is required"),
792
- installmentId: z2.string().optional(),
793
- amount: z2.number().positive("Amount must be positive"),
794
- type: z2.enum(["fee", "installment"]).default("installment"),
795
- notes: z2.string().optional()
796
- });
797
- var parentsSchema = z2.object({
798
- parents: z2.array(parentSchema).optional().default([])
799
- });
800
- var feesSchema = z2.object({
801
- fees: z2.array(bulkFeeItemSchema).min(1, "At least one fee is required")
802
- });
803
- var fullStudentSchema = z2.object({
804
- ...studentSchema.shape,
805
- ...parentsSchema.shape,
806
- ...feesSchema.shape
807
- });
808
- var subjectSchema = z2.object({
809
- id: optionalId,
810
- code: z2.string().min(2, "Subject code must be at least 2 characters").max(10, "Subject code too long"),
811
- name: z2.string().min(2, "Subject name must be at least 2 characters").max(100, "Subject name too long"),
812
- description: z2.string().max(500, "Description too long").optional(),
813
- gradeLevel: num().int().min(1).max(12).optional()
814
- });
815
- var sectionSchema = z2.object({
816
- id: optionalId,
817
- classId: requiredId,
818
- name: z2.string().min(1, "Section name is required").max(10, "Section name too long"),
819
- maxStudents: num().int().min(1, "Max students must be at least 1").max(100, "Max students cannot exceed 100").default(30),
820
- roomNumber: num().max(1e4, "Room number too long").optional(),
821
- status: sectionStatusEnum.default("active")
822
- });
823
- var classSchema = z2.object({
824
- id: optionalId,
825
- name: z2.string().min(1, "Class name is required").max(50, "Class name too long"),
826
- description: z2.string().max(500, "Description too long").optional(),
827
- academicYear: academicYearField,
828
- level: z2.string().min(1, "Class level is required")
829
- });
830
- var attendanceSchema = z2.object({
831
- studentId: requiredId,
832
- teacherId: requiredId,
833
- subjectId: requiredId,
834
- sectionId: requiredId,
835
- date: dateField,
836
- status: attendanceStatusEnum.default("present"),
837
- notes: z2.string().max(500, "Notes too long").optional()
838
- });
839
- var assessmentSchema = z2.object({
840
- classId: requiredId,
841
- sectionId: requiredId,
842
- subjectId: requiredId,
843
- teacherId: requiredId,
844
- teacherAssignmentId: optionalId,
845
- title: z2.string().min(3, "Title must be at least 3 characters").max(200, "Title too long"),
846
- description: z2.string().max(1e3, "Description too long").optional().nullable(),
847
- type: assessmentTypeEnum.default("quiz"),
848
- date: dateField,
849
- duration: num().int().min(1, "Duration must be at least 1 minute").max(480, "Duration cannot exceed 8 hours"),
850
- totalMarks: num().positive("Total marks must be greater than 0").max(1e3, "Total marks cannot exceed 1000"),
851
- passingMarks: num().min(0, "Passing marks must be non-negative").max(1e3, "Passing marks cannot exceed 1000"),
852
- instructions: z2.string().max(2e3, "Instructions too long").optional().nullable(),
853
- status: assessmentStatusEnum.default("scheduled"),
854
- assessmentId: optionalId
855
- });
856
- var bulkAssessmentSchema = z2.object({
857
- assessments: z2.array(assessmentSchema).min(1, "At least one assessment is required").max(50, "Cannot create more than 50 assessments at once")
858
- });
859
- var gradeSchema = z2.object({
860
- assessmentId: requiredId,
861
- teacherId: requiredId,
862
- subjectId: requiredId,
863
- sectionId: requiredId,
864
- studentId: requiredId,
865
- gradeId: requiredId,
866
- assessmentTitle: z2.string().min(3, "Assessment title must be at least 3 characters").max(200, "Assessment title too long").optional(),
867
- marksObtained: num().min(0, "Marks obtained must be non-negative").max(1e3, "Marks obtained cannot exceed 1000"),
868
- feedback: z2.string().max(1e3, "Feedback too long").optional().nullable(),
869
- status: gradeStatusEnum.default("graded")
870
- });
871
- var examSchema = z2.object({
872
- classId: optionalId,
873
- sectionId: requiredId,
874
- subjectId: requiredId,
875
- teacherId: requiredId,
876
- examId: requiredId,
877
- teacherAssignmentId: requiredId,
878
- title: z2.string().min(3, "Title must be at least 3 characters").max(200, "Title too long"),
879
- description: z2.string().max(1e3, "Description too long").optional().nullable(),
880
- type: examTypeEnum.default("midterm"),
881
- date: dateField,
882
- startTime: timeField,
883
- endTime: timeField,
884
- duration: num().int().min(30, "Exam duration must be at least 30 minutes").max(480, "Duration cannot exceed 8 hours"),
885
- totalMarks: num().positive("Total marks must be greater than 0").max(1e3, "Total marks cannot exceed 1000"),
886
- passingMarks: num().min(0, "Passing marks must be non-negative").max(1e3, "Passing marks cannot exceed 1000"),
887
- roomNumber: num().max(50, "Room number too long").optional().nullable(),
888
- allowedMaterials: z2.string().max(500, "Allowed materials description too long").optional().nullable(),
889
- instructions: z2.string().max(2e3, "Instructions too long").optional().nullable(),
890
- status: examStatusEnum.default("scheduled")
891
- });
892
- var announcementSchema = z2.object({
893
- title: z2.string().min(3, "Title must be at least 3 characters").max(200, "Title too long"),
894
- content: z2.string().min(10, "Content must be at least 10 characters").max(5e3, "Content too long"),
895
- authorId: optionalId,
896
- targetAudience: z2.enum(["all", "students", "teachers", "parents", "class"]),
897
- classId: optionalId,
898
- isPublished: z2.boolean().default(false),
899
- publishDate: z2.string().datetime("Invalid publish date").optional(),
900
- expiryDate: z2.string().datetime("Invalid expiry date").optional()
901
- });
902
- var alertSchema = z2.object({
903
- type: alertTypeEnum,
904
- title: z2.string().min(3, "Title must be at least 3 characters").max(200, "Title too long"),
905
- message: z2.string().min(10, "Message must be at least 10 characters").max(2e3, "Message too long"),
906
- priority: alertPriorityEnum.default("medium"),
907
- status: alertStatusEnum.default("active"),
908
- studentId: optionalId,
909
- teacherId: optionalId,
910
- classId: optionalId,
911
- subjectId: optionalId,
912
- targetAudience: z2.enum(["all", "students", "teachers", "parents"]).optional(),
913
- authorId: optionalId,
914
- isRead: z2.boolean().default(false)
915
- });
916
- var eventSchema = z2.object({
917
- title: z2.string().min(3, "Title must be at least 3 characters").max(200, "Title too long"),
918
- description: z2.string().max(5e3, "Description too long").optional().nullable(),
919
- type: eventTypeEnum,
920
- startDate: dateField,
921
- endDate: dateField,
922
- startTime: timeField,
923
- endTime: timeField,
924
- location: z2.string().max(200, "Location too long").optional().nullable(),
925
- venue: z2.string().max(200, "Venue too long").optional().nullable(),
926
- organizerId: optionalId,
927
- classId: optionalId.nullable(),
928
- sectionId: optionalId.nullable(),
929
- visibility: eventVisibilityEnum.default("public"),
930
- status: eventStatusEnum.default("scheduled"),
931
- capacity: num().int().positive("Capacity must be positive").optional().nullable(),
932
- registrationRequired: z2.boolean().default(false),
933
- registrationDeadline: optionalDateField.nullable(),
934
- attachments: z2.any().optional().nullable(),
935
- notes: z2.string().max(2e3, "Notes too long").optional().nullable()
936
- });
937
- var eventParticipantSchema = z2.object({
938
- eventId: optionalId,
939
- participantId: optionalId,
940
- participantType: participantTypeEnum,
941
- attendanceStatus: attendanceStatusEnum.optional().nullable(),
942
- notes: z2.string().max(500, "Notes too long").optional().nullable()
943
- });
944
- var expenseSchema = z2.object({
945
- id: optionalId,
946
- category: expenseCategoryEnum,
947
- title: z2.string().min(3, "Title must be at least 3 characters").max(200, "Title too long"),
948
- amount: num().positive("Amount must be greater than 0").max(1e7, "Amount too large"),
949
- expenseDate: dateField,
950
- paymentMethod: paymentMethodEnum.optional().nullable(),
951
- paymentDate: optionalDateField.nullable(),
952
- vendor: z2.string().max(200, "Vendor name too long").optional().nullable(),
953
- invoiceNumber: z2.string().max(100, "Invoice number too long").optional().nullable(),
954
- receiptNumber: z2.string().max(100, "Receipt number too long").optional().nullable(),
955
- checkNumber: z2.string().max(50, "Check number too long").optional().nullable(),
956
- transactionRef: z2.string().max(100, "Transaction reference too long").optional().nullable(),
957
- status: expenseStatusEnum.default("pending"),
958
- notes: z2.string().max(1e3, "Notes too long").optional().nullable()
959
- });
960
- var expenseApprovalSchema = z2.object({
961
- action: z2.enum(["approve", "reject"]),
962
- rejectionReason: z2.string().min(10, "Rejection reason must be at least 10 characters").max(1e3, "Rejection reason too long").optional().nullable()
963
- });
964
- var expensePaymentSchema = z2.object({
965
- paymentMethod: paymentMethodEnum,
966
- paymentDate: dateField,
967
- checkNumber: z2.string().max(50, "Check number too long").optional().nullable(),
968
- transactionRef: z2.string().max(100, "Transaction reference too long").optional().nullable(),
969
- notes: z2.string().max(1e3, "Notes too long").optional().nullable()
970
- });
971
- var vehicleSchema = z2.object({
972
- id: optionalId,
973
- name: z2.string().min(2, "Vehicle name must be at least 2 characters").max(100, "Vehicle name too long"),
974
- brand: z2.string().min(2, "Brand must be at least 2 characters").max(100, "Brand too long"),
975
- model: z2.string().min(2, "Model must be at least 2 characters").max(100, "Model too long"),
976
- year: num().int().min(1900, "Year must be after 1900").max((/* @__PURE__ */ new Date()).getFullYear() + 1, "Year cannot be in future"),
977
- type: vehicleTypeEnum.default("fullbus"),
978
- capacity: num().int().min(1, "Capacity must be at least 1").max(200, "Capacity cannot exceed 200"),
979
- licensePlate: z2.string().min(2, "License plate must be at least 2 characters").max(50, "License plate too long"),
980
- driverId: optionalId.nullable(),
981
- image: z2.string().max(500, "Image path too long").optional().nullable().default("novehicle.png"),
982
- purchaseDate: optionalDateField.nullable(),
983
- purchasePrice: num().min(0, "Purchase price must be non-negative").max(1e7, "Purchase price too large").optional().nullable(),
984
- initialMileage: num().min(0, "Initial mileage must be non-negative").max(1e7, "Initial mileage too large").optional().nullable(),
985
- currentMileage: num().min(0, "Current mileage must be non-negative").max(1e7, "Current mileage too large").optional().nullable(),
986
- status: vehicleStatusEnum.default("active"),
987
- notes: z2.string().max(1e3, "Notes too long").optional().nullable()
988
- });
989
- var refuelSchema = z2.object({
990
- id: optionalId,
991
- busId: optionalId,
992
- refuelDate: dateField,
993
- quantity: num().positive("Quantity must be greater than 0").max(1e4, "Quantity too large"),
994
- unitPrice: num().positive("Unit price must be greater than 0").max(1e5, "Unit price too large"),
995
- totalCost: num().positive("Total cost must be greater than 0").max(1e7, "Total cost too large").optional(),
996
- fuelType: fuelTypeEnum.default("diesel"),
997
- odometer: num().min(0, "Odometer must be non-negative").max(1e7, "Odometer value too large").optional().nullable(),
998
- fuelStation: z2.string().max(200, "Fuel station name too long").optional().nullable(),
999
- invoiceNumber: z2.string().max(100, "Invoice number too long").optional().nullable(),
1000
- paymentMethod: paymentMethodEnum.optional().nullable(),
1001
- paidBy: optionalId.nullable(),
1002
- status: refuelStatusEnum.default("completed"),
1003
- notes: z2.string().max(1e3, "Notes too long").optional().nullable()
1004
- });
1005
- var settingsSchema = z2.object({
1006
- // School Information
1007
- schoolName: z2.string().min(2, "School name must be at least 2 characters").max(200, "School name too long"),
1008
- schoolAddress: z2.string().max(500, "School address too long").optional(),
1009
- schoolPhone: phoneField,
1010
- schoolEmail: emailField,
1011
- schoolWebsite: z2.string().url("Must be a valid URL").max(255, "School website URL too long").optional(),
1012
- // New
1013
- schoolLogo: z2.string().url("Must be a valid image URL").max(255, "School logo URL too long").optional(),
1014
- // New
1015
- currentAcademicYear: academicYearField,
1016
- // Academic Settings
1017
- gradingScale: z2.any().optional(),
1018
- attendanceRequirement: num().min(0, "Attendance requirement must be non-negative").max(100, "Attendance requirement cannot exceed 100").default(75),
1019
- maxClassSize: num().int("Max class size must be an integer").min(1, "Max class size must be at least 1").max(200, "Max class size cannot exceed 200").default(34),
1020
- minimumPassingGrade: num().min(0, "Minimum passing grade must be non-negative").max(100, "Minimum passing grade cannot exceed 100").default(60),
1021
- defaultExamDuration: num().int("Default exam duration must be in minutes").min(15, "Exam duration must be at least 15 minutes").max(480, "Exam duration cannot exceed 480 minutes").default(120),
1022
- calendarSystem: calendarSystemEnum.default("SEMESTER"),
1023
- startMonth: z2.string().default("september"),
1024
- endMonth: z2.string().default("june"),
1025
- // Notification Settings
1026
- academicAlerts: z2.boolean().default(true),
1027
- attendanceAlerts: z2.boolean().default(true),
1028
- eventAlerts: z2.boolean().default(true),
1029
- homeworkAlerts: z2.boolean().default(true),
1030
- feesReminder: z2.boolean().default(true),
1031
- feesOverdueAlerts: z2.boolean().default(true),
1032
- emailNotifications: z2.boolean().default(true),
1033
- smsNotifications: z2.boolean().default(false),
1034
- parentNotifications: z2.boolean().default(true),
1035
- lowGradeAlerts: z2.boolean().default(true),
1036
- allowLateSubmission: z2.boolean().default(true),
1037
- examResultsAlerts: z2.boolean().default(true),
1038
- disciplinaryAlerts: z2.boolean().default(true),
1039
- achievementAlerts: z2.boolean().default(true),
1040
- maintenanceNotifications: z2.boolean().default(true),
1041
- // Security Settings
1042
- twoFactorEnabled: z2.boolean().default(false),
1043
- sessionTimeout: z2.string().regex(/^\d{1,4}$/, "Session timeout must be a number between 1-9999 minutes").default("60"),
1044
- passwordRequireSymbols: z2.boolean().default(true),
1045
- loginNotifications: z2.boolean().default(true),
1046
- parentAccessEnabled: z2.boolean().default(true),
1047
- teacherAccessEnabled: z2.boolean().default(true),
1048
- studentAccessEnabled: z2.boolean().default(true),
1049
- // System Preferences
1050
- timeZone: z2.string().min(1, "Time zone is required").default("UTC"),
1051
- language: languageEnum.default("en"),
1052
- theme: z2.enum(["light", "dark", "system"]).default("system"),
1053
- dateFormat: z2.enum(["YYYY-MM-DD", "MM/DD/YYYY", "DD/MM/YYYY", "DD-MM-YY", "DD-MM-YYYY"]).default("MM/DD/YYYY"),
1054
- // Adjusted default to match table
1055
- timeFormat: z2.enum(["12", "24"]).default("12"),
1056
- currency: z2.string().length(3, "Currency must be a 3-letter ISO code").regex(/^[A-Z]{3}$/, "Currency must be uppercase ISO code").default("USD"),
1057
- // Academic Calendar Settings
1058
- gradingPeriods: num().int("Grading periods must be an integer").min(1, "Grading periods must be at least 1").max(12, "Grading periods cannot exceed 12").default(4),
1059
- schoolStartTime: z2.string().regex(/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/, "Invalid start time format (HH:MM)").default("08:00"),
1060
- schoolEndTime: z2.string().regex(/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/, "Invalid end time format (HH:MM)").default("15:00"),
1061
- lunchBreakDuration: num().int("Lunch break duration must be in minutes").min(15, "Lunch break must be at least 15 minutes").max(120, "Lunch break cannot exceed 120 minutes").default(30),
1062
- // Maintenance & Backup Settings
1063
- maintenanceMode: z2.boolean().default(false),
1064
- autoBackup: z2.boolean().default(true)
1065
- });
1066
- var idParamSchema = z2.object({
1067
- id: optionalId
1068
- });
1069
- var paginationSchema = z2.object({
1070
- page: num().int().min(1).default(1),
1071
- limit: num().int().min(1).max(100).default(10)
1072
- });
1073
- var dateRangeSchema = z2.object({
1074
- dateFrom: dateField,
1075
- dateTo: dateField
1076
- });
1077
-
1078
- // src/database/schema/index.ts
1079
- import { pgTable, text, boolean, timestamp } from "drizzle-orm/pg-core";
1080
- import { nanoid } from "nanoid";
1081
- import { sql } from "drizzle-orm";
1082
-
1083
- // src/database/schema/PgEnum.ts
1084
- import { pgEnum } from "drizzle-orm/pg-core";
1085
- var createPgEnum = (enumKey) => {
1086
- const config = getEnumConfig(enumKey);
1087
- if (!config) throw new Error(`Enum ${enumKey} not found`);
1088
- const enumName = config.name || enumKey;
1089
- return pgEnum(enumName, config.values);
1090
- };
1091
- var userStatusEnum2 = createPgEnum("userStatus");
1092
- var tokenStatusEnum2 = createPgEnum("tokenStatus");
1093
- var tokenTypeEnum2 = createPgEnum("tokenType");
1094
- var studentStatusEnum2 = createPgEnum("studentStatus");
1095
-
1096
- // src/database/schema/index.ts
1097
- var timestamps = {
1098
- createdAt: timestamp("created_at", { mode: "string" }).defaultNow(),
1099
- updatedAt: timestamp("updated_at", { mode: "string" }).defaultNow().$onUpdate(() => sql`CURRENT_TIMESTAMP`)
1100
- };
1101
- var idField = (length = 5) => text("id").primaryKey().notNull().$defaultFn(() => nanoid(length));
1102
- var rolesTable = pgTable("roles", {
1103
- id: idField(),
1104
- name: text("name").notNull(),
1105
- description: text("description")
1106
- });
1107
- var usersTable = pgTable("users", {
1108
- id: idField(8),
1109
- email: text("email").notNull().unique(),
1110
- emailVerified: boolean("email_verified").default(false),
1111
- password: text("password").notNull(),
1112
- image: text("image").default("noavatar.png"),
1113
- status: userStatusEnum2("status").default("pending"),
1114
- roleId: text("role_id").references(() => rolesTable.id),
1115
- lastLogin: timestamp("last_login", { mode: "string" }),
1116
- ...timestamps
1117
- });
1118
- var tokensTable = pgTable("tokens", {
1119
- id: idField(10),
1120
- userId: text("user_id").references(() => usersTable.id, { onDelete: "cascade" }).unique().notNull(),
1121
- token: text("token").notNull(),
1122
- type: tokenTypeEnum2("type").default("refresh"),
1123
- status: tokenStatusEnum2("status").default("active"),
1124
- expiresAt: timestamp("expires_at", { mode: "string" }).notNull(),
1125
- ...timestamps
1126
- });
1127
- var permissionsTable = pgTable("permissions", {
1128
- id: idField(),
1129
- name: text("name").notNull().unique(),
1130
- description: text("description"),
1131
- resource: text("resource").notNull(),
1132
- action: text("action").notNull(),
1133
- ...timestamps
1134
- });
1135
- var rolePermissionsTable = pgTable("role_permissions", {
1136
- id: idField(),
1137
- roleId: text("role_id").references(() => rolesTable.id).notNull(),
1138
- permissionId: text("permission_id").references(() => permissionsTable.id).notNull(),
1139
- ...timestamps
1140
- });
1141
-
1142
- // src/permissions/PermissionRepository.ts
1143
- import { eq, and } from "drizzle-orm";
1144
- import { Repository } from "najm-api";
1145
- var PermissionRepository = class {
1146
- async getAll() {
1147
- return await this.db.select().from(permissionsTable);
1148
- }
1149
- async getById(id) {
1150
- const [existingPermission] = await this.db.select().from(permissionsTable).where(eq(permissionsTable.id, id));
1151
- return existingPermission;
1152
- }
1153
- async getByName(name) {
1154
- const [existingPermission] = await this.db.select().from(permissionsTable).where(eq(permissionsTable.name, name));
1155
- return existingPermission;
1156
- }
1157
- async create(data) {
1158
- const [newPermission] = await this.db.insert(permissionsTable).values(data).returning();
1159
- return newPermission;
1160
- }
1161
- async update(id, data) {
1162
- const [updatedPermission] = await this.db.update(permissionsTable).set(data).where(eq(permissionsTable.id, id)).returning();
1163
- return updatedPermission;
1164
- }
1165
- async delete(id) {
1166
- const [deletedPermission] = await this.db.delete(permissionsTable).where(eq(permissionsTable.id, id)).returning();
1167
- return deletedPermission;
1168
- }
1169
- async getPermissionsByRole(roleId) {
1170
- return await this.db.select({
1171
- id: permissionsTable.id,
1172
- name: permissionsTable.name,
1173
- description: permissionsTable.description,
1174
- resource: permissionsTable.resource,
1175
- action: permissionsTable.action
1176
- }).from(rolePermissionsTable).leftJoin(permissionsTable, eq(rolePermissionsTable.permissionId, permissionsTable.id)).where(eq(rolePermissionsTable.roleId, roleId));
1177
- }
1178
- async getRolesByPermission(permissionId) {
1179
- return await this.db.select({
1180
- id: rolesTable.id,
1181
- name: rolesTable.name,
1182
- description: rolesTable.description
1183
- }).from(rolePermissionsTable).leftJoin(rolesTable, eq(rolePermissionsTable.roleId, rolesTable.id)).where(eq(rolePermissionsTable.permissionId, permissionId));
1184
- }
1185
- async assignPermissionToRole(roleId, permissionId) {
1186
- const [newRolePermission] = await this.db.insert(rolePermissionsTable).values({ roleId, permissionId }).returning();
1187
- return newRolePermission;
1188
- }
1189
- async removePermissionFromRole(roleId, permissionId) {
1190
- const [deletedRolePermission] = await this.db.delete(rolePermissionsTable).where(and(eq(rolePermissionsTable.roleId, roleId), eq(rolePermissionsTable.permissionId, permissionId))).returning();
1191
- return deletedRolePermission;
1192
- }
1193
- async checkRoleHasPermission(roleId, permissionId) {
1194
- const [rolePermission] = await this.db.select().from(rolePermissionsTable).where(and(eq(rolePermissionsTable.roleId, roleId), eq(rolePermissionsTable.permissionId, permissionId)));
1195
- return !!rolePermission;
1196
- }
1197
- async deleteAll() {
1198
- await this.db.delete(rolePermissionsTable);
1199
- const deletedPermissions = await this.db.delete(permissionsTable).returning();
1200
- return deletedPermissions;
1201
- }
1202
- };
1203
- PermissionRepository = __decorateClass([
1204
- Repository()
1205
- ], PermissionRepository);
1206
-
1207
- // src/permissions/PermissionGuards.ts
1208
- import { createGuard as createGuard2, Injectable as Injectable5, GuardParams as GuardParams2, Headers as Headers2, Ctx as Ctx2 } from "najm-api";
1209
- var PermissionGuards = class {
1210
- constructor(tokenService) {
1211
- this.tokenService = tokenService;
1212
- }
1213
- async getUserPermissions(auth) {
1214
- const permissions = await this.tokenService.getUserPermissions(auth);
1215
- if (!permissions || !Array.isArray(permissions)) return null;
1216
- return permissions;
1217
- }
1218
- checkPermissionMatch(permissions, requiredPermission) {
1219
- if (permissions.includes(requiredPermission)) {
1220
- return true;
1221
- }
1222
- const [requiredAction, requiredResource] = requiredPermission.split(":");
1223
- if (requiredAction && requiredResource) {
1224
- if (permissions.includes(`${requiredAction}:*`)) {
1225
- return true;
1226
- }
1227
- if (permissions.includes(`*:${requiredResource}`)) {
1228
- return true;
1229
- }
1230
- }
1231
- if (permissions.includes("*:*")) {
1232
- return true;
1233
- }
1234
- return false;
1235
- }
1236
- async hasPermission(auth, ctx, requiredPermission) {
1237
- await this.tokenService.storeUserInCache(auth, ctx);
1238
- const permissions = await this.getUserPermissions(auth);
1239
- if (!permissions) return false;
1240
- const check = this.checkPermissionMatch(permissions, requiredPermission);
1241
- return check;
1242
- }
1243
- };
1244
- __decorateClass([
1245
- __decorateParam(0, Headers2("authorization")),
1246
- __decorateParam(1, Ctx2()),
1247
- __decorateParam(2, GuardParams2())
1248
- ], PermissionGuards.prototype, "hasPermission", 1);
1249
- PermissionGuards = __decorateClass([
1250
- Injectable5()
1251
- ], PermissionGuards);
1252
- var Permission = (...permissions) => createGuard2(PermissionGuards, "hasPermission")(...permissions);
1253
-
1254
- // src/permissions/PermissionController.ts
1255
- import { Controller as Controller2, Get as Get2, Post as Post2, Put, Delete, Params as Params2, Body as Body2, t as t3 } from "najm-api";
1256
- var PermissionController = class {
1257
- constructor(permissionService) {
1258
- this.permissionService = permissionService;
1259
- }
1260
- async getPermissions() {
1261
- const permissions = await this.permissionService.getAll();
1262
- return {
1263
- data: permissions,
1264
- message: t3("permissions.success.retrieved"),
1265
- status: "success"
1266
- };
1267
- }
1268
- async getPermission(id) {
1269
- const permission = await this.permissionService.getById(id);
1270
- return {
1271
- data: permission,
1272
- message: t3("permissions.success.retrieved"),
1273
- status: "success"
1274
- };
1275
- }
1276
- async create(body) {
1277
- const newPermission = await this.permissionService.create(body);
1278
- return {
1279
- data: newPermission,
1280
- message: t3("permissions.success.created"),
1281
- status: "success"
1282
- };
1283
- }
1284
- async update(id, body) {
1285
- const updatedPermission = await this.permissionService.update(id, body);
1286
- return {
1287
- data: updatedPermission,
1288
- message: t3("permissions.success.updated"),
1289
- status: "success"
1290
- };
1291
- }
1292
- async delete(id) {
1293
- const result = await this.permissionService.delete(id);
1294
- return {
1295
- data: result,
1296
- message: t3("permissions.success.deleted"),
1297
- status: "success"
1298
- };
1299
- }
1300
- async getByRole(roleId) {
1301
- const permissions = await this.permissionService.getPermissionsByRole(roleId);
1302
- return {
1303
- data: permissions,
1304
- message: t3("permissions.success.retrieved"),
1305
- status: "success"
1306
- };
1307
- }
1308
- async getRolesByPermission(permissionId) {
1309
- const roles = await this.permissionService.getRolesByPermission(permissionId);
1310
- return {
1311
- data: roles,
1312
- message: t3("permissions.success.retrieved"),
1313
- status: "success"
1314
- };
1315
- }
1316
- async assignToRole(roleId, permissionId) {
1317
- const result = await this.permissionService.assignPermissionToRole(roleId, permissionId);
1318
- return {
1319
- data: result,
1320
- message: t3("permissions.success.assigned"),
1321
- status: "success"
1322
- };
1323
- }
1324
- async removeFromRole(roleId, permissionId) {
1325
- const result = await this.permissionService.removePermissionFromRole(roleId, permissionId);
1326
- return {
1327
- data: result,
1328
- message: t3("permissions.success.removed"),
1329
- status: "success"
1330
- };
1331
- }
1332
- async deleteAll() {
1333
- const result = await this.permissionService.deleteAll();
1334
- return {
1335
- data: result,
1336
- message: t3("permissions.success.allDeleted"),
1337
- status: "success"
1338
- };
1339
- }
1340
- };
1341
- __decorateClass([
1342
- Get2()
1343
- ], PermissionController.prototype, "getPermissions", 1);
1344
- __decorateClass([
1345
- Get2("/:id"),
1346
- __decorateParam(0, Params2("id"))
1347
- ], PermissionController.prototype, "getPermission", 1);
1348
- __decorateClass([
1349
- Post2(),
1350
- __decorateParam(0, Body2())
1351
- ], PermissionController.prototype, "create", 1);
1352
- __decorateClass([
1353
- Put("/:id"),
1354
- __decorateParam(0, Params2("id")),
1355
- __decorateParam(1, Body2())
1356
- ], PermissionController.prototype, "update", 1);
1357
- __decorateClass([
1358
- Delete("/:id"),
1359
- __decorateParam(0, Params2("id"))
1360
- ], PermissionController.prototype, "delete", 1);
1361
- __decorateClass([
1362
- Get2("/role/:roleId"),
1363
- __decorateParam(0, Params2("roleId"))
1364
- ], PermissionController.prototype, "getByRole", 1);
1365
- __decorateClass([
1366
- Get2("/roles/:permissionId"),
1367
- __decorateParam(0, Params2("permissionId"))
1368
- ], PermissionController.prototype, "getRolesByPermission", 1);
1369
- __decorateClass([
1370
- Post2("/assign/:roleId/:permissionId"),
1371
- __decorateParam(0, Params2("roleId")),
1372
- __decorateParam(1, Params2("permissionId"))
1373
- ], PermissionController.prototype, "assignToRole", 1);
1374
- __decorateClass([
1375
- Delete("/remove/:roleId/:permissionId"),
1376
- __decorateParam(0, Params2("roleId")),
1377
- __decorateParam(1, Params2("permissionId"))
1378
- ], PermissionController.prototype, "removeFromRole", 1);
1379
- __decorateClass([
1380
- Delete(),
1381
- isAdmin()
1382
- ], PermissionController.prototype, "deleteAll", 1);
1383
- PermissionController = __decorateClass([
1384
- Controller2("/permissions"),
1385
- isAdmin()
1386
- ], PermissionController);
1387
-
1388
- // src/permissions/PermissionService.ts
1389
- import { Injectable as Injectable6 } from "najm-api";
1390
- var PermissionService = class {
1391
- constructor(permissionRepository, permissionValidator, roleService) {
1392
- this.permissionRepository = permissionRepository;
1393
- this.permissionValidator = permissionValidator;
1394
- this.roleService = roleService;
1395
- }
1396
- async getAll() {
1397
- return await this.permissionRepository.getAll();
1398
- }
1399
- async getById(id) {
1400
- await this.permissionValidator.checkPermissionExists(id);
1401
- return await this.permissionRepository.getById(id);
1402
- }
1403
- async getByName(name) {
1404
- return await this.permissionRepository.getByName(name);
1405
- }
1406
- async getByResource(resource) {
1407
- return await this.permissionRepository.getAll().then(
1408
- (permissions) => permissions.filter((p) => p.resource === resource)
1409
- );
1410
- }
1411
- async create(data) {
1412
- await this.permissionValidator.validateCreatePermission(data);
1413
- await this.permissionValidator.checkPermissionNameUnique(data.name);
1414
- return await this.permissionRepository.create(data);
1415
- }
1416
- async update(id, data) {
1417
- await this.permissionValidator.checkPermissionExists(id);
1418
- await this.permissionValidator.checkPermissionNameUnique(data.name, id);
1419
- return await this.permissionRepository.update(id, data);
1420
- }
1421
- async delete(id) {
1422
- await this.permissionValidator.checkPermissionExists(id);
1423
- return await this.permissionRepository.delete(id);
1424
- }
1425
- async getPermissionsByRole(roleId) {
1426
- return await this.permissionRepository.getPermissionsByRole(roleId);
1427
- }
1428
- async getRolesByPermission(permissionId) {
1429
- await this.permissionValidator.checkPermissionExists(permissionId);
1430
- return await this.permissionRepository.getRolesByPermission(permissionId);
1431
- }
1432
- async assignPermissionToRole(roleId, permissionId) {
1433
- await this.permissionValidator.checkRoleHasPermission(roleId, permissionId);
1434
- return await this.permissionRepository.assignPermissionToRole(roleId, permissionId);
1435
- }
1436
- async removePermissionFromRole(roleId, permissionId) {
1437
- return await this.permissionRepository.removePermissionFromRole(roleId, permissionId);
1438
- }
1439
- async seedDefaultPermissions(defaultPermissions) {
1440
- const createdPermissions = [];
1441
- for (const permission of defaultPermissions) {
1442
- try {
1443
- const permissionEntity = await this.create(permission);
1444
- createdPermissions.push(permissionEntity);
1445
- } catch (error) {
1446
- continue;
1447
- }
1448
- }
1449
- return createdPermissions;
1450
- }
1451
- async seedDefaultRolePermissions(defaultRolePermissions) {
1452
- const results = [];
1453
- for (const { roleName, permissions } of defaultRolePermissions) {
1454
- try {
1455
- await this.permissionValidator.checkRoleExistsByName(roleName);
1456
- const role = await this.roleService.getByName(roleName);
1457
- for (const permissionName of permissions) {
1458
- try {
1459
- await this.permissionValidator.checkPermissionExistsByName(permissionName);
1460
- const permission = await this.getByName(permissionName);
1461
- await this.permissionValidator.checkRoleHasPermission(role.id, permission.id);
1462
- await this.assignPermissionToRole(role.id, permission.id);
1463
- results.push({ role: roleName, permission: permissionName });
1464
- } catch (error) {
1465
- continue;
1466
- }
1467
- }
1468
- } catch (error) {
1469
- continue;
1470
- }
1471
- }
1472
- return results;
1473
- }
1474
- async deleteAll() {
1475
- return await this.permissionRepository.deleteAll();
1476
- }
1477
- };
1478
- PermissionService = __decorateClass([
1479
- Injectable6()
1480
- ], PermissionService);
1481
-
1482
- // src/permissions/PermissionValidator.ts
1483
- import { Injectable as Injectable7, t as t4 } from "najm-api";
1484
-
1485
- // src/shared/index.ts
1486
- import * as fs from "fs/promises";
1487
- import * as path from "path";
1488
- import _isEmpty from "lodash.isempty";
1489
- var avatarsPath = path.join(process.cwd(), "avatars");
1490
- var parseSchema = async (schema, data) => {
1491
- try {
1492
- return await schema.parseAsync(data);
1493
- } catch (error) {
1494
- const errors = error.issues || error.errors || [];
1495
- const errorMessage = errors.map((err) => `${err.path.join(".")}: ${err.message}`).join("; ");
1496
- throw new Error(errorMessage);
1497
- }
1498
- };
1499
- var clean = (obj) => {
1500
- const cleaned = {};
1501
- for (const [key, value] of Object.entries(obj)) {
1502
- if (value !== null && value !== void 0 && value !== "") {
1503
- cleaned[key] = value;
1504
- }
1505
- }
1506
- return cleaned;
1507
- };
1508
- var getAvatarFile = async (fileName) => {
1509
- try {
1510
- const filePath = path.join(avatarsPath, fileName);
1511
- const buffer = await fs.readFile(filePath);
1512
- const file = new File([buffer], fileName, {
1513
- type: "image/png"
1514
- });
1515
- return file;
1516
- } catch (error) {
1517
- return null;
1518
- }
1519
- };
1520
- var formatDate = (dateValue) => {
1521
- if (!dateValue) return null;
1522
- let date;
1523
- if (dateValue instanceof Date) {
1524
- date = dateValue;
1525
- } else if (typeof dateValue === "string") {
1526
- date = new Date(dateValue);
1527
- } else {
1528
- return null;
1529
- }
1530
- if (isNaN(date.getTime())) return null;
1531
- return date.toISOString().split("T")[0];
1532
- };
1533
- function calculateAge(dateOfBirth) {
1534
- if (!dateOfBirth) return null;
1535
- const formattedDate = formatDate(dateOfBirth);
1536
- if (!formattedDate) return null;
1537
- const birth = new Date(formattedDate);
1538
- const today = /* @__PURE__ */ new Date();
1539
- let age = today.getFullYear() - birth.getFullYear();
1540
- const monthDiff = today.getMonth() - birth.getMonth();
1541
- if (monthDiff < 0 || monthDiff === 0 && today.getDate() < birth.getDate()) {
1542
- age--;
1543
- }
1544
- return age;
1545
- }
1546
- function calculateYearsOfExperience(hireDate) {
1547
- if (!hireDate) return null;
1548
- const formattedDate = formatDate(hireDate);
1549
- if (!formattedDate) return null;
1550
- const hire = new Date(formattedDate);
1551
- const today = /* @__PURE__ */ new Date();
1552
- let years = today.getFullYear() - hire.getFullYear();
1553
- const monthDiff = today.getMonth() - hire.getMonth();
1554
- if (monthDiff < 0 || monthDiff === 0 && today.getDate() < hire.getDate()) {
1555
- years--;
1556
- }
1557
- return years;
1558
- }
1559
- function pickProps(source, keys) {
1560
- const result = {};
1561
- for (const key of keys) {
1562
- if (source[key] !== void 0) {
1563
- result[key] = source[key];
1564
- }
1565
- }
1566
- return result;
1567
- }
1568
- var isEmpty = _isEmpty;
1569
- var isPath = (img) => typeof img === "string" && img.trim().length > 0 && (img.startsWith("/") || img.startsWith("http") || img.startsWith("storage/"));
1570
- var isFile = (img) => !!img && typeof img !== "string" && img instanceof File;
1571
-
1572
- // src/permissions/PermissionValidator.ts
1573
- import { z as z3 } from "zod";
1574
- var permissionSchema = z3.object({
1575
- name: z3.string().min(1, "Permission name is required"),
1576
- description: z3.string().optional(),
1577
- resource: z3.string().min(1, "Resource is required"),
1578
- action: z3.string().min(1, "Action is required")
1579
- });
1580
- var PermissionValidator = class {
1581
- constructor(permissionRepository, roleValidator) {
1582
- this.permissionRepository = permissionRepository;
1583
- this.roleValidator = roleValidator;
1584
- }
1585
- async validateCreatePermission(data) {
1586
- return parseSchema(permissionSchema, data);
1587
- }
1588
- async isPermissionExists(id) {
1589
- const existingPermission = await this.permissionRepository.getById(id);
1590
- return !!existingPermission;
1591
- }
1592
- async isPermissionNameExists(name) {
1593
- const existingPermission = await this.permissionRepository.getByName(name);
1594
- return !!existingPermission;
1595
- }
1596
- //======================= throw errors
1597
- async checkPermissionExists(id) {
1598
- const permissionExists = await this.isPermissionExists(id);
1599
- if (!permissionExists) {
1600
- throw new Error(t4("permissions.errors.notFound"));
1601
- }
1602
- return permissionExists;
1603
- }
1604
- async checkPermissionExistsByName(name) {
1605
- const permissionExists = await this.isPermissionNameExists(name);
1606
- if (!permissionExists) {
1607
- throw new Error(t4("permissions.errors.notFound"));
1608
- }
1609
- return permissionExists;
1610
- }
1611
- async checkPermissionNameUnique(name, excludeId = null) {
1612
- if (!name) return;
1613
- const existingPermission = await this.permissionRepository.getByName(name);
1614
- if (existingPermission && existingPermission.id !== excludeId) {
1615
- throw new Error(t4("permissions.errors.nameExists"));
1616
- }
1617
- }
1618
- async checkRoleExists(id) {
1619
- return await this.roleValidator.checkRoleExists(id);
1620
- }
1621
- async checkRoleExistsByName(name) {
1622
- return await this.roleValidator.checkRoleExistsByName(name);
1623
- }
1624
- async checkRoleHasPermission(roleId, permissionId) {
1625
- await this.roleValidator.checkRoleExists(roleId);
1626
- await this.checkPermissionExists(permissionId);
1627
- const hasPermission = await this.permissionRepository.checkRoleHasPermission(roleId, permissionId);
1628
- if (hasPermission) {
1629
- throw new Error(t4("permissions.errors.roleAlreadyHasPermission"));
1630
- }
1631
- }
1632
- };
1633
- PermissionValidator = __decorateClass([
1634
- Injectable7()
1635
- ], PermissionValidator);
1636
-
1637
- // src/roles/RoleRepository.ts
1638
- import { eq as eq2 } from "drizzle-orm";
1639
- import { Repository as Repository2 } from "najm-api";
1640
- var RoleRepository = class {
1641
- async getAll() {
1642
- return await this.db.select().from(rolesTable);
1643
- }
1644
- async getById(id) {
1645
- const [existingRole] = await this.db.select().from(rolesTable).where(eq2(rolesTable.id, id));
1646
- return existingRole;
1647
- }
1648
- async getByName(name) {
1649
- const [existingRole] = await this.db.select().from(rolesTable).where(eq2(rolesTable.name, name));
1650
- return existingRole;
1651
- }
1652
- async create(data) {
1653
- const [newRole] = await this.db.insert(rolesTable).values(data).returning();
1654
- return newRole;
1655
- }
1656
- async update(id, data) {
1657
- const [updatedRole] = await this.db.update(rolesTable).set(data).where(eq2(rolesTable.id, id)).returning();
1658
- return updatedRole;
1659
- }
1660
- async delete(id) {
1661
- const [deletedRole] = await this.db.delete(rolesTable).where(eq2(rolesTable.id, id)).returning();
1662
- return deletedRole;
1663
- }
1664
- };
1665
- RoleRepository = __decorateClass([
1666
- Repository2()
1667
- ], RoleRepository);
1668
-
1669
- // src/roles/RoleValidator.ts
1670
- import { Injectable as Injectable8, t as t5 } from "najm-api";
1671
- var RoleValidator = class {
1672
- constructor(roleRepository) {
1673
- this.roleRepository = roleRepository;
1674
- }
1675
- async validateCreateRole(data) {
1676
- return parseSchema(roleSchema, data);
1677
- }
1678
- async isRoleNameExists(roleName) {
1679
- const existingRole = await this.roleRepository.getByName(roleName);
1680
- return !!existingRole;
1681
- }
1682
- async isRoleIdExists(id) {
1683
- const existingRole = await this.roleRepository.getById(id);
1684
- return !!existingRole;
1685
- }
1686
- async checkNameUnique(roleName, excludeId = null) {
1687
- if (!roleName) return;
1688
- const existingRole = await this.roleRepository.getByName(roleName);
1689
- if (existingRole && existingRole.id !== excludeId) {
1690
- throw new Error(t5("roles.errors.exists"));
1691
- }
1692
- }
1693
- async checkRoleExists(id) {
1694
- const roleIdExists = await this.isRoleIdExists(id);
1695
- if (!roleIdExists) {
1696
- throw new Error(t5("roles.errors.notFound"));
1697
- }
1698
- }
1699
- async checkRoleExistsByName(roleName) {
1700
- const roleNameExists = await this.isRoleNameExists(roleName);
1701
- if (!roleNameExists) {
1702
- throw new Error(t5("roles.errors.notFound"));
1703
- }
1704
- }
1705
- async checkAdminRoleExists() {
1706
- const adminRole = await this.roleRepository.getByName("admin");
1707
- if (!adminRole) {
1708
- throw new Error(t5("users.errors.adminRoleNotFound"));
1709
- }
1710
- return adminRole;
1711
- }
1712
- };
1713
- RoleValidator = __decorateClass([
1714
- Injectable8()
1715
- ], RoleValidator);
1716
-
1717
- // src/roles/RoleController.ts
1718
- import { Controller as Controller3, Get as Get3, Post as Post3, Put as Put2, Delete as Delete2, Params as Params3, Body as Body3, t as t6 } from "najm-api";
1719
- var RoleController = class {
1720
- constructor(roleService) {
1721
- this.roleService = roleService;
1722
- }
1723
- async getRoles() {
1724
- const roles = await this.roleService.getAll();
1725
- return {
1726
- data: roles,
1727
- message: t6("roles.success.retrieved"),
1728
- status: "success"
1729
- };
1730
- }
1731
- async getRole(id) {
1732
- const role = await this.roleService.getById(id);
1733
- return {
1734
- data: role,
1735
- message: t6("roles.success.retrieved"),
1736
- status: "success"
1737
- };
1738
- }
1739
- async createRole(body) {
1740
- const newRole = await this.roleService.create(body);
1741
- return {
1742
- data: newRole,
1743
- message: t6("roles.success.created"),
1744
- status: "success"
1745
- };
1746
- }
1747
- async updateRole(id, body) {
1748
- const updatedRole = await this.roleService.update(id, body);
1749
- return {
1750
- data: updatedRole,
1751
- message: t6("roles.success.updated"),
1752
- status: "success"
1753
- };
1754
- }
1755
- async deleteRole(id) {
1756
- const result = await this.roleService.delete(id);
1757
- return {
1758
- data: result,
1759
- message: t6("roles.success.deleted"),
1760
- status: "success"
1761
- };
1762
- }
1763
- };
1764
- __decorateClass([
1765
- Get3(),
1766
- isAdmin()
1767
- ], RoleController.prototype, "getRoles", 1);
1768
- __decorateClass([
1769
- Get3("/:id"),
1770
- isAdmin(),
1771
- __decorateParam(0, Params3("id"))
1772
- ], RoleController.prototype, "getRole", 1);
1773
- __decorateClass([
1774
- Post3(),
1775
- isAdmin(),
1776
- __decorateParam(0, Body3())
1777
- ], RoleController.prototype, "createRole", 1);
1778
- __decorateClass([
1779
- Put2("/:id"),
1780
- isAdmin(),
1781
- __decorateParam(0, Params3("id")),
1782
- __decorateParam(1, Body3())
1783
- ], RoleController.prototype, "updateRole", 1);
1784
- __decorateClass([
1785
- Delete2("/:id"),
1786
- isAdmin(),
1787
- __decorateParam(0, Params3("id"))
1788
- ], RoleController.prototype, "deleteRole", 1);
1789
- RoleController = __decorateClass([
1790
- Controller3("/roles")
1791
- ], RoleController);
1792
-
1793
- // src/roles/RoleService.ts
1794
- import { Injectable as Injectable9 } from "najm-api";
1795
- var RoleService = class {
1796
- constructor(roleRepository, roleValidator) {
1797
- this.roleRepository = roleRepository;
1798
- this.roleValidator = roleValidator;
1799
- }
1800
- async getAll() {
1801
- return await this.roleRepository.getAll();
1802
- }
1803
- async getById(id) {
1804
- await this.roleValidator.checkRoleExists(id);
1805
- return await this.roleRepository.getById(id);
1806
- }
1807
- async getByName(name) {
1808
- return await this.roleRepository.getByName(name);
1809
- }
1810
- async create(data) {
1811
- await this.roleValidator.validateCreateRole(data);
1812
- await this.roleValidator.checkNameUnique(data.name);
1813
- return await this.roleRepository.create(data);
1814
- }
1815
- async update(id, data) {
1816
- await this.roleValidator.checkRoleExists(id);
1817
- await this.roleValidator.checkNameUnique(data.name, id);
1818
- return await this.roleRepository.update(id, data);
1819
- }
1820
- async delete(id) {
1821
- await this.roleValidator.checkRoleExists(id);
1822
- return await this.roleRepository.delete(id);
1823
- }
1824
- async seedDefaultRoles(defaultRoles) {
1825
- const rolesToCreate = [];
1826
- for (const role of defaultRoles) {
1827
- const exists = await this.roleValidator.isRoleNameExists(role.name);
1828
- if (!exists) {
1829
- rolesToCreate.push(role);
1830
- }
1831
- }
1832
- const createdRoles = await Promise.all(
1833
- rolesToCreate.map((role) => this.roleRepository.create(role))
1834
- );
1835
- return createdRoles;
1836
- }
1837
- async getRoleIdByName(name) {
1838
- const teacherRole = await this.getByName(name);
1839
- return teacherRole?.id;
1840
- }
1841
- };
1842
- RoleService = __decorateClass([
1843
- Injectable9()
1844
- ], RoleService);
1845
-
1846
- // src/tokens/TokenRepository.ts
1847
- import { eq as eq3 } from "drizzle-orm";
1848
- import { Repository as Repository3 } from "najm-api";
1849
- var TokenRepository = class {
1850
- async storeRefreshToken(tokenData) {
1851
- return await this.db.insert(tokensTable).values(tokenData).onConflictDoUpdate({
1852
- target: tokensTable.userId,
1853
- set: {
1854
- token: tokenData.token,
1855
- expiresAt: tokenData.expiresAt
1856
- }
1857
- }).returning();
1858
- }
1859
- async getRefreshToken(userId) {
1860
- const [token] = await this.db.select().from(tokensTable).where(eq3(tokensTable.userId, userId));
1861
- return token?.token;
1862
- }
1863
- async revokeToken(userId) {
1864
- const [deletedToken] = await this.db.delete(tokensTable).where(eq3(tokensTable.userId, userId)).returning();
1865
- return deletedToken;
1866
- }
1867
- async isUserExists(userId) {
1868
- const [user] = await this.db.select({ id: usersTable.id }).from(usersTable).where(eq3(usersTable.id, userId)).limit(1);
1869
- return !!user;
1870
- }
1871
- async getRoleNameById(userId) {
1872
- const [role] = await this.db.select({
1873
- roleName: rolesTable.name
1874
- }).from(usersTable).leftJoin(rolesTable, eq3(usersTable.roleId, rolesTable.id)).where(eq3(usersTable.id, userId)).limit(1);
1875
- return role?.roleName;
1876
- }
1877
- async getUserPermissions(userId) {
1878
- const [user] = await this.db.select({ roleId: usersTable.roleId }).from(usersTable).where(eq3(usersTable.id, userId)).limit(1);
1879
- if (!user || !user.roleId) return [];
1880
- const userPermissions = await this.db.select({
1881
- name: permissionsTable.name
1882
- }).from(rolePermissionsTable).leftJoin(permissionsTable, eq3(rolePermissionsTable.permissionId, permissionsTable.id)).where(eq3(rolePermissionsTable.roleId, user.roleId));
1883
- return userPermissions.map((p) => p.name).filter((name) => name);
1884
- }
1885
- async getUser(userId) {
1886
- const [user] = await this.db.select({
1887
- id: usersTable.id,
1888
- email: usersTable.email,
1889
- status: usersTable.status,
1890
- roleId: usersTable.roleId,
1891
- roleName: rolesTable.name,
1892
- createdAt: usersTable.createdAt,
1893
- updatedAt: usersTable.updatedAt
1894
- }).from(usersTable).leftJoin(rolesTable, eq3(usersTable.roleId, rolesTable.id)).where(eq3(usersTable.id, userId)).limit(1);
1895
- return user ? { ...user, role: user.roleName } : null;
1896
- }
1897
- };
1898
- TokenRepository = __decorateClass([
1899
- Repository3()
1900
- ], TokenRepository);
1901
-
1902
- // src/tokens/TokenService.ts
1903
- import { t as t7 } from "najm-api";
1904
- import { getCookie, Injectable as Injectable10 } from "najm-api";
1905
- import jwt from "jsonwebtoken";
1906
- import { jwtDecode } from "jwt-decode";
1907
- import timestring2 from "timestring";
1908
- var TokenService = class {
1909
- constructor(tokenRepository) {
1910
- this.tokenRepository = tokenRepository;
1911
- this.accessSecretKey = process.env.JWT_ACCESS_SECRET;
1912
- this.accessExpiresIn = process.env.ACCESS_EXPIRES_IN;
1913
- this.refreshSecretKey = process.env.JWT_REFRESH_SECRET;
1914
- this.refreshExpiresIn = process.env.REFRESH_EXPIRES_IN;
1915
- }
1916
- //==== Validate tokens
1917
- extractAccessToken(authorization) {
1918
- if (authorization && authorization.startsWith("Bearer")) {
1919
- return authorization.split(" ")[1];
1920
- }
1921
- throw new Error(t7("auth.errors.tokenMissing"));
1922
- }
1923
- verifyAccessToken(token) {
1924
- try {
1925
- return jwt.verify(token, this.accessSecretKey);
1926
- } catch (error) {
1927
- throw new Error(t7("auth.errors.tokenVerificationFailed"));
1928
- }
1929
- }
1930
- verifyRefreshToken(token) {
1931
- try {
1932
- const decoded = jwt.verify(token, this.refreshSecretKey);
1933
- return decoded.userId;
1934
- } catch (error) {
1935
- throw new Error(t7("auth.errors.tokenVerificationFailed"));
1936
- }
1937
- }
1938
- async getUserIdByAccessToken(header) {
1939
- const token = this.extractAccessToken(header);
1940
- const decodedToken = this.verifyAccessToken(token);
1941
- const userId = decodedToken.userId;
1942
- const userExists = await this.tokenRepository.isUserExists(userId);
1943
- if (!userExists) {
1944
- throw new Error(t7("users.errors.notFound"));
1945
- }
1946
- return userId;
1947
- }
1948
- //=== Generate tokens
1949
- async storeRefreshToken(userId, refreshToken) {
1950
- const expireInSecond = timestring2(this.refreshExpiresIn, "s");
1951
- const tokenData = {
1952
- userId,
1953
- token: refreshToken,
1954
- expiresAt: new Date(Date.now() + expireInSecond * 1e3).toISOString()
1955
- };
1956
- await this.tokenRepository.storeRefreshToken(tokenData);
1957
- }
1958
- getTokenExpire(token) {
1959
- return jwtDecode(token).exp;
1960
- }
1961
- generateAccessToken(data) {
1962
- const options = { expiresIn: this.accessExpiresIn };
1963
- return jwt.sign(data, this.accessSecretKey, options);
1964
- }
1965
- generateRefreshToken(data) {
1966
- const options = { expiresIn: this.refreshExpiresIn };
1967
- return jwt.sign(data, this.refreshSecretKey, options);
1968
- }
1969
- async generateTokens(userId) {
1970
- const tokenData = { userId };
1971
- const accessToken = await this.generateAccessToken(tokenData);
1972
- const refreshToken = await this.generateRefreshToken(tokenData);
1973
- const accessTokenExpiresAt = this.getTokenExpire(accessToken);
1974
- const refreshTokenExpiresAt = this.getTokenExpire(refreshToken);
1975
- await this.storeRefreshToken(userId, refreshToken);
1976
- return {
1977
- accessToken,
1978
- refreshToken,
1979
- accessTokenExpiresAt,
1980
- refreshTokenExpiresAt
1981
- };
1982
- }
1983
- async refreshTokens() {
1984
- const newRefreshToken = getCookie("refreshToken");
1985
- const userId = this.verifyRefreshToken(newRefreshToken);
1986
- const userExists = await this.tokenRepository.isUserExists(userId);
1987
- if (!userExists) {
1988
- throw new Error(t7("users.errors.notFound"));
1989
- }
1990
- const storedRefreshToken = await this.tokenRepository.getRefreshToken(userId);
1991
- if (newRefreshToken != storedRefreshToken) {
1992
- throw new Error(t7("auth.errors.refreshTokenInvalid"));
1993
- }
1994
- return await this.generateTokens(userId);
1995
- }
1996
- async revokeToken(userId) {
1997
- return await this.tokenRepository.revokeToken(userId);
1998
- }
1999
- async getUserPermissions(auth) {
2000
- if (!auth) return;
2001
- const userId = await this.getUserIdByAccessToken(auth);
2002
- const permissions = await this.tokenRepository.getUserPermissions(userId);
2003
- return permissions;
2004
- }
2005
- async getUserRole(auth) {
2006
- if (!auth) return;
2007
- const userId = await this.getUserIdByAccessToken(auth);
2008
- const roleName = await this.tokenRepository.getRoleNameById(userId);
2009
- return roleName;
2010
- }
2011
- async getUser(auth) {
2012
- if (!auth) return;
2013
- const userId = await this.getUserIdByAccessToken(auth);
2014
- const user = await this.tokenRepository.getUser(userId);
2015
- if (!user) return null;
2016
- return user;
2017
- }
2018
- async storeUserInCache(auth, ctx) {
2019
- const cachedUser = ctx.get("user");
2020
- if (cachedUser) return cachedUser;
2021
- const user = await this.getUser(auth);
2022
- if (user) {
2023
- ctx.set("user", user);
2024
- }
2025
- return user;
2026
- }
2027
- };
2028
- TokenService = __decorateClass([
2029
- Injectable10()
2030
- ], TokenService);
2031
-
2032
- // src/users/UserRepository.ts
2033
- import { eq as eq4, ne } from "drizzle-orm";
2034
- import { Repository as Repository4 } from "najm-api";
2035
- var UserRepository = class {
2036
- getUser() {
2037
- return {
2038
- id: usersTable.id,
2039
- email: usersTable.email,
2040
- emailVerified: usersTable.emailVerified,
2041
- image: usersTable.image,
2042
- status: usersTable.status,
2043
- roleId: usersTable.roleId,
2044
- role: rolesTable.name,
2045
- createdAt: usersTable.createdAt,
2046
- updatedAt: usersTable.updatedAt
2047
- };
2048
- }
2049
- async getAll() {
2050
- const allUsers = await this.db.select(this.getUser()).from(usersTable).leftJoin(rolesTable, eq4(usersTable.roleId, rolesTable.id));
2051
- return Promise.all(allUsers.map(async (user) => ({
2052
- ...user,
2053
- permissions: await this.getUserPermissions(user.id)
2054
- })));
2055
- }
2056
- async getById(id) {
2057
- const [user] = await this.db.select(this.getUser()).from(usersTable).leftJoin(rolesTable, eq4(usersTable.roleId, rolesTable.id)).where(eq4(usersTable.id, id)).limit(1);
2058
- if (!user) return user;
2059
- return {
2060
- ...user,
2061
- permissions: await this.getUserPermissions(user.id)
2062
- };
2063
- }
2064
- async getByEmail(email) {
2065
- const [existingUser] = await this.db.select(this.getUser()).from(usersTable).leftJoin(rolesTable, eq4(usersTable.roleId, rolesTable.id)).where(eq4(usersTable.email, email));
2066
- return existingUser;
2067
- }
2068
- async create(data) {
2069
- const [newUser] = await this.db.insert(usersTable).values(data).returning();
2070
- return newUser;
2071
- }
2072
- async update(id, data) {
2073
- const [updatedUser] = await this.db.update(usersTable).set(data).where(eq4(usersTable.id, id)).returning();
2074
- return updatedUser;
2075
- }
2076
- async delete(id) {
2077
- const [deletedUser] = await this.db.delete(usersTable).where(eq4(usersTable.id, id)).returning();
2078
- return deletedUser;
2079
- }
2080
- async deleteAll() {
2081
- const adminRole = await this.db.select({ id: rolesTable.id }).from(rolesTable).where(eq4(rolesTable.name, "admin")).limit(1);
2082
- if (adminRole.length === 0) {
2083
- const deletedUsers2 = await this.db.delete(usersTable).returning();
2084
- return deletedUsers2;
2085
- }
2086
- const deletedUsers = await this.db.delete(usersTable).where(ne(usersTable.roleId, adminRole[0].id)).returning();
2087
- return deletedUsers;
2088
- }
2089
- async getRoleNameById(userId) {
2090
- const [role] = await this.db.select({
2091
- roleName: rolesTable.name
2092
- }).from(usersTable).leftJoin(rolesTable, eq4(usersTable.roleId, rolesTable.id)).where(eq4(usersTable.id, userId));
2093
- return role.roleName;
2094
- }
2095
- async getUserPassword(email) {
2096
- const [user] = await this.db.select({
2097
- id: usersTable.id,
2098
- email: usersTable.email,
2099
- password: usersTable.password
2100
- }).from(usersTable).where(eq4(usersTable.email, email)).limit(1);
2101
- return user.password;
2102
- }
2103
- async getUserPermissions(userId) {
2104
- const [user] = await this.db.select({ roleId: usersTable.roleId }).from(usersTable).where(eq4(usersTable.id, userId)).limit(1);
2105
- if (!user || !user.roleId) return [];
2106
- const userPermissions = await this.db.select({
2107
- name: permissionsTable.name
2108
- }).from(rolePermissionsTable).leftJoin(permissionsTable, eq4(rolePermissionsTable.permissionId, permissionsTable.id)).where(eq4(rolePermissionsTable.roleId, user.roleId));
2109
- return userPermissions.map((p) => p.name).filter((name) => name);
2110
- }
2111
- };
2112
- UserRepository = __decorateClass([
2113
- Repository4()
2114
- ], UserRepository);
2115
-
2116
- // src/users/UserValidator.ts
2117
- import { Injectable as Injectable11, t as t8 } from "najm-api";
2118
- var UserValidator = class {
2119
- constructor(userRepository, encryptionService) {
2120
- this.userRepository = userRepository;
2121
- this.encryptionService = encryptionService;
2122
- }
2123
- async validateCreateUser(data) {
2124
- return parseSchema(userSchema, data);
2125
- }
2126
- async isEmailExists(email) {
2127
- const existingUser = await this.userRepository.getByEmail(email);
2128
- return !!existingUser;
2129
- }
2130
- async isPasswordValid(password, hashedPassword) {
2131
- const isPasswordValid = await this.encryptionService.comparePassword(password, hashedPassword);
2132
- return !!isPasswordValid;
2133
- }
2134
- async isUserExist(id) {
2135
- const existingUser = await this.userRepository.getById(id);
2136
- return !!existingUser;
2137
- }
2138
- async checkUserIdIsUnique(id) {
2139
- if (!id) return;
2140
- const existingUser = await this.userRepository.getById(id);
2141
- if (existingUser) {
2142
- throw new Error(t8("users.errors.idExists"));
2143
- }
2144
- }
2145
- async isCorrectPass(password) {
2146
- return password && typeof password === "string" && password.trim().length > 0;
2147
- }
2148
- async hasRole(userId, roles) {
2149
- const roleName = await this.userRepository.getRoleNameById(userId);
2150
- if (!roleName) {
2151
- throw Error(t8("auth.errors.accessDenied"));
2152
- }
2153
- const hasRole = roles.some(
2154
- (item) => roleName.toLowerCase() === item.toLowerCase()
2155
- );
2156
- if (!hasRole) {
2157
- throw Error(t8("auth.errors.accessDenied"));
2158
- }
2159
- return true;
2160
- }
2161
- //======================= throw errors
2162
- async checkUserExistsByEmail(email) {
2163
- const user = await this.userRepository.getByEmail(email);
2164
- if (!user) {
2165
- throw new Error(t8("auth.errors.invalidCredentials"));
2166
- }
2167
- return user;
2168
- }
2169
- async checkUserExists(id) {
2170
- const userExists = await this.isUserExist(id);
2171
- if (!userExists) {
2172
- throw new Error(t8("users.errors.notFound"));
2173
- }
2174
- return userExists;
2175
- }
2176
- async checkEmailUnique(email, excludeId = null) {
2177
- if (!email) return;
2178
- const existingUser = await this.userRepository.getByEmail(email);
2179
- if (existingUser && existingUser.id !== excludeId) {
2180
- throw new Error(t8("auth.errors.emailExists"));
2181
- }
2182
- }
2183
- async checkEmailExists(email) {
2184
- const user = await this.userRepository.getByEmail(email);
2185
- if (!user) {
2186
- throw new Error(t8("users.errors.notFound"));
2187
- }
2188
- return user;
2189
- }
2190
- async checkPasswordValid(password, hashedPassword) {
2191
- const isPasswordValid = await this.isPasswordValid(password, hashedPassword);
2192
- if (!isPasswordValid) {
2193
- throw new Error(t8("auth.errors.invalidCredentials"));
2194
- }
2195
- }
2196
- };
2197
- UserValidator = __decorateClass([
2198
- Injectable11()
2199
- ], UserValidator);
2200
-
2201
- // src/users/UserService.ts
2202
- import { Injectable as Injectable12, setLanguage, getCurrentLanguage as getCurrentLanguage2, Transactional } from "najm-api";
2203
- import { nanoid as nanoid2 } from "nanoid";
2204
- var UserService = class {
2205
- constructor(roleValidator, roleService, userRepository, userValidator, encryptionService) {
2206
- this.roleValidator = roleValidator;
2207
- this.roleService = roleService;
2208
- this.userRepository = userRepository;
2209
- this.userValidator = userValidator;
2210
- this.encryptionService = encryptionService;
2211
- }
2212
- sanitizeUser(user) {
2213
- if (!user) return user;
2214
- const { password, ...sanitizedUser } = user;
2215
- return sanitizedUser;
2216
- }
2217
- sanitizeUsers(users) {
2218
- return users.map((user) => this.sanitizeUser(user));
2219
- }
2220
- async resolveUserRole(roleId, roleName) {
2221
- if (roleId) {
2222
- await this.roleValidator.checkRoleExists(roleId);
2223
- return roleId;
2224
- }
2225
- if (roleName) {
2226
- const roleByName = await this.roleService.getByName(roleName);
2227
- if (roleByName) {
2228
- return roleByName.id;
2229
- }
2230
- throw new Error(`Role '${roleName}' not found`);
2231
- }
2232
- const defaultRole = await this.roleService.getByName("Student");
2233
- return defaultRole.id;
2234
- }
2235
- async getAll() {
2236
- const users = await this.userRepository.getAll();
2237
- return this.sanitizeUsers(users);
2238
- }
2239
- async getById(id) {
2240
- await this.userValidator.checkUserExists(id);
2241
- const user = await this.userRepository.getById(id);
2242
- return this.sanitizeUser(user);
2243
- }
2244
- async getByEmail(email) {
2245
- const user = await this.userValidator.checkUserExistsByEmail(email);
2246
- return this.sanitizeUser(user);
2247
- }
2248
- async create(data) {
2249
- const { id, email, image, emailVerified, password, roleId, role } = data;
2250
- let userId = id || nanoid2(5);
2251
- let pass = password || "12345678";
2252
- await this.userValidator.checkEmailUnique(data.email);
2253
- await this.userValidator.checkUserIdIsUnique(id);
2254
- const hashedPassword = await this.encryptionService.hashPassword(pass);
2255
- const resolvedRoleId = await this.resolveUserRole(roleId, role);
2256
- const userDetails = {
2257
- id: userId,
2258
- email,
2259
- image,
2260
- password: hashedPassword,
2261
- roleId: resolvedRoleId,
2262
- emailVerified,
2263
- status: "pending"
2264
- };
2265
- await this.userValidator.validateCreateUser(userDetails);
2266
- const newUser = await this.userRepository.create(userDetails);
2267
- return this.sanitizeUser(newUser);
2268
- }
2269
- async update(id, data) {
2270
- const { password, image } = data;
2271
- await this.userValidator.checkUserExists(id);
2272
- await this.userValidator.checkEmailUnique(data.email, id);
2273
- const currentUser = await this.userRepository.getById(id);
2274
- const hashedPassword = await this.encryptionService.hashPassword(password);
2275
- const updateData = {
2276
- ...data,
2277
- image,
2278
- ...hashedPassword && { password: hashedPassword }
2279
- };
2280
- const cleanedUpdateData = clean(updateData);
2281
- const updatedUser = await this.userRepository.update(id, cleanedUpdateData);
2282
- return this.sanitizeUser(updatedUser);
2283
- }
2284
- async delete(id) {
2285
- await this.userValidator.checkUserExists(id);
2286
- const user = await this.userRepository.delete(id);
2287
- return this.sanitizeUser(user);
2288
- }
2289
- async deleteAll() {
2290
- const deletedUsers = await this.userRepository.deleteAll();
2291
- return this.sanitizeUsers(deletedUsers);
2292
- }
2293
- async getRoleName(id) {
2294
- await this.userValidator.checkUserExists(id);
2295
- return await this.userRepository.getRoleNameById(id);
2296
- }
2297
- async getPassword(email) {
2298
- await this.userValidator.checkUserExistsByEmail(email);
2299
- return await this.userRepository.getUserPassword(email);
2300
- }
2301
- async assignRole(id, roleId, roleName) {
2302
- await this.userValidator.checkUserExists(id);
2303
- const resolvedRoleId = await this.resolveUserRole(roleId, roleName);
2304
- const updatedUser = await this.userRepository.update(id, { roleId: resolvedRoleId });
2305
- return this.sanitizeUser(updatedUser);
2306
- }
2307
- async removeRole(id) {
2308
- await this.userValidator.checkUserExists(id);
2309
- const updatedUser = await this.userRepository.update(id, { roleId: null });
2310
- return this.sanitizeUser(updatedUser);
2311
- }
2312
- async seedAdminUser() {
2313
- const email = "admin@admin.com";
2314
- const adminRole = await this.roleValidator.checkAdminRoleExists();
2315
- const existingUser = await this.userRepository.getByEmail(email);
2316
- if (existingUser) {
2317
- await this.delete(existingUser.id);
2318
- }
2319
- const newAdminUser = await this.create({
2320
- id: "USR00",
2321
- name: "System Administrator",
2322
- email,
2323
- password: "12345678",
2324
- image: null,
2325
- roleId: adminRole.id,
2326
- status: "active",
2327
- emailVerified: true
2328
- });
2329
- return this.sanitizeUser(newAdminUser);
2330
- }
2331
- async updateLang(language) {
2332
- setLanguage(language);
2333
- return language;
2334
- }
2335
- async getLang() {
2336
- return getCurrentLanguage2();
2337
- }
2338
- };
2339
- __decorateClass([
2340
- Transactional()
2341
- ], UserService.prototype, "create", 1);
2342
- UserService = __decorateClass([
2343
- Injectable12()
2344
- ], UserService);
2345
-
2346
- // src/users/UserController.ts
2347
- import { Controller as Controller4, Get as Get4, Post as Post4, Put as Put3, Delete as Delete3, Params as Params4, Body as Body4, t as t9 } from "najm-api";
2348
- var UserController = class {
2349
- constructor(userService) {
2350
- this.userService = userService;
2351
- }
2352
- async getUsers() {
2353
- const users = await this.userService.getAll();
2354
- return {
2355
- data: users,
2356
- message: t9("users.success.retrieved"),
2357
- status: "success"
2358
- };
2359
- }
2360
- async getLang() {
2361
- const language = await this.userService.getLang();
2362
- return {
2363
- data: { language },
2364
- message: t9("users.success.retrieved"),
2365
- status: "success"
2366
- };
2367
- }
2368
- async updateLang(language) {
2369
- const data = await this.userService.updateLang(language);
2370
- return {
2371
- data,
2372
- message: t9("users.success.updated"),
2373
- status: "success"
2374
- };
2375
- }
2376
- async getUser(id) {
2377
- const user = await this.userService.getById(id);
2378
- return {
2379
- data: user,
2380
- message: t9("users.success.retrieved"),
2381
- status: "success"
2382
- };
2383
- }
2384
- async getByEmail(email) {
2385
- const user = await this.userService.getByEmail(email);
2386
- return {
2387
- data: user,
2388
- message: t9("users.success.retrieved"),
2389
- status: "success"
2390
- };
2391
- }
2392
- async getRole(userId) {
2393
- const role = await this.userService.getRoleName(userId);
2394
- return {
2395
- data: role,
2396
- message: t9("users.success.retrieved"),
2397
- status: "success"
2398
- };
2399
- }
2400
- async create(body) {
2401
- const newUser = await this.userService.create(body);
2402
- return {
2403
- data: newUser,
2404
- message: t9("users.success.created"),
2405
- status: "success"
2406
- };
2407
- }
2408
- async update(id, body) {
2409
- const updatedUser = await this.userService.update(id, body);
2410
- return {
2411
- data: updatedUser,
2412
- message: t9("users.success.updated"),
2413
- status: "success"
2414
- };
2415
- }
2416
- async delete(id) {
2417
- const result = await this.userService.delete(id);
2418
- return {
2419
- data: result,
2420
- message: t9("users.success.deleted"),
2421
- status: "success"
2422
- };
2423
- }
2424
- async deleteAll() {
2425
- const result = await this.userService.deleteAll();
2426
- return {
2427
- data: result,
2428
- message: t9("users.success.allDeleted"),
2429
- status: "success"
2430
- };
2431
- }
2432
- async assignRole(userId, roleId) {
2433
- await this.userService.assignRole(userId, roleId);
2434
- return {
2435
- message: t9("users.success.updated"),
2436
- status: "success"
2437
- };
2438
- }
2439
- async removeRole(userId) {
2440
- await this.userService.removeRole(userId);
2441
- return {
2442
- message: t9("users.success.updated"),
2443
- status: "success"
2444
- };
2445
- }
2446
- };
2447
- __decorateClass([
2448
- Get4(),
2449
- isAdmin()
2450
- ], UserController.prototype, "getUsers", 1);
2451
- __decorateClass([
2452
- Get4("/lang"),
2453
- isAuth()
2454
- ], UserController.prototype, "getLang", 1);
2455
- __decorateClass([
2456
- Post4("/lang/:language"),
2457
- isAuth(),
2458
- __decorateParam(0, Params4("language"))
2459
- ], UserController.prototype, "updateLang", 1);
2460
- __decorateClass([
2461
- Get4("/:id"),
2462
- isAdmin(),
2463
- __decorateParam(0, Params4("id"))
2464
- ], UserController.prototype, "getUser", 1);
2465
- __decorateClass([
2466
- Get4("/email/:email"),
2467
- isAdmin(),
2468
- __decorateParam(0, Params4("email"))
2469
- ], UserController.prototype, "getByEmail", 1);
2470
- __decorateClass([
2471
- Get4("/role/:userId"),
2472
- isAdmin(),
2473
- __decorateParam(0, Params4("userId"))
2474
- ], UserController.prototype, "getRole", 1);
2475
- __decorateClass([
2476
- Post4(),
2477
- isAdmin(),
2478
- __decorateParam(0, Body4())
2479
- ], UserController.prototype, "create", 1);
2480
- __decorateClass([
2481
- Put3("/:id"),
2482
- isAdmin(),
2483
- __decorateParam(0, Params4("id")),
2484
- __decorateParam(1, Body4())
2485
- ], UserController.prototype, "update", 1);
2486
- __decorateClass([
2487
- Delete3("/:id"),
2488
- isAdmin(),
2489
- __decorateParam(0, Params4("id"))
2490
- ], UserController.prototype, "delete", 1);
2491
- __decorateClass([
2492
- Delete3(),
2493
- isAdmin()
2494
- ], UserController.prototype, "deleteAll", 1);
2495
- __decorateClass([
2496
- Post4("/assign/:userId/:roleId"),
2497
- isAdmin(),
2498
- __decorateParam(0, Params4("userId")),
2499
- __decorateParam(1, Params4("roleId"))
2500
- ], UserController.prototype, "assignRole", 1);
2501
- __decorateClass([
2502
- Delete3("/remove/:userId"),
2503
- isAdmin(),
2504
- __decorateParam(0, Params4("userId"))
2505
- ], UserController.prototype, "removeRole", 1);
2506
- UserController = __decorateClass([
2507
- Controller4("/users")
2508
- ], UserController);
2509
-
2510
- // src/plugin.ts
2511
- var AuthPlugin = {
2512
- name: "najm-auth",
2513
- version: "0.1.3",
2514
- database: "default",
2515
- controllers: [
2516
- UserController,
2517
- AuthController,
2518
- RoleController,
2519
- PermissionController
2520
- ],
2521
- services: [
2522
- UserService,
2523
- AuthService,
2524
- CookieService,
2525
- EncryptionService,
2526
- RoleService,
2527
- PermissionService,
2528
- TokenService
2529
- ],
2530
- repositories: [
2531
- UserRepository,
2532
- RoleRepository,
2533
- PermissionRepository,
2534
- TokenRepository
2535
- ],
2536
- providers: [
2537
- UserValidator,
2538
- RoleValidator,
2539
- PermissionValidator,
2540
- RoleGuards,
2541
- PermissionGuards
2542
- ],
2543
- onSetup: async () => {
2544
- console.log(" \u2713 najm-auth plugin initialized");
2545
- console.log(" - Authentication endpoints ready");
2546
- console.log(" - Authorization system active");
2547
- console.log(" - Database connection established");
2548
- },
2549
- onTeardown: async () => {
2550
- console.log(" \u2713 najm-auth plugin cleanup complete");
2551
- }
2552
- };
2553
- export {
2554
- AuthController,
2555
- AuthPlugin,
2556
- AuthService,
2557
- CookieService,
2558
- ENUMS,
2559
- EncryptionService,
2560
- Permission,
2561
- PermissionController,
2562
- PermissionGuards,
2563
- PermissionRepository,
2564
- PermissionService,
2565
- PermissionValidator,
2566
- ROLES,
2567
- ROLE_GROUPS,
2568
- Role,
2569
- RoleChecker,
2570
- RoleController,
2571
- RoleGuards,
2572
- RoleRepository,
2573
- RoleService,
2574
- RoleValidator,
2575
- TokenRepository,
2576
- TokenService,
2577
- UserController,
2578
- UserRepository,
2579
- UserService,
2580
- UserValidator,
2581
- alertPriorityEnum,
2582
- alertSchema,
2583
- alertStatusEnum,
2584
- alertTypeEnum,
2585
- announcementSchema,
2586
- assessmentSchema,
2587
- assessmentStatusEnum,
2588
- assessmentTypeEnum,
2589
- assignmentSchema,
2590
- assignmentStatusEnum,
2591
- assignmentsSchema,
2592
- attendanceSchema,
2593
- attendanceStatusEnum,
2594
- avatarsPath,
2595
- bulkAssessmentSchema,
2596
- bulkFeeFormSchema,
2597
- bulkFeeItemSchema,
2598
- busStatusEnum,
2599
- calculateAge,
2600
- calculateYearsOfExperience,
2601
- calendarSystemEnum,
2602
- classSchema,
2603
- classStatusEnum,
2604
- clean,
2605
- dateRangeSchema,
2606
- dayOfWeekEnum,
2607
- driverSchema,
2608
- driverStatusEnum,
2609
- employmentTypeEnum,
2610
- enrollmentStatusEnum,
2611
- eventParticipantSchema,
2612
- eventSchema,
2613
- eventStatusEnum,
2614
- eventTypeEnum,
2615
- eventVisibilityEnum,
2616
- examSchema,
2617
- examSecurityEnum,
2618
- examStatusEnum,
2619
- examTypeEnum,
2620
- expenseApprovalSchema,
2621
- expenseCategoryEnum,
2622
- expensePaymentSchema,
2623
- expenseSchema,
2624
- expenseStatusEnum,
2625
- feeInstallmentSchema,
2626
- feeInstallmentStatusEnum,
2627
- feePaymentSchema,
2628
- feeSchema,
2629
- feeStatusEnum,
2630
- feeTypeSchema,
2631
- feeTypeStatusEnum,
2632
- feesSchema,
2633
- fileStatusEnum,
2634
- formatDate,
2635
- fuelTypeEnum,
2636
- fullStudentSchema,
2637
- genderEnum,
2638
- getAvatarFile,
2639
- getEnumConfig,
2640
- getEnumValues,
2641
- gradeSchema,
2642
- gradeStatusEnum,
2643
- idField,
2644
- idParamSchema,
2645
- isAccounting,
2646
- isAdmin,
2647
- isAdministrator,
2648
- isAuth,
2649
- isEmpty,
2650
- isFile,
2651
- isFinancial,
2652
- isParent,
2653
- isPath,
2654
- isPrincipal,
2655
- isSecretary,
2656
- isStaff,
2657
- isStudent,
2658
- isTeacher,
2659
- languageEnum,
2660
- maintenanceStatusEnum,
2661
- maintenanceTypeEnum,
2662
- maritalStatusEnum,
2663
- paginationSchema,
2664
- parentSchema,
2665
- parentsSchema,
2666
- parseSchema,
2667
- participantTypeEnum,
2668
- paymentAllocationSchema,
2669
- paymentMethodEnum,
2670
- paymentStatusEnum,
2671
- paymentTypeEnum,
2672
- permissionsTable,
2673
- pickProps,
2674
- proficiencyLevelEnum,
2675
- refuelSchema,
2676
- refuelStatusEnum,
2677
- relationshipTypeEnum,
2678
- rolePermissionsTable,
2679
- roleSchema,
2680
- rolesTable,
2681
- scheduleEnum,
2682
- sectionSchema,
2683
- sectionStatusEnum,
2684
- semesterEnum,
2685
- settingsSchema,
2686
- studentSchema,
2687
- studentStatusEnum,
2688
- subjectSchema,
2689
- submissionTypeEnum,
2690
- teacherFullSchema,
2691
- teacherPersonalSchema,
2692
- teacherProfessionalSchema,
2693
- teacherStatusEnum,
2694
- tokenStatusEnum,
2695
- tokenTypeEnum,
2696
- tokensTable,
2697
- trackerModeEnum,
2698
- userSchema,
2699
- userStatusEnum,
2700
- userTypeEnum,
2701
- usersTable,
2702
- vehicleDocumentTypeEnum,
2703
- vehicleSchema,
2704
- vehicleStatusEnum,
2705
- vehicleTypeEnum
2706
- };