@eeplatform/basic-edu 1.5.2 → 1.7.0
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/CONVENTION.md +632 -0
- package/dist/index.d.ts +324 -2
- package/dist/index.js +3111 -319
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3134 -322
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1344,10 +1344,13 @@ var require_papaparse = __commonJS({
|
|
|
1344
1344
|
var src_exports = {};
|
|
1345
1345
|
__export(src_exports, {
|
|
1346
1346
|
MAsset: () => MAsset,
|
|
1347
|
+
MBuilding: () => MBuilding,
|
|
1348
|
+
MBuildingUnit: () => MBuildingUnit,
|
|
1347
1349
|
MCurriculum: () => MCurriculum,
|
|
1348
1350
|
MCurriculumSubject: () => MCurriculumSubject,
|
|
1349
1351
|
MGradeLevel: () => MGradeLevel,
|
|
1350
1352
|
MLearner: () => MLearner,
|
|
1353
|
+
MPersonnel: () => MPersonnel,
|
|
1351
1354
|
MPlantilla: () => MPlantilla,
|
|
1352
1355
|
MStockCard: () => MStockCard,
|
|
1353
1356
|
allowedSectionStudentStatuses: () => allowedSectionStudentStatuses,
|
|
@@ -1358,9 +1361,12 @@ __export(src_exports, {
|
|
|
1358
1361
|
modelSection: () => modelSection,
|
|
1359
1362
|
modelSectionPreset: () => modelSectionPreset,
|
|
1360
1363
|
modelSectionStudent: () => modelSectionStudent,
|
|
1364
|
+
modelSectionSubject: () => modelSectionSubject,
|
|
1361
1365
|
schemaAsset: () => schemaAsset,
|
|
1362
1366
|
schemaAssetUpdateOption: () => schemaAssetUpdateOption,
|
|
1363
1367
|
schemaBasicEduCount: () => schemaBasicEduCount,
|
|
1368
|
+
schemaBuilding: () => schemaBuilding,
|
|
1369
|
+
schemaBuildingUnit: () => schemaBuildingUnit,
|
|
1364
1370
|
schemaCurriculum: () => schemaCurriculum,
|
|
1365
1371
|
schemaCurriculumSubject: () => schemaCurriculumSubject,
|
|
1366
1372
|
schemaCurriculumSubjectAdd: () => schemaCurriculumSubjectAdd,
|
|
@@ -1369,6 +1375,7 @@ __export(src_exports, {
|
|
|
1369
1375
|
schemaEnrollment: () => schemaEnrollment,
|
|
1370
1376
|
schemaGenerateSections: () => schemaGenerateSections,
|
|
1371
1377
|
schemaGradeLevel: () => schemaGradeLevel,
|
|
1378
|
+
schemaPersonnel: () => schemaPersonnel,
|
|
1372
1379
|
schemaPlantilla: () => schemaPlantilla,
|
|
1373
1380
|
schemaRegion: () => schemaRegion,
|
|
1374
1381
|
schemaSchool: () => schemaSchool,
|
|
@@ -1376,11 +1383,20 @@ __export(src_exports, {
|
|
|
1376
1383
|
schemaSection: () => schemaSection,
|
|
1377
1384
|
schemaSectionPreset: () => schemaSectionPreset,
|
|
1378
1385
|
schemaSectionStudent: () => schemaSectionStudent,
|
|
1386
|
+
schemaSectionSubject: () => schemaSectionSubject,
|
|
1387
|
+
schemaSectionSubjectSetup: () => schemaSectionSubjectSetup,
|
|
1379
1388
|
schemaStockCard: () => schemaStockCard,
|
|
1389
|
+
schemaUpdateOptions: () => schemaUpdateOptions,
|
|
1380
1390
|
schemaUpdateStatus: () => schemaUpdateStatus,
|
|
1381
1391
|
useAssetController: () => useAssetController,
|
|
1382
1392
|
useAssetRepo: () => useAssetRepo,
|
|
1383
1393
|
useBasicEduCountRepo: () => useBasicEduCountRepo,
|
|
1394
|
+
useBuildingController: () => useBuildingController,
|
|
1395
|
+
useBuildingRepo: () => useBuildingRepo,
|
|
1396
|
+
useBuildingService: () => useBuildingService,
|
|
1397
|
+
useBuildingUnitController: () => useBuildingUnitController,
|
|
1398
|
+
useBuildingUnitRepo: () => useBuildingUnitRepo,
|
|
1399
|
+
useBuildingUnitService: () => useBuildingUnitService,
|
|
1384
1400
|
useCurriculumController: () => useCurriculumController,
|
|
1385
1401
|
useCurriculumRepo: () => useCurriculumRepo,
|
|
1386
1402
|
useCurriculumSubjectController: () => useCurriculumSubjectController,
|
|
@@ -1396,6 +1412,8 @@ __export(src_exports, {
|
|
|
1396
1412
|
useGradeLevelRepo: () => useGradeLevelRepo,
|
|
1397
1413
|
useLearnerController: () => useLearnerController,
|
|
1398
1414
|
useLearnerRepo: () => useLearnerRepo,
|
|
1415
|
+
usePersonnelController: () => usePersonnelController,
|
|
1416
|
+
usePersonnelRepo: () => usePersonnelRepo,
|
|
1399
1417
|
usePlantillaController: () => usePlantillaController,
|
|
1400
1418
|
usePlantillaRepo: () => usePlantillaRepo,
|
|
1401
1419
|
usePlantillaService: () => usePlantillaService,
|
|
@@ -1408,7 +1426,11 @@ __export(src_exports, {
|
|
|
1408
1426
|
useSectionPresetController: () => useSectionPresetController,
|
|
1409
1427
|
useSectionPresetRepo: () => useSectionPresetRepo,
|
|
1410
1428
|
useSectionRepo: () => useSectionRepo,
|
|
1429
|
+
useSectionStudentController: () => useSectionStudentController,
|
|
1411
1430
|
useSectionStudentRepo: () => useSectionStudentRepo,
|
|
1431
|
+
useSectionSubjectController: () => useSectionSubjectController,
|
|
1432
|
+
useSectionSubjectRepo: () => useSectionSubjectRepo,
|
|
1433
|
+
useSectionSubjectService: () => useSectionSubjectService,
|
|
1412
1434
|
useStockCardController: () => useStockCardController,
|
|
1413
1435
|
useStockCardRepository: () => useStockCardRepository,
|
|
1414
1436
|
useStockCardService: () => useStockCardService
|
|
@@ -3587,8 +3609,11 @@ function useLearnerRepo() {
|
|
|
3587
3609
|
}
|
|
3588
3610
|
}
|
|
3589
3611
|
async function getByGradeLevel(value, session) {
|
|
3612
|
+
value.limit = value.limit && value.limit > 0 ? value.limit : 50;
|
|
3613
|
+
value.skip = value.skip && value.skip > 0 ? value.skip - 1 : 0;
|
|
3590
3614
|
const validation = import_joi7.default.object({
|
|
3591
3615
|
school: import_joi7.default.string().hex().required(),
|
|
3616
|
+
schoolYear: import_joi7.default.string().optional(),
|
|
3592
3617
|
gradeLevel: import_joi7.default.string().required(),
|
|
3593
3618
|
status: import_joi7.default.string().optional().allow("", null),
|
|
3594
3619
|
limit: import_joi7.default.number().integer().required(),
|
|
@@ -3605,8 +3630,14 @@ function useLearnerRepo() {
|
|
|
3605
3630
|
};
|
|
3606
3631
|
const cacheKeyOptions = {
|
|
3607
3632
|
...query,
|
|
3608
|
-
tag: "byGradeLevel"
|
|
3633
|
+
tag: "byGradeLevel",
|
|
3634
|
+
limit: value.limit,
|
|
3635
|
+
skip: value.skip
|
|
3609
3636
|
};
|
|
3637
|
+
if (value.schoolYear) {
|
|
3638
|
+
query.schoolYear = value.schoolYear;
|
|
3639
|
+
cacheKeyOptions.schoolYear = value.schoolYear;
|
|
3640
|
+
}
|
|
3610
3641
|
if (value.school && typeof value.school === "string") {
|
|
3611
3642
|
try {
|
|
3612
3643
|
query.school = new import_mongodb7.ObjectId(value.school);
|
|
@@ -3626,11 +3657,7 @@ function useLearnerRepo() {
|
|
|
3626
3657
|
}
|
|
3627
3658
|
try {
|
|
3628
3659
|
const data = await collection.aggregate(
|
|
3629
|
-
[
|
|
3630
|
-
{ $match: query },
|
|
3631
|
-
{ $skip: value.skip ?? 0 },
|
|
3632
|
-
{ $limit: value.limit ?? 100 }
|
|
3633
|
-
],
|
|
3660
|
+
[{ $match: query }, { $skip: value.skip }, { $limit: value.limit }],
|
|
3634
3661
|
{ session }
|
|
3635
3662
|
).toArray();
|
|
3636
3663
|
setCache(cacheKey, data, 600).then(() => {
|
|
@@ -37820,11 +37847,11 @@ function useSectionRepo() {
|
|
|
37820
37847
|
}
|
|
37821
37848
|
|
|
37822
37849
|
// src/resources/section/section.controller.ts
|
|
37823
|
-
var
|
|
37824
|
-
var
|
|
37850
|
+
var import_nodejs_utils53 = require("@eeplatform/nodejs-utils");
|
|
37851
|
+
var import_joi32 = __toESM(require("joi"));
|
|
37825
37852
|
|
|
37826
37853
|
// src/resources/section/section.service.ts
|
|
37827
|
-
var
|
|
37854
|
+
var import_nodejs_utils52 = require("@eeplatform/nodejs-utils");
|
|
37828
37855
|
|
|
37829
37856
|
// src/resources/section-student/section.student.repository.ts
|
|
37830
37857
|
var import_nodejs_utils47 = require("@eeplatform/nodejs-utils");
|
|
@@ -37841,9 +37868,15 @@ var allowedSectionStudentStatuses = [
|
|
|
37841
37868
|
];
|
|
37842
37869
|
var schemaSectionStudent = import_joi28.default.object({
|
|
37843
37870
|
_id: import_joi28.default.string().hex().optional().allow(null, ""),
|
|
37871
|
+
lrn: import_joi28.default.string().required(),
|
|
37872
|
+
school: import_joi28.default.string().hex().required(),
|
|
37873
|
+
schoolName: import_joi28.default.string().optional().allow(null, ""),
|
|
37844
37874
|
section: import_joi28.default.string().hex().required(),
|
|
37845
37875
|
student: import_joi28.default.string().required(),
|
|
37846
37876
|
studentName: import_joi28.default.string().required(),
|
|
37877
|
+
gradeLevel: import_joi28.default.string().optional().allow(null, ""),
|
|
37878
|
+
educationLevel: import_joi28.default.string().optional().allow(null, ""),
|
|
37879
|
+
schoolYear: import_joi28.default.string().optional().allow(null, ""),
|
|
37847
37880
|
status: import_joi28.default.string().valid(...allowedSectionStudentStatuses).optional().allow(null, ""),
|
|
37848
37881
|
assignedAt: import_joi28.default.string().isoDate().optional().allow(null, ""),
|
|
37849
37882
|
updatedAt: import_joi28.default.string().isoDate().optional().allow(null, "")
|
|
@@ -37867,11 +37900,24 @@ function modelSectionStudent(value) {
|
|
|
37867
37900
|
throw new Error("Invalid section ID.");
|
|
37868
37901
|
}
|
|
37869
37902
|
}
|
|
37903
|
+
if (value.school && typeof value.school === "string") {
|
|
37904
|
+
try {
|
|
37905
|
+
value.school = new import_mongodb27.ObjectId(value.school);
|
|
37906
|
+
} catch (error2) {
|
|
37907
|
+
throw new Error("Invalid school ID.");
|
|
37908
|
+
}
|
|
37909
|
+
}
|
|
37870
37910
|
return {
|
|
37871
37911
|
_id: value._id,
|
|
37912
|
+
lrn: value.lrn,
|
|
37913
|
+
school: value.school,
|
|
37914
|
+
schoolName: value.schoolName,
|
|
37872
37915
|
section: value.section,
|
|
37873
37916
|
student: value.student,
|
|
37874
37917
|
studentName: value.studentName,
|
|
37918
|
+
gradeLevel: value.gradeLevel,
|
|
37919
|
+
educationLevel: value.educationLevel,
|
|
37920
|
+
schoolYear: value.schoolYear,
|
|
37875
37921
|
status: value.status ?? "active",
|
|
37876
37922
|
assignedAt: value.assignedAt ?? "",
|
|
37877
37923
|
updatedAt: value.updatedAt ?? ""
|
|
@@ -37879,6 +37925,8 @@ function modelSectionStudent(value) {
|
|
|
37879
37925
|
}
|
|
37880
37926
|
|
|
37881
37927
|
// src/resources/section-student/section.student.repository.ts
|
|
37928
|
+
var import_mongodb28 = require("mongodb");
|
|
37929
|
+
var import_joi29 = __toESM(require("joi"));
|
|
37882
37930
|
function useSectionStudentRepo() {
|
|
37883
37931
|
const db = import_nodejs_utils47.useAtlas.getDb();
|
|
37884
37932
|
if (!db) {
|
|
@@ -37942,377 +37990,900 @@ function useSectionStudentRepo() {
|
|
|
37942
37990
|
}
|
|
37943
37991
|
}
|
|
37944
37992
|
}
|
|
37993
|
+
async function getAll({
|
|
37994
|
+
page = 1,
|
|
37995
|
+
limit = 10,
|
|
37996
|
+
search = "",
|
|
37997
|
+
school = "",
|
|
37998
|
+
status = "",
|
|
37999
|
+
gradeLevel = "",
|
|
38000
|
+
section = "",
|
|
38001
|
+
schoolYear = ""
|
|
38002
|
+
} = {}) {
|
|
38003
|
+
const { error } = import_joi29.default.object({
|
|
38004
|
+
page: import_joi29.default.number().min(1).default(1),
|
|
38005
|
+
limit: import_joi29.default.number().min(1).max(100).default(10),
|
|
38006
|
+
search: import_joi29.default.string().allow("").default(""),
|
|
38007
|
+
status: import_joi29.default.string().allow("").default(""),
|
|
38008
|
+
school: import_joi29.default.string().hex().allow("").default(""),
|
|
38009
|
+
gradeLevel: import_joi29.default.string().allow("").default(""),
|
|
38010
|
+
section: import_joi29.default.string().hex().allow("").default(""),
|
|
38011
|
+
schoolYear: import_joi29.default.string().allow("").default("")
|
|
38012
|
+
}).validate({ page, limit, search, status, school, gradeLevel, section });
|
|
38013
|
+
if (error) {
|
|
38014
|
+
throw new import_nodejs_utils47.BadRequestError(error.details[0].message);
|
|
38015
|
+
}
|
|
38016
|
+
const query = { status: { $ne: "deleted" } };
|
|
38017
|
+
const cacheKeyOptions = { page, limit };
|
|
38018
|
+
if (status) {
|
|
38019
|
+
query.status = status;
|
|
38020
|
+
cacheKeyOptions.status = status;
|
|
38021
|
+
}
|
|
38022
|
+
if (school && typeof school === "string") {
|
|
38023
|
+
try {
|
|
38024
|
+
query.school = new import_mongodb28.ObjectId(school);
|
|
38025
|
+
} catch (error2) {
|
|
38026
|
+
throw new import_nodejs_utils47.BadRequestError("Invalid school ID format.");
|
|
38027
|
+
}
|
|
38028
|
+
cacheKeyOptions.school = school;
|
|
38029
|
+
}
|
|
38030
|
+
if (gradeLevel) {
|
|
38031
|
+
query.gradeLevel = gradeLevel;
|
|
38032
|
+
cacheKeyOptions.gradeLevel = gradeLevel;
|
|
38033
|
+
}
|
|
38034
|
+
if (search) {
|
|
38035
|
+
query.$text = { $search: search };
|
|
38036
|
+
cacheKeyOptions.search = search;
|
|
38037
|
+
}
|
|
38038
|
+
if (section && typeof section === "string") {
|
|
38039
|
+
try {
|
|
38040
|
+
query.section = new import_mongodb28.ObjectId(section);
|
|
38041
|
+
} catch (error2) {
|
|
38042
|
+
throw new import_nodejs_utils47.BadRequestError("Invalid section ID format.");
|
|
38043
|
+
}
|
|
38044
|
+
cacheKeyOptions.section = section;
|
|
38045
|
+
}
|
|
38046
|
+
if (schoolYear) {
|
|
38047
|
+
query.schoolYear = schoolYear;
|
|
38048
|
+
cacheKeyOptions.schoolYear = schoolYear;
|
|
38049
|
+
}
|
|
38050
|
+
const cacheKey = (0, import_nodejs_utils47.makeCacheKey)(namespace_collection, cacheKeyOptions);
|
|
38051
|
+
import_nodejs_utils47.logger.log({
|
|
38052
|
+
level: "info",
|
|
38053
|
+
message: `Cache key for getAll sections: ${cacheKey}`
|
|
38054
|
+
});
|
|
38055
|
+
const cachedData = await getCache(cacheKey);
|
|
38056
|
+
if (cachedData) {
|
|
38057
|
+
import_nodejs_utils47.logger.log({
|
|
38058
|
+
level: "info",
|
|
38059
|
+
message: `Cache hit for getAll sections: ${cacheKey}`
|
|
38060
|
+
});
|
|
38061
|
+
return cachedData;
|
|
38062
|
+
}
|
|
38063
|
+
page = page > 0 ? page - 1 : 0;
|
|
38064
|
+
const items = await collection.aggregate([
|
|
38065
|
+
{ $match: query },
|
|
38066
|
+
{ $skip: page * limit },
|
|
38067
|
+
{ $limit: limit }
|
|
38068
|
+
]).toArray();
|
|
38069
|
+
const length = await collection.countDocuments(query);
|
|
38070
|
+
const data = (0, import_nodejs_utils47.paginate)(items, page, limit, length);
|
|
38071
|
+
setCache(cacheKey, data, 600).then(() => {
|
|
38072
|
+
import_nodejs_utils47.logger.log({
|
|
38073
|
+
level: "info",
|
|
38074
|
+
message: `Cache set for getAll section students: ${cacheKey}`
|
|
38075
|
+
});
|
|
38076
|
+
}).catch((err) => {
|
|
38077
|
+
import_nodejs_utils47.logger.log({
|
|
38078
|
+
level: "error",
|
|
38079
|
+
message: `Failed to set cache for getAll section students: ${err.message}`
|
|
38080
|
+
});
|
|
38081
|
+
});
|
|
38082
|
+
return data;
|
|
38083
|
+
}
|
|
37945
38084
|
return {
|
|
37946
38085
|
createIndexes,
|
|
37947
38086
|
delCachedData,
|
|
37948
|
-
add
|
|
38087
|
+
add,
|
|
38088
|
+
getAll
|
|
37949
38089
|
};
|
|
37950
38090
|
}
|
|
37951
38091
|
|
|
37952
|
-
// src/resources/section/section.
|
|
37953
|
-
|
|
37954
|
-
|
|
37955
|
-
|
|
37956
|
-
|
|
37957
|
-
|
|
37958
|
-
|
|
37959
|
-
|
|
37960
|
-
|
|
37961
|
-
|
|
37962
|
-
|
|
37963
|
-
|
|
37964
|
-
|
|
37965
|
-
|
|
37966
|
-
|
|
37967
|
-
|
|
37968
|
-
|
|
37969
|
-
|
|
37970
|
-
|
|
37971
|
-
|
|
37972
|
-
|
|
37973
|
-
|
|
37974
|
-
|
|
37975
|
-
|
|
37976
|
-
|
|
37977
|
-
|
|
37978
|
-
|
|
37979
|
-
|
|
37980
|
-
|
|
38092
|
+
// src/resources/section-subject/section.subject.model.ts
|
|
38093
|
+
var import_nodejs_utils48 = require("@eeplatform/nodejs-utils");
|
|
38094
|
+
var import_joi30 = __toESM(require("joi"));
|
|
38095
|
+
var import_mongodb29 = require("mongodb");
|
|
38096
|
+
var schemaSectionSubject = import_joi30.default.object({
|
|
38097
|
+
_id: import_joi30.default.string().hex().optional().allow(null, ""),
|
|
38098
|
+
school: import_joi30.default.string().hex().required(),
|
|
38099
|
+
schoolName: import_joi30.default.string().optional().allow(null, ""),
|
|
38100
|
+
section: import_joi30.default.string().hex().required(),
|
|
38101
|
+
sectionName: import_joi30.default.string().required(),
|
|
38102
|
+
gradeLevel: import_joi30.default.string().required(),
|
|
38103
|
+
educationLevel: import_joi30.default.string().required(),
|
|
38104
|
+
schoolYear: import_joi30.default.string().required(),
|
|
38105
|
+
subjectCode: import_joi30.default.string().required(),
|
|
38106
|
+
subjectName: import_joi30.default.string().required(),
|
|
38107
|
+
teacher: import_joi30.default.string().hex().optional().allow(null, ""),
|
|
38108
|
+
teacherName: import_joi30.default.string().optional().allow(null, ""),
|
|
38109
|
+
classroom: import_joi30.default.string().optional().allow(null, ""),
|
|
38110
|
+
classroomName: import_joi30.default.string().optional().allow(null, ""),
|
|
38111
|
+
daysOfWeek: import_joi30.default.array().items(import_joi30.default.string()).optional().allow(null),
|
|
38112
|
+
schedule: import_joi30.default.string().optional().allow(null, ""),
|
|
38113
|
+
sessionDuration: import_joi30.default.number().optional().allow(null, 0),
|
|
38114
|
+
sessionFrequency: import_joi30.default.number().optional().allow(null, 0),
|
|
38115
|
+
status: import_joi30.default.string().valid("active", "draft").optional(),
|
|
38116
|
+
createdAt: import_joi30.default.string().isoDate().optional().allow(null, ""),
|
|
38117
|
+
updatedAt: import_joi30.default.string().isoDate().optional().allow(null, ""),
|
|
38118
|
+
deletedAt: import_joi30.default.string().isoDate().optional().allow(null, "")
|
|
38119
|
+
});
|
|
38120
|
+
var schemaSectionSubjectSetup = import_joi30.default.object({
|
|
38121
|
+
teacher: import_joi30.default.string().hex().optional().allow(null, ""),
|
|
38122
|
+
teacherName: import_joi30.default.string().optional().allow(null, ""),
|
|
38123
|
+
classroom: import_joi30.default.string().optional().allow(null, ""),
|
|
38124
|
+
classroomName: import_joi30.default.string().optional().allow(null, ""),
|
|
38125
|
+
daysOfWeek: import_joi30.default.array().items(import_joi30.default.string()).optional().allow(null),
|
|
38126
|
+
schedule: import_joi30.default.string().optional().allow(null, "")
|
|
38127
|
+
});
|
|
38128
|
+
function modelSectionSubject(value) {
|
|
38129
|
+
const { error } = schemaSectionSubject.validate(value);
|
|
38130
|
+
if (error) {
|
|
38131
|
+
throw new import_nodejs_utils48.BadRequestError(`Invalid section subject data: ${error.message}`);
|
|
38132
|
+
}
|
|
38133
|
+
if (value._id && typeof value._id === "string") {
|
|
38134
|
+
try {
|
|
38135
|
+
value._id = new import_mongodb29.ObjectId(value._id);
|
|
38136
|
+
} catch (error2) {
|
|
38137
|
+
throw new Error("Invalid _id.");
|
|
37981
38138
|
}
|
|
37982
|
-
|
|
37983
|
-
|
|
37984
|
-
|
|
37985
|
-
|
|
37986
|
-
|
|
37987
|
-
|
|
38139
|
+
}
|
|
38140
|
+
if (value.school && typeof value.school === "string") {
|
|
38141
|
+
try {
|
|
38142
|
+
value.school = new import_mongodb29.ObjectId(value.school);
|
|
38143
|
+
} catch (error2) {
|
|
38144
|
+
throw new Error("Invalid school ID.");
|
|
37988
38145
|
}
|
|
37989
|
-
return sizes;
|
|
37990
38146
|
}
|
|
37991
|
-
|
|
37992
|
-
|
|
37993
|
-
|
|
37994
|
-
|
|
37995
|
-
|
|
37996
|
-
);
|
|
38147
|
+
if (value.section && typeof value.section === "string") {
|
|
38148
|
+
try {
|
|
38149
|
+
value.section = new import_mongodb29.ObjectId(value.section);
|
|
38150
|
+
} catch (error2) {
|
|
38151
|
+
throw new Error("Invalid section ID.");
|
|
37997
38152
|
}
|
|
37998
|
-
|
|
37999
|
-
|
|
38000
|
-
|
|
38153
|
+
}
|
|
38154
|
+
if (value.teacher && typeof value.teacher === "string") {
|
|
38155
|
+
try {
|
|
38156
|
+
value.teacher = new import_mongodb29.ObjectId(value.teacher);
|
|
38157
|
+
} catch (error2) {
|
|
38158
|
+
throw new Error("Invalid teacher ID.");
|
|
38001
38159
|
}
|
|
38160
|
+
}
|
|
38161
|
+
return {
|
|
38162
|
+
_id: value._id,
|
|
38163
|
+
school: value.school,
|
|
38164
|
+
schoolName: value.schoolName,
|
|
38165
|
+
section: value.section,
|
|
38166
|
+
sectionName: value.sectionName,
|
|
38167
|
+
gradeLevel: value.gradeLevel,
|
|
38168
|
+
educationLevel: value.educationLevel,
|
|
38169
|
+
schoolYear: value.schoolYear,
|
|
38170
|
+
subjectCode: value.subjectCode,
|
|
38171
|
+
subjectName: value.subjectName,
|
|
38172
|
+
teacher: value.teacher,
|
|
38173
|
+
teacherName: value.teacherName,
|
|
38174
|
+
classroom: value.classroom ?? "",
|
|
38175
|
+
classroomName: value.classroomName ?? "",
|
|
38176
|
+
daysOfWeek: value.daysOfWeek ?? [],
|
|
38177
|
+
schedule: value.schedule ?? "",
|
|
38178
|
+
sessionDuration: value.sessionDuration ?? 0,
|
|
38179
|
+
sessionFrequency: value.sessionFrequency ?? 0,
|
|
38180
|
+
status: value.status ?? "draft",
|
|
38181
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
38182
|
+
updatedAt: value.updatedAt ?? "",
|
|
38183
|
+
deletedAt: value.deletedAt ?? ""
|
|
38184
|
+
};
|
|
38185
|
+
}
|
|
38186
|
+
|
|
38187
|
+
// src/resources/section-subject/section.subject.repository.ts
|
|
38188
|
+
var import_nodejs_utils49 = require("@eeplatform/nodejs-utils");
|
|
38189
|
+
var import_mongodb30 = require("mongodb");
|
|
38190
|
+
function useSectionSubjectRepo() {
|
|
38191
|
+
const db = import_nodejs_utils49.useAtlas.getDb();
|
|
38192
|
+
if (!db) {
|
|
38193
|
+
throw new Error("Unable to connect to server.");
|
|
38194
|
+
}
|
|
38195
|
+
const namespace_collection = "deped.section.subjects";
|
|
38196
|
+
const collection = db.collection(namespace_collection);
|
|
38197
|
+
const { getCache, setCache, delNamespace } = (0, import_nodejs_utils49.useCache)(namespace_collection);
|
|
38198
|
+
async function createIndexes() {
|
|
38002
38199
|
try {
|
|
38003
|
-
await
|
|
38004
|
-
|
|
38200
|
+
await collection.createIndexes([
|
|
38201
|
+
{ key: { school: 1 } },
|
|
38202
|
+
{ key: { section: 1 } },
|
|
38203
|
+
{ key: { teacher: 1 } },
|
|
38204
|
+
{ key: { subjectCode: 1 } },
|
|
38205
|
+
{ key: { schoolYear: 1 } },
|
|
38206
|
+
{ key: { gradeLevel: 1 } },
|
|
38207
|
+
{ key: { createdAt: 1 } },
|
|
38005
38208
|
{
|
|
38006
|
-
|
|
38007
|
-
|
|
38008
|
-
|
|
38209
|
+
key: {
|
|
38210
|
+
subjectName: "text",
|
|
38211
|
+
subjectCode: "text",
|
|
38212
|
+
teacherName: "text"
|
|
38213
|
+
}
|
|
38009
38214
|
},
|
|
38010
|
-
session
|
|
38011
|
-
);
|
|
38012
|
-
if (studentCount === 0) {
|
|
38013
|
-
throw new import_nodejs_utils48.BadRequestError("No learners found for this grade level.");
|
|
38014
|
-
}
|
|
38015
|
-
const gradeLevelData = await getByGradeLevel(
|
|
38016
38215
|
{
|
|
38017
|
-
|
|
38018
|
-
|
|
38019
|
-
|
|
38020
|
-
|
|
38021
|
-
|
|
38022
|
-
|
|
38023
|
-
throw new import_nodejs_utils48.BadRequestError("Grade level not found.");
|
|
38024
|
-
}
|
|
38025
|
-
const minPerSection = gradeLevelData.minNumberOfLearners;
|
|
38026
|
-
const maxPerSection = gradeLevelData.maxNumberOfLearners;
|
|
38027
|
-
const sectionsNeeded = Math.ceil(studentCount / minPerSection);
|
|
38028
|
-
if (sectionsNeeded > value.set.length) {
|
|
38029
|
-
throw new import_nodejs_utils48.BadRequestError(
|
|
38030
|
-
"Insufficient number of section names in set[]."
|
|
38031
|
-
);
|
|
38032
|
-
}
|
|
38033
|
-
const sectionSizes = distributeStudents(
|
|
38034
|
-
studentCount,
|
|
38035
|
-
minPerSection,
|
|
38036
|
-
maxPerSection
|
|
38037
|
-
);
|
|
38038
|
-
if (sectionSizes.length === 0) {
|
|
38039
|
-
throw new import_nodejs_utils48.BadRequestError("Unable to compute section sizes.");
|
|
38040
|
-
}
|
|
38041
|
-
let pointer = 0;
|
|
38042
|
-
for (let i = 0; i < sectionSizes.length; i++) {
|
|
38043
|
-
const size = sectionSizes[i];
|
|
38044
|
-
const sectionName = value.set[i];
|
|
38045
|
-
const section = await createSection(
|
|
38046
|
-
{
|
|
38047
|
-
school: value.school,
|
|
38048
|
-
schoolYear: value.schoolYear,
|
|
38049
|
-
gradeLevel: value.gradeLevel,
|
|
38050
|
-
name: sectionName,
|
|
38051
|
-
students: size
|
|
38052
|
-
},
|
|
38053
|
-
session
|
|
38054
|
-
);
|
|
38055
|
-
const learners = await getLeanerByGradeLevel(
|
|
38056
|
-
{
|
|
38057
|
-
school: value.school,
|
|
38058
|
-
gradeLevel: value.gradeLevel,
|
|
38059
|
-
skip: pointer,
|
|
38060
|
-
limit: size
|
|
38216
|
+
key: {
|
|
38217
|
+
school: 1,
|
|
38218
|
+
section: 1,
|
|
38219
|
+
subjectCode: 1,
|
|
38220
|
+
schoolYear: 1,
|
|
38221
|
+
status: 1
|
|
38061
38222
|
},
|
|
38062
|
-
|
|
38063
|
-
|
|
38064
|
-
if (!learners.length) {
|
|
38065
|
-
throw new import_nodejs_utils48.BadRequestError(`No learners found for section #${i + 1}.`);
|
|
38066
|
-
}
|
|
38067
|
-
pointer += size;
|
|
38068
|
-
for (const student of learners) {
|
|
38069
|
-
if (!student._id) {
|
|
38070
|
-
throw new import_nodejs_utils48.BadRequestError("Learner ID is missing.");
|
|
38071
|
-
}
|
|
38072
|
-
await assignStudent(
|
|
38073
|
-
{
|
|
38074
|
-
section: section.toString(),
|
|
38075
|
-
student: student._id?.toString(),
|
|
38076
|
-
studentName: `${student.learnerInfo.firstName} ${student.learnerInfo.lastName}`,
|
|
38077
|
-
status: "active"
|
|
38078
|
-
},
|
|
38079
|
-
session
|
|
38080
|
-
);
|
|
38223
|
+
unique: true,
|
|
38224
|
+
name: "unique_section_subject"
|
|
38081
38225
|
}
|
|
38082
|
-
|
|
38083
|
-
|
|
38084
|
-
|
|
38085
|
-
} catch (error2) {
|
|
38086
|
-
await session.abortTransaction();
|
|
38087
|
-
if (error2 instanceof import_nodejs_utils48.AppError) {
|
|
38088
|
-
throw error2;
|
|
38089
|
-
} else {
|
|
38090
|
-
throw new import_nodejs_utils48.InternalServerError("Failed to generate sections.");
|
|
38091
|
-
}
|
|
38092
|
-
} finally {
|
|
38093
|
-
await session?.endSession();
|
|
38226
|
+
]);
|
|
38227
|
+
} catch (error) {
|
|
38228
|
+
throw new Error("Failed to create index on section subjects.");
|
|
38094
38229
|
}
|
|
38095
38230
|
}
|
|
38096
|
-
|
|
38097
|
-
|
|
38098
|
-
|
|
38099
|
-
|
|
38100
|
-
|
|
38101
|
-
const {
|
|
38102
|
-
add: _add,
|
|
38103
|
-
getAll: _getAll,
|
|
38104
|
-
getById: _getById,
|
|
38105
|
-
getByName: _getByName,
|
|
38106
|
-
getBySchool: _getBySchool,
|
|
38107
|
-
updateFieldById: _updateFieldById,
|
|
38108
|
-
addStudentToSection: _addStudentToSection,
|
|
38109
|
-
removeStudentFromSection: _removeStudentFromSection,
|
|
38110
|
-
deleteById: _deleteById
|
|
38111
|
-
} = useSectionRepo();
|
|
38112
|
-
const { generateSections: _generateSections } = useSectionService();
|
|
38113
|
-
async function add(req, res, next) {
|
|
38114
|
-
const value = req.body;
|
|
38115
|
-
const { error } = schemaSection.validate(value);
|
|
38116
|
-
if (error) {
|
|
38117
|
-
next(new import_nodejs_utils49.BadRequestError(error.message));
|
|
38118
|
-
return;
|
|
38119
|
-
}
|
|
38120
|
-
try {
|
|
38121
|
-
const data = await _add(value);
|
|
38122
|
-
res.json({
|
|
38123
|
-
message: "Successfully created section.",
|
|
38124
|
-
data
|
|
38231
|
+
function delCachedData() {
|
|
38232
|
+
delNamespace().then(() => {
|
|
38233
|
+
import_nodejs_utils49.logger.log({
|
|
38234
|
+
level: "info",
|
|
38235
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
38125
38236
|
});
|
|
38126
|
-
|
|
38127
|
-
|
|
38128
|
-
|
|
38129
|
-
|
|
38237
|
+
}).catch((err) => {
|
|
38238
|
+
import_nodejs_utils49.logger.log({
|
|
38239
|
+
level: "error",
|
|
38240
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
38241
|
+
});
|
|
38242
|
+
});
|
|
38130
38243
|
}
|
|
38131
|
-
async function
|
|
38132
|
-
const value = req.body;
|
|
38133
|
-
const { error } = schemaGenerateSections.validate(value);
|
|
38134
|
-
if (error) {
|
|
38135
|
-
next(new import_nodejs_utils49.BadRequestError(error.message));
|
|
38136
|
-
return;
|
|
38137
|
-
}
|
|
38244
|
+
async function add(value, session) {
|
|
38138
38245
|
try {
|
|
38139
|
-
|
|
38140
|
-
res.
|
|
38141
|
-
|
|
38142
|
-
|
|
38246
|
+
value = modelSectionSubject(value);
|
|
38247
|
+
const res = await collection.insertOne(value, { session });
|
|
38248
|
+
delCachedData();
|
|
38249
|
+
return res.insertedId;
|
|
38250
|
+
} catch (error) {
|
|
38251
|
+
import_nodejs_utils49.logger.log({
|
|
38252
|
+
level: "error",
|
|
38253
|
+
message: error.message
|
|
38143
38254
|
});
|
|
38144
|
-
|
|
38145
|
-
|
|
38146
|
-
|
|
38255
|
+
if (error instanceof import_nodejs_utils49.AppError) {
|
|
38256
|
+
throw error;
|
|
38257
|
+
} else {
|
|
38258
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
38259
|
+
if (isDuplicated) {
|
|
38260
|
+
throw new import_nodejs_utils49.BadRequestError("Section subject already exists.");
|
|
38261
|
+
}
|
|
38262
|
+
throw new Error("Failed to create section subject.");
|
|
38263
|
+
}
|
|
38147
38264
|
}
|
|
38148
38265
|
}
|
|
38149
|
-
async function getAll(
|
|
38150
|
-
|
|
38151
|
-
|
|
38152
|
-
|
|
38153
|
-
|
|
38154
|
-
|
|
38155
|
-
|
|
38156
|
-
|
|
38157
|
-
|
|
38158
|
-
|
|
38159
|
-
|
|
38160
|
-
|
|
38161
|
-
|
|
38162
|
-
|
|
38163
|
-
const
|
|
38164
|
-
const
|
|
38165
|
-
|
|
38166
|
-
|
|
38167
|
-
|
|
38168
|
-
|
|
38169
|
-
if (
|
|
38170
|
-
|
|
38171
|
-
|
|
38266
|
+
async function getAll({
|
|
38267
|
+
search = "",
|
|
38268
|
+
page = 1,
|
|
38269
|
+
limit = 10,
|
|
38270
|
+
sort = {},
|
|
38271
|
+
status = "active",
|
|
38272
|
+
school = "",
|
|
38273
|
+
section = "",
|
|
38274
|
+
teacher = "",
|
|
38275
|
+
schoolYear = "",
|
|
38276
|
+
gradeLevel = "",
|
|
38277
|
+
subjectCode = ""
|
|
38278
|
+
} = {}) {
|
|
38279
|
+
page = page > 0 ? page - 1 : 0;
|
|
38280
|
+
const query = { status: { $ne: "deleted" } };
|
|
38281
|
+
const cacheKeyOptions = {
|
|
38282
|
+
page,
|
|
38283
|
+
limit,
|
|
38284
|
+
sort: JSON.stringify(sort)
|
|
38285
|
+
};
|
|
38286
|
+
if (status) {
|
|
38287
|
+
query.status = status;
|
|
38288
|
+
cacheKeyOptions.status = status;
|
|
38172
38289
|
}
|
|
38173
|
-
|
|
38174
|
-
|
|
38175
|
-
|
|
38176
|
-
|
|
38290
|
+
if (school) {
|
|
38291
|
+
try {
|
|
38292
|
+
query.school = new import_mongodb30.ObjectId(school);
|
|
38293
|
+
} catch (error) {
|
|
38294
|
+
throw new import_nodejs_utils49.BadRequestError("Invalid school ID.");
|
|
38295
|
+
}
|
|
38296
|
+
cacheKeyOptions.school = school;
|
|
38177
38297
|
}
|
|
38178
|
-
if (
|
|
38179
|
-
|
|
38180
|
-
|
|
38298
|
+
if (section) {
|
|
38299
|
+
try {
|
|
38300
|
+
query.section = new import_mongodb30.ObjectId(section);
|
|
38301
|
+
} catch (error) {
|
|
38302
|
+
throw new import_nodejs_utils49.BadRequestError("Invalid section ID.");
|
|
38303
|
+
}
|
|
38304
|
+
cacheKeyOptions.section = section;
|
|
38181
38305
|
}
|
|
38182
|
-
|
|
38183
|
-
|
|
38184
|
-
|
|
38185
|
-
|
|
38186
|
-
|
|
38187
|
-
|
|
38188
|
-
|
|
38189
|
-
schoolYear,
|
|
38190
|
-
gradeLevel
|
|
38191
|
-
});
|
|
38192
|
-
res.json(data);
|
|
38193
|
-
return;
|
|
38194
|
-
} catch (error2) {
|
|
38195
|
-
next(error2);
|
|
38306
|
+
if (teacher) {
|
|
38307
|
+
try {
|
|
38308
|
+
query.teacher = new import_mongodb30.ObjectId(teacher);
|
|
38309
|
+
} catch (error) {
|
|
38310
|
+
throw new import_nodejs_utils49.BadRequestError("Invalid teacher ID.");
|
|
38311
|
+
}
|
|
38312
|
+
cacheKeyOptions.teacher = teacher;
|
|
38196
38313
|
}
|
|
38197
|
-
|
|
38198
|
-
|
|
38199
|
-
|
|
38200
|
-
|
|
38201
|
-
|
|
38202
|
-
|
|
38203
|
-
|
|
38204
|
-
|
|
38205
|
-
|
|
38206
|
-
|
|
38314
|
+
if (schoolYear) {
|
|
38315
|
+
query.schoolYear = schoolYear;
|
|
38316
|
+
cacheKeyOptions.schoolYear = schoolYear;
|
|
38317
|
+
}
|
|
38318
|
+
if (gradeLevel) {
|
|
38319
|
+
query.gradeLevel = gradeLevel;
|
|
38320
|
+
cacheKeyOptions.gradeLevel = gradeLevel;
|
|
38321
|
+
}
|
|
38322
|
+
if (subjectCode) {
|
|
38323
|
+
query.subjectCode = subjectCode;
|
|
38324
|
+
cacheKeyOptions.subjectCode = subjectCode;
|
|
38325
|
+
}
|
|
38326
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: 1 };
|
|
38327
|
+
if (search) {
|
|
38328
|
+
query.$text = { $search: search };
|
|
38329
|
+
cacheKeyOptions.search = search;
|
|
38207
38330
|
}
|
|
38331
|
+
const cacheKey = (0, import_nodejs_utils49.makeCacheKey)(namespace_collection, cacheKeyOptions);
|
|
38332
|
+
import_nodejs_utils49.logger.log({
|
|
38333
|
+
level: "info",
|
|
38334
|
+
message: `Cache key for getAll section subjects: ${cacheKey}`
|
|
38335
|
+
});
|
|
38208
38336
|
try {
|
|
38209
|
-
const
|
|
38210
|
-
|
|
38211
|
-
|
|
38212
|
-
|
|
38337
|
+
const cached = await getCache(cacheKey);
|
|
38338
|
+
if (cached) {
|
|
38339
|
+
import_nodejs_utils49.logger.log({
|
|
38340
|
+
level: "info",
|
|
38341
|
+
message: `Cache hit for getAll section subjects: ${cacheKey}`
|
|
38342
|
+
});
|
|
38343
|
+
return cached;
|
|
38344
|
+
}
|
|
38345
|
+
const items = await collection.aggregate([
|
|
38346
|
+
{ $match: query },
|
|
38347
|
+
{ $sort: sort },
|
|
38348
|
+
{ $skip: page * limit },
|
|
38349
|
+
{ $limit: limit }
|
|
38350
|
+
]).toArray();
|
|
38351
|
+
const length = await collection.countDocuments(query);
|
|
38352
|
+
const data = (0, import_nodejs_utils49.paginate)(items, page, limit, length);
|
|
38353
|
+
setCache(cacheKey, data, 600).then(() => {
|
|
38354
|
+
import_nodejs_utils49.logger.log({
|
|
38355
|
+
level: "info",
|
|
38356
|
+
message: `Cache set for getAll section subjects: ${cacheKey}`
|
|
38357
|
+
});
|
|
38358
|
+
}).catch((err) => {
|
|
38359
|
+
import_nodejs_utils49.logger.log({
|
|
38360
|
+
level: "error",
|
|
38361
|
+
message: `Failed to set cache for getAll section subjects: ${err.message}`
|
|
38362
|
+
});
|
|
38213
38363
|
});
|
|
38214
|
-
return;
|
|
38215
|
-
} catch (
|
|
38216
|
-
|
|
38364
|
+
return data;
|
|
38365
|
+
} catch (error) {
|
|
38366
|
+
import_nodejs_utils49.logger.log({ level: "error", message: `${error}` });
|
|
38367
|
+
throw error;
|
|
38217
38368
|
}
|
|
38218
38369
|
}
|
|
38219
|
-
async function
|
|
38220
|
-
|
|
38221
|
-
|
|
38222
|
-
|
|
38223
|
-
|
|
38224
|
-
const { error } = validation.validate({ name });
|
|
38225
|
-
if (error) {
|
|
38226
|
-
next(new import_nodejs_utils49.BadRequestError(error.message));
|
|
38227
|
-
return;
|
|
38370
|
+
async function getById(_id) {
|
|
38371
|
+
try {
|
|
38372
|
+
_id = new import_mongodb30.ObjectId(_id);
|
|
38373
|
+
} catch (error) {
|
|
38374
|
+
throw new import_nodejs_utils49.BadRequestError("Invalid ID.");
|
|
38228
38375
|
}
|
|
38376
|
+
const cacheKey = (0, import_nodejs_utils49.makeCacheKey)(namespace_collection, { _id: String(_id) });
|
|
38229
38377
|
try {
|
|
38230
|
-
const
|
|
38231
|
-
|
|
38232
|
-
|
|
38233
|
-
|
|
38378
|
+
const cached = await getCache(cacheKey);
|
|
38379
|
+
if (cached) {
|
|
38380
|
+
import_nodejs_utils49.logger.log({
|
|
38381
|
+
level: "info",
|
|
38382
|
+
message: `Cache hit for getById section subject: ${cacheKey}`
|
|
38383
|
+
});
|
|
38384
|
+
return cached;
|
|
38385
|
+
}
|
|
38386
|
+
const result = await collection.findOne({
|
|
38387
|
+
_id,
|
|
38388
|
+
deletedAt: { $in: ["", null] }
|
|
38234
38389
|
});
|
|
38235
|
-
|
|
38236
|
-
|
|
38237
|
-
|
|
38390
|
+
if (!result) {
|
|
38391
|
+
throw new import_nodejs_utils49.BadRequestError("Section subject not found.");
|
|
38392
|
+
}
|
|
38393
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
38394
|
+
import_nodejs_utils49.logger.log({
|
|
38395
|
+
level: "info",
|
|
38396
|
+
message: `Cache set for section subject by id: ${cacheKey}`
|
|
38397
|
+
});
|
|
38398
|
+
}).catch((err) => {
|
|
38399
|
+
import_nodejs_utils49.logger.log({
|
|
38400
|
+
level: "error",
|
|
38401
|
+
message: `Failed to set cache for section subject by id: ${err.message}`
|
|
38402
|
+
});
|
|
38403
|
+
});
|
|
38404
|
+
return result;
|
|
38405
|
+
} catch (error) {
|
|
38406
|
+
if (error instanceof import_nodejs_utils49.AppError) {
|
|
38407
|
+
throw error;
|
|
38408
|
+
} else {
|
|
38409
|
+
throw new import_nodejs_utils49.InternalServerError("Failed to get section subject.");
|
|
38410
|
+
}
|
|
38238
38411
|
}
|
|
38239
38412
|
}
|
|
38240
|
-
async function
|
|
38241
|
-
|
|
38242
|
-
|
|
38243
|
-
|
|
38244
|
-
|
|
38245
|
-
const { error } = validation.validate({ school });
|
|
38246
|
-
if (error) {
|
|
38247
|
-
next(new import_nodejs_utils49.BadRequestError(error.message));
|
|
38248
|
-
return;
|
|
38413
|
+
async function getBySection(section) {
|
|
38414
|
+
try {
|
|
38415
|
+
section = new import_mongodb30.ObjectId(section);
|
|
38416
|
+
} catch (error) {
|
|
38417
|
+
throw new import_nodejs_utils49.BadRequestError("Invalid section ID.");
|
|
38249
38418
|
}
|
|
38419
|
+
const cacheKey = (0, import_nodejs_utils49.makeCacheKey)(namespace_collection, {
|
|
38420
|
+
section: String(section)
|
|
38421
|
+
});
|
|
38250
38422
|
try {
|
|
38251
|
-
const
|
|
38252
|
-
|
|
38253
|
-
|
|
38254
|
-
|
|
38423
|
+
const cached = await getCache(cacheKey);
|
|
38424
|
+
if (cached) {
|
|
38425
|
+
import_nodejs_utils49.logger.log({
|
|
38426
|
+
level: "info",
|
|
38427
|
+
message: `Cache hit for getBySection section subjects: ${cacheKey}`
|
|
38428
|
+
});
|
|
38429
|
+
return cached;
|
|
38430
|
+
}
|
|
38431
|
+
const result = await collection.find({
|
|
38432
|
+
section,
|
|
38433
|
+
deletedAt: { $in: ["", null] }
|
|
38434
|
+
}).toArray();
|
|
38435
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
38436
|
+
import_nodejs_utils49.logger.log({
|
|
38437
|
+
level: "info",
|
|
38438
|
+
message: `Cache set for section subjects by section: ${cacheKey}`
|
|
38439
|
+
});
|
|
38440
|
+
}).catch((err) => {
|
|
38441
|
+
import_nodejs_utils49.logger.log({
|
|
38442
|
+
level: "error",
|
|
38443
|
+
message: `Failed to set cache for section subjects by section: ${err.message}`
|
|
38444
|
+
});
|
|
38255
38445
|
});
|
|
38256
|
-
return;
|
|
38257
|
-
} catch (
|
|
38258
|
-
|
|
38446
|
+
return result;
|
|
38447
|
+
} catch (error) {
|
|
38448
|
+
if (error instanceof import_nodejs_utils49.AppError) {
|
|
38449
|
+
throw error;
|
|
38450
|
+
} else {
|
|
38451
|
+
throw new import_nodejs_utils49.InternalServerError(
|
|
38452
|
+
"Failed to get section subjects by section."
|
|
38453
|
+
);
|
|
38454
|
+
}
|
|
38259
38455
|
}
|
|
38260
38456
|
}
|
|
38261
|
-
async function
|
|
38262
|
-
|
|
38263
|
-
|
|
38264
|
-
|
|
38265
|
-
|
|
38266
|
-
field: import_joi29.default.string().valid("name", "schoolYear", "gradeLevel", "adviser", "adviserName").required(),
|
|
38267
|
-
value: import_joi29.default.string().required()
|
|
38268
|
-
});
|
|
38269
|
-
const { error } = validation.validate({ _id, field, value });
|
|
38270
|
-
if (error) {
|
|
38271
|
-
next(new import_nodejs_utils49.BadRequestError(error.message));
|
|
38272
|
-
return;
|
|
38457
|
+
async function getByTeacher(teacher) {
|
|
38458
|
+
try {
|
|
38459
|
+
teacher = new import_mongodb30.ObjectId(teacher);
|
|
38460
|
+
} catch (error) {
|
|
38461
|
+
throw new import_nodejs_utils49.BadRequestError("Invalid teacher ID.");
|
|
38273
38462
|
}
|
|
38463
|
+
const cacheKey = (0, import_nodejs_utils49.makeCacheKey)(namespace_collection, {
|
|
38464
|
+
teacher: String(teacher)
|
|
38465
|
+
});
|
|
38274
38466
|
try {
|
|
38275
|
-
const
|
|
38276
|
-
|
|
38467
|
+
const cached = await getCache(cacheKey);
|
|
38468
|
+
if (cached) {
|
|
38469
|
+
import_nodejs_utils49.logger.log({
|
|
38470
|
+
level: "info",
|
|
38471
|
+
message: `Cache hit for getByTeacher section subjects: ${cacheKey}`
|
|
38472
|
+
});
|
|
38473
|
+
return cached;
|
|
38474
|
+
}
|
|
38475
|
+
const result = await collection.find({
|
|
38476
|
+
teacher,
|
|
38477
|
+
deletedAt: { $in: ["", null] }
|
|
38478
|
+
}).toArray();
|
|
38479
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
38480
|
+
import_nodejs_utils49.logger.log({
|
|
38481
|
+
level: "info",
|
|
38482
|
+
message: `Cache set for section subjects by teacher: ${cacheKey}`
|
|
38483
|
+
});
|
|
38484
|
+
}).catch((err) => {
|
|
38485
|
+
import_nodejs_utils49.logger.log({
|
|
38486
|
+
level: "error",
|
|
38487
|
+
message: `Failed to set cache for section subjects by teacher: ${err.message}`
|
|
38488
|
+
});
|
|
38489
|
+
});
|
|
38490
|
+
return result;
|
|
38491
|
+
} catch (error) {
|
|
38492
|
+
if (error instanceof import_nodejs_utils49.AppError) {
|
|
38493
|
+
throw error;
|
|
38494
|
+
} else {
|
|
38495
|
+
throw new import_nodejs_utils49.InternalServerError(
|
|
38496
|
+
"Failed to get section subjects by teacher."
|
|
38497
|
+
);
|
|
38498
|
+
}
|
|
38499
|
+
}
|
|
38500
|
+
}
|
|
38501
|
+
async function getBySchool(school) {
|
|
38502
|
+
try {
|
|
38503
|
+
school = new import_mongodb30.ObjectId(school);
|
|
38504
|
+
} catch (error) {
|
|
38505
|
+
throw new import_nodejs_utils49.BadRequestError("Invalid school ID.");
|
|
38506
|
+
}
|
|
38507
|
+
const cacheKey = (0, import_nodejs_utils49.makeCacheKey)(namespace_collection, {
|
|
38508
|
+
school: String(school)
|
|
38509
|
+
});
|
|
38510
|
+
try {
|
|
38511
|
+
const cached = await getCache(cacheKey);
|
|
38512
|
+
if (cached) {
|
|
38513
|
+
import_nodejs_utils49.logger.log({
|
|
38514
|
+
level: "info",
|
|
38515
|
+
message: `Cache hit for getBySchool section subjects: ${cacheKey}`
|
|
38516
|
+
});
|
|
38517
|
+
return cached;
|
|
38518
|
+
}
|
|
38519
|
+
const result = await collection.find({
|
|
38520
|
+
school,
|
|
38521
|
+
deletedAt: { $in: ["", null] }
|
|
38522
|
+
}).toArray();
|
|
38523
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
38524
|
+
import_nodejs_utils49.logger.log({
|
|
38525
|
+
level: "info",
|
|
38526
|
+
message: `Cache set for section subjects by school: ${cacheKey}`
|
|
38527
|
+
});
|
|
38528
|
+
}).catch((err) => {
|
|
38529
|
+
import_nodejs_utils49.logger.log({
|
|
38530
|
+
level: "error",
|
|
38531
|
+
message: `Failed to set cache for section subjects by school: ${err.message}`
|
|
38532
|
+
});
|
|
38533
|
+
});
|
|
38534
|
+
return result;
|
|
38535
|
+
} catch (error) {
|
|
38536
|
+
if (error instanceof import_nodejs_utils49.AppError) {
|
|
38537
|
+
throw error;
|
|
38538
|
+
} else {
|
|
38539
|
+
throw new import_nodejs_utils49.InternalServerError(
|
|
38540
|
+
"Failed to get section subjects by school."
|
|
38541
|
+
);
|
|
38542
|
+
}
|
|
38543
|
+
}
|
|
38544
|
+
}
|
|
38545
|
+
async function updateFieldById({ _id, field, value } = {}, session) {
|
|
38546
|
+
const allowedFields = [
|
|
38547
|
+
"teacher",
|
|
38548
|
+
"teacherName",
|
|
38549
|
+
"classroom",
|
|
38550
|
+
"schedule",
|
|
38551
|
+
"daysOfWeek"
|
|
38552
|
+
];
|
|
38553
|
+
if (!allowedFields.includes(field)) {
|
|
38554
|
+
throw new import_nodejs_utils49.BadRequestError(
|
|
38555
|
+
`Field "${field}" is not allowed to be updated.`
|
|
38556
|
+
);
|
|
38557
|
+
}
|
|
38558
|
+
try {
|
|
38559
|
+
_id = new import_mongodb30.ObjectId(_id);
|
|
38560
|
+
} catch (error) {
|
|
38561
|
+
throw new import_nodejs_utils49.BadRequestError("Invalid ID.");
|
|
38562
|
+
}
|
|
38563
|
+
if (field === "teacher" && value) {
|
|
38564
|
+
try {
|
|
38565
|
+
value = new import_mongodb30.ObjectId(value).toString();
|
|
38566
|
+
} catch (error) {
|
|
38567
|
+
throw new import_nodejs_utils49.BadRequestError("Invalid teacher ID.");
|
|
38568
|
+
}
|
|
38569
|
+
}
|
|
38570
|
+
try {
|
|
38571
|
+
const updateValue = field === "teacher" ? new import_mongodb30.ObjectId(value) : value;
|
|
38572
|
+
await collection.updateOne(
|
|
38573
|
+
{ _id, deletedAt: { $in: ["", null] } },
|
|
38574
|
+
{ $set: { [field]: updateValue, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } },
|
|
38575
|
+
{ session }
|
|
38576
|
+
);
|
|
38577
|
+
delCachedData();
|
|
38578
|
+
return `Successfully updated section subject ${field}.`;
|
|
38579
|
+
} catch (error) {
|
|
38580
|
+
throw new import_nodejs_utils49.InternalServerError(
|
|
38581
|
+
`Failed to update section subject ${field}.`
|
|
38582
|
+
);
|
|
38583
|
+
}
|
|
38584
|
+
}
|
|
38585
|
+
async function setupById(_id, value, session) {
|
|
38586
|
+
const { error } = schemaSectionSubjectSetup.validate(value);
|
|
38587
|
+
if (error) {
|
|
38588
|
+
throw new import_nodejs_utils49.BadRequestError(
|
|
38589
|
+
`Invalid section subject data: ${error.message}`
|
|
38590
|
+
);
|
|
38591
|
+
}
|
|
38592
|
+
try {
|
|
38593
|
+
_id = new import_mongodb30.ObjectId(_id);
|
|
38594
|
+
} catch (error2) {
|
|
38595
|
+
throw new import_nodejs_utils49.BadRequestError("Invalid ID.");
|
|
38596
|
+
}
|
|
38597
|
+
try {
|
|
38598
|
+
await collection.updateOne(
|
|
38599
|
+
{ _id, deletedAt: { $in: ["", null] } },
|
|
38600
|
+
{ $set: { ...value, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } },
|
|
38601
|
+
{ session }
|
|
38602
|
+
);
|
|
38603
|
+
delCachedData();
|
|
38604
|
+
return `Successfully updated section subject.`;
|
|
38605
|
+
} catch (error2) {
|
|
38606
|
+
throw new import_nodejs_utils49.InternalServerError(`Failed to update section subject.`);
|
|
38607
|
+
}
|
|
38608
|
+
}
|
|
38609
|
+
async function deleteById(_id) {
|
|
38610
|
+
try {
|
|
38611
|
+
_id = new import_mongodb30.ObjectId(_id);
|
|
38612
|
+
} catch (error) {
|
|
38613
|
+
throw new import_nodejs_utils49.BadRequestError("Invalid ID.");
|
|
38614
|
+
}
|
|
38615
|
+
try {
|
|
38616
|
+
await collection.updateOne(
|
|
38617
|
+
{ _id },
|
|
38618
|
+
{ $set: { status: "deleted", deletedAt: (/* @__PURE__ */ new Date()).toISOString() } }
|
|
38619
|
+
);
|
|
38620
|
+
delCachedData();
|
|
38621
|
+
return "Successfully deleted section subject.";
|
|
38622
|
+
} catch (error) {
|
|
38623
|
+
throw new import_nodejs_utils49.InternalServerError("Failed to delete section subject.");
|
|
38624
|
+
}
|
|
38625
|
+
}
|
|
38626
|
+
return {
|
|
38627
|
+
createIndexes,
|
|
38628
|
+
add,
|
|
38629
|
+
getAll,
|
|
38630
|
+
getById,
|
|
38631
|
+
getBySection,
|
|
38632
|
+
getByTeacher,
|
|
38633
|
+
getBySchool,
|
|
38634
|
+
updateFieldById,
|
|
38635
|
+
setupById,
|
|
38636
|
+
deleteById
|
|
38637
|
+
};
|
|
38638
|
+
}
|
|
38639
|
+
|
|
38640
|
+
// src/resources/section-subject/section.subject.service.ts
|
|
38641
|
+
var import_nodejs_utils50 = require("@eeplatform/nodejs-utils");
|
|
38642
|
+
function useSectionSubjectService() {
|
|
38643
|
+
const { getById: getSchoolById } = useSchoolRepo();
|
|
38644
|
+
const { add: _add } = useSectionSubjectRepo();
|
|
38645
|
+
async function add(value) {
|
|
38646
|
+
const { error } = schemaSectionSubject.validate(value);
|
|
38647
|
+
if (error) {
|
|
38648
|
+
throw new Error(`Invalid section subject data: ${error.message}`);
|
|
38649
|
+
}
|
|
38650
|
+
try {
|
|
38651
|
+
const school = await getSchoolById(value.school);
|
|
38652
|
+
if (!school) {
|
|
38653
|
+
throw new Error("School not found.");
|
|
38654
|
+
}
|
|
38655
|
+
if (!school.name) {
|
|
38656
|
+
throw new Error("School name is missing.");
|
|
38657
|
+
}
|
|
38658
|
+
value.schoolName = school.name;
|
|
38659
|
+
await _add(value);
|
|
38660
|
+
return "Successfully created section subject.";
|
|
38661
|
+
} catch (error2) {
|
|
38662
|
+
if (error2 instanceof import_nodejs_utils50.AppError) {
|
|
38663
|
+
throw error2;
|
|
38664
|
+
} else {
|
|
38665
|
+
throw new import_nodejs_utils50.InternalServerError("Failed to create section subject.");
|
|
38666
|
+
}
|
|
38667
|
+
}
|
|
38668
|
+
}
|
|
38669
|
+
return {
|
|
38670
|
+
add
|
|
38671
|
+
};
|
|
38672
|
+
}
|
|
38673
|
+
|
|
38674
|
+
// src/resources/section-subject/section.subject.controller.ts
|
|
38675
|
+
var import_nodejs_utils51 = require("@eeplatform/nodejs-utils");
|
|
38676
|
+
var import_joi31 = __toESM(require("joi"));
|
|
38677
|
+
function useSectionSubjectController() {
|
|
38678
|
+
const {
|
|
38679
|
+
getAll: _getAll,
|
|
38680
|
+
getById: _getById,
|
|
38681
|
+
getBySection: _getBySection,
|
|
38682
|
+
getByTeacher: _getByTeacher,
|
|
38683
|
+
getBySchool: _getBySchool,
|
|
38684
|
+
updateFieldById: _updateFieldById,
|
|
38685
|
+
deleteById: _deleteById,
|
|
38686
|
+
setupById: _setupById
|
|
38687
|
+
} = useSectionSubjectRepo();
|
|
38688
|
+
const { add: _add } = useSectionSubjectService();
|
|
38689
|
+
async function add(req, res, next) {
|
|
38690
|
+
const value = req.body;
|
|
38691
|
+
const { error } = schemaSectionSubject.validate(value);
|
|
38692
|
+
if (error) {
|
|
38693
|
+
next(new import_nodejs_utils51.BadRequestError(error.message));
|
|
38694
|
+
return;
|
|
38695
|
+
}
|
|
38696
|
+
try {
|
|
38697
|
+
const data = await _add(value);
|
|
38698
|
+
res.json({
|
|
38699
|
+
message: "Successfully created section subject.",
|
|
38700
|
+
data
|
|
38701
|
+
});
|
|
38277
38702
|
return;
|
|
38278
38703
|
} catch (error2) {
|
|
38279
38704
|
next(error2);
|
|
38280
38705
|
}
|
|
38281
38706
|
}
|
|
38282
|
-
async function
|
|
38707
|
+
async function getAll(req, res, next) {
|
|
38708
|
+
const query = req.query;
|
|
38709
|
+
const validation = import_joi31.default.object({
|
|
38710
|
+
page: import_joi31.default.number().min(1).optional().allow("", null),
|
|
38711
|
+
limit: import_joi31.default.number().min(1).optional().allow("", null),
|
|
38712
|
+
search: import_joi31.default.string().optional().allow("", null),
|
|
38713
|
+
status: import_joi31.default.string().optional().allow("", null),
|
|
38714
|
+
school: import_joi31.default.string().hex().optional().allow("", null),
|
|
38715
|
+
section: import_joi31.default.string().hex().optional().allow("", null),
|
|
38716
|
+
teacher: import_joi31.default.string().hex().optional().allow("", null),
|
|
38717
|
+
schoolYear: import_joi31.default.string().optional().allow("", null),
|
|
38718
|
+
gradeLevel: import_joi31.default.string().optional().allow("", null),
|
|
38719
|
+
subjectCode: import_joi31.default.string().optional().allow("", null)
|
|
38720
|
+
});
|
|
38721
|
+
const { error } = validation.validate(query);
|
|
38722
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
38723
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
38724
|
+
const search = req.query.search ?? "";
|
|
38725
|
+
const status = req.query.status ?? "";
|
|
38726
|
+
const school = req.query.school ?? "";
|
|
38727
|
+
const section = req.query.section ?? "";
|
|
38728
|
+
const teacher = req.query.teacher ?? "";
|
|
38729
|
+
const schoolYear = req.query.schoolYear ?? "";
|
|
38730
|
+
const gradeLevel = req.query.gradeLevel ?? "";
|
|
38731
|
+
const subjectCode = req.query.subjectCode ?? "";
|
|
38732
|
+
const isPageNumber = isFinite(page);
|
|
38733
|
+
if (!isPageNumber) {
|
|
38734
|
+
next(new import_nodejs_utils51.BadRequestError("Invalid page number."));
|
|
38735
|
+
return;
|
|
38736
|
+
}
|
|
38737
|
+
const isLimitNumber = isFinite(limit);
|
|
38738
|
+
if (!isLimitNumber) {
|
|
38739
|
+
next(new import_nodejs_utils51.BadRequestError("Invalid limit number."));
|
|
38740
|
+
return;
|
|
38741
|
+
}
|
|
38742
|
+
if (error) {
|
|
38743
|
+
next(new import_nodejs_utils51.BadRequestError(error.message));
|
|
38744
|
+
return;
|
|
38745
|
+
}
|
|
38746
|
+
try {
|
|
38747
|
+
const data = await _getAll({
|
|
38748
|
+
page,
|
|
38749
|
+
limit,
|
|
38750
|
+
search,
|
|
38751
|
+
status,
|
|
38752
|
+
school,
|
|
38753
|
+
section,
|
|
38754
|
+
teacher,
|
|
38755
|
+
schoolYear,
|
|
38756
|
+
gradeLevel,
|
|
38757
|
+
subjectCode
|
|
38758
|
+
});
|
|
38759
|
+
res.json(data);
|
|
38760
|
+
return;
|
|
38761
|
+
} catch (error2) {
|
|
38762
|
+
next(error2);
|
|
38763
|
+
}
|
|
38764
|
+
}
|
|
38765
|
+
async function getById(req, res, next) {
|
|
38766
|
+
const id = req.params.id;
|
|
38767
|
+
const validation = import_joi31.default.object({
|
|
38768
|
+
id: import_joi31.default.string().hex().required()
|
|
38769
|
+
});
|
|
38770
|
+
const { error } = validation.validate({ id });
|
|
38771
|
+
if (error) {
|
|
38772
|
+
next(new import_nodejs_utils51.BadRequestError(error.message));
|
|
38773
|
+
return;
|
|
38774
|
+
}
|
|
38775
|
+
try {
|
|
38776
|
+
const data = await _getById(id);
|
|
38777
|
+
res.json({
|
|
38778
|
+
message: "Successfully retrieved section subject.",
|
|
38779
|
+
data
|
|
38780
|
+
});
|
|
38781
|
+
return;
|
|
38782
|
+
} catch (error2) {
|
|
38783
|
+
next(error2);
|
|
38784
|
+
}
|
|
38785
|
+
}
|
|
38786
|
+
async function getBySection(req, res, next) {
|
|
38787
|
+
const section = req.params.section;
|
|
38788
|
+
const validation = import_joi31.default.object({
|
|
38789
|
+
section: import_joi31.default.string().hex().required()
|
|
38790
|
+
});
|
|
38791
|
+
const { error } = validation.validate({ section });
|
|
38792
|
+
if (error) {
|
|
38793
|
+
next(new import_nodejs_utils51.BadRequestError(error.message));
|
|
38794
|
+
return;
|
|
38795
|
+
}
|
|
38796
|
+
try {
|
|
38797
|
+
const data = await _getBySection(section);
|
|
38798
|
+
res.json({
|
|
38799
|
+
message: "Successfully retrieved section subjects.",
|
|
38800
|
+
data
|
|
38801
|
+
});
|
|
38802
|
+
return;
|
|
38803
|
+
} catch (error2) {
|
|
38804
|
+
next(error2);
|
|
38805
|
+
}
|
|
38806
|
+
}
|
|
38807
|
+
async function getByTeacher(req, res, next) {
|
|
38808
|
+
const teacher = req.params.teacher;
|
|
38809
|
+
const validation = import_joi31.default.object({
|
|
38810
|
+
teacher: import_joi31.default.string().hex().required()
|
|
38811
|
+
});
|
|
38812
|
+
const { error } = validation.validate({ teacher });
|
|
38813
|
+
if (error) {
|
|
38814
|
+
next(new import_nodejs_utils51.BadRequestError(error.message));
|
|
38815
|
+
return;
|
|
38816
|
+
}
|
|
38817
|
+
try {
|
|
38818
|
+
const data = await _getByTeacher(teacher);
|
|
38819
|
+
res.json({
|
|
38820
|
+
message: "Successfully retrieved section subjects.",
|
|
38821
|
+
data
|
|
38822
|
+
});
|
|
38823
|
+
return;
|
|
38824
|
+
} catch (error2) {
|
|
38825
|
+
next(error2);
|
|
38826
|
+
}
|
|
38827
|
+
}
|
|
38828
|
+
async function getBySchool(req, res, next) {
|
|
38829
|
+
const school = req.params.school;
|
|
38830
|
+
const validation = import_joi31.default.object({
|
|
38831
|
+
school: import_joi31.default.string().hex().required()
|
|
38832
|
+
});
|
|
38833
|
+
const { error } = validation.validate({ school });
|
|
38834
|
+
if (error) {
|
|
38835
|
+
next(new import_nodejs_utils51.BadRequestError(error.message));
|
|
38836
|
+
return;
|
|
38837
|
+
}
|
|
38838
|
+
try {
|
|
38839
|
+
const data = await _getBySchool(school);
|
|
38840
|
+
res.json({
|
|
38841
|
+
message: "Successfully retrieved section subjects.",
|
|
38842
|
+
data
|
|
38843
|
+
});
|
|
38844
|
+
return;
|
|
38845
|
+
} catch (error2) {
|
|
38846
|
+
next(error2);
|
|
38847
|
+
}
|
|
38848
|
+
}
|
|
38849
|
+
async function updateField(req, res, next) {
|
|
38283
38850
|
const _id = req.params.id;
|
|
38284
|
-
const {
|
|
38285
|
-
const validation =
|
|
38286
|
-
_id:
|
|
38287
|
-
|
|
38851
|
+
const { field, value } = req.body;
|
|
38852
|
+
const validation = import_joi31.default.object({
|
|
38853
|
+
_id: import_joi31.default.string().hex().required(),
|
|
38854
|
+
field: import_joi31.default.string().valid(
|
|
38855
|
+
"subjectCode",
|
|
38856
|
+
"subjectName",
|
|
38857
|
+
"teacher",
|
|
38858
|
+
"teacherName",
|
|
38859
|
+
"classroom",
|
|
38860
|
+
"schedule"
|
|
38861
|
+
).required(),
|
|
38862
|
+
value: import_joi31.default.string().required()
|
|
38288
38863
|
});
|
|
38289
|
-
const { error } = validation.validate({ _id,
|
|
38864
|
+
const { error } = validation.validate({ _id, field, value });
|
|
38290
38865
|
if (error) {
|
|
38291
|
-
next(new
|
|
38866
|
+
next(new import_nodejs_utils51.BadRequestError(error.message));
|
|
38292
38867
|
return;
|
|
38293
38868
|
}
|
|
38294
38869
|
try {
|
|
38295
|
-
const message = await
|
|
38870
|
+
const message = await _updateFieldById({ _id, field, value });
|
|
38296
38871
|
res.json({ message });
|
|
38297
38872
|
return;
|
|
38298
38873
|
} catch (error2) {
|
|
38299
38874
|
next(error2);
|
|
38300
38875
|
}
|
|
38301
38876
|
}
|
|
38302
|
-
async function
|
|
38877
|
+
async function setupById(req, res, next) {
|
|
38303
38878
|
const _id = req.params.id;
|
|
38304
|
-
const
|
|
38305
|
-
const
|
|
38306
|
-
_id: import_joi29.default.string().hex().required(),
|
|
38307
|
-
studentId: import_joi29.default.string().required()
|
|
38308
|
-
});
|
|
38309
|
-
const { error } = validation.validate({ _id, studentId });
|
|
38879
|
+
const data = req.body;
|
|
38880
|
+
const { error } = schemaSectionSubjectSetup.validate(data);
|
|
38310
38881
|
if (error) {
|
|
38311
|
-
next(new
|
|
38882
|
+
next(new import_nodejs_utils51.BadRequestError(error.message));
|
|
38312
38883
|
return;
|
|
38313
38884
|
}
|
|
38314
38885
|
try {
|
|
38315
|
-
const message = await
|
|
38886
|
+
const message = await _setupById(_id, data);
|
|
38316
38887
|
res.json({ message });
|
|
38317
38888
|
return;
|
|
38318
38889
|
} catch (error2) {
|
|
@@ -38321,12 +38892,12 @@ function useSectionController() {
|
|
|
38321
38892
|
}
|
|
38322
38893
|
async function deleteById(req, res, next) {
|
|
38323
38894
|
const _id = req.params.id;
|
|
38324
|
-
const validation =
|
|
38325
|
-
_id:
|
|
38895
|
+
const validation = import_joi31.default.object({
|
|
38896
|
+
_id: import_joi31.default.string().hex().required()
|
|
38326
38897
|
});
|
|
38327
38898
|
const { error } = validation.validate({ _id });
|
|
38328
38899
|
if (error) {
|
|
38329
|
-
next(new
|
|
38900
|
+
next(new import_nodejs_utils51.BadRequestError(error.message));
|
|
38330
38901
|
return;
|
|
38331
38902
|
}
|
|
38332
38903
|
try {
|
|
@@ -38339,28 +38910,2230 @@ function useSectionController() {
|
|
|
38339
38910
|
}
|
|
38340
38911
|
return {
|
|
38341
38912
|
add,
|
|
38342
|
-
generateSections,
|
|
38343
38913
|
getAll,
|
|
38344
38914
|
getById,
|
|
38345
|
-
|
|
38915
|
+
getBySection,
|
|
38916
|
+
getByTeacher,
|
|
38346
38917
|
getBySchool,
|
|
38347
38918
|
updateField,
|
|
38348
|
-
|
|
38349
|
-
removeStudent,
|
|
38919
|
+
setupById,
|
|
38350
38920
|
deleteById
|
|
38351
38921
|
};
|
|
38352
38922
|
}
|
|
38353
38923
|
|
|
38924
|
+
// src/resources/section/section.service.ts
|
|
38925
|
+
function useSectionService() {
|
|
38926
|
+
const { getCountByGradeLevel, getByGradeLevel: getLeanerByGradeLevel } = useLearnerRepo();
|
|
38927
|
+
const { getByGradeLevel } = useGradeLevelRepo();
|
|
38928
|
+
const { add: createSection } = useSectionRepo();
|
|
38929
|
+
const { add: assignStudent } = useSectionStudentRepo();
|
|
38930
|
+
const { getAll: getAllCurriculumSubjects } = useCurriculumSubjectRepo();
|
|
38931
|
+
const { add: addSectionSubject } = useSectionSubjectRepo();
|
|
38932
|
+
const { getById: getSchoolById } = useSchoolRepo();
|
|
38933
|
+
function distributeStudents(total, minPer, maxPer) {
|
|
38934
|
+
if (total <= 0)
|
|
38935
|
+
return [];
|
|
38936
|
+
if (minPer <= 0 || maxPer <= 0)
|
|
38937
|
+
return [];
|
|
38938
|
+
if (minPer > maxPer) {
|
|
38939
|
+
throw new import_nodejs_utils52.BadRequestError(
|
|
38940
|
+
"Minimum students per section cannot be greater than maximum."
|
|
38941
|
+
);
|
|
38942
|
+
}
|
|
38943
|
+
const minSections = Math.ceil(total / maxPer);
|
|
38944
|
+
const maxSections = Math.floor(total / minPer);
|
|
38945
|
+
let sectionCount;
|
|
38946
|
+
if (minSections <= maxSections) {
|
|
38947
|
+
sectionCount = minSections;
|
|
38948
|
+
} else {
|
|
38949
|
+
sectionCount = minSections;
|
|
38950
|
+
}
|
|
38951
|
+
const base = Math.floor(total / sectionCount);
|
|
38952
|
+
const extra = total % sectionCount;
|
|
38953
|
+
const sizes = new Array(sectionCount).fill(base);
|
|
38954
|
+
for (let i = 0; i < extra; i++) {
|
|
38955
|
+
sizes[i] += 1;
|
|
38956
|
+
}
|
|
38957
|
+
for (const size of sizes) {
|
|
38958
|
+
if (size > maxPer) {
|
|
38959
|
+
throw new import_nodejs_utils52.BadRequestError(
|
|
38960
|
+
`Generated section exceeds max limit of ${maxPer}.`
|
|
38961
|
+
);
|
|
38962
|
+
}
|
|
38963
|
+
}
|
|
38964
|
+
return sizes;
|
|
38965
|
+
}
|
|
38966
|
+
async function generateSections(value) {
|
|
38967
|
+
const { error } = schemaGenerateSections.validate(value);
|
|
38968
|
+
if (error) {
|
|
38969
|
+
throw new import_nodejs_utils52.BadRequestError(
|
|
38970
|
+
`Invalid section generation data: ${error.message}`
|
|
38971
|
+
);
|
|
38972
|
+
}
|
|
38973
|
+
const session = import_nodejs_utils52.useAtlas.getClient()?.startSession();
|
|
38974
|
+
if (!session) {
|
|
38975
|
+
throw new Error("Unable to start database session.");
|
|
38976
|
+
}
|
|
38977
|
+
try {
|
|
38978
|
+
await session.startTransaction();
|
|
38979
|
+
const studentCount = await getCountByGradeLevel(
|
|
38980
|
+
{
|
|
38981
|
+
school: value.school,
|
|
38982
|
+
schoolYear: value.schoolYear,
|
|
38983
|
+
gradeLevel: value.gradeLevel
|
|
38984
|
+
},
|
|
38985
|
+
session
|
|
38986
|
+
);
|
|
38987
|
+
if (studentCount === 0) {
|
|
38988
|
+
throw new import_nodejs_utils52.BadRequestError("No learners found for this grade level.");
|
|
38989
|
+
}
|
|
38990
|
+
const gradeLevelData = await getByGradeLevel(
|
|
38991
|
+
{
|
|
38992
|
+
school: value.school,
|
|
38993
|
+
gradeLevel: value.gradeLevel
|
|
38994
|
+
},
|
|
38995
|
+
session
|
|
38996
|
+
);
|
|
38997
|
+
if (!gradeLevelData) {
|
|
38998
|
+
throw new import_nodejs_utils52.BadRequestError("Grade level not found.");
|
|
38999
|
+
}
|
|
39000
|
+
const minPerSection = gradeLevelData.minNumberOfLearners;
|
|
39001
|
+
const maxPerSection = gradeLevelData.maxNumberOfLearners;
|
|
39002
|
+
const sectionsNeeded = Math.ceil(studentCount / minPerSection);
|
|
39003
|
+
if (sectionsNeeded > value.set.length) {
|
|
39004
|
+
throw new import_nodejs_utils52.BadRequestError(
|
|
39005
|
+
"Insufficient number of section names in set[]."
|
|
39006
|
+
);
|
|
39007
|
+
}
|
|
39008
|
+
const sectionSizes = distributeStudents(
|
|
39009
|
+
studentCount,
|
|
39010
|
+
minPerSection,
|
|
39011
|
+
maxPerSection
|
|
39012
|
+
);
|
|
39013
|
+
if (sectionSizes.length === 0) {
|
|
39014
|
+
throw new import_nodejs_utils52.BadRequestError("Unable to compute section sizes.");
|
|
39015
|
+
}
|
|
39016
|
+
const schoolData = await getSchoolById(value.school);
|
|
39017
|
+
if (!schoolData) {
|
|
39018
|
+
throw new import_nodejs_utils52.BadRequestError("School not found.");
|
|
39019
|
+
}
|
|
39020
|
+
let totalStudentsProcessed = 0;
|
|
39021
|
+
for (let i = 0; i < sectionSizes.length; i++) {
|
|
39022
|
+
const size = sectionSizes[i];
|
|
39023
|
+
const sectionName = value.set[i];
|
|
39024
|
+
const section = await createSection(
|
|
39025
|
+
{
|
|
39026
|
+
school: value.school,
|
|
39027
|
+
schoolYear: value.schoolYear,
|
|
39028
|
+
gradeLevel: value.gradeLevel,
|
|
39029
|
+
name: sectionName,
|
|
39030
|
+
students: size
|
|
39031
|
+
},
|
|
39032
|
+
session
|
|
39033
|
+
);
|
|
39034
|
+
const skip = totalStudentsProcessed;
|
|
39035
|
+
const learners = await getLeanerByGradeLevel(
|
|
39036
|
+
{
|
|
39037
|
+
school: value.school,
|
|
39038
|
+
gradeLevel: value.gradeLevel,
|
|
39039
|
+
skip,
|
|
39040
|
+
limit: size
|
|
39041
|
+
},
|
|
39042
|
+
session
|
|
39043
|
+
);
|
|
39044
|
+
if (!learners.length) {
|
|
39045
|
+
throw new import_nodejs_utils52.BadRequestError(`No learners found for section #${i + 1}.`);
|
|
39046
|
+
}
|
|
39047
|
+
totalStudentsProcessed += learners.length;
|
|
39048
|
+
for (const student of learners) {
|
|
39049
|
+
if (!student._id) {
|
|
39050
|
+
throw new import_nodejs_utils52.BadRequestError("Learner ID is missing.");
|
|
39051
|
+
}
|
|
39052
|
+
if (!student.learnerInfo.lrn) {
|
|
39053
|
+
throw new import_nodejs_utils52.BadRequestError("Learner LRN is missing.");
|
|
39054
|
+
}
|
|
39055
|
+
await assignStudent(
|
|
39056
|
+
{
|
|
39057
|
+
section: section.toString(),
|
|
39058
|
+
lrn: student.learnerInfo.lrn,
|
|
39059
|
+
student: student._id?.toString(),
|
|
39060
|
+
studentName: `${student.learnerInfo.firstName} ${student.learnerInfo.lastName}`,
|
|
39061
|
+
school: value.school,
|
|
39062
|
+
schoolName: schoolData.name,
|
|
39063
|
+
gradeLevel: value.gradeLevel,
|
|
39064
|
+
educationLevel: gradeLevelData.educationLevel,
|
|
39065
|
+
schoolYear: value.schoolYear,
|
|
39066
|
+
status: "active"
|
|
39067
|
+
},
|
|
39068
|
+
session
|
|
39069
|
+
);
|
|
39070
|
+
}
|
|
39071
|
+
const curriculumSubjects = await getAllCurriculumSubjects({
|
|
39072
|
+
schoolYear: Number(value.schoolYear),
|
|
39073
|
+
gradeLevel: value.gradeLevel,
|
|
39074
|
+
limit: 20
|
|
39075
|
+
});
|
|
39076
|
+
for (const curriculumSubject of curriculumSubjects.items) {
|
|
39077
|
+
await addSectionSubject(
|
|
39078
|
+
{
|
|
39079
|
+
school: value.school,
|
|
39080
|
+
schoolName: schoolData.name,
|
|
39081
|
+
gradeLevel: value.gradeLevel,
|
|
39082
|
+
educationLevel: gradeLevelData.educationLevel,
|
|
39083
|
+
schoolYear: value.schoolYear,
|
|
39084
|
+
section: section.toString(),
|
|
39085
|
+
sectionName,
|
|
39086
|
+
subjectCode: curriculumSubject.subjectCode,
|
|
39087
|
+
subjectName: curriculumSubject.subjectName,
|
|
39088
|
+
teacher: "",
|
|
39089
|
+
teacherName: "",
|
|
39090
|
+
schedule: "",
|
|
39091
|
+
daysOfWeek: [],
|
|
39092
|
+
classroom: "",
|
|
39093
|
+
classroomName: "",
|
|
39094
|
+
sessionDuration: curriculumSubject.sessionDuration,
|
|
39095
|
+
sessionFrequency: curriculumSubject.sessionFrequency,
|
|
39096
|
+
status: "draft"
|
|
39097
|
+
},
|
|
39098
|
+
session
|
|
39099
|
+
);
|
|
39100
|
+
}
|
|
39101
|
+
}
|
|
39102
|
+
await session.commitTransaction();
|
|
39103
|
+
return "Sections generated successfully.";
|
|
39104
|
+
} catch (error2) {
|
|
39105
|
+
await session.abortTransaction();
|
|
39106
|
+
if (error2 instanceof import_nodejs_utils52.AppError) {
|
|
39107
|
+
throw error2;
|
|
39108
|
+
} else {
|
|
39109
|
+
throw new import_nodejs_utils52.InternalServerError("Failed to generate sections.");
|
|
39110
|
+
}
|
|
39111
|
+
} finally {
|
|
39112
|
+
await session?.endSession();
|
|
39113
|
+
}
|
|
39114
|
+
}
|
|
39115
|
+
return { generateSections };
|
|
39116
|
+
}
|
|
39117
|
+
|
|
39118
|
+
// src/resources/section/section.controller.ts
|
|
39119
|
+
function useSectionController() {
|
|
39120
|
+
const {
|
|
39121
|
+
add: _add,
|
|
39122
|
+
getAll: _getAll,
|
|
39123
|
+
getById: _getById,
|
|
39124
|
+
getByName: _getByName,
|
|
39125
|
+
getBySchool: _getBySchool,
|
|
39126
|
+
updateFieldById: _updateFieldById,
|
|
39127
|
+
addStudentToSection: _addStudentToSection,
|
|
39128
|
+
removeStudentFromSection: _removeStudentFromSection,
|
|
39129
|
+
deleteById: _deleteById
|
|
39130
|
+
} = useSectionRepo();
|
|
39131
|
+
const { generateSections: _generateSections } = useSectionService();
|
|
39132
|
+
async function add(req, res, next) {
|
|
39133
|
+
const value = req.body;
|
|
39134
|
+
const { error } = schemaSection.validate(value);
|
|
39135
|
+
if (error) {
|
|
39136
|
+
next(new import_nodejs_utils53.BadRequestError(error.message));
|
|
39137
|
+
return;
|
|
39138
|
+
}
|
|
39139
|
+
try {
|
|
39140
|
+
const data = await _add(value);
|
|
39141
|
+
res.json({
|
|
39142
|
+
message: "Successfully created section.",
|
|
39143
|
+
data
|
|
39144
|
+
});
|
|
39145
|
+
return;
|
|
39146
|
+
} catch (error2) {
|
|
39147
|
+
next(error2);
|
|
39148
|
+
}
|
|
39149
|
+
}
|
|
39150
|
+
async function generateSections(req, res, next) {
|
|
39151
|
+
const value = req.body;
|
|
39152
|
+
const { error } = schemaGenerateSections.validate(value);
|
|
39153
|
+
if (error) {
|
|
39154
|
+
next(new import_nodejs_utils53.BadRequestError(error.message));
|
|
39155
|
+
return;
|
|
39156
|
+
}
|
|
39157
|
+
try {
|
|
39158
|
+
const data = await _generateSections(value);
|
|
39159
|
+
res.json({
|
|
39160
|
+
message: "Successfully created section.",
|
|
39161
|
+
data
|
|
39162
|
+
});
|
|
39163
|
+
return;
|
|
39164
|
+
} catch (error2) {
|
|
39165
|
+
next(error2);
|
|
39166
|
+
}
|
|
39167
|
+
}
|
|
39168
|
+
async function getAll(req, res, next) {
|
|
39169
|
+
const query = req.query;
|
|
39170
|
+
const validation = import_joi32.default.object({
|
|
39171
|
+
page: import_joi32.default.number().min(1).optional().allow("", null),
|
|
39172
|
+
limit: import_joi32.default.number().min(1).optional().allow("", null),
|
|
39173
|
+
search: import_joi32.default.string().optional().allow("", null),
|
|
39174
|
+
status: import_joi32.default.string().optional().allow("", null),
|
|
39175
|
+
school: import_joi32.default.string().hex().optional().allow("", null),
|
|
39176
|
+
schoolYear: import_joi32.default.string().optional().allow("", null),
|
|
39177
|
+
gradeLevel: import_joi32.default.string().optional().allow("", null)
|
|
39178
|
+
});
|
|
39179
|
+
const { error } = validation.validate(query);
|
|
39180
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
39181
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
39182
|
+
const search = req.query.search ?? "";
|
|
39183
|
+
const status = req.query.status ?? "active";
|
|
39184
|
+
const school = req.query.school ?? "";
|
|
39185
|
+
const schoolYear = req.query.schoolYear ?? "";
|
|
39186
|
+
const gradeLevel = req.query.gradeLevel ?? "";
|
|
39187
|
+
const isPageNumber = isFinite(page);
|
|
39188
|
+
if (!isPageNumber) {
|
|
39189
|
+
next(new import_nodejs_utils53.BadRequestError("Invalid page number."));
|
|
39190
|
+
return;
|
|
39191
|
+
}
|
|
39192
|
+
const isLimitNumber = isFinite(limit);
|
|
39193
|
+
if (!isLimitNumber) {
|
|
39194
|
+
next(new import_nodejs_utils53.BadRequestError("Invalid limit number."));
|
|
39195
|
+
return;
|
|
39196
|
+
}
|
|
39197
|
+
if (error) {
|
|
39198
|
+
next(new import_nodejs_utils53.BadRequestError(error.message));
|
|
39199
|
+
return;
|
|
39200
|
+
}
|
|
39201
|
+
try {
|
|
39202
|
+
const data = await _getAll({
|
|
39203
|
+
page,
|
|
39204
|
+
limit,
|
|
39205
|
+
search,
|
|
39206
|
+
status,
|
|
39207
|
+
school,
|
|
39208
|
+
schoolYear,
|
|
39209
|
+
gradeLevel
|
|
39210
|
+
});
|
|
39211
|
+
res.json(data);
|
|
39212
|
+
return;
|
|
39213
|
+
} catch (error2) {
|
|
39214
|
+
next(error2);
|
|
39215
|
+
}
|
|
39216
|
+
}
|
|
39217
|
+
async function getById(req, res, next) {
|
|
39218
|
+
const id = req.params.id;
|
|
39219
|
+
const validation = import_joi32.default.object({
|
|
39220
|
+
id: import_joi32.default.string().hex().required()
|
|
39221
|
+
});
|
|
39222
|
+
const { error } = validation.validate({ id });
|
|
39223
|
+
if (error) {
|
|
39224
|
+
next(new import_nodejs_utils53.BadRequestError(error.message));
|
|
39225
|
+
return;
|
|
39226
|
+
}
|
|
39227
|
+
try {
|
|
39228
|
+
const data = await _getById(id);
|
|
39229
|
+
res.json(data);
|
|
39230
|
+
return;
|
|
39231
|
+
} catch (error2) {
|
|
39232
|
+
next(error2);
|
|
39233
|
+
}
|
|
39234
|
+
}
|
|
39235
|
+
async function getByName(req, res, next) {
|
|
39236
|
+
const name = req.params.name;
|
|
39237
|
+
const validation = import_joi32.default.object({
|
|
39238
|
+
name: import_joi32.default.string().required()
|
|
39239
|
+
});
|
|
39240
|
+
const { error } = validation.validate({ name });
|
|
39241
|
+
if (error) {
|
|
39242
|
+
next(new import_nodejs_utils53.BadRequestError(error.message));
|
|
39243
|
+
return;
|
|
39244
|
+
}
|
|
39245
|
+
try {
|
|
39246
|
+
const data = await _getByName(name);
|
|
39247
|
+
res.json({
|
|
39248
|
+
message: "Successfully retrieved section.",
|
|
39249
|
+
data
|
|
39250
|
+
});
|
|
39251
|
+
return;
|
|
39252
|
+
} catch (error2) {
|
|
39253
|
+
next(error2);
|
|
39254
|
+
}
|
|
39255
|
+
}
|
|
39256
|
+
async function getBySchool(req, res, next) {
|
|
39257
|
+
const school = req.params.school;
|
|
39258
|
+
const validation = import_joi32.default.object({
|
|
39259
|
+
school: import_joi32.default.string().hex().required()
|
|
39260
|
+
});
|
|
39261
|
+
const { error } = validation.validate({ school });
|
|
39262
|
+
if (error) {
|
|
39263
|
+
next(new import_nodejs_utils53.BadRequestError(error.message));
|
|
39264
|
+
return;
|
|
39265
|
+
}
|
|
39266
|
+
try {
|
|
39267
|
+
const data = await _getBySchool(school);
|
|
39268
|
+
res.json({
|
|
39269
|
+
message: "Successfully retrieved sections.",
|
|
39270
|
+
data
|
|
39271
|
+
});
|
|
39272
|
+
return;
|
|
39273
|
+
} catch (error2) {
|
|
39274
|
+
next(error2);
|
|
39275
|
+
}
|
|
39276
|
+
}
|
|
39277
|
+
async function updateField(req, res, next) {
|
|
39278
|
+
const _id = req.params.id;
|
|
39279
|
+
const { field, value } = req.body;
|
|
39280
|
+
const validation = import_joi32.default.object({
|
|
39281
|
+
_id: import_joi32.default.string().hex().required(),
|
|
39282
|
+
field: import_joi32.default.string().valid("name", "schoolYear", "gradeLevel", "adviser", "adviserName").required(),
|
|
39283
|
+
value: import_joi32.default.string().required()
|
|
39284
|
+
});
|
|
39285
|
+
const { error } = validation.validate({ _id, field, value });
|
|
39286
|
+
if (error) {
|
|
39287
|
+
next(new import_nodejs_utils53.BadRequestError(error.message));
|
|
39288
|
+
return;
|
|
39289
|
+
}
|
|
39290
|
+
try {
|
|
39291
|
+
const message = await _updateFieldById({ _id, field, value });
|
|
39292
|
+
res.json({ message });
|
|
39293
|
+
return;
|
|
39294
|
+
} catch (error2) {
|
|
39295
|
+
next(error2);
|
|
39296
|
+
}
|
|
39297
|
+
}
|
|
39298
|
+
async function addStudent(req, res, next) {
|
|
39299
|
+
const _id = req.params.id;
|
|
39300
|
+
const { studentId } = req.body;
|
|
39301
|
+
const validation = import_joi32.default.object({
|
|
39302
|
+
_id: import_joi32.default.string().hex().required(),
|
|
39303
|
+
studentId: import_joi32.default.string().required()
|
|
39304
|
+
});
|
|
39305
|
+
const { error } = validation.validate({ _id, studentId });
|
|
39306
|
+
if (error) {
|
|
39307
|
+
next(new import_nodejs_utils53.BadRequestError(error.message));
|
|
39308
|
+
return;
|
|
39309
|
+
}
|
|
39310
|
+
try {
|
|
39311
|
+
const message = await _addStudentToSection(_id, studentId);
|
|
39312
|
+
res.json({ message });
|
|
39313
|
+
return;
|
|
39314
|
+
} catch (error2) {
|
|
39315
|
+
next(error2);
|
|
39316
|
+
}
|
|
39317
|
+
}
|
|
39318
|
+
async function removeStudent(req, res, next) {
|
|
39319
|
+
const _id = req.params.id;
|
|
39320
|
+
const { studentId } = req.body;
|
|
39321
|
+
const validation = import_joi32.default.object({
|
|
39322
|
+
_id: import_joi32.default.string().hex().required(),
|
|
39323
|
+
studentId: import_joi32.default.string().required()
|
|
39324
|
+
});
|
|
39325
|
+
const { error } = validation.validate({ _id, studentId });
|
|
39326
|
+
if (error) {
|
|
39327
|
+
next(new import_nodejs_utils53.BadRequestError(error.message));
|
|
39328
|
+
return;
|
|
39329
|
+
}
|
|
39330
|
+
try {
|
|
39331
|
+
const message = await _removeStudentFromSection(_id, studentId);
|
|
39332
|
+
res.json({ message });
|
|
39333
|
+
return;
|
|
39334
|
+
} catch (error2) {
|
|
39335
|
+
next(error2);
|
|
39336
|
+
}
|
|
39337
|
+
}
|
|
39338
|
+
async function deleteById(req, res, next) {
|
|
39339
|
+
const _id = req.params.id;
|
|
39340
|
+
const validation = import_joi32.default.object({
|
|
39341
|
+
_id: import_joi32.default.string().hex().required()
|
|
39342
|
+
});
|
|
39343
|
+
const { error } = validation.validate({ _id });
|
|
39344
|
+
if (error) {
|
|
39345
|
+
next(new import_nodejs_utils53.BadRequestError(error.message));
|
|
39346
|
+
return;
|
|
39347
|
+
}
|
|
39348
|
+
try {
|
|
39349
|
+
const message = await _deleteById(_id);
|
|
39350
|
+
res.json({ message });
|
|
39351
|
+
return;
|
|
39352
|
+
} catch (error2) {
|
|
39353
|
+
next(error2);
|
|
39354
|
+
}
|
|
39355
|
+
}
|
|
39356
|
+
return {
|
|
39357
|
+
add,
|
|
39358
|
+
generateSections,
|
|
39359
|
+
getAll,
|
|
39360
|
+
getById,
|
|
39361
|
+
getByName,
|
|
39362
|
+
getBySchool,
|
|
39363
|
+
updateField,
|
|
39364
|
+
addStudent,
|
|
39365
|
+
removeStudent,
|
|
39366
|
+
deleteById
|
|
39367
|
+
};
|
|
39368
|
+
}
|
|
39369
|
+
|
|
39370
|
+
// src/resources/section-student/section.student.controller.ts
|
|
39371
|
+
var import_nodejs_utils54 = require("@eeplatform/nodejs-utils");
|
|
39372
|
+
var import_joi33 = __toESM(require("joi"));
|
|
39373
|
+
function useSectionStudentController() {
|
|
39374
|
+
const { add: _add, getAll: _getAll } = useSectionStudentRepo();
|
|
39375
|
+
async function add(req, res, next) {
|
|
39376
|
+
const value = req.body;
|
|
39377
|
+
const { error } = schemaSectionStudent.validate(value);
|
|
39378
|
+
if (error) {
|
|
39379
|
+
next(new import_nodejs_utils54.BadRequestError(error.message));
|
|
39380
|
+
return;
|
|
39381
|
+
}
|
|
39382
|
+
try {
|
|
39383
|
+
const data = await _add(value);
|
|
39384
|
+
res.json({
|
|
39385
|
+
message: "Successfully created section student.",
|
|
39386
|
+
data
|
|
39387
|
+
});
|
|
39388
|
+
return;
|
|
39389
|
+
} catch (error2) {
|
|
39390
|
+
next(error2);
|
|
39391
|
+
}
|
|
39392
|
+
}
|
|
39393
|
+
async function getAll(req, res, next) {
|
|
39394
|
+
const query = req.query;
|
|
39395
|
+
const validation = import_joi33.default.object({
|
|
39396
|
+
page: import_joi33.default.number().min(1).optional().allow("", null),
|
|
39397
|
+
limit: import_joi33.default.number().min(1).optional().allow("", null),
|
|
39398
|
+
search: import_joi33.default.string().optional().allow("", null),
|
|
39399
|
+
status: import_joi33.default.string().optional().allow("", null),
|
|
39400
|
+
school: import_joi33.default.string().optional().allow("", null),
|
|
39401
|
+
gradeLevel: import_joi33.default.string().optional().allow("", null),
|
|
39402
|
+
section: import_joi33.default.string().optional().allow("", null),
|
|
39403
|
+
schoolYear: import_joi33.default.string().optional().allow("", null)
|
|
39404
|
+
});
|
|
39405
|
+
const { error } = validation.validate(query);
|
|
39406
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
39407
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
39408
|
+
const search = req.query.search ?? "";
|
|
39409
|
+
const status = req.query.status ?? "active";
|
|
39410
|
+
const school = req.query.school ?? "";
|
|
39411
|
+
const gradeLevel = req.query.gradeLevel ?? "";
|
|
39412
|
+
const section = req.query.section ?? "";
|
|
39413
|
+
const schoolYear = req.query.schoolYear ?? "";
|
|
39414
|
+
const isPageNumber = isFinite(page);
|
|
39415
|
+
if (!isPageNumber) {
|
|
39416
|
+
next(new import_nodejs_utils54.BadRequestError("Invalid page number."));
|
|
39417
|
+
return;
|
|
39418
|
+
}
|
|
39419
|
+
const isLimitNumber = isFinite(limit);
|
|
39420
|
+
if (!isLimitNumber) {
|
|
39421
|
+
next(new import_nodejs_utils54.BadRequestError("Invalid limit number."));
|
|
39422
|
+
return;
|
|
39423
|
+
}
|
|
39424
|
+
if (error) {
|
|
39425
|
+
next(new import_nodejs_utils54.BadRequestError(error.message));
|
|
39426
|
+
return;
|
|
39427
|
+
}
|
|
39428
|
+
try {
|
|
39429
|
+
const data = await _getAll({
|
|
39430
|
+
page,
|
|
39431
|
+
limit,
|
|
39432
|
+
search,
|
|
39433
|
+
status,
|
|
39434
|
+
school,
|
|
39435
|
+
gradeLevel,
|
|
39436
|
+
section,
|
|
39437
|
+
schoolYear
|
|
39438
|
+
});
|
|
39439
|
+
res.json(data);
|
|
39440
|
+
return;
|
|
39441
|
+
} catch (error2) {
|
|
39442
|
+
next(error2);
|
|
39443
|
+
}
|
|
39444
|
+
}
|
|
39445
|
+
return {
|
|
39446
|
+
add,
|
|
39447
|
+
getAll
|
|
39448
|
+
};
|
|
39449
|
+
}
|
|
39450
|
+
|
|
39451
|
+
// src/resources/building/building.model.ts
|
|
39452
|
+
var import_nodejs_utils55 = require("@eeplatform/nodejs-utils");
|
|
39453
|
+
var import_joi34 = __toESM(require("joi"));
|
|
39454
|
+
var import_mongodb31 = require("mongodb");
|
|
39455
|
+
var schemaBuilding = import_joi34.default.object({
|
|
39456
|
+
_id: import_joi34.default.string().hex().optional(),
|
|
39457
|
+
school: import_joi34.default.string().hex().required(),
|
|
39458
|
+
serial: import_joi34.default.string().optional().allow("", null),
|
|
39459
|
+
name: import_joi34.default.string().required(),
|
|
39460
|
+
levels: import_joi34.default.number().integer().min(1).required(),
|
|
39461
|
+
createdAt: import_joi34.default.date().optional().allow("", null),
|
|
39462
|
+
updatedAt: import_joi34.default.date().optional().allow("", null),
|
|
39463
|
+
deletedAt: import_joi34.default.date().optional().allow("", null),
|
|
39464
|
+
status: import_joi34.default.string().optional().allow("", null)
|
|
39465
|
+
});
|
|
39466
|
+
var schemaBuildingUnit = import_joi34.default.object({
|
|
39467
|
+
_id: import_joi34.default.string().hex().optional(),
|
|
39468
|
+
school: import_joi34.default.string().hex().required(),
|
|
39469
|
+
name: import_joi34.default.string().optional().allow("", null),
|
|
39470
|
+
building: import_joi34.default.string().hex().required(),
|
|
39471
|
+
buildingName: import_joi34.default.string().optional().allow("", null),
|
|
39472
|
+
level: import_joi34.default.number().integer().min(1).required(),
|
|
39473
|
+
category: import_joi34.default.string().required(),
|
|
39474
|
+
type: import_joi34.default.string().required(),
|
|
39475
|
+
seating_capacity: import_joi34.default.number().integer().min(0).required(),
|
|
39476
|
+
standing_capacity: import_joi34.default.number().integer().min(0).required(),
|
|
39477
|
+
description: import_joi34.default.string().optional().allow("", null),
|
|
39478
|
+
unit_of_measurement: import_joi34.default.string().valid("sqm").required(),
|
|
39479
|
+
area: import_joi34.default.number().positive().required(),
|
|
39480
|
+
status: import_joi34.default.string().optional().allow("", null)
|
|
39481
|
+
});
|
|
39482
|
+
var schemaUpdateOptions = import_joi34.default.object({
|
|
39483
|
+
name: import_joi34.default.string().optional().allow("", null),
|
|
39484
|
+
building: import_joi34.default.string().hex().optional().allow("", null),
|
|
39485
|
+
buildingName: import_joi34.default.string().optional().allow("", null),
|
|
39486
|
+
level: import_joi34.default.number().integer().min(1).optional().allow("", null),
|
|
39487
|
+
category: import_joi34.default.string().optional().allow("", null),
|
|
39488
|
+
type: import_joi34.default.string().optional().allow("", null),
|
|
39489
|
+
seating_capacity: import_joi34.default.number().integer().min(0).optional().allow("", null),
|
|
39490
|
+
standing_capacity: import_joi34.default.number().integer().min(0).optional().allow("", null),
|
|
39491
|
+
area: import_joi34.default.number().positive().optional().allow("", null)
|
|
39492
|
+
});
|
|
39493
|
+
function MBuilding(value) {
|
|
39494
|
+
const { error } = schemaBuilding.validate(value);
|
|
39495
|
+
if (error) {
|
|
39496
|
+
import_nodejs_utils55.logger.info(`Building Model: ${error.message}`);
|
|
39497
|
+
throw new import_nodejs_utils55.BadRequestError(error.message);
|
|
39498
|
+
}
|
|
39499
|
+
if (value._id && typeof value._id === "string") {
|
|
39500
|
+
try {
|
|
39501
|
+
value._id = new import_mongodb31.ObjectId(value._id);
|
|
39502
|
+
} catch (error2) {
|
|
39503
|
+
throw new import_nodejs_utils55.BadRequestError("Invalid _id format");
|
|
39504
|
+
}
|
|
39505
|
+
}
|
|
39506
|
+
try {
|
|
39507
|
+
value.school = new import_mongodb31.ObjectId(value.school);
|
|
39508
|
+
} catch (error2) {
|
|
39509
|
+
throw new import_nodejs_utils55.BadRequestError("Invalid school format");
|
|
39510
|
+
}
|
|
39511
|
+
return {
|
|
39512
|
+
_id: value._id ?? void 0,
|
|
39513
|
+
school: value.school,
|
|
39514
|
+
serial: value.serial ?? "",
|
|
39515
|
+
name: value.name ?? "",
|
|
39516
|
+
levels: value.levels ?? 0,
|
|
39517
|
+
status: value.status ?? "active",
|
|
39518
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
39519
|
+
updatedAt: value.updatedAt ?? "",
|
|
39520
|
+
deletedAt: value.deletedAt ?? ""
|
|
39521
|
+
};
|
|
39522
|
+
}
|
|
39523
|
+
function MBuildingUnit(value) {
|
|
39524
|
+
const { error } = schemaBuildingUnit.validate(value);
|
|
39525
|
+
if (error) {
|
|
39526
|
+
import_nodejs_utils55.logger.info(`Building Unit Model: ${error.message}`);
|
|
39527
|
+
throw new import_nodejs_utils55.BadRequestError(error.message);
|
|
39528
|
+
}
|
|
39529
|
+
if (value._id && typeof value._id === "string") {
|
|
39530
|
+
try {
|
|
39531
|
+
value._id = new import_mongodb31.ObjectId(value._id);
|
|
39532
|
+
} catch (error2) {
|
|
39533
|
+
throw new import_nodejs_utils55.BadRequestError("Invalid ID");
|
|
39534
|
+
}
|
|
39535
|
+
}
|
|
39536
|
+
try {
|
|
39537
|
+
value.school = new import_mongodb31.ObjectId(value.school);
|
|
39538
|
+
} catch (error2) {
|
|
39539
|
+
throw new import_nodejs_utils55.BadRequestError("Invalid school ID");
|
|
39540
|
+
}
|
|
39541
|
+
try {
|
|
39542
|
+
value.building = new import_mongodb31.ObjectId(value.building);
|
|
39543
|
+
} catch (error2) {
|
|
39544
|
+
throw new import_nodejs_utils55.BadRequestError("Invalid building ID");
|
|
39545
|
+
}
|
|
39546
|
+
return {
|
|
39547
|
+
_id: value._id ?? void 0,
|
|
39548
|
+
school: value.school,
|
|
39549
|
+
name: value.name ?? "",
|
|
39550
|
+
building: value.building,
|
|
39551
|
+
buildingName: value.buildingName ?? "",
|
|
39552
|
+
level: value.level ?? 0,
|
|
39553
|
+
category: value.category ?? "",
|
|
39554
|
+
type: value.type ?? "",
|
|
39555
|
+
seating_capacity: value.seating_capacity ?? 0,
|
|
39556
|
+
standing_capacity: value.standing_capacity ?? 0,
|
|
39557
|
+
description: value.description ?? "",
|
|
39558
|
+
unit_of_measurement: value.unit_of_measurement ?? "sqm",
|
|
39559
|
+
area: value.area ?? 0,
|
|
39560
|
+
status: value.status ?? "active",
|
|
39561
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
39562
|
+
updatedAt: value.updatedAt ?? "",
|
|
39563
|
+
deletedAt: value.deletedAt ?? ""
|
|
39564
|
+
};
|
|
39565
|
+
}
|
|
39566
|
+
|
|
39567
|
+
// src/resources/building/building.repository.ts
|
|
39568
|
+
var import_nodejs_utils56 = require("@eeplatform/nodejs-utils");
|
|
39569
|
+
var import_mongodb32 = require("mongodb");
|
|
39570
|
+
function useBuildingRepo() {
|
|
39571
|
+
const db = import_nodejs_utils56.useAtlas.getDb();
|
|
39572
|
+
if (!db) {
|
|
39573
|
+
throw new Error("Unable to connect to server.");
|
|
39574
|
+
}
|
|
39575
|
+
const namespace_collection = "school.buildings";
|
|
39576
|
+
const collection = db.collection(namespace_collection);
|
|
39577
|
+
const { getCache, setCache, delNamespace } = (0, import_nodejs_utils56.useCache)(namespace_collection);
|
|
39578
|
+
async function createIndexes() {
|
|
39579
|
+
try {
|
|
39580
|
+
await collection.createIndexes([
|
|
39581
|
+
{ key: { name: 1 }, unique: true, name: "unique_name_index" },
|
|
39582
|
+
{ key: { school: 1 } },
|
|
39583
|
+
{ key: { status: 1 } }
|
|
39584
|
+
]);
|
|
39585
|
+
} catch (error) {
|
|
39586
|
+
throw new Error("Failed to create index on buildings.");
|
|
39587
|
+
}
|
|
39588
|
+
}
|
|
39589
|
+
async function add(value, session) {
|
|
39590
|
+
try {
|
|
39591
|
+
value = MBuilding(value);
|
|
39592
|
+
const res = await collection.insertOne(value, { session });
|
|
39593
|
+
delCachedData();
|
|
39594
|
+
return res.insertedId;
|
|
39595
|
+
} catch (error) {
|
|
39596
|
+
import_nodejs_utils56.logger.log({
|
|
39597
|
+
level: "error",
|
|
39598
|
+
message: error.message
|
|
39599
|
+
});
|
|
39600
|
+
if (error instanceof import_nodejs_utils56.AppError) {
|
|
39601
|
+
throw error;
|
|
39602
|
+
} else {
|
|
39603
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
39604
|
+
if (isDuplicated) {
|
|
39605
|
+
throw new import_nodejs_utils56.BadRequestError("Building already exists.");
|
|
39606
|
+
}
|
|
39607
|
+
throw new Error("Failed to create building.");
|
|
39608
|
+
}
|
|
39609
|
+
}
|
|
39610
|
+
}
|
|
39611
|
+
async function updateById(_id, value, session) {
|
|
39612
|
+
try {
|
|
39613
|
+
_id = new import_mongodb32.ObjectId(_id);
|
|
39614
|
+
} catch (error) {
|
|
39615
|
+
throw new import_nodejs_utils56.BadRequestError("Invalid ID.");
|
|
39616
|
+
}
|
|
39617
|
+
try {
|
|
39618
|
+
const res = await collection.updateOne(
|
|
39619
|
+
{ _id },
|
|
39620
|
+
{ $set: value },
|
|
39621
|
+
{ session }
|
|
39622
|
+
);
|
|
39623
|
+
delCachedData();
|
|
39624
|
+
return res;
|
|
39625
|
+
} catch (error) {
|
|
39626
|
+
import_nodejs_utils56.logger.log({
|
|
39627
|
+
level: "error",
|
|
39628
|
+
message: error.message
|
|
39629
|
+
});
|
|
39630
|
+
if (error instanceof import_nodejs_utils56.AppError) {
|
|
39631
|
+
throw error;
|
|
39632
|
+
} else {
|
|
39633
|
+
throw new Error("Failed to update building.");
|
|
39634
|
+
}
|
|
39635
|
+
}
|
|
39636
|
+
}
|
|
39637
|
+
async function getAll({
|
|
39638
|
+
search = "",
|
|
39639
|
+
page = 1,
|
|
39640
|
+
limit = 10,
|
|
39641
|
+
sort = {},
|
|
39642
|
+
school = "",
|
|
39643
|
+
status = "active"
|
|
39644
|
+
} = {}) {
|
|
39645
|
+
page = page > 0 ? page - 1 : 0;
|
|
39646
|
+
const query = {
|
|
39647
|
+
status
|
|
39648
|
+
};
|
|
39649
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
39650
|
+
if (search) {
|
|
39651
|
+
query.$text = { $search: search };
|
|
39652
|
+
}
|
|
39653
|
+
if (school) {
|
|
39654
|
+
try {
|
|
39655
|
+
query.school = new import_mongodb32.ObjectId(school);
|
|
39656
|
+
} catch (error) {
|
|
39657
|
+
throw new import_nodejs_utils56.BadRequestError("Invalid school ID.");
|
|
39658
|
+
}
|
|
39659
|
+
}
|
|
39660
|
+
const cacheParams = {
|
|
39661
|
+
page,
|
|
39662
|
+
limit,
|
|
39663
|
+
sort: JSON.stringify(sort)
|
|
39664
|
+
};
|
|
39665
|
+
if (search)
|
|
39666
|
+
cacheParams.search = search;
|
|
39667
|
+
if (school)
|
|
39668
|
+
cacheParams.school = school;
|
|
39669
|
+
if (status !== "active")
|
|
39670
|
+
cacheParams.status = status;
|
|
39671
|
+
const cacheKey = (0, import_nodejs_utils56.makeCacheKey)(namespace_collection, cacheParams);
|
|
39672
|
+
import_nodejs_utils56.logger.log({
|
|
39673
|
+
level: "info",
|
|
39674
|
+
message: `Cache key for getAll buildings: ${cacheKey}`
|
|
39675
|
+
});
|
|
39676
|
+
try {
|
|
39677
|
+
const cached = await getCache(cacheKey);
|
|
39678
|
+
if (cached) {
|
|
39679
|
+
import_nodejs_utils56.logger.log({
|
|
39680
|
+
level: "info",
|
|
39681
|
+
message: `Cache hit for getAll buildings: ${cacheKey}`
|
|
39682
|
+
});
|
|
39683
|
+
return cached;
|
|
39684
|
+
}
|
|
39685
|
+
const items = await collection.aggregate([
|
|
39686
|
+
{ $match: query },
|
|
39687
|
+
{ $sort: sort },
|
|
39688
|
+
{ $skip: page * limit },
|
|
39689
|
+
{ $limit: limit }
|
|
39690
|
+
]).toArray();
|
|
39691
|
+
const length = await collection.countDocuments(query);
|
|
39692
|
+
const data = (0, import_nodejs_utils56.paginate)(items, page, limit, length);
|
|
39693
|
+
setCache(cacheKey, data, 600).then(() => {
|
|
39694
|
+
import_nodejs_utils56.logger.log({
|
|
39695
|
+
level: "info",
|
|
39696
|
+
message: `Cache set for getAll buildings: ${cacheKey}`
|
|
39697
|
+
});
|
|
39698
|
+
}).catch((err) => {
|
|
39699
|
+
import_nodejs_utils56.logger.log({
|
|
39700
|
+
level: "error",
|
|
39701
|
+
message: `Failed to set cache for getAll buildings: ${err.message}`
|
|
39702
|
+
});
|
|
39703
|
+
});
|
|
39704
|
+
return data;
|
|
39705
|
+
} catch (error) {
|
|
39706
|
+
import_nodejs_utils56.logger.log({ level: "error", message: `${error}` });
|
|
39707
|
+
throw error;
|
|
39708
|
+
}
|
|
39709
|
+
}
|
|
39710
|
+
async function getById(_id) {
|
|
39711
|
+
try {
|
|
39712
|
+
_id = new import_mongodb32.ObjectId(_id);
|
|
39713
|
+
} catch (error) {
|
|
39714
|
+
throw new import_nodejs_utils56.BadRequestError("Invalid ID.");
|
|
39715
|
+
}
|
|
39716
|
+
const cacheKey = (0, import_nodejs_utils56.makeCacheKey)(namespace_collection, { _id: String(_id) });
|
|
39717
|
+
try {
|
|
39718
|
+
const cached = await getCache(cacheKey);
|
|
39719
|
+
if (cached) {
|
|
39720
|
+
import_nodejs_utils56.logger.log({
|
|
39721
|
+
level: "info",
|
|
39722
|
+
message: `Cache hit for getById building: ${cacheKey}`
|
|
39723
|
+
});
|
|
39724
|
+
return cached;
|
|
39725
|
+
}
|
|
39726
|
+
const result = await collection.findOne({
|
|
39727
|
+
_id
|
|
39728
|
+
});
|
|
39729
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
39730
|
+
import_nodejs_utils56.logger.log({
|
|
39731
|
+
level: "info",
|
|
39732
|
+
message: `Cache set for building by id: ${cacheKey}`
|
|
39733
|
+
});
|
|
39734
|
+
}).catch((err) => {
|
|
39735
|
+
import_nodejs_utils56.logger.log({
|
|
39736
|
+
level: "error",
|
|
39737
|
+
message: `Failed to set cache for building by id: ${err.message}`
|
|
39738
|
+
});
|
|
39739
|
+
});
|
|
39740
|
+
return result;
|
|
39741
|
+
} catch (error) {
|
|
39742
|
+
if (error instanceof import_nodejs_utils56.AppError) {
|
|
39743
|
+
throw error;
|
|
39744
|
+
} else {
|
|
39745
|
+
throw new import_nodejs_utils56.InternalServerError("Failed to get building.");
|
|
39746
|
+
}
|
|
39747
|
+
}
|
|
39748
|
+
}
|
|
39749
|
+
async function deleteById(_id, session) {
|
|
39750
|
+
try {
|
|
39751
|
+
_id = new import_mongodb32.ObjectId(_id);
|
|
39752
|
+
} catch (error) {
|
|
39753
|
+
throw new import_nodejs_utils56.BadRequestError("Invalid ID.");
|
|
39754
|
+
}
|
|
39755
|
+
try {
|
|
39756
|
+
const res = await collection.updateOne(
|
|
39757
|
+
{ _id },
|
|
39758
|
+
{ $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
|
|
39759
|
+
);
|
|
39760
|
+
delCachedData();
|
|
39761
|
+
return res;
|
|
39762
|
+
} catch (error) {
|
|
39763
|
+
import_nodejs_utils56.logger.log({
|
|
39764
|
+
level: "error",
|
|
39765
|
+
message: error.message
|
|
39766
|
+
});
|
|
39767
|
+
if (error instanceof import_nodejs_utils56.AppError) {
|
|
39768
|
+
throw error;
|
|
39769
|
+
} else {
|
|
39770
|
+
throw new import_nodejs_utils56.InternalServerError("Failed to delete building.");
|
|
39771
|
+
}
|
|
39772
|
+
}
|
|
39773
|
+
}
|
|
39774
|
+
function delCachedData() {
|
|
39775
|
+
delNamespace().then(() => {
|
|
39776
|
+
import_nodejs_utils56.logger.log({
|
|
39777
|
+
level: "info",
|
|
39778
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
39779
|
+
});
|
|
39780
|
+
}).catch((err) => {
|
|
39781
|
+
import_nodejs_utils56.logger.log({
|
|
39782
|
+
level: "error",
|
|
39783
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
39784
|
+
});
|
|
39785
|
+
});
|
|
39786
|
+
}
|
|
39787
|
+
return {
|
|
39788
|
+
createIndexes,
|
|
39789
|
+
add,
|
|
39790
|
+
getAll,
|
|
39791
|
+
getById,
|
|
39792
|
+
updateById,
|
|
39793
|
+
deleteById
|
|
39794
|
+
};
|
|
39795
|
+
}
|
|
39796
|
+
|
|
39797
|
+
// src/resources/building/building.service.ts
|
|
39798
|
+
var import_nodejs_utils58 = require("@eeplatform/nodejs-utils");
|
|
39799
|
+
|
|
39800
|
+
// src/resources/building/building-unit.repository.ts
|
|
39801
|
+
var import_nodejs_utils57 = require("@eeplatform/nodejs-utils");
|
|
39802
|
+
var import_mongodb33 = require("mongodb");
|
|
39803
|
+
function useBuildingUnitRepo() {
|
|
39804
|
+
const db = import_nodejs_utils57.useAtlas.getDb();
|
|
39805
|
+
if (!db) {
|
|
39806
|
+
throw new Error("Unable to connect to server.");
|
|
39807
|
+
}
|
|
39808
|
+
const namespace_collection = "school.building-units";
|
|
39809
|
+
const collection = db.collection(namespace_collection);
|
|
39810
|
+
const { getCache, setCache, delNamespace } = (0, import_nodejs_utils57.useCache)(namespace_collection);
|
|
39811
|
+
async function createIndexes() {
|
|
39812
|
+
try {
|
|
39813
|
+
await collection.createIndexes([
|
|
39814
|
+
{
|
|
39815
|
+
key: { name: 1, building: 1, level: 1 },
|
|
39816
|
+
unique: true,
|
|
39817
|
+
name: "unique_name_index"
|
|
39818
|
+
},
|
|
39819
|
+
{ key: { school: 1 } },
|
|
39820
|
+
{ key: { building: 1 } },
|
|
39821
|
+
{ key: { status: 1 } },
|
|
39822
|
+
{ key: { createdAt: 1 } },
|
|
39823
|
+
{
|
|
39824
|
+
key: {
|
|
39825
|
+
name: "text",
|
|
39826
|
+
buildingName: "text",
|
|
39827
|
+
category: "text",
|
|
39828
|
+
type: "text"
|
|
39829
|
+
}
|
|
39830
|
+
}
|
|
39831
|
+
]);
|
|
39832
|
+
} catch (error) {
|
|
39833
|
+
throw new Error("Failed to create index on building units.");
|
|
39834
|
+
}
|
|
39835
|
+
}
|
|
39836
|
+
function delCachedData() {
|
|
39837
|
+
delNamespace().then(() => {
|
|
39838
|
+
import_nodejs_utils57.logger.log({
|
|
39839
|
+
level: "info",
|
|
39840
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
39841
|
+
});
|
|
39842
|
+
}).catch((err) => {
|
|
39843
|
+
import_nodejs_utils57.logger.log({
|
|
39844
|
+
level: "error",
|
|
39845
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
39846
|
+
});
|
|
39847
|
+
});
|
|
39848
|
+
}
|
|
39849
|
+
async function add(value, session) {
|
|
39850
|
+
try {
|
|
39851
|
+
value = MBuildingUnit(value);
|
|
39852
|
+
const res = await collection.insertOne(value, { session });
|
|
39853
|
+
delCachedData();
|
|
39854
|
+
return res.insertedId;
|
|
39855
|
+
} catch (error) {
|
|
39856
|
+
import_nodejs_utils57.logger.log({
|
|
39857
|
+
level: "error",
|
|
39858
|
+
message: error.message
|
|
39859
|
+
});
|
|
39860
|
+
if (error instanceof import_nodejs_utils57.AppError) {
|
|
39861
|
+
throw error;
|
|
39862
|
+
} else {
|
|
39863
|
+
throw new Error("Failed to create building unit.");
|
|
39864
|
+
}
|
|
39865
|
+
}
|
|
39866
|
+
}
|
|
39867
|
+
async function updateById(_id, value, session) {
|
|
39868
|
+
const { error } = schemaUpdateOptions.validate(value);
|
|
39869
|
+
if (error) {
|
|
39870
|
+
throw new import_nodejs_utils57.BadRequestError(error.message);
|
|
39871
|
+
}
|
|
39872
|
+
try {
|
|
39873
|
+
_id = new import_mongodb33.ObjectId(_id);
|
|
39874
|
+
} catch (error2) {
|
|
39875
|
+
throw new import_nodejs_utils57.BadRequestError("Invalid ID.");
|
|
39876
|
+
}
|
|
39877
|
+
try {
|
|
39878
|
+
const res = await collection.updateOne(
|
|
39879
|
+
{ _id },
|
|
39880
|
+
{ $set: value },
|
|
39881
|
+
{ session }
|
|
39882
|
+
);
|
|
39883
|
+
delCachedData();
|
|
39884
|
+
return res;
|
|
39885
|
+
} catch (error2) {
|
|
39886
|
+
import_nodejs_utils57.logger.log({
|
|
39887
|
+
level: "error",
|
|
39888
|
+
message: error2.message
|
|
39889
|
+
});
|
|
39890
|
+
if (error2 instanceof import_nodejs_utils57.AppError) {
|
|
39891
|
+
throw error2;
|
|
39892
|
+
} else {
|
|
39893
|
+
throw new Error("Failed to create building unit.");
|
|
39894
|
+
}
|
|
39895
|
+
}
|
|
39896
|
+
}
|
|
39897
|
+
async function updateByBuildingId(building, value, session) {
|
|
39898
|
+
const { error } = schemaUpdateOptions.validate(value);
|
|
39899
|
+
if (error) {
|
|
39900
|
+
throw new import_nodejs_utils57.BadRequestError(error.message);
|
|
39901
|
+
}
|
|
39902
|
+
try {
|
|
39903
|
+
building = new import_mongodb33.ObjectId(building);
|
|
39904
|
+
} catch (error2) {
|
|
39905
|
+
throw new import_nodejs_utils57.BadRequestError("Invalid building ID.");
|
|
39906
|
+
}
|
|
39907
|
+
try {
|
|
39908
|
+
const res = await collection.updateMany(
|
|
39909
|
+
{ building },
|
|
39910
|
+
{ $set: value },
|
|
39911
|
+
{ session }
|
|
39912
|
+
);
|
|
39913
|
+
delCachedData();
|
|
39914
|
+
return res;
|
|
39915
|
+
} catch (error2) {
|
|
39916
|
+
import_nodejs_utils57.logger.log({
|
|
39917
|
+
level: "error",
|
|
39918
|
+
message: error2.message
|
|
39919
|
+
});
|
|
39920
|
+
if (error2 instanceof import_nodejs_utils57.AppError) {
|
|
39921
|
+
throw error2;
|
|
39922
|
+
} else {
|
|
39923
|
+
throw new Error("Failed to update building unit.");
|
|
39924
|
+
}
|
|
39925
|
+
}
|
|
39926
|
+
}
|
|
39927
|
+
async function getAll({
|
|
39928
|
+
search = "",
|
|
39929
|
+
page = 1,
|
|
39930
|
+
limit = 10,
|
|
39931
|
+
sort = {},
|
|
39932
|
+
school = "",
|
|
39933
|
+
building = "",
|
|
39934
|
+
status = "active"
|
|
39935
|
+
} = {}) {
|
|
39936
|
+
page = page > 0 ? page - 1 : 0;
|
|
39937
|
+
const query = {
|
|
39938
|
+
deletedAt: { $in: ["", null] },
|
|
39939
|
+
status: { $in: [status, "", null] }
|
|
39940
|
+
};
|
|
39941
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
39942
|
+
if (search) {
|
|
39943
|
+
query.$text = { $search: search };
|
|
39944
|
+
}
|
|
39945
|
+
if (school) {
|
|
39946
|
+
try {
|
|
39947
|
+
query.school = new import_mongodb33.ObjectId(school);
|
|
39948
|
+
} catch (error) {
|
|
39949
|
+
throw new import_nodejs_utils57.BadRequestError("Invalid school ID.");
|
|
39950
|
+
}
|
|
39951
|
+
}
|
|
39952
|
+
if (building) {
|
|
39953
|
+
try {
|
|
39954
|
+
query.building = new import_mongodb33.ObjectId(building);
|
|
39955
|
+
} catch (error) {
|
|
39956
|
+
throw new import_nodejs_utils57.BadRequestError("Invalid building ID.");
|
|
39957
|
+
}
|
|
39958
|
+
}
|
|
39959
|
+
const cacheParams = {
|
|
39960
|
+
page,
|
|
39961
|
+
limit,
|
|
39962
|
+
sort: JSON.stringify(sort)
|
|
39963
|
+
};
|
|
39964
|
+
if (search)
|
|
39965
|
+
cacheParams.search = search;
|
|
39966
|
+
if (school)
|
|
39967
|
+
cacheParams.school = school;
|
|
39968
|
+
if (building)
|
|
39969
|
+
cacheParams.building = building;
|
|
39970
|
+
if (status !== "active")
|
|
39971
|
+
cacheParams.status = status;
|
|
39972
|
+
const cacheKey = (0, import_nodejs_utils57.makeCacheKey)(namespace_collection, cacheParams);
|
|
39973
|
+
import_nodejs_utils57.logger.log({
|
|
39974
|
+
level: "info",
|
|
39975
|
+
message: `Cache key for getAll building units: ${cacheKey}`
|
|
39976
|
+
});
|
|
39977
|
+
try {
|
|
39978
|
+
const cached = await getCache(cacheKey);
|
|
39979
|
+
if (cached) {
|
|
39980
|
+
import_nodejs_utils57.logger.log({
|
|
39981
|
+
level: "info",
|
|
39982
|
+
message: `Cache hit for getAll building units: ${cacheKey}`
|
|
39983
|
+
});
|
|
39984
|
+
return cached;
|
|
39985
|
+
}
|
|
39986
|
+
const items = await collection.aggregate([
|
|
39987
|
+
{ $match: query },
|
|
39988
|
+
{ $sort: sort },
|
|
39989
|
+
{ $skip: page * limit },
|
|
39990
|
+
{ $limit: limit }
|
|
39991
|
+
]).toArray();
|
|
39992
|
+
const length = await collection.countDocuments(query);
|
|
39993
|
+
const data = (0, import_nodejs_utils57.paginate)(items, page, limit, length);
|
|
39994
|
+
setCache(cacheKey, data, 600).then(() => {
|
|
39995
|
+
import_nodejs_utils57.logger.log({
|
|
39996
|
+
level: "info",
|
|
39997
|
+
message: `Cache set for getAll building units: ${cacheKey}`
|
|
39998
|
+
});
|
|
39999
|
+
}).catch((err) => {
|
|
40000
|
+
import_nodejs_utils57.logger.log({
|
|
40001
|
+
level: "error",
|
|
40002
|
+
message: `Failed to set cache for getAll building units: ${err.message}`
|
|
40003
|
+
});
|
|
40004
|
+
});
|
|
40005
|
+
return data;
|
|
40006
|
+
} catch (error) {
|
|
40007
|
+
import_nodejs_utils57.logger.log({ level: "error", message: `${error}` });
|
|
40008
|
+
throw error;
|
|
40009
|
+
}
|
|
40010
|
+
}
|
|
40011
|
+
async function getById(_id) {
|
|
40012
|
+
try {
|
|
40013
|
+
_id = new import_mongodb33.ObjectId(_id);
|
|
40014
|
+
} catch (error) {
|
|
40015
|
+
throw new import_nodejs_utils57.BadRequestError("Invalid ID.");
|
|
40016
|
+
}
|
|
40017
|
+
const cacheKey = (0, import_nodejs_utils57.makeCacheKey)(namespace_collection, { _id: String(_id) });
|
|
40018
|
+
try {
|
|
40019
|
+
const cached = await getCache(cacheKey);
|
|
40020
|
+
if (cached) {
|
|
40021
|
+
import_nodejs_utils57.logger.log({
|
|
40022
|
+
level: "info",
|
|
40023
|
+
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
40024
|
+
});
|
|
40025
|
+
return cached;
|
|
40026
|
+
}
|
|
40027
|
+
const result = await collection.findOne({
|
|
40028
|
+
_id,
|
|
40029
|
+
deletedAt: { $in: ["", null] }
|
|
40030
|
+
});
|
|
40031
|
+
if (!result) {
|
|
40032
|
+
throw new import_nodejs_utils57.BadRequestError("Building unit not found.");
|
|
40033
|
+
}
|
|
40034
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
40035
|
+
import_nodejs_utils57.logger.log({
|
|
40036
|
+
level: "info",
|
|
40037
|
+
message: `Cache set for building unit by id: ${cacheKey}`
|
|
40038
|
+
});
|
|
40039
|
+
}).catch((err) => {
|
|
40040
|
+
import_nodejs_utils57.logger.log({
|
|
40041
|
+
level: "error",
|
|
40042
|
+
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
40043
|
+
});
|
|
40044
|
+
});
|
|
40045
|
+
return result;
|
|
40046
|
+
} catch (error) {
|
|
40047
|
+
if (error instanceof import_nodejs_utils57.AppError) {
|
|
40048
|
+
throw error;
|
|
40049
|
+
} else {
|
|
40050
|
+
throw new import_nodejs_utils57.InternalServerError("Failed to get building unit.");
|
|
40051
|
+
}
|
|
40052
|
+
}
|
|
40053
|
+
}
|
|
40054
|
+
async function getByBuildingLevel(building, level) {
|
|
40055
|
+
try {
|
|
40056
|
+
building = new import_mongodb33.ObjectId(building);
|
|
40057
|
+
} catch (error) {
|
|
40058
|
+
throw new import_nodejs_utils57.BadRequestError("Invalid building ID.");
|
|
40059
|
+
}
|
|
40060
|
+
const cacheKey = (0, import_nodejs_utils57.makeCacheKey)(namespace_collection, {
|
|
40061
|
+
building: String(building),
|
|
40062
|
+
level
|
|
40063
|
+
});
|
|
40064
|
+
try {
|
|
40065
|
+
const cached = await getCache(cacheKey);
|
|
40066
|
+
if (cached) {
|
|
40067
|
+
import_nodejs_utils57.logger.log({
|
|
40068
|
+
level: "info",
|
|
40069
|
+
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
40070
|
+
});
|
|
40071
|
+
return cached;
|
|
40072
|
+
}
|
|
40073
|
+
const result = await collection.findOne({
|
|
40074
|
+
building,
|
|
40075
|
+
level,
|
|
40076
|
+
status: "active"
|
|
40077
|
+
});
|
|
40078
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
40079
|
+
import_nodejs_utils57.logger.log({
|
|
40080
|
+
level: "info",
|
|
40081
|
+
message: `Cache set for building unit by id: ${cacheKey}`
|
|
40082
|
+
});
|
|
40083
|
+
}).catch((err) => {
|
|
40084
|
+
import_nodejs_utils57.logger.log({
|
|
40085
|
+
level: "error",
|
|
40086
|
+
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
40087
|
+
});
|
|
40088
|
+
});
|
|
40089
|
+
return result;
|
|
40090
|
+
} catch (error) {
|
|
40091
|
+
if (error instanceof import_nodejs_utils57.AppError) {
|
|
40092
|
+
throw error;
|
|
40093
|
+
} else {
|
|
40094
|
+
throw new import_nodejs_utils57.InternalServerError("Failed to get building unit.");
|
|
40095
|
+
}
|
|
40096
|
+
}
|
|
40097
|
+
}
|
|
40098
|
+
async function getByBuilding(building) {
|
|
40099
|
+
try {
|
|
40100
|
+
building = new import_mongodb33.ObjectId(building);
|
|
40101
|
+
} catch (error) {
|
|
40102
|
+
throw new import_nodejs_utils57.BadRequestError("Invalid building ID.");
|
|
40103
|
+
}
|
|
40104
|
+
const cacheKey = (0, import_nodejs_utils57.makeCacheKey)(namespace_collection, {
|
|
40105
|
+
building: String(building)
|
|
40106
|
+
});
|
|
40107
|
+
try {
|
|
40108
|
+
const cached = await getCache(cacheKey);
|
|
40109
|
+
if (cached) {
|
|
40110
|
+
import_nodejs_utils57.logger.log({
|
|
40111
|
+
level: "info",
|
|
40112
|
+
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
40113
|
+
});
|
|
40114
|
+
return cached;
|
|
40115
|
+
}
|
|
40116
|
+
const result = await collection.findOne({
|
|
40117
|
+
building,
|
|
40118
|
+
status: "active"
|
|
40119
|
+
});
|
|
40120
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
40121
|
+
import_nodejs_utils57.logger.log({
|
|
40122
|
+
level: "info",
|
|
40123
|
+
message: `Cache set for building unit by id: ${cacheKey}`
|
|
40124
|
+
});
|
|
40125
|
+
}).catch((err) => {
|
|
40126
|
+
import_nodejs_utils57.logger.log({
|
|
40127
|
+
level: "error",
|
|
40128
|
+
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
40129
|
+
});
|
|
40130
|
+
});
|
|
40131
|
+
return result;
|
|
40132
|
+
} catch (error) {
|
|
40133
|
+
if (error instanceof import_nodejs_utils57.AppError) {
|
|
40134
|
+
throw error;
|
|
40135
|
+
} else {
|
|
40136
|
+
throw new import_nodejs_utils57.InternalServerError("Failed to get building unit.");
|
|
40137
|
+
}
|
|
40138
|
+
}
|
|
40139
|
+
}
|
|
40140
|
+
async function deleteById(_id, session) {
|
|
40141
|
+
try {
|
|
40142
|
+
_id = new import_mongodb33.ObjectId(_id);
|
|
40143
|
+
} catch (error) {
|
|
40144
|
+
throw new import_nodejs_utils57.BadRequestError("Invalid ID.");
|
|
40145
|
+
}
|
|
40146
|
+
try {
|
|
40147
|
+
const res = await collection.updateOne(
|
|
40148
|
+
{ _id },
|
|
40149
|
+
{ $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } },
|
|
40150
|
+
{ session }
|
|
40151
|
+
);
|
|
40152
|
+
delCachedData();
|
|
40153
|
+
return "Room/Facility deleted successfully.";
|
|
40154
|
+
} catch (error) {
|
|
40155
|
+
import_nodejs_utils57.logger.log({
|
|
40156
|
+
level: "error",
|
|
40157
|
+
message: error.message
|
|
40158
|
+
});
|
|
40159
|
+
if (error instanceof import_nodejs_utils57.AppError) {
|
|
40160
|
+
throw error;
|
|
40161
|
+
} else {
|
|
40162
|
+
throw new Error("Failed to deleted room/facility.");
|
|
40163
|
+
}
|
|
40164
|
+
}
|
|
40165
|
+
}
|
|
40166
|
+
return {
|
|
40167
|
+
createIndexes,
|
|
40168
|
+
add,
|
|
40169
|
+
getAll,
|
|
40170
|
+
getById,
|
|
40171
|
+
getByBuildingLevel,
|
|
40172
|
+
updateById,
|
|
40173
|
+
getByBuilding,
|
|
40174
|
+
deleteById,
|
|
40175
|
+
updateByBuildingId
|
|
40176
|
+
};
|
|
40177
|
+
}
|
|
40178
|
+
|
|
40179
|
+
// src/resources/building/building.service.ts
|
|
40180
|
+
function useBuildingService() {
|
|
40181
|
+
const {
|
|
40182
|
+
updateById: _updateById,
|
|
40183
|
+
getById: _getById,
|
|
40184
|
+
deleteById: _deleteById
|
|
40185
|
+
} = useBuildingRepo();
|
|
40186
|
+
const { getByBuildingLevel, getByBuilding, updateByBuildingId } = useBuildingUnitRepo();
|
|
40187
|
+
async function updateById(id, data) {
|
|
40188
|
+
data.levels = Number(data.levels);
|
|
40189
|
+
const session = import_nodejs_utils58.useAtlas.getClient()?.startSession();
|
|
40190
|
+
try {
|
|
40191
|
+
const building = await _getById(id);
|
|
40192
|
+
if (!building) {
|
|
40193
|
+
throw new import_nodejs_utils58.NotFoundError("Building not found.");
|
|
40194
|
+
}
|
|
40195
|
+
if (data.levels < building.levels) {
|
|
40196
|
+
const unit = await getByBuildingLevel(id, building.levels);
|
|
40197
|
+
if (unit) {
|
|
40198
|
+
throw new import_nodejs_utils58.BadRequestError(
|
|
40199
|
+
"Cannot reduce floors, there are existing building units at higher floors."
|
|
40200
|
+
);
|
|
40201
|
+
}
|
|
40202
|
+
}
|
|
40203
|
+
session?.startTransaction();
|
|
40204
|
+
if (building.name !== data.name) {
|
|
40205
|
+
await updateByBuildingId(id, { buildingName: data.name }, session);
|
|
40206
|
+
}
|
|
40207
|
+
const result = await _updateById(id, data, session);
|
|
40208
|
+
await session?.commitTransaction();
|
|
40209
|
+
return result;
|
|
40210
|
+
} catch (error) {
|
|
40211
|
+
await session?.abortTransaction();
|
|
40212
|
+
throw error;
|
|
40213
|
+
} finally {
|
|
40214
|
+
session?.endSession();
|
|
40215
|
+
}
|
|
40216
|
+
}
|
|
40217
|
+
async function deleteById(id) {
|
|
40218
|
+
const building = await getByBuilding(id);
|
|
40219
|
+
if (building) {
|
|
40220
|
+
throw new import_nodejs_utils58.BadRequestError(
|
|
40221
|
+
"Cannot delete building with existing room/facility. Please delete room/facility first."
|
|
40222
|
+
);
|
|
40223
|
+
}
|
|
40224
|
+
try {
|
|
40225
|
+
await _deleteById(id);
|
|
40226
|
+
return "Building deleted successfully.";
|
|
40227
|
+
} catch (error) {
|
|
40228
|
+
throw error;
|
|
40229
|
+
}
|
|
40230
|
+
}
|
|
40231
|
+
return {
|
|
40232
|
+
updateById,
|
|
40233
|
+
deleteById
|
|
40234
|
+
};
|
|
40235
|
+
}
|
|
40236
|
+
|
|
40237
|
+
// src/resources/building/building.controller.ts
|
|
40238
|
+
var import_nodejs_utils59 = require("@eeplatform/nodejs-utils");
|
|
40239
|
+
var import_joi35 = __toESM(require("joi"));
|
|
40240
|
+
function useBuildingController() {
|
|
40241
|
+
const { getAll: _getAll, getById: _getById, add: _add } = useBuildingRepo();
|
|
40242
|
+
const { updateById: _updateById, deleteById: _deleteById } = useBuildingService();
|
|
40243
|
+
async function createBuilding(req, res, next) {
|
|
40244
|
+
const value = req.body;
|
|
40245
|
+
const validation = import_joi35.default.object({
|
|
40246
|
+
name: import_joi35.default.string().required(),
|
|
40247
|
+
school: import_joi35.default.string().hex().required(),
|
|
40248
|
+
levels: import_joi35.default.number().integer().min(1).required(),
|
|
40249
|
+
serial: import_joi35.default.string().optional().allow("", null),
|
|
40250
|
+
status: import_joi35.default.string().optional().allow("", null)
|
|
40251
|
+
});
|
|
40252
|
+
const { error } = validation.validate(value);
|
|
40253
|
+
if (error) {
|
|
40254
|
+
next(new import_nodejs_utils59.BadRequestError(error.message));
|
|
40255
|
+
import_nodejs_utils59.logger.info(`Controller: ${error.message}`);
|
|
40256
|
+
return;
|
|
40257
|
+
}
|
|
40258
|
+
try {
|
|
40259
|
+
const result = await _add(value);
|
|
40260
|
+
res.json(result);
|
|
40261
|
+
return;
|
|
40262
|
+
} catch (error2) {
|
|
40263
|
+
next(error2);
|
|
40264
|
+
}
|
|
40265
|
+
}
|
|
40266
|
+
async function updateById(req, res, next) {
|
|
40267
|
+
const value = req.body;
|
|
40268
|
+
const id = req.params.id ?? "";
|
|
40269
|
+
const validation = import_joi35.default.object({
|
|
40270
|
+
id: import_joi35.default.string().hex().required(),
|
|
40271
|
+
value: import_joi35.default.object({
|
|
40272
|
+
name: import_joi35.default.string().required(),
|
|
40273
|
+
serial: import_joi35.default.string().optional().allow("", null),
|
|
40274
|
+
levels: import_joi35.default.number().integer().min(1).required()
|
|
40275
|
+
})
|
|
40276
|
+
});
|
|
40277
|
+
const { error } = validation.validate({ id, value });
|
|
40278
|
+
if (error) {
|
|
40279
|
+
next(new import_nodejs_utils59.BadRequestError(error.message));
|
|
40280
|
+
import_nodejs_utils59.logger.info(`Controller: ${error.message}`);
|
|
40281
|
+
return;
|
|
40282
|
+
}
|
|
40283
|
+
try {
|
|
40284
|
+
const result = await _updateById(id, value);
|
|
40285
|
+
res.json(result);
|
|
40286
|
+
return;
|
|
40287
|
+
} catch (error2) {
|
|
40288
|
+
next(error2);
|
|
40289
|
+
}
|
|
40290
|
+
}
|
|
40291
|
+
async function getAll(req, res, next) {
|
|
40292
|
+
const query = req.query;
|
|
40293
|
+
const validation = import_joi35.default.object({
|
|
40294
|
+
page: import_joi35.default.number().min(1).optional().allow("", null),
|
|
40295
|
+
limit: import_joi35.default.number().min(1).optional().allow("", null),
|
|
40296
|
+
search: import_joi35.default.string().optional().allow("", null),
|
|
40297
|
+
school: import_joi35.default.string().hex().optional().allow("", null),
|
|
40298
|
+
status: import_joi35.default.string().optional().allow("", null)
|
|
40299
|
+
});
|
|
40300
|
+
const { error } = validation.validate(query);
|
|
40301
|
+
if (error) {
|
|
40302
|
+
next(new import_nodejs_utils59.BadRequestError(error.message));
|
|
40303
|
+
return;
|
|
40304
|
+
}
|
|
40305
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
40306
|
+
let limit = parseInt(req.query.limit) ?? 20;
|
|
40307
|
+
limit = isNaN(limit) ? 20 : limit;
|
|
40308
|
+
const sort = req.query.sort ? String(req.query.sort).split(",") : "";
|
|
40309
|
+
const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
|
|
40310
|
+
const sortObj = {};
|
|
40311
|
+
if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
|
|
40312
|
+
sort.forEach((field, index) => {
|
|
40313
|
+
sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
|
|
40314
|
+
});
|
|
40315
|
+
}
|
|
40316
|
+
const status = req.query.status ?? "active";
|
|
40317
|
+
const school = req.query.school ?? "";
|
|
40318
|
+
const search = req.query.search ?? "";
|
|
40319
|
+
try {
|
|
40320
|
+
const buildings = await _getAll({
|
|
40321
|
+
page,
|
|
40322
|
+
limit,
|
|
40323
|
+
sort: sortObj,
|
|
40324
|
+
status,
|
|
40325
|
+
school,
|
|
40326
|
+
search
|
|
40327
|
+
});
|
|
40328
|
+
res.json(buildings);
|
|
40329
|
+
return;
|
|
40330
|
+
} catch (error2) {
|
|
40331
|
+
next(error2);
|
|
40332
|
+
}
|
|
40333
|
+
}
|
|
40334
|
+
async function getById(req, res, next) {
|
|
40335
|
+
const id = req.params.id;
|
|
40336
|
+
const validation = import_joi35.default.object({
|
|
40337
|
+
id: import_joi35.default.string().hex().required()
|
|
40338
|
+
});
|
|
40339
|
+
const { error } = validation.validate({ id });
|
|
40340
|
+
if (error) {
|
|
40341
|
+
next(new import_nodejs_utils59.BadRequestError(error.message));
|
|
40342
|
+
return;
|
|
40343
|
+
}
|
|
40344
|
+
try {
|
|
40345
|
+
const building = await _getById(id);
|
|
40346
|
+
res.json({
|
|
40347
|
+
message: "Successfully retrieved building.",
|
|
40348
|
+
data: { building }
|
|
40349
|
+
});
|
|
40350
|
+
return;
|
|
40351
|
+
} catch (error2) {
|
|
40352
|
+
next(error2);
|
|
40353
|
+
}
|
|
40354
|
+
}
|
|
40355
|
+
async function deleteById(req, res, next) {
|
|
40356
|
+
const id = req.params.id;
|
|
40357
|
+
const validation = import_joi35.default.object({
|
|
40358
|
+
id: import_joi35.default.string().hex().required()
|
|
40359
|
+
});
|
|
40360
|
+
const { error } = validation.validate({ id });
|
|
40361
|
+
if (error) {
|
|
40362
|
+
next(new import_nodejs_utils59.BadRequestError(error.message));
|
|
40363
|
+
return;
|
|
40364
|
+
}
|
|
40365
|
+
try {
|
|
40366
|
+
const message = await _deleteById(id);
|
|
40367
|
+
res.json(message);
|
|
40368
|
+
return;
|
|
40369
|
+
} catch (error2) {
|
|
40370
|
+
next(error2);
|
|
40371
|
+
}
|
|
40372
|
+
}
|
|
40373
|
+
return {
|
|
40374
|
+
createBuilding,
|
|
40375
|
+
getAll,
|
|
40376
|
+
getById,
|
|
40377
|
+
updateById,
|
|
40378
|
+
deleteById
|
|
40379
|
+
};
|
|
40380
|
+
}
|
|
40381
|
+
|
|
40382
|
+
// src/resources/building/building-unit.service.ts
|
|
40383
|
+
var import_nodejs_utils60 = require("@eeplatform/nodejs-utils");
|
|
40384
|
+
function useBuildingUnitService() {
|
|
40385
|
+
const { add: _add } = useBuildingUnitRepo();
|
|
40386
|
+
async function add(value) {
|
|
40387
|
+
const session = import_nodejs_utils60.useAtlas.getClient()?.startSession();
|
|
40388
|
+
if (!session) {
|
|
40389
|
+
throw new Error("Unable to start session for building unit service.");
|
|
40390
|
+
}
|
|
40391
|
+
try {
|
|
40392
|
+
await session.startTransaction();
|
|
40393
|
+
for (let index = 0; index < value.qty; index++) {
|
|
40394
|
+
await _add(
|
|
40395
|
+
{ ...value.building, name: `${value.building.name} ${index + 1}` },
|
|
40396
|
+
session
|
|
40397
|
+
);
|
|
40398
|
+
}
|
|
40399
|
+
await session.commitTransaction();
|
|
40400
|
+
return "Building unit added successfully.";
|
|
40401
|
+
} catch (error) {
|
|
40402
|
+
await session.abortTransaction();
|
|
40403
|
+
throw error;
|
|
40404
|
+
} finally {
|
|
40405
|
+
session.endSession();
|
|
40406
|
+
}
|
|
40407
|
+
}
|
|
40408
|
+
return {
|
|
40409
|
+
add
|
|
40410
|
+
};
|
|
40411
|
+
}
|
|
40412
|
+
|
|
40413
|
+
// src/resources/building/building-unit.controller.ts
|
|
40414
|
+
var import_nodejs_utils61 = require("@eeplatform/nodejs-utils");
|
|
40415
|
+
var import_joi36 = __toESM(require("joi"));
|
|
40416
|
+
function useBuildingUnitController() {
|
|
40417
|
+
const {
|
|
40418
|
+
getAll: _getAll,
|
|
40419
|
+
getById: _getById,
|
|
40420
|
+
updateById: _updateById,
|
|
40421
|
+
deleteById: _deleteById
|
|
40422
|
+
} = useBuildingUnitRepo();
|
|
40423
|
+
const { add: _add } = useBuildingUnitService();
|
|
40424
|
+
async function add(req, res, next) {
|
|
40425
|
+
const data = req.body;
|
|
40426
|
+
const validation = import_joi36.default.object({
|
|
40427
|
+
building: import_joi36.default.object({
|
|
40428
|
+
school: import_joi36.default.string().hex().required(),
|
|
40429
|
+
name: import_joi36.default.string().optional().allow("", null),
|
|
40430
|
+
building: import_joi36.default.string().hex().required(),
|
|
40431
|
+
buildingName: import_joi36.default.string().optional().allow("", null),
|
|
40432
|
+
level: import_joi36.default.number().integer().min(1).required(),
|
|
40433
|
+
category: import_joi36.default.string().required(),
|
|
40434
|
+
type: import_joi36.default.string().required(),
|
|
40435
|
+
seating_capacity: import_joi36.default.number().integer().min(0).required(),
|
|
40436
|
+
standing_capacity: import_joi36.default.number().integer().min(0).required(),
|
|
40437
|
+
description: import_joi36.default.string().optional().allow("", null),
|
|
40438
|
+
unit_of_measurement: import_joi36.default.string().valid("sqm").required(),
|
|
40439
|
+
area: import_joi36.default.number().positive().required(),
|
|
40440
|
+
status: import_joi36.default.string().optional().allow("", null)
|
|
40441
|
+
}),
|
|
40442
|
+
qty: import_joi36.default.number().integer().min(1).max(20).optional().default(1)
|
|
40443
|
+
});
|
|
40444
|
+
const { error } = validation.validate(data);
|
|
40445
|
+
if (error) {
|
|
40446
|
+
next(new import_nodejs_utils61.BadRequestError(error.message));
|
|
40447
|
+
return;
|
|
40448
|
+
}
|
|
40449
|
+
try {
|
|
40450
|
+
const buildingUnit = await _add(data);
|
|
40451
|
+
res.json({
|
|
40452
|
+
message: "Building unit added successfully.",
|
|
40453
|
+
data: { buildingUnit }
|
|
40454
|
+
});
|
|
40455
|
+
} catch (error2) {
|
|
40456
|
+
next(error2);
|
|
40457
|
+
}
|
|
40458
|
+
}
|
|
40459
|
+
async function updateById(req, res, next) {
|
|
40460
|
+
const data = req.body;
|
|
40461
|
+
const id = req.params.id ?? "";
|
|
40462
|
+
const validation = import_joi36.default.object({
|
|
40463
|
+
id: import_joi36.default.string().hex().required(),
|
|
40464
|
+
value: schemaUpdateOptions
|
|
40465
|
+
});
|
|
40466
|
+
const { error } = validation.validate({ id, value: data });
|
|
40467
|
+
if (error) {
|
|
40468
|
+
next(new import_nodejs_utils61.BadRequestError(error.message));
|
|
40469
|
+
return;
|
|
40470
|
+
}
|
|
40471
|
+
try {
|
|
40472
|
+
const buildingUnit = await _updateById(id, data);
|
|
40473
|
+
res.json({
|
|
40474
|
+
message: "Building unit updated successfully.",
|
|
40475
|
+
data: { buildingUnit }
|
|
40476
|
+
});
|
|
40477
|
+
} catch (error2) {
|
|
40478
|
+
next(error2);
|
|
40479
|
+
}
|
|
40480
|
+
}
|
|
40481
|
+
async function getAll(req, res, next) {
|
|
40482
|
+
const query = req.query;
|
|
40483
|
+
const validation = import_joi36.default.object({
|
|
40484
|
+
page: import_joi36.default.number().min(1).optional().allow("", null),
|
|
40485
|
+
limit: import_joi36.default.number().min(1).optional().allow("", null),
|
|
40486
|
+
search: import_joi36.default.string().optional().allow("", null),
|
|
40487
|
+
school: import_joi36.default.string().hex().optional().allow("", null),
|
|
40488
|
+
building: import_joi36.default.string().hex().optional().allow("", null),
|
|
40489
|
+
status: import_joi36.default.string().optional().allow("", null)
|
|
40490
|
+
});
|
|
40491
|
+
const { error } = validation.validate(query);
|
|
40492
|
+
if (error) {
|
|
40493
|
+
next(new import_nodejs_utils61.BadRequestError(error.message));
|
|
40494
|
+
return;
|
|
40495
|
+
}
|
|
40496
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
40497
|
+
let limit = parseInt(req.query.limit) ?? 20;
|
|
40498
|
+
limit = isNaN(limit) ? 20 : limit;
|
|
40499
|
+
const sort = req.query.sort ? String(req.query.sort).split(",") : "";
|
|
40500
|
+
const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
|
|
40501
|
+
const sortObj = {};
|
|
40502
|
+
if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
|
|
40503
|
+
sort.forEach((field, index) => {
|
|
40504
|
+
sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
|
|
40505
|
+
});
|
|
40506
|
+
}
|
|
40507
|
+
const status = req.query.status ?? "active";
|
|
40508
|
+
const school = req.query.school ?? "";
|
|
40509
|
+
const building = req.query.building ?? "";
|
|
40510
|
+
const search = req.query.search ?? "";
|
|
40511
|
+
try {
|
|
40512
|
+
const buildings = await _getAll({
|
|
40513
|
+
page,
|
|
40514
|
+
limit,
|
|
40515
|
+
sort: sortObj,
|
|
40516
|
+
status,
|
|
40517
|
+
school,
|
|
40518
|
+
search,
|
|
40519
|
+
building
|
|
40520
|
+
});
|
|
40521
|
+
res.json(buildings);
|
|
40522
|
+
return;
|
|
40523
|
+
} catch (error2) {
|
|
40524
|
+
next(error2);
|
|
40525
|
+
}
|
|
40526
|
+
}
|
|
40527
|
+
async function getById(req, res, next) {
|
|
40528
|
+
const id = req.params.id;
|
|
40529
|
+
const validation = import_joi36.default.object({
|
|
40530
|
+
id: import_joi36.default.string().hex().required()
|
|
40531
|
+
});
|
|
40532
|
+
const { error } = validation.validate({ id });
|
|
40533
|
+
if (error) {
|
|
40534
|
+
next(new import_nodejs_utils61.BadRequestError(error.message));
|
|
40535
|
+
return;
|
|
40536
|
+
}
|
|
40537
|
+
try {
|
|
40538
|
+
const buildingUnit = await _getById(id);
|
|
40539
|
+
res.json({
|
|
40540
|
+
message: "Successfully retrieved building unit.",
|
|
40541
|
+
data: { buildingUnit }
|
|
40542
|
+
});
|
|
40543
|
+
return;
|
|
40544
|
+
} catch (error2) {
|
|
40545
|
+
next(error2);
|
|
40546
|
+
}
|
|
40547
|
+
}
|
|
40548
|
+
async function deleteById(req, res, next) {
|
|
40549
|
+
const id = req.params.id;
|
|
40550
|
+
const validation = import_joi36.default.object({
|
|
40551
|
+
id: import_joi36.default.string().hex().required()
|
|
40552
|
+
});
|
|
40553
|
+
const { error } = validation.validate({ id });
|
|
40554
|
+
if (error) {
|
|
40555
|
+
next(new import_nodejs_utils61.BadRequestError(error.message));
|
|
40556
|
+
return;
|
|
40557
|
+
}
|
|
40558
|
+
try {
|
|
40559
|
+
const message = await _deleteById(id);
|
|
40560
|
+
res.json({ message });
|
|
40561
|
+
return;
|
|
40562
|
+
} catch (error2) {
|
|
40563
|
+
next(error2);
|
|
40564
|
+
}
|
|
40565
|
+
}
|
|
40566
|
+
return {
|
|
40567
|
+
add,
|
|
40568
|
+
getAll,
|
|
40569
|
+
getById,
|
|
40570
|
+
updateById,
|
|
40571
|
+
deleteById
|
|
40572
|
+
};
|
|
40573
|
+
}
|
|
40574
|
+
|
|
40575
|
+
// src/resources/personnel/personnel.model.ts
|
|
40576
|
+
var import_nodejs_utils62 = require("@eeplatform/nodejs-utils");
|
|
40577
|
+
var import_joi37 = __toESM(require("joi"));
|
|
40578
|
+
var import_mongodb34 = require("mongodb");
|
|
40579
|
+
var schemaPersonnel = import_joi37.default.object({
|
|
40580
|
+
_id: import_joi37.default.string().hex().optional().allow("", null),
|
|
40581
|
+
school: import_joi37.default.string().hex().required(),
|
|
40582
|
+
schoolName: import_joi37.default.string().optional().allow("", null),
|
|
40583
|
+
firstName: import_joi37.default.string().required(),
|
|
40584
|
+
lastName: import_joi37.default.string().required(),
|
|
40585
|
+
middleName: import_joi37.default.string().optional().allow("", null),
|
|
40586
|
+
suffix: import_joi37.default.string().optional().allow("", null),
|
|
40587
|
+
title: import_joi37.default.string().optional().allow("", null),
|
|
40588
|
+
classification: import_joi37.default.string().required(),
|
|
40589
|
+
status: import_joi37.default.string().optional().allow("", null),
|
|
40590
|
+
createdAt: import_joi37.default.date().optional().allow("", null),
|
|
40591
|
+
updatedAt: import_joi37.default.date().optional().allow("", null),
|
|
40592
|
+
deletedAt: import_joi37.default.date().optional().allow("", null)
|
|
40593
|
+
});
|
|
40594
|
+
function MPersonnel(value) {
|
|
40595
|
+
const { error } = schemaPersonnel.validate(value);
|
|
40596
|
+
if (error) {
|
|
40597
|
+
import_nodejs_utils62.logger.info(`Personnel Model: ${error.message}`);
|
|
40598
|
+
throw new import_nodejs_utils62.BadRequestError(error.message);
|
|
40599
|
+
}
|
|
40600
|
+
if (value._id && typeof value._id === "string") {
|
|
40601
|
+
try {
|
|
40602
|
+
value._id = new import_mongodb34.ObjectId(value._id);
|
|
40603
|
+
} catch (error2) {
|
|
40604
|
+
throw new import_nodejs_utils62.BadRequestError("Invalid _id format");
|
|
40605
|
+
}
|
|
40606
|
+
}
|
|
40607
|
+
if (value.school && typeof value.school === "string") {
|
|
40608
|
+
try {
|
|
40609
|
+
value.school = new import_mongodb34.ObjectId(value.school);
|
|
40610
|
+
} catch (error2) {
|
|
40611
|
+
throw new import_nodejs_utils62.BadRequestError("Invalid school format");
|
|
40612
|
+
}
|
|
40613
|
+
}
|
|
40614
|
+
if (!value.status) {
|
|
40615
|
+
value.status = "active";
|
|
40616
|
+
}
|
|
40617
|
+
return {
|
|
40618
|
+
_id: value._id,
|
|
40619
|
+
school: value.school,
|
|
40620
|
+
schoolName: value.schoolName ?? "",
|
|
40621
|
+
firstName: value.firstName ?? "",
|
|
40622
|
+
lastName: value.lastName ?? "",
|
|
40623
|
+
middleName: value.middleName ?? "",
|
|
40624
|
+
suffix: value.suffix ?? "",
|
|
40625
|
+
title: value.title ?? "",
|
|
40626
|
+
classification: value.classification ?? "",
|
|
40627
|
+
status: value.status,
|
|
40628
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
40629
|
+
updatedAt: value.updatedAt ?? "",
|
|
40630
|
+
deletedAt: value.deletedAt ?? ""
|
|
40631
|
+
};
|
|
40632
|
+
}
|
|
40633
|
+
|
|
40634
|
+
// src/resources/personnel/personnel.repository.ts
|
|
40635
|
+
var import_nodejs_utils63 = require("@eeplatform/nodejs-utils");
|
|
40636
|
+
var import_mongodb35 = require("mongodb");
|
|
40637
|
+
function usePersonnelRepo() {
|
|
40638
|
+
const db = import_nodejs_utils63.useAtlas.getDb();
|
|
40639
|
+
if (!db) {
|
|
40640
|
+
throw new Error("Unable to connect to server.");
|
|
40641
|
+
}
|
|
40642
|
+
const namespace_collection = "deped.school.personnel";
|
|
40643
|
+
const collection = db.collection(namespace_collection);
|
|
40644
|
+
const { getCache, setCache, delNamespace } = (0, import_nodejs_utils63.useCache)(namespace_collection);
|
|
40645
|
+
async function createIndexes() {
|
|
40646
|
+
try {
|
|
40647
|
+
await collection.createIndexes([
|
|
40648
|
+
{
|
|
40649
|
+
key: {
|
|
40650
|
+
firstName: 1,
|
|
40651
|
+
lastName: 1,
|
|
40652
|
+
classification: 1,
|
|
40653
|
+
status: 1
|
|
40654
|
+
},
|
|
40655
|
+
name: "personnel_search_index"
|
|
40656
|
+
},
|
|
40657
|
+
{ key: { status: 1 } },
|
|
40658
|
+
{ key: { classification: 1 } },
|
|
40659
|
+
{ key: { firstName: "text", lastName: "text", middleName: "text" } }
|
|
40660
|
+
]);
|
|
40661
|
+
} catch (error) {
|
|
40662
|
+
throw new Error("Failed to create index on personnel.");
|
|
40663
|
+
}
|
|
40664
|
+
}
|
|
40665
|
+
async function add(value, session) {
|
|
40666
|
+
try {
|
|
40667
|
+
value = MPersonnel(value);
|
|
40668
|
+
await collection.insertOne(value, { session });
|
|
40669
|
+
delCachedData();
|
|
40670
|
+
return "Successfully added personnel.";
|
|
40671
|
+
} catch (error) {
|
|
40672
|
+
import_nodejs_utils63.logger.log({
|
|
40673
|
+
level: "error",
|
|
40674
|
+
message: error.message
|
|
40675
|
+
});
|
|
40676
|
+
if (error instanceof import_nodejs_utils63.AppError) {
|
|
40677
|
+
throw error;
|
|
40678
|
+
} else {
|
|
40679
|
+
throw new Error("Failed to create personnel.");
|
|
40680
|
+
}
|
|
40681
|
+
}
|
|
40682
|
+
}
|
|
40683
|
+
async function updateById(_id, value, session) {
|
|
40684
|
+
try {
|
|
40685
|
+
_id = new import_mongodb35.ObjectId(_id);
|
|
40686
|
+
} catch (error) {
|
|
40687
|
+
throw new import_nodejs_utils63.BadRequestError("Invalid ID.");
|
|
40688
|
+
}
|
|
40689
|
+
try {
|
|
40690
|
+
const res = await collection.updateOne(
|
|
40691
|
+
{ _id },
|
|
40692
|
+
{ $set: { ...value, updatedAt: /* @__PURE__ */ new Date() } },
|
|
40693
|
+
{ session }
|
|
40694
|
+
);
|
|
40695
|
+
delCachedData();
|
|
40696
|
+
return res;
|
|
40697
|
+
} catch (error) {
|
|
40698
|
+
import_nodejs_utils63.logger.log({
|
|
40699
|
+
level: "error",
|
|
40700
|
+
message: error.message
|
|
40701
|
+
});
|
|
40702
|
+
if (error instanceof import_nodejs_utils63.AppError) {
|
|
40703
|
+
throw error;
|
|
40704
|
+
} else {
|
|
40705
|
+
throw new Error("Failed to update personnel.");
|
|
40706
|
+
}
|
|
40707
|
+
}
|
|
40708
|
+
}
|
|
40709
|
+
async function getAll({
|
|
40710
|
+
school = "",
|
|
40711
|
+
search = "",
|
|
40712
|
+
page = 1,
|
|
40713
|
+
limit = 10,
|
|
40714
|
+
sort = {},
|
|
40715
|
+
status = "active"
|
|
40716
|
+
} = {}) {
|
|
40717
|
+
page = page > 0 ? page - 1 : 0;
|
|
40718
|
+
const query = {
|
|
40719
|
+
status
|
|
40720
|
+
};
|
|
40721
|
+
const cacheParams = {
|
|
40722
|
+
page,
|
|
40723
|
+
limit,
|
|
40724
|
+
sort: JSON.stringify(sort)
|
|
40725
|
+
};
|
|
40726
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
40727
|
+
if (search) {
|
|
40728
|
+
query.$text = { $search: search };
|
|
40729
|
+
cacheParams.search = search;
|
|
40730
|
+
}
|
|
40731
|
+
if (school) {
|
|
40732
|
+
try {
|
|
40733
|
+
query.school = new import_mongodb35.ObjectId(school);
|
|
40734
|
+
} catch (error) {
|
|
40735
|
+
throw new import_nodejs_utils63.BadRequestError("Invalid school ID.");
|
|
40736
|
+
}
|
|
40737
|
+
cacheParams.school = school;
|
|
40738
|
+
}
|
|
40739
|
+
const cacheKey = (0, import_nodejs_utils63.makeCacheKey)(namespace_collection, cacheParams);
|
|
40740
|
+
import_nodejs_utils63.logger.log({
|
|
40741
|
+
level: "info",
|
|
40742
|
+
message: `Cache key for getAll personnel: ${cacheKey}`
|
|
40743
|
+
});
|
|
40744
|
+
try {
|
|
40745
|
+
const cached = await getCache(cacheKey);
|
|
40746
|
+
if (cached) {
|
|
40747
|
+
import_nodejs_utils63.logger.log({
|
|
40748
|
+
level: "info",
|
|
40749
|
+
message: `Cache hit for getAll personnel: ${cacheKey}`
|
|
40750
|
+
});
|
|
40751
|
+
return cached;
|
|
40752
|
+
}
|
|
40753
|
+
const items = await collection.aggregate([
|
|
40754
|
+
{ $match: query },
|
|
40755
|
+
{ $sort: sort },
|
|
40756
|
+
{ $skip: page * limit },
|
|
40757
|
+
{ $limit: limit }
|
|
40758
|
+
]).toArray();
|
|
40759
|
+
const length = await collection.countDocuments(query);
|
|
40760
|
+
const data = (0, import_nodejs_utils63.paginate)(items, page, limit, length);
|
|
40761
|
+
setCache(cacheKey, data, 600).then(() => {
|
|
40762
|
+
import_nodejs_utils63.logger.log({
|
|
40763
|
+
level: "info",
|
|
40764
|
+
message: `Cache set for getAll personnel: ${cacheKey}`
|
|
40765
|
+
});
|
|
40766
|
+
}).catch((err) => {
|
|
40767
|
+
import_nodejs_utils63.logger.log({
|
|
40768
|
+
level: "error",
|
|
40769
|
+
message: `Failed to set cache for getAll personnel: ${err.message}`
|
|
40770
|
+
});
|
|
40771
|
+
});
|
|
40772
|
+
return data;
|
|
40773
|
+
} catch (error) {
|
|
40774
|
+
import_nodejs_utils63.logger.log({ level: "error", message: `${error}` });
|
|
40775
|
+
throw error;
|
|
40776
|
+
}
|
|
40777
|
+
}
|
|
40778
|
+
async function getById(_id) {
|
|
40779
|
+
try {
|
|
40780
|
+
_id = new import_mongodb35.ObjectId(_id);
|
|
40781
|
+
} catch (error) {
|
|
40782
|
+
throw new import_nodejs_utils63.BadRequestError("Invalid ID.");
|
|
40783
|
+
}
|
|
40784
|
+
const cacheKey = (0, import_nodejs_utils63.makeCacheKey)(namespace_collection, { _id: String(_id) });
|
|
40785
|
+
try {
|
|
40786
|
+
const cached = await getCache(cacheKey);
|
|
40787
|
+
if (cached) {
|
|
40788
|
+
import_nodejs_utils63.logger.log({
|
|
40789
|
+
level: "info",
|
|
40790
|
+
message: `Cache hit for getById personnel: ${cacheKey}`
|
|
40791
|
+
});
|
|
40792
|
+
return cached;
|
|
40793
|
+
}
|
|
40794
|
+
const result = await collection.findOne({
|
|
40795
|
+
_id
|
|
40796
|
+
});
|
|
40797
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
40798
|
+
import_nodejs_utils63.logger.log({
|
|
40799
|
+
level: "info",
|
|
40800
|
+
message: `Cache set for personnel by id: ${cacheKey}`
|
|
40801
|
+
});
|
|
40802
|
+
}).catch((err) => {
|
|
40803
|
+
import_nodejs_utils63.logger.log({
|
|
40804
|
+
level: "error",
|
|
40805
|
+
message: `Failed to set cache for personnel by id: ${err.message}`
|
|
40806
|
+
});
|
|
40807
|
+
});
|
|
40808
|
+
return result;
|
|
40809
|
+
} catch (error) {
|
|
40810
|
+
if (error instanceof import_nodejs_utils63.AppError) {
|
|
40811
|
+
throw error;
|
|
40812
|
+
} else {
|
|
40813
|
+
throw new import_nodejs_utils63.InternalServerError("Failed to get personnel.");
|
|
40814
|
+
}
|
|
40815
|
+
}
|
|
40816
|
+
}
|
|
40817
|
+
async function deleteById(_id, session) {
|
|
40818
|
+
try {
|
|
40819
|
+
_id = new import_mongodb35.ObjectId(_id);
|
|
40820
|
+
} catch (error) {
|
|
40821
|
+
throw new import_nodejs_utils63.BadRequestError("Invalid ID.");
|
|
40822
|
+
}
|
|
40823
|
+
try {
|
|
40824
|
+
const res = await collection.updateOne(
|
|
40825
|
+
{ _id },
|
|
40826
|
+
{ $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
|
|
40827
|
+
);
|
|
40828
|
+
delCachedData();
|
|
40829
|
+
return res;
|
|
40830
|
+
} catch (error) {
|
|
40831
|
+
import_nodejs_utils63.logger.log({
|
|
40832
|
+
level: "error",
|
|
40833
|
+
message: error.message
|
|
40834
|
+
});
|
|
40835
|
+
if (error instanceof import_nodejs_utils63.AppError) {
|
|
40836
|
+
throw error;
|
|
40837
|
+
} else {
|
|
40838
|
+
throw new import_nodejs_utils63.InternalServerError("Failed to delete personnel.");
|
|
40839
|
+
}
|
|
40840
|
+
}
|
|
40841
|
+
}
|
|
40842
|
+
async function getByClassification(classification) {
|
|
40843
|
+
const query = {
|
|
40844
|
+
classification,
|
|
40845
|
+
status: "active"
|
|
40846
|
+
};
|
|
40847
|
+
const cacheKey = (0, import_nodejs_utils63.makeCacheKey)(namespace_collection, { classification });
|
|
40848
|
+
try {
|
|
40849
|
+
const cached = await getCache(cacheKey);
|
|
40850
|
+
if (cached) {
|
|
40851
|
+
import_nodejs_utils63.logger.log({
|
|
40852
|
+
level: "info",
|
|
40853
|
+
message: `Cache hit for getByClassification personnel: ${cacheKey}`
|
|
40854
|
+
});
|
|
40855
|
+
return cached;
|
|
40856
|
+
}
|
|
40857
|
+
const result = await collection.find(query).toArray();
|
|
40858
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
40859
|
+
import_nodejs_utils63.logger.log({
|
|
40860
|
+
level: "info",
|
|
40861
|
+
message: `Cache set for personnel by classification: ${cacheKey}`
|
|
40862
|
+
});
|
|
40863
|
+
}).catch((err) => {
|
|
40864
|
+
import_nodejs_utils63.logger.log({
|
|
40865
|
+
level: "error",
|
|
40866
|
+
message: `Failed to set cache for personnel by classification: ${err.message}`
|
|
40867
|
+
});
|
|
40868
|
+
});
|
|
40869
|
+
return result;
|
|
40870
|
+
} catch (error) {
|
|
40871
|
+
if (error instanceof import_nodejs_utils63.AppError) {
|
|
40872
|
+
throw error;
|
|
40873
|
+
} else {
|
|
40874
|
+
throw new import_nodejs_utils63.InternalServerError(
|
|
40875
|
+
"Failed to get personnel by classification."
|
|
40876
|
+
);
|
|
40877
|
+
}
|
|
40878
|
+
}
|
|
40879
|
+
}
|
|
40880
|
+
function delCachedData() {
|
|
40881
|
+
delNamespace().then(() => {
|
|
40882
|
+
import_nodejs_utils63.logger.log({
|
|
40883
|
+
level: "info",
|
|
40884
|
+
message: `Cache cleared for namespace: ${namespace_collection}`
|
|
40885
|
+
});
|
|
40886
|
+
}).catch((err) => {
|
|
40887
|
+
import_nodejs_utils63.logger.log({
|
|
40888
|
+
level: "error",
|
|
40889
|
+
message: `Failed to clear cache for namespace: ${namespace_collection}: ${err.message}`
|
|
40890
|
+
});
|
|
40891
|
+
});
|
|
40892
|
+
}
|
|
40893
|
+
return {
|
|
40894
|
+
createIndexes,
|
|
40895
|
+
add,
|
|
40896
|
+
updateById,
|
|
40897
|
+
getAll,
|
|
40898
|
+
getById,
|
|
40899
|
+
deleteById,
|
|
40900
|
+
getByClassification,
|
|
40901
|
+
delCachedData
|
|
40902
|
+
};
|
|
40903
|
+
}
|
|
40904
|
+
|
|
40905
|
+
// src/resources/personnel/personnel.controller.ts
|
|
40906
|
+
var import_nodejs_utils64 = require("@eeplatform/nodejs-utils");
|
|
40907
|
+
var import_joi38 = __toESM(require("joi"));
|
|
40908
|
+
function usePersonnelController() {
|
|
40909
|
+
const {
|
|
40910
|
+
getAll: _getAll,
|
|
40911
|
+
getById: _getById,
|
|
40912
|
+
add: _add,
|
|
40913
|
+
updateById: _updateById,
|
|
40914
|
+
deleteById: _deleteById,
|
|
40915
|
+
getByClassification: _getByClassification
|
|
40916
|
+
} = usePersonnelRepo();
|
|
40917
|
+
async function add(req, res, next) {
|
|
40918
|
+
const value = req.body;
|
|
40919
|
+
const { error } = schemaPersonnel.validate(value);
|
|
40920
|
+
if (error) {
|
|
40921
|
+
next(new import_nodejs_utils64.BadRequestError(error.message));
|
|
40922
|
+
import_nodejs_utils64.logger.info(`Controller: ${error.message}`);
|
|
40923
|
+
return;
|
|
40924
|
+
}
|
|
40925
|
+
try {
|
|
40926
|
+
const result = await _add(value);
|
|
40927
|
+
res.json(result);
|
|
40928
|
+
return;
|
|
40929
|
+
} catch (error2) {
|
|
40930
|
+
next(error2);
|
|
40931
|
+
}
|
|
40932
|
+
}
|
|
40933
|
+
async function updateById(req, res, next) {
|
|
40934
|
+
const value = req.body;
|
|
40935
|
+
const id = req.params.id ?? "";
|
|
40936
|
+
const validation = import_joi38.default.object({
|
|
40937
|
+
id: import_joi38.default.string().hex().required(),
|
|
40938
|
+
value: import_joi38.default.object({
|
|
40939
|
+
firstName: import_joi38.default.string().optional(),
|
|
40940
|
+
lastName: import_joi38.default.string().optional(),
|
|
40941
|
+
middleName: import_joi38.default.string().optional().allow("", null),
|
|
40942
|
+
classification: import_joi38.default.string().optional(),
|
|
40943
|
+
status: import_joi38.default.string().optional()
|
|
40944
|
+
}).min(1)
|
|
40945
|
+
});
|
|
40946
|
+
const { error } = validation.validate({ id, value });
|
|
40947
|
+
if (error) {
|
|
40948
|
+
next(new import_nodejs_utils64.BadRequestError(error.message));
|
|
40949
|
+
import_nodejs_utils64.logger.info(`Controller: ${error.message}`);
|
|
40950
|
+
return;
|
|
40951
|
+
}
|
|
40952
|
+
try {
|
|
40953
|
+
const result = await _updateById(id, value);
|
|
40954
|
+
res.json(result);
|
|
40955
|
+
return;
|
|
40956
|
+
} catch (error2) {
|
|
40957
|
+
next(error2);
|
|
40958
|
+
}
|
|
40959
|
+
}
|
|
40960
|
+
async function getAll(req, res, next) {
|
|
40961
|
+
const query = req.query;
|
|
40962
|
+
const validation = import_joi38.default.object({
|
|
40963
|
+
page: import_joi38.default.number().min(1).optional().allow("", null),
|
|
40964
|
+
limit: import_joi38.default.number().min(1).optional().allow("", null),
|
|
40965
|
+
search: import_joi38.default.string().optional().allow("", null),
|
|
40966
|
+
status: import_joi38.default.string().optional().allow("", null),
|
|
40967
|
+
classification: import_joi38.default.string().optional().allow("", null)
|
|
40968
|
+
});
|
|
40969
|
+
const { error } = validation.validate(query);
|
|
40970
|
+
if (error) {
|
|
40971
|
+
next(new import_nodejs_utils64.BadRequestError(error.message));
|
|
40972
|
+
return;
|
|
40973
|
+
}
|
|
40974
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
40975
|
+
let limit = parseInt(req.query.limit) ?? 20;
|
|
40976
|
+
limit = isNaN(limit) ? 20 : limit;
|
|
40977
|
+
const sort = req.query.sort ? String(req.query.sort).split(",") : "";
|
|
40978
|
+
const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
|
|
40979
|
+
const sortObj = {};
|
|
40980
|
+
if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
|
|
40981
|
+
sort.forEach((field, index) => {
|
|
40982
|
+
sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
|
|
40983
|
+
});
|
|
40984
|
+
}
|
|
40985
|
+
const status = req.query.status ?? "active";
|
|
40986
|
+
const search = req.query.search ?? "";
|
|
40987
|
+
try {
|
|
40988
|
+
const personnel = await _getAll({
|
|
40989
|
+
page,
|
|
40990
|
+
limit,
|
|
40991
|
+
sort: sortObj,
|
|
40992
|
+
status,
|
|
40993
|
+
search
|
|
40994
|
+
});
|
|
40995
|
+
res.json(personnel);
|
|
40996
|
+
return;
|
|
40997
|
+
} catch (error2) {
|
|
40998
|
+
next(error2);
|
|
40999
|
+
}
|
|
41000
|
+
}
|
|
41001
|
+
async function getAllBySchool(req, res, next) {
|
|
41002
|
+
const school = req.params.school;
|
|
41003
|
+
const schoolValidation = import_joi38.default.string().hex().required();
|
|
41004
|
+
const { error: schoolError } = schoolValidation.validate(school);
|
|
41005
|
+
if (schoolError) {
|
|
41006
|
+
next(new import_nodejs_utils64.BadRequestError(schoolError.message));
|
|
41007
|
+
return;
|
|
41008
|
+
}
|
|
41009
|
+
const query = req.query;
|
|
41010
|
+
const validation = import_joi38.default.object({
|
|
41011
|
+
page: import_joi38.default.number().min(1).optional().allow("", null),
|
|
41012
|
+
limit: import_joi38.default.number().min(1).optional().allow("", null),
|
|
41013
|
+
search: import_joi38.default.string().optional().allow("", null),
|
|
41014
|
+
status: import_joi38.default.string().optional().allow("", null),
|
|
41015
|
+
classification: import_joi38.default.string().optional().allow("", null)
|
|
41016
|
+
});
|
|
41017
|
+
const { error } = validation.validate(query);
|
|
41018
|
+
if (error) {
|
|
41019
|
+
next(new import_nodejs_utils64.BadRequestError(error.message));
|
|
41020
|
+
return;
|
|
41021
|
+
}
|
|
41022
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
41023
|
+
let limit = parseInt(req.query.limit) ?? 20;
|
|
41024
|
+
limit = isNaN(limit) ? 20 : limit;
|
|
41025
|
+
const sort = req.query.sort ? String(req.query.sort).split(",") : "";
|
|
41026
|
+
const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
|
|
41027
|
+
const sortObj = {};
|
|
41028
|
+
if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
|
|
41029
|
+
sort.forEach((field, index) => {
|
|
41030
|
+
sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
|
|
41031
|
+
});
|
|
41032
|
+
}
|
|
41033
|
+
const status = req.query.status ?? "active";
|
|
41034
|
+
const search = req.query.search ?? "";
|
|
41035
|
+
try {
|
|
41036
|
+
const personnel = await _getAll({
|
|
41037
|
+
school,
|
|
41038
|
+
page,
|
|
41039
|
+
limit,
|
|
41040
|
+
sort: sortObj,
|
|
41041
|
+
status,
|
|
41042
|
+
search
|
|
41043
|
+
});
|
|
41044
|
+
res.json(personnel);
|
|
41045
|
+
return;
|
|
41046
|
+
} catch (error2) {
|
|
41047
|
+
next(error2);
|
|
41048
|
+
}
|
|
41049
|
+
}
|
|
41050
|
+
async function getById(req, res, next) {
|
|
41051
|
+
const id = req.params.id;
|
|
41052
|
+
const validation = import_joi38.default.object({
|
|
41053
|
+
id: import_joi38.default.string().hex().required()
|
|
41054
|
+
});
|
|
41055
|
+
const { error } = validation.validate({ id });
|
|
41056
|
+
if (error) {
|
|
41057
|
+
next(new import_nodejs_utils64.BadRequestError(error.message));
|
|
41058
|
+
return;
|
|
41059
|
+
}
|
|
41060
|
+
try {
|
|
41061
|
+
const personnel = await _getById(id);
|
|
41062
|
+
res.json({
|
|
41063
|
+
message: "Successfully retrieved personnel.",
|
|
41064
|
+
data: personnel
|
|
41065
|
+
});
|
|
41066
|
+
return;
|
|
41067
|
+
} catch (error2) {
|
|
41068
|
+
next(error2);
|
|
41069
|
+
}
|
|
41070
|
+
}
|
|
41071
|
+
async function deleteById(req, res, next) {
|
|
41072
|
+
const id = req.params.id;
|
|
41073
|
+
const validation = import_joi38.default.object({
|
|
41074
|
+
id: import_joi38.default.string().hex().required()
|
|
41075
|
+
});
|
|
41076
|
+
const { error } = validation.validate({ id });
|
|
41077
|
+
if (error) {
|
|
41078
|
+
next(new import_nodejs_utils64.BadRequestError(error.message));
|
|
41079
|
+
return;
|
|
41080
|
+
}
|
|
41081
|
+
try {
|
|
41082
|
+
const result = await _deleteById(id);
|
|
41083
|
+
res.json({
|
|
41084
|
+
message: "Successfully deleted personnel.",
|
|
41085
|
+
data: result
|
|
41086
|
+
});
|
|
41087
|
+
return;
|
|
41088
|
+
} catch (error2) {
|
|
41089
|
+
next(error2);
|
|
41090
|
+
}
|
|
41091
|
+
}
|
|
41092
|
+
async function getByClassification(req, res, next) {
|
|
41093
|
+
const classification = req.params.classification;
|
|
41094
|
+
const validation = import_joi38.default.object({
|
|
41095
|
+
classification: import_joi38.default.string().required()
|
|
41096
|
+
});
|
|
41097
|
+
const { error } = validation.validate({ classification });
|
|
41098
|
+
if (error) {
|
|
41099
|
+
next(new import_nodejs_utils64.BadRequestError(error.message));
|
|
41100
|
+
return;
|
|
41101
|
+
}
|
|
41102
|
+
try {
|
|
41103
|
+
const personnel = await _getByClassification(classification);
|
|
41104
|
+
res.json({
|
|
41105
|
+
message: "Successfully retrieved personnel by classification.",
|
|
41106
|
+
data: personnel
|
|
41107
|
+
});
|
|
41108
|
+
return;
|
|
41109
|
+
} catch (error2) {
|
|
41110
|
+
next(error2);
|
|
41111
|
+
}
|
|
41112
|
+
}
|
|
41113
|
+
return {
|
|
41114
|
+
add,
|
|
41115
|
+
updateById,
|
|
41116
|
+
getAll,
|
|
41117
|
+
getAllBySchool,
|
|
41118
|
+
getById,
|
|
41119
|
+
deleteById,
|
|
41120
|
+
getByClassification
|
|
41121
|
+
};
|
|
41122
|
+
}
|
|
41123
|
+
|
|
38354
41124
|
// src/config.ts
|
|
38355
41125
|
var dotenv = __toESM(require("dotenv"));
|
|
38356
41126
|
dotenv.config();
|
|
38357
41127
|
// Annotate the CommonJS export names for ESM import in node:
|
|
38358
41128
|
0 && (module.exports = {
|
|
38359
41129
|
MAsset,
|
|
41130
|
+
MBuilding,
|
|
41131
|
+
MBuildingUnit,
|
|
38360
41132
|
MCurriculum,
|
|
38361
41133
|
MCurriculumSubject,
|
|
38362
41134
|
MGradeLevel,
|
|
38363
41135
|
MLearner,
|
|
41136
|
+
MPersonnel,
|
|
38364
41137
|
MPlantilla,
|
|
38365
41138
|
MStockCard,
|
|
38366
41139
|
allowedSectionStudentStatuses,
|
|
@@ -38371,9 +41144,12 @@ dotenv.config();
|
|
|
38371
41144
|
modelSection,
|
|
38372
41145
|
modelSectionPreset,
|
|
38373
41146
|
modelSectionStudent,
|
|
41147
|
+
modelSectionSubject,
|
|
38374
41148
|
schemaAsset,
|
|
38375
41149
|
schemaAssetUpdateOption,
|
|
38376
41150
|
schemaBasicEduCount,
|
|
41151
|
+
schemaBuilding,
|
|
41152
|
+
schemaBuildingUnit,
|
|
38377
41153
|
schemaCurriculum,
|
|
38378
41154
|
schemaCurriculumSubject,
|
|
38379
41155
|
schemaCurriculumSubjectAdd,
|
|
@@ -38382,6 +41158,7 @@ dotenv.config();
|
|
|
38382
41158
|
schemaEnrollment,
|
|
38383
41159
|
schemaGenerateSections,
|
|
38384
41160
|
schemaGradeLevel,
|
|
41161
|
+
schemaPersonnel,
|
|
38385
41162
|
schemaPlantilla,
|
|
38386
41163
|
schemaRegion,
|
|
38387
41164
|
schemaSchool,
|
|
@@ -38389,11 +41166,20 @@ dotenv.config();
|
|
|
38389
41166
|
schemaSection,
|
|
38390
41167
|
schemaSectionPreset,
|
|
38391
41168
|
schemaSectionStudent,
|
|
41169
|
+
schemaSectionSubject,
|
|
41170
|
+
schemaSectionSubjectSetup,
|
|
38392
41171
|
schemaStockCard,
|
|
41172
|
+
schemaUpdateOptions,
|
|
38393
41173
|
schemaUpdateStatus,
|
|
38394
41174
|
useAssetController,
|
|
38395
41175
|
useAssetRepo,
|
|
38396
41176
|
useBasicEduCountRepo,
|
|
41177
|
+
useBuildingController,
|
|
41178
|
+
useBuildingRepo,
|
|
41179
|
+
useBuildingService,
|
|
41180
|
+
useBuildingUnitController,
|
|
41181
|
+
useBuildingUnitRepo,
|
|
41182
|
+
useBuildingUnitService,
|
|
38397
41183
|
useCurriculumController,
|
|
38398
41184
|
useCurriculumRepo,
|
|
38399
41185
|
useCurriculumSubjectController,
|
|
@@ -38409,6 +41195,8 @@ dotenv.config();
|
|
|
38409
41195
|
useGradeLevelRepo,
|
|
38410
41196
|
useLearnerController,
|
|
38411
41197
|
useLearnerRepo,
|
|
41198
|
+
usePersonnelController,
|
|
41199
|
+
usePersonnelRepo,
|
|
38412
41200
|
usePlantillaController,
|
|
38413
41201
|
usePlantillaRepo,
|
|
38414
41202
|
usePlantillaService,
|
|
@@ -38421,7 +41209,11 @@ dotenv.config();
|
|
|
38421
41209
|
useSectionPresetController,
|
|
38422
41210
|
useSectionPresetRepo,
|
|
38423
41211
|
useSectionRepo,
|
|
41212
|
+
useSectionStudentController,
|
|
38424
41213
|
useSectionStudentRepo,
|
|
41214
|
+
useSectionSubjectController,
|
|
41215
|
+
useSectionSubjectRepo,
|
|
41216
|
+
useSectionSubjectService,
|
|
38425
41217
|
useStockCardController,
|
|
38426
41218
|
useStockCardRepository,
|
|
38427
41219
|
useStockCardService
|