@eeplatform/core 1.8.8 → 1.8.9
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 +6 -0
- package/dist/index.d.ts +198 -42
- package/dist/index.js +2531 -662
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2557 -676
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -75,26 +75,25 @@ function useUserRepo() {
|
|
|
75
75
|
});
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
-
async function
|
|
79
|
-
try {
|
|
80
|
-
await collection.createIndex({
|
|
81
|
-
firstName: "text",
|
|
82
|
-
middleName: "text",
|
|
83
|
-
lastName: "text",
|
|
84
|
-
email: "text"
|
|
85
|
-
});
|
|
86
|
-
} catch (error) {
|
|
87
|
-
throw new Error("Failed to create text index on email.");
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
async function createUniqueIndex() {
|
|
78
|
+
async function createIndexes() {
|
|
91
79
|
try {
|
|
92
|
-
await collection.
|
|
93
|
-
{
|
|
94
|
-
|
|
95
|
-
|
|
80
|
+
await collection.createIndexes([
|
|
81
|
+
{
|
|
82
|
+
key: {
|
|
83
|
+
firstName: "text",
|
|
84
|
+
middleName: "text",
|
|
85
|
+
lastName: "text",
|
|
86
|
+
email: "text"
|
|
87
|
+
},
|
|
88
|
+
name: "search_index"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
key: { email: 1, deletedAt: 1 },
|
|
92
|
+
unique: true
|
|
93
|
+
}
|
|
94
|
+
]);
|
|
96
95
|
} catch (error) {
|
|
97
|
-
throw new Error("Failed to create
|
|
96
|
+
throw new Error("Failed to create user indexes.");
|
|
98
97
|
}
|
|
99
98
|
}
|
|
100
99
|
async function createUser(value, session) {
|
|
@@ -391,8 +390,7 @@ function useUserRepo() {
|
|
|
391
390
|
}
|
|
392
391
|
}
|
|
393
392
|
return {
|
|
394
|
-
|
|
395
|
-
createUniqueIndex,
|
|
393
|
+
createIndexes,
|
|
396
394
|
createUser,
|
|
397
395
|
getUserByEmail,
|
|
398
396
|
getUserById,
|
|
@@ -1182,46 +1180,33 @@ function useMemberRepo() {
|
|
|
1182
1180
|
});
|
|
1183
1181
|
});
|
|
1184
1182
|
}
|
|
1185
|
-
async function
|
|
1186
|
-
try {
|
|
1187
|
-
await collection.createIndex([
|
|
1188
|
-
{
|
|
1189
|
-
name: 1
|
|
1190
|
-
},
|
|
1191
|
-
{
|
|
1192
|
-
status: 1
|
|
1193
|
-
}
|
|
1194
|
-
]);
|
|
1195
|
-
} catch (error) {
|
|
1196
|
-
throw new Error("Failed to create index.");
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
async function createUniqueIndex() {
|
|
1183
|
+
async function createIndexes() {
|
|
1200
1184
|
try {
|
|
1201
|
-
await collection.
|
|
1185
|
+
await collection.createIndexes([
|
|
1202
1186
|
{
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1187
|
+
key: {
|
|
1188
|
+
name: 1,
|
|
1189
|
+
status: 1
|
|
1190
|
+
}
|
|
1206
1191
|
},
|
|
1207
|
-
{ partialFilterExpression: { deletedAt: "" }, unique: true }
|
|
1208
|
-
);
|
|
1209
|
-
} catch (error) {
|
|
1210
|
-
throw new Error("Failed to create unique index.");
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
async function createTextIndex() {
|
|
1214
|
-
try {
|
|
1215
|
-
await collection.createIndex([
|
|
1216
1192
|
{
|
|
1217
|
-
|
|
1193
|
+
key: {
|
|
1194
|
+
org: 1,
|
|
1195
|
+
user: 1,
|
|
1196
|
+
type: 1
|
|
1197
|
+
},
|
|
1198
|
+
partialFilterExpression: { deletedAt: "" },
|
|
1199
|
+
unique: true
|
|
1218
1200
|
},
|
|
1219
1201
|
{
|
|
1220
|
-
|
|
1202
|
+
key: {
|
|
1203
|
+
name: "text",
|
|
1204
|
+
orgName: "text"
|
|
1205
|
+
},
|
|
1206
|
+
name: "search_index"
|
|
1221
1207
|
}
|
|
1222
1208
|
]);
|
|
1223
1209
|
} catch (error) {
|
|
1224
|
-
throw new Error("Failed to create text index.");
|
|
1225
1210
|
}
|
|
1226
1211
|
}
|
|
1227
1212
|
async function add(value, session) {
|
|
@@ -1759,9 +1744,7 @@ function useMemberRepo() {
|
|
|
1759
1744
|
}
|
|
1760
1745
|
}
|
|
1761
1746
|
return {
|
|
1762
|
-
|
|
1763
|
-
createUniqueIndex,
|
|
1764
|
-
createTextIndex,
|
|
1747
|
+
createIndexes,
|
|
1765
1748
|
add,
|
|
1766
1749
|
getById,
|
|
1767
1750
|
getByOrg,
|
|
@@ -2184,21 +2167,22 @@ function useRoleRepo() {
|
|
|
2184
2167
|
});
|
|
2185
2168
|
});
|
|
2186
2169
|
}
|
|
2187
|
-
async function
|
|
2188
|
-
try {
|
|
2189
|
-
await collection.createIndex({ name: 1 });
|
|
2190
|
-
await collection.createIndex({ type: 1 });
|
|
2191
|
-
await collection.createIndex({ status: 1 });
|
|
2192
|
-
await collection.createIndex({ id: 1 });
|
|
2193
|
-
} catch (error) {
|
|
2194
|
-
throw new InternalServerError8("Failed to create index on role.");
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2197
|
-
async function createTextIndex() {
|
|
2170
|
+
async function createIndexes() {
|
|
2198
2171
|
try {
|
|
2199
|
-
await collection.
|
|
2172
|
+
await collection.createIndexes([
|
|
2173
|
+
{
|
|
2174
|
+
key: {
|
|
2175
|
+
name: "text"
|
|
2176
|
+
},
|
|
2177
|
+
name: "text_index"
|
|
2178
|
+
},
|
|
2179
|
+
{
|
|
2180
|
+
key: { name: 1, type: 1, status: 1, id: 1 },
|
|
2181
|
+
unique: true
|
|
2182
|
+
}
|
|
2183
|
+
]);
|
|
2200
2184
|
} catch (error) {
|
|
2201
|
-
throw new InternalServerError8("Failed to create
|
|
2185
|
+
throw new InternalServerError8("Failed to create role indexes.");
|
|
2202
2186
|
}
|
|
2203
2187
|
}
|
|
2204
2188
|
async function createUniqueIndex() {
|
|
@@ -2481,8 +2465,7 @@ function useRoleRepo() {
|
|
|
2481
2465
|
}
|
|
2482
2466
|
}
|
|
2483
2467
|
return {
|
|
2484
|
-
|
|
2485
|
-
createTextIndex,
|
|
2468
|
+
createIndexes,
|
|
2486
2469
|
createUniqueIndex,
|
|
2487
2470
|
addRole,
|
|
2488
2471
|
getRoles,
|
|
@@ -3711,140 +3694,2166 @@ function useOrgController() {
|
|
|
3711
3694
|
};
|
|
3712
3695
|
}
|
|
3713
3696
|
|
|
3714
|
-
// src/resources/
|
|
3715
|
-
import
|
|
3716
|
-
import
|
|
3697
|
+
// src/resources/app/app.model.ts
|
|
3698
|
+
import { BadRequestError as BadRequestError16 } from "@eeplatform/nodejs-utils";
|
|
3699
|
+
import Joi6 from "joi";
|
|
3700
|
+
var schemaApp = Joi6.object({
|
|
3701
|
+
code: Joi6.string().alphanum().max(20).required(),
|
|
3702
|
+
name: Joi6.string().max(255).required(),
|
|
3703
|
+
description: Joi6.string().max(1024).optional().allow("", null),
|
|
3704
|
+
type: Joi6.string().allow("default", "standard").optional().allow("", null)
|
|
3705
|
+
});
|
|
3706
|
+
var schemaAppUpdate = Joi6.object({
|
|
3707
|
+
code: Joi6.string().alphanum().max(20).optional().allow("", null),
|
|
3708
|
+
name: Joi6.string().max(255).optional().allow("", null),
|
|
3709
|
+
description: Joi6.string().max(1024).optional().allow("", null)
|
|
3710
|
+
});
|
|
3711
|
+
function modelApp(value) {
|
|
3712
|
+
const { error } = schemaApp.validate(value);
|
|
3713
|
+
if (error) {
|
|
3714
|
+
throw new BadRequestError16(error.message);
|
|
3715
|
+
}
|
|
3716
|
+
return {
|
|
3717
|
+
_id: value._id,
|
|
3718
|
+
code: value.code,
|
|
3719
|
+
name: value.name,
|
|
3720
|
+
description: value.description,
|
|
3721
|
+
type: value.type ?? "standard",
|
|
3722
|
+
status: value.status ?? "active",
|
|
3723
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
3724
|
+
updatedAt: "",
|
|
3725
|
+
deletedAt: ""
|
|
3726
|
+
};
|
|
3727
|
+
}
|
|
3717
3728
|
|
|
3718
|
-
// src/resources/
|
|
3729
|
+
// src/resources/app/app.repository.ts
|
|
3719
3730
|
import {
|
|
3720
3731
|
AppError as AppError6,
|
|
3721
3732
|
BadRequestError as BadRequestError17,
|
|
3722
|
-
InternalServerError as InternalServerError13
|
|
3733
|
+
InternalServerError as InternalServerError13,
|
|
3734
|
+
logger as logger11,
|
|
3735
|
+
makeCacheKey as makeCacheKey9,
|
|
3736
|
+
paginate as paginate6,
|
|
3737
|
+
useRepo
|
|
3723
3738
|
} from "@eeplatform/nodejs-utils";
|
|
3739
|
+
import { ObjectId as ObjectId14 } from "mongodb";
|
|
3724
3740
|
import Joi7 from "joi";
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3741
|
+
function useAppRepo() {
|
|
3742
|
+
const namespace_collection = "apps";
|
|
3743
|
+
const repo = useRepo(namespace_collection);
|
|
3744
|
+
async function createIndexes() {
|
|
3745
|
+
try {
|
|
3746
|
+
await repo.collection.createIndexes([
|
|
3747
|
+
{ key: { code: 1 } },
|
|
3748
|
+
{ key: { status: 1 } },
|
|
3749
|
+
{
|
|
3750
|
+
key: { code: "text", name: "text", description: "text" },
|
|
3751
|
+
name: "text_index"
|
|
3752
|
+
},
|
|
3753
|
+
{
|
|
3754
|
+
key: { code: 1, status: 1 },
|
|
3755
|
+
unique: true,
|
|
3756
|
+
name: "unique_code",
|
|
3757
|
+
partialFilterExpression: { status: { $in: ["active", "draft"] } }
|
|
3758
|
+
},
|
|
3759
|
+
{
|
|
3760
|
+
key: { name: 1, status: 1 },
|
|
3761
|
+
unique: true,
|
|
3762
|
+
name: "unique_name",
|
|
3763
|
+
partialFilterExpression: { status: { $in: ["active", "draft"] } }
|
|
3764
|
+
}
|
|
3765
|
+
]);
|
|
3766
|
+
} catch (error) {
|
|
3767
|
+
throw new Error("Failed to create index on apps.");
|
|
3746
3768
|
}
|
|
3769
|
+
}
|
|
3770
|
+
async function add(value, session) {
|
|
3747
3771
|
try {
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3772
|
+
value = modelApp(value);
|
|
3773
|
+
const res = await repo.collection.insertOne(value, { session });
|
|
3774
|
+
repo.delCachedData();
|
|
3775
|
+
return res.insertedId;
|
|
3776
|
+
} catch (error) {
|
|
3777
|
+
logger11.log({
|
|
3778
|
+
level: "error",
|
|
3779
|
+
message: error.message
|
|
3780
|
+
});
|
|
3781
|
+
if (error instanceof AppError6) {
|
|
3782
|
+
throw error;
|
|
3783
|
+
} else {
|
|
3784
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
3785
|
+
if (isDuplicated) {
|
|
3786
|
+
throw new BadRequestError17("App already exists.");
|
|
3787
|
+
}
|
|
3788
|
+
throw new Error("Failed to create app.");
|
|
3752
3789
|
}
|
|
3753
|
-
res.json(member);
|
|
3754
|
-
} catch (error2) {
|
|
3755
|
-
next(error2);
|
|
3756
3790
|
}
|
|
3757
3791
|
}
|
|
3758
|
-
async function
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
});
|
|
3764
|
-
const { error } = validation.validate({ ...req.params, ...req.query });
|
|
3765
|
-
if (error) {
|
|
3766
|
-
next(new BadRequestError16(error.message));
|
|
3767
|
-
return;
|
|
3792
|
+
async function updateById(_id, value, session) {
|
|
3793
|
+
try {
|
|
3794
|
+
_id = new ObjectId14(_id);
|
|
3795
|
+
} catch (error) {
|
|
3796
|
+
throw new BadRequestError17("Invalid ID.");
|
|
3768
3797
|
}
|
|
3769
|
-
const orgId = req.query.org;
|
|
3770
|
-
const userId = req.params.user;
|
|
3771
|
-
const type = req.params.type;
|
|
3772
3798
|
try {
|
|
3773
|
-
const
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3799
|
+
const res = await repo.collection.updateOne(
|
|
3800
|
+
{ _id },
|
|
3801
|
+
{ $set: value },
|
|
3802
|
+
{ session }
|
|
3803
|
+
);
|
|
3804
|
+
repo.delCachedData();
|
|
3805
|
+
return res;
|
|
3806
|
+
} catch (error) {
|
|
3807
|
+
logger11.log({
|
|
3808
|
+
level: "error",
|
|
3809
|
+
message: error.message
|
|
3810
|
+
});
|
|
3811
|
+
if (error instanceof AppError6) {
|
|
3812
|
+
throw error;
|
|
3813
|
+
} else {
|
|
3814
|
+
throw new Error("Failed to update app.");
|
|
3777
3815
|
}
|
|
3778
|
-
res.json(member);
|
|
3779
|
-
} catch (error2) {
|
|
3780
|
-
next(error2);
|
|
3781
3816
|
}
|
|
3782
3817
|
}
|
|
3783
|
-
async function getAll(
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
status: Joi6.string().required()
|
|
3799
|
-
});
|
|
3800
|
-
const { error } = validation.validate({
|
|
3801
|
-
search,
|
|
3818
|
+
async function getAll({
|
|
3819
|
+
search = "",
|
|
3820
|
+
page = 1,
|
|
3821
|
+
limit = 10,
|
|
3822
|
+
sort = {},
|
|
3823
|
+
status = "active",
|
|
3824
|
+
type = "standard"
|
|
3825
|
+
} = {}) {
|
|
3826
|
+
page = page > 0 ? page - 1 : 0;
|
|
3827
|
+
const query = {
|
|
3828
|
+
status
|
|
3829
|
+
};
|
|
3830
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
3831
|
+
const cacheParams = {
|
|
3832
|
+
status,
|
|
3802
3833
|
page,
|
|
3803
|
-
user,
|
|
3804
|
-
org,
|
|
3805
|
-
type,
|
|
3806
3834
|
limit,
|
|
3807
|
-
|
|
3808
|
-
}
|
|
3809
|
-
if (
|
|
3810
|
-
|
|
3811
|
-
|
|
3835
|
+
sort: JSON.stringify(sort)
|
|
3836
|
+
};
|
|
3837
|
+
if (search) {
|
|
3838
|
+
query.$text = { $search: search };
|
|
3839
|
+
cacheParams.search = search;
|
|
3840
|
+
}
|
|
3841
|
+
if (type) {
|
|
3842
|
+
if (Array.isArray(type)) {
|
|
3843
|
+
query.type = { $in: type };
|
|
3844
|
+
} else {
|
|
3845
|
+
query.type = type;
|
|
3846
|
+
}
|
|
3847
|
+
cacheParams.type = type;
|
|
3812
3848
|
}
|
|
3849
|
+
const cacheKey = makeCacheKey9(namespace_collection, cacheParams);
|
|
3850
|
+
logger11.log({
|
|
3851
|
+
level: "info",
|
|
3852
|
+
message: `Cache key for getAll apps: ${cacheKey}`
|
|
3853
|
+
});
|
|
3813
3854
|
try {
|
|
3814
|
-
const
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3855
|
+
const cached = await repo.getCache(cacheKey);
|
|
3856
|
+
if (cached) {
|
|
3857
|
+
logger11.log({
|
|
3858
|
+
level: "info",
|
|
3859
|
+
message: `Cache hit for getAll apps: ${cacheKey}`
|
|
3860
|
+
});
|
|
3861
|
+
return cached;
|
|
3862
|
+
}
|
|
3863
|
+
const items = await repo.collection.aggregate([
|
|
3864
|
+
{ $match: query },
|
|
3865
|
+
{ $sort: sort },
|
|
3866
|
+
{ $skip: page * limit },
|
|
3867
|
+
{ $limit: limit }
|
|
3868
|
+
]).toArray();
|
|
3869
|
+
const length = await repo.collection.countDocuments(query);
|
|
3870
|
+
const data = paginate6(items, page, limit, length);
|
|
3871
|
+
repo.setCache(cacheKey, data, 600).then(() => {
|
|
3872
|
+
logger11.log({
|
|
3873
|
+
level: "info",
|
|
3874
|
+
message: `Cache set for getAll apps: ${cacheKey}`
|
|
3875
|
+
});
|
|
3876
|
+
}).catch((err) => {
|
|
3877
|
+
logger11.log({
|
|
3878
|
+
level: "error",
|
|
3879
|
+
message: `Failed to set cache for getAll apps: ${err.message}`
|
|
3880
|
+
});
|
|
3822
3881
|
});
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3882
|
+
return data;
|
|
3883
|
+
} catch (error) {
|
|
3884
|
+
logger11.log({ level: "error", message: `${error}` });
|
|
3885
|
+
throw error;
|
|
3827
3886
|
}
|
|
3828
3887
|
}
|
|
3829
|
-
async function
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3888
|
+
async function getById(_id) {
|
|
3889
|
+
try {
|
|
3890
|
+
_id = new ObjectId14(_id);
|
|
3891
|
+
} catch (error) {
|
|
3892
|
+
throw new BadRequestError17("Invalid ID.");
|
|
3893
|
+
}
|
|
3894
|
+
const cacheKey = makeCacheKey9(namespace_collection, { _id: String(_id) });
|
|
3895
|
+
try {
|
|
3896
|
+
const cached = await repo.getCache(cacheKey);
|
|
3897
|
+
if (cached) {
|
|
3898
|
+
logger11.log({
|
|
3899
|
+
level: "info",
|
|
3900
|
+
message: `Cache hit for getById app: ${cacheKey}`
|
|
3901
|
+
});
|
|
3902
|
+
return cached;
|
|
3903
|
+
}
|
|
3904
|
+
const result = await repo.collection.findOne({
|
|
3905
|
+
_id
|
|
3906
|
+
});
|
|
3907
|
+
repo.setCache(cacheKey, result, 300).then(() => {
|
|
3908
|
+
logger11.log({
|
|
3909
|
+
level: "info",
|
|
3910
|
+
message: `Cache set for app by id: ${cacheKey}`
|
|
3911
|
+
});
|
|
3912
|
+
}).catch((err) => {
|
|
3913
|
+
logger11.log({
|
|
3914
|
+
level: "error",
|
|
3915
|
+
message: `Failed to set cache for app by id: ${err.message}`
|
|
3916
|
+
});
|
|
3917
|
+
});
|
|
3918
|
+
return result;
|
|
3919
|
+
} catch (error) {
|
|
3920
|
+
if (error instanceof AppError6) {
|
|
3921
|
+
throw error;
|
|
3922
|
+
} else {
|
|
3923
|
+
throw new InternalServerError13("Failed to get app.");
|
|
3924
|
+
}
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
async function getByCode(code) {
|
|
3928
|
+
const validate = Joi7.string().required();
|
|
3929
|
+
const { error } = validate.validate(code);
|
|
3930
|
+
if (error) {
|
|
3931
|
+
throw new BadRequestError17("Invalid code.");
|
|
3932
|
+
}
|
|
3933
|
+
const cacheKey = makeCacheKey9(namespace_collection, {
|
|
3934
|
+
code,
|
|
3935
|
+
tag: "byCode"
|
|
3936
|
+
});
|
|
3937
|
+
try {
|
|
3938
|
+
const cached = await repo.getCache(cacheKey);
|
|
3939
|
+
if (cached) {
|
|
3940
|
+
logger11.log({
|
|
3941
|
+
level: "info",
|
|
3942
|
+
message: `Cache hit for getByCode app: ${cacheKey}`
|
|
3943
|
+
});
|
|
3944
|
+
return cached;
|
|
3945
|
+
}
|
|
3946
|
+
const result = await repo.collection.findOne({
|
|
3947
|
+
code
|
|
3948
|
+
});
|
|
3949
|
+
repo.setCache(cacheKey, result, 300).then(() => {
|
|
3950
|
+
logger11.log({
|
|
3951
|
+
level: "info",
|
|
3952
|
+
message: `Cache set for app by code: ${cacheKey}`
|
|
3953
|
+
});
|
|
3954
|
+
}).catch((err) => {
|
|
3955
|
+
logger11.log({
|
|
3956
|
+
level: "error",
|
|
3957
|
+
message: `Failed to set cache for app by code: ${err.message}`
|
|
3958
|
+
});
|
|
3959
|
+
});
|
|
3960
|
+
return result;
|
|
3961
|
+
} catch (error2) {
|
|
3962
|
+
if (error2 instanceof AppError6) {
|
|
3963
|
+
throw error2;
|
|
3964
|
+
} else {
|
|
3965
|
+
throw new InternalServerError13("Failed to get app.");
|
|
3966
|
+
}
|
|
3967
|
+
}
|
|
3968
|
+
}
|
|
3969
|
+
async function deleteById(_id, session) {
|
|
3970
|
+
try {
|
|
3971
|
+
_id = new ObjectId14(_id);
|
|
3972
|
+
} catch (error) {
|
|
3973
|
+
throw new BadRequestError17("Invalid ID.");
|
|
3974
|
+
}
|
|
3975
|
+
try {
|
|
3976
|
+
const res = await repo.collection.updateOne(
|
|
3977
|
+
{ _id },
|
|
3978
|
+
{ $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
|
|
3979
|
+
);
|
|
3980
|
+
repo.delCachedData();
|
|
3981
|
+
return res;
|
|
3982
|
+
} catch (error) {
|
|
3983
|
+
logger11.log({
|
|
3984
|
+
level: "error",
|
|
3985
|
+
message: error.message
|
|
3986
|
+
});
|
|
3987
|
+
if (error instanceof AppError6) {
|
|
3988
|
+
throw error;
|
|
3989
|
+
} else {
|
|
3990
|
+
throw new InternalServerError13("Failed to delete app.");
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3994
|
+
return {
|
|
3995
|
+
createIndexes,
|
|
3996
|
+
add,
|
|
3997
|
+
getAll,
|
|
3998
|
+
getById,
|
|
3999
|
+
getByCode,
|
|
4000
|
+
updateById,
|
|
4001
|
+
deleteById
|
|
4002
|
+
};
|
|
4003
|
+
}
|
|
4004
|
+
|
|
4005
|
+
// src/resources/app/app.service.ts
|
|
4006
|
+
import { logger as logger12, useAtlas as useAtlas11 } from "@eeplatform/nodejs-utils";
|
|
4007
|
+
function useAppService() {
|
|
4008
|
+
const {
|
|
4009
|
+
updateById: _updateById,
|
|
4010
|
+
getById: _getById,
|
|
4011
|
+
deleteById: _deleteById,
|
|
4012
|
+
getByCode: _getByCode,
|
|
4013
|
+
add: _add
|
|
4014
|
+
} = useAppRepo();
|
|
4015
|
+
async function addDefaultApps() {
|
|
4016
|
+
const apps = [
|
|
4017
|
+
{
|
|
4018
|
+
code: "admin",
|
|
4019
|
+
name: "Admin",
|
|
4020
|
+
description: "Administrative application.",
|
|
4021
|
+
type: "default"
|
|
4022
|
+
},
|
|
4023
|
+
{
|
|
4024
|
+
code: "basic-edu-ro",
|
|
4025
|
+
name: "Basic Education Regional Office",
|
|
4026
|
+
description: "Basic Education Regional Office application."
|
|
4027
|
+
},
|
|
4028
|
+
{
|
|
4029
|
+
code: "basic-edu-sdo",
|
|
4030
|
+
name: "Basic Education School Division Office",
|
|
4031
|
+
description: "Basic Education School Division Office application."
|
|
4032
|
+
},
|
|
4033
|
+
{
|
|
4034
|
+
code: "basic-edu-school",
|
|
4035
|
+
name: "Basic Education School",
|
|
4036
|
+
description: "Basic Education School application."
|
|
4037
|
+
}
|
|
4038
|
+
];
|
|
4039
|
+
const session = useAtlas11.getClient()?.startSession();
|
|
4040
|
+
if (!session) {
|
|
4041
|
+
throw new Error("Failed to start database session.");
|
|
4042
|
+
}
|
|
4043
|
+
try {
|
|
4044
|
+
session?.startTransaction();
|
|
4045
|
+
for (const app of apps) {
|
|
4046
|
+
const existingApp = await _getByCode(app.code);
|
|
4047
|
+
if (!existingApp) {
|
|
4048
|
+
await _add(app, session);
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
await session.commitTransaction();
|
|
4052
|
+
logger12.log({
|
|
4053
|
+
level: "info",
|
|
4054
|
+
message: "Default apps added successfully."
|
|
4055
|
+
});
|
|
4056
|
+
return;
|
|
4057
|
+
} catch (error) {
|
|
4058
|
+
await session.abortTransaction();
|
|
4059
|
+
logger12.log({
|
|
4060
|
+
level: "error",
|
|
4061
|
+
message: `Failed to add default apps: ${error}`
|
|
4062
|
+
});
|
|
4063
|
+
throw error;
|
|
4064
|
+
} finally {
|
|
4065
|
+
await session.endSession();
|
|
4066
|
+
}
|
|
4067
|
+
}
|
|
4068
|
+
async function deleteById(id) {
|
|
4069
|
+
try {
|
|
4070
|
+
await _deleteById(id);
|
|
4071
|
+
return "App deleted successfully.";
|
|
4072
|
+
} catch (error) {
|
|
4073
|
+
throw error;
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
return {
|
|
4077
|
+
addDefaultApps,
|
|
4078
|
+
deleteById
|
|
4079
|
+
};
|
|
4080
|
+
}
|
|
4081
|
+
|
|
4082
|
+
// src/resources/app/app.controller.ts
|
|
4083
|
+
import { BadRequestError as BadRequestError18 } from "@eeplatform/nodejs-utils";
|
|
4084
|
+
import Joi8 from "joi";
|
|
4085
|
+
function useAppController() {
|
|
4086
|
+
const {
|
|
4087
|
+
getAll: _getAll,
|
|
4088
|
+
getById: _getById,
|
|
4089
|
+
add: _add,
|
|
4090
|
+
updateById: _updateById
|
|
4091
|
+
} = useAppRepo();
|
|
4092
|
+
const { deleteById: _deleteById } = useAppService();
|
|
4093
|
+
async function add(req, res, next) {
|
|
4094
|
+
const value = req.body;
|
|
4095
|
+
const { error } = schemaApp.validate(value);
|
|
4096
|
+
if (error) {
|
|
4097
|
+
next(new BadRequestError18(error.message));
|
|
4098
|
+
return;
|
|
4099
|
+
}
|
|
4100
|
+
try {
|
|
4101
|
+
const result = await _add(value);
|
|
4102
|
+
res.json(result);
|
|
4103
|
+
return;
|
|
4104
|
+
} catch (error2) {
|
|
4105
|
+
next(error2);
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
async function updateById(req, res, next) {
|
|
4109
|
+
const id = req.params.id ?? "";
|
|
4110
|
+
const { error: errorId } = Joi8.string().hex().required().validate(id);
|
|
4111
|
+
if (errorId) {
|
|
4112
|
+
next(new BadRequestError18(errorId.message));
|
|
4113
|
+
return;
|
|
4114
|
+
}
|
|
4115
|
+
const value = req.body;
|
|
4116
|
+
const { error } = schemaAppUpdate.validate(value);
|
|
4117
|
+
if (error) {
|
|
4118
|
+
next(new BadRequestError18(error.message));
|
|
4119
|
+
return;
|
|
4120
|
+
}
|
|
4121
|
+
try {
|
|
4122
|
+
const result = await _updateById(req.params.id, value);
|
|
4123
|
+
res.json(result);
|
|
4124
|
+
return;
|
|
4125
|
+
} catch (error2) {
|
|
4126
|
+
next(error2);
|
|
4127
|
+
}
|
|
4128
|
+
}
|
|
4129
|
+
async function getAll(req, res, next) {
|
|
4130
|
+
const query = req.query;
|
|
4131
|
+
const validation = Joi8.object({
|
|
4132
|
+
page: Joi8.number().min(1).optional().allow("", null),
|
|
4133
|
+
limit: Joi8.number().min(1).optional().allow("", null),
|
|
4134
|
+
search: Joi8.string().optional().allow("", null),
|
|
4135
|
+
status: Joi8.string().optional().allow("", null),
|
|
4136
|
+
type: Joi8.string().optional().allow("", null)
|
|
4137
|
+
});
|
|
4138
|
+
const { error } = validation.validate(query);
|
|
4139
|
+
if (error) {
|
|
4140
|
+
next(new BadRequestError18(error.message));
|
|
4141
|
+
return;
|
|
4142
|
+
}
|
|
4143
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
4144
|
+
let limit = parseInt(req.query.limit) ?? 20;
|
|
4145
|
+
limit = isNaN(limit) ? 20 : limit;
|
|
4146
|
+
const sort = req.query.sort ? String(req.query.sort).split(",") : "";
|
|
4147
|
+
const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
|
|
4148
|
+
const sortObj = {};
|
|
4149
|
+
if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
|
|
4150
|
+
sort.forEach((field, index) => {
|
|
4151
|
+
sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
|
|
4152
|
+
});
|
|
4153
|
+
}
|
|
4154
|
+
const status = req.query.status ?? "active";
|
|
4155
|
+
const search = req.query.search ?? "";
|
|
4156
|
+
let type = req.query.type ? req.query.type.split(",") : "standard";
|
|
4157
|
+
try {
|
|
4158
|
+
const buildings = await _getAll({
|
|
4159
|
+
page,
|
|
4160
|
+
limit,
|
|
4161
|
+
sort: sortObj,
|
|
4162
|
+
status,
|
|
4163
|
+
search,
|
|
4164
|
+
type
|
|
4165
|
+
});
|
|
4166
|
+
res.json(buildings);
|
|
4167
|
+
return;
|
|
4168
|
+
} catch (error2) {
|
|
4169
|
+
next(error2);
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
async function getById(req, res, next) {
|
|
4173
|
+
const id = req.params.id;
|
|
4174
|
+
const validation = Joi8.object({
|
|
4175
|
+
id: Joi8.string().hex().required()
|
|
4176
|
+
});
|
|
4177
|
+
const { error } = validation.validate({ id });
|
|
4178
|
+
if (error) {
|
|
4179
|
+
next(new BadRequestError18(error.message));
|
|
4180
|
+
return;
|
|
4181
|
+
}
|
|
4182
|
+
try {
|
|
4183
|
+
const data = await _getById(id);
|
|
4184
|
+
res.json({
|
|
4185
|
+
message: "Successfully retrieved app.",
|
|
4186
|
+
data
|
|
4187
|
+
});
|
|
4188
|
+
return;
|
|
4189
|
+
} catch (error2) {
|
|
4190
|
+
next(error2);
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
async function deleteById(req, res, next) {
|
|
4194
|
+
const id = req.params.id;
|
|
4195
|
+
const validation = Joi8.object({
|
|
4196
|
+
id: Joi8.string().hex().required()
|
|
4197
|
+
});
|
|
4198
|
+
const { error } = validation.validate({ id });
|
|
4199
|
+
if (error) {
|
|
4200
|
+
next(new BadRequestError18(error.message));
|
|
4201
|
+
return;
|
|
4202
|
+
}
|
|
4203
|
+
try {
|
|
4204
|
+
const message = await _deleteById(id);
|
|
4205
|
+
res.json(message);
|
|
4206
|
+
return;
|
|
4207
|
+
} catch (error2) {
|
|
4208
|
+
next(error2);
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
return {
|
|
4212
|
+
add,
|
|
4213
|
+
updateById,
|
|
4214
|
+
getAll,
|
|
4215
|
+
getById,
|
|
4216
|
+
deleteById
|
|
4217
|
+
};
|
|
4218
|
+
}
|
|
4219
|
+
|
|
4220
|
+
// src/resources/permission/permission.model.ts
|
|
4221
|
+
import { BadRequestError as BadRequestError19 } from "@eeplatform/nodejs-utils";
|
|
4222
|
+
import Joi9 from "joi";
|
|
4223
|
+
var schemaPermission = Joi9.object({
|
|
4224
|
+
app: Joi9.string().required(),
|
|
4225
|
+
key: Joi9.string().required(),
|
|
4226
|
+
name: Joi9.string().required(),
|
|
4227
|
+
group: Joi9.string().required(),
|
|
4228
|
+
description: Joi9.string().required(),
|
|
4229
|
+
deprecated: Joi9.boolean().optional().allow(null)
|
|
4230
|
+
});
|
|
4231
|
+
var schemaPermissionUpdate = Joi9.object({
|
|
4232
|
+
key: Joi9.string().optional().allow("", null),
|
|
4233
|
+
name: Joi9.string().optional().allow("", null),
|
|
4234
|
+
group: Joi9.string().optional().allow("", null),
|
|
4235
|
+
description: Joi9.string().max(1024).optional().allow("", null)
|
|
4236
|
+
});
|
|
4237
|
+
function modelPermission(value) {
|
|
4238
|
+
const { error } = schemaPermission.validate(value);
|
|
4239
|
+
if (error) {
|
|
4240
|
+
throw new BadRequestError19(error.message);
|
|
4241
|
+
}
|
|
4242
|
+
return {
|
|
4243
|
+
_id: value._id,
|
|
4244
|
+
app: value.app,
|
|
4245
|
+
key: value.key,
|
|
4246
|
+
name: value.name,
|
|
4247
|
+
group: value.group,
|
|
4248
|
+
description: value.description,
|
|
4249
|
+
deprecated: value.deprecated ?? false,
|
|
4250
|
+
status: value.status ?? "active",
|
|
4251
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
4252
|
+
updatedAt: "",
|
|
4253
|
+
deletedAt: ""
|
|
4254
|
+
};
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4257
|
+
// src/resources/permission/permission.repository.ts
|
|
4258
|
+
import {
|
|
4259
|
+
AppError as AppError7,
|
|
4260
|
+
BadRequestError as BadRequestError20,
|
|
4261
|
+
InternalServerError as InternalServerError14,
|
|
4262
|
+
logger as logger14,
|
|
4263
|
+
makeCacheKey as makeCacheKey10,
|
|
4264
|
+
paginate as paginate7,
|
|
4265
|
+
useRepo as useRepo2
|
|
4266
|
+
} from "@eeplatform/nodejs-utils";
|
|
4267
|
+
import { ObjectId as ObjectId15 } from "mongodb";
|
|
4268
|
+
import Joi10 from "joi";
|
|
4269
|
+
function usePermissionRepo() {
|
|
4270
|
+
const namespace_collection = "permissions";
|
|
4271
|
+
const repo = useRepo2(namespace_collection);
|
|
4272
|
+
async function createIndexes() {
|
|
4273
|
+
try {
|
|
4274
|
+
await repo.collection.createIndexes([
|
|
4275
|
+
{ key: { app: 1 } },
|
|
4276
|
+
{ key: { name: 1 } },
|
|
4277
|
+
{ key: { key: 1 } },
|
|
4278
|
+
{ key: { group: 1 } },
|
|
4279
|
+
{
|
|
4280
|
+
key: {
|
|
4281
|
+
app: "text",
|
|
4282
|
+
name: "text",
|
|
4283
|
+
key: "text",
|
|
4284
|
+
description: "text",
|
|
4285
|
+
group: "text"
|
|
4286
|
+
},
|
|
4287
|
+
name: "text_index"
|
|
4288
|
+
},
|
|
4289
|
+
{
|
|
4290
|
+
key: { app: 1, name: 1, key: 1, group: 1 },
|
|
4291
|
+
unique: true,
|
|
4292
|
+
name: "unique_permission"
|
|
4293
|
+
}
|
|
4294
|
+
]);
|
|
4295
|
+
} catch (error) {
|
|
4296
|
+
throw new Error("Failed to create index on permissions.");
|
|
4297
|
+
}
|
|
4298
|
+
}
|
|
4299
|
+
async function add(value, session) {
|
|
4300
|
+
try {
|
|
4301
|
+
value = modelPermission(value);
|
|
4302
|
+
const res = await repo.collection.insertOne(value, { session });
|
|
4303
|
+
repo.delCachedData();
|
|
4304
|
+
return res.insertedId;
|
|
4305
|
+
} catch (error) {
|
|
4306
|
+
logger14.log({
|
|
4307
|
+
level: "error",
|
|
4308
|
+
message: error.message
|
|
4309
|
+
});
|
|
4310
|
+
if (error instanceof AppError7) {
|
|
4311
|
+
throw error;
|
|
4312
|
+
} else {
|
|
4313
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
4314
|
+
if (isDuplicated) {
|
|
4315
|
+
throw new BadRequestError20("Permission already exists.");
|
|
4316
|
+
}
|
|
4317
|
+
throw new Error("Failed to create permission.");
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
}
|
|
4321
|
+
async function updateById(_id, value, session) {
|
|
4322
|
+
try {
|
|
4323
|
+
_id = new ObjectId15(_id);
|
|
4324
|
+
} catch (error2) {
|
|
4325
|
+
throw new BadRequestError20("Invalid ID.");
|
|
4326
|
+
}
|
|
4327
|
+
const { error } = schemaPermissionUpdate.validate(value);
|
|
4328
|
+
if (error) {
|
|
4329
|
+
throw new BadRequestError20(`Invalid data: ${error.message}`);
|
|
4330
|
+
}
|
|
4331
|
+
try {
|
|
4332
|
+
const res = await repo.collection.updateOne(
|
|
4333
|
+
{ _id },
|
|
4334
|
+
{ $set: value },
|
|
4335
|
+
{ session }
|
|
4336
|
+
);
|
|
4337
|
+
repo.delCachedData();
|
|
4338
|
+
return res;
|
|
4339
|
+
} catch (error2) {
|
|
4340
|
+
logger14.log({
|
|
4341
|
+
level: "error",
|
|
4342
|
+
message: error2.message
|
|
4343
|
+
});
|
|
4344
|
+
if (error2 instanceof AppError7) {
|
|
4345
|
+
throw error2;
|
|
4346
|
+
} else {
|
|
4347
|
+
throw new Error("Failed to update permission.");
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
async function getAll({
|
|
4352
|
+
search = "",
|
|
4353
|
+
page = 1,
|
|
4354
|
+
limit = 10,
|
|
4355
|
+
sort = {},
|
|
4356
|
+
app = "",
|
|
4357
|
+
status = "active"
|
|
4358
|
+
} = {}) {
|
|
4359
|
+
page = page > 0 ? page - 1 : 0;
|
|
4360
|
+
const query = {};
|
|
4361
|
+
const cacheParams = {
|
|
4362
|
+
page,
|
|
4363
|
+
limit,
|
|
4364
|
+
sort: JSON.stringify(sort)
|
|
4365
|
+
};
|
|
4366
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
4367
|
+
query.status = status;
|
|
4368
|
+
cacheParams.status = status;
|
|
4369
|
+
if (search) {
|
|
4370
|
+
query.$text = { $search: search };
|
|
4371
|
+
cacheParams.search = search;
|
|
4372
|
+
}
|
|
4373
|
+
if (app) {
|
|
4374
|
+
query.app = app;
|
|
4375
|
+
cacheParams.app = app;
|
|
4376
|
+
}
|
|
4377
|
+
const cacheKey = makeCacheKey10(namespace_collection, cacheParams);
|
|
4378
|
+
logger14.log({
|
|
4379
|
+
level: "info",
|
|
4380
|
+
message: `Cache key for getAll permissions: ${cacheKey}`
|
|
4381
|
+
});
|
|
4382
|
+
try {
|
|
4383
|
+
const cached = await repo.getCache(cacheKey);
|
|
4384
|
+
if (cached) {
|
|
4385
|
+
logger14.log({
|
|
4386
|
+
level: "info",
|
|
4387
|
+
message: `Cache hit for getAll permissions: ${cacheKey}`
|
|
4388
|
+
});
|
|
4389
|
+
return cached;
|
|
4390
|
+
}
|
|
4391
|
+
const items = await repo.collection.aggregate([
|
|
4392
|
+
{ $match: query },
|
|
4393
|
+
{ $sort: sort },
|
|
4394
|
+
{ $skip: page * limit },
|
|
4395
|
+
{ $limit: limit }
|
|
4396
|
+
]).toArray();
|
|
4397
|
+
const length = await repo.collection.countDocuments(query);
|
|
4398
|
+
const data = paginate7(items, page, limit, length);
|
|
4399
|
+
repo.setCache(cacheKey, data, 600).then(() => {
|
|
4400
|
+
logger14.log({
|
|
4401
|
+
level: "info",
|
|
4402
|
+
message: `Cache set for getAll permissions: ${cacheKey}`
|
|
4403
|
+
});
|
|
4404
|
+
}).catch((err) => {
|
|
4405
|
+
logger14.log({
|
|
4406
|
+
level: "error",
|
|
4407
|
+
message: `Failed to set cache for getAll permissions: ${err.message}`
|
|
4408
|
+
});
|
|
4409
|
+
});
|
|
4410
|
+
return data;
|
|
4411
|
+
} catch (error) {
|
|
4412
|
+
logger14.log({ level: "error", message: `${error}` });
|
|
4413
|
+
throw error;
|
|
4414
|
+
}
|
|
4415
|
+
}
|
|
4416
|
+
async function getById(_id) {
|
|
4417
|
+
try {
|
|
4418
|
+
_id = new ObjectId15(_id);
|
|
4419
|
+
} catch (error) {
|
|
4420
|
+
throw new BadRequestError20("Invalid ID.");
|
|
4421
|
+
}
|
|
4422
|
+
const cacheKey = makeCacheKey10(namespace_collection, { _id: String(_id) });
|
|
4423
|
+
try {
|
|
4424
|
+
const cached = await repo.getCache(cacheKey);
|
|
4425
|
+
if (cached) {
|
|
4426
|
+
logger14.log({
|
|
4427
|
+
level: "info",
|
|
4428
|
+
message: `Cache hit for getById permission: ${cacheKey}`
|
|
4429
|
+
});
|
|
4430
|
+
return cached;
|
|
4431
|
+
}
|
|
4432
|
+
const result = await repo.collection.findOne({
|
|
4433
|
+
_id
|
|
4434
|
+
});
|
|
4435
|
+
repo.setCache(cacheKey, result, 300).then(() => {
|
|
4436
|
+
logger14.log({
|
|
4437
|
+
level: "info",
|
|
4438
|
+
message: `Cache set for permission by id: ${cacheKey}`
|
|
4439
|
+
});
|
|
4440
|
+
}).catch((err) => {
|
|
4441
|
+
logger14.log({
|
|
4442
|
+
level: "error",
|
|
4443
|
+
message: `Failed to set cache for permission by id: ${err.message}`
|
|
4444
|
+
});
|
|
4445
|
+
});
|
|
4446
|
+
return result;
|
|
4447
|
+
} catch (error) {
|
|
4448
|
+
if (error instanceof AppError7) {
|
|
4449
|
+
throw error;
|
|
4450
|
+
} else {
|
|
4451
|
+
throw new InternalServerError14("Failed to get permission.");
|
|
4452
|
+
}
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
async function getByKey(key, group, app) {
|
|
4456
|
+
const validation = Joi10.object({
|
|
4457
|
+
key: Joi10.string().required(),
|
|
4458
|
+
group: Joi10.string().optional().allow("", null),
|
|
4459
|
+
app: Joi10.string().optional().allow("", null)
|
|
4460
|
+
});
|
|
4461
|
+
const { error } = validation.validate({ key, group });
|
|
4462
|
+
if (error) {
|
|
4463
|
+
throw new BadRequestError20(`Invalid data: ${error.message}`);
|
|
4464
|
+
}
|
|
4465
|
+
const query = {};
|
|
4466
|
+
const cacheKeyOptions = {};
|
|
4467
|
+
query.key = key;
|
|
4468
|
+
cacheKeyOptions.key = key;
|
|
4469
|
+
if (group) {
|
|
4470
|
+
query.group = group;
|
|
4471
|
+
cacheKeyOptions.group = group;
|
|
4472
|
+
}
|
|
4473
|
+
if (app) {
|
|
4474
|
+
query.app = app;
|
|
4475
|
+
cacheKeyOptions.app = app;
|
|
4476
|
+
}
|
|
4477
|
+
const cacheKey = makeCacheKey10(namespace_collection, cacheKeyOptions);
|
|
4478
|
+
try {
|
|
4479
|
+
const cached = await repo.getCache(cacheKey);
|
|
4480
|
+
if (cached) {
|
|
4481
|
+
logger14.log({
|
|
4482
|
+
level: "info",
|
|
4483
|
+
message: `Cache hit for getById permission: ${cacheKey}`
|
|
4484
|
+
});
|
|
4485
|
+
return cached;
|
|
4486
|
+
}
|
|
4487
|
+
const result = await repo.collection.findOne(query);
|
|
4488
|
+
repo.setCache(cacheKey, result, 300).then(() => {
|
|
4489
|
+
logger14.log({
|
|
4490
|
+
level: "info",
|
|
4491
|
+
message: `Cache set for permission by key: ${cacheKey}`
|
|
4492
|
+
});
|
|
4493
|
+
}).catch((err) => {
|
|
4494
|
+
logger14.log({
|
|
4495
|
+
level: "error",
|
|
4496
|
+
message: `Failed to set cache for permission by key: ${err.message}`
|
|
4497
|
+
});
|
|
4498
|
+
});
|
|
4499
|
+
return result;
|
|
4500
|
+
} catch (error2) {
|
|
4501
|
+
if (error2 instanceof AppError7) {
|
|
4502
|
+
throw error2;
|
|
4503
|
+
} else {
|
|
4504
|
+
throw new InternalServerError14("Failed to get permission.");
|
|
4505
|
+
}
|
|
4506
|
+
}
|
|
4507
|
+
}
|
|
4508
|
+
async function countByGroup(group) {
|
|
4509
|
+
const cacheKey = makeCacheKey10(namespace_collection, {
|
|
4510
|
+
group,
|
|
4511
|
+
tag: "countByGroup"
|
|
4512
|
+
});
|
|
4513
|
+
try {
|
|
4514
|
+
const cached = await repo.getCache(cacheKey);
|
|
4515
|
+
if (cached) {
|
|
4516
|
+
logger14.log({
|
|
4517
|
+
level: "info",
|
|
4518
|
+
message: `Cache hit for getById permission: ${cacheKey}`
|
|
4519
|
+
});
|
|
4520
|
+
return cached;
|
|
4521
|
+
}
|
|
4522
|
+
const result = await repo.collection.countDocuments({
|
|
4523
|
+
group
|
|
4524
|
+
});
|
|
4525
|
+
repo.setCache(cacheKey, result, 300).then(() => {
|
|
4526
|
+
logger14.log({
|
|
4527
|
+
level: "info",
|
|
4528
|
+
message: `Cache set for permission count by group: ${cacheKey}`
|
|
4529
|
+
});
|
|
4530
|
+
}).catch((err) => {
|
|
4531
|
+
logger14.log({
|
|
4532
|
+
level: "error",
|
|
4533
|
+
message: `Failed to set cache for permission by group: ${err.message}`
|
|
4534
|
+
});
|
|
4535
|
+
});
|
|
4536
|
+
return result;
|
|
4537
|
+
} catch (error) {
|
|
4538
|
+
if (error instanceof AppError7) {
|
|
4539
|
+
throw error;
|
|
4540
|
+
} else {
|
|
4541
|
+
throw new InternalServerError14("Failed to count permission by group.");
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
}
|
|
4545
|
+
async function deleteById(_id, session) {
|
|
4546
|
+
try {
|
|
4547
|
+
_id = new ObjectId15(_id);
|
|
4548
|
+
} catch (error) {
|
|
4549
|
+
throw new BadRequestError20("Invalid ID.");
|
|
4550
|
+
}
|
|
4551
|
+
try {
|
|
4552
|
+
const res = await repo.collection.updateOne(
|
|
4553
|
+
{ _id },
|
|
4554
|
+
{ $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
|
|
4555
|
+
);
|
|
4556
|
+
repo.delCachedData();
|
|
4557
|
+
return res;
|
|
4558
|
+
} catch (error) {
|
|
4559
|
+
logger14.log({
|
|
4560
|
+
level: "error",
|
|
4561
|
+
message: error.message
|
|
4562
|
+
});
|
|
4563
|
+
if (error instanceof AppError7) {
|
|
4564
|
+
throw error;
|
|
4565
|
+
} else {
|
|
4566
|
+
throw new InternalServerError14("Failed to delete permission.");
|
|
4567
|
+
}
|
|
4568
|
+
}
|
|
4569
|
+
}
|
|
4570
|
+
return {
|
|
4571
|
+
createIndexes,
|
|
4572
|
+
add,
|
|
4573
|
+
getAll,
|
|
4574
|
+
getById,
|
|
4575
|
+
getByKey,
|
|
4576
|
+
updateById,
|
|
4577
|
+
deleteById,
|
|
4578
|
+
countByGroup
|
|
4579
|
+
};
|
|
4580
|
+
}
|
|
4581
|
+
|
|
4582
|
+
// src/resources/permission/permission.service.ts
|
|
4583
|
+
function usePermissionService() {
|
|
4584
|
+
const {
|
|
4585
|
+
updateById: _updateById,
|
|
4586
|
+
getById: _getById,
|
|
4587
|
+
deleteById: _deleteById
|
|
4588
|
+
} = usePermissionRepo();
|
|
4589
|
+
async function deleteById(id) {
|
|
4590
|
+
try {
|
|
4591
|
+
await _deleteById(id);
|
|
4592
|
+
return "Permission deleted successfully.";
|
|
4593
|
+
} catch (error) {
|
|
4594
|
+
throw error;
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
return {
|
|
4598
|
+
deleteById
|
|
4599
|
+
};
|
|
4600
|
+
}
|
|
4601
|
+
|
|
4602
|
+
// src/resources/permission/permission.controller.ts
|
|
4603
|
+
import { BadRequestError as BadRequestError21, logger as logger15 } from "@eeplatform/nodejs-utils";
|
|
4604
|
+
import Joi11 from "joi";
|
|
4605
|
+
function usePermissionController() {
|
|
4606
|
+
const {
|
|
4607
|
+
getAll: _getAll,
|
|
4608
|
+
getById: _getById,
|
|
4609
|
+
add: _add,
|
|
4610
|
+
updateById: _updateById
|
|
4611
|
+
} = usePermissionRepo();
|
|
4612
|
+
const { deleteById: _deleteById } = usePermissionService();
|
|
4613
|
+
async function add(req, res, next) {
|
|
4614
|
+
const value = req.body;
|
|
4615
|
+
const { error } = schemaPermission.validate(value);
|
|
4616
|
+
if (error) {
|
|
4617
|
+
next(new BadRequestError21(error.message));
|
|
4618
|
+
logger15.info(`Controller: ${error.message}`);
|
|
4619
|
+
return;
|
|
4620
|
+
}
|
|
4621
|
+
try {
|
|
4622
|
+
const result = await _add(value);
|
|
4623
|
+
res.json(result);
|
|
4624
|
+
return;
|
|
4625
|
+
} catch (error2) {
|
|
4626
|
+
next(error2);
|
|
4627
|
+
}
|
|
4628
|
+
}
|
|
4629
|
+
async function getAll(req, res, next) {
|
|
4630
|
+
const query = req.query;
|
|
4631
|
+
const validation = Joi11.object({
|
|
4632
|
+
page: Joi11.number().min(1).optional().allow("", null),
|
|
4633
|
+
limit: Joi11.number().min(1).optional().allow("", null),
|
|
4634
|
+
search: Joi11.string().optional().allow("", null),
|
|
4635
|
+
app: Joi11.string().optional().allow("", null),
|
|
4636
|
+
status: Joi11.string().optional().allow("", null)
|
|
4637
|
+
});
|
|
4638
|
+
const { error } = validation.validate(query);
|
|
4639
|
+
if (error) {
|
|
4640
|
+
next(new BadRequestError21(error.message));
|
|
4641
|
+
return;
|
|
4642
|
+
}
|
|
4643
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
4644
|
+
let limit = parseInt(req.query.limit) ?? 20;
|
|
4645
|
+
limit = isNaN(limit) ? 20 : limit;
|
|
4646
|
+
const sort = req.query.sort ? String(req.query.sort).split(",") : "";
|
|
4647
|
+
const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
|
|
4648
|
+
const sortObj = {};
|
|
4649
|
+
if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
|
|
4650
|
+
sort.forEach((field, index) => {
|
|
4651
|
+
sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
|
|
4652
|
+
});
|
|
4653
|
+
}
|
|
4654
|
+
const app = req.query.app ?? "";
|
|
4655
|
+
const search = req.query.search ?? "";
|
|
4656
|
+
const status = req.query.status ?? "active";
|
|
4657
|
+
try {
|
|
4658
|
+
const buildings = await _getAll({
|
|
4659
|
+
page,
|
|
4660
|
+
limit,
|
|
4661
|
+
sort: sortObj,
|
|
4662
|
+
app,
|
|
4663
|
+
search,
|
|
4664
|
+
status
|
|
4665
|
+
});
|
|
4666
|
+
res.json(buildings);
|
|
4667
|
+
return;
|
|
4668
|
+
} catch (error2) {
|
|
4669
|
+
next(error2);
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
async function getById(req, res, next) {
|
|
4673
|
+
const id = req.params.id;
|
|
4674
|
+
const validation = Joi11.object({
|
|
4675
|
+
id: Joi11.string().hex().required()
|
|
4676
|
+
});
|
|
4677
|
+
const { error } = validation.validate({ id });
|
|
4678
|
+
if (error) {
|
|
4679
|
+
next(new BadRequestError21(error.message));
|
|
4680
|
+
return;
|
|
4681
|
+
}
|
|
4682
|
+
try {
|
|
4683
|
+
const data = await _getById(id);
|
|
4684
|
+
res.json({
|
|
4685
|
+
message: "Successfully retrieved permission.",
|
|
4686
|
+
data
|
|
4687
|
+
});
|
|
4688
|
+
return;
|
|
4689
|
+
} catch (error2) {
|
|
4690
|
+
next(error2);
|
|
4691
|
+
}
|
|
4692
|
+
}
|
|
4693
|
+
async function deleteById(req, res, next) {
|
|
4694
|
+
const id = req.params.id;
|
|
4695
|
+
const validation = Joi11.object({
|
|
4696
|
+
id: Joi11.string().hex().required()
|
|
4697
|
+
});
|
|
4698
|
+
const { error } = validation.validate({ id });
|
|
4699
|
+
if (error) {
|
|
4700
|
+
next(new BadRequestError21(error.message));
|
|
4701
|
+
return;
|
|
4702
|
+
}
|
|
4703
|
+
try {
|
|
4704
|
+
const message = await _deleteById(id);
|
|
4705
|
+
res.json(message);
|
|
4706
|
+
return;
|
|
4707
|
+
} catch (error2) {
|
|
4708
|
+
next(error2);
|
|
4709
|
+
}
|
|
4710
|
+
}
|
|
4711
|
+
async function updateById(req, res, next) {
|
|
4712
|
+
const id = req.params.id;
|
|
4713
|
+
const { error: errorId } = Joi11.string().hex().required().validate(id);
|
|
4714
|
+
if (errorId) {
|
|
4715
|
+
next(new BadRequestError21(errorId.message));
|
|
4716
|
+
return;
|
|
4717
|
+
}
|
|
4718
|
+
const payload = req.body;
|
|
4719
|
+
const { error } = schemaPermissionUpdate.validate(payload);
|
|
4720
|
+
if (error) {
|
|
4721
|
+
next(new BadRequestError21(error.message));
|
|
4722
|
+
return;
|
|
4723
|
+
}
|
|
4724
|
+
try {
|
|
4725
|
+
const message = await _updateById(id, payload);
|
|
4726
|
+
res.json(message);
|
|
4727
|
+
return;
|
|
4728
|
+
} catch (error2) {
|
|
4729
|
+
next(error2);
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4732
|
+
return {
|
|
4733
|
+
add,
|
|
4734
|
+
getAll,
|
|
4735
|
+
getById,
|
|
4736
|
+
deleteById,
|
|
4737
|
+
updateById
|
|
4738
|
+
};
|
|
4739
|
+
}
|
|
4740
|
+
|
|
4741
|
+
// src/resources/permission/permission.group.model.ts
|
|
4742
|
+
import { BadRequestError as BadRequestError22 } from "@eeplatform/nodejs-utils";
|
|
4743
|
+
import Joi12 from "joi";
|
|
4744
|
+
var schemaPermissionGroup = Joi12.object({
|
|
4745
|
+
app: Joi12.string().required(),
|
|
4746
|
+
key: Joi12.string().required(),
|
|
4747
|
+
label: Joi12.string().required(),
|
|
4748
|
+
order: Joi12.number().integer().optional().allow("", null)
|
|
4749
|
+
});
|
|
4750
|
+
var schemaPermissionGroupUpdate = Joi12.object({
|
|
4751
|
+
key: Joi12.string().optional().allow("", null),
|
|
4752
|
+
label: Joi12.string().optional().allow("", null),
|
|
4753
|
+
order: Joi12.number().integer().optional().allow("", null)
|
|
4754
|
+
});
|
|
4755
|
+
function modelPermissionGroup(value) {
|
|
4756
|
+
const { error } = schemaPermissionGroup.validate(value);
|
|
4757
|
+
if (error) {
|
|
4758
|
+
throw new BadRequestError22(error.message);
|
|
4759
|
+
}
|
|
4760
|
+
return {
|
|
4761
|
+
_id: value._id,
|
|
4762
|
+
app: value.app,
|
|
4763
|
+
key: value.key,
|
|
4764
|
+
label: value.label,
|
|
4765
|
+
order: value.order ?? Date.now(),
|
|
4766
|
+
status: value.status ?? "active",
|
|
4767
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
4768
|
+
updatedAt: "",
|
|
4769
|
+
deletedAt: ""
|
|
4770
|
+
};
|
|
4771
|
+
}
|
|
4772
|
+
|
|
4773
|
+
// src/resources/permission/permission.group.repository.ts
|
|
4774
|
+
import {
|
|
4775
|
+
AppError as AppError8,
|
|
4776
|
+
BadRequestError as BadRequestError23,
|
|
4777
|
+
InternalServerError as InternalServerError15,
|
|
4778
|
+
logger as logger16,
|
|
4779
|
+
makeCacheKey as makeCacheKey11,
|
|
4780
|
+
paginate as paginate8,
|
|
4781
|
+
useRepo as useRepo3
|
|
4782
|
+
} from "@eeplatform/nodejs-utils";
|
|
4783
|
+
import { ObjectId as ObjectId16 } from "mongodb";
|
|
4784
|
+
import Joi13 from "joi";
|
|
4785
|
+
function usePermissionGroupRepo() {
|
|
4786
|
+
const namespace_collection = "permission.groups";
|
|
4787
|
+
const repo = useRepo3(namespace_collection);
|
|
4788
|
+
async function createIndexes() {
|
|
4789
|
+
try {
|
|
4790
|
+
await repo.collection.createIndexes([
|
|
4791
|
+
{ key: { app: 1 } },
|
|
4792
|
+
{ key: { key: 1 } },
|
|
4793
|
+
{ key: { label: 1 } },
|
|
4794
|
+
{
|
|
4795
|
+
key: { app: "text", key: "text", label: "text" },
|
|
4796
|
+
name: "text_index"
|
|
4797
|
+
},
|
|
4798
|
+
{
|
|
4799
|
+
key: { app: 1, key: 1, label: 1 },
|
|
4800
|
+
unique: true,
|
|
4801
|
+
name: "unique_permission_group"
|
|
4802
|
+
}
|
|
4803
|
+
]);
|
|
4804
|
+
} catch (error) {
|
|
4805
|
+
throw new Error("Failed to create index on permission groups.");
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
async function add(value, session) {
|
|
4809
|
+
try {
|
|
4810
|
+
value = modelPermissionGroup(value);
|
|
4811
|
+
const res = await repo.collection.insertOne(value, { session });
|
|
4812
|
+
repo.delCachedData();
|
|
4813
|
+
return res.insertedId;
|
|
4814
|
+
} catch (error) {
|
|
4815
|
+
logger16.log({
|
|
4816
|
+
level: "error",
|
|
4817
|
+
message: error.message
|
|
4818
|
+
});
|
|
4819
|
+
if (error instanceof AppError8) {
|
|
4820
|
+
throw error;
|
|
4821
|
+
} else {
|
|
4822
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
4823
|
+
if (isDuplicated) {
|
|
4824
|
+
throw new BadRequestError23("Permission group already exists.");
|
|
4825
|
+
}
|
|
4826
|
+
throw new Error("Failed to create permission group.");
|
|
4827
|
+
}
|
|
4828
|
+
}
|
|
4829
|
+
}
|
|
4830
|
+
async function updateById(_id, value, session) {
|
|
4831
|
+
try {
|
|
4832
|
+
_id = new ObjectId16(_id);
|
|
4833
|
+
} catch (error2) {
|
|
4834
|
+
throw new BadRequestError23("Invalid ID.");
|
|
4835
|
+
}
|
|
4836
|
+
const { error } = schemaPermissionGroupUpdate.validate(value);
|
|
4837
|
+
if (error) {
|
|
4838
|
+
throw new BadRequestError23(`Invalid data: ${error.message}`);
|
|
4839
|
+
}
|
|
4840
|
+
try {
|
|
4841
|
+
const res = await repo.collection.updateOne(
|
|
4842
|
+
{ _id },
|
|
4843
|
+
{ $set: value },
|
|
4844
|
+
{ session }
|
|
4845
|
+
);
|
|
4846
|
+
repo.delCachedData();
|
|
4847
|
+
return res;
|
|
4848
|
+
} catch (error2) {
|
|
4849
|
+
logger16.log({
|
|
4850
|
+
level: "error",
|
|
4851
|
+
message: error2.message
|
|
4852
|
+
});
|
|
4853
|
+
if (error2 instanceof AppError8) {
|
|
4854
|
+
throw error2;
|
|
4855
|
+
} else {
|
|
4856
|
+
throw new Error("Failed to update permission group.");
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4859
|
+
}
|
|
4860
|
+
async function getAll({
|
|
4861
|
+
search = "",
|
|
4862
|
+
page = 1,
|
|
4863
|
+
limit = 10,
|
|
4864
|
+
sort = {},
|
|
4865
|
+
app = "",
|
|
4866
|
+
status = "active"
|
|
4867
|
+
} = {}) {
|
|
4868
|
+
page = page > 0 ? page - 1 : 0;
|
|
4869
|
+
const query = {};
|
|
4870
|
+
const cacheParams = {
|
|
4871
|
+
page,
|
|
4872
|
+
limit,
|
|
4873
|
+
sort: JSON.stringify(sort)
|
|
4874
|
+
};
|
|
4875
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
4876
|
+
query.status = status;
|
|
4877
|
+
cacheParams.status = status;
|
|
4878
|
+
if (search) {
|
|
4879
|
+
query.$text = { $search: search };
|
|
4880
|
+
cacheParams.search = search;
|
|
4881
|
+
}
|
|
4882
|
+
if (app) {
|
|
4883
|
+
query.app = app;
|
|
4884
|
+
cacheParams.app = app;
|
|
4885
|
+
}
|
|
4886
|
+
const cacheKey = makeCacheKey11(namespace_collection, cacheParams);
|
|
4887
|
+
logger16.log({
|
|
4888
|
+
level: "info",
|
|
4889
|
+
message: `Cache key for getAll permission groups: ${cacheKey}`
|
|
4890
|
+
});
|
|
4891
|
+
try {
|
|
4892
|
+
const cached = await repo.getCache(cacheKey);
|
|
4893
|
+
if (cached) {
|
|
4894
|
+
logger16.log({
|
|
4895
|
+
level: "info",
|
|
4896
|
+
message: `Cache hit for getAll permission groups: ${cacheKey}`
|
|
4897
|
+
});
|
|
4898
|
+
return cached;
|
|
4899
|
+
}
|
|
4900
|
+
const items = await repo.collection.aggregate([
|
|
4901
|
+
{ $match: query },
|
|
4902
|
+
{ $sort: sort },
|
|
4903
|
+
{ $skip: page * limit },
|
|
4904
|
+
{ $limit: limit }
|
|
4905
|
+
]).toArray();
|
|
4906
|
+
const length = await repo.collection.countDocuments(query);
|
|
4907
|
+
const data = paginate8(items, page, limit, length);
|
|
4908
|
+
repo.setCache(cacheKey, data, 600).then(() => {
|
|
4909
|
+
logger16.log({
|
|
4910
|
+
level: "info",
|
|
4911
|
+
message: `Cache set for getAll permission groups: ${cacheKey}`
|
|
4912
|
+
});
|
|
4913
|
+
}).catch((err) => {
|
|
4914
|
+
logger16.log({
|
|
4915
|
+
level: "error",
|
|
4916
|
+
message: `Failed to set cache for getAll permission groups: ${err.message}`
|
|
4917
|
+
});
|
|
4918
|
+
});
|
|
4919
|
+
return data;
|
|
4920
|
+
} catch (error) {
|
|
4921
|
+
logger16.log({ level: "error", message: `${error}` });
|
|
4922
|
+
throw error;
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
async function getById(_id) {
|
|
4926
|
+
try {
|
|
4927
|
+
_id = new ObjectId16(_id);
|
|
4928
|
+
} catch (error) {
|
|
4929
|
+
throw new BadRequestError23("Invalid ID.");
|
|
4930
|
+
}
|
|
4931
|
+
const cacheKey = makeCacheKey11(namespace_collection, { _id: String(_id) });
|
|
4932
|
+
try {
|
|
4933
|
+
const cached = await repo.getCache(cacheKey);
|
|
4934
|
+
if (cached) {
|
|
4935
|
+
logger16.log({
|
|
4936
|
+
level: "info",
|
|
4937
|
+
message: `Cache hit for getById permission group: ${cacheKey}`
|
|
4938
|
+
});
|
|
4939
|
+
return cached;
|
|
4940
|
+
}
|
|
4941
|
+
const result = await repo.collection.findOne({
|
|
4942
|
+
_id
|
|
4943
|
+
});
|
|
4944
|
+
repo.setCache(cacheKey, result, 300).then(() => {
|
|
4945
|
+
logger16.log({
|
|
4946
|
+
level: "info",
|
|
4947
|
+
message: `Cache set for permission group by id: ${cacheKey}`
|
|
4948
|
+
});
|
|
4949
|
+
}).catch((err) => {
|
|
4950
|
+
logger16.log({
|
|
4951
|
+
level: "error",
|
|
4952
|
+
message: `Failed to set cache for permission group by id: ${err.message}`
|
|
4953
|
+
});
|
|
4954
|
+
});
|
|
4955
|
+
return result;
|
|
4956
|
+
} catch (error) {
|
|
4957
|
+
if (error instanceof AppError8) {
|
|
4958
|
+
throw error;
|
|
4959
|
+
} else {
|
|
4960
|
+
throw new InternalServerError15("Failed to get permission group.");
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
}
|
|
4964
|
+
async function getByKey(key, app) {
|
|
4965
|
+
const validation = Joi13.object({
|
|
4966
|
+
key: Joi13.string().required(),
|
|
4967
|
+
app: Joi13.string().optional().allow(null, "")
|
|
4968
|
+
});
|
|
4969
|
+
const { error } = validation.validate({ key, app });
|
|
4970
|
+
if (error) {
|
|
4971
|
+
throw new BadRequestError23("Invalid key.");
|
|
4972
|
+
}
|
|
4973
|
+
const query = { key };
|
|
4974
|
+
const cacheKeyOptions = { key, tag: "byKey" };
|
|
4975
|
+
if (app) {
|
|
4976
|
+
query.app = app;
|
|
4977
|
+
cacheKeyOptions.app = app;
|
|
4978
|
+
}
|
|
4979
|
+
const cacheKey = makeCacheKey11(namespace_collection, cacheKeyOptions);
|
|
4980
|
+
try {
|
|
4981
|
+
const cached = await repo.getCache(cacheKey);
|
|
4982
|
+
if (cached) {
|
|
4983
|
+
logger16.log({
|
|
4984
|
+
level: "info",
|
|
4985
|
+
message: `Cache hit for getById permission group: ${cacheKey}`
|
|
4986
|
+
});
|
|
4987
|
+
return cached;
|
|
4988
|
+
}
|
|
4989
|
+
const result = await repo.collection.findOne(query);
|
|
4990
|
+
repo.setCache(cacheKey, result, 300).then(() => {
|
|
4991
|
+
logger16.log({
|
|
4992
|
+
level: "info",
|
|
4993
|
+
message: `Cache set for permission group by key: ${cacheKey}`
|
|
4994
|
+
});
|
|
4995
|
+
}).catch((err) => {
|
|
4996
|
+
logger16.log({
|
|
4997
|
+
level: "error",
|
|
4998
|
+
message: `Failed to set cache for permission group by key: ${err.message}`
|
|
4999
|
+
});
|
|
5000
|
+
});
|
|
5001
|
+
return result;
|
|
5002
|
+
} catch (error2) {
|
|
5003
|
+
if (error2 instanceof AppError8) {
|
|
5004
|
+
throw error2;
|
|
5005
|
+
} else {
|
|
5006
|
+
throw new InternalServerError15("Failed to get permission group.");
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
}
|
|
5010
|
+
async function deleteById(_id, session) {
|
|
5011
|
+
try {
|
|
5012
|
+
_id = new ObjectId16(_id);
|
|
5013
|
+
} catch (error) {
|
|
5014
|
+
throw new BadRequestError23("Invalid ID.");
|
|
5015
|
+
}
|
|
5016
|
+
try {
|
|
5017
|
+
const res = await repo.collection.updateOne(
|
|
5018
|
+
{ _id },
|
|
5019
|
+
{ $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
|
|
5020
|
+
);
|
|
5021
|
+
repo.delCachedData();
|
|
5022
|
+
return res;
|
|
5023
|
+
} catch (error) {
|
|
5024
|
+
logger16.log({
|
|
5025
|
+
level: "error",
|
|
5026
|
+
message: error.message
|
|
5027
|
+
});
|
|
5028
|
+
if (error instanceof AppError8) {
|
|
5029
|
+
throw error;
|
|
5030
|
+
} else {
|
|
5031
|
+
throw new InternalServerError15("Failed to delete permission group.");
|
|
5032
|
+
}
|
|
5033
|
+
}
|
|
5034
|
+
}
|
|
5035
|
+
return {
|
|
5036
|
+
createIndexes,
|
|
5037
|
+
add,
|
|
5038
|
+
getAll,
|
|
5039
|
+
getById,
|
|
5040
|
+
getByKey,
|
|
5041
|
+
updateById,
|
|
5042
|
+
deleteById
|
|
5043
|
+
};
|
|
5044
|
+
}
|
|
5045
|
+
|
|
5046
|
+
// src/resources/permission/permission.group.service.ts
|
|
5047
|
+
import {
|
|
5048
|
+
AppError as AppError9,
|
|
5049
|
+
BadRequestError as BadRequestError24,
|
|
5050
|
+
InternalServerError as InternalServerError16,
|
|
5051
|
+
logger as logger17,
|
|
5052
|
+
useAtlas as useAtlas12
|
|
5053
|
+
} from "@eeplatform/nodejs-utils";
|
|
5054
|
+
function usePermissionGroupService() {
|
|
5055
|
+
const {
|
|
5056
|
+
updateById: _updateById,
|
|
5057
|
+
getById: _getById,
|
|
5058
|
+
deleteById: _deleteById,
|
|
5059
|
+
getByKey: _getByKey,
|
|
5060
|
+
add: _add
|
|
5061
|
+
} = usePermissionGroupRepo();
|
|
5062
|
+
const { getAll: getAllApps } = useAppRepo();
|
|
5063
|
+
const {
|
|
5064
|
+
countByGroup,
|
|
5065
|
+
getByKey: getPermissionByKey,
|
|
5066
|
+
add: addPermission
|
|
5067
|
+
} = usePermissionRepo();
|
|
5068
|
+
async function addDefaultModule() {
|
|
5069
|
+
const session = useAtlas12.getClient()?.startSession();
|
|
5070
|
+
if (!session) {
|
|
5071
|
+
throw new Error("Failed to start database session.");
|
|
5072
|
+
}
|
|
5073
|
+
try {
|
|
5074
|
+
session?.startTransaction();
|
|
5075
|
+
const apps = await getAllApps({
|
|
5076
|
+
limit: 20,
|
|
5077
|
+
type: ["default", "standard"]
|
|
5078
|
+
});
|
|
5079
|
+
if (apps && apps.items && apps.items.length) {
|
|
5080
|
+
const modules = [
|
|
5081
|
+
{
|
|
5082
|
+
key: "members",
|
|
5083
|
+
label: "Members",
|
|
5084
|
+
permissions: [
|
|
5085
|
+
{
|
|
5086
|
+
key: "members.view",
|
|
5087
|
+
name: "View Members",
|
|
5088
|
+
description: "Allow user to view members"
|
|
5089
|
+
},
|
|
5090
|
+
{
|
|
5091
|
+
key: "members.view.details",
|
|
5092
|
+
name: "View Member Details",
|
|
5093
|
+
description: "Allow user to view member details"
|
|
5094
|
+
},
|
|
5095
|
+
{
|
|
5096
|
+
key: "members.add",
|
|
5097
|
+
name: "Add Members",
|
|
5098
|
+
description: "Allow user to add new members"
|
|
5099
|
+
},
|
|
5100
|
+
{
|
|
5101
|
+
key: "members.edit.details",
|
|
5102
|
+
name: "Edit Member Details",
|
|
5103
|
+
description: "Allow user to edit member details"
|
|
5104
|
+
},
|
|
5105
|
+
{
|
|
5106
|
+
key: "members.delete",
|
|
5107
|
+
name: "Delete Members",
|
|
5108
|
+
description: "Allow user to delete members"
|
|
5109
|
+
}
|
|
5110
|
+
]
|
|
5111
|
+
},
|
|
5112
|
+
{
|
|
5113
|
+
key: "roles",
|
|
5114
|
+
label: "Roles",
|
|
5115
|
+
permissions: [
|
|
5116
|
+
{
|
|
5117
|
+
key: "roles.view",
|
|
5118
|
+
name: "View Roles",
|
|
5119
|
+
description: "Allow user to view roles"
|
|
5120
|
+
},
|
|
5121
|
+
{
|
|
5122
|
+
key: "roles.view.details",
|
|
5123
|
+
name: "View Role Details",
|
|
5124
|
+
description: "Allow user to view role details"
|
|
5125
|
+
},
|
|
5126
|
+
{
|
|
5127
|
+
key: "roles.add",
|
|
5128
|
+
name: "Add Roles",
|
|
5129
|
+
description: "Allow user to add new roles"
|
|
5130
|
+
},
|
|
5131
|
+
{
|
|
5132
|
+
key: "roles.edit.details",
|
|
5133
|
+
name: "Edit Role Details",
|
|
5134
|
+
description: "Allow user to edit role details"
|
|
5135
|
+
},
|
|
5136
|
+
{
|
|
5137
|
+
key: "roles.delete",
|
|
5138
|
+
name: "Delete Roles",
|
|
5139
|
+
description: "Allow user to delete roles"
|
|
5140
|
+
}
|
|
5141
|
+
]
|
|
5142
|
+
},
|
|
5143
|
+
{
|
|
5144
|
+
key: "invitations",
|
|
5145
|
+
label: "Invitations",
|
|
5146
|
+
permissions: [
|
|
5147
|
+
{
|
|
5148
|
+
key: "invitations.view",
|
|
5149
|
+
name: "View Invitations",
|
|
5150
|
+
description: "Allow user to view invitations"
|
|
5151
|
+
},
|
|
5152
|
+
{
|
|
5153
|
+
key: "invitations.view.details",
|
|
5154
|
+
name: "View Invitation Details",
|
|
5155
|
+
description: "Allow user to view invitation details"
|
|
5156
|
+
},
|
|
5157
|
+
{
|
|
5158
|
+
key: "invitations.send",
|
|
5159
|
+
name: "Send Invitations",
|
|
5160
|
+
description: "Allow user to send invitations"
|
|
5161
|
+
},
|
|
5162
|
+
{
|
|
5163
|
+
key: "invitations.revoke",
|
|
5164
|
+
name: "Revoke Invitations",
|
|
5165
|
+
description: "Allow user to revoke invitations"
|
|
5166
|
+
}
|
|
5167
|
+
]
|
|
5168
|
+
}
|
|
5169
|
+
];
|
|
5170
|
+
for (const app of apps.items) {
|
|
5171
|
+
for (const module of modules) {
|
|
5172
|
+
const existingGroup = await _getByKey(module.key, app.code);
|
|
5173
|
+
if (!existingGroup) {
|
|
5174
|
+
await _add({
|
|
5175
|
+
app: app.code,
|
|
5176
|
+
key: module.key,
|
|
5177
|
+
label: module.label
|
|
5178
|
+
});
|
|
5179
|
+
logger17.log({
|
|
5180
|
+
level: "info",
|
|
5181
|
+
message: `Default permission group added: ${app.code} - ${module.key}`
|
|
5182
|
+
});
|
|
5183
|
+
}
|
|
5184
|
+
for (const permission of module.permissions) {
|
|
5185
|
+
const existingPermission = await getPermissionByKey(
|
|
5186
|
+
permission.key,
|
|
5187
|
+
module.key,
|
|
5188
|
+
app.code
|
|
5189
|
+
);
|
|
5190
|
+
if (!existingPermission) {
|
|
5191
|
+
await addPermission({
|
|
5192
|
+
app: app.code,
|
|
5193
|
+
group: module.key,
|
|
5194
|
+
key: permission.key,
|
|
5195
|
+
name: permission.name,
|
|
5196
|
+
description: permission.description
|
|
5197
|
+
});
|
|
5198
|
+
}
|
|
5199
|
+
}
|
|
5200
|
+
}
|
|
5201
|
+
if (app.code === "admin") {
|
|
5202
|
+
const modules2 = [
|
|
5203
|
+
{
|
|
5204
|
+
key: "applications",
|
|
5205
|
+
label: "Applications",
|
|
5206
|
+
permissions: [
|
|
5207
|
+
{
|
|
5208
|
+
key: "applications.add",
|
|
5209
|
+
name: "Add Applications",
|
|
5210
|
+
description: "Allow user to add new applications"
|
|
5211
|
+
},
|
|
5212
|
+
{
|
|
5213
|
+
key: "applications.view",
|
|
5214
|
+
name: "View Applications",
|
|
5215
|
+
description: "Allow user to view applications"
|
|
5216
|
+
},
|
|
5217
|
+
{
|
|
5218
|
+
key: "applications.view.details",
|
|
5219
|
+
name: "View Application Details",
|
|
5220
|
+
description: "Allow user to view application details"
|
|
5221
|
+
},
|
|
5222
|
+
{
|
|
5223
|
+
key: "applications.edit",
|
|
5224
|
+
name: "Edit Applications",
|
|
5225
|
+
description: "Allow user to edit existing applications"
|
|
5226
|
+
},
|
|
5227
|
+
{
|
|
5228
|
+
key: "applications.update.details",
|
|
5229
|
+
name: "Update Application Details",
|
|
5230
|
+
description: "Allow user to update application details"
|
|
5231
|
+
},
|
|
5232
|
+
{
|
|
5233
|
+
key: "applications.delete",
|
|
5234
|
+
name: "Delete Applications",
|
|
5235
|
+
description: "Allow user to delete applications"
|
|
5236
|
+
}
|
|
5237
|
+
]
|
|
5238
|
+
},
|
|
5239
|
+
{
|
|
5240
|
+
key: "deped-ro",
|
|
5241
|
+
label: "Regional Offices",
|
|
5242
|
+
permissions: [
|
|
5243
|
+
{
|
|
5244
|
+
key: "deped-ro.add",
|
|
5245
|
+
name: "Add Regional Office",
|
|
5246
|
+
description: "Allow user to add new regional office"
|
|
5247
|
+
},
|
|
5248
|
+
{
|
|
5249
|
+
key: "deped-ro.view",
|
|
5250
|
+
name: "View Regional Offices",
|
|
5251
|
+
description: "Allow user to view regional offices"
|
|
5252
|
+
},
|
|
5253
|
+
{
|
|
5254
|
+
key: "deped-ro.view.details",
|
|
5255
|
+
name: "View Regional Office Details",
|
|
5256
|
+
description: "Allow user to view regional office details"
|
|
5257
|
+
},
|
|
5258
|
+
{
|
|
5259
|
+
key: "deped-ro.update.details",
|
|
5260
|
+
name: "Update Regional Office Details",
|
|
5261
|
+
description: "Allow user to update regional office details"
|
|
5262
|
+
},
|
|
5263
|
+
{
|
|
5264
|
+
key: "deped-ro.delete",
|
|
5265
|
+
name: "Delete Regional Office",
|
|
5266
|
+
description: "Allow user to delete regional office"
|
|
5267
|
+
}
|
|
5268
|
+
]
|
|
5269
|
+
},
|
|
5270
|
+
{
|
|
5271
|
+
key: "deped-sdo",
|
|
5272
|
+
label: "School Division Offices",
|
|
5273
|
+
permissions: [
|
|
5274
|
+
{
|
|
5275
|
+
key: "deped-sdo.add",
|
|
5276
|
+
name: "Add School Division Office",
|
|
5277
|
+
description: "Allow user to add new school division office"
|
|
5278
|
+
},
|
|
5279
|
+
{
|
|
5280
|
+
key: "deped-sdo.view",
|
|
5281
|
+
name: "View School Division Offices",
|
|
5282
|
+
description: "Allow user to view school division offices"
|
|
5283
|
+
},
|
|
5284
|
+
{
|
|
5285
|
+
key: "deped-sdo.view.details",
|
|
5286
|
+
name: "View School Division Office Details",
|
|
5287
|
+
description: "Allow user to view school division office details"
|
|
5288
|
+
},
|
|
5289
|
+
{
|
|
5290
|
+
key: "deped-sdo.update.details",
|
|
5291
|
+
name: "Update School Division Office Details",
|
|
5292
|
+
description: "Allow user to update school division office details"
|
|
5293
|
+
},
|
|
5294
|
+
{
|
|
5295
|
+
key: "deped-sdo.delete",
|
|
5296
|
+
name: "Delete School Division Office",
|
|
5297
|
+
description: "Allow user to delete school division office"
|
|
5298
|
+
}
|
|
5299
|
+
]
|
|
5300
|
+
},
|
|
5301
|
+
{
|
|
5302
|
+
key: "deped-school",
|
|
5303
|
+
label: "Schools",
|
|
5304
|
+
permissions: [
|
|
5305
|
+
{
|
|
5306
|
+
key: "deped-school.add",
|
|
5307
|
+
name: "Add School",
|
|
5308
|
+
description: "Allow user to add new school"
|
|
5309
|
+
},
|
|
5310
|
+
{
|
|
5311
|
+
key: "deped-school.view",
|
|
5312
|
+
name: "View Schools",
|
|
5313
|
+
description: "Allow user to view schools"
|
|
5314
|
+
},
|
|
5315
|
+
{
|
|
5316
|
+
key: "deped-school.view.details",
|
|
5317
|
+
name: "View School Details",
|
|
5318
|
+
description: "Allow user to view school details"
|
|
5319
|
+
},
|
|
5320
|
+
{
|
|
5321
|
+
key: "deped-school.update.details",
|
|
5322
|
+
name: "Update School Details",
|
|
5323
|
+
description: "Allow user to update school details"
|
|
5324
|
+
},
|
|
5325
|
+
{
|
|
5326
|
+
key: "deped-school.delete",
|
|
5327
|
+
name: "Delete School",
|
|
5328
|
+
description: "Allow user to delete school"
|
|
5329
|
+
}
|
|
5330
|
+
]
|
|
5331
|
+
},
|
|
5332
|
+
{
|
|
5333
|
+
key: "users",
|
|
5334
|
+
label: "Users",
|
|
5335
|
+
permissions: [
|
|
5336
|
+
{
|
|
5337
|
+
key: "users.add",
|
|
5338
|
+
name: "Add Users",
|
|
5339
|
+
description: "Allow user to add new users"
|
|
5340
|
+
},
|
|
5341
|
+
{
|
|
5342
|
+
key: "users.view",
|
|
5343
|
+
name: "View Users",
|
|
5344
|
+
description: "Allow user to view users"
|
|
5345
|
+
},
|
|
5346
|
+
{
|
|
5347
|
+
key: "users.view.details",
|
|
5348
|
+
name: "View User Details",
|
|
5349
|
+
description: "Allow user to view user details"
|
|
5350
|
+
},
|
|
5351
|
+
{
|
|
5352
|
+
key: "users.edit.status",
|
|
5353
|
+
name: "Edit User Status",
|
|
5354
|
+
description: "Allow user to edit user status"
|
|
5355
|
+
},
|
|
5356
|
+
{
|
|
5357
|
+
key: "users.delete",
|
|
5358
|
+
name: "Delete Users",
|
|
5359
|
+
description: "Allow user to delete users"
|
|
5360
|
+
}
|
|
5361
|
+
]
|
|
5362
|
+
}
|
|
5363
|
+
];
|
|
5364
|
+
for (const module of modules2) {
|
|
5365
|
+
const existingGroup = await _getByKey(module.key, app.code);
|
|
5366
|
+
if (!existingGroup) {
|
|
5367
|
+
await _add({
|
|
5368
|
+
app: app.code,
|
|
5369
|
+
key: module.key,
|
|
5370
|
+
label: module.label
|
|
5371
|
+
});
|
|
5372
|
+
logger17.log({
|
|
5373
|
+
level: "info",
|
|
5374
|
+
message: `Default permission group added: ${app.code} - ${module.key}`
|
|
5375
|
+
});
|
|
5376
|
+
}
|
|
5377
|
+
for (const permission of module.permissions) {
|
|
5378
|
+
const existingPermission = await getPermissionByKey(
|
|
5379
|
+
permission.key,
|
|
5380
|
+
module.key
|
|
5381
|
+
);
|
|
5382
|
+
if (!existingPermission) {
|
|
5383
|
+
await addPermission({
|
|
5384
|
+
app: app.code,
|
|
5385
|
+
group: module.key,
|
|
5386
|
+
key: permission.key,
|
|
5387
|
+
name: permission.name,
|
|
5388
|
+
description: permission.description
|
|
5389
|
+
});
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5395
|
+
await session.commitTransaction();
|
|
5396
|
+
}
|
|
5397
|
+
logger17.log({
|
|
5398
|
+
level: "info",
|
|
5399
|
+
message: "Default permission groups added successfully."
|
|
5400
|
+
});
|
|
5401
|
+
return;
|
|
5402
|
+
} catch (error) {
|
|
5403
|
+
console.log(error);
|
|
5404
|
+
await session.abortTransaction();
|
|
5405
|
+
throw error;
|
|
5406
|
+
} finally {
|
|
5407
|
+
await session.endSession();
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
async function deleteById(id) {
|
|
5411
|
+
const permission = await _getById(id);
|
|
5412
|
+
if (!permission) {
|
|
5413
|
+
throw new Error("Permission Group not found.");
|
|
5414
|
+
}
|
|
5415
|
+
const associatedPermissionsCount = await countByGroup(permission.key);
|
|
5416
|
+
if (associatedPermissionsCount > 0) {
|
|
5417
|
+
throw new BadRequestError24(
|
|
5418
|
+
"Cannot delete Permission Group with associated Permissions."
|
|
5419
|
+
);
|
|
5420
|
+
}
|
|
5421
|
+
try {
|
|
5422
|
+
await _deleteById(id);
|
|
5423
|
+
return "Permission deleted successfully.";
|
|
5424
|
+
} catch (error) {
|
|
5425
|
+
if (error instanceof AppError9) {
|
|
5426
|
+
throw error;
|
|
5427
|
+
} else {
|
|
5428
|
+
throw new InternalServerError16("Failed to delete Permission Group.");
|
|
5429
|
+
}
|
|
5430
|
+
}
|
|
5431
|
+
}
|
|
5432
|
+
return {
|
|
5433
|
+
addDefaultModule,
|
|
5434
|
+
deleteById
|
|
5435
|
+
};
|
|
5436
|
+
}
|
|
5437
|
+
|
|
5438
|
+
// src/resources/permission/permission.group.controller.ts
|
|
5439
|
+
import { BadRequestError as BadRequestError25, logger as logger18 } from "@eeplatform/nodejs-utils";
|
|
5440
|
+
import Joi14 from "joi";
|
|
5441
|
+
function usePermissionGroupController() {
|
|
5442
|
+
const {
|
|
5443
|
+
getAll: _getAll,
|
|
5444
|
+
getById: _getById,
|
|
5445
|
+
add: _add,
|
|
5446
|
+
updateById: _updateById
|
|
5447
|
+
} = usePermissionGroupRepo();
|
|
5448
|
+
const { deleteById: _deleteById } = usePermissionGroupService();
|
|
5449
|
+
async function add(req, res, next) {
|
|
5450
|
+
const value = req.body;
|
|
5451
|
+
const { error } = schemaPermissionGroup.validate(value);
|
|
5452
|
+
if (error) {
|
|
5453
|
+
next(new BadRequestError25(error.message));
|
|
5454
|
+
logger18.info(`Controller: ${error.message}`);
|
|
5455
|
+
return;
|
|
5456
|
+
}
|
|
5457
|
+
try {
|
|
5458
|
+
const result = await _add(value);
|
|
5459
|
+
res.json(result);
|
|
5460
|
+
return;
|
|
5461
|
+
} catch (error2) {
|
|
5462
|
+
next(error2);
|
|
5463
|
+
}
|
|
5464
|
+
}
|
|
5465
|
+
async function getAll(req, res, next) {
|
|
5466
|
+
const query = req.query;
|
|
5467
|
+
const validation = Joi14.object({
|
|
5468
|
+
page: Joi14.number().min(1).optional().allow("", null),
|
|
5469
|
+
limit: Joi14.number().min(1).optional().allow("", null),
|
|
5470
|
+
search: Joi14.string().optional().allow("", null),
|
|
5471
|
+
app: Joi14.string().optional().allow("", null),
|
|
5472
|
+
status: Joi14.string().optional().allow("", null)
|
|
5473
|
+
});
|
|
5474
|
+
const { error } = validation.validate(query);
|
|
5475
|
+
if (error) {
|
|
5476
|
+
next(new BadRequestError25(error.message));
|
|
5477
|
+
return;
|
|
5478
|
+
}
|
|
5479
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
5480
|
+
let limit = parseInt(req.query.limit) ?? 20;
|
|
5481
|
+
limit = isNaN(limit) ? 20 : limit;
|
|
5482
|
+
const sort = req.query.sort ? String(req.query.sort).split(",") : "";
|
|
5483
|
+
const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
|
|
5484
|
+
const sortObj = {};
|
|
5485
|
+
if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
|
|
5486
|
+
sort.forEach((field, index) => {
|
|
5487
|
+
sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
|
|
5488
|
+
});
|
|
5489
|
+
}
|
|
5490
|
+
const app = req.query.app ?? "";
|
|
5491
|
+
const search = req.query.search ?? "";
|
|
5492
|
+
const status = req.query.status ?? "active";
|
|
5493
|
+
try {
|
|
5494
|
+
const buildings = await _getAll({
|
|
5495
|
+
page,
|
|
5496
|
+
limit,
|
|
5497
|
+
sort: sortObj,
|
|
5498
|
+
app,
|
|
5499
|
+
search,
|
|
5500
|
+
status
|
|
5501
|
+
});
|
|
5502
|
+
res.json(buildings);
|
|
5503
|
+
return;
|
|
5504
|
+
} catch (error2) {
|
|
5505
|
+
next(error2);
|
|
5506
|
+
}
|
|
5507
|
+
}
|
|
5508
|
+
async function getById(req, res, next) {
|
|
5509
|
+
const id = req.params.id;
|
|
5510
|
+
const validation = Joi14.object({
|
|
5511
|
+
id: Joi14.string().hex().required()
|
|
5512
|
+
});
|
|
5513
|
+
const { error } = validation.validate({ id });
|
|
5514
|
+
if (error) {
|
|
5515
|
+
next(new BadRequestError25(error.message));
|
|
5516
|
+
return;
|
|
5517
|
+
}
|
|
5518
|
+
try {
|
|
5519
|
+
const data = await _getById(id);
|
|
5520
|
+
res.json({
|
|
5521
|
+
message: "Successfully retrieved permission group.",
|
|
5522
|
+
data
|
|
5523
|
+
});
|
|
5524
|
+
return;
|
|
5525
|
+
} catch (error2) {
|
|
5526
|
+
next(error2);
|
|
5527
|
+
}
|
|
5528
|
+
}
|
|
5529
|
+
async function deleteById(req, res, next) {
|
|
5530
|
+
const id = req.params.id;
|
|
5531
|
+
const validation = Joi14.object({
|
|
5532
|
+
id: Joi14.string().hex().required()
|
|
5533
|
+
});
|
|
5534
|
+
const { error } = validation.validate({ id });
|
|
5535
|
+
if (error) {
|
|
5536
|
+
next(new BadRequestError25(error.message));
|
|
5537
|
+
return;
|
|
5538
|
+
}
|
|
5539
|
+
try {
|
|
5540
|
+
const message = await _deleteById(id);
|
|
5541
|
+
res.json(message);
|
|
5542
|
+
return;
|
|
5543
|
+
} catch (error2) {
|
|
5544
|
+
next(error2);
|
|
5545
|
+
}
|
|
5546
|
+
}
|
|
5547
|
+
async function updateById(req, res, next) {
|
|
5548
|
+
const id = req.params.id;
|
|
5549
|
+
const { error: errorId } = Joi14.string().hex().required().validate(id);
|
|
5550
|
+
if (errorId) {
|
|
5551
|
+
next(new BadRequestError25(errorId.message));
|
|
5552
|
+
return;
|
|
5553
|
+
}
|
|
5554
|
+
const payload = req.body;
|
|
5555
|
+
const { error } = schemaPermissionGroupUpdate.validate(payload);
|
|
5556
|
+
if (error) {
|
|
5557
|
+
next(new BadRequestError25(error.message));
|
|
5558
|
+
return;
|
|
5559
|
+
}
|
|
5560
|
+
try {
|
|
5561
|
+
const message = await _updateById(id, payload);
|
|
5562
|
+
res.json(message);
|
|
5563
|
+
return;
|
|
5564
|
+
} catch (error2) {
|
|
5565
|
+
next(error2);
|
|
5566
|
+
}
|
|
5567
|
+
}
|
|
5568
|
+
return {
|
|
5569
|
+
add,
|
|
5570
|
+
getAll,
|
|
5571
|
+
getById,
|
|
5572
|
+
deleteById,
|
|
5573
|
+
updateById
|
|
5574
|
+
};
|
|
5575
|
+
}
|
|
5576
|
+
|
|
5577
|
+
// src/resources/file/file.service.ts
|
|
5578
|
+
import { logger as logger19, useS3 as useS32, useAtlas as useAtlas13 } from "@eeplatform/nodejs-utils";
|
|
5579
|
+
import cron from "node-cron";
|
|
5580
|
+
import * as fs from "fs";
|
|
5581
|
+
function useFileService() {
|
|
5582
|
+
const {
|
|
5583
|
+
createFile: _createFile,
|
|
5584
|
+
deleteFileById,
|
|
5585
|
+
getAllDraftedFiles
|
|
5586
|
+
} = useFileRepo();
|
|
5587
|
+
const s3 = new useS32({
|
|
5588
|
+
accessKeyId: SPACES_ACCESS_KEY,
|
|
5589
|
+
secretAccessKey: SPACES_SECRET_KEY,
|
|
5590
|
+
endpoint: SPACES_ENDPOINT,
|
|
5591
|
+
region: SPACES_REGION,
|
|
5592
|
+
bucket: SPACES_BUCKET,
|
|
5593
|
+
forcePathStyle: true
|
|
5594
|
+
});
|
|
5595
|
+
async function createFile(value) {
|
|
5596
|
+
const session = useAtlas13.getClient()?.startSession();
|
|
5597
|
+
session?.startTransaction();
|
|
5598
|
+
const file = {
|
|
5599
|
+
name: value.originalname,
|
|
5600
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5601
|
+
};
|
|
5602
|
+
try {
|
|
5603
|
+
const id = await _createFile(file, session);
|
|
5604
|
+
const fileBuffer = value.buffer || await fs.promises.readFile(value.path);
|
|
5605
|
+
await s3.uploadObject({
|
|
5606
|
+
key: id,
|
|
5607
|
+
body: fileBuffer,
|
|
5608
|
+
contentType: value.mimetype
|
|
5609
|
+
});
|
|
5610
|
+
await session?.commitTransaction();
|
|
5611
|
+
if (value.path) {
|
|
5612
|
+
try {
|
|
5613
|
+
await fs.promises.unlink(value.path);
|
|
5614
|
+
} catch (cleanupError) {
|
|
5615
|
+
console.error(
|
|
5616
|
+
`Failed to cleanup temporary file ${value.path}:`,
|
|
5617
|
+
cleanupError
|
|
5618
|
+
);
|
|
5619
|
+
}
|
|
5620
|
+
}
|
|
5621
|
+
return id;
|
|
5622
|
+
} catch (error) {
|
|
5623
|
+
await session?.abortTransaction();
|
|
5624
|
+
throw error;
|
|
5625
|
+
} finally {
|
|
5626
|
+
session?.endSession();
|
|
5627
|
+
}
|
|
5628
|
+
}
|
|
5629
|
+
async function deleteFile(id) {
|
|
5630
|
+
const session = useAtlas13.getClient()?.startSession();
|
|
5631
|
+
session?.startTransaction();
|
|
5632
|
+
try {
|
|
5633
|
+
await deleteFileById(id, session);
|
|
5634
|
+
await s3.deleteObject(id);
|
|
5635
|
+
await session?.commitTransaction();
|
|
5636
|
+
return "File deleted successfully";
|
|
5637
|
+
} catch (error) {
|
|
5638
|
+
await session?.abortTransaction();
|
|
5639
|
+
throw error;
|
|
5640
|
+
} finally {
|
|
5641
|
+
session?.endSession();
|
|
5642
|
+
}
|
|
5643
|
+
}
|
|
5644
|
+
function deleteDraft() {
|
|
5645
|
+
cron.schedule("0 0 * * *", async () => {
|
|
5646
|
+
const files = await getAllDraftedFiles();
|
|
5647
|
+
for (let index = 0; index < files.length; index++) {
|
|
5648
|
+
const file = files[index];
|
|
5649
|
+
try {
|
|
5650
|
+
await deleteFile(file._id.toString());
|
|
5651
|
+
await logger19.log({
|
|
5652
|
+
level: "info",
|
|
5653
|
+
message: "Successfully deleted draft files."
|
|
5654
|
+
});
|
|
5655
|
+
} catch (error) {
|
|
5656
|
+
logger19.log({
|
|
5657
|
+
level: "info",
|
|
5658
|
+
message: "Successfully deleted draft files."
|
|
5659
|
+
});
|
|
5660
|
+
return;
|
|
5661
|
+
}
|
|
5662
|
+
}
|
|
5663
|
+
});
|
|
5664
|
+
}
|
|
5665
|
+
return {
|
|
5666
|
+
createFile,
|
|
5667
|
+
deleteFile,
|
|
5668
|
+
deleteDraft
|
|
5669
|
+
};
|
|
5670
|
+
}
|
|
5671
|
+
|
|
5672
|
+
// src/resources/file/file.controller.ts
|
|
5673
|
+
import {
|
|
5674
|
+
AppError as AppError10,
|
|
5675
|
+
BadRequestError as BadRequestError26,
|
|
5676
|
+
InternalServerError as InternalServerError17
|
|
5677
|
+
} from "@eeplatform/nodejs-utils";
|
|
5678
|
+
import Joi15 from "joi";
|
|
5679
|
+
function useFileController() {
|
|
5680
|
+
const { createFile, deleteFile: _deleteFile } = useFileService();
|
|
5681
|
+
async function upload(req, res, next) {
|
|
5682
|
+
if (!req.file) {
|
|
5683
|
+
res.status(400).send("File is required!");
|
|
5684
|
+
return;
|
|
5685
|
+
}
|
|
5686
|
+
try {
|
|
5687
|
+
const id = await createFile(req.file);
|
|
5688
|
+
res.json({ message: "Successfully uploaded file", id });
|
|
5689
|
+
return;
|
|
5690
|
+
} catch (error) {
|
|
5691
|
+
if (error instanceof AppError10) {
|
|
5692
|
+
next(error);
|
|
5693
|
+
} else {
|
|
5694
|
+
next(new InternalServerError17(error));
|
|
5695
|
+
}
|
|
5696
|
+
}
|
|
5697
|
+
}
|
|
5698
|
+
async function deleteFile(req, res, next) {
|
|
5699
|
+
const id = req.params.id;
|
|
5700
|
+
const validation = Joi15.string().required();
|
|
5701
|
+
const { error } = validation.validate(id);
|
|
5702
|
+
if (error) {
|
|
5703
|
+
next(new BadRequestError26(error.message));
|
|
5704
|
+
}
|
|
5705
|
+
try {
|
|
5706
|
+
const message = await _deleteFile(id);
|
|
5707
|
+
res.json({ message });
|
|
5708
|
+
return;
|
|
5709
|
+
} catch (error2) {
|
|
5710
|
+
if (error2 instanceof AppError10) {
|
|
5711
|
+
next(error2);
|
|
5712
|
+
} else {
|
|
5713
|
+
next(new InternalServerError17(error2));
|
|
5714
|
+
}
|
|
5715
|
+
}
|
|
5716
|
+
}
|
|
5717
|
+
return {
|
|
5718
|
+
upload,
|
|
5719
|
+
deleteFile
|
|
5720
|
+
};
|
|
5721
|
+
}
|
|
5722
|
+
|
|
5723
|
+
// src/resources/role/role.controller.ts
|
|
5724
|
+
import Joi18 from "joi";
|
|
5725
|
+
import { BadRequestError as BadRequestError29 } from "@eeplatform/nodejs-utils";
|
|
5726
|
+
|
|
5727
|
+
// src/resources/role/role.service.ts
|
|
5728
|
+
import {
|
|
5729
|
+
AppError as AppError11,
|
|
5730
|
+
BadRequestError as BadRequestError28,
|
|
5731
|
+
InternalServerError as InternalServerError18
|
|
5732
|
+
} from "@eeplatform/nodejs-utils";
|
|
5733
|
+
import Joi17 from "joi";
|
|
5734
|
+
|
|
5735
|
+
// src/resources/member/member.controller.ts
|
|
5736
|
+
import Joi16 from "joi";
|
|
5737
|
+
import { BadRequestError as BadRequestError27 } from "@eeplatform/nodejs-utils";
|
|
5738
|
+
function useMemberController() {
|
|
5739
|
+
const {
|
|
5740
|
+
getByUserId: _getByUserId,
|
|
5741
|
+
getAll: _getAll,
|
|
5742
|
+
getOrgsByMembership: _getOrgsByMembership,
|
|
5743
|
+
updateStatusByUserId: _updateStatusByUserId,
|
|
5744
|
+
getByUserType: _getByUserType
|
|
5745
|
+
} = useMemberRepo();
|
|
5746
|
+
async function getByUserId(req, res, next) {
|
|
5747
|
+
const userId = req.params.id;
|
|
5748
|
+
const validation = Joi16.object({
|
|
5749
|
+
id: Joi16.string().hex().required()
|
|
5750
|
+
});
|
|
5751
|
+
const { error } = validation.validate({ id: userId });
|
|
5752
|
+
if (error) {
|
|
5753
|
+
next(new BadRequestError27(error.message));
|
|
5754
|
+
return;
|
|
5755
|
+
}
|
|
5756
|
+
try {
|
|
5757
|
+
const member = await _getByUserId(userId);
|
|
5758
|
+
if (!member) {
|
|
5759
|
+
res.status(404).json({ message: "Member not found." });
|
|
5760
|
+
return;
|
|
5761
|
+
}
|
|
5762
|
+
res.json(member);
|
|
5763
|
+
} catch (error2) {
|
|
5764
|
+
next(error2);
|
|
5765
|
+
}
|
|
5766
|
+
}
|
|
5767
|
+
async function getByUserType(req, res, next) {
|
|
5768
|
+
const validation = Joi16.object({
|
|
5769
|
+
org: Joi16.string().hex().optional().allow("", null),
|
|
5770
|
+
user: Joi16.string().hex().required(),
|
|
5771
|
+
type: Joi16.string().required()
|
|
5772
|
+
});
|
|
5773
|
+
const { error } = validation.validate({ ...req.params, ...req.query });
|
|
5774
|
+
if (error) {
|
|
5775
|
+
next(new BadRequestError27(error.message));
|
|
5776
|
+
return;
|
|
5777
|
+
}
|
|
5778
|
+
const orgId = req.query.org;
|
|
5779
|
+
const userId = req.params.user;
|
|
5780
|
+
const type = req.params.type;
|
|
5781
|
+
try {
|
|
5782
|
+
const member = await _getByUserType(userId, type, orgId);
|
|
5783
|
+
if (!member) {
|
|
5784
|
+
res.status(404).json({ message: "Member not found." });
|
|
5785
|
+
return;
|
|
5786
|
+
}
|
|
5787
|
+
res.json(member);
|
|
5788
|
+
} catch (error2) {
|
|
5789
|
+
next(error2);
|
|
5790
|
+
}
|
|
5791
|
+
}
|
|
5792
|
+
async function getAll(req, res, next) {
|
|
5793
|
+
const limit = Number(req.query.limit) ?? 10;
|
|
5794
|
+
const search = req.query.search ?? "";
|
|
5795
|
+
const page = Number(req.query.page) ?? 1;
|
|
5796
|
+
const user = req.query.user ?? "";
|
|
5797
|
+
const org = req.query.org ?? "";
|
|
5798
|
+
const type = req.query.type ?? "main";
|
|
5799
|
+
const status = req.query.status ?? "active";
|
|
5800
|
+
const validation = Joi16.object({
|
|
5801
|
+
limit: Joi16.number().min(10).max(300).required(),
|
|
5802
|
+
search: Joi16.string().optional().allow("", null),
|
|
5803
|
+
page: Joi16.number().required(),
|
|
5804
|
+
user: Joi16.string().hex().optional().allow("", null),
|
|
5805
|
+
org: Joi16.string().hex().optional().allow("", null),
|
|
5806
|
+
type: Joi16.string().required(),
|
|
5807
|
+
status: Joi16.string().required()
|
|
5808
|
+
});
|
|
5809
|
+
const { error } = validation.validate({
|
|
5810
|
+
search,
|
|
5811
|
+
page,
|
|
5812
|
+
user,
|
|
5813
|
+
org,
|
|
5814
|
+
type,
|
|
5815
|
+
limit,
|
|
5816
|
+
status
|
|
5817
|
+
});
|
|
5818
|
+
if (error) {
|
|
5819
|
+
next(new BadRequestError27(error.message));
|
|
5820
|
+
return;
|
|
5821
|
+
}
|
|
5822
|
+
try {
|
|
5823
|
+
const items = await _getAll({
|
|
5824
|
+
search,
|
|
5825
|
+
page,
|
|
5826
|
+
user,
|
|
5827
|
+
org,
|
|
5828
|
+
type,
|
|
5829
|
+
limit,
|
|
5830
|
+
status
|
|
5831
|
+
});
|
|
5832
|
+
res.json(items);
|
|
5833
|
+
return;
|
|
5834
|
+
} catch (error2) {
|
|
5835
|
+
next(error2);
|
|
5836
|
+
}
|
|
5837
|
+
}
|
|
5838
|
+
async function getOrgsByMembership(req, res, next) {
|
|
5839
|
+
const limit = Number(req.query.limit) ?? 10;
|
|
5840
|
+
const search = req.query.search ?? "";
|
|
5841
|
+
const page = Number(req.query.page) ?? 1;
|
|
5842
|
+
const user = req.query.user ?? "";
|
|
5843
|
+
const validation = Joi16.object({
|
|
5844
|
+
limit: Joi16.number().min(10).max(50).required(),
|
|
5845
|
+
search: Joi16.string().optional().allow("", null),
|
|
5846
|
+
page: Joi16.number().required(),
|
|
5847
|
+
user: Joi16.string().hex().optional().allow("", null)
|
|
5848
|
+
});
|
|
5849
|
+
const { error } = validation.validate({
|
|
5850
|
+
search,
|
|
5851
|
+
page,
|
|
5852
|
+
user,
|
|
3844
5853
|
limit
|
|
3845
5854
|
});
|
|
3846
5855
|
if (error) {
|
|
3847
|
-
next(new
|
|
5856
|
+
next(new BadRequestError27(error.message));
|
|
3848
5857
|
}
|
|
3849
5858
|
try {
|
|
3850
5859
|
const items = await _getOrgsByMembership({
|
|
@@ -3860,13 +5869,13 @@ function useMemberController() {
|
|
|
3860
5869
|
}
|
|
3861
5870
|
}
|
|
3862
5871
|
async function updateStatusByUserId(req, res, next) {
|
|
3863
|
-
const validation =
|
|
3864
|
-
id:
|
|
3865
|
-
status:
|
|
5872
|
+
const validation = Joi16.object({
|
|
5873
|
+
id: Joi16.string().hex().required(),
|
|
5874
|
+
status: Joi16.string().valid("active", "suspended", "deleted").required()
|
|
3866
5875
|
});
|
|
3867
5876
|
const { error } = validation.validate(req.params);
|
|
3868
5877
|
if (error) {
|
|
3869
|
-
next(new
|
|
5878
|
+
next(new BadRequestError27(error.message));
|
|
3870
5879
|
return;
|
|
3871
5880
|
}
|
|
3872
5881
|
const id = req.params.id;
|
|
@@ -3892,26 +5901,26 @@ function useRoleService() {
|
|
|
3892
5901
|
const { getByOrg } = useMemberRepo();
|
|
3893
5902
|
const { deleteRole, getRoleById } = useRoleRepo();
|
|
3894
5903
|
async function deleteById(_id) {
|
|
3895
|
-
const { error } =
|
|
5904
|
+
const { error } = Joi17.string().hex().length(24).validate(_id);
|
|
3896
5905
|
if (error) {
|
|
3897
|
-
throw new
|
|
5906
|
+
throw new BadRequestError28("Invalid Role ID");
|
|
3898
5907
|
}
|
|
3899
5908
|
try {
|
|
3900
5909
|
const role = await getRoleById(_id);
|
|
3901
5910
|
if (!role) {
|
|
3902
|
-
throw new
|
|
5911
|
+
throw new BadRequestError28("Role not found");
|
|
3903
5912
|
}
|
|
3904
5913
|
const org = await getByOrg(String(role.id));
|
|
3905
5914
|
if (org) {
|
|
3906
|
-
throw new
|
|
5915
|
+
throw new BadRequestError28("Cannot delete role assigned to members");
|
|
3907
5916
|
}
|
|
3908
5917
|
await deleteRole(_id);
|
|
3909
5918
|
return "Role deleted successfully";
|
|
3910
5919
|
} catch (error2) {
|
|
3911
|
-
if (error2 instanceof
|
|
5920
|
+
if (error2 instanceof AppError11) {
|
|
3912
5921
|
throw error2;
|
|
3913
5922
|
}
|
|
3914
|
-
throw new
|
|
5923
|
+
throw new InternalServerError18("Failed to delete role");
|
|
3915
5924
|
}
|
|
3916
5925
|
}
|
|
3917
5926
|
return {
|
|
@@ -3931,15 +5940,15 @@ function useRoleController() {
|
|
|
3931
5940
|
} = useRoleRepo();
|
|
3932
5941
|
async function createRole(req, res, next) {
|
|
3933
5942
|
const payload = req.body;
|
|
3934
|
-
const validation =
|
|
3935
|
-
name:
|
|
3936
|
-
permissions:
|
|
3937
|
-
type:
|
|
3938
|
-
id:
|
|
5943
|
+
const validation = Joi18.object({
|
|
5944
|
+
name: Joi18.string().required(),
|
|
5945
|
+
permissions: Joi18.array().items(Joi18.string()).required(),
|
|
5946
|
+
type: Joi18.string().valid("school", "division", "region", "account").required(),
|
|
5947
|
+
id: Joi18.string().hex().optional().allow("", null)
|
|
3939
5948
|
});
|
|
3940
5949
|
const { error } = validation.validate(payload);
|
|
3941
5950
|
if (error) {
|
|
3942
|
-
next(new
|
|
5951
|
+
next(new BadRequestError29(error.message));
|
|
3943
5952
|
return;
|
|
3944
5953
|
}
|
|
3945
5954
|
try {
|
|
@@ -3956,16 +5965,16 @@ function useRoleController() {
|
|
|
3956
5965
|
const limit = parseInt(req.query.limit ?? "10");
|
|
3957
5966
|
const type = req.query.type ?? "";
|
|
3958
5967
|
const id = req.query.id ?? "";
|
|
3959
|
-
const validation =
|
|
3960
|
-
search:
|
|
3961
|
-
page:
|
|
3962
|
-
limit:
|
|
3963
|
-
type:
|
|
3964
|
-
id:
|
|
5968
|
+
const validation = Joi18.object({
|
|
5969
|
+
search: Joi18.string().optional().allow("", null),
|
|
5970
|
+
page: Joi18.number().required(),
|
|
5971
|
+
limit: Joi18.number().required(),
|
|
5972
|
+
type: Joi18.string().optional().allow("", null),
|
|
5973
|
+
id: Joi18.string().hex().optional().allow("", null)
|
|
3965
5974
|
});
|
|
3966
5975
|
const { error } = validation.validate({ search, page, limit, type, id });
|
|
3967
5976
|
if (error) {
|
|
3968
|
-
next(new
|
|
5977
|
+
next(new BadRequestError29(error.message));
|
|
3969
5978
|
return;
|
|
3970
5979
|
}
|
|
3971
5980
|
try {
|
|
@@ -3978,12 +5987,12 @@ function useRoleController() {
|
|
|
3978
5987
|
}
|
|
3979
5988
|
async function getRoleByUserId(req, res, next) {
|
|
3980
5989
|
const userId = req.params.userId;
|
|
3981
|
-
const validation =
|
|
3982
|
-
userId:
|
|
5990
|
+
const validation = Joi18.object({
|
|
5991
|
+
userId: Joi18.string().required()
|
|
3983
5992
|
});
|
|
3984
5993
|
const { error } = validation.validate({ userId });
|
|
3985
5994
|
if (error) {
|
|
3986
|
-
next(new
|
|
5995
|
+
next(new BadRequestError29(error.message));
|
|
3987
5996
|
return;
|
|
3988
5997
|
}
|
|
3989
5998
|
try {
|
|
@@ -3996,12 +6005,12 @@ function useRoleController() {
|
|
|
3996
6005
|
}
|
|
3997
6006
|
async function getRoleById(req, res, next) {
|
|
3998
6007
|
const _id = req.params.id;
|
|
3999
|
-
const validation =
|
|
4000
|
-
_id:
|
|
6008
|
+
const validation = Joi18.object({
|
|
6009
|
+
_id: Joi18.string().hex().required()
|
|
4001
6010
|
});
|
|
4002
6011
|
const { error } = validation.validate({ _id });
|
|
4003
6012
|
if (error) {
|
|
4004
|
-
next(new
|
|
6013
|
+
next(new BadRequestError29(error.message));
|
|
4005
6014
|
return;
|
|
4006
6015
|
}
|
|
4007
6016
|
try {
|
|
@@ -4016,14 +6025,14 @@ function useRoleController() {
|
|
|
4016
6025
|
const _id = req.params.id;
|
|
4017
6026
|
const name = req.body.name ?? "";
|
|
4018
6027
|
const permissions = req.body.permissions ?? [];
|
|
4019
|
-
const validation =
|
|
4020
|
-
_id:
|
|
4021
|
-
name:
|
|
4022
|
-
permissions:
|
|
6028
|
+
const validation = Joi18.object({
|
|
6029
|
+
_id: Joi18.string().required(),
|
|
6030
|
+
name: Joi18.string().required(),
|
|
6031
|
+
permissions: Joi18.array().items(Joi18.string()).required()
|
|
4023
6032
|
});
|
|
4024
6033
|
const { error } = validation.validate({ _id, name, permissions });
|
|
4025
6034
|
if (error) {
|
|
4026
|
-
next(new
|
|
6035
|
+
next(new BadRequestError29(error.message));
|
|
4027
6036
|
return;
|
|
4028
6037
|
}
|
|
4029
6038
|
try {
|
|
@@ -4037,13 +6046,13 @@ function useRoleController() {
|
|
|
4037
6046
|
async function updatePermissionsById(req, res, next) {
|
|
4038
6047
|
const _id = req.params.id;
|
|
4039
6048
|
const permissions = req.body.permissions ?? [];
|
|
4040
|
-
const validation =
|
|
4041
|
-
_id:
|
|
4042
|
-
permissions:
|
|
6049
|
+
const validation = Joi18.object({
|
|
6050
|
+
_id: Joi18.string().required(),
|
|
6051
|
+
permissions: Joi18.array().items(Joi18.string()).required()
|
|
4043
6052
|
});
|
|
4044
6053
|
const { error } = validation.validate({ _id, permissions });
|
|
4045
6054
|
if (error) {
|
|
4046
|
-
next(new
|
|
6055
|
+
next(new BadRequestError29(error.message));
|
|
4047
6056
|
return;
|
|
4048
6057
|
}
|
|
4049
6058
|
try {
|
|
@@ -4057,12 +6066,12 @@ function useRoleController() {
|
|
|
4057
6066
|
const { deleteById } = useRoleService();
|
|
4058
6067
|
async function deleteRole(req, res, next) {
|
|
4059
6068
|
const _id = req.params.id;
|
|
4060
|
-
const validation =
|
|
4061
|
-
_id:
|
|
6069
|
+
const validation = Joi18.object({
|
|
6070
|
+
_id: Joi18.string().required()
|
|
4062
6071
|
});
|
|
4063
6072
|
const { error } = validation.validate({ _id });
|
|
4064
6073
|
if (error) {
|
|
4065
|
-
next(new
|
|
6074
|
+
next(new BadRequestError29(error.message));
|
|
4066
6075
|
return;
|
|
4067
6076
|
}
|
|
4068
6077
|
try {
|
|
@@ -4084,159 +6093,13 @@ function useRoleController() {
|
|
|
4084
6093
|
};
|
|
4085
6094
|
}
|
|
4086
6095
|
|
|
4087
|
-
// src/resources/file/file.service.ts
|
|
4088
|
-
import { logger as logger11, useS3 as useS32, useAtlas as useAtlas11 } from "@eeplatform/nodejs-utils";
|
|
4089
|
-
import cron from "node-cron";
|
|
4090
|
-
import * as fs from "fs";
|
|
4091
|
-
function useFileService() {
|
|
4092
|
-
const {
|
|
4093
|
-
createFile: _createFile,
|
|
4094
|
-
deleteFileById,
|
|
4095
|
-
getAllDraftedFiles
|
|
4096
|
-
} = useFileRepo();
|
|
4097
|
-
const s3 = new useS32({
|
|
4098
|
-
accessKeyId: SPACES_ACCESS_KEY,
|
|
4099
|
-
secretAccessKey: SPACES_SECRET_KEY,
|
|
4100
|
-
endpoint: SPACES_ENDPOINT,
|
|
4101
|
-
region: SPACES_REGION,
|
|
4102
|
-
bucket: SPACES_BUCKET,
|
|
4103
|
-
forcePathStyle: true
|
|
4104
|
-
});
|
|
4105
|
-
async function createFile(value) {
|
|
4106
|
-
const session = useAtlas11.getClient()?.startSession();
|
|
4107
|
-
session?.startTransaction();
|
|
4108
|
-
const file = {
|
|
4109
|
-
name: value.originalname,
|
|
4110
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4111
|
-
};
|
|
4112
|
-
try {
|
|
4113
|
-
const id = await _createFile(file, session);
|
|
4114
|
-
const fileBuffer = value.buffer || await fs.promises.readFile(value.path);
|
|
4115
|
-
await s3.uploadObject({
|
|
4116
|
-
key: id,
|
|
4117
|
-
body: fileBuffer,
|
|
4118
|
-
contentType: value.mimetype
|
|
4119
|
-
});
|
|
4120
|
-
await session?.commitTransaction();
|
|
4121
|
-
if (value.path) {
|
|
4122
|
-
try {
|
|
4123
|
-
await fs.promises.unlink(value.path);
|
|
4124
|
-
} catch (cleanupError) {
|
|
4125
|
-
console.error(
|
|
4126
|
-
`Failed to cleanup temporary file ${value.path}:`,
|
|
4127
|
-
cleanupError
|
|
4128
|
-
);
|
|
4129
|
-
}
|
|
4130
|
-
}
|
|
4131
|
-
return id;
|
|
4132
|
-
} catch (error) {
|
|
4133
|
-
await session?.abortTransaction();
|
|
4134
|
-
throw error;
|
|
4135
|
-
} finally {
|
|
4136
|
-
session?.endSession();
|
|
4137
|
-
}
|
|
4138
|
-
}
|
|
4139
|
-
async function deleteFile(id) {
|
|
4140
|
-
const session = useAtlas11.getClient()?.startSession();
|
|
4141
|
-
session?.startTransaction();
|
|
4142
|
-
try {
|
|
4143
|
-
await deleteFileById(id, session);
|
|
4144
|
-
await s3.deleteObject(id);
|
|
4145
|
-
await session?.commitTransaction();
|
|
4146
|
-
return "File deleted successfully";
|
|
4147
|
-
} catch (error) {
|
|
4148
|
-
await session?.abortTransaction();
|
|
4149
|
-
throw error;
|
|
4150
|
-
} finally {
|
|
4151
|
-
session?.endSession();
|
|
4152
|
-
}
|
|
4153
|
-
}
|
|
4154
|
-
function deleteDraft() {
|
|
4155
|
-
cron.schedule("0 0 * * *", async () => {
|
|
4156
|
-
const files = await getAllDraftedFiles();
|
|
4157
|
-
for (let index = 0; index < files.length; index++) {
|
|
4158
|
-
const file = files[index];
|
|
4159
|
-
try {
|
|
4160
|
-
await deleteFile(file._id.toString());
|
|
4161
|
-
await logger11.log({
|
|
4162
|
-
level: "info",
|
|
4163
|
-
message: "Successfully deleted draft files."
|
|
4164
|
-
});
|
|
4165
|
-
} catch (error) {
|
|
4166
|
-
logger11.log({
|
|
4167
|
-
level: "info",
|
|
4168
|
-
message: "Successfully deleted draft files."
|
|
4169
|
-
});
|
|
4170
|
-
return;
|
|
4171
|
-
}
|
|
4172
|
-
}
|
|
4173
|
-
});
|
|
4174
|
-
}
|
|
4175
|
-
return {
|
|
4176
|
-
createFile,
|
|
4177
|
-
deleteFile,
|
|
4178
|
-
deleteDraft
|
|
4179
|
-
};
|
|
4180
|
-
}
|
|
4181
|
-
|
|
4182
|
-
// src/resources/file/file.controller.ts
|
|
4183
|
-
import {
|
|
4184
|
-
AppError as AppError7,
|
|
4185
|
-
BadRequestError as BadRequestError19,
|
|
4186
|
-
InternalServerError as InternalServerError15
|
|
4187
|
-
} from "@eeplatform/nodejs-utils";
|
|
4188
|
-
import Joi9 from "joi";
|
|
4189
|
-
function useFileController() {
|
|
4190
|
-
const { createFile, deleteFile: _deleteFile } = useFileService();
|
|
4191
|
-
async function upload(req, res, next) {
|
|
4192
|
-
if (!req.file) {
|
|
4193
|
-
res.status(400).send("File is required!");
|
|
4194
|
-
return;
|
|
4195
|
-
}
|
|
4196
|
-
try {
|
|
4197
|
-
const id = await createFile(req.file);
|
|
4198
|
-
res.json({ message: "Successfully uploaded file", id });
|
|
4199
|
-
return;
|
|
4200
|
-
} catch (error) {
|
|
4201
|
-
if (error instanceof AppError7) {
|
|
4202
|
-
next(error);
|
|
4203
|
-
} else {
|
|
4204
|
-
next(new InternalServerError15(error));
|
|
4205
|
-
}
|
|
4206
|
-
}
|
|
4207
|
-
}
|
|
4208
|
-
async function deleteFile(req, res, next) {
|
|
4209
|
-
const id = req.params.id;
|
|
4210
|
-
const validation = Joi9.string().required();
|
|
4211
|
-
const { error } = validation.validate(id);
|
|
4212
|
-
if (error) {
|
|
4213
|
-
next(new BadRequestError19(error.message));
|
|
4214
|
-
}
|
|
4215
|
-
try {
|
|
4216
|
-
const message = await _deleteFile(id);
|
|
4217
|
-
res.json({ message });
|
|
4218
|
-
return;
|
|
4219
|
-
} catch (error2) {
|
|
4220
|
-
if (error2 instanceof AppError7) {
|
|
4221
|
-
next(error2);
|
|
4222
|
-
} else {
|
|
4223
|
-
next(new InternalServerError15(error2));
|
|
4224
|
-
}
|
|
4225
|
-
}
|
|
4226
|
-
}
|
|
4227
|
-
return {
|
|
4228
|
-
upload,
|
|
4229
|
-
deleteFile
|
|
4230
|
-
};
|
|
4231
|
-
}
|
|
4232
|
-
|
|
4233
6096
|
// src/resources/verification/verification.controller.ts
|
|
4234
6097
|
import {
|
|
4235
|
-
AppError as
|
|
4236
|
-
BadRequestError as
|
|
4237
|
-
InternalServerError as
|
|
6098
|
+
AppError as AppError12,
|
|
6099
|
+
BadRequestError as BadRequestError30,
|
|
6100
|
+
InternalServerError as InternalServerError20
|
|
4238
6101
|
} from "@eeplatform/nodejs-utils";
|
|
4239
|
-
import
|
|
6102
|
+
import Joi19 from "joi";
|
|
4240
6103
|
function useVerificationController() {
|
|
4241
6104
|
const {
|
|
4242
6105
|
createUserInvite: _createUserInvite,
|
|
@@ -4246,17 +6109,17 @@ function useVerificationController() {
|
|
|
4246
6109
|
} = useVerificationService();
|
|
4247
6110
|
const { getVerifications: _getVerifications } = useVerificationRepo();
|
|
4248
6111
|
async function createUserInvite(req, res, next) {
|
|
4249
|
-
const validation =
|
|
4250
|
-
email:
|
|
4251
|
-
app:
|
|
4252
|
-
role:
|
|
4253
|
-
roleName:
|
|
4254
|
-
org:
|
|
4255
|
-
orgName:
|
|
6112
|
+
const validation = Joi19.object({
|
|
6113
|
+
email: Joi19.string().email().required(),
|
|
6114
|
+
app: Joi19.string().required(),
|
|
6115
|
+
role: Joi19.string().hex().required(),
|
|
6116
|
+
roleName: Joi19.string().required(),
|
|
6117
|
+
org: Joi19.string().hex().optional().optional().allow("", null),
|
|
6118
|
+
orgName: Joi19.string().optional().optional().allow("", null)
|
|
4256
6119
|
});
|
|
4257
6120
|
const { error } = validation.validate(req.body);
|
|
4258
6121
|
if (error) {
|
|
4259
|
-
next(new
|
|
6122
|
+
next(new BadRequestError30(error.message));
|
|
4260
6123
|
return;
|
|
4261
6124
|
}
|
|
4262
6125
|
const email = req.body.email ?? "";
|
|
@@ -4284,10 +6147,10 @@ function useVerificationController() {
|
|
|
4284
6147
|
}
|
|
4285
6148
|
async function createForgetPassword(req, res, next) {
|
|
4286
6149
|
const email = req.body.email || "";
|
|
4287
|
-
const validation =
|
|
6150
|
+
const validation = Joi19.string().email().required();
|
|
4288
6151
|
const { error } = validation.validate(email);
|
|
4289
6152
|
if (error) {
|
|
4290
|
-
next(new
|
|
6153
|
+
next(new BadRequestError30(error.message));
|
|
4291
6154
|
return;
|
|
4292
6155
|
}
|
|
4293
6156
|
try {
|
|
@@ -4297,25 +6160,25 @@ function useVerificationController() {
|
|
|
4297
6160
|
});
|
|
4298
6161
|
return;
|
|
4299
6162
|
} catch (error2) {
|
|
4300
|
-
if (error2 instanceof
|
|
6163
|
+
if (error2 instanceof AppError12) {
|
|
4301
6164
|
next(error2);
|
|
4302
6165
|
} else {
|
|
4303
|
-
next(new
|
|
6166
|
+
next(new InternalServerError20("An unexpected error occurred"));
|
|
4304
6167
|
}
|
|
4305
6168
|
}
|
|
4306
6169
|
}
|
|
4307
6170
|
async function getVerifications(req, res, next) {
|
|
4308
|
-
const validation =
|
|
4309
|
-
status:
|
|
4310
|
-
search:
|
|
4311
|
-
page:
|
|
4312
|
-
type:
|
|
4313
|
-
email:
|
|
4314
|
-
app:
|
|
6171
|
+
const validation = Joi19.object({
|
|
6172
|
+
status: Joi19.string().required(),
|
|
6173
|
+
search: Joi19.string().optional().allow("", null),
|
|
6174
|
+
page: Joi19.number().required(),
|
|
6175
|
+
type: Joi19.string().optional().allow("", null),
|
|
6176
|
+
email: Joi19.string().optional().allow("", null),
|
|
6177
|
+
app: Joi19.string().optional().allow("", null)
|
|
4315
6178
|
});
|
|
4316
6179
|
const { error } = validation.validate(req.query);
|
|
4317
6180
|
if (error) {
|
|
4318
|
-
next(new
|
|
6181
|
+
next(new BadRequestError30(error.message));
|
|
4319
6182
|
return;
|
|
4320
6183
|
}
|
|
4321
6184
|
const status = req.query.status ?? "";
|
|
@@ -4346,10 +6209,10 @@ function useVerificationController() {
|
|
|
4346
6209
|
}
|
|
4347
6210
|
async function verify(req, res, next) {
|
|
4348
6211
|
const id = req.params.id || "";
|
|
4349
|
-
const validation =
|
|
6212
|
+
const validation = Joi19.string().hex().required();
|
|
4350
6213
|
const { error } = validation.validate(id);
|
|
4351
6214
|
if (error) {
|
|
4352
|
-
next(new
|
|
6215
|
+
next(new BadRequestError30(error.message));
|
|
4353
6216
|
return;
|
|
4354
6217
|
}
|
|
4355
6218
|
try {
|
|
@@ -4362,10 +6225,10 @@ function useVerificationController() {
|
|
|
4362
6225
|
}
|
|
4363
6226
|
async function cancelUserInvitation(req, res, next) {
|
|
4364
6227
|
const otpId = req.params.id || "";
|
|
4365
|
-
const validation =
|
|
6228
|
+
const validation = Joi19.string().hex().required();
|
|
4366
6229
|
const { error } = validation.validate(otpId);
|
|
4367
6230
|
if (error) {
|
|
4368
|
-
next(new
|
|
6231
|
+
next(new BadRequestError30(error.message));
|
|
4369
6232
|
return;
|
|
4370
6233
|
}
|
|
4371
6234
|
try {
|
|
@@ -4387,34 +6250,34 @@ function useVerificationController() {
|
|
|
4387
6250
|
}
|
|
4388
6251
|
|
|
4389
6252
|
// src/resources/address/address.model.ts
|
|
4390
|
-
import { BadRequestError as
|
|
4391
|
-
import
|
|
4392
|
-
import { ObjectId as
|
|
4393
|
-
var addressSchema =
|
|
4394
|
-
type:
|
|
4395
|
-
user:
|
|
4396
|
-
org:
|
|
4397
|
-
country:
|
|
4398
|
-
address:
|
|
4399
|
-
continuedAddress:
|
|
4400
|
-
city:
|
|
4401
|
-
province:
|
|
4402
|
-
postalCode:
|
|
4403
|
-
taxId:
|
|
6253
|
+
import { BadRequestError as BadRequestError31 } from "@eeplatform/nodejs-utils";
|
|
6254
|
+
import Joi20 from "joi";
|
|
6255
|
+
import { ObjectId as ObjectId17 } from "mongodb";
|
|
6256
|
+
var addressSchema = Joi20.object({
|
|
6257
|
+
type: Joi20.string().required(),
|
|
6258
|
+
user: Joi20.string().hex().optional().allow("", null),
|
|
6259
|
+
org: Joi20.string().hex().optional().allow("", null),
|
|
6260
|
+
country: Joi20.string().required(),
|
|
6261
|
+
address: Joi20.string().required(),
|
|
6262
|
+
continuedAddress: Joi20.string().optional().allow("", null),
|
|
6263
|
+
city: Joi20.string().required(),
|
|
6264
|
+
province: Joi20.string().required(),
|
|
6265
|
+
postalCode: Joi20.string().required(),
|
|
6266
|
+
taxId: Joi20.string().optional().allow("", null)
|
|
4404
6267
|
});
|
|
4405
6268
|
function MAddress(value) {
|
|
4406
6269
|
if (value.user) {
|
|
4407
6270
|
try {
|
|
4408
|
-
value.user = new
|
|
6271
|
+
value.user = new ObjectId17(value.user);
|
|
4409
6272
|
} catch (error) {
|
|
4410
|
-
throw new
|
|
6273
|
+
throw new BadRequestError31("Invalid user ID.");
|
|
4411
6274
|
}
|
|
4412
6275
|
}
|
|
4413
6276
|
if (value.org) {
|
|
4414
6277
|
try {
|
|
4415
|
-
value.org = new
|
|
6278
|
+
value.org = new ObjectId17(value.org);
|
|
4416
6279
|
} catch (error) {
|
|
4417
|
-
throw new
|
|
6280
|
+
throw new BadRequestError31("Invalid org ID.");
|
|
4418
6281
|
}
|
|
4419
6282
|
}
|
|
4420
6283
|
return {
|
|
@@ -4433,29 +6296,29 @@ function MAddress(value) {
|
|
|
4433
6296
|
|
|
4434
6297
|
// src/resources/address/address.repository.ts
|
|
4435
6298
|
import {
|
|
4436
|
-
BadRequestError as
|
|
4437
|
-
useAtlas as
|
|
6299
|
+
BadRequestError as BadRequestError32,
|
|
6300
|
+
useAtlas as useAtlas14,
|
|
4438
6301
|
useCache as useCache10,
|
|
4439
|
-
makeCacheKey as
|
|
4440
|
-
logger as
|
|
6302
|
+
makeCacheKey as makeCacheKey12,
|
|
6303
|
+
logger as logger20
|
|
4441
6304
|
} from "@eeplatform/nodejs-utils";
|
|
4442
|
-
import { ObjectId as
|
|
6305
|
+
import { ObjectId as ObjectId18 } from "mongodb";
|
|
4443
6306
|
function useAddressRepo() {
|
|
4444
|
-
const db =
|
|
6307
|
+
const db = useAtlas14.getDb();
|
|
4445
6308
|
if (!db) {
|
|
4446
|
-
throw new
|
|
6309
|
+
throw new BadRequestError32("Unable to connect to server.");
|
|
4447
6310
|
}
|
|
4448
6311
|
const namespace_collection = "addresses";
|
|
4449
6312
|
const collection = db.collection(namespace_collection);
|
|
4450
6313
|
const { getCache, setCache, delNamespace } = useCache10(namespace_collection);
|
|
4451
6314
|
function delCachedData() {
|
|
4452
6315
|
delNamespace().then(() => {
|
|
4453
|
-
|
|
6316
|
+
logger20.log({
|
|
4454
6317
|
level: "info",
|
|
4455
6318
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
4456
6319
|
});
|
|
4457
6320
|
}).catch((err) => {
|
|
4458
|
-
|
|
6321
|
+
logger20.log({
|
|
4459
6322
|
level: "error",
|
|
4460
6323
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
4461
6324
|
});
|
|
@@ -4469,7 +6332,7 @@ function useAddressRepo() {
|
|
|
4469
6332
|
{ key: { orgId: 1 } }
|
|
4470
6333
|
]);
|
|
4471
6334
|
} catch (error) {
|
|
4472
|
-
throw new
|
|
6335
|
+
throw new BadRequestError32("Failed to create index on address.");
|
|
4473
6336
|
}
|
|
4474
6337
|
}
|
|
4475
6338
|
async function add(value, session) {
|
|
@@ -4479,20 +6342,20 @@ function useAddressRepo() {
|
|
|
4479
6342
|
delCachedData();
|
|
4480
6343
|
return res.insertedId;
|
|
4481
6344
|
} catch (error) {
|
|
4482
|
-
throw new
|
|
6345
|
+
throw new BadRequestError32("Failed to create address.");
|
|
4483
6346
|
}
|
|
4484
6347
|
}
|
|
4485
6348
|
async function updateById(_id, value, session) {
|
|
4486
6349
|
try {
|
|
4487
|
-
_id = new
|
|
6350
|
+
_id = new ObjectId18(_id);
|
|
4488
6351
|
} catch (error) {
|
|
4489
|
-
throw new
|
|
6352
|
+
throw new BadRequestError32("Invalid address ID.");
|
|
4490
6353
|
}
|
|
4491
6354
|
if (value.org) {
|
|
4492
6355
|
try {
|
|
4493
|
-
value.org = new
|
|
6356
|
+
value.org = new ObjectId18(value.org);
|
|
4494
6357
|
} catch (error) {
|
|
4495
|
-
throw new
|
|
6358
|
+
throw new BadRequestError32("Invalid org ID.");
|
|
4496
6359
|
}
|
|
4497
6360
|
}
|
|
4498
6361
|
try {
|
|
@@ -4504,20 +6367,20 @@ function useAddressRepo() {
|
|
|
4504
6367
|
delCachedData();
|
|
4505
6368
|
return "Successfully updated address.";
|
|
4506
6369
|
} catch (error) {
|
|
4507
|
-
throw new
|
|
6370
|
+
throw new BadRequestError32("Failed to update address.");
|
|
4508
6371
|
}
|
|
4509
6372
|
}
|
|
4510
6373
|
async function getByUserId(user) {
|
|
4511
6374
|
try {
|
|
4512
|
-
user = new
|
|
6375
|
+
user = new ObjectId18(user);
|
|
4513
6376
|
} catch (error) {
|
|
4514
|
-
throw new
|
|
6377
|
+
throw new BadRequestError32("Invalid user ID.");
|
|
4515
6378
|
}
|
|
4516
|
-
const cacheKey =
|
|
6379
|
+
const cacheKey = makeCacheKey12(namespace_collection, { user: String(user) });
|
|
4517
6380
|
try {
|
|
4518
6381
|
const cached = await getCache(cacheKey);
|
|
4519
6382
|
if (cached) {
|
|
4520
|
-
|
|
6383
|
+
logger20.log({
|
|
4521
6384
|
level: "info",
|
|
4522
6385
|
message: `Cache hit for getByUserId address: ${cacheKey}`
|
|
4523
6386
|
});
|
|
@@ -4526,12 +6389,12 @@ function useAddressRepo() {
|
|
|
4526
6389
|
const data = await collection.findOne({ user });
|
|
4527
6390
|
if (data) {
|
|
4528
6391
|
setCache(cacheKey, data, 300).then(() => {
|
|
4529
|
-
|
|
6392
|
+
logger20.log({
|
|
4530
6393
|
level: "info",
|
|
4531
6394
|
message: `Cache set for address by user ID: ${cacheKey}`
|
|
4532
6395
|
});
|
|
4533
6396
|
}).catch((err) => {
|
|
4534
|
-
|
|
6397
|
+
logger20.log({
|
|
4535
6398
|
level: "error",
|
|
4536
6399
|
message: `Failed to set cache for address by user ID: ${err.message}`
|
|
4537
6400
|
});
|
|
@@ -4539,20 +6402,20 @@ function useAddressRepo() {
|
|
|
4539
6402
|
}
|
|
4540
6403
|
return data;
|
|
4541
6404
|
} catch (error) {
|
|
4542
|
-
throw new
|
|
6405
|
+
throw new BadRequestError32("Failed to get address by ID.");
|
|
4543
6406
|
}
|
|
4544
6407
|
}
|
|
4545
6408
|
async function getByOrgId(org) {
|
|
4546
6409
|
try {
|
|
4547
|
-
org = new
|
|
6410
|
+
org = new ObjectId18(org);
|
|
4548
6411
|
} catch (error) {
|
|
4549
|
-
throw new
|
|
6412
|
+
throw new BadRequestError32("Invalid orgId.");
|
|
4550
6413
|
}
|
|
4551
|
-
const cacheKey =
|
|
6414
|
+
const cacheKey = makeCacheKey12(namespace_collection, { org: String(org) });
|
|
4552
6415
|
try {
|
|
4553
6416
|
const cached = await getCache(cacheKey);
|
|
4554
6417
|
if (cached) {
|
|
4555
|
-
|
|
6418
|
+
logger20.log({
|
|
4556
6419
|
level: "info",
|
|
4557
6420
|
message: `Cache hit for getByOrgId address: ${cacheKey}`
|
|
4558
6421
|
});
|
|
@@ -4561,12 +6424,12 @@ function useAddressRepo() {
|
|
|
4561
6424
|
const data = await collection.findOne({ org });
|
|
4562
6425
|
if (data) {
|
|
4563
6426
|
setCache(cacheKey, data, 300).then(() => {
|
|
4564
|
-
|
|
6427
|
+
logger20.log({
|
|
4565
6428
|
level: "info",
|
|
4566
6429
|
message: `Cache set for address by org ID: ${cacheKey}`
|
|
4567
6430
|
});
|
|
4568
6431
|
}).catch((err) => {
|
|
4569
|
-
|
|
6432
|
+
logger20.log({
|
|
4570
6433
|
level: "error",
|
|
4571
6434
|
message: `Failed to set cache for address by org ID: ${err.message}`
|
|
4572
6435
|
});
|
|
@@ -4574,7 +6437,7 @@ function useAddressRepo() {
|
|
|
4574
6437
|
}
|
|
4575
6438
|
return data;
|
|
4576
6439
|
} catch (error) {
|
|
4577
|
-
throw new
|
|
6440
|
+
throw new BadRequestError32("Failed to get address by orgId.");
|
|
4578
6441
|
}
|
|
4579
6442
|
}
|
|
4580
6443
|
return {
|
|
@@ -4587,8 +6450,8 @@ function useAddressRepo() {
|
|
|
4587
6450
|
}
|
|
4588
6451
|
|
|
4589
6452
|
// src/resources/address/address.controller.ts
|
|
4590
|
-
import { BadRequestError as
|
|
4591
|
-
import
|
|
6453
|
+
import { BadRequestError as BadRequestError33, NotFoundError as NotFoundError4 } from "@eeplatform/nodejs-utils";
|
|
6454
|
+
import Joi21 from "joi";
|
|
4592
6455
|
function useAddressController() {
|
|
4593
6456
|
const {
|
|
4594
6457
|
add: _add,
|
|
@@ -4598,21 +6461,21 @@ function useAddressController() {
|
|
|
4598
6461
|
} = useAddressRepo();
|
|
4599
6462
|
async function add(req, res, next) {
|
|
4600
6463
|
const value = req.body;
|
|
4601
|
-
const validation =
|
|
4602
|
-
type:
|
|
4603
|
-
user:
|
|
4604
|
-
org:
|
|
4605
|
-
country:
|
|
4606
|
-
address:
|
|
4607
|
-
continuedAddress:
|
|
4608
|
-
city:
|
|
4609
|
-
province:
|
|
4610
|
-
postalCode:
|
|
4611
|
-
taxId:
|
|
6464
|
+
const validation = Joi21.object({
|
|
6465
|
+
type: Joi21.string().required(),
|
|
6466
|
+
user: Joi21.string().hex().optional().allow("", null),
|
|
6467
|
+
org: Joi21.string().hex().optional().allow("", null),
|
|
6468
|
+
country: Joi21.string().required(),
|
|
6469
|
+
address: Joi21.string().required(),
|
|
6470
|
+
continuedAddress: Joi21.string().optional().allow("", null),
|
|
6471
|
+
city: Joi21.string().required(),
|
|
6472
|
+
province: Joi21.string().required(),
|
|
6473
|
+
postalCode: Joi21.string().required(),
|
|
6474
|
+
taxId: Joi21.string().optional().allow("", null)
|
|
4612
6475
|
});
|
|
4613
6476
|
const { error } = validation.validate(value);
|
|
4614
6477
|
if (error) {
|
|
4615
|
-
next(new
|
|
6478
|
+
next(new BadRequestError33(error.message));
|
|
4616
6479
|
}
|
|
4617
6480
|
try {
|
|
4618
6481
|
const value2 = req.body;
|
|
@@ -4626,20 +6489,20 @@ function useAddressController() {
|
|
|
4626
6489
|
async function updateById(req, res, next) {
|
|
4627
6490
|
const id = req.params.id ?? "";
|
|
4628
6491
|
const value = req.body;
|
|
4629
|
-
const validation =
|
|
4630
|
-
id:
|
|
4631
|
-
country:
|
|
4632
|
-
address:
|
|
4633
|
-
continuedAddress:
|
|
4634
|
-
city:
|
|
4635
|
-
province:
|
|
4636
|
-
postalCode:
|
|
4637
|
-
taxId:
|
|
4638
|
-
org:
|
|
6492
|
+
const validation = Joi21.object({
|
|
6493
|
+
id: Joi21.string().hex().required(),
|
|
6494
|
+
country: Joi21.string().required(),
|
|
6495
|
+
address: Joi21.string().required(),
|
|
6496
|
+
continuedAddress: Joi21.string().optional().allow("", null),
|
|
6497
|
+
city: Joi21.string().required(),
|
|
6498
|
+
province: Joi21.string().required(),
|
|
6499
|
+
postalCode: Joi21.string().required(),
|
|
6500
|
+
taxId: Joi21.string().optional().allow("", null),
|
|
6501
|
+
org: Joi21.string().hex().optional().allow("", null)
|
|
4639
6502
|
});
|
|
4640
6503
|
const { error } = validation.validate({ id, ...value });
|
|
4641
6504
|
if (error) {
|
|
4642
|
-
next(new
|
|
6505
|
+
next(new BadRequestError33(error.message));
|
|
4643
6506
|
return;
|
|
4644
6507
|
}
|
|
4645
6508
|
try {
|
|
@@ -4652,10 +6515,10 @@ function useAddressController() {
|
|
|
4652
6515
|
}
|
|
4653
6516
|
async function getByUserId(req, res, next) {
|
|
4654
6517
|
const user = req.params.user;
|
|
4655
|
-
const validation =
|
|
6518
|
+
const validation = Joi21.string().hex().required();
|
|
4656
6519
|
const { error } = validation.validate(user);
|
|
4657
6520
|
if (error) {
|
|
4658
|
-
next(new
|
|
6521
|
+
next(new BadRequestError33(error.message));
|
|
4659
6522
|
}
|
|
4660
6523
|
try {
|
|
4661
6524
|
const address = await _getByUserId(user);
|
|
@@ -4671,10 +6534,10 @@ function useAddressController() {
|
|
|
4671
6534
|
}
|
|
4672
6535
|
async function getByOrgId(req, res, next) {
|
|
4673
6536
|
const id = req.params.id;
|
|
4674
|
-
const validation =
|
|
6537
|
+
const validation = Joi21.string().hex().required();
|
|
4675
6538
|
const { error } = validation.validate(id);
|
|
4676
6539
|
if (error) {
|
|
4677
|
-
next(new
|
|
6540
|
+
next(new BadRequestError33(error.message));
|
|
4678
6541
|
}
|
|
4679
6542
|
try {
|
|
4680
6543
|
const address = await _getByOrgId(id);
|
|
@@ -4697,24 +6560,24 @@ function useAddressController() {
|
|
|
4697
6560
|
}
|
|
4698
6561
|
|
|
4699
6562
|
// src/resources/token/token.model.ts
|
|
4700
|
-
import { ObjectId as
|
|
6563
|
+
import { ObjectId as ObjectId19 } from "mongodb";
|
|
4701
6564
|
var MToken = class {
|
|
4702
6565
|
constructor(value) {
|
|
4703
6566
|
this.token = value.token ?? "";
|
|
4704
|
-
this.user = value.user ?? new
|
|
6567
|
+
this.user = value.user ?? new ObjectId19();
|
|
4705
6568
|
this.createdAt = value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
4706
6569
|
}
|
|
4707
6570
|
};
|
|
4708
6571
|
|
|
4709
6572
|
// src/resources/counter/counter.model.ts
|
|
4710
|
-
import { BadRequestError as
|
|
4711
|
-
import { ObjectId as
|
|
6573
|
+
import { BadRequestError as BadRequestError34 } from "@eeplatform/nodejs-utils";
|
|
6574
|
+
import { ObjectId as ObjectId20 } from "mongodb";
|
|
4712
6575
|
import { z } from "zod";
|
|
4713
6576
|
var TCounter = z.object({
|
|
4714
6577
|
_id: z.union([
|
|
4715
6578
|
z.string().length(24, "Invalid ObjectId hex string"),
|
|
4716
|
-
z.instanceof(
|
|
4717
|
-
]).transform((val) => typeof val === "string" ? new
|
|
6579
|
+
z.instanceof(ObjectId20)
|
|
6580
|
+
]).transform((val) => typeof val === "string" ? new ObjectId20(val) : val).optional(),
|
|
4718
6581
|
count: z.number().int().min(0).default(0),
|
|
4719
6582
|
type: z.string(),
|
|
4720
6583
|
createdAt: z.date().optional().default(() => /* @__PURE__ */ new Date()),
|
|
@@ -4727,7 +6590,7 @@ function useCounterModel(db) {
|
|
|
4727
6590
|
try {
|
|
4728
6591
|
return TCounter.parse(value);
|
|
4729
6592
|
} catch (error) {
|
|
4730
|
-
throw new
|
|
6593
|
+
throw new BadRequestError34(error.issues[0].message);
|
|
4731
6594
|
}
|
|
4732
6595
|
}
|
|
4733
6596
|
function validateCounter(data) {
|
|
@@ -4742,13 +6605,13 @@ function useCounterModel(db) {
|
|
|
4742
6605
|
|
|
4743
6606
|
// src/resources/counter/counter.repository.ts
|
|
4744
6607
|
import {
|
|
4745
|
-
useAtlas as
|
|
6608
|
+
useAtlas as useAtlas15,
|
|
4746
6609
|
useCache as useCache11,
|
|
4747
|
-
makeCacheKey as
|
|
4748
|
-
logger as
|
|
6610
|
+
makeCacheKey as makeCacheKey13,
|
|
6611
|
+
logger as logger21
|
|
4749
6612
|
} from "@eeplatform/nodejs-utils";
|
|
4750
6613
|
function useCounterRepo() {
|
|
4751
|
-
const db =
|
|
6614
|
+
const db = useAtlas15.getDb();
|
|
4752
6615
|
if (!db) {
|
|
4753
6616
|
throw new Error("Unable to connect to server.");
|
|
4754
6617
|
}
|
|
@@ -4757,12 +6620,12 @@ function useCounterRepo() {
|
|
|
4757
6620
|
const { getCache, setCache, delNamespace } = useCache11(namespace_collection);
|
|
4758
6621
|
function delCachedData() {
|
|
4759
6622
|
delNamespace().then(() => {
|
|
4760
|
-
|
|
6623
|
+
logger21.log({
|
|
4761
6624
|
level: "info",
|
|
4762
6625
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
4763
6626
|
});
|
|
4764
6627
|
}).catch((err) => {
|
|
4765
|
-
|
|
6628
|
+
logger21.log({
|
|
4766
6629
|
level: "error",
|
|
4767
6630
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
4768
6631
|
});
|
|
@@ -4814,11 +6677,11 @@ function useCounterRepo() {
|
|
|
4814
6677
|
}
|
|
4815
6678
|
}
|
|
4816
6679
|
async function getByType(type) {
|
|
4817
|
-
const cacheKey =
|
|
6680
|
+
const cacheKey = makeCacheKey13(namespace_collection, { type });
|
|
4818
6681
|
try {
|
|
4819
6682
|
const cached = await getCache(cacheKey);
|
|
4820
6683
|
if (cached) {
|
|
4821
|
-
|
|
6684
|
+
logger21.log({
|
|
4822
6685
|
level: "info",
|
|
4823
6686
|
message: `Cache hit for getByType counter: ${cacheKey}`
|
|
4824
6687
|
});
|
|
@@ -4827,12 +6690,12 @@ function useCounterRepo() {
|
|
|
4827
6690
|
const data = await collection.findOne({ type });
|
|
4828
6691
|
if (data) {
|
|
4829
6692
|
setCache(cacheKey, data, 300).then(() => {
|
|
4830
|
-
|
|
6693
|
+
logger21.log({
|
|
4831
6694
|
level: "info",
|
|
4832
6695
|
message: `Cache set for counter by type: ${cacheKey}`
|
|
4833
6696
|
});
|
|
4834
6697
|
}).catch((err) => {
|
|
4835
|
-
|
|
6698
|
+
logger21.log({
|
|
4836
6699
|
level: "error",
|
|
4837
6700
|
message: `Failed to set cache for counter by type: ${err.message}`
|
|
4838
6701
|
});
|
|
@@ -5170,7 +7033,7 @@ IMPORTANT: Only consider it a match if the target phoneme is the FIRST sound pro
|
|
|
5170
7033
|
}
|
|
5171
7034
|
|
|
5172
7035
|
// src/resources/utils/github.service.ts
|
|
5173
|
-
import { AppError as
|
|
7036
|
+
import { AppError as AppError13, BadRequestError as BadRequestError35 } from "@eeplatform/nodejs-utils";
|
|
5174
7037
|
import { Octokit } from "@octokit/rest";
|
|
5175
7038
|
import _sodium from "libsodium-wrappers";
|
|
5176
7039
|
function useGitHubService() {
|
|
@@ -5184,23 +7047,23 @@ function useGitHubService() {
|
|
|
5184
7047
|
try {
|
|
5185
7048
|
const { data: repoData } = await octokit.repos.get({ owner, repo });
|
|
5186
7049
|
if (!repoData.permissions?.admin) {
|
|
5187
|
-
throw new
|
|
7050
|
+
throw new BadRequestError35(
|
|
5188
7051
|
"You do not have admin access to this repository."
|
|
5189
7052
|
);
|
|
5190
7053
|
}
|
|
5191
7054
|
} catch (error) {
|
|
5192
7055
|
if (error.status === 404) {
|
|
5193
|
-
throw new
|
|
7056
|
+
throw new BadRequestError35(
|
|
5194
7057
|
"Repository not found or you don't have access to it."
|
|
5195
7058
|
);
|
|
5196
7059
|
} else if (error.status === 401) {
|
|
5197
|
-
throw new
|
|
7060
|
+
throw new BadRequestError35(
|
|
5198
7061
|
"Invalid GitHub token or insufficient permissions."
|
|
5199
7062
|
);
|
|
5200
7063
|
} else if (error.message.includes("admin access")) {
|
|
5201
7064
|
throw error;
|
|
5202
7065
|
} else {
|
|
5203
|
-
throw new
|
|
7066
|
+
throw new BadRequestError35(
|
|
5204
7067
|
`Failed to check repository permissions: ${error.message}`
|
|
5205
7068
|
);
|
|
5206
7069
|
}
|
|
@@ -5249,7 +7112,7 @@ function useGitHubService() {
|
|
|
5249
7112
|
key_id: publicKeyRes.key_id
|
|
5250
7113
|
});
|
|
5251
7114
|
} catch (encryptionError) {
|
|
5252
|
-
throw new
|
|
7115
|
+
throw new BadRequestError35(
|
|
5253
7116
|
`Failed to encrypt secret '${key}': ${encryptionError.message}`
|
|
5254
7117
|
);
|
|
5255
7118
|
}
|
|
@@ -5265,22 +7128,22 @@ function useGitHubService() {
|
|
|
5265
7128
|
}
|
|
5266
7129
|
return `Successfully set ${lines.length} ${type} variables/secrets in environment '${environment}'`;
|
|
5267
7130
|
} catch (error) {
|
|
5268
|
-
if (error instanceof
|
|
7131
|
+
if (error instanceof AppError13)
|
|
5269
7132
|
throw error;
|
|
5270
7133
|
if (error.status === 422) {
|
|
5271
|
-
throw new
|
|
7134
|
+
throw new BadRequestError35(
|
|
5272
7135
|
`GitHub API validation error: ${error.message}`
|
|
5273
7136
|
);
|
|
5274
7137
|
} else if (error.status === 404) {
|
|
5275
|
-
throw new
|
|
7138
|
+
throw new BadRequestError35("Environment or repository not found.");
|
|
5276
7139
|
} else if (error.status === 403) {
|
|
5277
|
-
throw new
|
|
7140
|
+
throw new BadRequestError35(
|
|
5278
7141
|
"Forbidden: Insufficient permissions or rate limit exceeded."
|
|
5279
7142
|
);
|
|
5280
7143
|
} else if (error.message.includes("admin access") || error.message.includes("permissions")) {
|
|
5281
7144
|
throw error;
|
|
5282
7145
|
} else {
|
|
5283
|
-
throw new
|
|
7146
|
+
throw new BadRequestError35(
|
|
5284
7147
|
`Failed to set GitHub variables: ${error.message}`
|
|
5285
7148
|
);
|
|
5286
7149
|
}
|
|
@@ -5292,7 +7155,7 @@ function useGitHubService() {
|
|
|
5292
7155
|
}
|
|
5293
7156
|
|
|
5294
7157
|
// src/resources/utils/transcribe.service.ts
|
|
5295
|
-
import { AppError as
|
|
7158
|
+
import { AppError as AppError14, BadRequestError as BadRequestError36, useRedis } from "@eeplatform/nodejs-utils";
|
|
5296
7159
|
function useTranscribeService() {
|
|
5297
7160
|
const { createFile } = useFileService();
|
|
5298
7161
|
const { getClient } = useRedis();
|
|
@@ -5301,10 +7164,10 @@ function useTranscribeService() {
|
|
|
5301
7164
|
try {
|
|
5302
7165
|
const fileId = await createFile(file);
|
|
5303
7166
|
} catch (error) {
|
|
5304
|
-
if (error instanceof
|
|
7167
|
+
if (error instanceof AppError14) {
|
|
5305
7168
|
throw error;
|
|
5306
7169
|
} else {
|
|
5307
|
-
throw new
|
|
7170
|
+
throw new BadRequestError36("Failed to transcribe audio file");
|
|
5308
7171
|
}
|
|
5309
7172
|
}
|
|
5310
7173
|
}
|
|
@@ -5315,31 +7178,31 @@ function useTranscribeService() {
|
|
|
5315
7178
|
|
|
5316
7179
|
// src/resources/utils/audio-transcription.controller.ts
|
|
5317
7180
|
import {
|
|
5318
|
-
AppError as
|
|
5319
|
-
BadRequestError as
|
|
5320
|
-
InternalServerError as
|
|
7181
|
+
AppError as AppError15,
|
|
7182
|
+
BadRequestError as BadRequestError37,
|
|
7183
|
+
InternalServerError as InternalServerError21
|
|
5321
7184
|
} from "@eeplatform/nodejs-utils";
|
|
5322
|
-
import
|
|
7185
|
+
import Joi22 from "joi";
|
|
5323
7186
|
function useAudioTranscriptionController() {
|
|
5324
7187
|
const geminiService = useGeminiAiService();
|
|
5325
|
-
const transcriptionOptionsSchema =
|
|
5326
|
-
language:
|
|
5327
|
-
enableTimestamps:
|
|
5328
|
-
prompt:
|
|
5329
|
-
maxTokens:
|
|
7188
|
+
const transcriptionOptionsSchema = Joi22.object({
|
|
7189
|
+
language: Joi22.string().optional().max(50),
|
|
7190
|
+
enableTimestamps: Joi22.boolean().optional(),
|
|
7191
|
+
prompt: Joi22.string().optional().max(1e3),
|
|
7192
|
+
maxTokens: Joi22.number().integer().min(1).max(8192).optional()
|
|
5330
7193
|
});
|
|
5331
|
-
const phonemeOptionsSchema =
|
|
5332
|
-
language:
|
|
5333
|
-
caseSensitive:
|
|
5334
|
-
partialMatch:
|
|
7194
|
+
const phonemeOptionsSchema = Joi22.object({
|
|
7195
|
+
language: Joi22.string().optional().max(50),
|
|
7196
|
+
caseSensitive: Joi22.boolean().optional(),
|
|
7197
|
+
partialMatch: Joi22.boolean().optional()
|
|
5335
7198
|
});
|
|
5336
|
-
const phonemeMatchSchema =
|
|
5337
|
-
targetPhoneme:
|
|
7199
|
+
const phonemeMatchSchema = Joi22.object({
|
|
7200
|
+
targetPhoneme: Joi22.string().required().min(1).max(10),
|
|
5338
7201
|
options: phonemeOptionsSchema.optional()
|
|
5339
7202
|
});
|
|
5340
7203
|
async function transcribeFromFile(req, res, next) {
|
|
5341
7204
|
if (!req.file) {
|
|
5342
|
-
next(new
|
|
7205
|
+
next(new BadRequestError37("Audio file is required"));
|
|
5343
7206
|
return;
|
|
5344
7207
|
}
|
|
5345
7208
|
try {
|
|
@@ -5347,14 +7210,14 @@ function useAudioTranscriptionController() {
|
|
|
5347
7210
|
req.body
|
|
5348
7211
|
);
|
|
5349
7212
|
if (error) {
|
|
5350
|
-
next(new
|
|
7213
|
+
next(new BadRequestError37(error.message));
|
|
5351
7214
|
return;
|
|
5352
7215
|
}
|
|
5353
7216
|
const { buffer, mimetype, originalname, size } = req.file;
|
|
5354
7217
|
if (!geminiService.validateAudioFormat(mimetype)) {
|
|
5355
7218
|
const supportedFormats = geminiService.getSupportedAudioFormats();
|
|
5356
7219
|
next(
|
|
5357
|
-
new
|
|
7220
|
+
new BadRequestError37(
|
|
5358
7221
|
`Unsupported audio format: ${mimetype}. Supported formats: ${supportedFormats.join(
|
|
5359
7222
|
", "
|
|
5360
7223
|
)}`
|
|
@@ -5365,7 +7228,7 @@ function useAudioTranscriptionController() {
|
|
|
5365
7228
|
const maxSizeBytes = 25 * 1024 * 1024;
|
|
5366
7229
|
if (size > maxSizeBytes) {
|
|
5367
7230
|
next(
|
|
5368
|
-
new
|
|
7231
|
+
new BadRequestError37(
|
|
5369
7232
|
`File size too large. Maximum allowed size is ${maxSizeBytes / (1024 * 1024)}MB`
|
|
5370
7233
|
)
|
|
5371
7234
|
);
|
|
@@ -5395,11 +7258,11 @@ function useAudioTranscriptionController() {
|
|
|
5395
7258
|
}
|
|
5396
7259
|
});
|
|
5397
7260
|
} catch (error) {
|
|
5398
|
-
if (error instanceof
|
|
7261
|
+
if (error instanceof AppError15) {
|
|
5399
7262
|
next(error);
|
|
5400
7263
|
} else {
|
|
5401
7264
|
next(
|
|
5402
|
-
new
|
|
7265
|
+
new InternalServerError21(
|
|
5403
7266
|
`Audio transcription failed: ${error.message}`
|
|
5404
7267
|
)
|
|
5405
7268
|
);
|
|
@@ -5408,21 +7271,21 @@ function useAudioTranscriptionController() {
|
|
|
5408
7271
|
}
|
|
5409
7272
|
async function transcribeFromBase64(req, res, next) {
|
|
5410
7273
|
try {
|
|
5411
|
-
const bodySchema =
|
|
5412
|
-
audioData:
|
|
5413
|
-
mimeType:
|
|
7274
|
+
const bodySchema = Joi22.object({
|
|
7275
|
+
audioData: Joi22.string().required(),
|
|
7276
|
+
mimeType: Joi22.string().required(),
|
|
5414
7277
|
options: transcriptionOptionsSchema.optional()
|
|
5415
7278
|
});
|
|
5416
7279
|
const { error, value } = bodySchema.validate(req.body);
|
|
5417
7280
|
if (error) {
|
|
5418
|
-
next(new
|
|
7281
|
+
next(new BadRequestError37(error.message));
|
|
5419
7282
|
return;
|
|
5420
7283
|
}
|
|
5421
7284
|
const { audioData, mimeType, options = {} } = value;
|
|
5422
7285
|
if (!geminiService.validateAudioFormat(mimeType)) {
|
|
5423
7286
|
const supportedFormats = geminiService.getSupportedAudioFormats();
|
|
5424
7287
|
next(
|
|
5425
|
-
new
|
|
7288
|
+
new BadRequestError37(
|
|
5426
7289
|
`Unsupported audio format: ${mimeType}. Supported formats: ${supportedFormats.join(
|
|
5427
7290
|
", "
|
|
5428
7291
|
)}`
|
|
@@ -5434,13 +7297,13 @@ function useAudioTranscriptionController() {
|
|
|
5434
7297
|
try {
|
|
5435
7298
|
audioBuffer = Buffer.from(audioData, "base64");
|
|
5436
7299
|
} catch (conversionError) {
|
|
5437
|
-
next(new
|
|
7300
|
+
next(new BadRequestError37("Invalid base64 audio data"));
|
|
5438
7301
|
return;
|
|
5439
7302
|
}
|
|
5440
7303
|
const maxSizeBytes = 25 * 1024 * 1024;
|
|
5441
7304
|
if (audioBuffer.length > maxSizeBytes) {
|
|
5442
7305
|
next(
|
|
5443
|
-
new
|
|
7306
|
+
new BadRequestError37(
|
|
5444
7307
|
`Audio data too large. Maximum allowed size is ${maxSizeBytes / (1024 * 1024)}MB`
|
|
5445
7308
|
)
|
|
5446
7309
|
);
|
|
@@ -5469,11 +7332,11 @@ function useAudioTranscriptionController() {
|
|
|
5469
7332
|
}
|
|
5470
7333
|
});
|
|
5471
7334
|
} catch (error) {
|
|
5472
|
-
if (error instanceof
|
|
7335
|
+
if (error instanceof AppError15) {
|
|
5473
7336
|
next(error);
|
|
5474
7337
|
} else {
|
|
5475
7338
|
next(
|
|
5476
|
-
new
|
|
7339
|
+
new InternalServerError21(
|
|
5477
7340
|
`Audio transcription failed: ${error.message}`
|
|
5478
7341
|
)
|
|
5479
7342
|
);
|
|
@@ -5493,7 +7356,7 @@ function useAudioTranscriptionController() {
|
|
|
5493
7356
|
});
|
|
5494
7357
|
} catch (error) {
|
|
5495
7358
|
next(
|
|
5496
|
-
new
|
|
7359
|
+
new InternalServerError21(
|
|
5497
7360
|
`Failed to get supported formats: ${error.message}`
|
|
5498
7361
|
)
|
|
5499
7362
|
);
|
|
@@ -5501,12 +7364,12 @@ function useAudioTranscriptionController() {
|
|
|
5501
7364
|
}
|
|
5502
7365
|
async function validateFormat(req, res, next) {
|
|
5503
7366
|
try {
|
|
5504
|
-
const schema =
|
|
5505
|
-
mimeType:
|
|
7367
|
+
const schema = Joi22.object({
|
|
7368
|
+
mimeType: Joi22.string().required()
|
|
5506
7369
|
});
|
|
5507
7370
|
const { error, value } = schema.validate(req.body);
|
|
5508
7371
|
if (error) {
|
|
5509
|
-
next(new
|
|
7372
|
+
next(new BadRequestError37(error.message));
|
|
5510
7373
|
return;
|
|
5511
7374
|
}
|
|
5512
7375
|
const { mimeType } = value;
|
|
@@ -5522,19 +7385,19 @@ function useAudioTranscriptionController() {
|
|
|
5522
7385
|
});
|
|
5523
7386
|
} catch (error) {
|
|
5524
7387
|
next(
|
|
5525
|
-
new
|
|
7388
|
+
new InternalServerError21(`Format validation failed: ${error.message}`)
|
|
5526
7389
|
);
|
|
5527
7390
|
}
|
|
5528
7391
|
}
|
|
5529
7392
|
async function checkPhonemeFromFile(req, res, next) {
|
|
5530
7393
|
if (!req.file) {
|
|
5531
|
-
next(new
|
|
7394
|
+
next(new BadRequestError37("Audio file is required"));
|
|
5532
7395
|
return;
|
|
5533
7396
|
}
|
|
5534
7397
|
try {
|
|
5535
7398
|
const { error, value } = phonemeMatchSchema.validate(req.body);
|
|
5536
7399
|
if (error) {
|
|
5537
|
-
next(new
|
|
7400
|
+
next(new BadRequestError37(error.message));
|
|
5538
7401
|
return;
|
|
5539
7402
|
}
|
|
5540
7403
|
const { targetPhoneme, options = {} } = value;
|
|
@@ -5542,7 +7405,7 @@ function useAudioTranscriptionController() {
|
|
|
5542
7405
|
if (!geminiService.validateAudioFormat(mimetype)) {
|
|
5543
7406
|
const supportedFormats = geminiService.getSupportedAudioFormats();
|
|
5544
7407
|
next(
|
|
5545
|
-
new
|
|
7408
|
+
new BadRequestError37(
|
|
5546
7409
|
`Unsupported audio format: ${mimetype}. Supported formats: ${supportedFormats.join(
|
|
5547
7410
|
", "
|
|
5548
7411
|
)}`
|
|
@@ -5553,7 +7416,7 @@ function useAudioTranscriptionController() {
|
|
|
5553
7416
|
const maxSizeBytes = 25 * 1024 * 1024;
|
|
5554
7417
|
if (size > maxSizeBytes) {
|
|
5555
7418
|
next(
|
|
5556
|
-
new
|
|
7419
|
+
new BadRequestError37(
|
|
5557
7420
|
`File size too large. Maximum allowed size is ${maxSizeBytes / (1024 * 1024)}MB`
|
|
5558
7421
|
)
|
|
5559
7422
|
);
|
|
@@ -5568,7 +7431,7 @@ function useAudioTranscriptionController() {
|
|
|
5568
7431
|
);
|
|
5569
7432
|
const processingTime = Date.now() - startTime;
|
|
5570
7433
|
if (!result.isMatch) {
|
|
5571
|
-
throw new
|
|
7434
|
+
throw new BadRequestError37(
|
|
5572
7435
|
`Phoneme "${targetPhoneme}" not found in the provided audio. Transcription: "${result.transcription}"`
|
|
5573
7436
|
);
|
|
5574
7437
|
}
|
|
@@ -5596,33 +7459,33 @@ function useAudioTranscriptionController() {
|
|
|
5596
7459
|
}
|
|
5597
7460
|
});
|
|
5598
7461
|
} catch (error) {
|
|
5599
|
-
if (error instanceof
|
|
7462
|
+
if (error instanceof AppError15) {
|
|
5600
7463
|
next(error);
|
|
5601
7464
|
} else {
|
|
5602
7465
|
next(
|
|
5603
|
-
new
|
|
7466
|
+
new InternalServerError21(`Phoneme analysis failed: ${error.message}`)
|
|
5604
7467
|
);
|
|
5605
7468
|
}
|
|
5606
7469
|
}
|
|
5607
7470
|
}
|
|
5608
7471
|
async function checkPhonemeFromBase64(req, res, next) {
|
|
5609
7472
|
try {
|
|
5610
|
-
const bodySchema =
|
|
5611
|
-
audioData:
|
|
5612
|
-
mimeType:
|
|
5613
|
-
targetPhoneme:
|
|
7473
|
+
const bodySchema = Joi22.object({
|
|
7474
|
+
audioData: Joi22.string().required(),
|
|
7475
|
+
mimeType: Joi22.string().required(),
|
|
7476
|
+
targetPhoneme: Joi22.string().required().min(1).max(10),
|
|
5614
7477
|
options: phonemeOptionsSchema.optional()
|
|
5615
7478
|
});
|
|
5616
7479
|
const { error, value } = bodySchema.validate(req.body);
|
|
5617
7480
|
if (error) {
|
|
5618
|
-
next(new
|
|
7481
|
+
next(new BadRequestError37(error.message));
|
|
5619
7482
|
return;
|
|
5620
7483
|
}
|
|
5621
7484
|
const { audioData, mimeType, targetPhoneme, options = {} } = value;
|
|
5622
7485
|
if (!geminiService.validateAudioFormat(mimeType)) {
|
|
5623
7486
|
const supportedFormats = geminiService.getSupportedAudioFormats();
|
|
5624
7487
|
next(
|
|
5625
|
-
new
|
|
7488
|
+
new BadRequestError37(
|
|
5626
7489
|
`Unsupported audio format: ${mimeType}. Supported formats: ${supportedFormats.join(
|
|
5627
7490
|
", "
|
|
5628
7491
|
)}`
|
|
@@ -5634,13 +7497,13 @@ function useAudioTranscriptionController() {
|
|
|
5634
7497
|
try {
|
|
5635
7498
|
audioBuffer = Buffer.from(audioData, "base64");
|
|
5636
7499
|
} catch (conversionError) {
|
|
5637
|
-
next(new
|
|
7500
|
+
next(new BadRequestError37("Invalid base64 audio data"));
|
|
5638
7501
|
return;
|
|
5639
7502
|
}
|
|
5640
7503
|
const maxSizeBytes = 25 * 1024 * 1024;
|
|
5641
7504
|
if (audioBuffer.length > maxSizeBytes) {
|
|
5642
7505
|
next(
|
|
5643
|
-
new
|
|
7506
|
+
new BadRequestError37(
|
|
5644
7507
|
`Audio data too large. Maximum allowed size is ${maxSizeBytes / (1024 * 1024)}MB`
|
|
5645
7508
|
)
|
|
5646
7509
|
);
|
|
@@ -5655,7 +7518,7 @@ function useAudioTranscriptionController() {
|
|
|
5655
7518
|
);
|
|
5656
7519
|
const processingTime = Date.now() - startTime;
|
|
5657
7520
|
if (!result.isMatch) {
|
|
5658
|
-
throw new
|
|
7521
|
+
throw new BadRequestError37(
|
|
5659
7522
|
`Phoneme "${targetPhoneme}" not found in the provided audio. Transcription: "${result.transcription}"`
|
|
5660
7523
|
);
|
|
5661
7524
|
}
|
|
@@ -5682,28 +7545,28 @@ function useAudioTranscriptionController() {
|
|
|
5682
7545
|
}
|
|
5683
7546
|
});
|
|
5684
7547
|
} catch (error) {
|
|
5685
|
-
if (error instanceof
|
|
7548
|
+
if (error instanceof AppError15) {
|
|
5686
7549
|
next(error);
|
|
5687
7550
|
} else {
|
|
5688
7551
|
next(
|
|
5689
|
-
new
|
|
7552
|
+
new InternalServerError21(`Phoneme analysis failed: ${error.message}`)
|
|
5690
7553
|
);
|
|
5691
7554
|
}
|
|
5692
7555
|
}
|
|
5693
7556
|
}
|
|
5694
7557
|
async function batchPhonemeCheck(req, res, next) {
|
|
5695
7558
|
if (!req.file) {
|
|
5696
|
-
next(new
|
|
7559
|
+
next(new BadRequestError37("Audio file is required"));
|
|
5697
7560
|
return;
|
|
5698
7561
|
}
|
|
5699
7562
|
try {
|
|
5700
|
-
const batchSchema =
|
|
5701
|
-
targetPhonemes:
|
|
7563
|
+
const batchSchema = Joi22.object({
|
|
7564
|
+
targetPhonemes: Joi22.array().items(Joi22.string().min(1).max(10)).min(1).max(20).required(),
|
|
5702
7565
|
options: phonemeOptionsSchema.optional()
|
|
5703
7566
|
});
|
|
5704
7567
|
const { error, value } = batchSchema.validate(req.body);
|
|
5705
7568
|
if (error) {
|
|
5706
|
-
next(new
|
|
7569
|
+
next(new BadRequestError37(error.message));
|
|
5707
7570
|
return;
|
|
5708
7571
|
}
|
|
5709
7572
|
const { targetPhonemes, options = {} } = value;
|
|
@@ -5711,7 +7574,7 @@ function useAudioTranscriptionController() {
|
|
|
5711
7574
|
if (!geminiService.validateAudioFormat(mimetype)) {
|
|
5712
7575
|
const supportedFormats = geminiService.getSupportedAudioFormats();
|
|
5713
7576
|
next(
|
|
5714
|
-
new
|
|
7577
|
+
new BadRequestError37(
|
|
5715
7578
|
`Unsupported audio format: ${mimetype}. Supported formats: ${supportedFormats.join(
|
|
5716
7579
|
", "
|
|
5717
7580
|
)}`
|
|
@@ -5722,7 +7585,7 @@ function useAudioTranscriptionController() {
|
|
|
5722
7585
|
const maxSizeBytes = 25 * 1024 * 1024;
|
|
5723
7586
|
if (size > maxSizeBytes) {
|
|
5724
7587
|
next(
|
|
5725
|
-
new
|
|
7588
|
+
new BadRequestError37(
|
|
5726
7589
|
`File size too large. Maximum allowed size is ${maxSizeBytes / (1024 * 1024)}MB`
|
|
5727
7590
|
)
|
|
5728
7591
|
);
|
|
@@ -5778,11 +7641,11 @@ function useAudioTranscriptionController() {
|
|
|
5778
7641
|
}
|
|
5779
7642
|
});
|
|
5780
7643
|
} catch (error) {
|
|
5781
|
-
if (error instanceof
|
|
7644
|
+
if (error instanceof AppError15) {
|
|
5782
7645
|
next(error);
|
|
5783
7646
|
} else {
|
|
5784
7647
|
next(
|
|
5785
|
-
new
|
|
7648
|
+
new InternalServerError21(
|
|
5786
7649
|
`Batch phoneme analysis failed: ${error.message}`
|
|
5787
7650
|
)
|
|
5788
7651
|
);
|
|
@@ -5803,7 +7666,7 @@ function useAudioTranscriptionController() {
|
|
|
5803
7666
|
}
|
|
5804
7667
|
});
|
|
5805
7668
|
} catch (error) {
|
|
5806
|
-
next(new
|
|
7669
|
+
next(new InternalServerError21(`Health check failed: ${error.message}`));
|
|
5807
7670
|
}
|
|
5808
7671
|
}
|
|
5809
7672
|
return {
|
|
@@ -5819,12 +7682,12 @@ function useAudioTranscriptionController() {
|
|
|
5819
7682
|
}
|
|
5820
7683
|
|
|
5821
7684
|
// src/resources/utils/util.controller.ts
|
|
5822
|
-
import
|
|
7685
|
+
import Joi23 from "joi";
|
|
5823
7686
|
import {
|
|
5824
|
-
AppError as
|
|
5825
|
-
BadRequestError as
|
|
5826
|
-
InternalServerError as
|
|
5827
|
-
logger as
|
|
7687
|
+
AppError as AppError16,
|
|
7688
|
+
BadRequestError as BadRequestError38,
|
|
7689
|
+
InternalServerError as InternalServerError22,
|
|
7690
|
+
logger as logger22
|
|
5828
7691
|
} from "@eeplatform/nodejs-utils";
|
|
5829
7692
|
function useUtilController() {
|
|
5830
7693
|
async function healthCheck(req, res, next) {
|
|
@@ -5841,32 +7704,32 @@ function useUtilController() {
|
|
|
5841
7704
|
}
|
|
5842
7705
|
});
|
|
5843
7706
|
} catch (error) {
|
|
5844
|
-
|
|
5845
|
-
next(new
|
|
7707
|
+
logger22.error("Health check failed", { error: error.message });
|
|
7708
|
+
next(new InternalServerError22("Health check failed"));
|
|
5846
7709
|
}
|
|
5847
7710
|
}
|
|
5848
7711
|
async function setGitHubVariables(req, res, next) {
|
|
5849
7712
|
try {
|
|
5850
7713
|
const { githubToken, repoUrl, environment, type, keyValues } = req.body;
|
|
5851
|
-
const validation =
|
|
5852
|
-
githubToken:
|
|
7714
|
+
const validation = Joi23.object({
|
|
7715
|
+
githubToken: Joi23.string().required().messages({
|
|
5853
7716
|
"string.empty": "GitHub token is required",
|
|
5854
7717
|
"any.required": "GitHub token is required"
|
|
5855
7718
|
}),
|
|
5856
|
-
repoUrl:
|
|
7719
|
+
repoUrl: Joi23.string().uri().required().messages({
|
|
5857
7720
|
"string.empty": "Repository URL is required",
|
|
5858
7721
|
"string.uri": "Repository URL must be a valid URL",
|
|
5859
7722
|
"any.required": "Repository URL is required"
|
|
5860
7723
|
}),
|
|
5861
|
-
environment:
|
|
7724
|
+
environment: Joi23.string().required().messages({
|
|
5862
7725
|
"string.empty": "Environment name is required",
|
|
5863
7726
|
"any.required": "Environment name is required"
|
|
5864
7727
|
}),
|
|
5865
|
-
type:
|
|
7728
|
+
type: Joi23.string().valid("env", "secret").required().messages({
|
|
5866
7729
|
"any.only": 'Type must be either "env" or "secret"',
|
|
5867
7730
|
"any.required": "Type is required"
|
|
5868
7731
|
}),
|
|
5869
|
-
keyValues:
|
|
7732
|
+
keyValues: Joi23.string().required().messages({
|
|
5870
7733
|
"string.empty": "Key-value pairs are required",
|
|
5871
7734
|
"any.required": "Key-value pairs are required"
|
|
5872
7735
|
})
|
|
@@ -5879,13 +7742,13 @@ function useUtilController() {
|
|
|
5879
7742
|
keyValues
|
|
5880
7743
|
});
|
|
5881
7744
|
if (error) {
|
|
5882
|
-
next(new
|
|
7745
|
+
next(new BadRequestError38(error.message));
|
|
5883
7746
|
return;
|
|
5884
7747
|
}
|
|
5885
7748
|
const repoUrlPattern = /github\.com[:\/]([^\/]+)\/(.+)\.git$/;
|
|
5886
7749
|
if (!repoUrlPattern.test(repoUrl)) {
|
|
5887
7750
|
next(
|
|
5888
|
-
new
|
|
7751
|
+
new BadRequestError38(
|
|
5889
7752
|
"Invalid GitHub repository URL format. Expected format: https://github.com/owner/repo.git"
|
|
5890
7753
|
)
|
|
5891
7754
|
);
|
|
@@ -5897,7 +7760,7 @@ function useUtilController() {
|
|
|
5897
7760
|
);
|
|
5898
7761
|
if (invalidLines.length > 0) {
|
|
5899
7762
|
next(
|
|
5900
|
-
new
|
|
7763
|
+
new BadRequestError38(
|
|
5901
7764
|
"Invalid key-value format. Each pair should be in format: KEY=value. Pairs should be separated by semicolons."
|
|
5902
7765
|
)
|
|
5903
7766
|
);
|
|
@@ -5911,7 +7774,7 @@ function useUtilController() {
|
|
|
5911
7774
|
type,
|
|
5912
7775
|
keyValues
|
|
5913
7776
|
});
|
|
5914
|
-
|
|
7777
|
+
logger22.info(`GitHub variables set successfully`, {
|
|
5915
7778
|
repoUrl,
|
|
5916
7779
|
environment,
|
|
5917
7780
|
type,
|
|
@@ -5928,15 +7791,15 @@ function useUtilController() {
|
|
|
5928
7791
|
}
|
|
5929
7792
|
});
|
|
5930
7793
|
} catch (error) {
|
|
5931
|
-
|
|
7794
|
+
logger22.error("Failed to set GitHub variables", {
|
|
5932
7795
|
error: error.message,
|
|
5933
7796
|
stack: error.stack
|
|
5934
7797
|
});
|
|
5935
|
-
if (error instanceof
|
|
7798
|
+
if (error instanceof AppError16) {
|
|
5936
7799
|
next(error);
|
|
5937
7800
|
} else {
|
|
5938
7801
|
next(
|
|
5939
|
-
new
|
|
7802
|
+
new InternalServerError22(
|
|
5940
7803
|
`Failed to set GitHub variables: ${error.message}`
|
|
5941
7804
|
)
|
|
5942
7805
|
);
|
|
@@ -5950,34 +7813,34 @@ function useUtilController() {
|
|
|
5950
7813
|
}
|
|
5951
7814
|
|
|
5952
7815
|
// src/resources/utils/transaction.schema.ts
|
|
5953
|
-
import
|
|
5954
|
-
var transactionSchema =
|
|
5955
|
-
_id:
|
|
5956
|
-
payment:
|
|
5957
|
-
user:
|
|
5958
|
-
org:
|
|
5959
|
-
type:
|
|
5960
|
-
amount:
|
|
5961
|
-
currency:
|
|
5962
|
-
description:
|
|
5963
|
-
metadata:
|
|
5964
|
-
subscriptionId:
|
|
5965
|
-
cycle:
|
|
5966
|
-
seats:
|
|
5967
|
-
promoCode:
|
|
7816
|
+
import Joi24 from "joi";
|
|
7817
|
+
var transactionSchema = Joi24.object({
|
|
7818
|
+
_id: Joi24.string().hex().optional().allow("", null),
|
|
7819
|
+
payment: Joi24.string().required(),
|
|
7820
|
+
user: Joi24.string().hex().optional().allow("", null),
|
|
7821
|
+
org: Joi24.string().hex().optional().allow("", null),
|
|
7822
|
+
type: Joi24.string().required(),
|
|
7823
|
+
amount: Joi24.number().positive().min(0).required(),
|
|
7824
|
+
currency: Joi24.string().required(),
|
|
7825
|
+
description: Joi24.string().optional().allow("", null),
|
|
7826
|
+
metadata: Joi24.object({
|
|
7827
|
+
subscriptionId: Joi24.string().hex().optional().allow("", null),
|
|
7828
|
+
cycle: Joi24.number().optional().allow("", null),
|
|
7829
|
+
seats: Joi24.number().optional().allow("", null),
|
|
7830
|
+
promoCode: Joi24.string().optional().allow("", null)
|
|
5968
7831
|
}).optional().allow("", null),
|
|
5969
|
-
status:
|
|
5970
|
-
createdAt:
|
|
5971
|
-
updatedAt:
|
|
5972
|
-
deletedAt:
|
|
7832
|
+
status: Joi24.string().optional().allow("", null),
|
|
7833
|
+
createdAt: Joi24.string().optional().allow("", null),
|
|
7834
|
+
updatedAt: Joi24.string().optional().allow("", null),
|
|
7835
|
+
deletedAt: Joi24.string().optional().allow("", null)
|
|
5973
7836
|
});
|
|
5974
7837
|
|
|
5975
7838
|
// src/resources/psgc/psgc.model.ts
|
|
5976
|
-
import
|
|
5977
|
-
var schemaPSGC =
|
|
5978
|
-
code:
|
|
5979
|
-
name:
|
|
5980
|
-
type:
|
|
7839
|
+
import Joi25 from "joi";
|
|
7840
|
+
var schemaPSGC = Joi25.object({
|
|
7841
|
+
code: Joi25.string().length(10).required(),
|
|
7842
|
+
name: Joi25.string().required(),
|
|
7843
|
+
type: Joi25.string().valid("Reg", "Prov", "City", "Mun", "Bgy").required()
|
|
5981
7844
|
});
|
|
5982
7845
|
function modelPSGC(data) {
|
|
5983
7846
|
const { error } = schemaPSGC.validate(data);
|
|
@@ -5993,18 +7856,18 @@ function modelPSGC(data) {
|
|
|
5993
7856
|
|
|
5994
7857
|
// src/resources/psgc/psgc.repository.ts
|
|
5995
7858
|
import {
|
|
5996
|
-
AppError as
|
|
5997
|
-
BadRequestError as
|
|
5998
|
-
InternalServerError as
|
|
5999
|
-
logger as
|
|
6000
|
-
makeCacheKey as
|
|
6001
|
-
paginate as
|
|
6002
|
-
useAtlas as
|
|
7859
|
+
AppError as AppError17,
|
|
7860
|
+
BadRequestError as BadRequestError39,
|
|
7861
|
+
InternalServerError as InternalServerError23,
|
|
7862
|
+
logger as logger23,
|
|
7863
|
+
makeCacheKey as makeCacheKey14,
|
|
7864
|
+
paginate as paginate9,
|
|
7865
|
+
useAtlas as useAtlas16,
|
|
6003
7866
|
useCache as useCache12
|
|
6004
7867
|
} from "@eeplatform/nodejs-utils";
|
|
6005
|
-
import { ObjectId as
|
|
7868
|
+
import { ObjectId as ObjectId21 } from "mongodb";
|
|
6006
7869
|
function usePSGCRepo() {
|
|
6007
|
-
const db =
|
|
7870
|
+
const db = useAtlas16.getDb();
|
|
6008
7871
|
if (!db) {
|
|
6009
7872
|
throw new Error("Unable to connect to server.");
|
|
6010
7873
|
}
|
|
@@ -6024,12 +7887,12 @@ function usePSGCRepo() {
|
|
|
6024
7887
|
}
|
|
6025
7888
|
function delCachedData() {
|
|
6026
7889
|
delNamespace().then(() => {
|
|
6027
|
-
|
|
7890
|
+
logger23.log({
|
|
6028
7891
|
level: "info",
|
|
6029
7892
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
6030
7893
|
});
|
|
6031
7894
|
}).catch((err) => {
|
|
6032
|
-
|
|
7895
|
+
logger23.log({
|
|
6033
7896
|
level: "error",
|
|
6034
7897
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
6035
7898
|
});
|
|
@@ -6042,16 +7905,16 @@ function usePSGCRepo() {
|
|
|
6042
7905
|
delCachedData();
|
|
6043
7906
|
return res.insertedId;
|
|
6044
7907
|
} catch (error) {
|
|
6045
|
-
|
|
7908
|
+
logger23.log({
|
|
6046
7909
|
level: "error",
|
|
6047
7910
|
message: error.message
|
|
6048
7911
|
});
|
|
6049
|
-
if (error instanceof
|
|
7912
|
+
if (error instanceof AppError17) {
|
|
6050
7913
|
throw error;
|
|
6051
7914
|
} else {
|
|
6052
7915
|
const isDuplicated = error.message.includes("duplicate");
|
|
6053
7916
|
if (isDuplicated) {
|
|
6054
|
-
throw new
|
|
7917
|
+
throw new BadRequestError39("Region already exists.");
|
|
6055
7918
|
}
|
|
6056
7919
|
throw new Error("Failed to create PSGC.");
|
|
6057
7920
|
}
|
|
@@ -6087,15 +7950,15 @@ function usePSGCRepo() {
|
|
|
6087
7950
|
query.$text = { $search: search };
|
|
6088
7951
|
cacheKeyOptions.search = search;
|
|
6089
7952
|
}
|
|
6090
|
-
const cacheKey =
|
|
6091
|
-
|
|
7953
|
+
const cacheKey = makeCacheKey14(namespace_collection, cacheKeyOptions);
|
|
7954
|
+
logger23.log({
|
|
6092
7955
|
level: "info",
|
|
6093
7956
|
message: `Cache key for getAll PSGC: ${cacheKey}`
|
|
6094
7957
|
});
|
|
6095
7958
|
try {
|
|
6096
7959
|
const cached = await getCache(cacheKey);
|
|
6097
7960
|
if (cached) {
|
|
6098
|
-
|
|
7961
|
+
logger23.log({
|
|
6099
7962
|
level: "info",
|
|
6100
7963
|
message: `Cache hit for getAll PSGC: ${cacheKey}`
|
|
6101
7964
|
});
|
|
@@ -6108,35 +7971,35 @@ function usePSGCRepo() {
|
|
|
6108
7971
|
{ $limit: limit }
|
|
6109
7972
|
]).toArray();
|
|
6110
7973
|
const length = await collection.countDocuments(query);
|
|
6111
|
-
const data =
|
|
7974
|
+
const data = paginate9(items, page, limit, length);
|
|
6112
7975
|
setCache(cacheKey, data, 600).then(() => {
|
|
6113
|
-
|
|
7976
|
+
logger23.log({
|
|
6114
7977
|
level: "info",
|
|
6115
7978
|
message: `Cache set for getAll PSGC: ${cacheKey}`
|
|
6116
7979
|
});
|
|
6117
7980
|
}).catch((err) => {
|
|
6118
|
-
|
|
7981
|
+
logger23.log({
|
|
6119
7982
|
level: "error",
|
|
6120
7983
|
message: `Failed to set cache for getAll PSGC: ${err.message}`
|
|
6121
7984
|
});
|
|
6122
7985
|
});
|
|
6123
7986
|
return data;
|
|
6124
7987
|
} catch (error) {
|
|
6125
|
-
|
|
7988
|
+
logger23.log({ level: "error", message: `${error}` });
|
|
6126
7989
|
throw error;
|
|
6127
7990
|
}
|
|
6128
7991
|
}
|
|
6129
7992
|
async function getById(_id) {
|
|
6130
7993
|
try {
|
|
6131
|
-
_id = new
|
|
7994
|
+
_id = new ObjectId21(_id);
|
|
6132
7995
|
} catch (error) {
|
|
6133
|
-
throw new
|
|
7996
|
+
throw new BadRequestError39("Invalid ID.");
|
|
6134
7997
|
}
|
|
6135
|
-
const cacheKey =
|
|
7998
|
+
const cacheKey = makeCacheKey14(namespace_collection, { _id: String(_id) });
|
|
6136
7999
|
try {
|
|
6137
8000
|
const cached = await getCache(cacheKey);
|
|
6138
8001
|
if (cached) {
|
|
6139
|
-
|
|
8002
|
+
logger23.log({
|
|
6140
8003
|
level: "info",
|
|
6141
8004
|
message: `Cache hit for getById PSGC: ${cacheKey}`
|
|
6142
8005
|
});
|
|
@@ -6147,25 +8010,25 @@ function usePSGCRepo() {
|
|
|
6147
8010
|
deletedAt: { $in: ["", null] }
|
|
6148
8011
|
});
|
|
6149
8012
|
if (!result) {
|
|
6150
|
-
throw new
|
|
8013
|
+
throw new BadRequestError39("Region not found.");
|
|
6151
8014
|
}
|
|
6152
8015
|
setCache(cacheKey, result, 300).then(() => {
|
|
6153
|
-
|
|
8016
|
+
logger23.log({
|
|
6154
8017
|
level: "info",
|
|
6155
8018
|
message: `Cache set for PSGC by id: ${cacheKey}`
|
|
6156
8019
|
});
|
|
6157
8020
|
}).catch((err) => {
|
|
6158
|
-
|
|
8021
|
+
logger23.log({
|
|
6159
8022
|
level: "error",
|
|
6160
8023
|
message: `Failed to set cache for PSGC by id: ${err.message}`
|
|
6161
8024
|
});
|
|
6162
8025
|
});
|
|
6163
8026
|
return result;
|
|
6164
8027
|
} catch (error) {
|
|
6165
|
-
if (error instanceof
|
|
8028
|
+
if (error instanceof AppError17) {
|
|
6166
8029
|
throw error;
|
|
6167
8030
|
} else {
|
|
6168
|
-
throw new
|
|
8031
|
+
throw new InternalServerError23("Failed to get PSGC.");
|
|
6169
8032
|
}
|
|
6170
8033
|
}
|
|
6171
8034
|
}
|
|
@@ -6189,15 +8052,15 @@ function usePSGCRepo() {
|
|
|
6189
8052
|
query.code = { $regex: `^${prefix}` };
|
|
6190
8053
|
cacheKeyOptions.prefix = prefix;
|
|
6191
8054
|
}
|
|
6192
|
-
const cacheKey =
|
|
6193
|
-
|
|
8055
|
+
const cacheKey = makeCacheKey14(namespace_collection, { name });
|
|
8056
|
+
logger23.log({
|
|
6194
8057
|
level: "info",
|
|
6195
8058
|
message: `Query for getByName PSGC: ${JSON.stringify(query)}`
|
|
6196
8059
|
});
|
|
6197
8060
|
try {
|
|
6198
8061
|
const cached = await getCache(cacheKey);
|
|
6199
8062
|
if (cached) {
|
|
6200
|
-
|
|
8063
|
+
logger23.log({
|
|
6201
8064
|
level: "info",
|
|
6202
8065
|
message: `Cache hit for getByName PSGC: ${cacheKey}`
|
|
6203
8066
|
});
|
|
@@ -6205,36 +8068,36 @@ function usePSGCRepo() {
|
|
|
6205
8068
|
}
|
|
6206
8069
|
const result = await collection.findOne(query);
|
|
6207
8070
|
setCache(cacheKey, result, 300).then(() => {
|
|
6208
|
-
|
|
8071
|
+
logger23.log({
|
|
6209
8072
|
level: "info",
|
|
6210
8073
|
message: `Cache set for PSGC by name: ${cacheKey}`
|
|
6211
8074
|
});
|
|
6212
8075
|
}).catch((err) => {
|
|
6213
|
-
|
|
8076
|
+
logger23.log({
|
|
6214
8077
|
level: "error",
|
|
6215
8078
|
message: `Failed to set cache for PSGC by name: ${err.message}`
|
|
6216
8079
|
});
|
|
6217
8080
|
});
|
|
6218
8081
|
return result;
|
|
6219
8082
|
} catch (error) {
|
|
6220
|
-
if (error instanceof
|
|
8083
|
+
if (error instanceof AppError17) {
|
|
6221
8084
|
throw error;
|
|
6222
8085
|
} else {
|
|
6223
|
-
throw new
|
|
8086
|
+
throw new InternalServerError23("Failed to get PSGC.");
|
|
6224
8087
|
}
|
|
6225
8088
|
}
|
|
6226
8089
|
}
|
|
6227
8090
|
async function updateFieldById({ _id, field, value } = {}, session) {
|
|
6228
8091
|
const allowedFields = ["name"];
|
|
6229
8092
|
if (!allowedFields.includes(field)) {
|
|
6230
|
-
throw new
|
|
8093
|
+
throw new BadRequestError39(
|
|
6231
8094
|
`Field "${field}" is not allowed to be updated.`
|
|
6232
8095
|
);
|
|
6233
8096
|
}
|
|
6234
8097
|
try {
|
|
6235
|
-
_id = new
|
|
8098
|
+
_id = new ObjectId21(_id);
|
|
6236
8099
|
} catch (error) {
|
|
6237
|
-
throw new
|
|
8100
|
+
throw new BadRequestError39("Invalid ID.");
|
|
6238
8101
|
}
|
|
6239
8102
|
try {
|
|
6240
8103
|
await collection.updateOne(
|
|
@@ -6245,14 +8108,14 @@ function usePSGCRepo() {
|
|
|
6245
8108
|
delCachedData();
|
|
6246
8109
|
return `Successfully updated PSGC ${field}.`;
|
|
6247
8110
|
} catch (error) {
|
|
6248
|
-
throw new
|
|
8111
|
+
throw new InternalServerError23(`Failed to update PSGC ${field}.`);
|
|
6249
8112
|
}
|
|
6250
8113
|
}
|
|
6251
8114
|
async function deleteById(_id) {
|
|
6252
8115
|
try {
|
|
6253
|
-
_id = new
|
|
8116
|
+
_id = new ObjectId21(_id);
|
|
6254
8117
|
} catch (error) {
|
|
6255
|
-
throw new
|
|
8118
|
+
throw new BadRequestError39("Invalid ID.");
|
|
6256
8119
|
}
|
|
6257
8120
|
try {
|
|
6258
8121
|
await collection.updateOne(
|
|
@@ -6262,7 +8125,7 @@ function usePSGCRepo() {
|
|
|
6262
8125
|
delCachedData();
|
|
6263
8126
|
return "Successfully deleted PSGC.";
|
|
6264
8127
|
} catch (error) {
|
|
6265
|
-
throw new
|
|
8128
|
+
throw new InternalServerError23("Failed to delete PSGC.");
|
|
6266
8129
|
}
|
|
6267
8130
|
}
|
|
6268
8131
|
async function setRegionProvinceName() {
|
|
@@ -6312,8 +8175,8 @@ function usePSGCRepo() {
|
|
|
6312
8175
|
}
|
|
6313
8176
|
|
|
6314
8177
|
// src/resources/psgc/psgc.controller.ts
|
|
6315
|
-
import { BadRequestError as
|
|
6316
|
-
import
|
|
8178
|
+
import { BadRequestError as BadRequestError40 } from "@eeplatform/nodejs-utils";
|
|
8179
|
+
import Joi26 from "joi";
|
|
6317
8180
|
function usePSGCController() {
|
|
6318
8181
|
const {
|
|
6319
8182
|
add: _add,
|
|
@@ -6327,7 +8190,7 @@ function usePSGCController() {
|
|
|
6327
8190
|
const value = req.body;
|
|
6328
8191
|
const { error } = schemaPSGC.validate(value);
|
|
6329
8192
|
if (error) {
|
|
6330
|
-
next(new
|
|
8193
|
+
next(new BadRequestError40(error.message));
|
|
6331
8194
|
return;
|
|
6332
8195
|
}
|
|
6333
8196
|
try {
|
|
@@ -6343,12 +8206,12 @@ function usePSGCController() {
|
|
|
6343
8206
|
}
|
|
6344
8207
|
async function getAll(req, res, next) {
|
|
6345
8208
|
const query = req.query;
|
|
6346
|
-
const validation =
|
|
6347
|
-
page:
|
|
6348
|
-
limit:
|
|
6349
|
-
search:
|
|
6350
|
-
type:
|
|
6351
|
-
prefix:
|
|
8209
|
+
const validation = Joi26.object({
|
|
8210
|
+
page: Joi26.number().min(1).optional().allow("", null),
|
|
8211
|
+
limit: Joi26.number().min(1).optional().allow("", null),
|
|
8212
|
+
search: Joi26.string().optional().allow("", null),
|
|
8213
|
+
type: Joi26.string().valid("Reg", "Prov", "City", "Mun", "Bgy").required(),
|
|
8214
|
+
prefix: Joi26.string().optional().allow("", null)
|
|
6352
8215
|
});
|
|
6353
8216
|
const { error } = validation.validate(query);
|
|
6354
8217
|
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
@@ -6358,16 +8221,16 @@ function usePSGCController() {
|
|
|
6358
8221
|
const prefix = req.query.prefix ? String(req.query.prefix) : "";
|
|
6359
8222
|
const isPageNumber = isFinite(page);
|
|
6360
8223
|
if (!isPageNumber) {
|
|
6361
|
-
next(new
|
|
8224
|
+
next(new BadRequestError40("Invalid page number."));
|
|
6362
8225
|
return;
|
|
6363
8226
|
}
|
|
6364
8227
|
const isLimitNumber = isFinite(limit);
|
|
6365
8228
|
if (!isLimitNumber) {
|
|
6366
|
-
next(new
|
|
8229
|
+
next(new BadRequestError40("Invalid limit number."));
|
|
6367
8230
|
return;
|
|
6368
8231
|
}
|
|
6369
8232
|
if (error) {
|
|
6370
|
-
next(new
|
|
8233
|
+
next(new BadRequestError40(error.message));
|
|
6371
8234
|
return;
|
|
6372
8235
|
}
|
|
6373
8236
|
try {
|
|
@@ -6386,12 +8249,12 @@ function usePSGCController() {
|
|
|
6386
8249
|
}
|
|
6387
8250
|
async function getById(req, res, next) {
|
|
6388
8251
|
const id = req.params.id;
|
|
6389
|
-
const validation =
|
|
6390
|
-
id:
|
|
8252
|
+
const validation = Joi26.object({
|
|
8253
|
+
id: Joi26.string().hex().required()
|
|
6391
8254
|
});
|
|
6392
8255
|
const { error } = validation.validate({ id });
|
|
6393
8256
|
if (error) {
|
|
6394
|
-
next(new
|
|
8257
|
+
next(new BadRequestError40(error.message));
|
|
6395
8258
|
return;
|
|
6396
8259
|
}
|
|
6397
8260
|
try {
|
|
@@ -6407,12 +8270,12 @@ function usePSGCController() {
|
|
|
6407
8270
|
}
|
|
6408
8271
|
async function getByName(req, res, next) {
|
|
6409
8272
|
const name = req.params.name;
|
|
6410
|
-
const validation =
|
|
6411
|
-
name:
|
|
8273
|
+
const validation = Joi26.object({
|
|
8274
|
+
name: Joi26.string().required()
|
|
6412
8275
|
});
|
|
6413
8276
|
const { error } = validation.validate({ name });
|
|
6414
8277
|
if (error) {
|
|
6415
|
-
next(new
|
|
8278
|
+
next(new BadRequestError40(error.message));
|
|
6416
8279
|
return;
|
|
6417
8280
|
}
|
|
6418
8281
|
try {
|
|
@@ -6429,14 +8292,14 @@ function usePSGCController() {
|
|
|
6429
8292
|
async function updateField(req, res, next) {
|
|
6430
8293
|
const _id = req.params.id;
|
|
6431
8294
|
const { field, value } = req.body;
|
|
6432
|
-
const validation =
|
|
6433
|
-
_id:
|
|
6434
|
-
field:
|
|
6435
|
-
value:
|
|
8295
|
+
const validation = Joi26.object({
|
|
8296
|
+
_id: Joi26.string().hex().required(),
|
|
8297
|
+
field: Joi26.string().valid("name", "director", "directorName").required(),
|
|
8298
|
+
value: Joi26.string().required()
|
|
6436
8299
|
});
|
|
6437
8300
|
const { error } = validation.validate({ _id, field, value });
|
|
6438
8301
|
if (error) {
|
|
6439
|
-
next(new
|
|
8302
|
+
next(new BadRequestError40(error.message));
|
|
6440
8303
|
return;
|
|
6441
8304
|
}
|
|
6442
8305
|
try {
|
|
@@ -6449,12 +8312,12 @@ function usePSGCController() {
|
|
|
6449
8312
|
}
|
|
6450
8313
|
async function deleteById(req, res, next) {
|
|
6451
8314
|
const _id = req.params.id;
|
|
6452
|
-
const validation =
|
|
6453
|
-
_id:
|
|
8315
|
+
const validation = Joi26.object({
|
|
8316
|
+
_id: Joi26.string().hex().required()
|
|
6454
8317
|
});
|
|
6455
8318
|
const { error } = validation.validate({ _id });
|
|
6456
8319
|
if (error) {
|
|
6457
|
-
next(new
|
|
8320
|
+
next(new BadRequestError40(error.message));
|
|
6458
8321
|
return;
|
|
6459
8322
|
}
|
|
6460
8323
|
try {
|
|
@@ -6523,12 +8386,24 @@ export {
|
|
|
6523
8386
|
XENDIT_SECRET_KEY,
|
|
6524
8387
|
addressSchema,
|
|
6525
8388
|
isDev,
|
|
8389
|
+
modelApp,
|
|
6526
8390
|
modelPSGC,
|
|
8391
|
+
modelPermission,
|
|
8392
|
+
modelPermissionGroup,
|
|
8393
|
+
schemaApp,
|
|
8394
|
+
schemaAppUpdate,
|
|
6527
8395
|
schemaOrg,
|
|
6528
8396
|
schemaPSGC,
|
|
8397
|
+
schemaPermission,
|
|
8398
|
+
schemaPermissionGroup,
|
|
8399
|
+
schemaPermissionGroupUpdate,
|
|
8400
|
+
schemaPermissionUpdate,
|
|
6529
8401
|
transactionSchema,
|
|
6530
8402
|
useAddressController,
|
|
6531
8403
|
useAddressRepo,
|
|
8404
|
+
useAppController,
|
|
8405
|
+
useAppRepo,
|
|
8406
|
+
useAppService,
|
|
6532
8407
|
useAudioTranscriptionController,
|
|
6533
8408
|
useAuthController,
|
|
6534
8409
|
useAuthService,
|
|
@@ -6546,6 +8421,12 @@ export {
|
|
|
6546
8421
|
useOrgService,
|
|
6547
8422
|
usePSGCController,
|
|
6548
8423
|
usePSGCRepo,
|
|
8424
|
+
usePermissionController,
|
|
8425
|
+
usePermissionGroupController,
|
|
8426
|
+
usePermissionGroupRepo,
|
|
8427
|
+
usePermissionGroupService,
|
|
8428
|
+
usePermissionRepo,
|
|
8429
|
+
usePermissionService,
|
|
6549
8430
|
useRoleController,
|
|
6550
8431
|
useRoleRepo,
|
|
6551
8432
|
useTokenRepo,
|