@eeplatform/core 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.d.ts +154 -5
- package/dist/index.js +1744 -45
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1756 -45
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -11703,10 +11703,12 @@ var MUser = class {
|
|
|
11703
11703
|
this.createdAt = value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
11704
11704
|
this.updatedAt = value.updatedAt ?? "";
|
|
11705
11705
|
this.deletedAt = value.deletedAt ?? "";
|
|
11706
|
-
|
|
11707
|
-
|
|
11708
|
-
|
|
11709
|
-
|
|
11706
|
+
if (value.defaultOrg) {
|
|
11707
|
+
try {
|
|
11708
|
+
value.defaultOrg = new ObjectId3(value.defaultOrg);
|
|
11709
|
+
} catch (error) {
|
|
11710
|
+
throw new Error("Invalid defaultOrg ID.");
|
|
11711
|
+
}
|
|
11710
11712
|
}
|
|
11711
11713
|
this.defaultOrg = value.defaultOrg;
|
|
11712
11714
|
}
|
|
@@ -12188,7 +12190,8 @@ function useMemberRepo() {
|
|
|
12188
12190
|
await collection.createIndex(
|
|
12189
12191
|
{
|
|
12190
12192
|
org: 1,
|
|
12191
|
-
user: 1
|
|
12193
|
+
user: 1,
|
|
12194
|
+
type: 1
|
|
12192
12195
|
},
|
|
12193
12196
|
{ partialFilterExpression: { deletedAt: "" }, unique: true }
|
|
12194
12197
|
);
|
|
@@ -12217,6 +12220,10 @@ function useMemberRepo() {
|
|
|
12217
12220
|
delCachedData();
|
|
12218
12221
|
return "Successfully added member.";
|
|
12219
12222
|
} catch (error) {
|
|
12223
|
+
logger3.log({
|
|
12224
|
+
level: "error",
|
|
12225
|
+
message: `Failed to create member: ${error}`
|
|
12226
|
+
});
|
|
12220
12227
|
if (error instanceof AppError) {
|
|
12221
12228
|
throw error;
|
|
12222
12229
|
} else {
|
|
@@ -12758,9 +12765,6 @@ function useVerificationService() {
|
|
|
12758
12765
|
if (!metadata.app) {
|
|
12759
12766
|
throw new BadRequestError6("App metadata is required.");
|
|
12760
12767
|
}
|
|
12761
|
-
if (!metadata.org || !metadata.orgName) {
|
|
12762
|
-
throw new BadRequestError6("Organization metadata is required.");
|
|
12763
|
-
}
|
|
12764
12768
|
try {
|
|
12765
12769
|
const user = await getUserByEmail(email);
|
|
12766
12770
|
const dir = __dirname;
|
|
@@ -12772,7 +12776,7 @@ function useVerificationService() {
|
|
|
12772
12776
|
context: {
|
|
12773
12777
|
validity: VERIFICATION_USER_INVITE_DURATION,
|
|
12774
12778
|
link: `${APP_MAIN}/verify/member-invite/${res2}`,
|
|
12775
|
-
organization_name: metadata.orgName
|
|
12779
|
+
organization_name: metadata.app === "admin" ? "Admin" : metadata.orgName
|
|
12776
12780
|
},
|
|
12777
12781
|
filePath: filePath2
|
|
12778
12782
|
});
|
|
@@ -12943,11 +12947,6 @@ function useVerificationService() {
|
|
|
12943
12947
|
"App metadata is required for member invite."
|
|
12944
12948
|
);
|
|
12945
12949
|
}
|
|
12946
|
-
if (!_id.metadata?.org || !_id.metadata?.orgName) {
|
|
12947
|
-
throw new BadRequestError6(
|
|
12948
|
-
"Organization metadata is required for member invite."
|
|
12949
|
-
);
|
|
12950
|
-
}
|
|
12951
12950
|
if (!_id.metadata?.role || !_id.metadata?.roleName) {
|
|
12952
12951
|
throw new BadRequestError6(
|
|
12953
12952
|
"Role metadata is required for member invite."
|
|
@@ -12957,8 +12956,8 @@ function useVerificationService() {
|
|
|
12957
12956
|
{
|
|
12958
12957
|
user: user._id?.toString() ?? "",
|
|
12959
12958
|
type: _id.metadata?.app,
|
|
12960
|
-
org: _id.metadata?.org,
|
|
12961
|
-
orgName: _id.metadata?.orgName,
|
|
12959
|
+
org: _id.metadata?.org ?? "",
|
|
12960
|
+
orgName: _id.metadata?.orgName ?? "",
|
|
12962
12961
|
role: _id.metadata?.role,
|
|
12963
12962
|
roleName: _id.metadata?.roleName,
|
|
12964
12963
|
name: `${user.firstName} ${user.lastName}`
|
|
@@ -13081,8 +13080,8 @@ function useVerificationController() {
|
|
|
13081
13080
|
app: Joi2.string().required(),
|
|
13082
13081
|
role: Joi2.string().hex().required(),
|
|
13083
13082
|
roleName: Joi2.string().required(),
|
|
13084
|
-
org: Joi2.string().
|
|
13085
|
-
orgName: Joi2.string().
|
|
13083
|
+
org: Joi2.string().hex().optional().optional().allow("", null),
|
|
13084
|
+
orgName: Joi2.string().optional().optional().allow("", null)
|
|
13086
13085
|
});
|
|
13087
13086
|
const { error } = validation.validate(req.body);
|
|
13088
13087
|
if (error) {
|
|
@@ -17405,14 +17404,14 @@ var MRole = class {
|
|
|
17405
17404
|
throw new Error("Invalid _id.");
|
|
17406
17405
|
}
|
|
17407
17406
|
}
|
|
17408
|
-
if (typeof value.
|
|
17407
|
+
if (typeof value.id === "string" && value.id.length === 24) {
|
|
17409
17408
|
try {
|
|
17410
|
-
value.
|
|
17409
|
+
value.id = new ObjectId12(value.id);
|
|
17411
17410
|
} catch (error) {
|
|
17412
|
-
throw new Error("Invalid
|
|
17411
|
+
throw new Error("Invalid id.");
|
|
17413
17412
|
}
|
|
17414
17413
|
}
|
|
17415
|
-
this.
|
|
17414
|
+
this.id = value.id ?? "";
|
|
17416
17415
|
this._id = value._id ?? new ObjectId12();
|
|
17417
17416
|
this.name = value.name ?? "";
|
|
17418
17417
|
this.description = value.description ?? "";
|
|
@@ -17462,6 +17461,7 @@ function useRoleRepo() {
|
|
|
17462
17461
|
await collection.createIndex({ name: 1 });
|
|
17463
17462
|
await collection.createIndex({ type: 1 });
|
|
17464
17463
|
await collection.createIndex({ status: 1 });
|
|
17464
|
+
await collection.createIndex({ id: 1 });
|
|
17465
17465
|
} catch (error) {
|
|
17466
17466
|
throw new InternalServerError8("Failed to create index on role.");
|
|
17467
17467
|
}
|
|
@@ -17476,7 +17476,7 @@ function useRoleRepo() {
|
|
|
17476
17476
|
async function createUniqueIndex() {
|
|
17477
17477
|
try {
|
|
17478
17478
|
await collection.createIndex(
|
|
17479
|
-
{ name: 1, type: 1,
|
|
17479
|
+
{ name: 1, type: 1, id: 1 },
|
|
17480
17480
|
{ unique: true }
|
|
17481
17481
|
);
|
|
17482
17482
|
} catch (error) {
|
|
@@ -17607,26 +17607,29 @@ function useRoleRepo() {
|
|
|
17607
17607
|
limit = 10,
|
|
17608
17608
|
sort = {},
|
|
17609
17609
|
type = "",
|
|
17610
|
-
|
|
17610
|
+
id = ""
|
|
17611
17611
|
} = {}) {
|
|
17612
17612
|
limit = limit > 0 ? limit : 10;
|
|
17613
17613
|
search = search || "";
|
|
17614
17614
|
page = page > 0 ? page - 1 : 0;
|
|
17615
|
-
if (
|
|
17615
|
+
if (id && typeof id === "string" && id.length === 24) {
|
|
17616
17616
|
try {
|
|
17617
|
-
|
|
17617
|
+
id = new ObjectId13(id);
|
|
17618
17618
|
} catch (error) {
|
|
17619
|
-
throw new BadRequestError10("Invalid
|
|
17619
|
+
throw new BadRequestError10("Invalid ID.");
|
|
17620
17620
|
}
|
|
17621
17621
|
}
|
|
17622
|
-
const query = { status: "active"
|
|
17622
|
+
const query = { status: "active" };
|
|
17623
|
+
if (id) {
|
|
17624
|
+
query.id = id;
|
|
17625
|
+
}
|
|
17623
17626
|
const cacheKeyOptions = {
|
|
17624
17627
|
status: "active",
|
|
17625
17628
|
limit,
|
|
17626
17629
|
page
|
|
17627
17630
|
};
|
|
17628
|
-
if (
|
|
17629
|
-
cacheKeyOptions.
|
|
17631
|
+
if (id) {
|
|
17632
|
+
cacheKeyOptions.id = String(id);
|
|
17630
17633
|
}
|
|
17631
17634
|
if (type) {
|
|
17632
17635
|
cacheKeyOptions.type = type;
|
|
@@ -17813,7 +17816,7 @@ function useUserService() {
|
|
|
17813
17816
|
await _createUser(user, session);
|
|
17814
17817
|
const roleId = await addRole(
|
|
17815
17818
|
{
|
|
17816
|
-
|
|
17819
|
+
id: "",
|
|
17817
17820
|
name: "Super Admin",
|
|
17818
17821
|
type: "admin",
|
|
17819
17822
|
permissions: ["*"],
|
|
@@ -17922,9 +17925,6 @@ function useUserService() {
|
|
|
17922
17925
|
throw new BadRequestError11("Invitation expired.");
|
|
17923
17926
|
}
|
|
17924
17927
|
const email = invitation.email;
|
|
17925
|
-
if (!invitation.metadata.org) {
|
|
17926
|
-
throw new BadRequestError11("Invitation does not have an organization.");
|
|
17927
|
-
}
|
|
17928
17928
|
const _user = await getUserByEmail(invitation.email);
|
|
17929
17929
|
let userId = _user?._id ?? "";
|
|
17930
17930
|
if (!_user) {
|
|
@@ -17949,8 +17949,8 @@ function useUserService() {
|
|
|
17949
17949
|
role: invitation.metadata?.role,
|
|
17950
17950
|
roleName: invitation.metadata?.roleName,
|
|
17951
17951
|
type: invitation.metadata?.app,
|
|
17952
|
-
org: invitation.metadata?.org,
|
|
17953
|
-
orgName: invitation.metadata?.orgName
|
|
17952
|
+
org: invitation.metadata?.org ?? "",
|
|
17953
|
+
orgName: invitation.metadata?.orgName ?? ""
|
|
17954
17954
|
},
|
|
17955
17955
|
session
|
|
17956
17956
|
);
|
|
@@ -18779,8 +18779,8 @@ function useRoleController() {
|
|
|
18779
18779
|
const validation = Joi7.object({
|
|
18780
18780
|
name: Joi7.string().required(),
|
|
18781
18781
|
permissions: Joi7.array().items(Joi7.string()).required(),
|
|
18782
|
-
type: Joi7.string().
|
|
18783
|
-
|
|
18782
|
+
type: Joi7.string().valid("school", "division", "region", "account").required(),
|
|
18783
|
+
id: Joi7.string().hex().optional().allow("", null)
|
|
18784
18784
|
});
|
|
18785
18785
|
const { error } = validation.validate(payload);
|
|
18786
18786
|
if (error) {
|
|
@@ -18800,21 +18800,21 @@ function useRoleController() {
|
|
|
18800
18800
|
const page = parseInt(req.query.page ?? "1");
|
|
18801
18801
|
const limit = parseInt(req.query.limit ?? "10");
|
|
18802
18802
|
const type = req.query.type ?? "";
|
|
18803
|
-
const
|
|
18803
|
+
const id = req.query.id ?? "";
|
|
18804
18804
|
const validation = Joi7.object({
|
|
18805
18805
|
search: Joi7.string().optional().allow("", null),
|
|
18806
18806
|
page: Joi7.number().required(),
|
|
18807
18807
|
limit: Joi7.number().required(),
|
|
18808
18808
|
type: Joi7.string().optional().allow("", null),
|
|
18809
|
-
|
|
18809
|
+
id: Joi7.string().hex().optional().allow("", null)
|
|
18810
18810
|
});
|
|
18811
|
-
const { error } = validation.validate({ search, page, limit, type,
|
|
18811
|
+
const { error } = validation.validate({ search, page, limit, type, id });
|
|
18812
18812
|
if (error) {
|
|
18813
18813
|
next(new BadRequestError16(error.message));
|
|
18814
18814
|
return;
|
|
18815
18815
|
}
|
|
18816
18816
|
try {
|
|
18817
|
-
const data = await _getRoles({ search, page, limit, type,
|
|
18817
|
+
const data = await _getRoles({ search, page, limit, type, id });
|
|
18818
18818
|
res.json(data);
|
|
18819
18819
|
return;
|
|
18820
18820
|
} catch (error2) {
|
|
@@ -21731,7 +21731,7 @@ function useSubscriptionService() {
|
|
|
21731
21731
|
const roleName = "owner";
|
|
21732
21732
|
const role = await addRole(
|
|
21733
21733
|
{
|
|
21734
|
-
|
|
21734
|
+
id: orgId.toString(),
|
|
21735
21735
|
name: roleName,
|
|
21736
21736
|
permissions: ["*"],
|
|
21737
21737
|
type: "organization",
|
|
@@ -21920,7 +21920,7 @@ function useSubscriptionService() {
|
|
|
21920
21920
|
}
|
|
21921
21921
|
const role = await addRole(
|
|
21922
21922
|
{
|
|
21923
|
-
|
|
21923
|
+
id: orgId.toString(),
|
|
21924
21924
|
name: "owner",
|
|
21925
21925
|
permissions: ["*"],
|
|
21926
21926
|
type: "organization",
|
|
@@ -24174,7 +24174,7 @@ function useOrgService() {
|
|
|
24174
24174
|
);
|
|
24175
24175
|
const role = await addRole(
|
|
24176
24176
|
{
|
|
24177
|
-
org,
|
|
24177
|
+
id: org,
|
|
24178
24178
|
name: "Owner",
|
|
24179
24179
|
description: "Owner of the organization",
|
|
24180
24180
|
permissions: ["all"]
|
|
@@ -25335,6 +25335,1704 @@ function usePriceController() {
|
|
|
25335
25335
|
getByNameType
|
|
25336
25336
|
};
|
|
25337
25337
|
}
|
|
25338
|
+
|
|
25339
|
+
// src/models/region.model.ts
|
|
25340
|
+
import { BadRequestError as BadRequestError50 } from "@eeplatform/nodejs-utils";
|
|
25341
|
+
import Joi27 from "joi";
|
|
25342
|
+
import { ObjectId as ObjectId33 } from "mongodb";
|
|
25343
|
+
var schemaRegion = Joi27.object({
|
|
25344
|
+
_id: Joi27.string().hex().optional().allow(null, ""),
|
|
25345
|
+
name: Joi27.string().min(1).max(100).required(),
|
|
25346
|
+
director: Joi27.string().hex().optional().allow(null, ""),
|
|
25347
|
+
directorName: Joi27.string().min(1).max(100).optional().allow(null, ""),
|
|
25348
|
+
createdAt: Joi27.string().isoDate().optional(),
|
|
25349
|
+
updatedAt: Joi27.string().isoDate().optional(),
|
|
25350
|
+
deletedAt: Joi27.string().isoDate().optional().allow(null, "")
|
|
25351
|
+
});
|
|
25352
|
+
function MRegion(value) {
|
|
25353
|
+
const { error } = schemaRegion.validate(value);
|
|
25354
|
+
if (error) {
|
|
25355
|
+
throw new BadRequestError50(`Invalid region data: ${error.message}`);
|
|
25356
|
+
}
|
|
25357
|
+
if (value._id && typeof value._id === "string") {
|
|
25358
|
+
try {
|
|
25359
|
+
value._id = new ObjectId33(value._id);
|
|
25360
|
+
} catch (error2) {
|
|
25361
|
+
throw new Error("Invalid _id.");
|
|
25362
|
+
}
|
|
25363
|
+
}
|
|
25364
|
+
if (value.director && typeof value.director === "string") {
|
|
25365
|
+
try {
|
|
25366
|
+
value.director = new ObjectId33(value.director);
|
|
25367
|
+
} catch (error2) {
|
|
25368
|
+
throw new Error("Invalid director.");
|
|
25369
|
+
}
|
|
25370
|
+
}
|
|
25371
|
+
return {
|
|
25372
|
+
_id: value._id,
|
|
25373
|
+
name: value.name,
|
|
25374
|
+
director: value.director ?? "",
|
|
25375
|
+
directorName: value.directorName ?? "",
|
|
25376
|
+
createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
25377
|
+
updatedAt: value.updatedAt ?? "",
|
|
25378
|
+
deletedAt: value.deletedAt ?? ""
|
|
25379
|
+
};
|
|
25380
|
+
}
|
|
25381
|
+
|
|
25382
|
+
// src/repositories/region.repository.ts
|
|
25383
|
+
import {
|
|
25384
|
+
AppError as AppError12,
|
|
25385
|
+
BadRequestError as BadRequestError51,
|
|
25386
|
+
InternalServerError as InternalServerError23,
|
|
25387
|
+
logger as logger24,
|
|
25388
|
+
makeCacheKey as makeCacheKey16,
|
|
25389
|
+
paginate as paginate12,
|
|
25390
|
+
useAtlas as useAtlas25,
|
|
25391
|
+
useCache as useCache16
|
|
25392
|
+
} from "@eeplatform/nodejs-utils";
|
|
25393
|
+
import { ObjectId as ObjectId34 } from "mongodb";
|
|
25394
|
+
function useRegionRepo() {
|
|
25395
|
+
const db = useAtlas25.getDb();
|
|
25396
|
+
if (!db) {
|
|
25397
|
+
throw new Error("Unable to connect to server.");
|
|
25398
|
+
}
|
|
25399
|
+
const namespace_collection = "regions";
|
|
25400
|
+
const collection = db.collection(namespace_collection);
|
|
25401
|
+
const { getCache, setCache, delNamespace } = useCache16();
|
|
25402
|
+
async function createIndex() {
|
|
25403
|
+
try {
|
|
25404
|
+
await collection.createIndex([
|
|
25405
|
+
{ name: 1 },
|
|
25406
|
+
{ director: 1 },
|
|
25407
|
+
{ createdAt: 1 }
|
|
25408
|
+
]);
|
|
25409
|
+
} catch (error) {
|
|
25410
|
+
throw new Error("Failed to create index on regions.");
|
|
25411
|
+
}
|
|
25412
|
+
}
|
|
25413
|
+
async function createTextIndex() {
|
|
25414
|
+
try {
|
|
25415
|
+
await collection.createIndex({
|
|
25416
|
+
name: "text",
|
|
25417
|
+
directorName: "text"
|
|
25418
|
+
});
|
|
25419
|
+
} catch (error) {
|
|
25420
|
+
throw new Error(
|
|
25421
|
+
"Failed to create text index on region name and director name."
|
|
25422
|
+
);
|
|
25423
|
+
}
|
|
25424
|
+
}
|
|
25425
|
+
async function createUniqueIndex() {
|
|
25426
|
+
try {
|
|
25427
|
+
await collection.createIndex(
|
|
25428
|
+
{
|
|
25429
|
+
name: 1
|
|
25430
|
+
},
|
|
25431
|
+
{ unique: true }
|
|
25432
|
+
);
|
|
25433
|
+
} catch (error) {
|
|
25434
|
+
throw new Error("Failed to create unique index on region name.");
|
|
25435
|
+
}
|
|
25436
|
+
}
|
|
25437
|
+
function delCachedData() {
|
|
25438
|
+
delNamespace(namespace_collection).then(() => {
|
|
25439
|
+
logger24.log({
|
|
25440
|
+
level: "info",
|
|
25441
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
25442
|
+
});
|
|
25443
|
+
}).catch((err) => {
|
|
25444
|
+
logger24.log({
|
|
25445
|
+
level: "error",
|
|
25446
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
25447
|
+
});
|
|
25448
|
+
});
|
|
25449
|
+
}
|
|
25450
|
+
async function add(value, session) {
|
|
25451
|
+
try {
|
|
25452
|
+
value = MRegion(value);
|
|
25453
|
+
const res = await collection.insertOne(value, { session });
|
|
25454
|
+
delCachedData();
|
|
25455
|
+
return res.insertedId;
|
|
25456
|
+
} catch (error) {
|
|
25457
|
+
logger24.log({
|
|
25458
|
+
level: "error",
|
|
25459
|
+
message: error.message
|
|
25460
|
+
});
|
|
25461
|
+
if (error instanceof AppError12) {
|
|
25462
|
+
throw error;
|
|
25463
|
+
} else {
|
|
25464
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
25465
|
+
if (isDuplicated) {
|
|
25466
|
+
throw new BadRequestError51("Region already exists.");
|
|
25467
|
+
}
|
|
25468
|
+
throw new Error("Failed to create region.");
|
|
25469
|
+
}
|
|
25470
|
+
}
|
|
25471
|
+
}
|
|
25472
|
+
async function getAll({ search = "", page = 1, limit = 10, sort = {} } = {}) {
|
|
25473
|
+
page = page > 0 ? page - 1 : 0;
|
|
25474
|
+
const query = { deletedAt: { $in: ["", null] } };
|
|
25475
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: 1 };
|
|
25476
|
+
if (search) {
|
|
25477
|
+
query.$text = { $search: search };
|
|
25478
|
+
}
|
|
25479
|
+
const cacheKey = makeCacheKey16(namespace_collection, {
|
|
25480
|
+
search,
|
|
25481
|
+
page,
|
|
25482
|
+
limit,
|
|
25483
|
+
sort: JSON.stringify(sort)
|
|
25484
|
+
});
|
|
25485
|
+
logger24.log({
|
|
25486
|
+
level: "info",
|
|
25487
|
+
message: `Cache key for getAll regions: ${cacheKey}`
|
|
25488
|
+
});
|
|
25489
|
+
try {
|
|
25490
|
+
const cached = await getCache(cacheKey);
|
|
25491
|
+
if (cached) {
|
|
25492
|
+
logger24.log({
|
|
25493
|
+
level: "info",
|
|
25494
|
+
message: `Cache hit for getAll regions: ${cacheKey}`
|
|
25495
|
+
});
|
|
25496
|
+
return cached;
|
|
25497
|
+
}
|
|
25498
|
+
const items = await collection.aggregate([
|
|
25499
|
+
{ $match: query },
|
|
25500
|
+
{ $sort: sort },
|
|
25501
|
+
{ $skip: page * limit },
|
|
25502
|
+
{ $limit: limit },
|
|
25503
|
+
{
|
|
25504
|
+
$project: {
|
|
25505
|
+
_id: 1,
|
|
25506
|
+
name: 1,
|
|
25507
|
+
director: 1,
|
|
25508
|
+
directorName: 1,
|
|
25509
|
+
createdAt: 1,
|
|
25510
|
+
updatedAt: 1
|
|
25511
|
+
}
|
|
25512
|
+
}
|
|
25513
|
+
]).toArray();
|
|
25514
|
+
const length = await collection.countDocuments(query);
|
|
25515
|
+
const data = paginate12(items, page, limit, length);
|
|
25516
|
+
setCache(cacheKey, data, 600, namespace_collection).then(() => {
|
|
25517
|
+
logger24.log({
|
|
25518
|
+
level: "info",
|
|
25519
|
+
message: `Cache set for getAll regions: ${cacheKey}`
|
|
25520
|
+
});
|
|
25521
|
+
}).catch((err) => {
|
|
25522
|
+
logger24.log({
|
|
25523
|
+
level: "error",
|
|
25524
|
+
message: `Failed to set cache for getAll regions: ${err.message}`
|
|
25525
|
+
});
|
|
25526
|
+
});
|
|
25527
|
+
return data;
|
|
25528
|
+
} catch (error) {
|
|
25529
|
+
logger24.log({ level: "error", message: `${error}` });
|
|
25530
|
+
throw error;
|
|
25531
|
+
}
|
|
25532
|
+
}
|
|
25533
|
+
async function getById(_id) {
|
|
25534
|
+
try {
|
|
25535
|
+
_id = new ObjectId34(_id);
|
|
25536
|
+
} catch (error) {
|
|
25537
|
+
throw new BadRequestError51("Invalid ID.");
|
|
25538
|
+
}
|
|
25539
|
+
const cacheKey = makeCacheKey16(namespace_collection, { _id: String(_id) });
|
|
25540
|
+
try {
|
|
25541
|
+
const cached = await getCache(cacheKey);
|
|
25542
|
+
if (cached) {
|
|
25543
|
+
logger24.log({
|
|
25544
|
+
level: "info",
|
|
25545
|
+
message: `Cache hit for getById region: ${cacheKey}`
|
|
25546
|
+
});
|
|
25547
|
+
return cached;
|
|
25548
|
+
}
|
|
25549
|
+
const result = await collection.findOne({
|
|
25550
|
+
_id,
|
|
25551
|
+
deletedAt: { $in: ["", null] }
|
|
25552
|
+
});
|
|
25553
|
+
if (!result) {
|
|
25554
|
+
throw new BadRequestError51("Region not found.");
|
|
25555
|
+
}
|
|
25556
|
+
setCache(cacheKey, result, 300, namespace_collection).then(() => {
|
|
25557
|
+
logger24.log({
|
|
25558
|
+
level: "info",
|
|
25559
|
+
message: `Cache set for region by id: ${cacheKey}`
|
|
25560
|
+
});
|
|
25561
|
+
}).catch((err) => {
|
|
25562
|
+
logger24.log({
|
|
25563
|
+
level: "error",
|
|
25564
|
+
message: `Failed to set cache for region by id: ${err.message}`
|
|
25565
|
+
});
|
|
25566
|
+
});
|
|
25567
|
+
return result;
|
|
25568
|
+
} catch (error) {
|
|
25569
|
+
if (error instanceof AppError12) {
|
|
25570
|
+
throw error;
|
|
25571
|
+
} else {
|
|
25572
|
+
throw new InternalServerError23("Failed to get region.");
|
|
25573
|
+
}
|
|
25574
|
+
}
|
|
25575
|
+
}
|
|
25576
|
+
async function getByName(name) {
|
|
25577
|
+
const cacheKey = makeCacheKey16(namespace_collection, { name });
|
|
25578
|
+
try {
|
|
25579
|
+
const cached = await getCache(cacheKey);
|
|
25580
|
+
if (cached) {
|
|
25581
|
+
logger24.log({
|
|
25582
|
+
level: "info",
|
|
25583
|
+
message: `Cache hit for getByName region: ${cacheKey}`
|
|
25584
|
+
});
|
|
25585
|
+
return cached;
|
|
25586
|
+
}
|
|
25587
|
+
const result = await collection.findOne({
|
|
25588
|
+
name,
|
|
25589
|
+
deletedAt: { $in: ["", null] }
|
|
25590
|
+
});
|
|
25591
|
+
if (!result) {
|
|
25592
|
+
throw new BadRequestError51("Region not found.");
|
|
25593
|
+
}
|
|
25594
|
+
setCache(cacheKey, result, 300, namespace_collection).then(() => {
|
|
25595
|
+
logger24.log({
|
|
25596
|
+
level: "info",
|
|
25597
|
+
message: `Cache set for region by name: ${cacheKey}`
|
|
25598
|
+
});
|
|
25599
|
+
}).catch((err) => {
|
|
25600
|
+
logger24.log({
|
|
25601
|
+
level: "error",
|
|
25602
|
+
message: `Failed to set cache for region by name: ${err.message}`
|
|
25603
|
+
});
|
|
25604
|
+
});
|
|
25605
|
+
return result;
|
|
25606
|
+
} catch (error) {
|
|
25607
|
+
if (error instanceof AppError12) {
|
|
25608
|
+
throw error;
|
|
25609
|
+
} else {
|
|
25610
|
+
throw new InternalServerError23("Failed to get region.");
|
|
25611
|
+
}
|
|
25612
|
+
}
|
|
25613
|
+
}
|
|
25614
|
+
async function updateFieldById({ _id, field, value } = {}, session) {
|
|
25615
|
+
const allowedFields = ["name", "director", "directorName"];
|
|
25616
|
+
if (!allowedFields.includes(field)) {
|
|
25617
|
+
throw new BadRequestError51(
|
|
25618
|
+
`Field "${field}" is not allowed to be updated.`
|
|
25619
|
+
);
|
|
25620
|
+
}
|
|
25621
|
+
try {
|
|
25622
|
+
_id = new ObjectId34(_id);
|
|
25623
|
+
} catch (error) {
|
|
25624
|
+
throw new BadRequestError51("Invalid ID.");
|
|
25625
|
+
}
|
|
25626
|
+
try {
|
|
25627
|
+
await collection.updateOne(
|
|
25628
|
+
{ _id, deletedAt: { $in: ["", null] } },
|
|
25629
|
+
{ $set: { [field]: value, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } },
|
|
25630
|
+
{ session }
|
|
25631
|
+
);
|
|
25632
|
+
delCachedData();
|
|
25633
|
+
return `Successfully updated region ${field}.`;
|
|
25634
|
+
} catch (error) {
|
|
25635
|
+
throw new InternalServerError23(`Failed to update region ${field}.`);
|
|
25636
|
+
}
|
|
25637
|
+
}
|
|
25638
|
+
async function deleteById(_id) {
|
|
25639
|
+
try {
|
|
25640
|
+
_id = new ObjectId34(_id);
|
|
25641
|
+
} catch (error) {
|
|
25642
|
+
throw new BadRequestError51("Invalid ID.");
|
|
25643
|
+
}
|
|
25644
|
+
try {
|
|
25645
|
+
await collection.updateOne(
|
|
25646
|
+
{ _id },
|
|
25647
|
+
{ $set: { deletedAt: (/* @__PURE__ */ new Date()).toISOString() } }
|
|
25648
|
+
);
|
|
25649
|
+
delCachedData();
|
|
25650
|
+
return "Successfully deleted region.";
|
|
25651
|
+
} catch (error) {
|
|
25652
|
+
throw new InternalServerError23("Failed to delete region.");
|
|
25653
|
+
}
|
|
25654
|
+
}
|
|
25655
|
+
return {
|
|
25656
|
+
createIndex,
|
|
25657
|
+
createTextIndex,
|
|
25658
|
+
createUniqueIndex,
|
|
25659
|
+
add,
|
|
25660
|
+
getAll,
|
|
25661
|
+
getById,
|
|
25662
|
+
updateFieldById,
|
|
25663
|
+
deleteById,
|
|
25664
|
+
getByName
|
|
25665
|
+
};
|
|
25666
|
+
}
|
|
25667
|
+
|
|
25668
|
+
// src/controllers/region.controller.ts
|
|
25669
|
+
import { BadRequestError as BadRequestError52 } from "@eeplatform/nodejs-utils";
|
|
25670
|
+
import Joi28 from "joi";
|
|
25671
|
+
|
|
25672
|
+
// src/services/region.service.ts
|
|
25673
|
+
import { useAtlas as useAtlas26 } from "@eeplatform/nodejs-utils";
|
|
25674
|
+
function useRegionService() {
|
|
25675
|
+
const { add: _add } = useRegionRepo();
|
|
25676
|
+
const { addRole } = useRoleRepo();
|
|
25677
|
+
async function add(value) {
|
|
25678
|
+
const session = useAtlas26.getClient()?.startSession();
|
|
25679
|
+
if (!session) {
|
|
25680
|
+
throw new Error("Unable to start session for region service.");
|
|
25681
|
+
}
|
|
25682
|
+
try {
|
|
25683
|
+
session.startTransaction();
|
|
25684
|
+
const region = await _add(value, session);
|
|
25685
|
+
await addRole(
|
|
25686
|
+
{
|
|
25687
|
+
id: region.toString(),
|
|
25688
|
+
name: "Admin",
|
|
25689
|
+
type: "region",
|
|
25690
|
+
permissions: ["*"],
|
|
25691
|
+
status: "active",
|
|
25692
|
+
default: true
|
|
25693
|
+
},
|
|
25694
|
+
session
|
|
25695
|
+
);
|
|
25696
|
+
await session.commitTransaction();
|
|
25697
|
+
return "Region and admin role created successfully.";
|
|
25698
|
+
} catch (error) {
|
|
25699
|
+
await session.abortTransaction();
|
|
25700
|
+
throw error;
|
|
25701
|
+
} finally {
|
|
25702
|
+
session.endSession();
|
|
25703
|
+
}
|
|
25704
|
+
}
|
|
25705
|
+
return {
|
|
25706
|
+
add
|
|
25707
|
+
};
|
|
25708
|
+
}
|
|
25709
|
+
|
|
25710
|
+
// src/controllers/region.controller.ts
|
|
25711
|
+
function useRegionController() {
|
|
25712
|
+
const {
|
|
25713
|
+
getAll: _getAll,
|
|
25714
|
+
getById: _getById,
|
|
25715
|
+
getByName: _getByName,
|
|
25716
|
+
updateFieldById: _updateFieldById,
|
|
25717
|
+
deleteById: _deleteById
|
|
25718
|
+
} = useRegionRepo();
|
|
25719
|
+
const { add: _createRegion } = useRegionService();
|
|
25720
|
+
async function createRegion(req, res, next) {
|
|
25721
|
+
const value = req.body;
|
|
25722
|
+
const validation = Joi28.object({
|
|
25723
|
+
name: Joi28.string().min(1).max(100).required(),
|
|
25724
|
+
director: Joi28.string().hex().optional().allow("", null),
|
|
25725
|
+
directorName: Joi28.string().min(1).max(100).optional().allow("", null)
|
|
25726
|
+
});
|
|
25727
|
+
const { error } = validation.validate(value);
|
|
25728
|
+
if (error) {
|
|
25729
|
+
next(new BadRequestError52(error.message));
|
|
25730
|
+
return;
|
|
25731
|
+
}
|
|
25732
|
+
try {
|
|
25733
|
+
const regionId = await _createRegion(value);
|
|
25734
|
+
res.json({
|
|
25735
|
+
message: "Successfully created region.",
|
|
25736
|
+
data: { regionId }
|
|
25737
|
+
});
|
|
25738
|
+
return;
|
|
25739
|
+
} catch (error2) {
|
|
25740
|
+
next(error2);
|
|
25741
|
+
}
|
|
25742
|
+
}
|
|
25743
|
+
async function getAll(req, res, next) {
|
|
25744
|
+
const query = req.query;
|
|
25745
|
+
const validation = Joi28.object({
|
|
25746
|
+
page: Joi28.number().min(1).optional().allow("", null),
|
|
25747
|
+
limit: Joi28.number().min(1).optional().allow("", null),
|
|
25748
|
+
search: Joi28.string().optional().allow("", null)
|
|
25749
|
+
});
|
|
25750
|
+
const { error } = validation.validate(query);
|
|
25751
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
25752
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
25753
|
+
const search = req.query.search ?? "";
|
|
25754
|
+
const isPageNumber = isFinite(page);
|
|
25755
|
+
if (!isPageNumber) {
|
|
25756
|
+
next(new BadRequestError52("Invalid page number."));
|
|
25757
|
+
return;
|
|
25758
|
+
}
|
|
25759
|
+
const isLimitNumber = isFinite(limit);
|
|
25760
|
+
if (!isLimitNumber) {
|
|
25761
|
+
next(new BadRequestError52("Invalid limit number."));
|
|
25762
|
+
return;
|
|
25763
|
+
}
|
|
25764
|
+
if (error) {
|
|
25765
|
+
next(new BadRequestError52(error.message));
|
|
25766
|
+
return;
|
|
25767
|
+
}
|
|
25768
|
+
try {
|
|
25769
|
+
const regions = await _getAll({ page, limit, search });
|
|
25770
|
+
res.json(regions);
|
|
25771
|
+
return;
|
|
25772
|
+
} catch (error2) {
|
|
25773
|
+
next(error2);
|
|
25774
|
+
}
|
|
25775
|
+
}
|
|
25776
|
+
async function getById(req, res, next) {
|
|
25777
|
+
const id = req.params.id;
|
|
25778
|
+
const validation = Joi28.object({
|
|
25779
|
+
id: Joi28.string().hex().required()
|
|
25780
|
+
});
|
|
25781
|
+
const { error } = validation.validate({ id });
|
|
25782
|
+
if (error) {
|
|
25783
|
+
next(new BadRequestError52(error.message));
|
|
25784
|
+
return;
|
|
25785
|
+
}
|
|
25786
|
+
try {
|
|
25787
|
+
const region = await _getById(id);
|
|
25788
|
+
res.json({
|
|
25789
|
+
message: "Successfully retrieved region.",
|
|
25790
|
+
data: { region }
|
|
25791
|
+
});
|
|
25792
|
+
return;
|
|
25793
|
+
} catch (error2) {
|
|
25794
|
+
next(error2);
|
|
25795
|
+
}
|
|
25796
|
+
}
|
|
25797
|
+
async function getByName(req, res, next) {
|
|
25798
|
+
const name = req.params.name;
|
|
25799
|
+
const validation = Joi28.object({
|
|
25800
|
+
name: Joi28.string().required()
|
|
25801
|
+
});
|
|
25802
|
+
const { error } = validation.validate({ name });
|
|
25803
|
+
if (error) {
|
|
25804
|
+
next(new BadRequestError52(error.message));
|
|
25805
|
+
return;
|
|
25806
|
+
}
|
|
25807
|
+
try {
|
|
25808
|
+
const region = await _getByName(name);
|
|
25809
|
+
res.json({
|
|
25810
|
+
message: "Successfully retrieved region.",
|
|
25811
|
+
data: { region }
|
|
25812
|
+
});
|
|
25813
|
+
return;
|
|
25814
|
+
} catch (error2) {
|
|
25815
|
+
next(error2);
|
|
25816
|
+
}
|
|
25817
|
+
}
|
|
25818
|
+
async function updateField(req, res, next) {
|
|
25819
|
+
const _id = req.params.id;
|
|
25820
|
+
const { field, value } = req.body;
|
|
25821
|
+
const validation = Joi28.object({
|
|
25822
|
+
_id: Joi28.string().hex().required(),
|
|
25823
|
+
field: Joi28.string().valid("name", "director", "directorName").required(),
|
|
25824
|
+
value: Joi28.string().required()
|
|
25825
|
+
});
|
|
25826
|
+
const { error } = validation.validate({ _id, field, value });
|
|
25827
|
+
if (error) {
|
|
25828
|
+
next(new BadRequestError52(error.message));
|
|
25829
|
+
return;
|
|
25830
|
+
}
|
|
25831
|
+
try {
|
|
25832
|
+
const message = await _updateFieldById({ _id, field, value });
|
|
25833
|
+
res.json({ message });
|
|
25834
|
+
return;
|
|
25835
|
+
} catch (error2) {
|
|
25836
|
+
next(error2);
|
|
25837
|
+
}
|
|
25838
|
+
}
|
|
25839
|
+
async function deleteRegion(req, res, next) {
|
|
25840
|
+
const _id = req.params.id;
|
|
25841
|
+
const validation = Joi28.object({
|
|
25842
|
+
_id: Joi28.string().hex().required()
|
|
25843
|
+
});
|
|
25844
|
+
const { error } = validation.validate({ _id });
|
|
25845
|
+
if (error) {
|
|
25846
|
+
next(new BadRequestError52(error.message));
|
|
25847
|
+
return;
|
|
25848
|
+
}
|
|
25849
|
+
try {
|
|
25850
|
+
const message = await _deleteById(_id);
|
|
25851
|
+
res.json({ message });
|
|
25852
|
+
return;
|
|
25853
|
+
} catch (error2) {
|
|
25854
|
+
next(error2);
|
|
25855
|
+
}
|
|
25856
|
+
}
|
|
25857
|
+
return {
|
|
25858
|
+
createRegion,
|
|
25859
|
+
getAll,
|
|
25860
|
+
getById,
|
|
25861
|
+
getByName,
|
|
25862
|
+
updateField,
|
|
25863
|
+
deleteRegion
|
|
25864
|
+
};
|
|
25865
|
+
}
|
|
25866
|
+
|
|
25867
|
+
// src/models/division.model.ts
|
|
25868
|
+
import { BadRequestError as BadRequestError53 } from "@eeplatform/nodejs-utils";
|
|
25869
|
+
import Joi29 from "joi";
|
|
25870
|
+
import { ObjectId as ObjectId35 } from "mongodb";
|
|
25871
|
+
var schemaDivision = Joi29.object({
|
|
25872
|
+
_id: Joi29.string().hex().optional().allow(null, ""),
|
|
25873
|
+
name: Joi29.string().min(1).max(100).required(),
|
|
25874
|
+
region: Joi29.string().hex().optional().allow(null, ""),
|
|
25875
|
+
regionName: Joi29.string().min(1).max(100).optional().allow(null, ""),
|
|
25876
|
+
superintendent: Joi29.string().hex().optional().allow(null, ""),
|
|
25877
|
+
superintendentName: Joi29.string().min(1).max(100).optional().allow(null, ""),
|
|
25878
|
+
createdAt: Joi29.string().isoDate().optional(),
|
|
25879
|
+
updatedAt: Joi29.string().isoDate().optional(),
|
|
25880
|
+
deletedAt: Joi29.string().isoDate().optional().allow(null, "")
|
|
25881
|
+
});
|
|
25882
|
+
function MDivision(value) {
|
|
25883
|
+
const { error } = schemaDivision.validate(value);
|
|
25884
|
+
if (error) {
|
|
25885
|
+
throw new BadRequestError53(`Invalid division data: ${error.message}`);
|
|
25886
|
+
}
|
|
25887
|
+
if (value._id && typeof value._id === "string") {
|
|
25888
|
+
try {
|
|
25889
|
+
value._id = new ObjectId35(value._id);
|
|
25890
|
+
} catch (error2) {
|
|
25891
|
+
throw new Error("Invalid _id.");
|
|
25892
|
+
}
|
|
25893
|
+
}
|
|
25894
|
+
if (value.region && typeof value.region === "string") {
|
|
25895
|
+
try {
|
|
25896
|
+
value.region = new ObjectId35(value.region);
|
|
25897
|
+
} catch (error2) {
|
|
25898
|
+
throw new Error("Invalid region.");
|
|
25899
|
+
}
|
|
25900
|
+
}
|
|
25901
|
+
if (value.superintendent && typeof value.superintendent === "string") {
|
|
25902
|
+
try {
|
|
25903
|
+
value.superintendent = new ObjectId35(value.superintendent);
|
|
25904
|
+
} catch (error2) {
|
|
25905
|
+
throw new Error("Invalid superintendent.");
|
|
25906
|
+
}
|
|
25907
|
+
}
|
|
25908
|
+
return {
|
|
25909
|
+
_id: value._id,
|
|
25910
|
+
name: value.name,
|
|
25911
|
+
region: value.region ?? "",
|
|
25912
|
+
regionName: value.regionName ?? "",
|
|
25913
|
+
superintendent: value.superintendent ?? "",
|
|
25914
|
+
superintendentName: value.superintendentName ?? "",
|
|
25915
|
+
createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
25916
|
+
updatedAt: value.updatedAt ?? "",
|
|
25917
|
+
deletedAt: value.deletedAt ?? ""
|
|
25918
|
+
};
|
|
25919
|
+
}
|
|
25920
|
+
|
|
25921
|
+
// src/repositories/division.repository.ts
|
|
25922
|
+
import {
|
|
25923
|
+
AppError as AppError13,
|
|
25924
|
+
BadRequestError as BadRequestError54,
|
|
25925
|
+
InternalServerError as InternalServerError24,
|
|
25926
|
+
logger as logger25,
|
|
25927
|
+
makeCacheKey as makeCacheKey17,
|
|
25928
|
+
paginate as paginate13,
|
|
25929
|
+
useAtlas as useAtlas27,
|
|
25930
|
+
useCache as useCache17
|
|
25931
|
+
} from "@eeplatform/nodejs-utils";
|
|
25932
|
+
import { ObjectId as ObjectId36 } from "mongodb";
|
|
25933
|
+
function useDivisionRepo() {
|
|
25934
|
+
const db = useAtlas27.getDb();
|
|
25935
|
+
if (!db) {
|
|
25936
|
+
throw new Error("Unable to connect to server.");
|
|
25937
|
+
}
|
|
25938
|
+
const namespace_collection = "divisions";
|
|
25939
|
+
const collection = db.collection(namespace_collection);
|
|
25940
|
+
const { getCache, setCache, delNamespace } = useCache17();
|
|
25941
|
+
async function createIndex() {
|
|
25942
|
+
try {
|
|
25943
|
+
await collection.createIndex([
|
|
25944
|
+
{ name: 1 },
|
|
25945
|
+
{ region: 1 },
|
|
25946
|
+
{ superintendent: 1 },
|
|
25947
|
+
{ createdAt: 1 }
|
|
25948
|
+
]);
|
|
25949
|
+
} catch (error) {
|
|
25950
|
+
throw new Error("Failed to create index on divisions.");
|
|
25951
|
+
}
|
|
25952
|
+
}
|
|
25953
|
+
async function createTextIndex() {
|
|
25954
|
+
try {
|
|
25955
|
+
await collection.createIndex({
|
|
25956
|
+
name: "text",
|
|
25957
|
+
regionName: "text",
|
|
25958
|
+
superintendentName: "text"
|
|
25959
|
+
});
|
|
25960
|
+
} catch (error) {
|
|
25961
|
+
throw new Error(
|
|
25962
|
+
"Failed to create text index on division name and superintendent name."
|
|
25963
|
+
);
|
|
25964
|
+
}
|
|
25965
|
+
}
|
|
25966
|
+
async function createUniqueIndex() {
|
|
25967
|
+
try {
|
|
25968
|
+
await collection.createIndex(
|
|
25969
|
+
{
|
|
25970
|
+
name: 1
|
|
25971
|
+
},
|
|
25972
|
+
{ unique: true }
|
|
25973
|
+
);
|
|
25974
|
+
} catch (error) {
|
|
25975
|
+
throw new Error("Failed to create unique index on division name.");
|
|
25976
|
+
}
|
|
25977
|
+
}
|
|
25978
|
+
function delCachedData() {
|
|
25979
|
+
delNamespace(namespace_collection).then(() => {
|
|
25980
|
+
logger25.log({
|
|
25981
|
+
level: "info",
|
|
25982
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
25983
|
+
});
|
|
25984
|
+
}).catch((err) => {
|
|
25985
|
+
logger25.log({
|
|
25986
|
+
level: "error",
|
|
25987
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
25988
|
+
});
|
|
25989
|
+
});
|
|
25990
|
+
}
|
|
25991
|
+
async function add(value, session) {
|
|
25992
|
+
try {
|
|
25993
|
+
value = MDivision(value);
|
|
25994
|
+
const res = await collection.insertOne(value, { session });
|
|
25995
|
+
delCachedData();
|
|
25996
|
+
return res.insertedId;
|
|
25997
|
+
} catch (error) {
|
|
25998
|
+
logger25.log({
|
|
25999
|
+
level: "error",
|
|
26000
|
+
message: error.message
|
|
26001
|
+
});
|
|
26002
|
+
if (error instanceof AppError13) {
|
|
26003
|
+
throw error;
|
|
26004
|
+
} else {
|
|
26005
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
26006
|
+
if (isDuplicated) {
|
|
26007
|
+
throw new BadRequestError54("Division already exists.");
|
|
26008
|
+
}
|
|
26009
|
+
throw new Error("Failed to create division.");
|
|
26010
|
+
}
|
|
26011
|
+
}
|
|
26012
|
+
}
|
|
26013
|
+
async function getAll({
|
|
26014
|
+
search = "",
|
|
26015
|
+
page = 1,
|
|
26016
|
+
limit = 10,
|
|
26017
|
+
sort = {},
|
|
26018
|
+
region = ""
|
|
26019
|
+
} = {}) {
|
|
26020
|
+
page = page > 0 ? page - 1 : 0;
|
|
26021
|
+
const query = { deletedAt: { $in: ["", null] } };
|
|
26022
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
26023
|
+
if (search) {
|
|
26024
|
+
query.$text = { $search: search };
|
|
26025
|
+
}
|
|
26026
|
+
if (region) {
|
|
26027
|
+
try {
|
|
26028
|
+
query.region = new ObjectId36(region);
|
|
26029
|
+
} catch (error) {
|
|
26030
|
+
throw new BadRequestError54("Invalid region ID.");
|
|
26031
|
+
}
|
|
26032
|
+
}
|
|
26033
|
+
const cacheKey = makeCacheKey17(namespace_collection, {
|
|
26034
|
+
search,
|
|
26035
|
+
page,
|
|
26036
|
+
limit,
|
|
26037
|
+
sort: JSON.stringify(sort),
|
|
26038
|
+
region
|
|
26039
|
+
});
|
|
26040
|
+
logger25.log({
|
|
26041
|
+
level: "info",
|
|
26042
|
+
message: `Cache key for getAll divisions: ${cacheKey}`
|
|
26043
|
+
});
|
|
26044
|
+
try {
|
|
26045
|
+
const cached = await getCache(cacheKey);
|
|
26046
|
+
if (cached) {
|
|
26047
|
+
logger25.log({
|
|
26048
|
+
level: "info",
|
|
26049
|
+
message: `Cache hit for getAll divisions: ${cacheKey}`
|
|
26050
|
+
});
|
|
26051
|
+
return cached;
|
|
26052
|
+
}
|
|
26053
|
+
const items = await collection.aggregate([
|
|
26054
|
+
{ $match: query },
|
|
26055
|
+
{ $sort: sort },
|
|
26056
|
+
{ $skip: page * limit },
|
|
26057
|
+
{ $limit: limit },
|
|
26058
|
+
{
|
|
26059
|
+
$project: {
|
|
26060
|
+
_id: 1,
|
|
26061
|
+
name: 1,
|
|
26062
|
+
region: 1,
|
|
26063
|
+
regionName: 1,
|
|
26064
|
+
superintendent: 1,
|
|
26065
|
+
superintendentName: 1,
|
|
26066
|
+
createdAt: 1,
|
|
26067
|
+
updatedAt: 1
|
|
26068
|
+
}
|
|
26069
|
+
}
|
|
26070
|
+
]).toArray();
|
|
26071
|
+
const length = await collection.countDocuments(query);
|
|
26072
|
+
const data = paginate13(items, page, limit, length);
|
|
26073
|
+
setCache(cacheKey, data, 600, namespace_collection).then(() => {
|
|
26074
|
+
logger25.log({
|
|
26075
|
+
level: "info",
|
|
26076
|
+
message: `Cache set for getAll divisions: ${cacheKey}`
|
|
26077
|
+
});
|
|
26078
|
+
}).catch((err) => {
|
|
26079
|
+
logger25.log({
|
|
26080
|
+
level: "error",
|
|
26081
|
+
message: `Failed to set cache for getAll divisions: ${err.message}`
|
|
26082
|
+
});
|
|
26083
|
+
});
|
|
26084
|
+
return data;
|
|
26085
|
+
} catch (error) {
|
|
26086
|
+
logger25.log({ level: "error", message: `${error}` });
|
|
26087
|
+
throw error;
|
|
26088
|
+
}
|
|
26089
|
+
}
|
|
26090
|
+
async function getById(_id) {
|
|
26091
|
+
try {
|
|
26092
|
+
_id = new ObjectId36(_id);
|
|
26093
|
+
} catch (error) {
|
|
26094
|
+
throw new BadRequestError54("Invalid ID.");
|
|
26095
|
+
}
|
|
26096
|
+
const cacheKey = makeCacheKey17(namespace_collection, { _id: String(_id) });
|
|
26097
|
+
try {
|
|
26098
|
+
const cached = await getCache(cacheKey);
|
|
26099
|
+
if (cached) {
|
|
26100
|
+
logger25.log({
|
|
26101
|
+
level: "info",
|
|
26102
|
+
message: `Cache hit for getById division: ${cacheKey}`
|
|
26103
|
+
});
|
|
26104
|
+
return cached;
|
|
26105
|
+
}
|
|
26106
|
+
const result = await collection.findOne({
|
|
26107
|
+
_id,
|
|
26108
|
+
deletedAt: { $in: ["", null] }
|
|
26109
|
+
});
|
|
26110
|
+
if (!result) {
|
|
26111
|
+
throw new BadRequestError54("Division not found.");
|
|
26112
|
+
}
|
|
26113
|
+
setCache(cacheKey, result, 300, namespace_collection).then(() => {
|
|
26114
|
+
logger25.log({
|
|
26115
|
+
level: "info",
|
|
26116
|
+
message: `Cache set for division by id: ${cacheKey}`
|
|
26117
|
+
});
|
|
26118
|
+
}).catch((err) => {
|
|
26119
|
+
logger25.log({
|
|
26120
|
+
level: "error",
|
|
26121
|
+
message: `Failed to set cache for division by id: ${err.message}`
|
|
26122
|
+
});
|
|
26123
|
+
});
|
|
26124
|
+
return result;
|
|
26125
|
+
} catch (error) {
|
|
26126
|
+
if (error instanceof AppError13) {
|
|
26127
|
+
throw error;
|
|
26128
|
+
} else {
|
|
26129
|
+
throw new InternalServerError24("Failed to get division.");
|
|
26130
|
+
}
|
|
26131
|
+
}
|
|
26132
|
+
}
|
|
26133
|
+
async function getByName(name) {
|
|
26134
|
+
const cacheKey = makeCacheKey17(namespace_collection, { name });
|
|
26135
|
+
try {
|
|
26136
|
+
const cached = await getCache(cacheKey);
|
|
26137
|
+
if (cached) {
|
|
26138
|
+
logger25.log({
|
|
26139
|
+
level: "info",
|
|
26140
|
+
message: `Cache hit for getByName division: ${cacheKey}`
|
|
26141
|
+
});
|
|
26142
|
+
return cached;
|
|
26143
|
+
}
|
|
26144
|
+
const result = await collection.findOne({
|
|
26145
|
+
name,
|
|
26146
|
+
deletedAt: { $in: ["", null] }
|
|
26147
|
+
});
|
|
26148
|
+
if (!result) {
|
|
26149
|
+
throw new BadRequestError54("Division not found.");
|
|
26150
|
+
}
|
|
26151
|
+
setCache(cacheKey, result, 300, namespace_collection).then(() => {
|
|
26152
|
+
logger25.log({
|
|
26153
|
+
level: "info",
|
|
26154
|
+
message: `Cache set for division by name: ${cacheKey}`
|
|
26155
|
+
});
|
|
26156
|
+
}).catch((err) => {
|
|
26157
|
+
logger25.log({
|
|
26158
|
+
level: "error",
|
|
26159
|
+
message: `Failed to set cache for division by name: ${err.message}`
|
|
26160
|
+
});
|
|
26161
|
+
});
|
|
26162
|
+
return result;
|
|
26163
|
+
} catch (error) {
|
|
26164
|
+
if (error instanceof AppError13) {
|
|
26165
|
+
throw error;
|
|
26166
|
+
} else {
|
|
26167
|
+
throw new InternalServerError24("Failed to get division.");
|
|
26168
|
+
}
|
|
26169
|
+
}
|
|
26170
|
+
}
|
|
26171
|
+
async function updateFieldById({ _id, field, value } = {}, session) {
|
|
26172
|
+
const allowedFields = [
|
|
26173
|
+
"name",
|
|
26174
|
+
"region",
|
|
26175
|
+
"regionName",
|
|
26176
|
+
"superintendent",
|
|
26177
|
+
"superintendentName"
|
|
26178
|
+
];
|
|
26179
|
+
if (!allowedFields.includes(field)) {
|
|
26180
|
+
throw new BadRequestError54(
|
|
26181
|
+
`Field "${field}" is not allowed to be updated.`
|
|
26182
|
+
);
|
|
26183
|
+
}
|
|
26184
|
+
try {
|
|
26185
|
+
_id = new ObjectId36(_id);
|
|
26186
|
+
} catch (error) {
|
|
26187
|
+
throw new BadRequestError54("Invalid ID.");
|
|
26188
|
+
}
|
|
26189
|
+
try {
|
|
26190
|
+
await collection.updateOne(
|
|
26191
|
+
{ _id, deletedAt: { $in: ["", null] } },
|
|
26192
|
+
{ $set: { [field]: value, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } },
|
|
26193
|
+
{ session }
|
|
26194
|
+
);
|
|
26195
|
+
delCachedData();
|
|
26196
|
+
return `Successfully updated division ${field}.`;
|
|
26197
|
+
} catch (error) {
|
|
26198
|
+
throw new InternalServerError24(`Failed to update division ${field}.`);
|
|
26199
|
+
}
|
|
26200
|
+
}
|
|
26201
|
+
async function deleteById(_id) {
|
|
26202
|
+
try {
|
|
26203
|
+
_id = new ObjectId36(_id);
|
|
26204
|
+
} catch (error) {
|
|
26205
|
+
throw new BadRequestError54("Invalid ID.");
|
|
26206
|
+
}
|
|
26207
|
+
try {
|
|
26208
|
+
await collection.updateOne(
|
|
26209
|
+
{ _id },
|
|
26210
|
+
{ $set: { deletedAt: (/* @__PURE__ */ new Date()).toISOString() } }
|
|
26211
|
+
);
|
|
26212
|
+
delCachedData();
|
|
26213
|
+
return "Successfully deleted division.";
|
|
26214
|
+
} catch (error) {
|
|
26215
|
+
throw new InternalServerError24("Failed to delete division.");
|
|
26216
|
+
}
|
|
26217
|
+
}
|
|
26218
|
+
return {
|
|
26219
|
+
createIndex,
|
|
26220
|
+
createTextIndex,
|
|
26221
|
+
createUniqueIndex,
|
|
26222
|
+
add,
|
|
26223
|
+
getAll,
|
|
26224
|
+
getById,
|
|
26225
|
+
updateFieldById,
|
|
26226
|
+
deleteById,
|
|
26227
|
+
getByName
|
|
26228
|
+
};
|
|
26229
|
+
}
|
|
26230
|
+
|
|
26231
|
+
// src/controllers/division.controller.ts
|
|
26232
|
+
import { BadRequestError as BadRequestError55 } from "@eeplatform/nodejs-utils";
|
|
26233
|
+
import Joi30 from "joi";
|
|
26234
|
+
|
|
26235
|
+
// src/services/division.service.ts
|
|
26236
|
+
import { useAtlas as useAtlas28 } from "@eeplatform/nodejs-utils";
|
|
26237
|
+
function useDivisionService() {
|
|
26238
|
+
const { add: _add } = useDivisionRepo();
|
|
26239
|
+
const { addRole } = useRoleRepo();
|
|
26240
|
+
async function add(value) {
|
|
26241
|
+
const session = useAtlas28.getClient()?.startSession();
|
|
26242
|
+
if (!session) {
|
|
26243
|
+
throw new Error("Unable to start session for division service.");
|
|
26244
|
+
}
|
|
26245
|
+
try {
|
|
26246
|
+
session.startTransaction();
|
|
26247
|
+
const division = await _add(value, session);
|
|
26248
|
+
await addRole(
|
|
26249
|
+
{
|
|
26250
|
+
id: division.toString(),
|
|
26251
|
+
name: "Admin",
|
|
26252
|
+
type: "division",
|
|
26253
|
+
permissions: ["*"],
|
|
26254
|
+
status: "active",
|
|
26255
|
+
default: true
|
|
26256
|
+
},
|
|
26257
|
+
session
|
|
26258
|
+
);
|
|
26259
|
+
await session.commitTransaction();
|
|
26260
|
+
return "Division and admin role created successfully.";
|
|
26261
|
+
} catch (error) {
|
|
26262
|
+
session.abortTransaction();
|
|
26263
|
+
throw error;
|
|
26264
|
+
} finally {
|
|
26265
|
+
session.endSession();
|
|
26266
|
+
}
|
|
26267
|
+
}
|
|
26268
|
+
return {
|
|
26269
|
+
add
|
|
26270
|
+
};
|
|
26271
|
+
}
|
|
26272
|
+
|
|
26273
|
+
// src/controllers/division.controller.ts
|
|
26274
|
+
function useDivisionController() {
|
|
26275
|
+
const {
|
|
26276
|
+
getAll: _getAll,
|
|
26277
|
+
getById: _getById,
|
|
26278
|
+
getByName: _getByName,
|
|
26279
|
+
updateFieldById: _updateFieldById,
|
|
26280
|
+
deleteById: _deleteById
|
|
26281
|
+
} = useDivisionRepo();
|
|
26282
|
+
const { add: _createDivision } = useDivisionService();
|
|
26283
|
+
async function createDivision(req, res, next) {
|
|
26284
|
+
const value = req.body;
|
|
26285
|
+
const validation = Joi30.object({
|
|
26286
|
+
name: Joi30.string().min(1).max(100).required(),
|
|
26287
|
+
region: Joi30.string().hex().optional().allow("", null),
|
|
26288
|
+
regionName: Joi30.string().min(1).max(100).optional().allow("", null),
|
|
26289
|
+
superintendent: Joi30.string().hex().optional().allow("", null),
|
|
26290
|
+
superintendentName: Joi30.string().min(1).max(100).optional().allow("", null)
|
|
26291
|
+
});
|
|
26292
|
+
const { error } = validation.validate(value);
|
|
26293
|
+
if (error) {
|
|
26294
|
+
next(new BadRequestError55(error.message));
|
|
26295
|
+
return;
|
|
26296
|
+
}
|
|
26297
|
+
try {
|
|
26298
|
+
const divisionId = await _createDivision(value);
|
|
26299
|
+
res.json({
|
|
26300
|
+
message: "Successfully created division.",
|
|
26301
|
+
data: { divisionId }
|
|
26302
|
+
});
|
|
26303
|
+
return;
|
|
26304
|
+
} catch (error2) {
|
|
26305
|
+
next(error2);
|
|
26306
|
+
}
|
|
26307
|
+
}
|
|
26308
|
+
async function getAll(req, res, next) {
|
|
26309
|
+
const query = req.query;
|
|
26310
|
+
const validation = Joi30.object({
|
|
26311
|
+
page: Joi30.number().min(1).optional().allow("", null),
|
|
26312
|
+
limit: Joi30.number().min(1).optional().allow("", null),
|
|
26313
|
+
search: Joi30.string().optional().allow("", null),
|
|
26314
|
+
region: Joi30.string().hex().optional().allow("", null)
|
|
26315
|
+
});
|
|
26316
|
+
const { error } = validation.validate(query);
|
|
26317
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
26318
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
26319
|
+
const search = req.query.search ?? "";
|
|
26320
|
+
const region = req.query.region ?? "";
|
|
26321
|
+
const isPageNumber = isFinite(page);
|
|
26322
|
+
if (!isPageNumber) {
|
|
26323
|
+
next(new BadRequestError55("Invalid page number."));
|
|
26324
|
+
return;
|
|
26325
|
+
}
|
|
26326
|
+
const isLimitNumber = isFinite(limit);
|
|
26327
|
+
if (!isLimitNumber) {
|
|
26328
|
+
next(new BadRequestError55("Invalid limit number."));
|
|
26329
|
+
return;
|
|
26330
|
+
}
|
|
26331
|
+
if (error) {
|
|
26332
|
+
next(new BadRequestError55(error.message));
|
|
26333
|
+
return;
|
|
26334
|
+
}
|
|
26335
|
+
try {
|
|
26336
|
+
const divisions = await _getAll({ page, limit, search, region });
|
|
26337
|
+
res.json(divisions);
|
|
26338
|
+
return;
|
|
26339
|
+
} catch (error2) {
|
|
26340
|
+
next(error2);
|
|
26341
|
+
}
|
|
26342
|
+
}
|
|
26343
|
+
async function getById(req, res, next) {
|
|
26344
|
+
const id = req.params.id;
|
|
26345
|
+
const validation = Joi30.object({
|
|
26346
|
+
id: Joi30.string().hex().required()
|
|
26347
|
+
});
|
|
26348
|
+
const { error } = validation.validate({ id });
|
|
26349
|
+
if (error) {
|
|
26350
|
+
next(new BadRequestError55(error.message));
|
|
26351
|
+
return;
|
|
26352
|
+
}
|
|
26353
|
+
try {
|
|
26354
|
+
const division = await _getById(id);
|
|
26355
|
+
res.json({
|
|
26356
|
+
message: "Successfully retrieved division.",
|
|
26357
|
+
data: { division }
|
|
26358
|
+
});
|
|
26359
|
+
return;
|
|
26360
|
+
} catch (error2) {
|
|
26361
|
+
next(error2);
|
|
26362
|
+
}
|
|
26363
|
+
}
|
|
26364
|
+
async function getByName(req, res, next) {
|
|
26365
|
+
const name = req.params.name;
|
|
26366
|
+
const validation = Joi30.object({
|
|
26367
|
+
name: Joi30.string().required()
|
|
26368
|
+
});
|
|
26369
|
+
const { error } = validation.validate({ name });
|
|
26370
|
+
if (error) {
|
|
26371
|
+
next(new BadRequestError55(error.message));
|
|
26372
|
+
return;
|
|
26373
|
+
}
|
|
26374
|
+
try {
|
|
26375
|
+
const division = await _getByName(name);
|
|
26376
|
+
res.json({
|
|
26377
|
+
message: "Successfully retrieved division.",
|
|
26378
|
+
data: { division }
|
|
26379
|
+
});
|
|
26380
|
+
return;
|
|
26381
|
+
} catch (error2) {
|
|
26382
|
+
next(error2);
|
|
26383
|
+
}
|
|
26384
|
+
}
|
|
26385
|
+
async function updateField(req, res, next) {
|
|
26386
|
+
const _id = req.params.id;
|
|
26387
|
+
const { field, value } = req.body;
|
|
26388
|
+
const validation = Joi30.object({
|
|
26389
|
+
_id: Joi30.string().hex().required(),
|
|
26390
|
+
field: Joi30.string().valid(
|
|
26391
|
+
"name",
|
|
26392
|
+
"region",
|
|
26393
|
+
"regionName",
|
|
26394
|
+
"superintendent",
|
|
26395
|
+
"superintendentName"
|
|
26396
|
+
).required(),
|
|
26397
|
+
value: Joi30.string().required()
|
|
26398
|
+
});
|
|
26399
|
+
const { error } = validation.validate({ _id, field, value });
|
|
26400
|
+
if (error) {
|
|
26401
|
+
next(new BadRequestError55(error.message));
|
|
26402
|
+
return;
|
|
26403
|
+
}
|
|
26404
|
+
try {
|
|
26405
|
+
const message = await _updateFieldById({ _id, field, value });
|
|
26406
|
+
res.json({ message });
|
|
26407
|
+
return;
|
|
26408
|
+
} catch (error2) {
|
|
26409
|
+
next(error2);
|
|
26410
|
+
}
|
|
26411
|
+
}
|
|
26412
|
+
async function deleteDivision(req, res, next) {
|
|
26413
|
+
const _id = req.params.id;
|
|
26414
|
+
const validation = Joi30.object({
|
|
26415
|
+
_id: Joi30.string().hex().required()
|
|
26416
|
+
});
|
|
26417
|
+
const { error } = validation.validate({ _id });
|
|
26418
|
+
if (error) {
|
|
26419
|
+
next(new BadRequestError55(error.message));
|
|
26420
|
+
return;
|
|
26421
|
+
}
|
|
26422
|
+
try {
|
|
26423
|
+
const message = await _deleteById(_id);
|
|
26424
|
+
res.json({ message });
|
|
26425
|
+
return;
|
|
26426
|
+
} catch (error2) {
|
|
26427
|
+
next(error2);
|
|
26428
|
+
}
|
|
26429
|
+
}
|
|
26430
|
+
return {
|
|
26431
|
+
createDivision,
|
|
26432
|
+
getAll,
|
|
26433
|
+
getById,
|
|
26434
|
+
getByName,
|
|
26435
|
+
updateField,
|
|
26436
|
+
deleteDivision
|
|
26437
|
+
};
|
|
26438
|
+
}
|
|
26439
|
+
|
|
26440
|
+
// src/models/school.model.ts
|
|
26441
|
+
import Joi31 from "joi";
|
|
26442
|
+
import { ObjectId as ObjectId37 } from "mongodb";
|
|
26443
|
+
var schemaSchool = Joi31.object({
|
|
26444
|
+
_id: Joi31.string().hex().optional().allow("", null),
|
|
26445
|
+
id: Joi31.string().required(),
|
|
26446
|
+
name: Joi31.string().required(),
|
|
26447
|
+
country: Joi31.string().required(),
|
|
26448
|
+
address: Joi31.string().required(),
|
|
26449
|
+
continuedAddress: Joi31.string().optional().allow("", null),
|
|
26450
|
+
city: Joi31.string().required(),
|
|
26451
|
+
province: Joi31.string().required(),
|
|
26452
|
+
postalCode: Joi31.string().required(),
|
|
26453
|
+
courses: Joi31.array().items(Joi31.string()).required(),
|
|
26454
|
+
principalName: Joi31.string().required(),
|
|
26455
|
+
principalEmail: Joi31.string().email().optional().allow("", null),
|
|
26456
|
+
principalNumber: Joi31.string().optional().allow("", null),
|
|
26457
|
+
region: Joi31.string().hex().required(),
|
|
26458
|
+
regionName: Joi31.string().optional().allow("", null),
|
|
26459
|
+
division: Joi31.string().hex().required(),
|
|
26460
|
+
divisionName: Joi31.string().optional().allow("", null),
|
|
26461
|
+
status: Joi31.string().optional().allow(null, ""),
|
|
26462
|
+
createdAt: Joi31.date().optional().allow("", null),
|
|
26463
|
+
updatedAt: Joi31.date().optional().allow("", null),
|
|
26464
|
+
createdBy: Joi31.string().hex().required()
|
|
26465
|
+
});
|
|
26466
|
+
function MSchool(value) {
|
|
26467
|
+
const { error } = schemaSchool.validate(value);
|
|
26468
|
+
if (error) {
|
|
26469
|
+
throw new Error(`Validation error: ${error.message}`);
|
|
26470
|
+
}
|
|
26471
|
+
if (value._id) {
|
|
26472
|
+
try {
|
|
26473
|
+
value._id = new ObjectId37(value._id);
|
|
26474
|
+
} catch (error2) {
|
|
26475
|
+
throw new Error("Invalid _id.");
|
|
26476
|
+
}
|
|
26477
|
+
}
|
|
26478
|
+
if (value.region) {
|
|
26479
|
+
try {
|
|
26480
|
+
value.region = new ObjectId37(value.region);
|
|
26481
|
+
} catch (error2) {
|
|
26482
|
+
throw new Error("Invalid region.");
|
|
26483
|
+
}
|
|
26484
|
+
}
|
|
26485
|
+
if (value.division) {
|
|
26486
|
+
try {
|
|
26487
|
+
value.division = new ObjectId37(value.division);
|
|
26488
|
+
} catch (error2) {
|
|
26489
|
+
throw new Error("Invalid division.");
|
|
26490
|
+
}
|
|
26491
|
+
}
|
|
26492
|
+
if (value.createdBy) {
|
|
26493
|
+
try {
|
|
26494
|
+
value.createdBy = new ObjectId37(value.createdBy);
|
|
26495
|
+
} catch (error2) {
|
|
26496
|
+
throw new Error("Invalid createdBy.");
|
|
26497
|
+
}
|
|
26498
|
+
}
|
|
26499
|
+
return {
|
|
26500
|
+
_id: value._id ? value._id : new ObjectId37(),
|
|
26501
|
+
id: value.id,
|
|
26502
|
+
name: value.name,
|
|
26503
|
+
country: value.country,
|
|
26504
|
+
address: value.address,
|
|
26505
|
+
continuedAddress: value.continuedAddress ?? "",
|
|
26506
|
+
city: value.city,
|
|
26507
|
+
province: value.province,
|
|
26508
|
+
postalCode: value.postalCode,
|
|
26509
|
+
courses: value.courses || [],
|
|
26510
|
+
principalName: value.principalName,
|
|
26511
|
+
principalEmail: value.principalEmail,
|
|
26512
|
+
principalNumber: value.principalNumber ?? "",
|
|
26513
|
+
region: value.region,
|
|
26514
|
+
regionName: value.regionName ?? "",
|
|
26515
|
+
division: value.division,
|
|
26516
|
+
divisionName: value.divisionName ?? "",
|
|
26517
|
+
createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
26518
|
+
updatedAt: value.updatedAt ?? "",
|
|
26519
|
+
status: value.status ?? "pending",
|
|
26520
|
+
createdBy: value.createdBy
|
|
26521
|
+
};
|
|
26522
|
+
}
|
|
26523
|
+
|
|
26524
|
+
// src/repositories/school.repository.ts
|
|
26525
|
+
import {
|
|
26526
|
+
BadRequestError as BadRequestError56,
|
|
26527
|
+
logger as logger26,
|
|
26528
|
+
makeCacheKey as makeCacheKey18,
|
|
26529
|
+
paginate as paginate14,
|
|
26530
|
+
useAtlas as useAtlas29,
|
|
26531
|
+
useCache as useCache18
|
|
26532
|
+
} from "@eeplatform/nodejs-utils";
|
|
26533
|
+
import { ObjectId as ObjectId38 } from "mongodb";
|
|
26534
|
+
function useSchoolRepo() {
|
|
26535
|
+
const db = useAtlas29.getDb();
|
|
26536
|
+
if (!db) {
|
|
26537
|
+
throw new BadRequestError56("Unable to connect to server.");
|
|
26538
|
+
}
|
|
26539
|
+
const namespace_collection = "schools";
|
|
26540
|
+
const collection = db.collection(namespace_collection);
|
|
26541
|
+
const { getCache, setCache, delNamespace } = useCache18();
|
|
26542
|
+
function delCachedData() {
|
|
26543
|
+
delNamespace(namespace_collection).then(() => {
|
|
26544
|
+
logger26.log({
|
|
26545
|
+
level: "info",
|
|
26546
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
26547
|
+
});
|
|
26548
|
+
}).catch((err) => {
|
|
26549
|
+
logger26.log({
|
|
26550
|
+
level: "error",
|
|
26551
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
26552
|
+
});
|
|
26553
|
+
});
|
|
26554
|
+
}
|
|
26555
|
+
async function createIndex() {
|
|
26556
|
+
try {
|
|
26557
|
+
await collection.createIndexes([
|
|
26558
|
+
{ key: { name: 1 } },
|
|
26559
|
+
{ key: { id: 1 }, unique: true },
|
|
26560
|
+
{ key: { region: 1 } },
|
|
26561
|
+
{ key: { division: 1 } },
|
|
26562
|
+
{
|
|
26563
|
+
key: {
|
|
26564
|
+
name: "text",
|
|
26565
|
+
address: "text",
|
|
26566
|
+
continuedAddress: "text",
|
|
26567
|
+
city: "text",
|
|
26568
|
+
province: "text",
|
|
26569
|
+
postalCode: "text",
|
|
26570
|
+
regionName: "text",
|
|
26571
|
+
divisionName: "text"
|
|
26572
|
+
}
|
|
26573
|
+
}
|
|
26574
|
+
]);
|
|
26575
|
+
} catch (error) {
|
|
26576
|
+
throw new BadRequestError56("Failed to create index on school.");
|
|
26577
|
+
}
|
|
26578
|
+
}
|
|
26579
|
+
async function add(value, session) {
|
|
26580
|
+
try {
|
|
26581
|
+
value = MSchool(value);
|
|
26582
|
+
const res = await collection.insertOne(value, { session });
|
|
26583
|
+
delCachedData();
|
|
26584
|
+
return res.insertedId;
|
|
26585
|
+
} catch (error) {
|
|
26586
|
+
logger26.log({
|
|
26587
|
+
level: "error",
|
|
26588
|
+
message: `Failed to add school: ${error}`
|
|
26589
|
+
});
|
|
26590
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
26591
|
+
if (isDuplicated) {
|
|
26592
|
+
throw new BadRequestError56("School already exist.");
|
|
26593
|
+
}
|
|
26594
|
+
throw error;
|
|
26595
|
+
}
|
|
26596
|
+
}
|
|
26597
|
+
async function getAll({
|
|
26598
|
+
page = 1,
|
|
26599
|
+
limit = 20,
|
|
26600
|
+
sort = {},
|
|
26601
|
+
status = "active",
|
|
26602
|
+
org = "",
|
|
26603
|
+
app = "admin",
|
|
26604
|
+
search = ""
|
|
26605
|
+
} = {}) {
|
|
26606
|
+
page = Math.max(0, page - 1);
|
|
26607
|
+
if (sort && Object.keys(sort).length === 0) {
|
|
26608
|
+
sort = { name: 1 };
|
|
26609
|
+
}
|
|
26610
|
+
const query = { status };
|
|
26611
|
+
const cacheKeyOptions = {
|
|
26612
|
+
page,
|
|
26613
|
+
limit,
|
|
26614
|
+
sort: JSON.stringify(sort),
|
|
26615
|
+
status
|
|
26616
|
+
};
|
|
26617
|
+
if (search) {
|
|
26618
|
+
query.$text = { $search: search };
|
|
26619
|
+
cacheKeyOptions.search = search;
|
|
26620
|
+
}
|
|
26621
|
+
if (org) {
|
|
26622
|
+
try {
|
|
26623
|
+
query[app] = new ObjectId38(org);
|
|
26624
|
+
cacheKeyOptions[app] = org;
|
|
26625
|
+
} catch (error) {
|
|
26626
|
+
throw new BadRequestError56("Invalid org.");
|
|
26627
|
+
}
|
|
26628
|
+
}
|
|
26629
|
+
try {
|
|
26630
|
+
const cacheKey = makeCacheKey18(namespace_collection, cacheKeyOptions);
|
|
26631
|
+
const cachedData = await getCache(cacheKey);
|
|
26632
|
+
if (cachedData) {
|
|
26633
|
+
return cachedData;
|
|
26634
|
+
}
|
|
26635
|
+
const items = await collection.aggregate([
|
|
26636
|
+
{ $match: query },
|
|
26637
|
+
{ $sort: sort },
|
|
26638
|
+
{ $skip: page * limit },
|
|
26639
|
+
{ $limit: limit }
|
|
26640
|
+
]).toArray();
|
|
26641
|
+
const length = await collection.countDocuments(query);
|
|
26642
|
+
const data = paginate14(items, page, limit, length);
|
|
26643
|
+
setCache(cacheKey, data, 600, namespace_collection).then(() => {
|
|
26644
|
+
logger26.log({
|
|
26645
|
+
level: "info",
|
|
26646
|
+
message: `Cache set for key ${cacheKey}`
|
|
26647
|
+
});
|
|
26648
|
+
}).catch((err) => {
|
|
26649
|
+
logger26.log({
|
|
26650
|
+
level: "error",
|
|
26651
|
+
message: `Failed to set cache for key ${cacheKey}: ${err.message}`
|
|
26652
|
+
});
|
|
26653
|
+
});
|
|
26654
|
+
return data;
|
|
26655
|
+
} catch (error) {
|
|
26656
|
+
logger26.log({
|
|
26657
|
+
level: "error",
|
|
26658
|
+
message: `Failed to get all schools: ${error}`
|
|
26659
|
+
});
|
|
26660
|
+
throw error;
|
|
26661
|
+
}
|
|
26662
|
+
}
|
|
26663
|
+
async function updateStatusById(_id, status, session) {
|
|
26664
|
+
try {
|
|
26665
|
+
_id = new ObjectId38(_id);
|
|
26666
|
+
} catch (error) {
|
|
26667
|
+
throw new BadRequestError56("Invalid school ID.");
|
|
26668
|
+
}
|
|
26669
|
+
const result = await collection.updateOne(
|
|
26670
|
+
{ _id },
|
|
26671
|
+
{ $set: { status, updatedAt: /* @__PURE__ */ new Date() } },
|
|
26672
|
+
{ session }
|
|
26673
|
+
);
|
|
26674
|
+
delCachedData();
|
|
26675
|
+
return result;
|
|
26676
|
+
}
|
|
26677
|
+
async function updateFieldById({ _id, field, value } = {}, session) {
|
|
26678
|
+
const allowedFields = [
|
|
26679
|
+
"name",
|
|
26680
|
+
"country",
|
|
26681
|
+
"address",
|
|
26682
|
+
"continuedAddress",
|
|
26683
|
+
"city",
|
|
26684
|
+
"province",
|
|
26685
|
+
"postalCode",
|
|
26686
|
+
"courses",
|
|
26687
|
+
"email",
|
|
26688
|
+
"principalName",
|
|
26689
|
+
"principalEmail",
|
|
26690
|
+
"principalNumber",
|
|
26691
|
+
"region",
|
|
26692
|
+
"regionName",
|
|
26693
|
+
"division",
|
|
26694
|
+
"divisionName"
|
|
26695
|
+
];
|
|
26696
|
+
if (!allowedFields.includes(field)) {
|
|
26697
|
+
throw new BadRequestError56(
|
|
26698
|
+
`Field "${field}" is not allowed to be updated.`
|
|
26699
|
+
);
|
|
26700
|
+
}
|
|
26701
|
+
try {
|
|
26702
|
+
_id = new ObjectId38(_id);
|
|
26703
|
+
} catch (error) {
|
|
26704
|
+
throw new BadRequestError56("Invalid ID.");
|
|
26705
|
+
}
|
|
26706
|
+
try {
|
|
26707
|
+
const result = await collection.updateOne(
|
|
26708
|
+
{ _id },
|
|
26709
|
+
{ $set: { [field]: value } },
|
|
26710
|
+
{ session }
|
|
26711
|
+
);
|
|
26712
|
+
delCachedData();
|
|
26713
|
+
return result;
|
|
26714
|
+
} catch (error) {
|
|
26715
|
+
throw new BadRequestError56(`Failed to update school ${field}.`);
|
|
26716
|
+
}
|
|
26717
|
+
}
|
|
26718
|
+
async function getPendingByCreatedBy(createdBy) {
|
|
26719
|
+
try {
|
|
26720
|
+
createdBy = new ObjectId38(createdBy);
|
|
26721
|
+
} catch (error) {
|
|
26722
|
+
throw new BadRequestError56("Invalid createdBy ID.");
|
|
26723
|
+
}
|
|
26724
|
+
const cacheKey = makeCacheKey18(namespace_collection, {
|
|
26725
|
+
createdBy,
|
|
26726
|
+
status: "pending"
|
|
26727
|
+
});
|
|
26728
|
+
const cachedData = await getCache(cacheKey);
|
|
26729
|
+
if (cachedData) {
|
|
26730
|
+
return cachedData;
|
|
26731
|
+
}
|
|
26732
|
+
try {
|
|
26733
|
+
const school = await collection.findOne({ createdBy, status: "pending" });
|
|
26734
|
+
setCache(cacheKey, school, 600, namespace_collection).then(() => {
|
|
26735
|
+
logger26.log({
|
|
26736
|
+
level: "info",
|
|
26737
|
+
message: `Cache set for school by createdBy: ${cacheKey}`
|
|
26738
|
+
});
|
|
26739
|
+
}).catch((err) => {
|
|
26740
|
+
logger26.log({
|
|
26741
|
+
level: "error",
|
|
26742
|
+
message: `Failed to set cache for school by createdBy: ${err.message}`
|
|
26743
|
+
});
|
|
26744
|
+
});
|
|
26745
|
+
return school;
|
|
26746
|
+
} catch (error) {
|
|
26747
|
+
throw error;
|
|
26748
|
+
}
|
|
26749
|
+
}
|
|
26750
|
+
async function getPendingById(_id) {
|
|
26751
|
+
try {
|
|
26752
|
+
_id = new ObjectId38(_id);
|
|
26753
|
+
} catch (error) {
|
|
26754
|
+
throw new BadRequestError56("Invalid ID.");
|
|
26755
|
+
}
|
|
26756
|
+
const cacheKey = makeCacheKey18(namespace_collection, {
|
|
26757
|
+
_id,
|
|
26758
|
+
status: "pending"
|
|
26759
|
+
});
|
|
26760
|
+
const cachedData = await getCache(cacheKey);
|
|
26761
|
+
if (cachedData) {
|
|
26762
|
+
return cachedData;
|
|
26763
|
+
}
|
|
26764
|
+
try {
|
|
26765
|
+
const school = await collection.findOne({ _id, status: "pending" });
|
|
26766
|
+
setCache(cacheKey, school, 600, namespace_collection).then(() => {
|
|
26767
|
+
logger26.log({
|
|
26768
|
+
level: "info",
|
|
26769
|
+
message: `Cache set for school by ID: ${cacheKey}`
|
|
26770
|
+
});
|
|
26771
|
+
}).catch((err) => {
|
|
26772
|
+
logger26.log({
|
|
26773
|
+
level: "error",
|
|
26774
|
+
message: `Failed to set cache for school by ID: ${err.message}`
|
|
26775
|
+
});
|
|
26776
|
+
});
|
|
26777
|
+
return school;
|
|
26778
|
+
} catch (error) {
|
|
26779
|
+
throw error;
|
|
26780
|
+
}
|
|
26781
|
+
}
|
|
26782
|
+
return {
|
|
26783
|
+
createIndex,
|
|
26784
|
+
add,
|
|
26785
|
+
getAll,
|
|
26786
|
+
updateStatusById,
|
|
26787
|
+
updateFieldById,
|
|
26788
|
+
getPendingByCreatedBy,
|
|
26789
|
+
getPendingById
|
|
26790
|
+
};
|
|
26791
|
+
}
|
|
26792
|
+
|
|
26793
|
+
// src/services/school.service.ts
|
|
26794
|
+
import { BadRequestError as BadRequestError57, useAtlas as useAtlas30, logger as logger27 } from "@eeplatform/nodejs-utils";
|
|
26795
|
+
function useSchoolService() {
|
|
26796
|
+
const { add, getPendingByCreatedBy, updateStatusById, getPendingById } = useSchoolRepo();
|
|
26797
|
+
const { addRole } = useRoleRepo();
|
|
26798
|
+
const { getUserById } = useUserRepo();
|
|
26799
|
+
const { add: addMember } = useMemberRepo();
|
|
26800
|
+
async function register(value) {
|
|
26801
|
+
const { error } = schemaSchool.validate(value);
|
|
26802
|
+
if (error) {
|
|
26803
|
+
throw new BadRequestError57(error.message);
|
|
26804
|
+
}
|
|
26805
|
+
const existingSchool = await getPendingByCreatedBy(value.createdBy ?? "");
|
|
26806
|
+
if (existingSchool) {
|
|
26807
|
+
throw new BadRequestError57(
|
|
26808
|
+
"You already have a pending school registration."
|
|
26809
|
+
);
|
|
26810
|
+
}
|
|
26811
|
+
try {
|
|
26812
|
+
value.status = "pending";
|
|
26813
|
+
await add(value);
|
|
26814
|
+
return "Request to register school has been sent successfully. Please wait for approval.";
|
|
26815
|
+
} catch (error2) {
|
|
26816
|
+
throw error2;
|
|
26817
|
+
}
|
|
26818
|
+
}
|
|
26819
|
+
async function approve(id) {
|
|
26820
|
+
const school = await getPendingById(id);
|
|
26821
|
+
if (!school) {
|
|
26822
|
+
throw new BadRequestError57("School registration not found.");
|
|
26823
|
+
}
|
|
26824
|
+
const session = useAtlas30.getClient()?.startSession();
|
|
26825
|
+
if (!session) {
|
|
26826
|
+
throw new Error("Unable to start session for school service.");
|
|
26827
|
+
}
|
|
26828
|
+
try {
|
|
26829
|
+
session.startTransaction();
|
|
26830
|
+
school.status = "approved";
|
|
26831
|
+
await updateStatusById(id, "active", session);
|
|
26832
|
+
const roleType = "school";
|
|
26833
|
+
const roleName = "Admin";
|
|
26834
|
+
const roleId = await addRole(
|
|
26835
|
+
{
|
|
26836
|
+
id,
|
|
26837
|
+
type: roleType,
|
|
26838
|
+
name: roleName,
|
|
26839
|
+
permissions: ["*"],
|
|
26840
|
+
status: "active",
|
|
26841
|
+
default: true
|
|
26842
|
+
},
|
|
26843
|
+
session
|
|
26844
|
+
);
|
|
26845
|
+
if (!school.createdBy) {
|
|
26846
|
+
throw new BadRequestError57("School must have a creator.");
|
|
26847
|
+
}
|
|
26848
|
+
const user = await getUserById(school.createdBy ?? "");
|
|
26849
|
+
if (!user) {
|
|
26850
|
+
throw new BadRequestError57("User not found for the school creator.");
|
|
26851
|
+
}
|
|
26852
|
+
await addMember(
|
|
26853
|
+
{
|
|
26854
|
+
org: id,
|
|
26855
|
+
orgName: school.name,
|
|
26856
|
+
user: school.createdBy.toString(),
|
|
26857
|
+
name: `${user.firstName} ${user.lastName}`,
|
|
26858
|
+
role: roleId.toString(),
|
|
26859
|
+
roleName,
|
|
26860
|
+
type: roleType
|
|
26861
|
+
},
|
|
26862
|
+
session
|
|
26863
|
+
);
|
|
26864
|
+
await session.commitTransaction();
|
|
26865
|
+
return "School registration has been approved.";
|
|
26866
|
+
} catch (error) {
|
|
26867
|
+
logger27.log({
|
|
26868
|
+
level: "error",
|
|
26869
|
+
message: `Error approving school registration: ${error.message}`
|
|
26870
|
+
});
|
|
26871
|
+
await session.abortTransaction();
|
|
26872
|
+
throw error;
|
|
26873
|
+
} finally {
|
|
26874
|
+
await session.endSession();
|
|
26875
|
+
}
|
|
26876
|
+
}
|
|
26877
|
+
return {
|
|
26878
|
+
register,
|
|
26879
|
+
approve
|
|
26880
|
+
};
|
|
26881
|
+
}
|
|
26882
|
+
|
|
26883
|
+
// src/controllers/school.controller.ts
|
|
26884
|
+
import { BadRequestError as BadRequestError58 } from "@eeplatform/nodejs-utils";
|
|
26885
|
+
import Joi32 from "joi";
|
|
26886
|
+
function useSchoolController() {
|
|
26887
|
+
const {
|
|
26888
|
+
add: _add,
|
|
26889
|
+
getAll: _getAll,
|
|
26890
|
+
getPendingByCreatedBy: _getPendingByCreatedBy,
|
|
26891
|
+
updateStatusById: _updateStatusById
|
|
26892
|
+
} = useSchoolRepo();
|
|
26893
|
+
async function add(req, res, next) {
|
|
26894
|
+
const payload = req.body;
|
|
26895
|
+
const { error } = schemaSchool.validate(payload);
|
|
26896
|
+
if (error) {
|
|
26897
|
+
next(new BadRequestError58(`Validation error: ${error.message}`));
|
|
26898
|
+
return;
|
|
26899
|
+
}
|
|
26900
|
+
try {
|
|
26901
|
+
const school = await _add(payload);
|
|
26902
|
+
res.status(201).json(school);
|
|
26903
|
+
return;
|
|
26904
|
+
} catch (error2) {
|
|
26905
|
+
next(error2);
|
|
26906
|
+
return;
|
|
26907
|
+
}
|
|
26908
|
+
}
|
|
26909
|
+
async function getAll(req, res, next) {
|
|
26910
|
+
const validation = Joi32.object({
|
|
26911
|
+
page: Joi32.number().optional().allow(null, ""),
|
|
26912
|
+
limit: Joi32.number().optional().allow(null, ""),
|
|
26913
|
+
sort: Joi32.string().optional().allow(null, ""),
|
|
26914
|
+
sortOrder: Joi32.string().optional().allow(null, ""),
|
|
26915
|
+
status: Joi32.string().optional().allow(null, ""),
|
|
26916
|
+
org: Joi32.string().hex().optional().allow(null, ""),
|
|
26917
|
+
app: Joi32.string().optional().allow(null, ""),
|
|
26918
|
+
search: Joi32.string().optional().allow(null, "")
|
|
26919
|
+
});
|
|
26920
|
+
const { error } = validation.validate(req.query);
|
|
26921
|
+
if (error) {
|
|
26922
|
+
next(new BadRequestError58(`Validation error: ${error.message}`));
|
|
26923
|
+
return;
|
|
26924
|
+
}
|
|
26925
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
26926
|
+
let limit = parseInt(req.query.limit) ?? 20;
|
|
26927
|
+
limit = isNaN(limit) ? 20 : limit;
|
|
26928
|
+
const sort = req.query.sort ? String(req.query.sort).split(",") : "";
|
|
26929
|
+
const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
|
|
26930
|
+
const sortObj = {};
|
|
26931
|
+
if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
|
|
26932
|
+
sort.forEach((field, index) => {
|
|
26933
|
+
sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
|
|
26934
|
+
});
|
|
26935
|
+
}
|
|
26936
|
+
const status = req.query.status ?? "active";
|
|
26937
|
+
const org = req.query.org ?? "";
|
|
26938
|
+
const app = req.query.app ?? "admin";
|
|
26939
|
+
const search = req.query.search ?? "";
|
|
26940
|
+
try {
|
|
26941
|
+
const schools = await _getAll({
|
|
26942
|
+
page,
|
|
26943
|
+
limit,
|
|
26944
|
+
sort: sortObj,
|
|
26945
|
+
status,
|
|
26946
|
+
org,
|
|
26947
|
+
app,
|
|
26948
|
+
search
|
|
26949
|
+
});
|
|
26950
|
+
res.status(200).json(schools);
|
|
26951
|
+
return;
|
|
26952
|
+
} catch (error2) {
|
|
26953
|
+
next(error2);
|
|
26954
|
+
}
|
|
26955
|
+
}
|
|
26956
|
+
async function getByCreatedBy(req, res, next) {
|
|
26957
|
+
const createdBy = req.params.createdBy;
|
|
26958
|
+
const validation = Joi32.string().hex().required();
|
|
26959
|
+
const { error } = validation.validate(createdBy);
|
|
26960
|
+
if (error) {
|
|
26961
|
+
next(new BadRequestError58(`Validation error: ${error.message}`));
|
|
26962
|
+
return;
|
|
26963
|
+
}
|
|
26964
|
+
try {
|
|
26965
|
+
const school = await _getPendingByCreatedBy(createdBy);
|
|
26966
|
+
res.status(200).json(school);
|
|
26967
|
+
return;
|
|
26968
|
+
} catch (error2) {
|
|
26969
|
+
next(error2);
|
|
26970
|
+
}
|
|
26971
|
+
}
|
|
26972
|
+
async function updateStatusById(req, res, next) {
|
|
26973
|
+
const schoolId = req.params.id;
|
|
26974
|
+
const status = req.params.status;
|
|
26975
|
+
const validation = Joi32.object({
|
|
26976
|
+
id: Joi32.string().hex().required(),
|
|
26977
|
+
status: Joi32.string().valid("active", "deleted", "suspended").required()
|
|
26978
|
+
});
|
|
26979
|
+
const { error } = validation.validate({ id: schoolId, status });
|
|
26980
|
+
if (error) {
|
|
26981
|
+
next(new BadRequestError58(`Validation error: ${error.message}`));
|
|
26982
|
+
return;
|
|
26983
|
+
}
|
|
26984
|
+
try {
|
|
26985
|
+
const updatedSchool = await _updateStatusById(schoolId, status);
|
|
26986
|
+
res.status(200).json(updatedSchool);
|
|
26987
|
+
return;
|
|
26988
|
+
} catch (error2) {
|
|
26989
|
+
next(error2);
|
|
26990
|
+
}
|
|
26991
|
+
}
|
|
26992
|
+
const { register: _registerSchool, approve } = useSchoolService();
|
|
26993
|
+
async function registerSchool(req, res, next) {
|
|
26994
|
+
const payload = req.body;
|
|
26995
|
+
const { error } = schemaSchool.validate(payload);
|
|
26996
|
+
if (error) {
|
|
26997
|
+
next(new BadRequestError58(`Validation error: ${error.message}`));
|
|
26998
|
+
return;
|
|
26999
|
+
}
|
|
27000
|
+
try {
|
|
27001
|
+
const schoolId = await _registerSchool(payload);
|
|
27002
|
+
res.status(201).json({ schoolId });
|
|
27003
|
+
return;
|
|
27004
|
+
} catch (error2) {
|
|
27005
|
+
next(error2);
|
|
27006
|
+
return;
|
|
27007
|
+
}
|
|
27008
|
+
}
|
|
27009
|
+
async function approveSchool(req, res, next) {
|
|
27010
|
+
const schoolId = req.params.id;
|
|
27011
|
+
const validation = Joi32.object({
|
|
27012
|
+
id: Joi32.string().hex().required()
|
|
27013
|
+
});
|
|
27014
|
+
const { error } = validation.validate({ id: schoolId });
|
|
27015
|
+
if (error) {
|
|
27016
|
+
next(new BadRequestError58(`Validation error: ${error.message}`));
|
|
27017
|
+
return;
|
|
27018
|
+
}
|
|
27019
|
+
try {
|
|
27020
|
+
const updatedSchool = await approve(schoolId);
|
|
27021
|
+
res.status(200).json(updatedSchool);
|
|
27022
|
+
return;
|
|
27023
|
+
} catch (error2) {
|
|
27024
|
+
next(error2);
|
|
27025
|
+
}
|
|
27026
|
+
}
|
|
27027
|
+
return {
|
|
27028
|
+
add,
|
|
27029
|
+
getAll,
|
|
27030
|
+
getByCreatedBy,
|
|
27031
|
+
updateStatusById,
|
|
27032
|
+
registerSchool,
|
|
27033
|
+
approveSchool
|
|
27034
|
+
};
|
|
27035
|
+
}
|
|
25338
27036
|
export {
|
|
25339
27037
|
ACCESS_TOKEN_EXPIRY,
|
|
25340
27038
|
ACCESS_TOKEN_SECRET,
|
|
@@ -25353,6 +27051,7 @@ export {
|
|
|
25353
27051
|
MAILER_TRANSPORT_PORT,
|
|
25354
27052
|
MAILER_TRANSPORT_SECURE,
|
|
25355
27053
|
MAddress,
|
|
27054
|
+
MDivision,
|
|
25356
27055
|
MEntity,
|
|
25357
27056
|
MFile,
|
|
25358
27057
|
MMember,
|
|
@@ -25362,7 +27061,9 @@ export {
|
|
|
25362
27061
|
MOrg,
|
|
25363
27062
|
MPaymentMethod,
|
|
25364
27063
|
MPromoCode,
|
|
27064
|
+
MRegion,
|
|
25365
27065
|
MRole,
|
|
27066
|
+
MSchool,
|
|
25366
27067
|
MSubscription,
|
|
25367
27068
|
MToken,
|
|
25368
27069
|
MUser,
|
|
@@ -25390,12 +27091,17 @@ export {
|
|
|
25390
27091
|
addressSchema,
|
|
25391
27092
|
isDev,
|
|
25392
27093
|
schema,
|
|
27094
|
+
schemaDivision,
|
|
27095
|
+
schemaRegion,
|
|
27096
|
+
schemaSchool,
|
|
25393
27097
|
useAddressController,
|
|
25394
27098
|
useAddressRepo,
|
|
25395
27099
|
useAuthController,
|
|
25396
27100
|
useAuthService,
|
|
25397
27101
|
useCounterModel,
|
|
25398
27102
|
useCounterRepo,
|
|
27103
|
+
useDivisionController,
|
|
27104
|
+
useDivisionRepo,
|
|
25399
27105
|
useEntityController,
|
|
25400
27106
|
useEntityRepo,
|
|
25401
27107
|
useFileController,
|
|
@@ -25424,8 +27130,13 @@ export {
|
|
|
25424
27130
|
usePriceRepo,
|
|
25425
27131
|
usePromoCodeController,
|
|
25426
27132
|
usePromoCodeRepo,
|
|
27133
|
+
useRegionController,
|
|
27134
|
+
useRegionRepo,
|
|
25427
27135
|
useRoleController,
|
|
25428
27136
|
useRoleRepo,
|
|
27137
|
+
useSchoolController,
|
|
27138
|
+
useSchoolRepo,
|
|
27139
|
+
useSchoolService,
|
|
25429
27140
|
useSubscriptionController,
|
|
25430
27141
|
useSubscriptionRepo,
|
|
25431
27142
|
useSubscriptionService,
|