@goweekdays/core 2.3.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.d.ts +125 -3
- package/dist/index.js +2004 -722
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2005 -715
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/tsconfig.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -807,25 +807,25 @@ function useAuthService() {
|
|
|
807
807
|
}
|
|
808
808
|
|
|
809
809
|
// src/resources/auth/auth.controller.ts
|
|
810
|
-
import
|
|
810
|
+
import Joi32 from "joi";
|
|
811
811
|
import {
|
|
812
|
-
AppError as
|
|
813
|
-
BadRequestError as
|
|
814
|
-
InternalServerError as
|
|
815
|
-
logger as
|
|
812
|
+
AppError as AppError17,
|
|
813
|
+
BadRequestError as BadRequestError42,
|
|
814
|
+
InternalServerError as InternalServerError21,
|
|
815
|
+
logger as logger21
|
|
816
816
|
} from "@goweekdays/utils";
|
|
817
817
|
|
|
818
818
|
// src/resources/verification/verification.service.ts
|
|
819
819
|
import {
|
|
820
820
|
useMailer,
|
|
821
821
|
compileHandlebar,
|
|
822
|
-
logger as
|
|
822
|
+
logger as logger20,
|
|
823
823
|
getDirectory,
|
|
824
|
-
BadRequestError as
|
|
824
|
+
BadRequestError as BadRequestError41,
|
|
825
825
|
NotFoundError as NotFoundError4,
|
|
826
|
-
InternalServerError as
|
|
827
|
-
useAtlas as
|
|
828
|
-
AppError as
|
|
826
|
+
InternalServerError as InternalServerError20,
|
|
827
|
+
useAtlas as useAtlas19,
|
|
828
|
+
AppError as AppError16
|
|
829
829
|
} from "@goweekdays/utils";
|
|
830
830
|
|
|
831
831
|
// src/resources/verification/verification.model.ts
|
|
@@ -1228,15 +1228,15 @@ var DOMAIN = process.env.DOMAIN || "localhost";
|
|
|
1228
1228
|
|
|
1229
1229
|
// src/resources/user/user.service.ts
|
|
1230
1230
|
import {
|
|
1231
|
-
AppError as
|
|
1232
|
-
BadRequestError as
|
|
1233
|
-
InternalServerError as
|
|
1231
|
+
AppError as AppError14,
|
|
1232
|
+
BadRequestError as BadRequestError39,
|
|
1233
|
+
InternalServerError as InternalServerError18,
|
|
1234
1234
|
NotFoundError as NotFoundError3,
|
|
1235
1235
|
hashPassword,
|
|
1236
|
-
logger as
|
|
1237
|
-
makeCacheKey as
|
|
1238
|
-
useAtlas as
|
|
1239
|
-
useCache as
|
|
1236
|
+
logger as logger19,
|
|
1237
|
+
makeCacheKey as makeCacheKey14,
|
|
1238
|
+
useAtlas as useAtlas18,
|
|
1239
|
+
useCache as useCache15,
|
|
1240
1240
|
useS3
|
|
1241
1241
|
} from "@goweekdays/utils";
|
|
1242
1242
|
|
|
@@ -4154,6 +4154,33 @@ function usePermissionGroupService() {
|
|
|
4154
4154
|
description: "Allow user to revoke invitations"
|
|
4155
4155
|
}
|
|
4156
4156
|
]
|
|
4157
|
+
},
|
|
4158
|
+
{
|
|
4159
|
+
key: "billing",
|
|
4160
|
+
label: "Billing",
|
|
4161
|
+
permissions: [
|
|
4162
|
+
{
|
|
4163
|
+
key: "billing.view",
|
|
4164
|
+
name: "View Billing",
|
|
4165
|
+
description: "Allow user to view billing"
|
|
4166
|
+
}
|
|
4167
|
+
]
|
|
4168
|
+
},
|
|
4169
|
+
{
|
|
4170
|
+
key: "setting",
|
|
4171
|
+
label: "Setting",
|
|
4172
|
+
permissions: [
|
|
4173
|
+
{
|
|
4174
|
+
key: "setting.view",
|
|
4175
|
+
name: "View Setting",
|
|
4176
|
+
description: "Allow user to view setting"
|
|
4177
|
+
},
|
|
4178
|
+
{
|
|
4179
|
+
key: "setting.edit.details",
|
|
4180
|
+
name: "Edit Setting Details",
|
|
4181
|
+
description: "Allow user to edit setting details"
|
|
4182
|
+
}
|
|
4183
|
+
]
|
|
4157
4184
|
}
|
|
4158
4185
|
];
|
|
4159
4186
|
for (const app of apps.items) {
|
|
@@ -4588,13 +4615,25 @@ function usePermissionGroupController() {
|
|
|
4588
4615
|
import { BadRequestError as BadRequestError23 } from "@goweekdays/utils";
|
|
4589
4616
|
import Joi17 from "joi";
|
|
4590
4617
|
import { ObjectId as ObjectId15 } from "mongodb";
|
|
4591
|
-
var
|
|
4618
|
+
var schema = {
|
|
4592
4619
|
name: Joi17.string().max(255).required(),
|
|
4593
4620
|
description: Joi17.string().max(1024).optional().allow("", null),
|
|
4594
|
-
email: Joi17.string().email().max(255).
|
|
4595
|
-
contact: Joi17.string().max(50).optional().allow("", null)
|
|
4621
|
+
email: Joi17.string().email().max(255).required(),
|
|
4622
|
+
contact: Joi17.string().max(50).optional().allow("", null)
|
|
4623
|
+
};
|
|
4624
|
+
var schemaOrg = Joi17.object({
|
|
4625
|
+
...schema,
|
|
4596
4626
|
createdBy: Joi17.string().hex().required()
|
|
4597
4627
|
});
|
|
4628
|
+
var schemaOrgAdd = Joi17.object({
|
|
4629
|
+
...schema,
|
|
4630
|
+
createdBy: Joi17.string().hex().required(),
|
|
4631
|
+
seats: Joi17.number().required()
|
|
4632
|
+
});
|
|
4633
|
+
var schemaOrgUpdate = Joi17.object({
|
|
4634
|
+
...schema,
|
|
4635
|
+
_id: Joi17.string().hex().required()
|
|
4636
|
+
});
|
|
4598
4637
|
function modelOrg(value) {
|
|
4599
4638
|
const { error } = schemaOrg.validate(value);
|
|
4600
4639
|
if (error) {
|
|
@@ -4877,6 +4916,30 @@ function useOrgRepo() {
|
|
|
4877
4916
|
throw new InternalServerError11("Failed to delete organization.");
|
|
4878
4917
|
}
|
|
4879
4918
|
}
|
|
4919
|
+
async function updateById(_id, options) {
|
|
4920
|
+
const { error } = schemaOrgUpdate.validate({ ...options, _id });
|
|
4921
|
+
if (error) {
|
|
4922
|
+
throw new BadRequestError24(error.message);
|
|
4923
|
+
}
|
|
4924
|
+
try {
|
|
4925
|
+
_id = new ObjectId16(_id);
|
|
4926
|
+
} catch (error2) {
|
|
4927
|
+
throw new BadRequestError24("Invalid org ID.");
|
|
4928
|
+
}
|
|
4929
|
+
try {
|
|
4930
|
+
await collection.updateOne(
|
|
4931
|
+
{ _id },
|
|
4932
|
+
{ $set: { ...options, updatedAt: /* @__PURE__ */ new Date() } }
|
|
4933
|
+
);
|
|
4934
|
+
delCachedData();
|
|
4935
|
+
} catch (error2) {
|
|
4936
|
+
const isDuplicated = error2.message.includes("duplicate");
|
|
4937
|
+
if (isDuplicated) {
|
|
4938
|
+
throw new BadRequestError24("Organization name already exist.");
|
|
4939
|
+
}
|
|
4940
|
+
throw new InternalServerError11("Failed to update org info.");
|
|
4941
|
+
}
|
|
4942
|
+
}
|
|
4880
4943
|
return {
|
|
4881
4944
|
createIndexes,
|
|
4882
4945
|
add,
|
|
@@ -4884,12 +4947,13 @@ function useOrgRepo() {
|
|
|
4884
4947
|
getById,
|
|
4885
4948
|
updateFieldById,
|
|
4886
4949
|
deleteById,
|
|
4887
|
-
getByName
|
|
4950
|
+
getByName,
|
|
4951
|
+
updateById
|
|
4888
4952
|
};
|
|
4889
4953
|
}
|
|
4890
4954
|
|
|
4891
4955
|
// src/resources/organization/organization.service.ts
|
|
4892
|
-
import { BadRequestError as
|
|
4956
|
+
import { BadRequestError as BadRequestError37, useAtlas as useAtlas17 } from "@goweekdays/utils";
|
|
4893
4957
|
|
|
4894
4958
|
// src/resources/member/member.controller.ts
|
|
4895
4959
|
import Joi20 from "joi";
|
|
@@ -5414,162 +5478,1353 @@ function useMemberController() {
|
|
|
5414
5478
|
};
|
|
5415
5479
|
}
|
|
5416
5480
|
|
|
5417
|
-
// src/resources/
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5481
|
+
// src/resources/subscription/subscription.model.ts
|
|
5482
|
+
import { BadRequestError as BadRequestError29 } from "@goweekdays/utils";
|
|
5483
|
+
import Joi21 from "joi";
|
|
5484
|
+
import { ObjectId as ObjectId17 } from "mongodb";
|
|
5485
|
+
var schema2 = {
|
|
5486
|
+
seats: Joi21.number().integer().min(1).required(),
|
|
5487
|
+
paidSeats: Joi21.number().integer().min(0).required(),
|
|
5488
|
+
amount: Joi21.number().positive().required(),
|
|
5489
|
+
promoCode: Joi21.string().optional().allow("", null),
|
|
5490
|
+
nextBillingDate: Joi21.date().optional().allow("", null)
|
|
5491
|
+
};
|
|
5492
|
+
var schemaSubscription = Joi21.object({
|
|
5493
|
+
...schema2,
|
|
5494
|
+
org: Joi21.string().hex().length(24).required(),
|
|
5495
|
+
currency: Joi21.string().length(3).required(),
|
|
5496
|
+
billingCycle: Joi21.string().valid("monthly", "yearly").required()
|
|
5497
|
+
});
|
|
5498
|
+
var schemaSubscriptionUpdate = Joi21.object({
|
|
5499
|
+
...schema2,
|
|
5500
|
+
status: Joi21.string().optional().allow("", null)
|
|
5501
|
+
});
|
|
5502
|
+
var schemaSubscriptionSeats = Joi21.object({
|
|
5503
|
+
id: Joi21.string().hex().length(24).required(),
|
|
5504
|
+
seats: Joi21.number().integer().min(1).required(),
|
|
5505
|
+
amount: Joi21.number().positive().optional().allow(null, 0),
|
|
5506
|
+
user: Joi21.string().hex().length(24).required()
|
|
5507
|
+
});
|
|
5508
|
+
function modelSubscription(data) {
|
|
5509
|
+
const { error } = schemaSubscription.validate(data);
|
|
5510
|
+
if (error) {
|
|
5511
|
+
throw new BadRequestError29(`Invalid subscription data: ${error.message}`);
|
|
5512
|
+
}
|
|
5513
|
+
if (data._id && typeof data._id === "string") {
|
|
5429
5514
|
try {
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
app: "org",
|
|
5434
|
-
limit: 100
|
|
5435
|
-
});
|
|
5436
|
-
let permissions = [];
|
|
5437
|
-
if (allPermissions && allPermissions.items && allPermissions.items.length) {
|
|
5438
|
-
permissions = allPermissions.items.map((perm) => perm.key);
|
|
5439
|
-
}
|
|
5440
|
-
if (permissions.length === 0) {
|
|
5441
|
-
throw new Error("No permissions found for the organization type.");
|
|
5442
|
-
}
|
|
5443
|
-
const createdBy = String(value.createdBy);
|
|
5444
|
-
const roleData = {
|
|
5445
|
-
org: String(org),
|
|
5446
|
-
name: "Owner",
|
|
5447
|
-
description: "Owner of the organization",
|
|
5448
|
-
permissions,
|
|
5449
|
-
createdBy,
|
|
5450
|
-
app: "org"
|
|
5451
|
-
};
|
|
5452
|
-
const role = await addRole(roleData, session);
|
|
5453
|
-
if (!role) {
|
|
5454
|
-
throw new BadRequestError29("Role is required to create org member.");
|
|
5455
|
-
}
|
|
5456
|
-
const user = await getUserById(createdBy);
|
|
5457
|
-
if (!user) {
|
|
5458
|
-
throw new BadRequestError29("User is required to create org member.");
|
|
5459
|
-
}
|
|
5460
|
-
await addMember(
|
|
5461
|
-
{
|
|
5462
|
-
role: String(role),
|
|
5463
|
-
roleName: roleData.name,
|
|
5464
|
-
org: String(org),
|
|
5465
|
-
name: `${user.firstName} ${user.lastName}`,
|
|
5466
|
-
user: createdBy,
|
|
5467
|
-
app: "org"
|
|
5468
|
-
},
|
|
5469
|
-
session
|
|
5470
|
-
);
|
|
5471
|
-
await session?.commitTransaction();
|
|
5472
|
-
return String(org);
|
|
5473
|
-
} catch (error) {
|
|
5474
|
-
await session?.abortTransaction();
|
|
5475
|
-
throw error;
|
|
5476
|
-
} finally {
|
|
5477
|
-
await session?.endSession();
|
|
5515
|
+
data._id = new ObjectId17(data._id);
|
|
5516
|
+
} catch (error2) {
|
|
5517
|
+
throw new BadRequestError29("Invalid subscription ID.");
|
|
5478
5518
|
}
|
|
5479
5519
|
}
|
|
5520
|
+
try {
|
|
5521
|
+
data.org = new ObjectId17(data.org);
|
|
5522
|
+
} catch (error2) {
|
|
5523
|
+
throw new BadRequestError29("Invalid organization ID.");
|
|
5524
|
+
}
|
|
5480
5525
|
return {
|
|
5481
|
-
|
|
5526
|
+
_id: data._id,
|
|
5527
|
+
org: data.org,
|
|
5528
|
+
seats: data.seats,
|
|
5529
|
+
paidSeats: data.paidSeats,
|
|
5530
|
+
amount: data.amount,
|
|
5531
|
+
currency: data.currency,
|
|
5532
|
+
billingCycle: data.billingCycle,
|
|
5533
|
+
promoCode: data.promoCode,
|
|
5534
|
+
status: data.status ?? "active",
|
|
5535
|
+
nextBillingDate: data.nextBillingDate,
|
|
5536
|
+
createdAt: data.createdAt ?? /* @__PURE__ */ new Date(),
|
|
5537
|
+
updatedAt: data.updatedAt ?? ""
|
|
5482
5538
|
};
|
|
5483
5539
|
}
|
|
5484
5540
|
|
|
5485
|
-
// src/resources/
|
|
5486
|
-
import {
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5541
|
+
// src/resources/subscription/subscription.repository.ts
|
|
5542
|
+
import {
|
|
5543
|
+
AppError as AppError11,
|
|
5544
|
+
BadRequestError as BadRequestError30,
|
|
5545
|
+
InternalServerError as InternalServerError15,
|
|
5546
|
+
logger as logger16,
|
|
5547
|
+
makeCacheKey as makeCacheKey11,
|
|
5548
|
+
paginate as paginate9,
|
|
5549
|
+
useAtlas as useAtlas13,
|
|
5550
|
+
useCache as useCache12
|
|
5551
|
+
} from "@goweekdays/utils";
|
|
5552
|
+
import Joi22 from "joi";
|
|
5553
|
+
import { ObjectId as ObjectId18 } from "mongodb";
|
|
5554
|
+
function useSubscriptionRepo() {
|
|
5555
|
+
const db = useAtlas13.getDb();
|
|
5556
|
+
if (!db) {
|
|
5557
|
+
throw new InternalServerError15("Unable to connect to server.");
|
|
5558
|
+
}
|
|
5559
|
+
const namespace_collection = "subscriptions";
|
|
5560
|
+
const collection = db.collection(namespace_collection);
|
|
5561
|
+
const { getCache, setCache, delNamespace } = useCache12(namespace_collection);
|
|
5562
|
+
function delCachedData() {
|
|
5563
|
+
delNamespace().then(() => {
|
|
5564
|
+
logger16.log({
|
|
5565
|
+
level: "info",
|
|
5566
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
5567
|
+
});
|
|
5568
|
+
}).catch((err) => {
|
|
5569
|
+
logger16.log({
|
|
5570
|
+
level: "error",
|
|
5571
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
5572
|
+
});
|
|
5573
|
+
});
|
|
5574
|
+
}
|
|
5575
|
+
async function createIndexes() {
|
|
5576
|
+
try {
|
|
5577
|
+
await collection.createIndexes([
|
|
5578
|
+
{
|
|
5579
|
+
key: {
|
|
5580
|
+
org: 1
|
|
5581
|
+
},
|
|
5582
|
+
name: "org_index"
|
|
5583
|
+
},
|
|
5584
|
+
{
|
|
5585
|
+
key: { org: 1, status: 1 },
|
|
5586
|
+
name: "org_status_index"
|
|
5587
|
+
}
|
|
5588
|
+
]);
|
|
5589
|
+
} catch (error) {
|
|
5502
5590
|
}
|
|
5591
|
+
}
|
|
5592
|
+
createIndexes().catch((error) => {
|
|
5593
|
+
logger16.log({
|
|
5594
|
+
level: "error",
|
|
5595
|
+
message: `Failed to create indexes for subscriptions collection: ${error.message}`
|
|
5596
|
+
});
|
|
5597
|
+
});
|
|
5598
|
+
async function add(value, session) {
|
|
5503
5599
|
try {
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5600
|
+
value = modelSubscription(value);
|
|
5601
|
+
const result = await collection.insertOne(value, { session });
|
|
5602
|
+
delCachedData();
|
|
5603
|
+
return result.insertedId.toString();
|
|
5604
|
+
} catch (error) {
|
|
5605
|
+
logger16.log({
|
|
5606
|
+
level: "error",
|
|
5607
|
+
message: `${error}`
|
|
5508
5608
|
});
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5609
|
+
if (error instanceof AppError11) {
|
|
5610
|
+
throw error;
|
|
5611
|
+
}
|
|
5612
|
+
throw new InternalServerError15("Failed to add subscription.");
|
|
5512
5613
|
}
|
|
5513
5614
|
}
|
|
5514
|
-
async function
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5615
|
+
async function getAll({
|
|
5616
|
+
page = 1,
|
|
5617
|
+
limit = 10,
|
|
5618
|
+
search = "",
|
|
5619
|
+
status = "active"
|
|
5620
|
+
} = {}) {
|
|
5621
|
+
page = page < 1 ? page - 1 : page;
|
|
5622
|
+
const query = { status };
|
|
5623
|
+
const cacheKeyOptions = {
|
|
5624
|
+
page,
|
|
5625
|
+
limit,
|
|
5626
|
+
search,
|
|
5627
|
+
status,
|
|
5628
|
+
tag: "getAll"
|
|
5629
|
+
};
|
|
5630
|
+
if (search) {
|
|
5631
|
+
query.$text = { $search: search };
|
|
5523
5632
|
}
|
|
5524
|
-
const
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5633
|
+
const cacheKey = makeCacheKey11(namespace_collection, cacheKeyOptions);
|
|
5634
|
+
try {
|
|
5635
|
+
const cachedData = await getCache(cacheKey);
|
|
5636
|
+
if (cachedData) {
|
|
5637
|
+
return cachedData;
|
|
5638
|
+
}
|
|
5639
|
+
const items = await collection.aggregate([
|
|
5640
|
+
{ $match: query },
|
|
5641
|
+
{ $skip: page * limit },
|
|
5642
|
+
{ $limit: limit }
|
|
5643
|
+
]).toArray();
|
|
5644
|
+
const length = await collection.countDocuments(query);
|
|
5645
|
+
const data = paginate9(
|
|
5646
|
+
items,
|
|
5647
|
+
page,
|
|
5648
|
+
limit,
|
|
5649
|
+
length
|
|
5650
|
+
);
|
|
5651
|
+
setCache(cacheKey, data).then(() => {
|
|
5652
|
+
logger16.log({
|
|
5653
|
+
level: "info",
|
|
5654
|
+
message: `Cache set for getAll subscription: ${cacheKey}`
|
|
5655
|
+
});
|
|
5656
|
+
}).catch((err) => {
|
|
5657
|
+
logger16.log({
|
|
5658
|
+
level: "error",
|
|
5659
|
+
message: `Failed to set cache for getAll subscription: ${err.message}`
|
|
5660
|
+
});
|
|
5661
|
+
});
|
|
5662
|
+
return data;
|
|
5663
|
+
} catch (error) {
|
|
5664
|
+
throw new InternalServerError15("Failed to get subscriptions.");
|
|
5528
5665
|
}
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
limit: Joi21.number().min(1).optional().allow("", null),
|
|
5533
|
-
search: Joi21.string().optional().allow("", null)
|
|
5534
|
-
});
|
|
5535
|
-
const { error } = validation.validate({ user, page, limit, search });
|
|
5666
|
+
}
|
|
5667
|
+
async function getByOrg(org) {
|
|
5668
|
+
const { error } = Joi22.string().hex().length(24).required().validate(org);
|
|
5536
5669
|
if (error) {
|
|
5537
|
-
|
|
5538
|
-
return;
|
|
5670
|
+
throw new Error(`Invalid org ID: ${error.message}`);
|
|
5539
5671
|
}
|
|
5540
5672
|
try {
|
|
5541
|
-
|
|
5542
|
-
res.json(orgs);
|
|
5543
|
-
return;
|
|
5673
|
+
org = new ObjectId18(org);
|
|
5544
5674
|
} catch (error2) {
|
|
5545
|
-
|
|
5675
|
+
throw new BadRequestError30("Invalid org ID.");
|
|
5546
5676
|
}
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5677
|
+
try {
|
|
5678
|
+
const cacheKey = makeCacheKey11(namespace_collection, {
|
|
5679
|
+
org: String(org),
|
|
5680
|
+
tag: "getByOrg"
|
|
5681
|
+
});
|
|
5682
|
+
const cachedData = await getCache(cacheKey);
|
|
5683
|
+
if (cachedData) {
|
|
5684
|
+
return cachedData;
|
|
5685
|
+
}
|
|
5686
|
+
const data = await collection.findOne({
|
|
5687
|
+
org,
|
|
5688
|
+
status: { $ne: "deleted" }
|
|
5689
|
+
});
|
|
5690
|
+
setCache(cacheKey, data).then(() => {
|
|
5691
|
+
logger16.log({
|
|
5692
|
+
level: "info",
|
|
5693
|
+
message: `Cache set for getByOrg subscription: ${cacheKey}`
|
|
5694
|
+
});
|
|
5695
|
+
}).catch((err) => {
|
|
5696
|
+
logger16.log({
|
|
5697
|
+
level: "error",
|
|
5698
|
+
message: `Failed to set cache for getByOrg subscription: ${err.message}`
|
|
5699
|
+
});
|
|
5700
|
+
});
|
|
5701
|
+
return data;
|
|
5702
|
+
} catch (error2) {
|
|
5703
|
+
throw new InternalServerError15("Failed to get subscription.");
|
|
5704
|
+
}
|
|
5705
|
+
}
|
|
5706
|
+
async function getById(_id) {
|
|
5707
|
+
const { error } = Joi22.string().hex().length(24).required().validate(_id);
|
|
5708
|
+
if (error) {
|
|
5709
|
+
throw new Error(`Invalid subscription ID: ${error.message}`);
|
|
5710
|
+
}
|
|
5711
|
+
try {
|
|
5712
|
+
_id = new ObjectId18(_id);
|
|
5713
|
+
} catch (error2) {
|
|
5714
|
+
throw new BadRequestError30("Invalid subscription ID.");
|
|
5715
|
+
}
|
|
5716
|
+
try {
|
|
5717
|
+
const cacheKey = makeCacheKey11(namespace_collection, {
|
|
5718
|
+
_id: String(_id),
|
|
5719
|
+
tag: "getById"
|
|
5720
|
+
});
|
|
5721
|
+
const cachedData = await getCache(cacheKey);
|
|
5722
|
+
if (cachedData) {
|
|
5723
|
+
return cachedData;
|
|
5724
|
+
}
|
|
5725
|
+
const data = await collection.findOne({
|
|
5726
|
+
_id,
|
|
5727
|
+
status: { $ne: "deleted" }
|
|
5728
|
+
});
|
|
5729
|
+
setCache(cacheKey, data).then(() => {
|
|
5730
|
+
logger16.log({
|
|
5731
|
+
level: "info",
|
|
5732
|
+
message: `Cache set for getById subscription: ${cacheKey}`
|
|
5733
|
+
});
|
|
5734
|
+
}).catch((err) => {
|
|
5735
|
+
logger16.log({
|
|
5736
|
+
level: "error",
|
|
5737
|
+
message: `Failed to set cache for getById subscription: ${err.message}`
|
|
5738
|
+
});
|
|
5739
|
+
});
|
|
5740
|
+
return data;
|
|
5741
|
+
} catch (error2) {
|
|
5742
|
+
throw new InternalServerError15("Failed to get subscription.");
|
|
5743
|
+
}
|
|
5744
|
+
}
|
|
5745
|
+
async function deleteById(_id) {
|
|
5746
|
+
const { error } = Joi22.string().hex().length(24).required().validate(_id);
|
|
5747
|
+
if (error) {
|
|
5748
|
+
throw new Error(`Invalid subscription ID: ${error.message}`);
|
|
5749
|
+
}
|
|
5750
|
+
try {
|
|
5751
|
+
_id = new ObjectId18(_id);
|
|
5752
|
+
} catch (error2) {
|
|
5753
|
+
throw new BadRequestError30("Invalid subscription ID.");
|
|
5754
|
+
}
|
|
5755
|
+
try {
|
|
5756
|
+
const result = await collection.updateOne(
|
|
5757
|
+
{ _id },
|
|
5758
|
+
{ $set: { status: "deleted" } }
|
|
5759
|
+
);
|
|
5760
|
+
if (result.modifiedCount === 0) {
|
|
5761
|
+
throw new InternalServerError15("Failed to delete subscription.");
|
|
5762
|
+
}
|
|
5763
|
+
delCachedData();
|
|
5764
|
+
return "Successfully deleted subscription.";
|
|
5765
|
+
} catch (error2) {
|
|
5766
|
+
if (error2 instanceof AppError11) {
|
|
5767
|
+
throw error2;
|
|
5768
|
+
}
|
|
5769
|
+
throw new InternalServerError15("Failed to delete subscription.");
|
|
5770
|
+
}
|
|
5771
|
+
}
|
|
5772
|
+
async function updateById(_id, options, session) {
|
|
5773
|
+
const { error: errorId } = Joi22.string().hex().length(24).required().validate(_id);
|
|
5774
|
+
if (errorId) {
|
|
5775
|
+
throw new Error(`Invalid subscription ID: ${errorId.message}`);
|
|
5776
|
+
}
|
|
5777
|
+
const { error } = schemaSubscriptionUpdate.validate(options);
|
|
5778
|
+
if (error) {
|
|
5779
|
+
throw new BadRequestError30(
|
|
5780
|
+
`Invalid subscription update data: ${error.message}`
|
|
5781
|
+
);
|
|
5782
|
+
}
|
|
5783
|
+
try {
|
|
5784
|
+
_id = new ObjectId18(_id);
|
|
5785
|
+
} catch (error2) {
|
|
5786
|
+
throw new BadRequestError30("Invalid subscription ID.");
|
|
5787
|
+
}
|
|
5788
|
+
try {
|
|
5789
|
+
const result = await collection.updateOne(
|
|
5790
|
+
{ _id },
|
|
5791
|
+
{ $set: { ...options, updatedAt: /* @__PURE__ */ new Date() } },
|
|
5792
|
+
{ session }
|
|
5793
|
+
);
|
|
5794
|
+
if (result.modifiedCount === 0) {
|
|
5795
|
+
throw new InternalServerError15("Failed to update subscription.");
|
|
5796
|
+
}
|
|
5797
|
+
delCachedData();
|
|
5798
|
+
return "Successfully updated subscription.";
|
|
5799
|
+
} catch (error2) {
|
|
5800
|
+
if (error2 instanceof AppError11) {
|
|
5801
|
+
throw error2;
|
|
5802
|
+
}
|
|
5803
|
+
throw new InternalServerError15("Failed to update subscription.");
|
|
5804
|
+
}
|
|
5805
|
+
}
|
|
5806
|
+
return {
|
|
5807
|
+
add,
|
|
5808
|
+
getAll,
|
|
5809
|
+
getByOrg,
|
|
5810
|
+
getById,
|
|
5811
|
+
deleteById,
|
|
5812
|
+
updateById
|
|
5813
|
+
};
|
|
5814
|
+
}
|
|
5815
|
+
|
|
5816
|
+
// src/resources/subscription/subscription.controller.ts
|
|
5817
|
+
import Joi24 from "joi";
|
|
5818
|
+
import { BadRequestError as BadRequestError33 } from "@goweekdays/utils";
|
|
5819
|
+
|
|
5820
|
+
// src/resources/subscription/subscription.service.ts
|
|
5821
|
+
import { BadRequestError as BadRequestError32, useAtlas as useAtlas15 } from "@goweekdays/utils";
|
|
5822
|
+
|
|
5823
|
+
// src/resources/subscription/subscription.transaction.repository.ts
|
|
5824
|
+
import {
|
|
5825
|
+
AppError as AppError12,
|
|
5826
|
+
InternalServerError as InternalServerError16,
|
|
5827
|
+
logger as logger17,
|
|
5828
|
+
makeCacheKey as makeCacheKey12,
|
|
5829
|
+
paginate as paginate10,
|
|
5830
|
+
useAtlas as useAtlas14,
|
|
5831
|
+
useCache as useCache13
|
|
5832
|
+
} from "@goweekdays/utils";
|
|
5833
|
+
|
|
5834
|
+
// src/resources/subscription/subscription.transaction.model.ts
|
|
5835
|
+
import { BadRequestError as BadRequestError31 } from "@goweekdays/utils";
|
|
5836
|
+
import Joi23 from "joi";
|
|
5837
|
+
import { ObjectId as ObjectId19 } from "mongodb";
|
|
5838
|
+
var schemaSubscriptionTransaction = Joi23.object({
|
|
5839
|
+
subscription: Joi23.string().hex().length(24).required(),
|
|
5840
|
+
amount: Joi23.number().positive().required(),
|
|
5841
|
+
currency: Joi23.string().length(3).required(),
|
|
5842
|
+
type: Joi23.string().valid("initiate", "add-seat", "remove-seat", "renewal").required(),
|
|
5843
|
+
description: Joi23.string().max(255).optional().allow("", null),
|
|
5844
|
+
createdBy: Joi23.string().hex().length(24).required(),
|
|
5845
|
+
createdByName: Joi23.string().optional().allow("", null)
|
|
5846
|
+
});
|
|
5847
|
+
function modelSubscriptionTransaction(data) {
|
|
5848
|
+
const { error } = schemaSubscriptionTransaction.validate(data);
|
|
5849
|
+
if (error) {
|
|
5850
|
+
throw new BadRequestError31(
|
|
5851
|
+
`Invalid subscription transaction data: ${error.message}`
|
|
5852
|
+
);
|
|
5853
|
+
}
|
|
5854
|
+
if (data._id && typeof data._id === "string") {
|
|
5855
|
+
try {
|
|
5856
|
+
data._id = new ObjectId19(data._id);
|
|
5857
|
+
} catch (error2) {
|
|
5858
|
+
throw new BadRequestError31("Invalid subscription transaction ID.");
|
|
5859
|
+
}
|
|
5860
|
+
}
|
|
5861
|
+
if (data.subscription && typeof data.subscription === "string") {
|
|
5862
|
+
try {
|
|
5863
|
+
data.subscription = new ObjectId19(data.subscription);
|
|
5864
|
+
} catch (error2) {
|
|
5865
|
+
throw new BadRequestError31("Invalid subscription ID.");
|
|
5866
|
+
}
|
|
5867
|
+
}
|
|
5868
|
+
if (data.createdBy && typeof data.createdBy === "string") {
|
|
5869
|
+
try {
|
|
5870
|
+
data.createdBy = new ObjectId19(data.createdBy);
|
|
5871
|
+
} catch (error2) {
|
|
5872
|
+
throw new BadRequestError31("Invalid createdBy ID.");
|
|
5873
|
+
}
|
|
5874
|
+
}
|
|
5875
|
+
return {
|
|
5876
|
+
_id: data._id,
|
|
5877
|
+
subscription: data.subscription,
|
|
5878
|
+
amount: data.amount,
|
|
5879
|
+
currency: data.currency,
|
|
5880
|
+
type: data.type,
|
|
5881
|
+
description: data.description ?? "",
|
|
5882
|
+
createdBy: data.createdBy,
|
|
5883
|
+
createdByName: data.createdByName,
|
|
5884
|
+
createdAt: data.createdAt ?? /* @__PURE__ */ new Date(),
|
|
5885
|
+
updatedAt: data.updatedAt ?? ""
|
|
5886
|
+
};
|
|
5887
|
+
}
|
|
5888
|
+
|
|
5889
|
+
// src/resources/subscription/subscription.transaction.repository.ts
|
|
5890
|
+
import { ObjectId as ObjectId20 } from "mongodb";
|
|
5891
|
+
function useSubscriptionTransactionRepo() {
|
|
5892
|
+
const db = useAtlas14.getDb();
|
|
5893
|
+
if (!db) {
|
|
5894
|
+
throw new InternalServerError16("Unable to connect to server.");
|
|
5895
|
+
}
|
|
5896
|
+
const namespace_collection = "subscription.transactions";
|
|
5897
|
+
const collection = db.collection(namespace_collection);
|
|
5898
|
+
const { getCache, setCache, delNamespace } = useCache13(namespace_collection);
|
|
5899
|
+
function delCachedData() {
|
|
5900
|
+
delNamespace().then(() => {
|
|
5901
|
+
logger17.log({
|
|
5902
|
+
level: "info",
|
|
5903
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
5904
|
+
});
|
|
5905
|
+
}).catch((err) => {
|
|
5906
|
+
logger17.log({
|
|
5907
|
+
level: "error",
|
|
5908
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
5909
|
+
});
|
|
5910
|
+
});
|
|
5911
|
+
}
|
|
5912
|
+
async function createIndexes() {
|
|
5913
|
+
try {
|
|
5914
|
+
await collection.createIndexes([
|
|
5915
|
+
{
|
|
5916
|
+
key: {
|
|
5917
|
+
subscription: 1
|
|
5918
|
+
},
|
|
5919
|
+
name: "subscription_index"
|
|
5920
|
+
},
|
|
5921
|
+
{
|
|
5922
|
+
key: { subscription: 1, type: 1 },
|
|
5923
|
+
name: "subscription_type_index"
|
|
5924
|
+
},
|
|
5925
|
+
{
|
|
5926
|
+
key: { createdAt: -1 },
|
|
5927
|
+
name: "createdAt_index"
|
|
5928
|
+
}
|
|
5929
|
+
]);
|
|
5930
|
+
} catch (error) {
|
|
5931
|
+
}
|
|
5932
|
+
}
|
|
5933
|
+
createIndexes().catch((error) => {
|
|
5934
|
+
logger17.log({
|
|
5935
|
+
level: "error",
|
|
5936
|
+
message: `Failed to create indexes for subscription_transactions collection: ${error.message}`
|
|
5937
|
+
});
|
|
5938
|
+
});
|
|
5939
|
+
async function add(value, session) {
|
|
5940
|
+
try {
|
|
5941
|
+
value = modelSubscriptionTransaction(value);
|
|
5942
|
+
await collection.insertOne(value, { session });
|
|
5943
|
+
delCachedData();
|
|
5944
|
+
return "Successfully added subscription transaction.";
|
|
5945
|
+
} catch (error) {
|
|
5946
|
+
logger17.log({
|
|
5947
|
+
level: "error",
|
|
5948
|
+
message: `${error}`
|
|
5949
|
+
});
|
|
5950
|
+
if (error instanceof AppError12) {
|
|
5951
|
+
throw error;
|
|
5952
|
+
}
|
|
5953
|
+
throw new InternalServerError16("Failed to add subscription transaction.");
|
|
5954
|
+
}
|
|
5955
|
+
}
|
|
5956
|
+
async function getAll({ page = 1, limit = 10, search = "", id = "" } = {}) {
|
|
5957
|
+
page = page > 0 ? page - 1 : page;
|
|
5958
|
+
const query = {};
|
|
5959
|
+
const cacheKeyOptions = {
|
|
5960
|
+
page,
|
|
5961
|
+
limit,
|
|
5962
|
+
search,
|
|
5963
|
+
tag: "getAll"
|
|
5964
|
+
};
|
|
5965
|
+
try {
|
|
5966
|
+
query.subscription = new ObjectId20(id);
|
|
5967
|
+
cacheKeyOptions.subscription = id;
|
|
5968
|
+
} catch (error) {
|
|
5969
|
+
throw new InternalServerError16("Invalid organization ID.");
|
|
5970
|
+
}
|
|
5971
|
+
if (search) {
|
|
5972
|
+
query.$text = { $search: search };
|
|
5973
|
+
}
|
|
5974
|
+
const cacheKey = makeCacheKey12(namespace_collection, cacheKeyOptions);
|
|
5975
|
+
try {
|
|
5976
|
+
const cachedData = await getCache(
|
|
5977
|
+
cacheKey
|
|
5978
|
+
);
|
|
5979
|
+
if (cachedData) {
|
|
5980
|
+
logger17.log({
|
|
5981
|
+
level: "info",
|
|
5982
|
+
message: `Cache hit for getAll subscription transaction: ${cacheKey}`
|
|
5983
|
+
});
|
|
5984
|
+
return cachedData;
|
|
5985
|
+
}
|
|
5986
|
+
const items = await collection.aggregate([
|
|
5987
|
+
{ $match: query },
|
|
5988
|
+
{ $skip: page * limit },
|
|
5989
|
+
{ $limit: limit }
|
|
5990
|
+
]).toArray();
|
|
5991
|
+
const length = await collection.countDocuments(query);
|
|
5992
|
+
const data = paginate10(
|
|
5993
|
+
items,
|
|
5994
|
+
page,
|
|
5995
|
+
limit,
|
|
5996
|
+
length
|
|
5997
|
+
);
|
|
5998
|
+
setCache(cacheKey, data).then(() => {
|
|
5999
|
+
logger17.log({
|
|
6000
|
+
level: "info",
|
|
6001
|
+
message: `Cache set for getAll subscription transaction: ${cacheKey}`
|
|
6002
|
+
});
|
|
6003
|
+
}).catch((err) => {
|
|
6004
|
+
logger17.log({
|
|
6005
|
+
level: "error",
|
|
6006
|
+
message: `Failed to set cache for getAll subscription transaction: ${err.message}`
|
|
6007
|
+
});
|
|
6008
|
+
});
|
|
6009
|
+
return data;
|
|
6010
|
+
} catch (error) {
|
|
6011
|
+
throw new InternalServerError16("Failed to get subscription transactions.");
|
|
6012
|
+
}
|
|
6013
|
+
}
|
|
6014
|
+
return {
|
|
6015
|
+
add,
|
|
6016
|
+
getAll
|
|
6017
|
+
};
|
|
6018
|
+
}
|
|
6019
|
+
|
|
6020
|
+
// src/resources/subscription/subscription.service.ts
|
|
6021
|
+
function useSubscriptionService() {
|
|
6022
|
+
const { getById, updateById } = useSubscriptionRepo();
|
|
6023
|
+
const { add: addTransaction } = useSubscriptionTransactionRepo();
|
|
6024
|
+
const { getUserById } = useUserRepo();
|
|
6025
|
+
async function updateSeats({
|
|
6026
|
+
id = "",
|
|
6027
|
+
user = "",
|
|
6028
|
+
amount = 0,
|
|
6029
|
+
seats = 0
|
|
6030
|
+
} = {}) {
|
|
6031
|
+
const { error } = schemaSubscriptionSeats.validate({
|
|
6032
|
+
id,
|
|
6033
|
+
seats,
|
|
6034
|
+
amount,
|
|
6035
|
+
user
|
|
6036
|
+
});
|
|
6037
|
+
if (error) {
|
|
6038
|
+
throw new BadRequestError32(error.message);
|
|
6039
|
+
}
|
|
6040
|
+
const subscription = await getById(id);
|
|
6041
|
+
if (!subscription) {
|
|
6042
|
+
throw new Error("Subscription not found");
|
|
6043
|
+
}
|
|
6044
|
+
if (subscription.seats === seats) {
|
|
6045
|
+
throw new Error("Failed to update subscription, no changes detected.");
|
|
6046
|
+
}
|
|
6047
|
+
const userData = await getUserById(user);
|
|
6048
|
+
if (!userData) {
|
|
6049
|
+
throw new Error("User not found.");
|
|
6050
|
+
}
|
|
6051
|
+
const session = useAtlas15.getClient()?.startSession();
|
|
6052
|
+
if (!session) {
|
|
6053
|
+
throw new Error("Unable to start database session.");
|
|
6054
|
+
}
|
|
6055
|
+
let subscriptionAmount = subscription.amount;
|
|
6056
|
+
const seatIncreased = seats > subscription.paidSeats;
|
|
6057
|
+
let paidSeats = subscription.paidSeats;
|
|
6058
|
+
if (seatIncreased) {
|
|
6059
|
+
subscriptionAmount += amount ?? 0;
|
|
6060
|
+
paidSeats = seats;
|
|
6061
|
+
}
|
|
6062
|
+
try {
|
|
6063
|
+
session.startTransaction();
|
|
6064
|
+
await updateById(
|
|
6065
|
+
id,
|
|
6066
|
+
{ seats, amount: subscriptionAmount, paidSeats },
|
|
6067
|
+
session
|
|
6068
|
+
);
|
|
6069
|
+
if (seatIncreased) {
|
|
6070
|
+
await addTransaction(
|
|
6071
|
+
{
|
|
6072
|
+
type: "add-seat",
|
|
6073
|
+
description: `Added ${seats - subscription.paidSeats} seats.`,
|
|
6074
|
+
amount: amount ?? 0,
|
|
6075
|
+
currency: subscription.currency,
|
|
6076
|
+
subscription: id,
|
|
6077
|
+
createdBy: user,
|
|
6078
|
+
createdByName: `${userData.firstName} ${userData.lastName}`
|
|
6079
|
+
},
|
|
6080
|
+
session
|
|
6081
|
+
);
|
|
6082
|
+
}
|
|
6083
|
+
await session.commitTransaction();
|
|
6084
|
+
return "Successfully updated subscription seats.";
|
|
6085
|
+
} catch (error2) {
|
|
6086
|
+
await session.abortTransaction();
|
|
6087
|
+
throw error2;
|
|
6088
|
+
} finally {
|
|
6089
|
+
session.endSession();
|
|
6090
|
+
}
|
|
6091
|
+
}
|
|
6092
|
+
return {
|
|
6093
|
+
updateSeats
|
|
6094
|
+
};
|
|
6095
|
+
}
|
|
6096
|
+
|
|
6097
|
+
// src/resources/subscription/subscription.controller.ts
|
|
6098
|
+
function useSubscriptionController() {
|
|
6099
|
+
const {
|
|
6100
|
+
getAll: _getAll,
|
|
6101
|
+
getById: _getById,
|
|
6102
|
+
getByOrg: _getByOrg
|
|
6103
|
+
} = useSubscriptionRepo();
|
|
6104
|
+
const { updateSeats: _updateSeats } = useSubscriptionService();
|
|
6105
|
+
async function getAll(req, res, next) {
|
|
6106
|
+
const validation = Joi24.object({
|
|
6107
|
+
page: Joi24.number().min(1).max(100).optional().allow(null, "").default(1),
|
|
6108
|
+
limit: Joi24.number().min(1).max(100).optional().allow(null, "").default(10),
|
|
6109
|
+
status: Joi24.string().valid("active", "suspended").optional().default("active")
|
|
6110
|
+
});
|
|
6111
|
+
const query = req.query;
|
|
6112
|
+
const { error, value } = validation.validate(query);
|
|
6113
|
+
if (error) {
|
|
6114
|
+
next(new BadRequestError33(error.message));
|
|
6115
|
+
return;
|
|
6116
|
+
}
|
|
6117
|
+
try {
|
|
6118
|
+
const data = await _getAll(value);
|
|
6119
|
+
res.json(data);
|
|
6120
|
+
return;
|
|
6121
|
+
} catch (error2) {
|
|
6122
|
+
next(error2);
|
|
6123
|
+
}
|
|
6124
|
+
}
|
|
6125
|
+
async function getById(req, res, next) {
|
|
6126
|
+
const id = req.params.id ?? "";
|
|
6127
|
+
const validation = Joi24.object({
|
|
6128
|
+
id: Joi24.string().hex().length(24).required()
|
|
6129
|
+
});
|
|
6130
|
+
const { error, value } = validation.validate({ id });
|
|
6131
|
+
if (error) {
|
|
6132
|
+
next(new BadRequestError33(error.message));
|
|
6133
|
+
return;
|
|
6134
|
+
}
|
|
6135
|
+
try {
|
|
6136
|
+
const data = await _getById(value.id);
|
|
6137
|
+
res.json(data);
|
|
6138
|
+
return;
|
|
6139
|
+
} catch (error2) {
|
|
6140
|
+
next(error2);
|
|
6141
|
+
}
|
|
6142
|
+
}
|
|
6143
|
+
async function getByOrg(req, res, next) {
|
|
6144
|
+
const org = req.params.org ?? "";
|
|
6145
|
+
const validation = Joi24.object({
|
|
6146
|
+
org: Joi24.string().hex().length(24).required()
|
|
6147
|
+
});
|
|
6148
|
+
const { error, value } = validation.validate({ org });
|
|
6149
|
+
if (error) {
|
|
6150
|
+
next(new BadRequestError33(error.message));
|
|
6151
|
+
return;
|
|
6152
|
+
}
|
|
6153
|
+
try {
|
|
6154
|
+
const data = await _getByOrg(value.org);
|
|
6155
|
+
res.json(data);
|
|
6156
|
+
return;
|
|
6157
|
+
} catch (error2) {
|
|
6158
|
+
next(error2);
|
|
6159
|
+
}
|
|
6160
|
+
}
|
|
6161
|
+
async function updateSeats(req, res, next) {
|
|
6162
|
+
const id = req.params.id ?? "";
|
|
6163
|
+
const payload = req.body;
|
|
6164
|
+
const { error } = schemaSubscriptionSeats.validate({ ...payload, id });
|
|
6165
|
+
if (error) {
|
|
6166
|
+
next(new BadRequestError33(error.message));
|
|
6167
|
+
return;
|
|
6168
|
+
}
|
|
6169
|
+
const user = payload.user ?? "";
|
|
6170
|
+
const seats = payload.seats ?? 0;
|
|
6171
|
+
const amount = payload.amount ?? 0;
|
|
6172
|
+
try {
|
|
6173
|
+
const message = await _updateSeats({ id, seats, amount, user });
|
|
6174
|
+
res.json({ message });
|
|
6175
|
+
return;
|
|
6176
|
+
} catch (error2) {
|
|
6177
|
+
next(error2);
|
|
6178
|
+
}
|
|
6179
|
+
}
|
|
6180
|
+
return {
|
|
6181
|
+
getAll,
|
|
6182
|
+
getById,
|
|
6183
|
+
getByOrg,
|
|
6184
|
+
updateSeats
|
|
6185
|
+
};
|
|
6186
|
+
}
|
|
6187
|
+
|
|
6188
|
+
// src/resources/subscription/subscription.transaction.controller.ts
|
|
6189
|
+
import Joi25 from "joi";
|
|
6190
|
+
import { BadRequestError as BadRequestError34 } from "@goweekdays/utils";
|
|
6191
|
+
function useSubscriptionTransactionController() {
|
|
6192
|
+
const { getAll: _getAll } = useSubscriptionTransactionRepo();
|
|
6193
|
+
async function getAll(req, res, next) {
|
|
6194
|
+
const validation = Joi25.object({
|
|
6195
|
+
id: Joi25.string().hex().length(24).required(),
|
|
6196
|
+
page: Joi25.number().min(1).max(100).optional().allow(null, "").default(1),
|
|
6197
|
+
limit: Joi25.number().min(1).max(100).optional().allow(null, "").default(10)
|
|
6198
|
+
});
|
|
6199
|
+
const query = req.query;
|
|
6200
|
+
const id = req.params.id ?? "";
|
|
6201
|
+
const { error, value } = validation.validate({ ...query, id });
|
|
6202
|
+
if (error) {
|
|
6203
|
+
next(new BadRequestError34(error.message));
|
|
6204
|
+
return;
|
|
6205
|
+
}
|
|
6206
|
+
try {
|
|
6207
|
+
const data = await _getAll(value);
|
|
6208
|
+
res.json(data);
|
|
6209
|
+
return;
|
|
6210
|
+
} catch (error2) {
|
|
6211
|
+
next(error2);
|
|
6212
|
+
}
|
|
6213
|
+
}
|
|
6214
|
+
return {
|
|
6215
|
+
getAll
|
|
6216
|
+
};
|
|
6217
|
+
}
|
|
6218
|
+
|
|
6219
|
+
// src/resources/plan/plan.model.ts
|
|
6220
|
+
import Joi26 from "joi";
|
|
6221
|
+
var currencies = ["USD", "PHP"];
|
|
6222
|
+
var schemaPlan = Joi26.object({
|
|
6223
|
+
name: Joi26.string().min(3).max(100).required(),
|
|
6224
|
+
description: Joi26.string().max(255).optional().allow("", null),
|
|
6225
|
+
features: Joi26.array().items(Joi26.string().max(100)).optional(),
|
|
6226
|
+
price: Joi26.number().positive().required(),
|
|
6227
|
+
currency: Joi26.string().length(3).allow(...currencies).required(),
|
|
6228
|
+
default: Joi26.boolean().optional().allow(null, ""),
|
|
6229
|
+
billingCycle: Joi26.string().valid("monthly", "yearly").required()
|
|
6230
|
+
});
|
|
6231
|
+
function modelPlan(data) {
|
|
6232
|
+
const { error } = schemaPlan.validate(data);
|
|
6233
|
+
if (error) {
|
|
6234
|
+
throw new Error(`Invalid plan data: ${error.message}`);
|
|
6235
|
+
}
|
|
6236
|
+
return {
|
|
6237
|
+
_id: data._id,
|
|
6238
|
+
name: data.name,
|
|
6239
|
+
description: data.description,
|
|
6240
|
+
features: data.features,
|
|
6241
|
+
price: data.price,
|
|
6242
|
+
currency: data.currency,
|
|
6243
|
+
billingCycle: data.billingCycle,
|
|
6244
|
+
status: data.status ?? "active",
|
|
6245
|
+
default: data.default ?? false,
|
|
6246
|
+
createdAt: data.createdAt ?? /* @__PURE__ */ new Date(),
|
|
6247
|
+
updatedAt: data.updatedAt ?? ""
|
|
6248
|
+
};
|
|
6249
|
+
}
|
|
6250
|
+
|
|
6251
|
+
// src/resources/plan/plan.repository.ts
|
|
6252
|
+
import {
|
|
6253
|
+
AppError as AppError13,
|
|
6254
|
+
BadRequestError as BadRequestError35,
|
|
6255
|
+
InternalServerError as InternalServerError17,
|
|
6256
|
+
logger as logger18,
|
|
6257
|
+
makeCacheKey as makeCacheKey13,
|
|
6258
|
+
paginate as paginate11,
|
|
6259
|
+
useAtlas as useAtlas16,
|
|
6260
|
+
useCache as useCache14
|
|
6261
|
+
} from "@goweekdays/utils";
|
|
6262
|
+
import Joi27 from "joi";
|
|
6263
|
+
import { ObjectId as ObjectId21 } from "mongodb";
|
|
6264
|
+
function usePlanRepo() {
|
|
6265
|
+
const db = useAtlas16.getDb();
|
|
6266
|
+
if (!db) {
|
|
6267
|
+
throw new InternalServerError17("Unable to connect to server.");
|
|
6268
|
+
}
|
|
6269
|
+
const namespace_collection = "plans";
|
|
6270
|
+
const collection = db.collection(namespace_collection);
|
|
6271
|
+
const { getCache, setCache, delNamespace } = useCache14(namespace_collection);
|
|
6272
|
+
function delCachedData() {
|
|
6273
|
+
delNamespace().then(() => {
|
|
6274
|
+
logger18.log({
|
|
6275
|
+
level: "info",
|
|
6276
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
6277
|
+
});
|
|
6278
|
+
}).catch((err) => {
|
|
6279
|
+
logger18.log({
|
|
6280
|
+
level: "error",
|
|
6281
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
6282
|
+
});
|
|
6283
|
+
});
|
|
6284
|
+
}
|
|
6285
|
+
async function createIndexes() {
|
|
6286
|
+
try {
|
|
6287
|
+
await collection.createIndexes([
|
|
6288
|
+
{
|
|
6289
|
+
key: {
|
|
6290
|
+
status: 1
|
|
6291
|
+
}
|
|
6292
|
+
},
|
|
6293
|
+
{
|
|
6294
|
+
key: {
|
|
6295
|
+
name: 1
|
|
6296
|
+
}
|
|
6297
|
+
},
|
|
6298
|
+
{
|
|
6299
|
+
key: { billingCycle: 1 }
|
|
6300
|
+
},
|
|
6301
|
+
{
|
|
6302
|
+
key: { name: "text", description: "text" },
|
|
6303
|
+
name: "name_description_text_index"
|
|
6304
|
+
},
|
|
6305
|
+
{
|
|
6306
|
+
key: { name: 1, status: 1 },
|
|
6307
|
+
partialFilterExpression: { status: "active" },
|
|
6308
|
+
unique: true,
|
|
6309
|
+
name: "unique_name_index"
|
|
6310
|
+
},
|
|
6311
|
+
{
|
|
6312
|
+
key: { default: 1 },
|
|
6313
|
+
unique: true,
|
|
6314
|
+
partialFilterExpression: { status: "active" }
|
|
6315
|
+
}
|
|
6316
|
+
]);
|
|
6317
|
+
} catch (error) {
|
|
6318
|
+
}
|
|
6319
|
+
}
|
|
6320
|
+
createIndexes().catch((error) => {
|
|
6321
|
+
logger18.log({
|
|
6322
|
+
level: "error",
|
|
6323
|
+
message: `Failed to create indexes for plans collection: ${error.message}`
|
|
6324
|
+
});
|
|
6325
|
+
});
|
|
6326
|
+
async function add(value) {
|
|
6327
|
+
try {
|
|
6328
|
+
value = modelPlan(value);
|
|
6329
|
+
await collection.insertOne(value);
|
|
6330
|
+
delCachedData();
|
|
6331
|
+
return "Successfully added plan.";
|
|
6332
|
+
} catch (error) {
|
|
6333
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
6334
|
+
if (isDuplicated) {
|
|
6335
|
+
throw new BadRequestError35("Plan name already exist.");
|
|
6336
|
+
}
|
|
6337
|
+
throw new InternalServerError17("Failed to add plan.");
|
|
6338
|
+
}
|
|
6339
|
+
}
|
|
6340
|
+
async function getAll({
|
|
6341
|
+
page = 1,
|
|
6342
|
+
limit = 10,
|
|
6343
|
+
search = "",
|
|
6344
|
+
status = "active"
|
|
6345
|
+
} = {}) {
|
|
6346
|
+
page = page < 1 ? page - 1 : page;
|
|
6347
|
+
const query = { status };
|
|
6348
|
+
const cacheKeyOptions = {
|
|
6349
|
+
page,
|
|
6350
|
+
limit,
|
|
6351
|
+
search,
|
|
6352
|
+
status,
|
|
6353
|
+
tag: "getAll"
|
|
6354
|
+
};
|
|
6355
|
+
if (search) {
|
|
6356
|
+
query.$text = { $search: search };
|
|
6357
|
+
}
|
|
6358
|
+
const cacheKey = makeCacheKey13(namespace_collection, cacheKeyOptions);
|
|
6359
|
+
try {
|
|
6360
|
+
const cachedData = await getCache(cacheKey);
|
|
6361
|
+
if (cachedData) {
|
|
6362
|
+
return cachedData;
|
|
6363
|
+
}
|
|
6364
|
+
const items = await collection.aggregate([
|
|
6365
|
+
{ $match: query },
|
|
6366
|
+
{ $skip: page * limit },
|
|
6367
|
+
{ $limit: limit }
|
|
6368
|
+
]).toArray();
|
|
6369
|
+
const length = await collection.countDocuments(query);
|
|
6370
|
+
const data = paginate11(items, page, limit, length);
|
|
6371
|
+
setCache(cacheKey, data).then(() => {
|
|
6372
|
+
logger18.log({
|
|
6373
|
+
level: "info",
|
|
6374
|
+
message: `Cache set for getAll plan: ${cacheKey}`
|
|
6375
|
+
});
|
|
6376
|
+
}).catch((err) => {
|
|
6377
|
+
logger18.log({
|
|
6378
|
+
level: "error",
|
|
6379
|
+
message: `Failed to set cache for getAll plan: ${err.message}`
|
|
6380
|
+
});
|
|
6381
|
+
});
|
|
6382
|
+
return data;
|
|
6383
|
+
} catch (error) {
|
|
6384
|
+
throw new InternalServerError17("Failed to get plans.");
|
|
6385
|
+
}
|
|
6386
|
+
}
|
|
6387
|
+
async function getById(_id) {
|
|
6388
|
+
const { error } = Joi27.string().hex().length(24).required().validate(_id);
|
|
6389
|
+
if (error) {
|
|
6390
|
+
throw new Error(`Invalid plan ID: ${error.message}`);
|
|
6391
|
+
}
|
|
6392
|
+
try {
|
|
6393
|
+
_id = new ObjectId21(_id);
|
|
6394
|
+
} catch (error2) {
|
|
6395
|
+
throw new BadRequestError35("Invalid plan ID.");
|
|
6396
|
+
}
|
|
6397
|
+
try {
|
|
6398
|
+
const cacheKey = makeCacheKey13(namespace_collection, {
|
|
6399
|
+
_id: String(_id),
|
|
6400
|
+
tag: "getById"
|
|
6401
|
+
});
|
|
6402
|
+
const cachedData = await getCache(cacheKey);
|
|
6403
|
+
if (cachedData) {
|
|
6404
|
+
return cachedData;
|
|
6405
|
+
}
|
|
6406
|
+
const data = await collection.findOne({
|
|
6407
|
+
_id,
|
|
6408
|
+
status: { $ne: "deleted" }
|
|
6409
|
+
});
|
|
6410
|
+
setCache(cacheKey, data).then(() => {
|
|
6411
|
+
logger18.log({
|
|
6412
|
+
level: "info",
|
|
6413
|
+
message: `Cache set for getById plan: ${cacheKey}`
|
|
6414
|
+
});
|
|
6415
|
+
}).catch((err) => {
|
|
6416
|
+
logger18.log({
|
|
6417
|
+
level: "error",
|
|
6418
|
+
message: `Failed to set cache for getById plan: ${err.message}`
|
|
6419
|
+
});
|
|
6420
|
+
});
|
|
6421
|
+
return data;
|
|
6422
|
+
} catch (error2) {
|
|
6423
|
+
throw new InternalServerError17("Failed to get plan.");
|
|
6424
|
+
}
|
|
6425
|
+
}
|
|
6426
|
+
async function getDefault() {
|
|
6427
|
+
try {
|
|
6428
|
+
const cacheKey = makeCacheKey13(namespace_collection, {
|
|
6429
|
+
default: true,
|
|
6430
|
+
tag: "getDefault"
|
|
6431
|
+
});
|
|
6432
|
+
const cachedData = await getCache(cacheKey);
|
|
6433
|
+
if (cachedData) {
|
|
6434
|
+
return cachedData;
|
|
6435
|
+
}
|
|
6436
|
+
const data = await collection.findOne({
|
|
6437
|
+
default: true,
|
|
6438
|
+
status: "active"
|
|
6439
|
+
});
|
|
6440
|
+
setCache(cacheKey, data).then(() => {
|
|
6441
|
+
logger18.log({
|
|
6442
|
+
level: "info",
|
|
6443
|
+
message: `Cache set for default plan: ${cacheKey}`
|
|
6444
|
+
});
|
|
6445
|
+
}).catch((err) => {
|
|
6446
|
+
logger18.log({
|
|
6447
|
+
level: "error",
|
|
6448
|
+
message: `Failed to set cache for default plan: ${err.message}`
|
|
6449
|
+
});
|
|
6450
|
+
});
|
|
6451
|
+
return data;
|
|
6452
|
+
} catch (error) {
|
|
6453
|
+
throw new InternalServerError17("Failed to get default plan.");
|
|
6454
|
+
}
|
|
6455
|
+
}
|
|
6456
|
+
async function deleteById(_id) {
|
|
6457
|
+
const { error } = Joi27.string().hex().length(24).required().validate(_id);
|
|
6458
|
+
if (error) {
|
|
6459
|
+
throw new Error(`Invalid plan ID: ${error.message}`);
|
|
6460
|
+
}
|
|
6461
|
+
try {
|
|
6462
|
+
_id = new ObjectId21(_id);
|
|
6463
|
+
} catch (error2) {
|
|
6464
|
+
throw new BadRequestError35("Invalid plan ID.");
|
|
6465
|
+
}
|
|
6466
|
+
try {
|
|
6467
|
+
const result = await collection.updateOne(
|
|
6468
|
+
{ _id },
|
|
6469
|
+
{ $set: { status: "deleted" } }
|
|
6470
|
+
);
|
|
6471
|
+
if (result.modifiedCount === 0) {
|
|
6472
|
+
throw new InternalServerError17("Failed to delete plan.");
|
|
6473
|
+
}
|
|
6474
|
+
delCachedData();
|
|
6475
|
+
return "Successfully deleted plan.";
|
|
6476
|
+
} catch (error2) {
|
|
6477
|
+
if (error2 instanceof AppError13) {
|
|
6478
|
+
throw error2;
|
|
6479
|
+
}
|
|
6480
|
+
throw new InternalServerError17("Failed to delete plan.");
|
|
6481
|
+
}
|
|
6482
|
+
}
|
|
6483
|
+
return {
|
|
6484
|
+
add,
|
|
6485
|
+
getAll,
|
|
6486
|
+
getById,
|
|
6487
|
+
getDefault,
|
|
6488
|
+
deleteById
|
|
6489
|
+
};
|
|
6490
|
+
}
|
|
6491
|
+
|
|
6492
|
+
// src/resources/plan/plan.service.ts
|
|
6493
|
+
function usePlanService() {
|
|
6494
|
+
const { add } = usePlanRepo();
|
|
6495
|
+
async function addDefaultPlan() {
|
|
6496
|
+
try {
|
|
6497
|
+
await add({
|
|
6498
|
+
name: "Standard",
|
|
6499
|
+
description: "Default standard plan",
|
|
6500
|
+
price: 1e3,
|
|
6501
|
+
currency: "PHP",
|
|
6502
|
+
billingCycle: "monthly",
|
|
6503
|
+
default: true
|
|
6504
|
+
});
|
|
6505
|
+
} catch (error) {
|
|
6506
|
+
throw error;
|
|
6507
|
+
}
|
|
6508
|
+
}
|
|
6509
|
+
return {
|
|
6510
|
+
addDefaultPlan
|
|
6511
|
+
};
|
|
6512
|
+
}
|
|
6513
|
+
|
|
6514
|
+
// src/resources/plan/plan.controller.ts
|
|
6515
|
+
import Joi28 from "joi";
|
|
6516
|
+
import { BadRequestError as BadRequestError36 } from "@goweekdays/utils";
|
|
6517
|
+
function usePlanController() {
|
|
6518
|
+
const {
|
|
6519
|
+
add: _add,
|
|
6520
|
+
getAll: _getAll,
|
|
6521
|
+
getById: _getById,
|
|
6522
|
+
deleteById: _deleteById,
|
|
6523
|
+
getDefault: _getDefault
|
|
6524
|
+
} = usePlanRepo();
|
|
6525
|
+
async function add(req, res, next) {
|
|
6526
|
+
const value = req.body;
|
|
6527
|
+
const validation = Joi28.object({
|
|
6528
|
+
name: Joi28.string().min(3).max(100).required(),
|
|
6529
|
+
description: Joi28.string().max(255).optional().allow("", null),
|
|
6530
|
+
features: Joi28.array().items(Joi28.string().max(100)).optional(),
|
|
6531
|
+
price: Joi28.number().positive().required(),
|
|
6532
|
+
currency: Joi28.string().length(3).required(),
|
|
6533
|
+
billingCycle: Joi28.string().valid("monthly", "yearly").required()
|
|
6534
|
+
});
|
|
6535
|
+
const { error } = validation.validate(value);
|
|
6536
|
+
if (error) {
|
|
6537
|
+
next(new BadRequestError36(error.message));
|
|
6538
|
+
return;
|
|
6539
|
+
}
|
|
6540
|
+
try {
|
|
6541
|
+
const message = await _add(value);
|
|
6542
|
+
res.json({ message });
|
|
6543
|
+
return;
|
|
6544
|
+
} catch (error2) {
|
|
6545
|
+
next(error2);
|
|
6546
|
+
}
|
|
6547
|
+
}
|
|
6548
|
+
async function getAll(req, res, next) {
|
|
6549
|
+
const status = req.query.status ?? "active";
|
|
6550
|
+
const search = req.query.search ?? "";
|
|
6551
|
+
const page = Number(req.query.page) ?? 1;
|
|
6552
|
+
const limit = Number(req.query.limit) ?? 10;
|
|
6553
|
+
const validation = Joi28.object({
|
|
6554
|
+
status: Joi28.string().required(),
|
|
6555
|
+
search: Joi28.string().optional().allow("", null),
|
|
6556
|
+
page: Joi28.number().required(),
|
|
6557
|
+
limit: Joi28.number().required()
|
|
6558
|
+
});
|
|
6559
|
+
const { error } = validation.validate({ status, search, page, limit });
|
|
6560
|
+
if (error) {
|
|
6561
|
+
next(new BadRequestError36(error.message));
|
|
6562
|
+
return;
|
|
6563
|
+
}
|
|
6564
|
+
try {
|
|
6565
|
+
const plans = await _getAll({ status, search, page, limit });
|
|
6566
|
+
res.json(plans);
|
|
6567
|
+
return;
|
|
6568
|
+
} catch (error2) {
|
|
6569
|
+
next(error2);
|
|
6570
|
+
}
|
|
6571
|
+
}
|
|
6572
|
+
async function getById(req, res, next) {
|
|
6573
|
+
const id = req.params.id;
|
|
6574
|
+
const validation = Joi28.string().hex().length(24).required();
|
|
6575
|
+
const { error } = validation.validate(id);
|
|
6576
|
+
if (error) {
|
|
6577
|
+
next(new BadRequestError36(error.message));
|
|
6578
|
+
return;
|
|
6579
|
+
}
|
|
6580
|
+
try {
|
|
6581
|
+
const plan = await _getById(id);
|
|
6582
|
+
res.json(plan);
|
|
6583
|
+
return;
|
|
6584
|
+
} catch (error2) {
|
|
6585
|
+
next(error2);
|
|
6586
|
+
}
|
|
6587
|
+
}
|
|
6588
|
+
async function deleteById(req, res, next) {
|
|
6589
|
+
const id = req.params.id;
|
|
6590
|
+
const validation = Joi28.string().hex().length(24).required();
|
|
6591
|
+
const { error } = validation.validate(id);
|
|
6592
|
+
if (error) {
|
|
6593
|
+
next(new BadRequestError36(error.message));
|
|
6594
|
+
return;
|
|
6595
|
+
}
|
|
6596
|
+
try {
|
|
6597
|
+
const message = await _deleteById(id);
|
|
6598
|
+
res.json({ message });
|
|
6599
|
+
return;
|
|
6600
|
+
} catch (error2) {
|
|
6601
|
+
next(error2);
|
|
6602
|
+
}
|
|
6603
|
+
}
|
|
6604
|
+
async function getDefault(req, res, next) {
|
|
6605
|
+
try {
|
|
6606
|
+
const plan = await _getDefault();
|
|
6607
|
+
res.json(plan);
|
|
6608
|
+
return;
|
|
6609
|
+
} catch (error) {
|
|
6610
|
+
next(error);
|
|
6611
|
+
}
|
|
6612
|
+
}
|
|
6613
|
+
return {
|
|
6614
|
+
add,
|
|
6615
|
+
getAll,
|
|
6616
|
+
getById,
|
|
6617
|
+
deleteById,
|
|
6618
|
+
getDefault
|
|
6619
|
+
};
|
|
6620
|
+
}
|
|
6621
|
+
|
|
6622
|
+
// src/resources/organization/organization.service.ts
|
|
6623
|
+
function useOrgService() {
|
|
6624
|
+
const { add: addOrg } = useOrgRepo();
|
|
6625
|
+
const { addRole } = useRoleRepo();
|
|
6626
|
+
const { getAll: getAllPermission } = usePermissionRepo();
|
|
6627
|
+
const { add: addMember, updateRoleById: _updateRoleById } = useMemberRepo();
|
|
6628
|
+
const { getUserById } = useUserRepo();
|
|
6629
|
+
const { getDefault } = usePlanRepo();
|
|
6630
|
+
const { add: addSubscription } = useSubscriptionRepo();
|
|
6631
|
+
const { add: addSubscriptionTransaction } = useSubscriptionTransactionRepo();
|
|
6632
|
+
async function add(value) {
|
|
6633
|
+
const { error } = schemaOrgAdd.validate(value);
|
|
6634
|
+
if (error) {
|
|
6635
|
+
throw new BadRequestError37(error.message);
|
|
6636
|
+
}
|
|
6637
|
+
const session = useAtlas17.getClient()?.startSession();
|
|
6638
|
+
if (!session) {
|
|
6639
|
+
throw new BadRequestError37("Unable to start database session.");
|
|
6640
|
+
}
|
|
6641
|
+
try {
|
|
6642
|
+
session?.startTransaction();
|
|
6643
|
+
const org = await addOrg(
|
|
6644
|
+
{
|
|
6645
|
+
email: value.email,
|
|
6646
|
+
name: value.name,
|
|
6647
|
+
contact: value.contact,
|
|
6648
|
+
createdBy: value.createdBy
|
|
6649
|
+
},
|
|
6650
|
+
session
|
|
6651
|
+
);
|
|
6652
|
+
const plan = await getDefault();
|
|
6653
|
+
if (!plan) {
|
|
6654
|
+
throw new BadRequestError37(
|
|
6655
|
+
"Failed to create organization, plan not found."
|
|
6656
|
+
);
|
|
6657
|
+
}
|
|
6658
|
+
const currentDate = /* @__PURE__ */ new Date();
|
|
6659
|
+
const nextBillingDate = new Date(currentDate);
|
|
6660
|
+
nextBillingDate.setMonth(currentDate.getMonth() + 1);
|
|
6661
|
+
const amount = plan.price * value.seats;
|
|
6662
|
+
const subscriptionId = await addSubscription(
|
|
6663
|
+
{
|
|
6664
|
+
amount,
|
|
6665
|
+
org: String(org),
|
|
6666
|
+
seats: value.seats,
|
|
6667
|
+
paidSeats: value.seats,
|
|
6668
|
+
currency: plan.currency,
|
|
6669
|
+
billingCycle: plan.billingCycle,
|
|
6670
|
+
nextBillingDate
|
|
6671
|
+
},
|
|
6672
|
+
session
|
|
6673
|
+
);
|
|
6674
|
+
const createdBy = String(value.createdBy);
|
|
6675
|
+
const user = await getUserById(createdBy);
|
|
6676
|
+
if (!user) {
|
|
6677
|
+
throw new BadRequestError37("User is required to create org member.");
|
|
6678
|
+
}
|
|
6679
|
+
await addSubscriptionTransaction(
|
|
6680
|
+
{
|
|
6681
|
+
subscription: subscriptionId,
|
|
6682
|
+
type: "initiate",
|
|
6683
|
+
amount,
|
|
6684
|
+
currency: plan.currency,
|
|
6685
|
+
description: "Initial subscription transaction",
|
|
6686
|
+
createdBy: value.createdBy,
|
|
6687
|
+
createdByName: `${user.firstName} ${user.lastName}`
|
|
6688
|
+
},
|
|
6689
|
+
session
|
|
6690
|
+
);
|
|
6691
|
+
const allPermissions = await getAllPermission({
|
|
6692
|
+
app: "org",
|
|
6693
|
+
limit: 100
|
|
6694
|
+
});
|
|
6695
|
+
let permissions = [];
|
|
6696
|
+
if (allPermissions && allPermissions.items && allPermissions.items.length) {
|
|
6697
|
+
permissions = allPermissions.items.map((perm) => perm.key);
|
|
6698
|
+
}
|
|
6699
|
+
if (permissions.length === 0) {
|
|
6700
|
+
throw new Error("No permissions found for the organization type.");
|
|
6701
|
+
}
|
|
6702
|
+
const roleData = {
|
|
6703
|
+
org: String(org),
|
|
6704
|
+
name: "Owner",
|
|
6705
|
+
description: "Owner of the organization",
|
|
6706
|
+
permissions,
|
|
6707
|
+
createdBy,
|
|
6708
|
+
app: "org"
|
|
6709
|
+
};
|
|
6710
|
+
const role = await addRole(roleData, session);
|
|
6711
|
+
if (!role) {
|
|
6712
|
+
throw new BadRequestError37("Role is required to create org member.");
|
|
6713
|
+
}
|
|
6714
|
+
await addMember(
|
|
6715
|
+
{
|
|
6716
|
+
role: String(role),
|
|
6717
|
+
roleName: roleData.name,
|
|
6718
|
+
org: String(org),
|
|
6719
|
+
name: `${user.firstName} ${user.lastName}`,
|
|
6720
|
+
user: createdBy,
|
|
6721
|
+
app: "org"
|
|
6722
|
+
},
|
|
6723
|
+
session
|
|
6724
|
+
);
|
|
6725
|
+
await session?.commitTransaction();
|
|
6726
|
+
return String(org);
|
|
6727
|
+
} catch (error2) {
|
|
6728
|
+
await session?.abortTransaction();
|
|
6729
|
+
throw error2;
|
|
6730
|
+
} finally {
|
|
6731
|
+
await session?.endSession();
|
|
6732
|
+
}
|
|
6733
|
+
}
|
|
6734
|
+
return {
|
|
6735
|
+
add
|
|
6736
|
+
};
|
|
6737
|
+
}
|
|
6738
|
+
|
|
6739
|
+
// src/resources/organization/organization.controller.ts
|
|
6740
|
+
import { BadRequestError as BadRequestError38 } from "@goweekdays/utils";
|
|
6741
|
+
import Joi29 from "joi";
|
|
6742
|
+
function useOrgController() {
|
|
6743
|
+
const { add: _add } = useOrgService();
|
|
6744
|
+
const { getOrgsByMembership } = useMemberRepo();
|
|
6745
|
+
const {
|
|
6746
|
+
getByName: _getByName,
|
|
6747
|
+
getAll: getAllOrg,
|
|
6748
|
+
getById: _getById,
|
|
6749
|
+
updateById: _updateById
|
|
6750
|
+
} = useOrgRepo();
|
|
6751
|
+
async function add(req, res, next) {
|
|
6752
|
+
const value = req.body;
|
|
6753
|
+
const { error } = schemaOrgAdd.validate(value);
|
|
6754
|
+
if (error) {
|
|
6755
|
+
next(new BadRequestError38(error.message));
|
|
6756
|
+
return;
|
|
6757
|
+
}
|
|
6758
|
+
try {
|
|
6759
|
+
const org = await _add(value);
|
|
6760
|
+
res.json({
|
|
6761
|
+
message: "Organization created successfully.",
|
|
6762
|
+
data: { org }
|
|
6763
|
+
});
|
|
6764
|
+
return;
|
|
6765
|
+
} catch (error2) {
|
|
6766
|
+
next(error2);
|
|
6767
|
+
}
|
|
6768
|
+
}
|
|
6769
|
+
async function getOrgsByUserId(req, res, next) {
|
|
6770
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
6771
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
6772
|
+
const search = req.query.search ?? "";
|
|
6773
|
+
const user = req.params.user ?? "";
|
|
6774
|
+
const isPageNumber = isFinite(page);
|
|
6775
|
+
if (!isPageNumber) {
|
|
6776
|
+
next(new BadRequestError38("Invalid page number."));
|
|
6777
|
+
return;
|
|
6778
|
+
}
|
|
6779
|
+
const isLimitNumber = isFinite(limit);
|
|
6780
|
+
if (!isLimitNumber) {
|
|
6781
|
+
next(new BadRequestError38("Invalid limit number."));
|
|
6782
|
+
return;
|
|
6783
|
+
}
|
|
6784
|
+
const validation = Joi29.object({
|
|
6785
|
+
user: Joi29.string().hex().required(),
|
|
6786
|
+
page: Joi29.number().min(1).optional().allow("", null),
|
|
6787
|
+
limit: Joi29.number().min(1).optional().allow("", null),
|
|
6788
|
+
search: Joi29.string().optional().allow("", null)
|
|
6789
|
+
});
|
|
6790
|
+
const { error } = validation.validate({ user, page, limit, search });
|
|
6791
|
+
if (error) {
|
|
6792
|
+
next(new BadRequestError38(error.message));
|
|
6793
|
+
return;
|
|
6794
|
+
}
|
|
6795
|
+
try {
|
|
6796
|
+
const orgs = await getOrgsByMembership({ user, page, limit, search });
|
|
6797
|
+
res.json(orgs);
|
|
6798
|
+
return;
|
|
6799
|
+
} catch (error2) {
|
|
6800
|
+
next(error2);
|
|
6801
|
+
}
|
|
6802
|
+
}
|
|
6803
|
+
async function getAll(req, res, next) {
|
|
6804
|
+
const query = req.query;
|
|
6805
|
+
const validation = Joi29.object({
|
|
6806
|
+
page: Joi29.number().min(1).optional().allow("", null),
|
|
6807
|
+
limit: Joi29.number().min(1).optional().allow("", null),
|
|
6808
|
+
search: Joi29.string().optional().allow("", null),
|
|
6809
|
+
status: Joi29.string().valid("active", "suspended", "inactive", "deleted").optional()
|
|
6810
|
+
});
|
|
6811
|
+
const { error } = validation.validate(query);
|
|
6812
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
6813
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
6814
|
+
const search = req.query.search ?? "";
|
|
6815
|
+
const status = req.query.status ?? "active";
|
|
6816
|
+
const isPageNumber = isFinite(page);
|
|
5562
6817
|
if (!isPageNumber) {
|
|
5563
|
-
next(new
|
|
6818
|
+
next(new BadRequestError38("Invalid page number."));
|
|
5564
6819
|
return;
|
|
5565
6820
|
}
|
|
5566
6821
|
const isLimitNumber = isFinite(limit);
|
|
5567
6822
|
if (!isLimitNumber) {
|
|
5568
|
-
next(new
|
|
6823
|
+
next(new BadRequestError38("Invalid limit number."));
|
|
5569
6824
|
return;
|
|
5570
6825
|
}
|
|
5571
6826
|
if (error) {
|
|
5572
|
-
next(new
|
|
6827
|
+
next(new BadRequestError38(error.message));
|
|
5573
6828
|
return;
|
|
5574
6829
|
}
|
|
5575
6830
|
try {
|
|
@@ -5582,12 +6837,12 @@ function useOrgController() {
|
|
|
5582
6837
|
}
|
|
5583
6838
|
async function getByName(req, res, next) {
|
|
5584
6839
|
const name = req.params.name;
|
|
5585
|
-
const validation =
|
|
5586
|
-
name:
|
|
6840
|
+
const validation = Joi29.object({
|
|
6841
|
+
name: Joi29.string().required()
|
|
5587
6842
|
});
|
|
5588
6843
|
const { error } = validation.validate({ name });
|
|
5589
6844
|
if (error) {
|
|
5590
|
-
next(new
|
|
6845
|
+
next(new BadRequestError38(error.message));
|
|
5591
6846
|
return;
|
|
5592
6847
|
}
|
|
5593
6848
|
try {
|
|
@@ -5600,12 +6855,12 @@ function useOrgController() {
|
|
|
5600
6855
|
}
|
|
5601
6856
|
async function getById(req, res, next) {
|
|
5602
6857
|
const id = req.params.id;
|
|
5603
|
-
const validation =
|
|
5604
|
-
id:
|
|
6858
|
+
const validation = Joi29.object({
|
|
6859
|
+
id: Joi29.string().hex().required()
|
|
5605
6860
|
});
|
|
5606
6861
|
const { error } = validation.validate({ id });
|
|
5607
6862
|
if (error) {
|
|
5608
|
-
next(new
|
|
6863
|
+
next(new BadRequestError38(error.message));
|
|
5609
6864
|
return;
|
|
5610
6865
|
}
|
|
5611
6866
|
try {
|
|
@@ -5616,12 +6871,29 @@ function useOrgController() {
|
|
|
5616
6871
|
next(error2);
|
|
5617
6872
|
}
|
|
5618
6873
|
}
|
|
6874
|
+
async function updateById(req, res, next) {
|
|
6875
|
+
const _id = req.params.id ?? "";
|
|
6876
|
+
const payload = req.body;
|
|
6877
|
+
const { error } = schemaOrgUpdate.validate({ _id, ...payload });
|
|
6878
|
+
if (error) {
|
|
6879
|
+
next(new BadRequestError38(error.message));
|
|
6880
|
+
return;
|
|
6881
|
+
}
|
|
6882
|
+
try {
|
|
6883
|
+
const message = await _updateById(_id, payload);
|
|
6884
|
+
res.json({ message });
|
|
6885
|
+
return;
|
|
6886
|
+
} catch (error2) {
|
|
6887
|
+
next(error2);
|
|
6888
|
+
}
|
|
6889
|
+
}
|
|
5619
6890
|
return {
|
|
5620
6891
|
add,
|
|
5621
6892
|
getOrgsByUserId,
|
|
5622
6893
|
getByName,
|
|
5623
6894
|
getAll,
|
|
5624
|
-
getById
|
|
6895
|
+
getById,
|
|
6896
|
+
updateById
|
|
5625
6897
|
};
|
|
5626
6898
|
}
|
|
5627
6899
|
|
|
@@ -5640,12 +6912,12 @@ function useUserService() {
|
|
|
5640
6912
|
const { getAll: getAllPermission } = usePermissionRepo();
|
|
5641
6913
|
const { getById: getOrgById } = useOrgRepo();
|
|
5642
6914
|
async function createDefaultUser() {
|
|
5643
|
-
const session =
|
|
6915
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5644
6916
|
try {
|
|
5645
6917
|
session?.startTransaction();
|
|
5646
6918
|
const _user = await getUserByEmail(DEFAULT_USER_EMAIL);
|
|
5647
6919
|
if (_user) {
|
|
5648
|
-
throw new
|
|
6920
|
+
throw new BadRequestError39(
|
|
5649
6921
|
`User already exists: ${DEFAULT_USER_EMAIL}.`
|
|
5650
6922
|
);
|
|
5651
6923
|
}
|
|
@@ -5695,7 +6967,7 @@ function useUserService() {
|
|
|
5695
6967
|
try {
|
|
5696
6968
|
const _user = await getUserByEmail(value.email);
|
|
5697
6969
|
if (_user) {
|
|
5698
|
-
throw new
|
|
6970
|
+
throw new BadRequestError39(`User already exists: ${value.email}.`);
|
|
5699
6971
|
}
|
|
5700
6972
|
const hashedPassword = await hashPassword(value.password);
|
|
5701
6973
|
const insertedId = await addUser({
|
|
@@ -5707,10 +6979,10 @@ function useUserService() {
|
|
|
5707
6979
|
});
|
|
5708
6980
|
return insertedId;
|
|
5709
6981
|
} catch (error) {
|
|
5710
|
-
if (error instanceof
|
|
6982
|
+
if (error instanceof AppError14) {
|
|
5711
6983
|
throw error;
|
|
5712
6984
|
} else {
|
|
5713
|
-
throw new
|
|
6985
|
+
throw new InternalServerError18(`Error creating user: ${error}`);
|
|
5714
6986
|
}
|
|
5715
6987
|
}
|
|
5716
6988
|
}
|
|
@@ -5721,22 +6993,22 @@ function useUserService() {
|
|
|
5721
6993
|
lastName = "",
|
|
5722
6994
|
password = ""
|
|
5723
6995
|
} = {}) {
|
|
5724
|
-
const session =
|
|
6996
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5725
6997
|
session?.startTransaction();
|
|
5726
6998
|
try {
|
|
5727
6999
|
const invitation = await _getVerificationById(id);
|
|
5728
7000
|
if (!invitation || !invitation.metadata?.app || !invitation.metadata?.role) {
|
|
5729
|
-
throw new
|
|
7001
|
+
throw new BadRequestError39("Invalid invitation.");
|
|
5730
7002
|
}
|
|
5731
7003
|
if (invitation.status === "complete") {
|
|
5732
|
-
throw new
|
|
7004
|
+
throw new BadRequestError39("Invitation already used.");
|
|
5733
7005
|
}
|
|
5734
7006
|
if (!invitation.expireAt) {
|
|
5735
|
-
throw new
|
|
7007
|
+
throw new BadRequestError39("Expiration date is required.");
|
|
5736
7008
|
}
|
|
5737
7009
|
const expired = new Date(invitation.expireAt) < /* @__PURE__ */ new Date();
|
|
5738
7010
|
if (invitation.status === "expired" || expired) {
|
|
5739
|
-
throw new
|
|
7011
|
+
throw new BadRequestError39("Invitation expired.");
|
|
5740
7012
|
}
|
|
5741
7013
|
const email = invitation.email;
|
|
5742
7014
|
const user = await getUserByEmail(invitation.email);
|
|
@@ -5787,10 +7059,10 @@ function useUserService() {
|
|
|
5787
7059
|
return userId;
|
|
5788
7060
|
} catch (error) {
|
|
5789
7061
|
await session?.abortTransaction();
|
|
5790
|
-
if (error instanceof
|
|
7062
|
+
if (error instanceof AppError14) {
|
|
5791
7063
|
throw error;
|
|
5792
7064
|
} else {
|
|
5793
|
-
throw new
|
|
7065
|
+
throw new InternalServerError18("Failed to create user by invite.");
|
|
5794
7066
|
}
|
|
5795
7067
|
} finally {
|
|
5796
7068
|
session?.endSession();
|
|
@@ -5802,29 +7074,29 @@ function useUserService() {
|
|
|
5802
7074
|
lastName = "",
|
|
5803
7075
|
password = ""
|
|
5804
7076
|
} = {}) {
|
|
5805
|
-
const session =
|
|
7077
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5806
7078
|
session?.startTransaction();
|
|
5807
7079
|
try {
|
|
5808
7080
|
const signUp = await _getVerificationById(id);
|
|
5809
7081
|
if (!signUp) {
|
|
5810
|
-
throw new
|
|
7082
|
+
throw new BadRequestError39("Invalid sign up link.");
|
|
5811
7083
|
}
|
|
5812
7084
|
if (signUp.status === "complete") {
|
|
5813
|
-
throw new
|
|
7085
|
+
throw new BadRequestError39(
|
|
5814
7086
|
"You have already an account created using this link."
|
|
5815
7087
|
);
|
|
5816
7088
|
}
|
|
5817
7089
|
if (!signUp.expireAt) {
|
|
5818
|
-
throw new
|
|
7090
|
+
throw new BadRequestError39("Expiration date is required.");
|
|
5819
7091
|
}
|
|
5820
7092
|
const expired = new Date(signUp.expireAt) < /* @__PURE__ */ new Date();
|
|
5821
7093
|
if (signUp.status === "expired" || expired) {
|
|
5822
|
-
throw new
|
|
7094
|
+
throw new BadRequestError39("Sign up link expired.");
|
|
5823
7095
|
}
|
|
5824
7096
|
const email = signUp.email;
|
|
5825
7097
|
const _user = await getUserByEmail(signUp.email);
|
|
5826
7098
|
if (_user) {
|
|
5827
|
-
throw new
|
|
7099
|
+
throw new BadRequestError39(`User already exists: ${email}.`);
|
|
5828
7100
|
}
|
|
5829
7101
|
const hashedPassword = await hashPassword(password);
|
|
5830
7102
|
const userId = await addUser(
|
|
@@ -5850,17 +7122,17 @@ function useUserService() {
|
|
|
5850
7122
|
const { updateStatusById: updateVerificationStatusById } = useVerificationRepo();
|
|
5851
7123
|
async function resetPassword(value) {
|
|
5852
7124
|
if (value.newPassword !== value.confirmPassword) {
|
|
5853
|
-
throw new
|
|
7125
|
+
throw new BadRequestError39("Passwords do not match.");
|
|
5854
7126
|
}
|
|
5855
7127
|
let hashedPassword = "";
|
|
5856
7128
|
try {
|
|
5857
7129
|
hashedPassword = await hashPassword(value.newPassword);
|
|
5858
7130
|
} catch (error) {
|
|
5859
|
-
throw new
|
|
7131
|
+
throw new InternalServerError18(`Error hashing password: ${error}`);
|
|
5860
7132
|
}
|
|
5861
|
-
const session =
|
|
7133
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5862
7134
|
if (!session) {
|
|
5863
|
-
throw new
|
|
7135
|
+
throw new InternalServerError18("Failed to start database session.");
|
|
5864
7136
|
}
|
|
5865
7137
|
try {
|
|
5866
7138
|
session.startTransaction();
|
|
@@ -5876,7 +7148,7 @@ function useUserService() {
|
|
|
5876
7148
|
throw new NotFoundError3("User ID is invalid.");
|
|
5877
7149
|
}
|
|
5878
7150
|
if (otpDoc.status === "used") {
|
|
5879
|
-
throw new
|
|
7151
|
+
throw new BadRequestError39("This link has already been invalidated.");
|
|
5880
7152
|
}
|
|
5881
7153
|
await updateVerificationStatusById(value.id, "used", session);
|
|
5882
7154
|
await _updateUserFieldById(
|
|
@@ -5887,31 +7159,31 @@ function useUserService() {
|
|
|
5887
7159
|
return "Successfully reset password.";
|
|
5888
7160
|
} catch (error) {
|
|
5889
7161
|
await session.abortTransaction();
|
|
5890
|
-
if (error instanceof
|
|
7162
|
+
if (error instanceof AppError14) {
|
|
5891
7163
|
throw error;
|
|
5892
7164
|
}
|
|
5893
|
-
throw new
|
|
7165
|
+
throw new InternalServerError18("Failed to reset password.");
|
|
5894
7166
|
}
|
|
5895
7167
|
}
|
|
5896
7168
|
const { updateName: updateMemberName } = useMemberRepo();
|
|
5897
7169
|
async function updateName(_id, firstName, lastName) {
|
|
5898
7170
|
if (!_id) {
|
|
5899
|
-
throw new
|
|
7171
|
+
throw new BadRequestError39("Invalid user ID");
|
|
5900
7172
|
}
|
|
5901
7173
|
if (!firstName) {
|
|
5902
|
-
throw new
|
|
7174
|
+
throw new BadRequestError39("Invalid firstName");
|
|
5903
7175
|
}
|
|
5904
7176
|
if (!lastName) {
|
|
5905
|
-
throw new
|
|
7177
|
+
throw new BadRequestError39("Invalid lastName");
|
|
5906
7178
|
}
|
|
5907
|
-
const session =
|
|
7179
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5908
7180
|
session?.startTransaction();
|
|
5909
|
-
const cacheKey =
|
|
7181
|
+
const cacheKey = makeCacheKey14("users", { user: _id });
|
|
5910
7182
|
try {
|
|
5911
|
-
|
|
5912
|
-
|
|
7183
|
+
useCache15().delCache(cacheKey).then(() => {
|
|
7184
|
+
logger19.info(`Cache cleared for user: ${_id}`);
|
|
5913
7185
|
}).catch((error) => {
|
|
5914
|
-
|
|
7186
|
+
logger19.error(`Failed to clear cache for user: ${_id}`, error);
|
|
5915
7187
|
});
|
|
5916
7188
|
await _updateName({ _id, firstName, lastName }, session);
|
|
5917
7189
|
await updateMemberName(
|
|
@@ -5929,16 +7201,16 @@ function useUserService() {
|
|
|
5929
7201
|
}
|
|
5930
7202
|
async function updateBirthday(_id, month, day, year) {
|
|
5931
7203
|
if (!_id) {
|
|
5932
|
-
throw new
|
|
7204
|
+
throw new BadRequestError39("Invalid user ID");
|
|
5933
7205
|
}
|
|
5934
7206
|
if (!month) {
|
|
5935
|
-
throw new
|
|
7207
|
+
throw new BadRequestError39("Invalid birth month.");
|
|
5936
7208
|
}
|
|
5937
7209
|
if (!day) {
|
|
5938
|
-
throw new
|
|
7210
|
+
throw new BadRequestError39("Invalid birthday.");
|
|
5939
7211
|
}
|
|
5940
7212
|
if (!year) {
|
|
5941
|
-
throw new
|
|
7213
|
+
throw new BadRequestError39("Invalid birth year.");
|
|
5942
7214
|
}
|
|
5943
7215
|
try {
|
|
5944
7216
|
await _updateBirthday({ _id, month, day, year });
|
|
@@ -5963,7 +7235,7 @@ function useUserService() {
|
|
|
5963
7235
|
bucket: SPACES_BUCKET
|
|
5964
7236
|
});
|
|
5965
7237
|
async function updateUserProfile({ file, user, previousProfile } = {}) {
|
|
5966
|
-
const session =
|
|
7238
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5967
7239
|
session?.startTransaction();
|
|
5968
7240
|
const _file = {
|
|
5969
7241
|
name: file.originalname,
|
|
@@ -6008,11 +7280,11 @@ function useUserService() {
|
|
|
6008
7280
|
|
|
6009
7281
|
// src/resources/user/user.controller.ts
|
|
6010
7282
|
import {
|
|
6011
|
-
AppError as
|
|
6012
|
-
BadRequestError as
|
|
6013
|
-
InternalServerError as
|
|
7283
|
+
AppError as AppError15,
|
|
7284
|
+
BadRequestError as BadRequestError40,
|
|
7285
|
+
InternalServerError as InternalServerError19
|
|
6014
7286
|
} from "@goweekdays/utils";
|
|
6015
|
-
import
|
|
7287
|
+
import Joi30 from "joi";
|
|
6016
7288
|
function useUserController() {
|
|
6017
7289
|
const {
|
|
6018
7290
|
updateName: _updateName,
|
|
@@ -6028,14 +7300,14 @@ function useUserController() {
|
|
|
6028
7300
|
const status = req.query.status ?? "";
|
|
6029
7301
|
const search = req.query.search ?? "";
|
|
6030
7302
|
const page = Number(req.query.page) ?? 1;
|
|
6031
|
-
const validation =
|
|
6032
|
-
status:
|
|
6033
|
-
search:
|
|
6034
|
-
page:
|
|
7303
|
+
const validation = Joi30.object({
|
|
7304
|
+
status: Joi30.string().required(),
|
|
7305
|
+
search: Joi30.string().optional().allow("", null),
|
|
7306
|
+
page: Joi30.number().required()
|
|
6035
7307
|
});
|
|
6036
7308
|
const { error } = validation.validate({ status, search, page });
|
|
6037
7309
|
if (error) {
|
|
6038
|
-
next(new
|
|
7310
|
+
next(new BadRequestError40(error.message));
|
|
6039
7311
|
return;
|
|
6040
7312
|
}
|
|
6041
7313
|
try {
|
|
@@ -6048,14 +7320,14 @@ function useUserController() {
|
|
|
6048
7320
|
}
|
|
6049
7321
|
async function getUserById(req, res, next) {
|
|
6050
7322
|
const id = req.params.id || "";
|
|
6051
|
-
const validation =
|
|
7323
|
+
const validation = Joi30.string().hex().validate(id);
|
|
6052
7324
|
if (validation.error) {
|
|
6053
|
-
throw new
|
|
7325
|
+
throw new BadRequestError40("Invalid id.");
|
|
6054
7326
|
}
|
|
6055
7327
|
try {
|
|
6056
7328
|
const user = await _getUserById(id);
|
|
6057
7329
|
if (!user) {
|
|
6058
|
-
throw new
|
|
7330
|
+
throw new BadRequestError40("User not found.");
|
|
6059
7331
|
}
|
|
6060
7332
|
res.json(user);
|
|
6061
7333
|
} catch (error) {
|
|
@@ -6066,13 +7338,13 @@ function useUserController() {
|
|
|
6066
7338
|
const id = req.headers.user ?? "";
|
|
6067
7339
|
const firstName = req.body.firstName ?? "";
|
|
6068
7340
|
const lastName = req.body.lastName ?? "";
|
|
6069
|
-
const validation =
|
|
6070
|
-
firstName:
|
|
6071
|
-
lastName:
|
|
7341
|
+
const validation = Joi30.object({
|
|
7342
|
+
firstName: Joi30.string().required(),
|
|
7343
|
+
lastName: Joi30.string().required()
|
|
6072
7344
|
});
|
|
6073
7345
|
const { error } = validation.validate({ firstName, lastName });
|
|
6074
7346
|
if (error) {
|
|
6075
|
-
next(new
|
|
7347
|
+
next(new BadRequestError40(error.message));
|
|
6076
7348
|
return;
|
|
6077
7349
|
}
|
|
6078
7350
|
try {
|
|
@@ -6088,14 +7360,14 @@ function useUserController() {
|
|
|
6088
7360
|
const month = req.body.month ?? "";
|
|
6089
7361
|
const day = req.body.day ?? 0;
|
|
6090
7362
|
const year = req.body.year ?? 0;
|
|
6091
|
-
const validation =
|
|
6092
|
-
month:
|
|
6093
|
-
day:
|
|
6094
|
-
year:
|
|
7363
|
+
const validation = Joi30.object({
|
|
7364
|
+
month: Joi30.string().required(),
|
|
7365
|
+
day: Joi30.number().integer().min(1).max(31).required(),
|
|
7366
|
+
year: Joi30.number().integer().min(1900).max((/* @__PURE__ */ new Date()).getFullYear()).required()
|
|
6095
7367
|
});
|
|
6096
7368
|
const { error } = validation.validate({ month, day, year });
|
|
6097
7369
|
if (error) {
|
|
6098
|
-
next(new
|
|
7370
|
+
next(new BadRequestError40(error.message));
|
|
6099
7371
|
return;
|
|
6100
7372
|
}
|
|
6101
7373
|
try {
|
|
@@ -6109,18 +7381,18 @@ function useUserController() {
|
|
|
6109
7381
|
async function updateUserFieldById(req, res, next) {
|
|
6110
7382
|
const _id = req.params.id;
|
|
6111
7383
|
const { field, value } = req.body;
|
|
6112
|
-
const validation =
|
|
6113
|
-
_id:
|
|
6114
|
-
field:
|
|
6115
|
-
value:
|
|
7384
|
+
const validation = Joi30.object({
|
|
7385
|
+
_id: Joi30.string().hex().required(),
|
|
7386
|
+
field: Joi30.string().valid("gender", "email", "contact", "profile").required(),
|
|
7387
|
+
value: Joi30.alternatives().conditional("field", {
|
|
6116
7388
|
is: "email",
|
|
6117
|
-
then:
|
|
6118
|
-
otherwise:
|
|
7389
|
+
then: Joi30.string().email().required(),
|
|
7390
|
+
otherwise: Joi30.string().required()
|
|
6119
7391
|
})
|
|
6120
7392
|
});
|
|
6121
7393
|
const { error } = validation.validate({ _id, field, value });
|
|
6122
7394
|
if (error) {
|
|
6123
|
-
next(new
|
|
7395
|
+
next(new BadRequestError40(error.message));
|
|
6124
7396
|
return;
|
|
6125
7397
|
}
|
|
6126
7398
|
try {
|
|
@@ -6136,12 +7408,12 @@ function useUserController() {
|
|
|
6136
7408
|
return;
|
|
6137
7409
|
}
|
|
6138
7410
|
const previousProfile = req.body.previousProfile ?? "";
|
|
6139
|
-
const validation =
|
|
6140
|
-
previousProfile:
|
|
7411
|
+
const validation = Joi30.object({
|
|
7412
|
+
previousProfile: Joi30.string().hex().optional().allow("", null)
|
|
6141
7413
|
});
|
|
6142
7414
|
const { error } = validation.validate({ previousProfile });
|
|
6143
7415
|
if (error) {
|
|
6144
|
-
next(new
|
|
7416
|
+
next(new BadRequestError40(error.message));
|
|
6145
7417
|
return;
|
|
6146
7418
|
}
|
|
6147
7419
|
const user = req.headers["user"] ?? "";
|
|
@@ -6154,10 +7426,10 @@ function useUserController() {
|
|
|
6154
7426
|
res.json({ message: "Successfully updated profile picture." });
|
|
6155
7427
|
return;
|
|
6156
7428
|
} catch (error2) {
|
|
6157
|
-
if (error2 instanceof
|
|
7429
|
+
if (error2 instanceof AppError15) {
|
|
6158
7430
|
next(error2);
|
|
6159
7431
|
} else {
|
|
6160
|
-
next(new
|
|
7432
|
+
next(new InternalServerError19(error2));
|
|
6161
7433
|
}
|
|
6162
7434
|
}
|
|
6163
7435
|
}
|
|
@@ -6167,12 +7439,12 @@ function useUserController() {
|
|
|
6167
7439
|
const password = req.body.password ?? "";
|
|
6168
7440
|
const id = req.params.id ?? "";
|
|
6169
7441
|
const type = req.body.type ?? "";
|
|
6170
|
-
const validation =
|
|
6171
|
-
firstName:
|
|
6172
|
-
lastName:
|
|
6173
|
-
password:
|
|
6174
|
-
id:
|
|
6175
|
-
type:
|
|
7442
|
+
const validation = Joi30.object({
|
|
7443
|
+
firstName: Joi30.string().required(),
|
|
7444
|
+
lastName: Joi30.string().required(),
|
|
7445
|
+
password: Joi30.string().required(),
|
|
7446
|
+
id: Joi30.string().hex().required(),
|
|
7447
|
+
type: Joi30.string().required()
|
|
6176
7448
|
});
|
|
6177
7449
|
const { error } = validation.validate({
|
|
6178
7450
|
firstName,
|
|
@@ -6182,7 +7454,7 @@ function useUserController() {
|
|
|
6182
7454
|
type
|
|
6183
7455
|
});
|
|
6184
7456
|
if (error) {
|
|
6185
|
-
next(new
|
|
7457
|
+
next(new BadRequestError40(error.message));
|
|
6186
7458
|
return;
|
|
6187
7459
|
}
|
|
6188
7460
|
try {
|
|
@@ -6205,14 +7477,14 @@ function useUserController() {
|
|
|
6205
7477
|
}
|
|
6206
7478
|
async function resetPassword(req, res, next) {
|
|
6207
7479
|
const payload = req.body;
|
|
6208
|
-
const validation =
|
|
6209
|
-
id:
|
|
6210
|
-
newPassword:
|
|
6211
|
-
confirmPassword:
|
|
7480
|
+
const validation = Joi30.object({
|
|
7481
|
+
id: Joi30.string().hex().required(),
|
|
7482
|
+
newPassword: Joi30.string().min(8).required(),
|
|
7483
|
+
confirmPassword: Joi30.string().min(8).required()
|
|
6212
7484
|
});
|
|
6213
7485
|
const { error } = validation.validate(payload);
|
|
6214
7486
|
if (error) {
|
|
6215
|
-
next(new
|
|
7487
|
+
next(new BadRequestError40(error.message));
|
|
6216
7488
|
return;
|
|
6217
7489
|
}
|
|
6218
7490
|
try {
|
|
@@ -6237,7 +7509,7 @@ function useUserController() {
|
|
|
6237
7509
|
}
|
|
6238
7510
|
|
|
6239
7511
|
// src/resources/verification/verification.service.ts
|
|
6240
|
-
import
|
|
7512
|
+
import Joi31 from "joi";
|
|
6241
7513
|
function useVerificationService() {
|
|
6242
7514
|
const MailerConfig = {
|
|
6243
7515
|
host: MAILER_TRANSPORT_HOST,
|
|
@@ -6272,7 +7544,7 @@ function useVerificationService() {
|
|
|
6272
7544
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6273
7545
|
};
|
|
6274
7546
|
if (!metadata.app) {
|
|
6275
|
-
throw new
|
|
7547
|
+
throw new BadRequestError41("App metadata is required.");
|
|
6276
7548
|
}
|
|
6277
7549
|
try {
|
|
6278
7550
|
const user = await getUserByEmail(email);
|
|
@@ -6295,7 +7567,7 @@ function useVerificationService() {
|
|
|
6295
7567
|
html: emailContent2,
|
|
6296
7568
|
from: "GoWeekdays"
|
|
6297
7569
|
}).catch((error) => {
|
|
6298
|
-
|
|
7570
|
+
logger20.log({
|
|
6299
7571
|
level: "error",
|
|
6300
7572
|
message: `Error sending user invite email: ${error}`
|
|
6301
7573
|
});
|
|
@@ -6317,7 +7589,7 @@ function useVerificationService() {
|
|
|
6317
7589
|
html: emailContent,
|
|
6318
7590
|
from: "GoWeekdays"
|
|
6319
7591
|
}).catch((error) => {
|
|
6320
|
-
|
|
7592
|
+
logger20.log({
|
|
6321
7593
|
level: "error",
|
|
6322
7594
|
message: `Error sending user invite email: ${error}`
|
|
6323
7595
|
});
|
|
@@ -6352,14 +7624,14 @@ function useVerificationService() {
|
|
|
6352
7624
|
from: "GoWeekdays",
|
|
6353
7625
|
html: emailContent
|
|
6354
7626
|
}).catch((error) => {
|
|
6355
|
-
|
|
7627
|
+
logger20.log({
|
|
6356
7628
|
level: "error",
|
|
6357
7629
|
message: `Error sending forget password email: ${error}`
|
|
6358
7630
|
});
|
|
6359
7631
|
});
|
|
6360
7632
|
return "Successfully created a link to reset password. Please check your email.";
|
|
6361
7633
|
} catch (error) {
|
|
6362
|
-
throw new
|
|
7634
|
+
throw new InternalServerError20("Failed to create forget password link.");
|
|
6363
7635
|
}
|
|
6364
7636
|
}
|
|
6365
7637
|
async function getById(id) {
|
|
@@ -6398,34 +7670,34 @@ function useVerificationService() {
|
|
|
6398
7670
|
}
|
|
6399
7671
|
function errorByType(type, status) {
|
|
6400
7672
|
if (type === "user-invite" && status === "expired") {
|
|
6401
|
-
throw new
|
|
7673
|
+
throw new BadRequestError41(
|
|
6402
7674
|
"Invitation has already expired, please contact admin to resend the invitation."
|
|
6403
7675
|
);
|
|
6404
7676
|
}
|
|
6405
7677
|
if (type === "user-sign-up" && status === "expired") {
|
|
6406
|
-
throw new
|
|
7678
|
+
throw new BadRequestError41(
|
|
6407
7679
|
"Sign up verification has expired, please sign up again to get a new verification link."
|
|
6408
7680
|
);
|
|
6409
7681
|
}
|
|
6410
7682
|
if (type === "user-invite" && status === "complete") {
|
|
6411
|
-
throw new
|
|
7683
|
+
throw new BadRequestError41(
|
|
6412
7684
|
"User already registered, please login to continue."
|
|
6413
7685
|
);
|
|
6414
7686
|
}
|
|
6415
7687
|
if (type === "forget-password" && status === "complete") {
|
|
6416
|
-
throw new
|
|
7688
|
+
throw new BadRequestError41(
|
|
6417
7689
|
"Forget password verification has already been used, please request a new one."
|
|
6418
7690
|
);
|
|
6419
7691
|
}
|
|
6420
7692
|
if (type === "forget-password" && status === "expired") {
|
|
6421
|
-
throw new
|
|
7693
|
+
throw new BadRequestError41(
|
|
6422
7694
|
"Forget password verification has expired, please request a new one."
|
|
6423
7695
|
);
|
|
6424
7696
|
}
|
|
6425
|
-
throw new
|
|
7697
|
+
throw new BadRequestError41("Invalid verification.");
|
|
6426
7698
|
}
|
|
6427
7699
|
async function verify(id) {
|
|
6428
|
-
const session =
|
|
7700
|
+
const session = useAtlas19.getClient()?.startSession();
|
|
6429
7701
|
session?.startTransaction();
|
|
6430
7702
|
try {
|
|
6431
7703
|
const _id = await _getById(id);
|
|
@@ -6436,10 +7708,10 @@ function useVerificationService() {
|
|
|
6436
7708
|
errorByType(_id.type, "expired");
|
|
6437
7709
|
}
|
|
6438
7710
|
if (_id.status === "complete") {
|
|
6439
|
-
throw new
|
|
7711
|
+
throw new BadRequestError41("Verification already completed.");
|
|
6440
7712
|
}
|
|
6441
7713
|
if (!_id.expireAt) {
|
|
6442
|
-
throw new
|
|
7714
|
+
throw new BadRequestError41("Expiration date is required.");
|
|
6443
7715
|
}
|
|
6444
7716
|
const expiration = new Date(_id.expireAt).getTime();
|
|
6445
7717
|
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
@@ -6455,12 +7727,12 @@ function useVerificationService() {
|
|
|
6455
7727
|
throw new NotFoundError4("User not found for member invite.");
|
|
6456
7728
|
}
|
|
6457
7729
|
if (!_id.metadata?.app) {
|
|
6458
|
-
throw new
|
|
7730
|
+
throw new BadRequestError41(
|
|
6459
7731
|
"App metadata is required for member invite."
|
|
6460
7732
|
);
|
|
6461
7733
|
}
|
|
6462
7734
|
if (!_id.metadata?.role || !_id.metadata?.roleName) {
|
|
6463
|
-
throw new
|
|
7735
|
+
throw new BadRequestError41(
|
|
6464
7736
|
"Role metadata is required for member invite."
|
|
6465
7737
|
);
|
|
6466
7738
|
}
|
|
@@ -6482,7 +7754,7 @@ function useVerificationService() {
|
|
|
6482
7754
|
return _id;
|
|
6483
7755
|
} catch (error) {
|
|
6484
7756
|
await session?.abortTransaction();
|
|
6485
|
-
|
|
7757
|
+
logger20.log({
|
|
6486
7758
|
level: "info",
|
|
6487
7759
|
message: `Error verifying user invitation: ${error}`
|
|
6488
7760
|
});
|
|
@@ -6495,7 +7767,7 @@ function useVerificationService() {
|
|
|
6495
7767
|
try {
|
|
6496
7768
|
await updateStatusById(id, "cancelled");
|
|
6497
7769
|
} catch (error) {
|
|
6498
|
-
throw new
|
|
7770
|
+
throw new InternalServerError20(
|
|
6499
7771
|
`Error cancelling user invitation: ${error}`
|
|
6500
7772
|
);
|
|
6501
7773
|
}
|
|
@@ -6515,7 +7787,7 @@ function useVerificationService() {
|
|
|
6515
7787
|
try {
|
|
6516
7788
|
const user = await getUserByEmail(email);
|
|
6517
7789
|
if (user) {
|
|
6518
|
-
throw new
|
|
7790
|
+
throw new BadRequestError41(
|
|
6519
7791
|
`Email ${email} is already registered, please login to continue.`
|
|
6520
7792
|
);
|
|
6521
7793
|
}
|
|
@@ -6542,7 +7814,7 @@ function useVerificationService() {
|
|
|
6542
7814
|
html: emailContent,
|
|
6543
7815
|
from: "GoWeekdays"
|
|
6544
7816
|
}).catch((error) => {
|
|
6545
|
-
|
|
7817
|
+
logger20.log({
|
|
6546
7818
|
level: "error",
|
|
6547
7819
|
message: `Error sending user invite email: ${error}`
|
|
6548
7820
|
});
|
|
@@ -6555,7 +7827,7 @@ function useVerificationService() {
|
|
|
6555
7827
|
async function inviteMember(value) {
|
|
6556
7828
|
const { error } = schemaInviteMember.validate(value);
|
|
6557
7829
|
if (error) {
|
|
6558
|
-
throw new
|
|
7830
|
+
throw new BadRequestError41(error.message);
|
|
6559
7831
|
}
|
|
6560
7832
|
const role = await getRoleById(value.role);
|
|
6561
7833
|
if (!role) {
|
|
@@ -6599,7 +7871,7 @@ function useVerificationService() {
|
|
|
6599
7871
|
html: emailContent2,
|
|
6600
7872
|
from: "GoWeekdays"
|
|
6601
7873
|
}).catch((error2) => {
|
|
6602
|
-
|
|
7874
|
+
logger20.log({
|
|
6603
7875
|
level: "error",
|
|
6604
7876
|
message: `Error sending user invite email: ${error2}`
|
|
6605
7877
|
});
|
|
@@ -6621,24 +7893,24 @@ function useVerificationService() {
|
|
|
6621
7893
|
html: emailContent,
|
|
6622
7894
|
from: "GoWeekdays"
|
|
6623
7895
|
}).catch((error2) => {
|
|
6624
|
-
|
|
7896
|
+
logger20.log({
|
|
6625
7897
|
level: "error",
|
|
6626
7898
|
message: `Error sending user invite email: ${error2}`
|
|
6627
7899
|
});
|
|
6628
7900
|
});
|
|
6629
7901
|
return verificationId;
|
|
6630
7902
|
} catch (error2) {
|
|
6631
|
-
if (error2 instanceof
|
|
7903
|
+
if (error2 instanceof AppError16) {
|
|
6632
7904
|
throw error2;
|
|
6633
7905
|
} else {
|
|
6634
|
-
throw new
|
|
7906
|
+
throw new InternalServerError20("Failed to invite member.");
|
|
6635
7907
|
}
|
|
6636
7908
|
}
|
|
6637
7909
|
}
|
|
6638
7910
|
async function cancelInviteMember(id) {
|
|
6639
|
-
const { error } =
|
|
7911
|
+
const { error } = Joi31.string().hex().required().validate(id);
|
|
6640
7912
|
if (error) {
|
|
6641
|
-
throw new
|
|
7913
|
+
throw new BadRequestError41("Invalid verification ID.");
|
|
6642
7914
|
}
|
|
6643
7915
|
try {
|
|
6644
7916
|
const invite = await _getById(id);
|
|
@@ -6646,25 +7918,25 @@ function useVerificationService() {
|
|
|
6646
7918
|
throw new NotFoundError4("Invitation not found.");
|
|
6647
7919
|
}
|
|
6648
7920
|
if (invite.status === "cancelled") {
|
|
6649
|
-
throw new
|
|
7921
|
+
throw new BadRequestError41("Invitation already cancelled.");
|
|
6650
7922
|
}
|
|
6651
7923
|
if (invite.status === "complete") {
|
|
6652
|
-
throw new
|
|
7924
|
+
throw new BadRequestError41("Cannot cancel a completed invitation.");
|
|
6653
7925
|
}
|
|
6654
7926
|
await _updateStatusById(id, "cancelled");
|
|
6655
7927
|
return "Successfully cancelled the invitation.";
|
|
6656
7928
|
} catch (error2) {
|
|
6657
|
-
if (error2 instanceof
|
|
7929
|
+
if (error2 instanceof AppError16) {
|
|
6658
7930
|
throw error2;
|
|
6659
7931
|
} else {
|
|
6660
|
-
throw new
|
|
7932
|
+
throw new InternalServerError20("Failed to cancel the invitation.");
|
|
6661
7933
|
}
|
|
6662
7934
|
}
|
|
6663
7935
|
}
|
|
6664
7936
|
async function forgetPassword(email) {
|
|
6665
|
-
const { error } =
|
|
7937
|
+
const { error } = Joi31.string().email().required().validate(email);
|
|
6666
7938
|
if (error) {
|
|
6667
|
-
throw new
|
|
7939
|
+
throw new BadRequestError41("Invalid email address.");
|
|
6668
7940
|
}
|
|
6669
7941
|
try {
|
|
6670
7942
|
const member = await getUserByEmail(email);
|
|
@@ -6693,17 +7965,17 @@ function useVerificationService() {
|
|
|
6693
7965
|
from: "GoWeekdays",
|
|
6694
7966
|
html: emailContent
|
|
6695
7967
|
}).catch((error2) => {
|
|
6696
|
-
|
|
7968
|
+
logger20.log({
|
|
6697
7969
|
level: "error",
|
|
6698
7970
|
message: `Error sending forget password email: ${error2}`
|
|
6699
7971
|
});
|
|
6700
7972
|
});
|
|
6701
7973
|
return "Successfully created a link to reset password. Please check your email.";
|
|
6702
7974
|
} catch (error2) {
|
|
6703
|
-
if (error2 instanceof
|
|
7975
|
+
if (error2 instanceof AppError16) {
|
|
6704
7976
|
throw error2;
|
|
6705
7977
|
} else {
|
|
6706
|
-
throw new
|
|
7978
|
+
throw new InternalServerError20(
|
|
6707
7979
|
"Failed to process forget password request."
|
|
6708
7980
|
);
|
|
6709
7981
|
}
|
|
@@ -6730,13 +8002,13 @@ function useAuthController() {
|
|
|
6730
8002
|
async function login(req, res, next) {
|
|
6731
8003
|
const email = req.body.email;
|
|
6732
8004
|
const password = req.body.password;
|
|
6733
|
-
const validation =
|
|
6734
|
-
email:
|
|
6735
|
-
password:
|
|
8005
|
+
const validation = Joi32.object({
|
|
8006
|
+
email: Joi32.string().email().required(),
|
|
8007
|
+
password: Joi32.string().required()
|
|
6736
8008
|
});
|
|
6737
8009
|
const { error } = validation.validate({ email, password });
|
|
6738
8010
|
if (error) {
|
|
6739
|
-
next(new
|
|
8011
|
+
next(new BadRequestError42(error.message));
|
|
6740
8012
|
return;
|
|
6741
8013
|
}
|
|
6742
8014
|
try {
|
|
@@ -6752,14 +8024,14 @@ function useAuthController() {
|
|
|
6752
8024
|
res.cookie("sid", session.sid, cookieOptions).cookie("user", session.user, cookieOptions).json({ message: "Login successful" });
|
|
6753
8025
|
return;
|
|
6754
8026
|
} catch (error2) {
|
|
6755
|
-
|
|
8027
|
+
logger21.log({
|
|
6756
8028
|
level: "error",
|
|
6757
8029
|
message: `Error during login: ${error2.message}`
|
|
6758
8030
|
});
|
|
6759
|
-
if (error2 instanceof
|
|
8031
|
+
if (error2 instanceof AppError17) {
|
|
6760
8032
|
next(error2);
|
|
6761
8033
|
} else {
|
|
6762
|
-
next(new
|
|
8034
|
+
next(new InternalServerError21("An unexpected error occurred"));
|
|
6763
8035
|
}
|
|
6764
8036
|
return;
|
|
6765
8037
|
}
|
|
@@ -6767,17 +8039,17 @@ function useAuthController() {
|
|
|
6767
8039
|
async function logout(req, res, next) {
|
|
6768
8040
|
const sid = req.headers["authorization"] ?? "";
|
|
6769
8041
|
if (!sid) {
|
|
6770
|
-
next(new
|
|
8042
|
+
next(new BadRequestError42("Session ID is required"));
|
|
6771
8043
|
return;
|
|
6772
8044
|
}
|
|
6773
8045
|
try {
|
|
6774
8046
|
await useAuthService().logout(sid);
|
|
6775
8047
|
res.json({ message: "Logged out successfully" });
|
|
6776
8048
|
} catch (error) {
|
|
6777
|
-
if (error instanceof
|
|
8049
|
+
if (error instanceof AppError17) {
|
|
6778
8050
|
next(error);
|
|
6779
8051
|
} else {
|
|
6780
|
-
next(new
|
|
8052
|
+
next(new InternalServerError21("An unexpected error occurred"));
|
|
6781
8053
|
}
|
|
6782
8054
|
}
|
|
6783
8055
|
}
|
|
@@ -6788,64 +8060,64 @@ function useAuthController() {
|
|
|
6788
8060
|
}
|
|
6789
8061
|
|
|
6790
8062
|
// src/resources/building/building.model.ts
|
|
6791
|
-
import { BadRequestError as
|
|
6792
|
-
import
|
|
6793
|
-
import { ObjectId as
|
|
6794
|
-
var schemaBuilding =
|
|
6795
|
-
_id:
|
|
6796
|
-
school:
|
|
6797
|
-
serial:
|
|
6798
|
-
name:
|
|
6799
|
-
levels:
|
|
6800
|
-
createdAt:
|
|
6801
|
-
updatedAt:
|
|
6802
|
-
deletedAt:
|
|
6803
|
-
status:
|
|
8063
|
+
import { BadRequestError as BadRequestError43, logger as logger22 } from "@goweekdays/utils";
|
|
8064
|
+
import Joi33 from "joi";
|
|
8065
|
+
import { ObjectId as ObjectId22 } from "mongodb";
|
|
8066
|
+
var schemaBuilding = Joi33.object({
|
|
8067
|
+
_id: Joi33.string().hex().optional(),
|
|
8068
|
+
school: Joi33.string().hex().required(),
|
|
8069
|
+
serial: Joi33.string().optional().allow("", null),
|
|
8070
|
+
name: Joi33.string().required(),
|
|
8071
|
+
levels: Joi33.number().integer().min(1).required(),
|
|
8072
|
+
createdAt: Joi33.date().optional().allow("", null),
|
|
8073
|
+
updatedAt: Joi33.date().optional().allow("", null),
|
|
8074
|
+
deletedAt: Joi33.date().optional().allow("", null),
|
|
8075
|
+
status: Joi33.string().optional().allow("", null)
|
|
6804
8076
|
});
|
|
6805
|
-
var schemaBuildingUnit =
|
|
6806
|
-
_id:
|
|
6807
|
-
school:
|
|
6808
|
-
name:
|
|
6809
|
-
building:
|
|
6810
|
-
buildingName:
|
|
6811
|
-
level:
|
|
6812
|
-
category:
|
|
6813
|
-
type:
|
|
6814
|
-
seating_capacity:
|
|
6815
|
-
standing_capacity:
|
|
6816
|
-
description:
|
|
6817
|
-
unit_of_measurement:
|
|
6818
|
-
area:
|
|
6819
|
-
status:
|
|
8077
|
+
var schemaBuildingUnit = Joi33.object({
|
|
8078
|
+
_id: Joi33.string().hex().optional(),
|
|
8079
|
+
school: Joi33.string().hex().required(),
|
|
8080
|
+
name: Joi33.string().optional().allow("", null),
|
|
8081
|
+
building: Joi33.string().hex().required(),
|
|
8082
|
+
buildingName: Joi33.string().optional().allow("", null),
|
|
8083
|
+
level: Joi33.number().integer().min(1).required(),
|
|
8084
|
+
category: Joi33.string().required(),
|
|
8085
|
+
type: Joi33.string().required(),
|
|
8086
|
+
seating_capacity: Joi33.number().integer().min(0).required(),
|
|
8087
|
+
standing_capacity: Joi33.number().integer().min(0).required(),
|
|
8088
|
+
description: Joi33.string().optional().allow("", null),
|
|
8089
|
+
unit_of_measurement: Joi33.string().valid("sqm").required(),
|
|
8090
|
+
area: Joi33.number().positive().required(),
|
|
8091
|
+
status: Joi33.string().optional().allow("", null)
|
|
6820
8092
|
});
|
|
6821
|
-
var schemaUpdateOptions =
|
|
6822
|
-
name:
|
|
6823
|
-
building:
|
|
6824
|
-
buildingName:
|
|
6825
|
-
level:
|
|
6826
|
-
category:
|
|
6827
|
-
type:
|
|
6828
|
-
seating_capacity:
|
|
6829
|
-
standing_capacity:
|
|
6830
|
-
area:
|
|
8093
|
+
var schemaUpdateOptions = Joi33.object({
|
|
8094
|
+
name: Joi33.string().optional().allow("", null),
|
|
8095
|
+
building: Joi33.string().hex().optional().allow("", null),
|
|
8096
|
+
buildingName: Joi33.string().optional().allow("", null),
|
|
8097
|
+
level: Joi33.number().integer().min(1).optional().allow("", null),
|
|
8098
|
+
category: Joi33.string().optional().allow("", null),
|
|
8099
|
+
type: Joi33.string().optional().allow("", null),
|
|
8100
|
+
seating_capacity: Joi33.number().integer().min(0).optional().allow("", null),
|
|
8101
|
+
standing_capacity: Joi33.number().integer().min(0).optional().allow("", null),
|
|
8102
|
+
area: Joi33.number().positive().optional().allow("", null)
|
|
6831
8103
|
});
|
|
6832
8104
|
function MBuilding(value) {
|
|
6833
8105
|
const { error } = schemaBuilding.validate(value);
|
|
6834
8106
|
if (error) {
|
|
6835
|
-
|
|
6836
|
-
throw new
|
|
8107
|
+
logger22.info(`Building Model: ${error.message}`);
|
|
8108
|
+
throw new BadRequestError43(error.message);
|
|
6837
8109
|
}
|
|
6838
8110
|
if (value._id && typeof value._id === "string") {
|
|
6839
8111
|
try {
|
|
6840
|
-
value._id = new
|
|
8112
|
+
value._id = new ObjectId22(value._id);
|
|
6841
8113
|
} catch (error2) {
|
|
6842
|
-
throw new
|
|
8114
|
+
throw new BadRequestError43("Invalid _id format");
|
|
6843
8115
|
}
|
|
6844
8116
|
}
|
|
6845
8117
|
try {
|
|
6846
|
-
value.school = new
|
|
8118
|
+
value.school = new ObjectId22(value.school);
|
|
6847
8119
|
} catch (error2) {
|
|
6848
|
-
throw new
|
|
8120
|
+
throw new BadRequestError43("Invalid school format");
|
|
6849
8121
|
}
|
|
6850
8122
|
return {
|
|
6851
8123
|
_id: value._id ?? void 0,
|
|
@@ -6862,25 +8134,25 @@ function MBuilding(value) {
|
|
|
6862
8134
|
function MBuildingUnit(value) {
|
|
6863
8135
|
const { error } = schemaBuildingUnit.validate(value);
|
|
6864
8136
|
if (error) {
|
|
6865
|
-
|
|
6866
|
-
throw new
|
|
8137
|
+
logger22.info(`Building Unit Model: ${error.message}`);
|
|
8138
|
+
throw new BadRequestError43(error.message);
|
|
6867
8139
|
}
|
|
6868
8140
|
if (value._id && typeof value._id === "string") {
|
|
6869
8141
|
try {
|
|
6870
|
-
value._id = new
|
|
8142
|
+
value._id = new ObjectId22(value._id);
|
|
6871
8143
|
} catch (error2) {
|
|
6872
|
-
throw new
|
|
8144
|
+
throw new BadRequestError43("Invalid ID");
|
|
6873
8145
|
}
|
|
6874
8146
|
}
|
|
6875
8147
|
try {
|
|
6876
|
-
value.school = new
|
|
8148
|
+
value.school = new ObjectId22(value.school);
|
|
6877
8149
|
} catch (error2) {
|
|
6878
|
-
throw new
|
|
8150
|
+
throw new BadRequestError43("Invalid school ID");
|
|
6879
8151
|
}
|
|
6880
8152
|
try {
|
|
6881
|
-
value.building = new
|
|
8153
|
+
value.building = new ObjectId22(value.building);
|
|
6882
8154
|
} catch (error2) {
|
|
6883
|
-
throw new
|
|
8155
|
+
throw new BadRequestError43("Invalid building ID");
|
|
6884
8156
|
}
|
|
6885
8157
|
return {
|
|
6886
8158
|
_id: value._id ?? void 0,
|
|
@@ -6905,24 +8177,24 @@ function MBuildingUnit(value) {
|
|
|
6905
8177
|
|
|
6906
8178
|
// src/resources/building/building.repository.ts
|
|
6907
8179
|
import {
|
|
6908
|
-
AppError as
|
|
6909
|
-
BadRequestError as
|
|
6910
|
-
InternalServerError as
|
|
6911
|
-
logger as
|
|
6912
|
-
makeCacheKey as
|
|
6913
|
-
paginate as
|
|
6914
|
-
useAtlas as
|
|
6915
|
-
useCache as
|
|
8180
|
+
AppError as AppError18,
|
|
8181
|
+
BadRequestError as BadRequestError44,
|
|
8182
|
+
InternalServerError as InternalServerError22,
|
|
8183
|
+
logger as logger23,
|
|
8184
|
+
makeCacheKey as makeCacheKey15,
|
|
8185
|
+
paginate as paginate12,
|
|
8186
|
+
useAtlas as useAtlas20,
|
|
8187
|
+
useCache as useCache16
|
|
6916
8188
|
} from "@goweekdays/utils";
|
|
6917
|
-
import { ObjectId as
|
|
8189
|
+
import { ObjectId as ObjectId23 } from "mongodb";
|
|
6918
8190
|
function useBuildingRepo() {
|
|
6919
|
-
const db =
|
|
8191
|
+
const db = useAtlas20.getDb();
|
|
6920
8192
|
if (!db) {
|
|
6921
8193
|
throw new Error("Unable to connect to server.");
|
|
6922
8194
|
}
|
|
6923
8195
|
const namespace_collection = "school.buildings";
|
|
6924
8196
|
const collection = db.collection(namespace_collection);
|
|
6925
|
-
const { getCache, setCache, delNamespace } =
|
|
8197
|
+
const { getCache, setCache, delNamespace } = useCache16(namespace_collection);
|
|
6926
8198
|
async function createIndexes() {
|
|
6927
8199
|
try {
|
|
6928
8200
|
await collection.createIndexes([
|
|
@@ -6935,7 +8207,7 @@ function useBuildingRepo() {
|
|
|
6935
8207
|
}
|
|
6936
8208
|
}
|
|
6937
8209
|
createIndexes().catch((error) => {
|
|
6938
|
-
|
|
8210
|
+
logger23.log({ level: "error", message: `Index creation error: ${error}` });
|
|
6939
8211
|
});
|
|
6940
8212
|
async function add(value, session) {
|
|
6941
8213
|
try {
|
|
@@ -6944,16 +8216,16 @@ function useBuildingRepo() {
|
|
|
6944
8216
|
delCachedData();
|
|
6945
8217
|
return res.insertedId;
|
|
6946
8218
|
} catch (error) {
|
|
6947
|
-
|
|
8219
|
+
logger23.log({
|
|
6948
8220
|
level: "error",
|
|
6949
8221
|
message: error.message
|
|
6950
8222
|
});
|
|
6951
|
-
if (error instanceof
|
|
8223
|
+
if (error instanceof AppError18) {
|
|
6952
8224
|
throw error;
|
|
6953
8225
|
} else {
|
|
6954
8226
|
const isDuplicated = error.message.includes("duplicate");
|
|
6955
8227
|
if (isDuplicated) {
|
|
6956
|
-
throw new
|
|
8228
|
+
throw new BadRequestError44("Building already exists.");
|
|
6957
8229
|
}
|
|
6958
8230
|
throw new Error("Failed to create building.");
|
|
6959
8231
|
}
|
|
@@ -6961,9 +8233,9 @@ function useBuildingRepo() {
|
|
|
6961
8233
|
}
|
|
6962
8234
|
async function updateById(_id, value, session) {
|
|
6963
8235
|
try {
|
|
6964
|
-
_id = new
|
|
8236
|
+
_id = new ObjectId23(_id);
|
|
6965
8237
|
} catch (error) {
|
|
6966
|
-
throw new
|
|
8238
|
+
throw new BadRequestError44("Invalid ID.");
|
|
6967
8239
|
}
|
|
6968
8240
|
try {
|
|
6969
8241
|
const res = await collection.updateOne(
|
|
@@ -6974,11 +8246,11 @@ function useBuildingRepo() {
|
|
|
6974
8246
|
delCachedData();
|
|
6975
8247
|
return res;
|
|
6976
8248
|
} catch (error) {
|
|
6977
|
-
|
|
8249
|
+
logger23.log({
|
|
6978
8250
|
level: "error",
|
|
6979
8251
|
message: error.message
|
|
6980
8252
|
});
|
|
6981
|
-
if (error instanceof
|
|
8253
|
+
if (error instanceof AppError18) {
|
|
6982
8254
|
throw error;
|
|
6983
8255
|
} else {
|
|
6984
8256
|
throw new Error("Failed to update building.");
|
|
@@ -7003,9 +8275,9 @@ function useBuildingRepo() {
|
|
|
7003
8275
|
}
|
|
7004
8276
|
if (school) {
|
|
7005
8277
|
try {
|
|
7006
|
-
query.school = new
|
|
8278
|
+
query.school = new ObjectId23(school);
|
|
7007
8279
|
} catch (error) {
|
|
7008
|
-
throw new
|
|
8280
|
+
throw new BadRequestError44("Invalid school ID.");
|
|
7009
8281
|
}
|
|
7010
8282
|
}
|
|
7011
8283
|
const cacheParams = {
|
|
@@ -7019,15 +8291,15 @@ function useBuildingRepo() {
|
|
|
7019
8291
|
cacheParams.school = school;
|
|
7020
8292
|
if (status !== "active")
|
|
7021
8293
|
cacheParams.status = status;
|
|
7022
|
-
const cacheKey =
|
|
7023
|
-
|
|
8294
|
+
const cacheKey = makeCacheKey15(namespace_collection, cacheParams);
|
|
8295
|
+
logger23.log({
|
|
7024
8296
|
level: "info",
|
|
7025
8297
|
message: `Cache key for getAll buildings: ${cacheKey}`
|
|
7026
8298
|
});
|
|
7027
8299
|
try {
|
|
7028
8300
|
const cached = await getCache(cacheKey);
|
|
7029
8301
|
if (cached) {
|
|
7030
|
-
|
|
8302
|
+
logger23.log({
|
|
7031
8303
|
level: "info",
|
|
7032
8304
|
message: `Cache hit for getAll buildings: ${cacheKey}`
|
|
7033
8305
|
});
|
|
@@ -7040,35 +8312,35 @@ function useBuildingRepo() {
|
|
|
7040
8312
|
{ $limit: limit }
|
|
7041
8313
|
]).toArray();
|
|
7042
8314
|
const length = await collection.countDocuments(query);
|
|
7043
|
-
const data =
|
|
8315
|
+
const data = paginate12(items, page, limit, length);
|
|
7044
8316
|
setCache(cacheKey, data, 600).then(() => {
|
|
7045
|
-
|
|
8317
|
+
logger23.log({
|
|
7046
8318
|
level: "info",
|
|
7047
8319
|
message: `Cache set for getAll buildings: ${cacheKey}`
|
|
7048
8320
|
});
|
|
7049
8321
|
}).catch((err) => {
|
|
7050
|
-
|
|
8322
|
+
logger23.log({
|
|
7051
8323
|
level: "error",
|
|
7052
8324
|
message: `Failed to set cache for getAll buildings: ${err.message}`
|
|
7053
8325
|
});
|
|
7054
8326
|
});
|
|
7055
8327
|
return data;
|
|
7056
8328
|
} catch (error) {
|
|
7057
|
-
|
|
8329
|
+
logger23.log({ level: "error", message: `${error}` });
|
|
7058
8330
|
throw error;
|
|
7059
8331
|
}
|
|
7060
8332
|
}
|
|
7061
8333
|
async function getById(_id) {
|
|
7062
8334
|
try {
|
|
7063
|
-
_id = new
|
|
8335
|
+
_id = new ObjectId23(_id);
|
|
7064
8336
|
} catch (error) {
|
|
7065
|
-
throw new
|
|
8337
|
+
throw new BadRequestError44("Invalid ID.");
|
|
7066
8338
|
}
|
|
7067
|
-
const cacheKey =
|
|
8339
|
+
const cacheKey = makeCacheKey15(namespace_collection, { _id: String(_id) });
|
|
7068
8340
|
try {
|
|
7069
8341
|
const cached = await getCache(cacheKey);
|
|
7070
8342
|
if (cached) {
|
|
7071
|
-
|
|
8343
|
+
logger23.log({
|
|
7072
8344
|
level: "info",
|
|
7073
8345
|
message: `Cache hit for getById building: ${cacheKey}`
|
|
7074
8346
|
});
|
|
@@ -7078,30 +8350,30 @@ function useBuildingRepo() {
|
|
|
7078
8350
|
_id
|
|
7079
8351
|
});
|
|
7080
8352
|
setCache(cacheKey, result, 300).then(() => {
|
|
7081
|
-
|
|
8353
|
+
logger23.log({
|
|
7082
8354
|
level: "info",
|
|
7083
8355
|
message: `Cache set for building by id: ${cacheKey}`
|
|
7084
8356
|
});
|
|
7085
8357
|
}).catch((err) => {
|
|
7086
|
-
|
|
8358
|
+
logger23.log({
|
|
7087
8359
|
level: "error",
|
|
7088
8360
|
message: `Failed to set cache for building by id: ${err.message}`
|
|
7089
8361
|
});
|
|
7090
8362
|
});
|
|
7091
8363
|
return result;
|
|
7092
8364
|
} catch (error) {
|
|
7093
|
-
if (error instanceof
|
|
8365
|
+
if (error instanceof AppError18) {
|
|
7094
8366
|
throw error;
|
|
7095
8367
|
} else {
|
|
7096
|
-
throw new
|
|
8368
|
+
throw new InternalServerError22("Failed to get building.");
|
|
7097
8369
|
}
|
|
7098
8370
|
}
|
|
7099
8371
|
}
|
|
7100
8372
|
async function deleteById(_id, session) {
|
|
7101
8373
|
try {
|
|
7102
|
-
_id = new
|
|
8374
|
+
_id = new ObjectId23(_id);
|
|
7103
8375
|
} catch (error) {
|
|
7104
|
-
throw new
|
|
8376
|
+
throw new BadRequestError44("Invalid ID.");
|
|
7105
8377
|
}
|
|
7106
8378
|
try {
|
|
7107
8379
|
const res = await collection.updateOne(
|
|
@@ -7111,25 +8383,25 @@ function useBuildingRepo() {
|
|
|
7111
8383
|
delCachedData();
|
|
7112
8384
|
return res;
|
|
7113
8385
|
} catch (error) {
|
|
7114
|
-
|
|
8386
|
+
logger23.log({
|
|
7115
8387
|
level: "error",
|
|
7116
8388
|
message: error.message
|
|
7117
8389
|
});
|
|
7118
|
-
if (error instanceof
|
|
8390
|
+
if (error instanceof AppError18) {
|
|
7119
8391
|
throw error;
|
|
7120
8392
|
} else {
|
|
7121
|
-
throw new
|
|
8393
|
+
throw new InternalServerError22("Failed to delete building.");
|
|
7122
8394
|
}
|
|
7123
8395
|
}
|
|
7124
8396
|
}
|
|
7125
8397
|
function delCachedData() {
|
|
7126
8398
|
delNamespace().then(() => {
|
|
7127
|
-
|
|
8399
|
+
logger23.log({
|
|
7128
8400
|
level: "info",
|
|
7129
8401
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
7130
8402
|
});
|
|
7131
8403
|
}).catch((err) => {
|
|
7132
|
-
|
|
8404
|
+
logger23.log({
|
|
7133
8405
|
level: "error",
|
|
7134
8406
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
7135
8407
|
});
|
|
@@ -7146,28 +8418,28 @@ function useBuildingRepo() {
|
|
|
7146
8418
|
}
|
|
7147
8419
|
|
|
7148
8420
|
// src/resources/building/building.service.ts
|
|
7149
|
-
import { BadRequestError as
|
|
8421
|
+
import { BadRequestError as BadRequestError46, NotFoundError as NotFoundError5, useAtlas as useAtlas22 } from "@goweekdays/utils";
|
|
7150
8422
|
|
|
7151
8423
|
// src/resources/building/building-unit.repository.ts
|
|
7152
8424
|
import {
|
|
7153
|
-
AppError as
|
|
7154
|
-
BadRequestError as
|
|
7155
|
-
InternalServerError as
|
|
7156
|
-
logger as
|
|
7157
|
-
makeCacheKey as
|
|
7158
|
-
paginate as
|
|
7159
|
-
useAtlas as
|
|
7160
|
-
useCache as
|
|
8425
|
+
AppError as AppError19,
|
|
8426
|
+
BadRequestError as BadRequestError45,
|
|
8427
|
+
InternalServerError as InternalServerError23,
|
|
8428
|
+
logger as logger24,
|
|
8429
|
+
makeCacheKey as makeCacheKey16,
|
|
8430
|
+
paginate as paginate13,
|
|
8431
|
+
useAtlas as useAtlas21,
|
|
8432
|
+
useCache as useCache17
|
|
7161
8433
|
} from "@goweekdays/utils";
|
|
7162
|
-
import { ObjectId as
|
|
8434
|
+
import { ObjectId as ObjectId24 } from "mongodb";
|
|
7163
8435
|
function useBuildingUnitRepo() {
|
|
7164
|
-
const db =
|
|
8436
|
+
const db = useAtlas21.getDb();
|
|
7165
8437
|
if (!db) {
|
|
7166
8438
|
throw new Error("Unable to connect to server.");
|
|
7167
8439
|
}
|
|
7168
8440
|
const namespace_collection = "school.building-units";
|
|
7169
8441
|
const collection = db.collection(namespace_collection);
|
|
7170
|
-
const { getCache, setCache, delNamespace } =
|
|
8442
|
+
const { getCache, setCache, delNamespace } = useCache17(namespace_collection);
|
|
7171
8443
|
async function createIndexes() {
|
|
7172
8444
|
try {
|
|
7173
8445
|
await collection.createIndexes([
|
|
@@ -7195,12 +8467,12 @@ function useBuildingUnitRepo() {
|
|
|
7195
8467
|
}
|
|
7196
8468
|
function delCachedData() {
|
|
7197
8469
|
delNamespace().then(() => {
|
|
7198
|
-
|
|
8470
|
+
logger24.log({
|
|
7199
8471
|
level: "info",
|
|
7200
8472
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
7201
8473
|
});
|
|
7202
8474
|
}).catch((err) => {
|
|
7203
|
-
|
|
8475
|
+
logger24.log({
|
|
7204
8476
|
level: "error",
|
|
7205
8477
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
7206
8478
|
});
|
|
@@ -7213,11 +8485,11 @@ function useBuildingUnitRepo() {
|
|
|
7213
8485
|
delCachedData();
|
|
7214
8486
|
return res.insertedId;
|
|
7215
8487
|
} catch (error) {
|
|
7216
|
-
|
|
8488
|
+
logger24.log({
|
|
7217
8489
|
level: "error",
|
|
7218
8490
|
message: error.message
|
|
7219
8491
|
});
|
|
7220
|
-
if (error instanceof
|
|
8492
|
+
if (error instanceof AppError19) {
|
|
7221
8493
|
throw error;
|
|
7222
8494
|
} else {
|
|
7223
8495
|
throw new Error("Failed to create building unit.");
|
|
@@ -7227,12 +8499,12 @@ function useBuildingUnitRepo() {
|
|
|
7227
8499
|
async function updateById(_id, value, session) {
|
|
7228
8500
|
const { error } = schemaUpdateOptions.validate(value);
|
|
7229
8501
|
if (error) {
|
|
7230
|
-
throw new
|
|
8502
|
+
throw new BadRequestError45(error.message);
|
|
7231
8503
|
}
|
|
7232
8504
|
try {
|
|
7233
|
-
_id = new
|
|
8505
|
+
_id = new ObjectId24(_id);
|
|
7234
8506
|
} catch (error2) {
|
|
7235
|
-
throw new
|
|
8507
|
+
throw new BadRequestError45("Invalid ID.");
|
|
7236
8508
|
}
|
|
7237
8509
|
try {
|
|
7238
8510
|
const res = await collection.updateOne(
|
|
@@ -7243,11 +8515,11 @@ function useBuildingUnitRepo() {
|
|
|
7243
8515
|
delCachedData();
|
|
7244
8516
|
return res;
|
|
7245
8517
|
} catch (error2) {
|
|
7246
|
-
|
|
8518
|
+
logger24.log({
|
|
7247
8519
|
level: "error",
|
|
7248
8520
|
message: error2.message
|
|
7249
8521
|
});
|
|
7250
|
-
if (error2 instanceof
|
|
8522
|
+
if (error2 instanceof AppError19) {
|
|
7251
8523
|
throw error2;
|
|
7252
8524
|
} else {
|
|
7253
8525
|
throw new Error("Failed to create building unit.");
|
|
@@ -7257,12 +8529,12 @@ function useBuildingUnitRepo() {
|
|
|
7257
8529
|
async function updateByBuildingId(building, value, session) {
|
|
7258
8530
|
const { error } = schemaUpdateOptions.validate(value);
|
|
7259
8531
|
if (error) {
|
|
7260
|
-
throw new
|
|
8532
|
+
throw new BadRequestError45(error.message);
|
|
7261
8533
|
}
|
|
7262
8534
|
try {
|
|
7263
|
-
building = new
|
|
8535
|
+
building = new ObjectId24(building);
|
|
7264
8536
|
} catch (error2) {
|
|
7265
|
-
throw new
|
|
8537
|
+
throw new BadRequestError45("Invalid building ID.");
|
|
7266
8538
|
}
|
|
7267
8539
|
try {
|
|
7268
8540
|
const res = await collection.updateMany(
|
|
@@ -7273,11 +8545,11 @@ function useBuildingUnitRepo() {
|
|
|
7273
8545
|
delCachedData();
|
|
7274
8546
|
return res;
|
|
7275
8547
|
} catch (error2) {
|
|
7276
|
-
|
|
8548
|
+
logger24.log({
|
|
7277
8549
|
level: "error",
|
|
7278
8550
|
message: error2.message
|
|
7279
8551
|
});
|
|
7280
|
-
if (error2 instanceof
|
|
8552
|
+
if (error2 instanceof AppError19) {
|
|
7281
8553
|
throw error2;
|
|
7282
8554
|
} else {
|
|
7283
8555
|
throw new Error("Failed to update building unit.");
|
|
@@ -7304,16 +8576,16 @@ function useBuildingUnitRepo() {
|
|
|
7304
8576
|
}
|
|
7305
8577
|
if (school) {
|
|
7306
8578
|
try {
|
|
7307
|
-
query.school = new
|
|
8579
|
+
query.school = new ObjectId24(school);
|
|
7308
8580
|
} catch (error) {
|
|
7309
|
-
throw new
|
|
8581
|
+
throw new BadRequestError45("Invalid school ID.");
|
|
7310
8582
|
}
|
|
7311
8583
|
}
|
|
7312
8584
|
if (building) {
|
|
7313
8585
|
try {
|
|
7314
|
-
query.building = new
|
|
8586
|
+
query.building = new ObjectId24(building);
|
|
7315
8587
|
} catch (error) {
|
|
7316
|
-
throw new
|
|
8588
|
+
throw new BadRequestError45("Invalid building ID.");
|
|
7317
8589
|
}
|
|
7318
8590
|
}
|
|
7319
8591
|
const cacheParams = {
|
|
@@ -7329,15 +8601,15 @@ function useBuildingUnitRepo() {
|
|
|
7329
8601
|
cacheParams.building = building;
|
|
7330
8602
|
if (status !== "active")
|
|
7331
8603
|
cacheParams.status = status;
|
|
7332
|
-
const cacheKey =
|
|
7333
|
-
|
|
8604
|
+
const cacheKey = makeCacheKey16(namespace_collection, cacheParams);
|
|
8605
|
+
logger24.log({
|
|
7334
8606
|
level: "info",
|
|
7335
8607
|
message: `Cache key for getAll building units: ${cacheKey}`
|
|
7336
8608
|
});
|
|
7337
8609
|
try {
|
|
7338
8610
|
const cached = await getCache(cacheKey);
|
|
7339
8611
|
if (cached) {
|
|
7340
|
-
|
|
8612
|
+
logger24.log({
|
|
7341
8613
|
level: "info",
|
|
7342
8614
|
message: `Cache hit for getAll building units: ${cacheKey}`
|
|
7343
8615
|
});
|
|
@@ -7350,35 +8622,35 @@ function useBuildingUnitRepo() {
|
|
|
7350
8622
|
{ $limit: limit }
|
|
7351
8623
|
]).toArray();
|
|
7352
8624
|
const length = await collection.countDocuments(query);
|
|
7353
|
-
const data =
|
|
8625
|
+
const data = paginate13(items, page, limit, length);
|
|
7354
8626
|
setCache(cacheKey, data, 600).then(() => {
|
|
7355
|
-
|
|
8627
|
+
logger24.log({
|
|
7356
8628
|
level: "info",
|
|
7357
8629
|
message: `Cache set for getAll building units: ${cacheKey}`
|
|
7358
8630
|
});
|
|
7359
8631
|
}).catch((err) => {
|
|
7360
|
-
|
|
8632
|
+
logger24.log({
|
|
7361
8633
|
level: "error",
|
|
7362
8634
|
message: `Failed to set cache for getAll building units: ${err.message}`
|
|
7363
8635
|
});
|
|
7364
8636
|
});
|
|
7365
8637
|
return data;
|
|
7366
8638
|
} catch (error) {
|
|
7367
|
-
|
|
8639
|
+
logger24.log({ level: "error", message: `${error}` });
|
|
7368
8640
|
throw error;
|
|
7369
8641
|
}
|
|
7370
8642
|
}
|
|
7371
8643
|
async function getById(_id) {
|
|
7372
8644
|
try {
|
|
7373
|
-
_id = new
|
|
8645
|
+
_id = new ObjectId24(_id);
|
|
7374
8646
|
} catch (error) {
|
|
7375
|
-
throw new
|
|
8647
|
+
throw new BadRequestError45("Invalid ID.");
|
|
7376
8648
|
}
|
|
7377
|
-
const cacheKey =
|
|
8649
|
+
const cacheKey = makeCacheKey16(namespace_collection, { _id: String(_id) });
|
|
7378
8650
|
try {
|
|
7379
8651
|
const cached = await getCache(cacheKey);
|
|
7380
8652
|
if (cached) {
|
|
7381
|
-
|
|
8653
|
+
logger24.log({
|
|
7382
8654
|
level: "info",
|
|
7383
8655
|
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
7384
8656
|
});
|
|
@@ -7389,42 +8661,42 @@ function useBuildingUnitRepo() {
|
|
|
7389
8661
|
deletedAt: { $in: ["", null] }
|
|
7390
8662
|
});
|
|
7391
8663
|
if (!result) {
|
|
7392
|
-
throw new
|
|
8664
|
+
throw new BadRequestError45("Building unit not found.");
|
|
7393
8665
|
}
|
|
7394
8666
|
setCache(cacheKey, result, 300).then(() => {
|
|
7395
|
-
|
|
8667
|
+
logger24.log({
|
|
7396
8668
|
level: "info",
|
|
7397
8669
|
message: `Cache set for building unit by id: ${cacheKey}`
|
|
7398
8670
|
});
|
|
7399
8671
|
}).catch((err) => {
|
|
7400
|
-
|
|
8672
|
+
logger24.log({
|
|
7401
8673
|
level: "error",
|
|
7402
8674
|
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
7403
8675
|
});
|
|
7404
8676
|
});
|
|
7405
8677
|
return result;
|
|
7406
8678
|
} catch (error) {
|
|
7407
|
-
if (error instanceof
|
|
8679
|
+
if (error instanceof AppError19) {
|
|
7408
8680
|
throw error;
|
|
7409
8681
|
} else {
|
|
7410
|
-
throw new
|
|
8682
|
+
throw new InternalServerError23("Failed to get building unit.");
|
|
7411
8683
|
}
|
|
7412
8684
|
}
|
|
7413
8685
|
}
|
|
7414
8686
|
async function getByBuildingLevel(building, level) {
|
|
7415
8687
|
try {
|
|
7416
|
-
building = new
|
|
8688
|
+
building = new ObjectId24(building);
|
|
7417
8689
|
} catch (error) {
|
|
7418
|
-
throw new
|
|
8690
|
+
throw new BadRequestError45("Invalid building ID.");
|
|
7419
8691
|
}
|
|
7420
|
-
const cacheKey =
|
|
8692
|
+
const cacheKey = makeCacheKey16(namespace_collection, {
|
|
7421
8693
|
building: String(building),
|
|
7422
8694
|
level
|
|
7423
8695
|
});
|
|
7424
8696
|
try {
|
|
7425
8697
|
const cached = await getCache(cacheKey);
|
|
7426
8698
|
if (cached) {
|
|
7427
|
-
|
|
8699
|
+
logger24.log({
|
|
7428
8700
|
level: "info",
|
|
7429
8701
|
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
7430
8702
|
});
|
|
@@ -7436,38 +8708,38 @@ function useBuildingUnitRepo() {
|
|
|
7436
8708
|
status: "active"
|
|
7437
8709
|
});
|
|
7438
8710
|
setCache(cacheKey, result, 300).then(() => {
|
|
7439
|
-
|
|
8711
|
+
logger24.log({
|
|
7440
8712
|
level: "info",
|
|
7441
8713
|
message: `Cache set for building unit by id: ${cacheKey}`
|
|
7442
8714
|
});
|
|
7443
8715
|
}).catch((err) => {
|
|
7444
|
-
|
|
8716
|
+
logger24.log({
|
|
7445
8717
|
level: "error",
|
|
7446
8718
|
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
7447
8719
|
});
|
|
7448
8720
|
});
|
|
7449
8721
|
return result;
|
|
7450
8722
|
} catch (error) {
|
|
7451
|
-
if (error instanceof
|
|
8723
|
+
if (error instanceof AppError19) {
|
|
7452
8724
|
throw error;
|
|
7453
8725
|
} else {
|
|
7454
|
-
throw new
|
|
8726
|
+
throw new InternalServerError23("Failed to get building unit.");
|
|
7455
8727
|
}
|
|
7456
8728
|
}
|
|
7457
8729
|
}
|
|
7458
8730
|
async function getByBuilding(building) {
|
|
7459
8731
|
try {
|
|
7460
|
-
building = new
|
|
8732
|
+
building = new ObjectId24(building);
|
|
7461
8733
|
} catch (error) {
|
|
7462
|
-
throw new
|
|
8734
|
+
throw new BadRequestError45("Invalid building ID.");
|
|
7463
8735
|
}
|
|
7464
|
-
const cacheKey =
|
|
8736
|
+
const cacheKey = makeCacheKey16(namespace_collection, {
|
|
7465
8737
|
building: String(building)
|
|
7466
8738
|
});
|
|
7467
8739
|
try {
|
|
7468
8740
|
const cached = await getCache(cacheKey);
|
|
7469
8741
|
if (cached) {
|
|
7470
|
-
|
|
8742
|
+
logger24.log({
|
|
7471
8743
|
level: "info",
|
|
7472
8744
|
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
7473
8745
|
});
|
|
@@ -7478,30 +8750,30 @@ function useBuildingUnitRepo() {
|
|
|
7478
8750
|
status: "active"
|
|
7479
8751
|
});
|
|
7480
8752
|
setCache(cacheKey, result, 300).then(() => {
|
|
7481
|
-
|
|
8753
|
+
logger24.log({
|
|
7482
8754
|
level: "info",
|
|
7483
8755
|
message: `Cache set for building unit by id: ${cacheKey}`
|
|
7484
8756
|
});
|
|
7485
8757
|
}).catch((err) => {
|
|
7486
|
-
|
|
8758
|
+
logger24.log({
|
|
7487
8759
|
level: "error",
|
|
7488
8760
|
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
7489
8761
|
});
|
|
7490
8762
|
});
|
|
7491
8763
|
return result;
|
|
7492
8764
|
} catch (error) {
|
|
7493
|
-
if (error instanceof
|
|
8765
|
+
if (error instanceof AppError19) {
|
|
7494
8766
|
throw error;
|
|
7495
8767
|
} else {
|
|
7496
|
-
throw new
|
|
8768
|
+
throw new InternalServerError23("Failed to get building unit.");
|
|
7497
8769
|
}
|
|
7498
8770
|
}
|
|
7499
8771
|
}
|
|
7500
8772
|
async function deleteById(_id, session) {
|
|
7501
8773
|
try {
|
|
7502
|
-
_id = new
|
|
8774
|
+
_id = new ObjectId24(_id);
|
|
7503
8775
|
} catch (error) {
|
|
7504
|
-
throw new
|
|
8776
|
+
throw new BadRequestError45("Invalid ID.");
|
|
7505
8777
|
}
|
|
7506
8778
|
try {
|
|
7507
8779
|
const res = await collection.updateOne(
|
|
@@ -7512,11 +8784,11 @@ function useBuildingUnitRepo() {
|
|
|
7512
8784
|
delCachedData();
|
|
7513
8785
|
return "Room/Facility deleted successfully.";
|
|
7514
8786
|
} catch (error) {
|
|
7515
|
-
|
|
8787
|
+
logger24.log({
|
|
7516
8788
|
level: "error",
|
|
7517
8789
|
message: error.message
|
|
7518
8790
|
});
|
|
7519
|
-
if (error instanceof
|
|
8791
|
+
if (error instanceof AppError19) {
|
|
7520
8792
|
throw error;
|
|
7521
8793
|
} else {
|
|
7522
8794
|
throw new Error("Failed to deleted room/facility.");
|
|
@@ -7546,7 +8818,7 @@ function useBuildingService() {
|
|
|
7546
8818
|
const { getByBuildingLevel, getByBuilding, updateByBuildingId } = useBuildingUnitRepo();
|
|
7547
8819
|
async function updateById(id, data) {
|
|
7548
8820
|
data.levels = Number(data.levels);
|
|
7549
|
-
const session =
|
|
8821
|
+
const session = useAtlas22.getClient()?.startSession();
|
|
7550
8822
|
try {
|
|
7551
8823
|
const building = await _getById(id);
|
|
7552
8824
|
if (!building) {
|
|
@@ -7555,7 +8827,7 @@ function useBuildingService() {
|
|
|
7555
8827
|
if (data.levels < building.levels) {
|
|
7556
8828
|
const unit = await getByBuildingLevel(id, building.levels);
|
|
7557
8829
|
if (unit) {
|
|
7558
|
-
throw new
|
|
8830
|
+
throw new BadRequestError46(
|
|
7559
8831
|
"Cannot reduce floors, there are existing building units at higher floors."
|
|
7560
8832
|
);
|
|
7561
8833
|
}
|
|
@@ -7577,7 +8849,7 @@ function useBuildingService() {
|
|
|
7577
8849
|
async function deleteById(id) {
|
|
7578
8850
|
const building = await getByBuilding(id);
|
|
7579
8851
|
if (building) {
|
|
7580
|
-
throw new
|
|
8852
|
+
throw new BadRequestError46(
|
|
7581
8853
|
"Cannot delete building with existing room/facility. Please delete room/facility first."
|
|
7582
8854
|
);
|
|
7583
8855
|
}
|
|
@@ -7595,24 +8867,24 @@ function useBuildingService() {
|
|
|
7595
8867
|
}
|
|
7596
8868
|
|
|
7597
8869
|
// src/resources/building/building.controller.ts
|
|
7598
|
-
import { BadRequestError as
|
|
7599
|
-
import
|
|
8870
|
+
import { BadRequestError as BadRequestError47, logger as logger25 } from "@goweekdays/utils";
|
|
8871
|
+
import Joi34 from "joi";
|
|
7600
8872
|
function useBuildingController() {
|
|
7601
8873
|
const { getAll: _getAll, getById: _getById, add: _add } = useBuildingRepo();
|
|
7602
8874
|
const { updateById: _updateById, deleteById: _deleteById } = useBuildingService();
|
|
7603
8875
|
async function createBuilding(req, res, next) {
|
|
7604
8876
|
const value = req.body;
|
|
7605
|
-
const validation =
|
|
7606
|
-
name:
|
|
7607
|
-
school:
|
|
7608
|
-
levels:
|
|
7609
|
-
serial:
|
|
7610
|
-
status:
|
|
8877
|
+
const validation = Joi34.object({
|
|
8878
|
+
name: Joi34.string().required(),
|
|
8879
|
+
school: Joi34.string().hex().required(),
|
|
8880
|
+
levels: Joi34.number().integer().min(1).required(),
|
|
8881
|
+
serial: Joi34.string().optional().allow("", null),
|
|
8882
|
+
status: Joi34.string().optional().allow("", null)
|
|
7611
8883
|
});
|
|
7612
8884
|
const { error } = validation.validate(value);
|
|
7613
8885
|
if (error) {
|
|
7614
|
-
next(new
|
|
7615
|
-
|
|
8886
|
+
next(new BadRequestError47(error.message));
|
|
8887
|
+
logger25.info(`Controller: ${error.message}`);
|
|
7616
8888
|
return;
|
|
7617
8889
|
}
|
|
7618
8890
|
try {
|
|
@@ -7626,18 +8898,18 @@ function useBuildingController() {
|
|
|
7626
8898
|
async function updateById(req, res, next) {
|
|
7627
8899
|
const value = req.body;
|
|
7628
8900
|
const id = req.params.id ?? "";
|
|
7629
|
-
const validation =
|
|
7630
|
-
id:
|
|
7631
|
-
value:
|
|
7632
|
-
name:
|
|
7633
|
-
serial:
|
|
7634
|
-
levels:
|
|
8901
|
+
const validation = Joi34.object({
|
|
8902
|
+
id: Joi34.string().hex().required(),
|
|
8903
|
+
value: Joi34.object({
|
|
8904
|
+
name: Joi34.string().required(),
|
|
8905
|
+
serial: Joi34.string().optional().allow("", null),
|
|
8906
|
+
levels: Joi34.number().integer().min(1).required()
|
|
7635
8907
|
})
|
|
7636
8908
|
});
|
|
7637
8909
|
const { error } = validation.validate({ id, value });
|
|
7638
8910
|
if (error) {
|
|
7639
|
-
next(new
|
|
7640
|
-
|
|
8911
|
+
next(new BadRequestError47(error.message));
|
|
8912
|
+
logger25.info(`Controller: ${error.message}`);
|
|
7641
8913
|
return;
|
|
7642
8914
|
}
|
|
7643
8915
|
try {
|
|
@@ -7650,16 +8922,16 @@ function useBuildingController() {
|
|
|
7650
8922
|
}
|
|
7651
8923
|
async function getAll(req, res, next) {
|
|
7652
8924
|
const query = req.query;
|
|
7653
|
-
const validation =
|
|
7654
|
-
page:
|
|
7655
|
-
limit:
|
|
7656
|
-
search:
|
|
7657
|
-
school:
|
|
7658
|
-
status:
|
|
8925
|
+
const validation = Joi34.object({
|
|
8926
|
+
page: Joi34.number().min(1).optional().allow("", null),
|
|
8927
|
+
limit: Joi34.number().min(1).optional().allow("", null),
|
|
8928
|
+
search: Joi34.string().optional().allow("", null),
|
|
8929
|
+
school: Joi34.string().hex().optional().allow("", null),
|
|
8930
|
+
status: Joi34.string().optional().allow("", null)
|
|
7659
8931
|
});
|
|
7660
8932
|
const { error } = validation.validate(query);
|
|
7661
8933
|
if (error) {
|
|
7662
|
-
next(new
|
|
8934
|
+
next(new BadRequestError47(error.message));
|
|
7663
8935
|
return;
|
|
7664
8936
|
}
|
|
7665
8937
|
const page = parseInt(req.query.page) ?? 1;
|
|
@@ -7693,12 +8965,12 @@ function useBuildingController() {
|
|
|
7693
8965
|
}
|
|
7694
8966
|
async function getById(req, res, next) {
|
|
7695
8967
|
const id = req.params.id;
|
|
7696
|
-
const validation =
|
|
7697
|
-
id:
|
|
8968
|
+
const validation = Joi34.object({
|
|
8969
|
+
id: Joi34.string().hex().required()
|
|
7698
8970
|
});
|
|
7699
8971
|
const { error } = validation.validate({ id });
|
|
7700
8972
|
if (error) {
|
|
7701
|
-
next(new
|
|
8973
|
+
next(new BadRequestError47(error.message));
|
|
7702
8974
|
return;
|
|
7703
8975
|
}
|
|
7704
8976
|
try {
|
|
@@ -7714,12 +8986,12 @@ function useBuildingController() {
|
|
|
7714
8986
|
}
|
|
7715
8987
|
async function deleteById(req, res, next) {
|
|
7716
8988
|
const id = req.params.id;
|
|
7717
|
-
const validation =
|
|
7718
|
-
id:
|
|
8989
|
+
const validation = Joi34.object({
|
|
8990
|
+
id: Joi34.string().hex().required()
|
|
7719
8991
|
});
|
|
7720
8992
|
const { error } = validation.validate({ id });
|
|
7721
8993
|
if (error) {
|
|
7722
|
-
next(new
|
|
8994
|
+
next(new BadRequestError47(error.message));
|
|
7723
8995
|
return;
|
|
7724
8996
|
}
|
|
7725
8997
|
try {
|
|
@@ -7740,11 +9012,11 @@ function useBuildingController() {
|
|
|
7740
9012
|
}
|
|
7741
9013
|
|
|
7742
9014
|
// src/resources/building/building-unit.service.ts
|
|
7743
|
-
import { useAtlas as
|
|
9015
|
+
import { useAtlas as useAtlas23 } from "@goweekdays/utils";
|
|
7744
9016
|
function useBuildingUnitService() {
|
|
7745
9017
|
const { add: _add } = useBuildingUnitRepo();
|
|
7746
9018
|
async function add(value) {
|
|
7747
|
-
const session =
|
|
9019
|
+
const session = useAtlas23.getClient()?.startSession();
|
|
7748
9020
|
if (!session) {
|
|
7749
9021
|
throw new Error("Unable to start session for building unit service.");
|
|
7750
9022
|
}
|
|
@@ -7771,8 +9043,8 @@ function useBuildingUnitService() {
|
|
|
7771
9043
|
}
|
|
7772
9044
|
|
|
7773
9045
|
// src/resources/building/building-unit.controller.ts
|
|
7774
|
-
import { BadRequestError as
|
|
7775
|
-
import
|
|
9046
|
+
import { BadRequestError as BadRequestError48 } from "@goweekdays/utils";
|
|
9047
|
+
import Joi35 from "joi";
|
|
7776
9048
|
function useBuildingUnitController() {
|
|
7777
9049
|
const {
|
|
7778
9050
|
getAll: _getAll,
|
|
@@ -7783,27 +9055,27 @@ function useBuildingUnitController() {
|
|
|
7783
9055
|
const { add: _add } = useBuildingUnitService();
|
|
7784
9056
|
async function add(req, res, next) {
|
|
7785
9057
|
const data = req.body;
|
|
7786
|
-
const validation =
|
|
7787
|
-
building:
|
|
7788
|
-
school:
|
|
7789
|
-
name:
|
|
7790
|
-
building:
|
|
7791
|
-
buildingName:
|
|
7792
|
-
level:
|
|
7793
|
-
category:
|
|
7794
|
-
type:
|
|
7795
|
-
seating_capacity:
|
|
7796
|
-
standing_capacity:
|
|
7797
|
-
description:
|
|
7798
|
-
unit_of_measurement:
|
|
7799
|
-
area:
|
|
7800
|
-
status:
|
|
9058
|
+
const validation = Joi35.object({
|
|
9059
|
+
building: Joi35.object({
|
|
9060
|
+
school: Joi35.string().hex().required(),
|
|
9061
|
+
name: Joi35.string().optional().allow("", null),
|
|
9062
|
+
building: Joi35.string().hex().required(),
|
|
9063
|
+
buildingName: Joi35.string().optional().allow("", null),
|
|
9064
|
+
level: Joi35.number().integer().min(1).required(),
|
|
9065
|
+
category: Joi35.string().required(),
|
|
9066
|
+
type: Joi35.string().required(),
|
|
9067
|
+
seating_capacity: Joi35.number().integer().min(0).required(),
|
|
9068
|
+
standing_capacity: Joi35.number().integer().min(0).required(),
|
|
9069
|
+
description: Joi35.string().optional().allow("", null),
|
|
9070
|
+
unit_of_measurement: Joi35.string().valid("sqm").required(),
|
|
9071
|
+
area: Joi35.number().positive().required(),
|
|
9072
|
+
status: Joi35.string().optional().allow("", null)
|
|
7801
9073
|
}),
|
|
7802
|
-
qty:
|
|
9074
|
+
qty: Joi35.number().integer().min(1).max(20).optional().default(1)
|
|
7803
9075
|
});
|
|
7804
9076
|
const { error } = validation.validate(data);
|
|
7805
9077
|
if (error) {
|
|
7806
|
-
next(new
|
|
9078
|
+
next(new BadRequestError48(error.message));
|
|
7807
9079
|
return;
|
|
7808
9080
|
}
|
|
7809
9081
|
try {
|
|
@@ -7819,13 +9091,13 @@ function useBuildingUnitController() {
|
|
|
7819
9091
|
async function updateById(req, res, next) {
|
|
7820
9092
|
const data = req.body;
|
|
7821
9093
|
const id = req.params.id ?? "";
|
|
7822
|
-
const validation =
|
|
7823
|
-
id:
|
|
9094
|
+
const validation = Joi35.object({
|
|
9095
|
+
id: Joi35.string().hex().required(),
|
|
7824
9096
|
value: schemaUpdateOptions
|
|
7825
9097
|
});
|
|
7826
9098
|
const { error } = validation.validate({ id, value: data });
|
|
7827
9099
|
if (error) {
|
|
7828
|
-
next(new
|
|
9100
|
+
next(new BadRequestError48(error.message));
|
|
7829
9101
|
return;
|
|
7830
9102
|
}
|
|
7831
9103
|
try {
|
|
@@ -7840,17 +9112,17 @@ function useBuildingUnitController() {
|
|
|
7840
9112
|
}
|
|
7841
9113
|
async function getAll(req, res, next) {
|
|
7842
9114
|
const query = req.query;
|
|
7843
|
-
const validation =
|
|
7844
|
-
page:
|
|
7845
|
-
limit:
|
|
7846
|
-
search:
|
|
7847
|
-
school:
|
|
7848
|
-
building:
|
|
7849
|
-
status:
|
|
9115
|
+
const validation = Joi35.object({
|
|
9116
|
+
page: Joi35.number().min(1).optional().allow("", null),
|
|
9117
|
+
limit: Joi35.number().min(1).optional().allow("", null),
|
|
9118
|
+
search: Joi35.string().optional().allow("", null),
|
|
9119
|
+
school: Joi35.string().hex().optional().allow("", null),
|
|
9120
|
+
building: Joi35.string().hex().optional().allow("", null),
|
|
9121
|
+
status: Joi35.string().optional().allow("", null)
|
|
7850
9122
|
});
|
|
7851
9123
|
const { error } = validation.validate(query);
|
|
7852
9124
|
if (error) {
|
|
7853
|
-
next(new
|
|
9125
|
+
next(new BadRequestError48(error.message));
|
|
7854
9126
|
return;
|
|
7855
9127
|
}
|
|
7856
9128
|
const page = parseInt(req.query.page) ?? 1;
|
|
@@ -7886,12 +9158,12 @@ function useBuildingUnitController() {
|
|
|
7886
9158
|
}
|
|
7887
9159
|
async function getById(req, res, next) {
|
|
7888
9160
|
const id = req.params.id;
|
|
7889
|
-
const validation =
|
|
7890
|
-
id:
|
|
9161
|
+
const validation = Joi35.object({
|
|
9162
|
+
id: Joi35.string().hex().required()
|
|
7891
9163
|
});
|
|
7892
9164
|
const { error } = validation.validate({ id });
|
|
7893
9165
|
if (error) {
|
|
7894
|
-
next(new
|
|
9166
|
+
next(new BadRequestError48(error.message));
|
|
7895
9167
|
return;
|
|
7896
9168
|
}
|
|
7897
9169
|
try {
|
|
@@ -7907,12 +9179,12 @@ function useBuildingUnitController() {
|
|
|
7907
9179
|
}
|
|
7908
9180
|
async function deleteById(req, res, next) {
|
|
7909
9181
|
const id = req.params.id;
|
|
7910
|
-
const validation =
|
|
7911
|
-
id:
|
|
9182
|
+
const validation = Joi35.object({
|
|
9183
|
+
id: Joi35.string().hex().required()
|
|
7912
9184
|
});
|
|
7913
9185
|
const { error } = validation.validate({ id });
|
|
7914
9186
|
if (error) {
|
|
7915
|
-
next(new
|
|
9187
|
+
next(new BadRequestError48(error.message));
|
|
7916
9188
|
return;
|
|
7917
9189
|
}
|
|
7918
9190
|
try {
|
|
@@ -7933,14 +9205,14 @@ function useBuildingUnitController() {
|
|
|
7933
9205
|
}
|
|
7934
9206
|
|
|
7935
9207
|
// src/resources/counter/counter.model.ts
|
|
7936
|
-
import { BadRequestError as
|
|
7937
|
-
import { ObjectId as
|
|
9208
|
+
import { BadRequestError as BadRequestError49 } from "@goweekdays/utils";
|
|
9209
|
+
import { ObjectId as ObjectId25 } from "mongodb";
|
|
7938
9210
|
import { z } from "zod";
|
|
7939
9211
|
var TCounter = z.object({
|
|
7940
9212
|
_id: z.union([
|
|
7941
9213
|
z.string().length(24, "Invalid ObjectId hex string"),
|
|
7942
|
-
z.instanceof(
|
|
7943
|
-
]).transform((val) => typeof val === "string" ? new
|
|
9214
|
+
z.instanceof(ObjectId25)
|
|
9215
|
+
]).transform((val) => typeof val === "string" ? new ObjectId25(val) : val).optional(),
|
|
7944
9216
|
count: z.number().int().min(0).default(0),
|
|
7945
9217
|
type: z.string(),
|
|
7946
9218
|
createdAt: z.date().optional().default(() => /* @__PURE__ */ new Date()),
|
|
@@ -7953,7 +9225,7 @@ function useCounterModel(db) {
|
|
|
7953
9225
|
try {
|
|
7954
9226
|
return TCounter.parse(value);
|
|
7955
9227
|
} catch (error) {
|
|
7956
|
-
throw new
|
|
9228
|
+
throw new BadRequestError49(error.issues[0].message);
|
|
7957
9229
|
}
|
|
7958
9230
|
}
|
|
7959
9231
|
function validateCounter(data) {
|
|
@@ -7967,23 +9239,23 @@ function useCounterModel(db) {
|
|
|
7967
9239
|
}
|
|
7968
9240
|
|
|
7969
9241
|
// src/resources/counter/counter.repository.ts
|
|
7970
|
-
import { useAtlas as
|
|
9242
|
+
import { useAtlas as useAtlas24, useCache as useCache18, makeCacheKey as makeCacheKey17, logger as logger26 } from "@goweekdays/utils";
|
|
7971
9243
|
function useCounterRepo() {
|
|
7972
|
-
const db =
|
|
9244
|
+
const db = useAtlas24.getDb();
|
|
7973
9245
|
if (!db) {
|
|
7974
9246
|
throw new Error("Unable to connect to server.");
|
|
7975
9247
|
}
|
|
7976
9248
|
const namespace_collection = "counters";
|
|
7977
9249
|
const { collection, createCounter } = useCounterModel(db);
|
|
7978
|
-
const { getCache, setCache, delNamespace } =
|
|
9250
|
+
const { getCache, setCache, delNamespace } = useCache18(namespace_collection);
|
|
7979
9251
|
function delCachedData() {
|
|
7980
9252
|
delNamespace().then(() => {
|
|
7981
|
-
|
|
9253
|
+
logger26.log({
|
|
7982
9254
|
level: "info",
|
|
7983
9255
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
7984
9256
|
});
|
|
7985
9257
|
}).catch((err) => {
|
|
7986
|
-
|
|
9258
|
+
logger26.log({
|
|
7987
9259
|
level: "error",
|
|
7988
9260
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
7989
9261
|
});
|
|
@@ -8035,11 +9307,11 @@ function useCounterRepo() {
|
|
|
8035
9307
|
}
|
|
8036
9308
|
}
|
|
8037
9309
|
async function getByType(type) {
|
|
8038
|
-
const cacheKey =
|
|
9310
|
+
const cacheKey = makeCacheKey17(namespace_collection, { type });
|
|
8039
9311
|
try {
|
|
8040
9312
|
const cached = await getCache(cacheKey);
|
|
8041
9313
|
if (cached) {
|
|
8042
|
-
|
|
9314
|
+
logger26.log({
|
|
8043
9315
|
level: "info",
|
|
8044
9316
|
message: `Cache hit for getByType counter: ${cacheKey}`
|
|
8045
9317
|
});
|
|
@@ -8048,12 +9320,12 @@ function useCounterRepo() {
|
|
|
8048
9320
|
const data = await collection.findOne({ type });
|
|
8049
9321
|
if (data) {
|
|
8050
9322
|
setCache(cacheKey, data, 300).then(() => {
|
|
8051
|
-
|
|
9323
|
+
logger26.log({
|
|
8052
9324
|
level: "info",
|
|
8053
9325
|
message: `Cache set for counter by type: ${cacheKey}`
|
|
8054
9326
|
});
|
|
8055
9327
|
}).catch((err) => {
|
|
8056
|
-
|
|
9328
|
+
logger26.log({
|
|
8057
9329
|
level: "error",
|
|
8058
9330
|
message: `Failed to set cache for counter by type: ${err.message}`
|
|
8059
9331
|
});
|
|
@@ -8074,7 +9346,7 @@ function useCounterRepo() {
|
|
|
8074
9346
|
}
|
|
8075
9347
|
|
|
8076
9348
|
// src/resources/file/file.service.ts
|
|
8077
|
-
import { logger as
|
|
9349
|
+
import { logger as logger27, useS3 as useS32, useAtlas as useAtlas25 } from "@goweekdays/utils";
|
|
8078
9350
|
import cron from "node-cron";
|
|
8079
9351
|
import * as fs from "fs";
|
|
8080
9352
|
function useFileService() {
|
|
@@ -8092,7 +9364,7 @@ function useFileService() {
|
|
|
8092
9364
|
forcePathStyle: true
|
|
8093
9365
|
});
|
|
8094
9366
|
async function createFile(value) {
|
|
8095
|
-
const session =
|
|
9367
|
+
const session = useAtlas25.getClient()?.startSession();
|
|
8096
9368
|
session?.startTransaction();
|
|
8097
9369
|
const file = {
|
|
8098
9370
|
name: value.originalname,
|
|
@@ -8126,7 +9398,7 @@ function useFileService() {
|
|
|
8126
9398
|
}
|
|
8127
9399
|
}
|
|
8128
9400
|
async function deleteFile(id) {
|
|
8129
|
-
const session =
|
|
9401
|
+
const session = useAtlas25.getClient()?.startSession();
|
|
8130
9402
|
session?.startTransaction();
|
|
8131
9403
|
try {
|
|
8132
9404
|
await deleteFileById(id, session);
|
|
@@ -8147,12 +9419,12 @@ function useFileService() {
|
|
|
8147
9419
|
const file = files[index];
|
|
8148
9420
|
try {
|
|
8149
9421
|
await deleteFile(file._id.toString());
|
|
8150
|
-
await
|
|
9422
|
+
await logger27.log({
|
|
8151
9423
|
level: "info",
|
|
8152
9424
|
message: "Successfully deleted draft files."
|
|
8153
9425
|
});
|
|
8154
9426
|
} catch (error) {
|
|
8155
|
-
|
|
9427
|
+
logger27.log({
|
|
8156
9428
|
level: "info",
|
|
8157
9429
|
message: "Successfully deleted draft files."
|
|
8158
9430
|
});
|
|
@@ -8170,11 +9442,11 @@ function useFileService() {
|
|
|
8170
9442
|
|
|
8171
9443
|
// src/resources/file/file.controller.ts
|
|
8172
9444
|
import {
|
|
8173
|
-
AppError as
|
|
8174
|
-
BadRequestError as
|
|
8175
|
-
InternalServerError as
|
|
9445
|
+
AppError as AppError20,
|
|
9446
|
+
BadRequestError as BadRequestError50,
|
|
9447
|
+
InternalServerError as InternalServerError24
|
|
8176
9448
|
} from "@goweekdays/utils";
|
|
8177
|
-
import
|
|
9449
|
+
import Joi36 from "joi";
|
|
8178
9450
|
function useFileController() {
|
|
8179
9451
|
const { createFile, deleteFile: _deleteFile } = useFileService();
|
|
8180
9452
|
async function upload(req, res, next) {
|
|
@@ -8187,29 +9459,29 @@ function useFileController() {
|
|
|
8187
9459
|
res.json({ message: "Successfully uploaded file", id });
|
|
8188
9460
|
return;
|
|
8189
9461
|
} catch (error) {
|
|
8190
|
-
if (error instanceof
|
|
9462
|
+
if (error instanceof AppError20) {
|
|
8191
9463
|
next(error);
|
|
8192
9464
|
} else {
|
|
8193
|
-
next(new
|
|
9465
|
+
next(new InternalServerError24(error));
|
|
8194
9466
|
}
|
|
8195
9467
|
}
|
|
8196
9468
|
}
|
|
8197
9469
|
async function deleteFile(req, res, next) {
|
|
8198
9470
|
const id = req.params.id;
|
|
8199
|
-
const validation =
|
|
9471
|
+
const validation = Joi36.string().required();
|
|
8200
9472
|
const { error } = validation.validate(id);
|
|
8201
9473
|
if (error) {
|
|
8202
|
-
next(new
|
|
9474
|
+
next(new BadRequestError50(error.message));
|
|
8203
9475
|
}
|
|
8204
9476
|
try {
|
|
8205
9477
|
const message = await _deleteFile(id);
|
|
8206
9478
|
res.json({ message });
|
|
8207
9479
|
return;
|
|
8208
9480
|
} catch (error2) {
|
|
8209
|
-
if (error2 instanceof
|
|
9481
|
+
if (error2 instanceof AppError20) {
|
|
8210
9482
|
next(error2);
|
|
8211
9483
|
} else {
|
|
8212
|
-
next(new
|
|
9484
|
+
next(new InternalServerError24(error2));
|
|
8213
9485
|
}
|
|
8214
9486
|
}
|
|
8215
9487
|
}
|
|
@@ -8220,11 +9492,11 @@ function useFileController() {
|
|
|
8220
9492
|
}
|
|
8221
9493
|
|
|
8222
9494
|
// src/resources/psgc/psgc.model.ts
|
|
8223
|
-
import
|
|
8224
|
-
var schemaPSGC =
|
|
8225
|
-
code:
|
|
8226
|
-
name:
|
|
8227
|
-
type:
|
|
9495
|
+
import Joi37 from "joi";
|
|
9496
|
+
var schemaPSGC = Joi37.object({
|
|
9497
|
+
code: Joi37.string().length(10).required(),
|
|
9498
|
+
name: Joi37.string().required(),
|
|
9499
|
+
type: Joi37.string().valid("Reg", "Prov", "City", "Mun", "Bgy").required()
|
|
8228
9500
|
});
|
|
8229
9501
|
function modelPSGC(data) {
|
|
8230
9502
|
const { error } = schemaPSGC.validate(data);
|
|
@@ -8240,24 +9512,24 @@ function modelPSGC(data) {
|
|
|
8240
9512
|
|
|
8241
9513
|
// src/resources/psgc/psgc.repository.ts
|
|
8242
9514
|
import {
|
|
8243
|
-
AppError as
|
|
8244
|
-
BadRequestError as
|
|
8245
|
-
InternalServerError as
|
|
8246
|
-
logger as
|
|
8247
|
-
makeCacheKey as
|
|
8248
|
-
paginate as
|
|
8249
|
-
useAtlas as
|
|
8250
|
-
useCache as
|
|
9515
|
+
AppError as AppError21,
|
|
9516
|
+
BadRequestError as BadRequestError51,
|
|
9517
|
+
InternalServerError as InternalServerError25,
|
|
9518
|
+
logger as logger28,
|
|
9519
|
+
makeCacheKey as makeCacheKey18,
|
|
9520
|
+
paginate as paginate14,
|
|
9521
|
+
useAtlas as useAtlas26,
|
|
9522
|
+
useCache as useCache19
|
|
8251
9523
|
} from "@goweekdays/utils";
|
|
8252
|
-
import { ObjectId as
|
|
9524
|
+
import { ObjectId as ObjectId26 } from "mongodb";
|
|
8253
9525
|
function usePSGCRepo() {
|
|
8254
|
-
const db =
|
|
9526
|
+
const db = useAtlas26.getDb();
|
|
8255
9527
|
if (!db) {
|
|
8256
9528
|
throw new Error("Unable to connect to server.");
|
|
8257
9529
|
}
|
|
8258
9530
|
const namespace_collection = "psgc";
|
|
8259
9531
|
const collection = db.collection(namespace_collection);
|
|
8260
|
-
const { getCache, setCache, delNamespace } =
|
|
9532
|
+
const { getCache, setCache, delNamespace } = useCache19(namespace_collection);
|
|
8261
9533
|
async function createIndexes() {
|
|
8262
9534
|
try {
|
|
8263
9535
|
await collection.createIndexes([
|
|
@@ -8271,12 +9543,12 @@ function usePSGCRepo() {
|
|
|
8271
9543
|
}
|
|
8272
9544
|
function delCachedData() {
|
|
8273
9545
|
delNamespace().then(() => {
|
|
8274
|
-
|
|
9546
|
+
logger28.log({
|
|
8275
9547
|
level: "info",
|
|
8276
9548
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
8277
9549
|
});
|
|
8278
9550
|
}).catch((err) => {
|
|
8279
|
-
|
|
9551
|
+
logger28.log({
|
|
8280
9552
|
level: "error",
|
|
8281
9553
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
8282
9554
|
});
|
|
@@ -8289,16 +9561,16 @@ function usePSGCRepo() {
|
|
|
8289
9561
|
delCachedData();
|
|
8290
9562
|
return res.insertedId;
|
|
8291
9563
|
} catch (error) {
|
|
8292
|
-
|
|
9564
|
+
logger28.log({
|
|
8293
9565
|
level: "error",
|
|
8294
9566
|
message: error.message
|
|
8295
9567
|
});
|
|
8296
|
-
if (error instanceof
|
|
9568
|
+
if (error instanceof AppError21) {
|
|
8297
9569
|
throw error;
|
|
8298
9570
|
} else {
|
|
8299
9571
|
const isDuplicated = error.message.includes("duplicate");
|
|
8300
9572
|
if (isDuplicated) {
|
|
8301
|
-
throw new
|
|
9573
|
+
throw new BadRequestError51("Region already exists.");
|
|
8302
9574
|
}
|
|
8303
9575
|
throw new Error("Failed to create PSGC.");
|
|
8304
9576
|
}
|
|
@@ -8334,15 +9606,15 @@ function usePSGCRepo() {
|
|
|
8334
9606
|
query.$text = { $search: search };
|
|
8335
9607
|
cacheKeyOptions.search = search;
|
|
8336
9608
|
}
|
|
8337
|
-
const cacheKey =
|
|
8338
|
-
|
|
9609
|
+
const cacheKey = makeCacheKey18(namespace_collection, cacheKeyOptions);
|
|
9610
|
+
logger28.log({
|
|
8339
9611
|
level: "info",
|
|
8340
9612
|
message: `Cache key for getAll PSGC: ${cacheKey}`
|
|
8341
9613
|
});
|
|
8342
9614
|
try {
|
|
8343
9615
|
const cached = await getCache(cacheKey);
|
|
8344
9616
|
if (cached) {
|
|
8345
|
-
|
|
9617
|
+
logger28.log({
|
|
8346
9618
|
level: "info",
|
|
8347
9619
|
message: `Cache hit for getAll PSGC: ${cacheKey}`
|
|
8348
9620
|
});
|
|
@@ -8355,35 +9627,35 @@ function usePSGCRepo() {
|
|
|
8355
9627
|
{ $limit: limit }
|
|
8356
9628
|
]).toArray();
|
|
8357
9629
|
const length = await collection.countDocuments(query);
|
|
8358
|
-
const data =
|
|
9630
|
+
const data = paginate14(items, page, limit, length);
|
|
8359
9631
|
setCache(cacheKey, data, 600).then(() => {
|
|
8360
|
-
|
|
9632
|
+
logger28.log({
|
|
8361
9633
|
level: "info",
|
|
8362
9634
|
message: `Cache set for getAll PSGC: ${cacheKey}`
|
|
8363
9635
|
});
|
|
8364
9636
|
}).catch((err) => {
|
|
8365
|
-
|
|
9637
|
+
logger28.log({
|
|
8366
9638
|
level: "error",
|
|
8367
9639
|
message: `Failed to set cache for getAll PSGC: ${err.message}`
|
|
8368
9640
|
});
|
|
8369
9641
|
});
|
|
8370
9642
|
return data;
|
|
8371
9643
|
} catch (error) {
|
|
8372
|
-
|
|
9644
|
+
logger28.log({ level: "error", message: `${error}` });
|
|
8373
9645
|
throw error;
|
|
8374
9646
|
}
|
|
8375
9647
|
}
|
|
8376
9648
|
async function getById(_id) {
|
|
8377
9649
|
try {
|
|
8378
|
-
_id = new
|
|
9650
|
+
_id = new ObjectId26(_id);
|
|
8379
9651
|
} catch (error) {
|
|
8380
|
-
throw new
|
|
9652
|
+
throw new BadRequestError51("Invalid ID.");
|
|
8381
9653
|
}
|
|
8382
|
-
const cacheKey =
|
|
9654
|
+
const cacheKey = makeCacheKey18(namespace_collection, { _id: String(_id) });
|
|
8383
9655
|
try {
|
|
8384
9656
|
const cached = await getCache(cacheKey);
|
|
8385
9657
|
if (cached) {
|
|
8386
|
-
|
|
9658
|
+
logger28.log({
|
|
8387
9659
|
level: "info",
|
|
8388
9660
|
message: `Cache hit for getById PSGC: ${cacheKey}`
|
|
8389
9661
|
});
|
|
@@ -8394,25 +9666,25 @@ function usePSGCRepo() {
|
|
|
8394
9666
|
deletedAt: { $in: ["", null] }
|
|
8395
9667
|
});
|
|
8396
9668
|
if (!result) {
|
|
8397
|
-
throw new
|
|
9669
|
+
throw new BadRequestError51("Region not found.");
|
|
8398
9670
|
}
|
|
8399
9671
|
setCache(cacheKey, result, 300).then(() => {
|
|
8400
|
-
|
|
9672
|
+
logger28.log({
|
|
8401
9673
|
level: "info",
|
|
8402
9674
|
message: `Cache set for PSGC by id: ${cacheKey}`
|
|
8403
9675
|
});
|
|
8404
9676
|
}).catch((err) => {
|
|
8405
|
-
|
|
9677
|
+
logger28.log({
|
|
8406
9678
|
level: "error",
|
|
8407
9679
|
message: `Failed to set cache for PSGC by id: ${err.message}`
|
|
8408
9680
|
});
|
|
8409
9681
|
});
|
|
8410
9682
|
return result;
|
|
8411
9683
|
} catch (error) {
|
|
8412
|
-
if (error instanceof
|
|
9684
|
+
if (error instanceof AppError21) {
|
|
8413
9685
|
throw error;
|
|
8414
9686
|
} else {
|
|
8415
|
-
throw new
|
|
9687
|
+
throw new InternalServerError25("Failed to get PSGC.");
|
|
8416
9688
|
}
|
|
8417
9689
|
}
|
|
8418
9690
|
}
|
|
@@ -8436,15 +9708,15 @@ function usePSGCRepo() {
|
|
|
8436
9708
|
query.code = { $regex: `^${prefix}` };
|
|
8437
9709
|
cacheKeyOptions.prefix = prefix;
|
|
8438
9710
|
}
|
|
8439
|
-
const cacheKey =
|
|
8440
|
-
|
|
9711
|
+
const cacheKey = makeCacheKey18(namespace_collection, { name });
|
|
9712
|
+
logger28.log({
|
|
8441
9713
|
level: "info",
|
|
8442
9714
|
message: `Query for getByName PSGC: ${JSON.stringify(query)}`
|
|
8443
9715
|
});
|
|
8444
9716
|
try {
|
|
8445
9717
|
const cached = await getCache(cacheKey);
|
|
8446
9718
|
if (cached) {
|
|
8447
|
-
|
|
9719
|
+
logger28.log({
|
|
8448
9720
|
level: "info",
|
|
8449
9721
|
message: `Cache hit for getByName PSGC: ${cacheKey}`
|
|
8450
9722
|
});
|
|
@@ -8452,36 +9724,36 @@ function usePSGCRepo() {
|
|
|
8452
9724
|
}
|
|
8453
9725
|
const result = await collection.findOne(query);
|
|
8454
9726
|
setCache(cacheKey, result, 300).then(() => {
|
|
8455
|
-
|
|
9727
|
+
logger28.log({
|
|
8456
9728
|
level: "info",
|
|
8457
9729
|
message: `Cache set for PSGC by name: ${cacheKey}`
|
|
8458
9730
|
});
|
|
8459
9731
|
}).catch((err) => {
|
|
8460
|
-
|
|
9732
|
+
logger28.log({
|
|
8461
9733
|
level: "error",
|
|
8462
9734
|
message: `Failed to set cache for PSGC by name: ${err.message}`
|
|
8463
9735
|
});
|
|
8464
9736
|
});
|
|
8465
9737
|
return result;
|
|
8466
9738
|
} catch (error) {
|
|
8467
|
-
if (error instanceof
|
|
9739
|
+
if (error instanceof AppError21) {
|
|
8468
9740
|
throw error;
|
|
8469
9741
|
} else {
|
|
8470
|
-
throw new
|
|
9742
|
+
throw new InternalServerError25("Failed to get PSGC.");
|
|
8471
9743
|
}
|
|
8472
9744
|
}
|
|
8473
9745
|
}
|
|
8474
9746
|
async function updateFieldById({ _id, field, value } = {}, session) {
|
|
8475
9747
|
const allowedFields = ["name"];
|
|
8476
9748
|
if (!allowedFields.includes(field)) {
|
|
8477
|
-
throw new
|
|
9749
|
+
throw new BadRequestError51(
|
|
8478
9750
|
`Field "${field}" is not allowed to be updated.`
|
|
8479
9751
|
);
|
|
8480
9752
|
}
|
|
8481
9753
|
try {
|
|
8482
|
-
_id = new
|
|
9754
|
+
_id = new ObjectId26(_id);
|
|
8483
9755
|
} catch (error) {
|
|
8484
|
-
throw new
|
|
9756
|
+
throw new BadRequestError51("Invalid ID.");
|
|
8485
9757
|
}
|
|
8486
9758
|
try {
|
|
8487
9759
|
await collection.updateOne(
|
|
@@ -8492,14 +9764,14 @@ function usePSGCRepo() {
|
|
|
8492
9764
|
delCachedData();
|
|
8493
9765
|
return `Successfully updated PSGC ${field}.`;
|
|
8494
9766
|
} catch (error) {
|
|
8495
|
-
throw new
|
|
9767
|
+
throw new InternalServerError25(`Failed to update PSGC ${field}.`);
|
|
8496
9768
|
}
|
|
8497
9769
|
}
|
|
8498
9770
|
async function deleteById(_id) {
|
|
8499
9771
|
try {
|
|
8500
|
-
_id = new
|
|
9772
|
+
_id = new ObjectId26(_id);
|
|
8501
9773
|
} catch (error) {
|
|
8502
|
-
throw new
|
|
9774
|
+
throw new BadRequestError51("Invalid ID.");
|
|
8503
9775
|
}
|
|
8504
9776
|
try {
|
|
8505
9777
|
await collection.updateOne(
|
|
@@ -8509,7 +9781,7 @@ function usePSGCRepo() {
|
|
|
8509
9781
|
delCachedData();
|
|
8510
9782
|
return "Successfully deleted PSGC.";
|
|
8511
9783
|
} catch (error) {
|
|
8512
|
-
throw new
|
|
9784
|
+
throw new InternalServerError25("Failed to delete PSGC.");
|
|
8513
9785
|
}
|
|
8514
9786
|
}
|
|
8515
9787
|
return {
|
|
@@ -8524,8 +9796,8 @@ function usePSGCRepo() {
|
|
|
8524
9796
|
}
|
|
8525
9797
|
|
|
8526
9798
|
// src/resources/psgc/psgc.controller.ts
|
|
8527
|
-
import { BadRequestError as
|
|
8528
|
-
import
|
|
9799
|
+
import { BadRequestError as BadRequestError52 } from "@goweekdays/utils";
|
|
9800
|
+
import Joi38 from "joi";
|
|
8529
9801
|
function usePSGCController() {
|
|
8530
9802
|
const {
|
|
8531
9803
|
add: _add,
|
|
@@ -8539,7 +9811,7 @@ function usePSGCController() {
|
|
|
8539
9811
|
const value = req.body;
|
|
8540
9812
|
const { error } = schemaPSGC.validate(value);
|
|
8541
9813
|
if (error) {
|
|
8542
|
-
next(new
|
|
9814
|
+
next(new BadRequestError52(error.message));
|
|
8543
9815
|
return;
|
|
8544
9816
|
}
|
|
8545
9817
|
try {
|
|
@@ -8555,12 +9827,12 @@ function usePSGCController() {
|
|
|
8555
9827
|
}
|
|
8556
9828
|
async function getAll(req, res, next) {
|
|
8557
9829
|
const query = req.query;
|
|
8558
|
-
const validation =
|
|
8559
|
-
page:
|
|
8560
|
-
limit:
|
|
8561
|
-
search:
|
|
8562
|
-
type:
|
|
8563
|
-
prefix:
|
|
9830
|
+
const validation = Joi38.object({
|
|
9831
|
+
page: Joi38.number().min(1).optional().allow("", null),
|
|
9832
|
+
limit: Joi38.number().min(1).optional().allow("", null),
|
|
9833
|
+
search: Joi38.string().optional().allow("", null),
|
|
9834
|
+
type: Joi38.string().valid("Reg", "Prov", "City", "Mun", "Bgy").required(),
|
|
9835
|
+
prefix: Joi38.string().optional().allow("", null)
|
|
8564
9836
|
});
|
|
8565
9837
|
const { error } = validation.validate(query);
|
|
8566
9838
|
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
@@ -8570,16 +9842,16 @@ function usePSGCController() {
|
|
|
8570
9842
|
const prefix = req.query.prefix ? String(req.query.prefix) : "";
|
|
8571
9843
|
const isPageNumber = isFinite(page);
|
|
8572
9844
|
if (!isPageNumber) {
|
|
8573
|
-
next(new
|
|
9845
|
+
next(new BadRequestError52("Invalid page number."));
|
|
8574
9846
|
return;
|
|
8575
9847
|
}
|
|
8576
9848
|
const isLimitNumber = isFinite(limit);
|
|
8577
9849
|
if (!isLimitNumber) {
|
|
8578
|
-
next(new
|
|
9850
|
+
next(new BadRequestError52("Invalid limit number."));
|
|
8579
9851
|
return;
|
|
8580
9852
|
}
|
|
8581
9853
|
if (error) {
|
|
8582
|
-
next(new
|
|
9854
|
+
next(new BadRequestError52(error.message));
|
|
8583
9855
|
return;
|
|
8584
9856
|
}
|
|
8585
9857
|
try {
|
|
@@ -8598,12 +9870,12 @@ function usePSGCController() {
|
|
|
8598
9870
|
}
|
|
8599
9871
|
async function getById(req, res, next) {
|
|
8600
9872
|
const id = req.params.id;
|
|
8601
|
-
const validation =
|
|
8602
|
-
id:
|
|
9873
|
+
const validation = Joi38.object({
|
|
9874
|
+
id: Joi38.string().hex().required()
|
|
8603
9875
|
});
|
|
8604
9876
|
const { error } = validation.validate({ id });
|
|
8605
9877
|
if (error) {
|
|
8606
|
-
next(new
|
|
9878
|
+
next(new BadRequestError52(error.message));
|
|
8607
9879
|
return;
|
|
8608
9880
|
}
|
|
8609
9881
|
try {
|
|
@@ -8619,12 +9891,12 @@ function usePSGCController() {
|
|
|
8619
9891
|
}
|
|
8620
9892
|
async function getByName(req, res, next) {
|
|
8621
9893
|
const name = req.params.name;
|
|
8622
|
-
const validation =
|
|
8623
|
-
name:
|
|
9894
|
+
const validation = Joi38.object({
|
|
9895
|
+
name: Joi38.string().required()
|
|
8624
9896
|
});
|
|
8625
9897
|
const { error } = validation.validate({ name });
|
|
8626
9898
|
if (error) {
|
|
8627
|
-
next(new
|
|
9899
|
+
next(new BadRequestError52(error.message));
|
|
8628
9900
|
return;
|
|
8629
9901
|
}
|
|
8630
9902
|
try {
|
|
@@ -8641,14 +9913,14 @@ function usePSGCController() {
|
|
|
8641
9913
|
async function updateField(req, res, next) {
|
|
8642
9914
|
const _id = req.params.id;
|
|
8643
9915
|
const { field, value } = req.body;
|
|
8644
|
-
const validation =
|
|
8645
|
-
_id:
|
|
8646
|
-
field:
|
|
8647
|
-
value:
|
|
9916
|
+
const validation = Joi38.object({
|
|
9917
|
+
_id: Joi38.string().hex().required(),
|
|
9918
|
+
field: Joi38.string().valid("name", "director", "directorName").required(),
|
|
9919
|
+
value: Joi38.string().required()
|
|
8648
9920
|
});
|
|
8649
9921
|
const { error } = validation.validate({ _id, field, value });
|
|
8650
9922
|
if (error) {
|
|
8651
|
-
next(new
|
|
9923
|
+
next(new BadRequestError52(error.message));
|
|
8652
9924
|
return;
|
|
8653
9925
|
}
|
|
8654
9926
|
try {
|
|
@@ -8661,12 +9933,12 @@ function usePSGCController() {
|
|
|
8661
9933
|
}
|
|
8662
9934
|
async function deleteById(req, res, next) {
|
|
8663
9935
|
const _id = req.params.id;
|
|
8664
|
-
const validation =
|
|
8665
|
-
_id:
|
|
9936
|
+
const validation = Joi38.object({
|
|
9937
|
+
_id: Joi38.string().hex().required()
|
|
8666
9938
|
});
|
|
8667
9939
|
const { error } = validation.validate({ _id });
|
|
8668
9940
|
if (error) {
|
|
8669
|
-
next(new
|
|
9941
|
+
next(new BadRequestError52(error.message));
|
|
8670
9942
|
return;
|
|
8671
9943
|
}
|
|
8672
9944
|
try {
|
|
@@ -8688,7 +9960,7 @@ function usePSGCController() {
|
|
|
8688
9960
|
}
|
|
8689
9961
|
|
|
8690
9962
|
// src/resources/utils/github.service.ts
|
|
8691
|
-
import { AppError as
|
|
9963
|
+
import { AppError as AppError22, BadRequestError as BadRequestError53 } from "@goweekdays/utils";
|
|
8692
9964
|
import { Octokit } from "@octokit/rest";
|
|
8693
9965
|
import _sodium from "libsodium-wrappers";
|
|
8694
9966
|
function useGitHubService() {
|
|
@@ -8702,23 +9974,23 @@ function useGitHubService() {
|
|
|
8702
9974
|
try {
|
|
8703
9975
|
const { data: repoData } = await octokit.repos.get({ owner, repo });
|
|
8704
9976
|
if (!repoData.permissions?.admin) {
|
|
8705
|
-
throw new
|
|
9977
|
+
throw new BadRequestError53(
|
|
8706
9978
|
"You do not have admin access to this repository."
|
|
8707
9979
|
);
|
|
8708
9980
|
}
|
|
8709
9981
|
} catch (error) {
|
|
8710
9982
|
if (error.status === 404) {
|
|
8711
|
-
throw new
|
|
9983
|
+
throw new BadRequestError53(
|
|
8712
9984
|
"Repository not found or you don't have access to it."
|
|
8713
9985
|
);
|
|
8714
9986
|
} else if (error.status === 401) {
|
|
8715
|
-
throw new
|
|
9987
|
+
throw new BadRequestError53(
|
|
8716
9988
|
"Invalid GitHub token or insufficient permissions."
|
|
8717
9989
|
);
|
|
8718
9990
|
} else if (error.message.includes("admin access")) {
|
|
8719
9991
|
throw error;
|
|
8720
9992
|
} else {
|
|
8721
|
-
throw new
|
|
9993
|
+
throw new BadRequestError53(
|
|
8722
9994
|
`Failed to check repository permissions: ${error.message}`
|
|
8723
9995
|
);
|
|
8724
9996
|
}
|
|
@@ -8767,7 +10039,7 @@ function useGitHubService() {
|
|
|
8767
10039
|
key_id: publicKeyRes.key_id
|
|
8768
10040
|
});
|
|
8769
10041
|
} catch (encryptionError) {
|
|
8770
|
-
throw new
|
|
10042
|
+
throw new BadRequestError53(
|
|
8771
10043
|
`Failed to encrypt secret '${key}': ${encryptionError.message}`
|
|
8772
10044
|
);
|
|
8773
10045
|
}
|
|
@@ -8797,22 +10069,22 @@ function useGitHubService() {
|
|
|
8797
10069
|
}
|
|
8798
10070
|
return `Successfully set ${lines.length} ${type} variables/secrets in environment '${environment}'`;
|
|
8799
10071
|
} catch (error) {
|
|
8800
|
-
if (error instanceof
|
|
10072
|
+
if (error instanceof AppError22)
|
|
8801
10073
|
throw error;
|
|
8802
10074
|
if (error.status === 422) {
|
|
8803
|
-
throw new
|
|
10075
|
+
throw new BadRequestError53(
|
|
8804
10076
|
`GitHub API validation error: ${error.message}`
|
|
8805
10077
|
);
|
|
8806
10078
|
} else if (error.status === 404) {
|
|
8807
|
-
throw new
|
|
10079
|
+
throw new BadRequestError53("Environment or repository not found.");
|
|
8808
10080
|
} else if (error.status === 403) {
|
|
8809
|
-
throw new
|
|
10081
|
+
throw new BadRequestError53(
|
|
8810
10082
|
"Forbidden: Insufficient permissions or rate limit exceeded."
|
|
8811
10083
|
);
|
|
8812
10084
|
} else if (error.message.includes("admin access") || error.message.includes("permissions")) {
|
|
8813
10085
|
throw error;
|
|
8814
10086
|
} else {
|
|
8815
|
-
throw new
|
|
10087
|
+
throw new BadRequestError53(
|
|
8816
10088
|
`Failed to set GitHub variables: ${error.message}`
|
|
8817
10089
|
);
|
|
8818
10090
|
}
|
|
@@ -8824,12 +10096,12 @@ function useGitHubService() {
|
|
|
8824
10096
|
}
|
|
8825
10097
|
|
|
8826
10098
|
// src/resources/utils/util.controller.ts
|
|
8827
|
-
import
|
|
10099
|
+
import Joi39 from "joi";
|
|
8828
10100
|
import {
|
|
8829
|
-
AppError as
|
|
8830
|
-
BadRequestError as
|
|
8831
|
-
InternalServerError as
|
|
8832
|
-
logger as
|
|
10101
|
+
AppError as AppError23,
|
|
10102
|
+
BadRequestError as BadRequestError54,
|
|
10103
|
+
InternalServerError as InternalServerError26,
|
|
10104
|
+
logger as logger29
|
|
8833
10105
|
} from "@goweekdays/utils";
|
|
8834
10106
|
function useUtilController() {
|
|
8835
10107
|
async function healthCheck(req, res, next) {
|
|
@@ -8846,32 +10118,32 @@ function useUtilController() {
|
|
|
8846
10118
|
}
|
|
8847
10119
|
});
|
|
8848
10120
|
} catch (error) {
|
|
8849
|
-
|
|
8850
|
-
next(new
|
|
10121
|
+
logger29.error("Health check failed", { error: error.message });
|
|
10122
|
+
next(new InternalServerError26("Health check failed"));
|
|
8851
10123
|
}
|
|
8852
10124
|
}
|
|
8853
10125
|
async function setGitHubVariables(req, res, next) {
|
|
8854
10126
|
try {
|
|
8855
10127
|
const { githubToken, repoUrl, environment, type, keyValues } = req.body;
|
|
8856
|
-
const validation =
|
|
8857
|
-
githubToken:
|
|
10128
|
+
const validation = Joi39.object({
|
|
10129
|
+
githubToken: Joi39.string().required().messages({
|
|
8858
10130
|
"string.empty": "GitHub token is required",
|
|
8859
10131
|
"any.required": "GitHub token is required"
|
|
8860
10132
|
}),
|
|
8861
|
-
repoUrl:
|
|
10133
|
+
repoUrl: Joi39.string().uri().required().messages({
|
|
8862
10134
|
"string.empty": "Repository URL is required",
|
|
8863
10135
|
"string.uri": "Repository URL must be a valid URL",
|
|
8864
10136
|
"any.required": "Repository URL is required"
|
|
8865
10137
|
}),
|
|
8866
|
-
environment:
|
|
10138
|
+
environment: Joi39.string().required().messages({
|
|
8867
10139
|
"string.empty": "Environment name is required",
|
|
8868
10140
|
"any.required": "Environment name is required"
|
|
8869
10141
|
}),
|
|
8870
|
-
type:
|
|
10142
|
+
type: Joi39.string().valid("env", "secret").required().messages({
|
|
8871
10143
|
"any.only": 'Type must be either "env" or "secret"',
|
|
8872
10144
|
"any.required": "Type is required"
|
|
8873
10145
|
}),
|
|
8874
|
-
keyValues:
|
|
10146
|
+
keyValues: Joi39.string().required().messages({
|
|
8875
10147
|
"string.empty": "Key-value pairs are required",
|
|
8876
10148
|
"any.required": "Key-value pairs are required"
|
|
8877
10149
|
})
|
|
@@ -8884,13 +10156,13 @@ function useUtilController() {
|
|
|
8884
10156
|
keyValues
|
|
8885
10157
|
});
|
|
8886
10158
|
if (error) {
|
|
8887
|
-
next(new
|
|
10159
|
+
next(new BadRequestError54(error.message));
|
|
8888
10160
|
return;
|
|
8889
10161
|
}
|
|
8890
10162
|
const repoUrlPattern = /github\.com[:\/]([^\/]+)\/(.+)\.git$/;
|
|
8891
10163
|
if (!repoUrlPattern.test(repoUrl)) {
|
|
8892
10164
|
next(
|
|
8893
|
-
new
|
|
10165
|
+
new BadRequestError54(
|
|
8894
10166
|
"Invalid GitHub repository URL format. Expected format: https://github.com/owner/repo.git"
|
|
8895
10167
|
)
|
|
8896
10168
|
);
|
|
@@ -8902,7 +10174,7 @@ function useUtilController() {
|
|
|
8902
10174
|
);
|
|
8903
10175
|
if (invalidLines.length > 0) {
|
|
8904
10176
|
next(
|
|
8905
|
-
new
|
|
10177
|
+
new BadRequestError54(
|
|
8906
10178
|
"Invalid key-value format. Each pair should be in format: KEY=value. Pairs should be separated by semicolons."
|
|
8907
10179
|
)
|
|
8908
10180
|
);
|
|
@@ -8916,7 +10188,7 @@ function useUtilController() {
|
|
|
8916
10188
|
type,
|
|
8917
10189
|
keyValues
|
|
8918
10190
|
});
|
|
8919
|
-
|
|
10191
|
+
logger29.info(`GitHub variables set successfully`, {
|
|
8920
10192
|
repoUrl,
|
|
8921
10193
|
environment,
|
|
8922
10194
|
type,
|
|
@@ -8933,15 +10205,15 @@ function useUtilController() {
|
|
|
8933
10205
|
}
|
|
8934
10206
|
});
|
|
8935
10207
|
} catch (error) {
|
|
8936
|
-
|
|
10208
|
+
logger29.error("Failed to set GitHub variables", {
|
|
8937
10209
|
error: error.message,
|
|
8938
10210
|
stack: error.stack
|
|
8939
10211
|
});
|
|
8940
|
-
if (error instanceof
|
|
10212
|
+
if (error instanceof AppError23) {
|
|
8941
10213
|
next(error);
|
|
8942
10214
|
} else {
|
|
8943
10215
|
next(
|
|
8944
|
-
new
|
|
10216
|
+
new InternalServerError26(
|
|
8945
10217
|
`Failed to set GitHub variables: ${error.message}`
|
|
8946
10218
|
)
|
|
8947
10219
|
);
|
|
@@ -8955,35 +10227,35 @@ function useUtilController() {
|
|
|
8955
10227
|
}
|
|
8956
10228
|
|
|
8957
10229
|
// src/resources/utils/transaction.schema.ts
|
|
8958
|
-
import
|
|
8959
|
-
var transactionSchema =
|
|
8960
|
-
_id:
|
|
8961
|
-
payment:
|
|
8962
|
-
user:
|
|
8963
|
-
org:
|
|
8964
|
-
type:
|
|
8965
|
-
amount:
|
|
8966
|
-
currency:
|
|
8967
|
-
description:
|
|
8968
|
-
metadata:
|
|
8969
|
-
subscriptionId:
|
|
8970
|
-
cycle:
|
|
8971
|
-
seats:
|
|
8972
|
-
promoCode:
|
|
10230
|
+
import Joi40 from "joi";
|
|
10231
|
+
var transactionSchema = Joi40.object({
|
|
10232
|
+
_id: Joi40.string().hex().optional().allow("", null),
|
|
10233
|
+
payment: Joi40.string().required(),
|
|
10234
|
+
user: Joi40.string().hex().optional().allow("", null),
|
|
10235
|
+
org: Joi40.string().hex().optional().allow("", null),
|
|
10236
|
+
type: Joi40.string().required(),
|
|
10237
|
+
amount: Joi40.number().positive().min(0).required(),
|
|
10238
|
+
currency: Joi40.string().required(),
|
|
10239
|
+
description: Joi40.string().optional().allow("", null),
|
|
10240
|
+
metadata: Joi40.object({
|
|
10241
|
+
subscriptionId: Joi40.string().hex().optional().allow("", null),
|
|
10242
|
+
cycle: Joi40.number().optional().allow("", null),
|
|
10243
|
+
seats: Joi40.number().optional().allow("", null),
|
|
10244
|
+
promoCode: Joi40.string().optional().allow("", null)
|
|
8973
10245
|
}).optional().allow("", null),
|
|
8974
|
-
status:
|
|
8975
|
-
createdAt:
|
|
8976
|
-
updatedAt:
|
|
8977
|
-
deletedAt:
|
|
10246
|
+
status: Joi40.string().optional().allow("", null),
|
|
10247
|
+
createdAt: Joi40.string().optional().allow("", null),
|
|
10248
|
+
updatedAt: Joi40.string().optional().allow("", null),
|
|
10249
|
+
deletedAt: Joi40.string().optional().allow("", null)
|
|
8978
10250
|
});
|
|
8979
10251
|
|
|
8980
10252
|
// src/resources/verification/verification.controller.ts
|
|
8981
10253
|
import {
|
|
8982
|
-
AppError as
|
|
8983
|
-
BadRequestError as
|
|
8984
|
-
InternalServerError as
|
|
10254
|
+
AppError as AppError24,
|
|
10255
|
+
BadRequestError as BadRequestError55,
|
|
10256
|
+
InternalServerError as InternalServerError27
|
|
8985
10257
|
} from "@goweekdays/utils";
|
|
8986
|
-
import
|
|
10258
|
+
import Joi41 from "joi";
|
|
8987
10259
|
function useVerificationController() {
|
|
8988
10260
|
const {
|
|
8989
10261
|
createUserInvite: _createUserInvite,
|
|
@@ -8997,17 +10269,17 @@ function useVerificationController() {
|
|
|
8997
10269
|
} = useVerificationService();
|
|
8998
10270
|
const { getVerifications: _getVerifications } = useVerificationRepo();
|
|
8999
10271
|
async function createUserInvite(req, res, next) {
|
|
9000
|
-
const validation =
|
|
9001
|
-
email:
|
|
9002
|
-
app:
|
|
9003
|
-
role:
|
|
9004
|
-
roleName:
|
|
9005
|
-
org:
|
|
9006
|
-
orgName:
|
|
10272
|
+
const validation = Joi41.object({
|
|
10273
|
+
email: Joi41.string().email().required(),
|
|
10274
|
+
app: Joi41.string().required(),
|
|
10275
|
+
role: Joi41.string().hex().required(),
|
|
10276
|
+
roleName: Joi41.string().required(),
|
|
10277
|
+
org: Joi41.string().hex().optional().optional().allow("", null),
|
|
10278
|
+
orgName: Joi41.string().optional().optional().allow("", null)
|
|
9007
10279
|
});
|
|
9008
10280
|
const { error } = validation.validate(req.body);
|
|
9009
10281
|
if (error) {
|
|
9010
|
-
next(new
|
|
10282
|
+
next(new BadRequestError55(error.message));
|
|
9011
10283
|
return;
|
|
9012
10284
|
}
|
|
9013
10285
|
const email = req.body.email ?? "";
|
|
@@ -9035,10 +10307,10 @@ function useVerificationController() {
|
|
|
9035
10307
|
}
|
|
9036
10308
|
async function createForgetPassword(req, res, next) {
|
|
9037
10309
|
const email = req.body.email || "";
|
|
9038
|
-
const validation =
|
|
10310
|
+
const validation = Joi41.string().email().required();
|
|
9039
10311
|
const { error } = validation.validate(email);
|
|
9040
10312
|
if (error) {
|
|
9041
|
-
next(new
|
|
10313
|
+
next(new BadRequestError55(error.message));
|
|
9042
10314
|
return;
|
|
9043
10315
|
}
|
|
9044
10316
|
try {
|
|
@@ -9048,26 +10320,26 @@ function useVerificationController() {
|
|
|
9048
10320
|
});
|
|
9049
10321
|
return;
|
|
9050
10322
|
} catch (error2) {
|
|
9051
|
-
if (error2 instanceof
|
|
10323
|
+
if (error2 instanceof AppError24) {
|
|
9052
10324
|
next(error2);
|
|
9053
10325
|
} else {
|
|
9054
|
-
next(new
|
|
10326
|
+
next(new InternalServerError27("An unexpected error occurred"));
|
|
9055
10327
|
}
|
|
9056
10328
|
}
|
|
9057
10329
|
}
|
|
9058
10330
|
async function getVerifications(req, res, next) {
|
|
9059
|
-
const validation =
|
|
9060
|
-
status:
|
|
9061
|
-
search:
|
|
9062
|
-
page:
|
|
9063
|
-
type:
|
|
9064
|
-
email:
|
|
9065
|
-
app:
|
|
9066
|
-
org:
|
|
10331
|
+
const validation = Joi41.object({
|
|
10332
|
+
status: Joi41.string().required(),
|
|
10333
|
+
search: Joi41.string().optional().allow("", null),
|
|
10334
|
+
page: Joi41.number().required(),
|
|
10335
|
+
type: Joi41.string().optional().allow("", null),
|
|
10336
|
+
email: Joi41.string().optional().allow("", null),
|
|
10337
|
+
app: Joi41.string().optional().allow("", null),
|
|
10338
|
+
org: Joi41.string().optional().allow("", null)
|
|
9067
10339
|
});
|
|
9068
10340
|
const { error } = validation.validate(req.query);
|
|
9069
10341
|
if (error) {
|
|
9070
|
-
next(new
|
|
10342
|
+
next(new BadRequestError55(error.message));
|
|
9071
10343
|
return;
|
|
9072
10344
|
}
|
|
9073
10345
|
const status = req.query.status ?? "";
|
|
@@ -9100,10 +10372,10 @@ function useVerificationController() {
|
|
|
9100
10372
|
}
|
|
9101
10373
|
async function verify(req, res, next) {
|
|
9102
10374
|
const id = req.params.id || "";
|
|
9103
|
-
const validation =
|
|
10375
|
+
const validation = Joi41.string().hex().required();
|
|
9104
10376
|
const { error } = validation.validate(id);
|
|
9105
10377
|
if (error) {
|
|
9106
|
-
next(new
|
|
10378
|
+
next(new BadRequestError55(error.message));
|
|
9107
10379
|
return;
|
|
9108
10380
|
}
|
|
9109
10381
|
try {
|
|
@@ -9116,10 +10388,10 @@ function useVerificationController() {
|
|
|
9116
10388
|
}
|
|
9117
10389
|
async function cancelUserInvitation(req, res, next) {
|
|
9118
10390
|
const otpId = req.params.id || "";
|
|
9119
|
-
const validation =
|
|
10391
|
+
const validation = Joi41.string().hex().required();
|
|
9120
10392
|
const { error } = validation.validate(otpId);
|
|
9121
10393
|
if (error) {
|
|
9122
|
-
next(new
|
|
10394
|
+
next(new BadRequestError55(error.message));
|
|
9123
10395
|
return;
|
|
9124
10396
|
}
|
|
9125
10397
|
try {
|
|
@@ -9132,10 +10404,10 @@ function useVerificationController() {
|
|
|
9132
10404
|
}
|
|
9133
10405
|
}
|
|
9134
10406
|
async function signUp(req, res, next) {
|
|
9135
|
-
const validation =
|
|
10407
|
+
const validation = Joi41.string().email().required();
|
|
9136
10408
|
const { error } = validation.validate(req.body.email);
|
|
9137
10409
|
if (error) {
|
|
9138
|
-
next(new
|
|
10410
|
+
next(new BadRequestError55(error.message));
|
|
9139
10411
|
return;
|
|
9140
10412
|
}
|
|
9141
10413
|
const email = req.body.email ?? "";
|
|
@@ -9150,7 +10422,7 @@ function useVerificationController() {
|
|
|
9150
10422
|
async function inviteMember(req, res, next) {
|
|
9151
10423
|
const { error } = schemaInviteMember.validate(req.body);
|
|
9152
10424
|
if (error) {
|
|
9153
|
-
next(new
|
|
10425
|
+
next(new BadRequestError55(error.message));
|
|
9154
10426
|
return;
|
|
9155
10427
|
}
|
|
9156
10428
|
try {
|
|
@@ -9163,10 +10435,10 @@ function useVerificationController() {
|
|
|
9163
10435
|
}
|
|
9164
10436
|
async function cancelInviteMember(req, res, next) {
|
|
9165
10437
|
const id = req.params.id || "";
|
|
9166
|
-
const validation =
|
|
10438
|
+
const validation = Joi41.string().hex().required();
|
|
9167
10439
|
const { error } = validation.validate(id);
|
|
9168
10440
|
if (error) {
|
|
9169
|
-
next(new
|
|
10441
|
+
next(new BadRequestError55(error.message));
|
|
9170
10442
|
return;
|
|
9171
10443
|
}
|
|
9172
10444
|
try {
|
|
@@ -9179,10 +10451,10 @@ function useVerificationController() {
|
|
|
9179
10451
|
}
|
|
9180
10452
|
async function forgetPassword(req, res, next) {
|
|
9181
10453
|
const email = req.body.email ?? "";
|
|
9182
|
-
const validation =
|
|
10454
|
+
const validation = Joi41.string().email().required();
|
|
9183
10455
|
const { error } = validation.validate(email);
|
|
9184
10456
|
if (error) {
|
|
9185
|
-
next(new
|
|
10457
|
+
next(new BadRequestError55(error.message));
|
|
9186
10458
|
return;
|
|
9187
10459
|
}
|
|
9188
10460
|
try {
|
|
@@ -9192,10 +10464,10 @@ function useVerificationController() {
|
|
|
9192
10464
|
});
|
|
9193
10465
|
return;
|
|
9194
10466
|
} catch (error2) {
|
|
9195
|
-
if (error2 instanceof
|
|
10467
|
+
if (error2 instanceof AppError24) {
|
|
9196
10468
|
next(error2);
|
|
9197
10469
|
} else {
|
|
9198
|
-
next(new
|
|
10470
|
+
next(new InternalServerError27("An unexpected error occurred"));
|
|
9199
10471
|
}
|
|
9200
10472
|
}
|
|
9201
10473
|
}
|
|
@@ -9252,6 +10524,7 @@ export {
|
|
|
9252
10524
|
XENDIT_BASE_URL,
|
|
9253
10525
|
XENDIT_SECRET_KEY,
|
|
9254
10526
|
addressSchema,
|
|
10527
|
+
currencies,
|
|
9255
10528
|
isDev,
|
|
9256
10529
|
modelApp,
|
|
9257
10530
|
modelMember,
|
|
@@ -9259,7 +10532,10 @@ export {
|
|
|
9259
10532
|
modelPSGC,
|
|
9260
10533
|
modelPermission,
|
|
9261
10534
|
modelPermissionGroup,
|
|
10535
|
+
modelPlan,
|
|
9262
10536
|
modelRole,
|
|
10537
|
+
modelSubscription,
|
|
10538
|
+
modelSubscriptionTransaction,
|
|
9263
10539
|
modelUser,
|
|
9264
10540
|
modelVerification,
|
|
9265
10541
|
schemaApp,
|
|
@@ -9271,13 +10547,20 @@ export {
|
|
|
9271
10547
|
schemaMemberRole,
|
|
9272
10548
|
schemaMemberStatus,
|
|
9273
10549
|
schemaOrg,
|
|
10550
|
+
schemaOrgAdd,
|
|
10551
|
+
schemaOrgUpdate,
|
|
9274
10552
|
schemaPSGC,
|
|
9275
10553
|
schemaPermission,
|
|
9276
10554
|
schemaPermissionGroup,
|
|
9277
10555
|
schemaPermissionGroupUpdate,
|
|
9278
10556
|
schemaPermissionUpdate,
|
|
10557
|
+
schemaPlan,
|
|
9279
10558
|
schemaRole,
|
|
9280
10559
|
schemaRoleUpdate,
|
|
10560
|
+
schemaSubscription,
|
|
10561
|
+
schemaSubscriptionSeats,
|
|
10562
|
+
schemaSubscriptionTransaction,
|
|
10563
|
+
schemaSubscriptionUpdate,
|
|
9281
10564
|
schemaUpdateOptions,
|
|
9282
10565
|
schemaUser,
|
|
9283
10566
|
schemaVerification,
|
|
@@ -9314,9 +10597,16 @@ export {
|
|
|
9314
10597
|
usePermissionGroupService,
|
|
9315
10598
|
usePermissionRepo,
|
|
9316
10599
|
usePermissionService,
|
|
10600
|
+
usePlanController,
|
|
10601
|
+
usePlanRepo,
|
|
10602
|
+
usePlanService,
|
|
9317
10603
|
useRoleController,
|
|
9318
10604
|
useRoleRepo,
|
|
9319
10605
|
useRoleService,
|
|
10606
|
+
useSubscriptionController,
|
|
10607
|
+
useSubscriptionRepo,
|
|
10608
|
+
useSubscriptionTransactionController,
|
|
10609
|
+
useSubscriptionTransactionRepo,
|
|
9320
10610
|
useUserController,
|
|
9321
10611
|
useUserRepo,
|
|
9322
10612
|
useUserService,
|