@goweekdays/core 2.3.1 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.d.ts +130 -7
- package/dist/index.js +2054 -731
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2049 -718
- 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
|
|
|
@@ -1801,9 +1801,10 @@ function useMemberRepo() {
|
|
|
1801
1801
|
}
|
|
1802
1802
|
}
|
|
1803
1803
|
async function getAll({ search, limit, page, user, org, app, status } = {}) {
|
|
1804
|
-
limit = limit > 0 ? limit : 10;
|
|
1804
|
+
limit = limit && limit > 0 ? limit : 10;
|
|
1805
1805
|
search = search || "";
|
|
1806
|
-
page = page > 0 ? page - 1 : 0;
|
|
1806
|
+
page = page && page > 0 ? page - 1 : 0;
|
|
1807
|
+
status = status ?? "active";
|
|
1807
1808
|
const query = { app, status };
|
|
1808
1809
|
const cacheKeyOptions = { app, status, limit, page };
|
|
1809
1810
|
if (user) {
|
|
@@ -4154,6 +4155,33 @@ function usePermissionGroupService() {
|
|
|
4154
4155
|
description: "Allow user to revoke invitations"
|
|
4155
4156
|
}
|
|
4156
4157
|
]
|
|
4158
|
+
},
|
|
4159
|
+
{
|
|
4160
|
+
key: "billing",
|
|
4161
|
+
label: "Billing",
|
|
4162
|
+
permissions: [
|
|
4163
|
+
{
|
|
4164
|
+
key: "billing.view",
|
|
4165
|
+
name: "View Billing",
|
|
4166
|
+
description: "Allow user to view billing"
|
|
4167
|
+
}
|
|
4168
|
+
]
|
|
4169
|
+
},
|
|
4170
|
+
{
|
|
4171
|
+
key: "setting",
|
|
4172
|
+
label: "Setting",
|
|
4173
|
+
permissions: [
|
|
4174
|
+
{
|
|
4175
|
+
key: "setting.view",
|
|
4176
|
+
name: "View Setting",
|
|
4177
|
+
description: "Allow user to view setting"
|
|
4178
|
+
},
|
|
4179
|
+
{
|
|
4180
|
+
key: "setting.edit.details",
|
|
4181
|
+
name: "Edit Setting Details",
|
|
4182
|
+
description: "Allow user to edit setting details"
|
|
4183
|
+
}
|
|
4184
|
+
]
|
|
4157
4185
|
}
|
|
4158
4186
|
];
|
|
4159
4187
|
for (const app of apps.items) {
|
|
@@ -4588,13 +4616,25 @@ function usePermissionGroupController() {
|
|
|
4588
4616
|
import { BadRequestError as BadRequestError23 } from "@goweekdays/utils";
|
|
4589
4617
|
import Joi17 from "joi";
|
|
4590
4618
|
import { ObjectId as ObjectId15 } from "mongodb";
|
|
4591
|
-
var
|
|
4619
|
+
var schema = {
|
|
4592
4620
|
name: Joi17.string().max(255).required(),
|
|
4593
4621
|
description: Joi17.string().max(1024).optional().allow("", null),
|
|
4594
|
-
email: Joi17.string().email().max(255).
|
|
4595
|
-
contact: Joi17.string().max(50).optional().allow("", null)
|
|
4622
|
+
email: Joi17.string().email().max(255).required(),
|
|
4623
|
+
contact: Joi17.string().max(50).optional().allow("", null)
|
|
4624
|
+
};
|
|
4625
|
+
var schemaOrg = Joi17.object({
|
|
4626
|
+
...schema,
|
|
4596
4627
|
createdBy: Joi17.string().hex().required()
|
|
4597
4628
|
});
|
|
4629
|
+
var schemaOrgAdd = Joi17.object({
|
|
4630
|
+
...schema,
|
|
4631
|
+
createdBy: Joi17.string().hex().required(),
|
|
4632
|
+
seats: Joi17.number().required()
|
|
4633
|
+
});
|
|
4634
|
+
var schemaOrgUpdate = Joi17.object({
|
|
4635
|
+
...schema,
|
|
4636
|
+
_id: Joi17.string().hex().required()
|
|
4637
|
+
});
|
|
4598
4638
|
function modelOrg(value) {
|
|
4599
4639
|
const { error } = schemaOrg.validate(value);
|
|
4600
4640
|
if (error) {
|
|
@@ -4877,6 +4917,30 @@ function useOrgRepo() {
|
|
|
4877
4917
|
throw new InternalServerError11("Failed to delete organization.");
|
|
4878
4918
|
}
|
|
4879
4919
|
}
|
|
4920
|
+
async function updateById(_id, options) {
|
|
4921
|
+
const { error } = schemaOrgUpdate.validate({ ...options, _id });
|
|
4922
|
+
if (error) {
|
|
4923
|
+
throw new BadRequestError24(error.message);
|
|
4924
|
+
}
|
|
4925
|
+
try {
|
|
4926
|
+
_id = new ObjectId16(_id);
|
|
4927
|
+
} catch (error2) {
|
|
4928
|
+
throw new BadRequestError24("Invalid org ID.");
|
|
4929
|
+
}
|
|
4930
|
+
try {
|
|
4931
|
+
await collection.updateOne(
|
|
4932
|
+
{ _id },
|
|
4933
|
+
{ $set: { ...options, updatedAt: /* @__PURE__ */ new Date() } }
|
|
4934
|
+
);
|
|
4935
|
+
delCachedData();
|
|
4936
|
+
} catch (error2) {
|
|
4937
|
+
const isDuplicated = error2.message.includes("duplicate");
|
|
4938
|
+
if (isDuplicated) {
|
|
4939
|
+
throw new BadRequestError24("Organization name already exist.");
|
|
4940
|
+
}
|
|
4941
|
+
throw new InternalServerError11("Failed to update org info.");
|
|
4942
|
+
}
|
|
4943
|
+
}
|
|
4880
4944
|
return {
|
|
4881
4945
|
createIndexes,
|
|
4882
4946
|
add,
|
|
@@ -4884,12 +4948,13 @@ function useOrgRepo() {
|
|
|
4884
4948
|
getById,
|
|
4885
4949
|
updateFieldById,
|
|
4886
4950
|
deleteById,
|
|
4887
|
-
getByName
|
|
4951
|
+
getByName,
|
|
4952
|
+
updateById
|
|
4888
4953
|
};
|
|
4889
4954
|
}
|
|
4890
4955
|
|
|
4891
4956
|
// src/resources/organization/organization.service.ts
|
|
4892
|
-
import { BadRequestError as
|
|
4957
|
+
import { BadRequestError as BadRequestError37, useAtlas as useAtlas17 } from "@goweekdays/utils";
|
|
4893
4958
|
|
|
4894
4959
|
// src/resources/member/member.controller.ts
|
|
4895
4960
|
import Joi20 from "joi";
|
|
@@ -5304,6 +5369,44 @@ function useMemberController() {
|
|
|
5304
5369
|
next(error2);
|
|
5305
5370
|
}
|
|
5306
5371
|
}
|
|
5372
|
+
async function getAllByAppUser(req, res, next) {
|
|
5373
|
+
const limit = Number(req.query.limit) ?? 10;
|
|
5374
|
+
const search = req.query.search ?? "";
|
|
5375
|
+
const page = Number(req.query.page) ?? 1;
|
|
5376
|
+
const user = req.params.user ?? "";
|
|
5377
|
+
const app = req.params.app ?? "";
|
|
5378
|
+
const validation = Joi20.object({
|
|
5379
|
+
limit: Joi20.number().min(10).max(50).allow(null, ""),
|
|
5380
|
+
search: Joi20.string().optional().allow("", null),
|
|
5381
|
+
page: Joi20.number().optional().allow(null, ""),
|
|
5382
|
+
app: Joi20.string().required(),
|
|
5383
|
+
user: Joi20.string().hex().required()
|
|
5384
|
+
});
|
|
5385
|
+
const { error } = validation.validate({
|
|
5386
|
+
search,
|
|
5387
|
+
page,
|
|
5388
|
+
limit,
|
|
5389
|
+
user,
|
|
5390
|
+
app
|
|
5391
|
+
});
|
|
5392
|
+
if (error) {
|
|
5393
|
+
next(new BadRequestError28(error.message));
|
|
5394
|
+
return;
|
|
5395
|
+
}
|
|
5396
|
+
try {
|
|
5397
|
+
const items = await _getAll({
|
|
5398
|
+
search,
|
|
5399
|
+
page,
|
|
5400
|
+
limit,
|
|
5401
|
+
user,
|
|
5402
|
+
app
|
|
5403
|
+
});
|
|
5404
|
+
res.json(items);
|
|
5405
|
+
return;
|
|
5406
|
+
} catch (error2) {
|
|
5407
|
+
next(error2);
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5307
5410
|
async function getOrgsByMembership(req, res, next) {
|
|
5308
5411
|
const limit = Number(req.query.limit) ?? 10;
|
|
5309
5412
|
const search = req.query.search ?? "";
|
|
@@ -5410,166 +5513,1359 @@ function useMemberController() {
|
|
|
5410
5513
|
getByUserType,
|
|
5411
5514
|
updateRoleById,
|
|
5412
5515
|
updateStatusById,
|
|
5413
|
-
deleteById
|
|
5516
|
+
deleteById,
|
|
5517
|
+
getAllByAppUser
|
|
5414
5518
|
};
|
|
5415
5519
|
}
|
|
5416
5520
|
|
|
5417
|
-
// src/resources/
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5521
|
+
// src/resources/subscription/subscription.model.ts
|
|
5522
|
+
import { BadRequestError as BadRequestError29 } from "@goweekdays/utils";
|
|
5523
|
+
import Joi21 from "joi";
|
|
5524
|
+
import { ObjectId as ObjectId17 } from "mongodb";
|
|
5525
|
+
var schema2 = {
|
|
5526
|
+
seats: Joi21.number().integer().min(1).required(),
|
|
5527
|
+
paidSeats: Joi21.number().integer().min(0).required(),
|
|
5528
|
+
amount: Joi21.number().positive().required(),
|
|
5529
|
+
promoCode: Joi21.string().optional().allow("", null),
|
|
5530
|
+
nextBillingDate: Joi21.date().optional().allow("", null)
|
|
5531
|
+
};
|
|
5532
|
+
var schemaSubscription = Joi21.object({
|
|
5533
|
+
...schema2,
|
|
5534
|
+
org: Joi21.string().hex().length(24).required(),
|
|
5535
|
+
currency: Joi21.string().length(3).required(),
|
|
5536
|
+
billingCycle: Joi21.string().valid("monthly", "yearly").required()
|
|
5537
|
+
});
|
|
5538
|
+
var schemaSubscriptionUpdate = Joi21.object({
|
|
5539
|
+
...schema2,
|
|
5540
|
+
status: Joi21.string().optional().allow("", null)
|
|
5541
|
+
});
|
|
5542
|
+
var schemaSubscriptionSeats = Joi21.object({
|
|
5543
|
+
id: Joi21.string().hex().length(24).required(),
|
|
5544
|
+
seats: Joi21.number().integer().min(1).required(),
|
|
5545
|
+
amount: Joi21.number().positive().optional().allow(null, 0),
|
|
5546
|
+
user: Joi21.string().hex().length(24).required()
|
|
5547
|
+
});
|
|
5548
|
+
function modelSubscription(data) {
|
|
5549
|
+
const { error } = schemaSubscription.validate(data);
|
|
5550
|
+
if (error) {
|
|
5551
|
+
throw new BadRequestError29(`Invalid subscription data: ${error.message}`);
|
|
5552
|
+
}
|
|
5553
|
+
if (data._id && typeof data._id === "string") {
|
|
5429
5554
|
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();
|
|
5555
|
+
data._id = new ObjectId17(data._id);
|
|
5556
|
+
} catch (error2) {
|
|
5557
|
+
throw new BadRequestError29("Invalid subscription ID.");
|
|
5478
5558
|
}
|
|
5479
5559
|
}
|
|
5560
|
+
try {
|
|
5561
|
+
data.org = new ObjectId17(data.org);
|
|
5562
|
+
} catch (error2) {
|
|
5563
|
+
throw new BadRequestError29("Invalid organization ID.");
|
|
5564
|
+
}
|
|
5480
5565
|
return {
|
|
5481
|
-
|
|
5566
|
+
_id: data._id,
|
|
5567
|
+
org: data.org,
|
|
5568
|
+
seats: data.seats,
|
|
5569
|
+
paidSeats: data.paidSeats,
|
|
5570
|
+
amount: data.amount,
|
|
5571
|
+
currency: data.currency,
|
|
5572
|
+
billingCycle: data.billingCycle,
|
|
5573
|
+
promoCode: data.promoCode,
|
|
5574
|
+
status: data.status ?? "active",
|
|
5575
|
+
nextBillingDate: data.nextBillingDate,
|
|
5576
|
+
createdAt: data.createdAt ?? /* @__PURE__ */ new Date(),
|
|
5577
|
+
updatedAt: data.updatedAt ?? ""
|
|
5482
5578
|
};
|
|
5483
5579
|
}
|
|
5484
5580
|
|
|
5485
|
-
// src/resources/
|
|
5486
|
-
import {
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5581
|
+
// src/resources/subscription/subscription.repository.ts
|
|
5582
|
+
import {
|
|
5583
|
+
AppError as AppError11,
|
|
5584
|
+
BadRequestError as BadRequestError30,
|
|
5585
|
+
InternalServerError as InternalServerError15,
|
|
5586
|
+
logger as logger16,
|
|
5587
|
+
makeCacheKey as makeCacheKey11,
|
|
5588
|
+
paginate as paginate9,
|
|
5589
|
+
useAtlas as useAtlas13,
|
|
5590
|
+
useCache as useCache12
|
|
5591
|
+
} from "@goweekdays/utils";
|
|
5592
|
+
import Joi22 from "joi";
|
|
5593
|
+
import { ObjectId as ObjectId18 } from "mongodb";
|
|
5594
|
+
function useSubscriptionRepo() {
|
|
5595
|
+
const db = useAtlas13.getDb();
|
|
5596
|
+
if (!db) {
|
|
5597
|
+
throw new InternalServerError15("Unable to connect to server.");
|
|
5598
|
+
}
|
|
5599
|
+
const namespace_collection = "subscriptions";
|
|
5600
|
+
const collection = db.collection(namespace_collection);
|
|
5601
|
+
const { getCache, setCache, delNamespace } = useCache12(namespace_collection);
|
|
5602
|
+
function delCachedData() {
|
|
5603
|
+
delNamespace().then(() => {
|
|
5604
|
+
logger16.log({
|
|
5605
|
+
level: "info",
|
|
5606
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
5508
5607
|
});
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5608
|
+
}).catch((err) => {
|
|
5609
|
+
logger16.log({
|
|
5610
|
+
level: "error",
|
|
5611
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
5612
|
+
});
|
|
5613
|
+
});
|
|
5513
5614
|
}
|
|
5514
|
-
async function
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5615
|
+
async function createIndexes() {
|
|
5616
|
+
try {
|
|
5617
|
+
await collection.createIndexes([
|
|
5618
|
+
{
|
|
5619
|
+
key: {
|
|
5620
|
+
org: 1
|
|
5621
|
+
},
|
|
5622
|
+
name: "org_index"
|
|
5623
|
+
},
|
|
5624
|
+
{
|
|
5625
|
+
key: { org: 1, status: 1 },
|
|
5626
|
+
name: "org_status_index"
|
|
5627
|
+
}
|
|
5628
|
+
]);
|
|
5629
|
+
} catch (error) {
|
|
5528
5630
|
}
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5631
|
+
}
|
|
5632
|
+
createIndexes().catch((error) => {
|
|
5633
|
+
logger16.log({
|
|
5634
|
+
level: "error",
|
|
5635
|
+
message: `Failed to create indexes for subscriptions collection: ${error.message}`
|
|
5534
5636
|
});
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
next(new BadRequestError30(error.message));
|
|
5538
|
-
return;
|
|
5539
|
-
}
|
|
5637
|
+
});
|
|
5638
|
+
async function add(value, session) {
|
|
5540
5639
|
try {
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5640
|
+
value = modelSubscription(value);
|
|
5641
|
+
const result = await collection.insertOne(value, { session });
|
|
5642
|
+
delCachedData();
|
|
5643
|
+
return result.insertedId.toString();
|
|
5644
|
+
} catch (error) {
|
|
5645
|
+
logger16.log({
|
|
5646
|
+
level: "error",
|
|
5647
|
+
message: `${error}`
|
|
5648
|
+
});
|
|
5649
|
+
if (error instanceof AppError11) {
|
|
5650
|
+
throw error;
|
|
5651
|
+
}
|
|
5652
|
+
throw new InternalServerError15("Failed to add subscription.");
|
|
5546
5653
|
}
|
|
5547
5654
|
}
|
|
5548
|
-
async function getAll(
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
}
|
|
5556
|
-
const
|
|
5655
|
+
async function getAll({
|
|
5656
|
+
page = 1,
|
|
5657
|
+
limit = 10,
|
|
5658
|
+
search = "",
|
|
5659
|
+
status = "active"
|
|
5660
|
+
} = {}) {
|
|
5661
|
+
page = page < 1 ? page - 1 : page;
|
|
5662
|
+
const query = { status };
|
|
5663
|
+
const cacheKeyOptions = {
|
|
5664
|
+
page,
|
|
5665
|
+
limit,
|
|
5666
|
+
search,
|
|
5667
|
+
status,
|
|
5668
|
+
tag: "getAll"
|
|
5669
|
+
};
|
|
5670
|
+
if (search) {
|
|
5671
|
+
query.$text = { $search: search };
|
|
5672
|
+
}
|
|
5673
|
+
const cacheKey = makeCacheKey11(namespace_collection, cacheKeyOptions);
|
|
5674
|
+
try {
|
|
5675
|
+
const cachedData = await getCache(cacheKey);
|
|
5676
|
+
if (cachedData) {
|
|
5677
|
+
return cachedData;
|
|
5678
|
+
}
|
|
5679
|
+
const items = await collection.aggregate([
|
|
5680
|
+
{ $match: query },
|
|
5681
|
+
{ $skip: page * limit },
|
|
5682
|
+
{ $limit: limit }
|
|
5683
|
+
]).toArray();
|
|
5684
|
+
const length = await collection.countDocuments(query);
|
|
5685
|
+
const data = paginate9(
|
|
5686
|
+
items,
|
|
5687
|
+
page,
|
|
5688
|
+
limit,
|
|
5689
|
+
length
|
|
5690
|
+
);
|
|
5691
|
+
setCache(cacheKey, data).then(() => {
|
|
5692
|
+
logger16.log({
|
|
5693
|
+
level: "info",
|
|
5694
|
+
message: `Cache set for getAll subscription: ${cacheKey}`
|
|
5695
|
+
});
|
|
5696
|
+
}).catch((err) => {
|
|
5697
|
+
logger16.log({
|
|
5698
|
+
level: "error",
|
|
5699
|
+
message: `Failed to set cache for getAll subscription: ${err.message}`
|
|
5700
|
+
});
|
|
5701
|
+
});
|
|
5702
|
+
return data;
|
|
5703
|
+
} catch (error) {
|
|
5704
|
+
throw new InternalServerError15("Failed to get subscriptions.");
|
|
5705
|
+
}
|
|
5706
|
+
}
|
|
5707
|
+
async function getByOrg(org) {
|
|
5708
|
+
const { error } = Joi22.string().hex().length(24).required().validate(org);
|
|
5709
|
+
if (error) {
|
|
5710
|
+
throw new Error(`Invalid org ID: ${error.message}`);
|
|
5711
|
+
}
|
|
5712
|
+
try {
|
|
5713
|
+
org = new ObjectId18(org);
|
|
5714
|
+
} catch (error2) {
|
|
5715
|
+
throw new BadRequestError30("Invalid org ID.");
|
|
5716
|
+
}
|
|
5717
|
+
try {
|
|
5718
|
+
const cacheKey = makeCacheKey11(namespace_collection, {
|
|
5719
|
+
org: String(org),
|
|
5720
|
+
tag: "getByOrg"
|
|
5721
|
+
});
|
|
5722
|
+
const cachedData = await getCache(cacheKey);
|
|
5723
|
+
if (cachedData) {
|
|
5724
|
+
return cachedData;
|
|
5725
|
+
}
|
|
5726
|
+
const data = await collection.findOne({
|
|
5727
|
+
org,
|
|
5728
|
+
status: { $ne: "deleted" }
|
|
5729
|
+
});
|
|
5730
|
+
setCache(cacheKey, data).then(() => {
|
|
5731
|
+
logger16.log({
|
|
5732
|
+
level: "info",
|
|
5733
|
+
message: `Cache set for getByOrg subscription: ${cacheKey}`
|
|
5734
|
+
});
|
|
5735
|
+
}).catch((err) => {
|
|
5736
|
+
logger16.log({
|
|
5737
|
+
level: "error",
|
|
5738
|
+
message: `Failed to set cache for getByOrg subscription: ${err.message}`
|
|
5739
|
+
});
|
|
5740
|
+
});
|
|
5741
|
+
return data;
|
|
5742
|
+
} catch (error2) {
|
|
5743
|
+
throw new InternalServerError15("Failed to get subscription.");
|
|
5744
|
+
}
|
|
5745
|
+
}
|
|
5746
|
+
async function getById(_id) {
|
|
5747
|
+
const { error } = Joi22.string().hex().length(24).required().validate(_id);
|
|
5748
|
+
if (error) {
|
|
5749
|
+
throw new Error(`Invalid subscription ID: ${error.message}`);
|
|
5750
|
+
}
|
|
5751
|
+
try {
|
|
5752
|
+
_id = new ObjectId18(_id);
|
|
5753
|
+
} catch (error2) {
|
|
5754
|
+
throw new BadRequestError30("Invalid subscription ID.");
|
|
5755
|
+
}
|
|
5756
|
+
try {
|
|
5757
|
+
const cacheKey = makeCacheKey11(namespace_collection, {
|
|
5758
|
+
_id: String(_id),
|
|
5759
|
+
tag: "getById"
|
|
5760
|
+
});
|
|
5761
|
+
const cachedData = await getCache(cacheKey);
|
|
5762
|
+
if (cachedData) {
|
|
5763
|
+
return cachedData;
|
|
5764
|
+
}
|
|
5765
|
+
const data = await collection.findOne({
|
|
5766
|
+
_id,
|
|
5767
|
+
status: { $ne: "deleted" }
|
|
5768
|
+
});
|
|
5769
|
+
setCache(cacheKey, data).then(() => {
|
|
5770
|
+
logger16.log({
|
|
5771
|
+
level: "info",
|
|
5772
|
+
message: `Cache set for getById subscription: ${cacheKey}`
|
|
5773
|
+
});
|
|
5774
|
+
}).catch((err) => {
|
|
5775
|
+
logger16.log({
|
|
5776
|
+
level: "error",
|
|
5777
|
+
message: `Failed to set cache for getById subscription: ${err.message}`
|
|
5778
|
+
});
|
|
5779
|
+
});
|
|
5780
|
+
return data;
|
|
5781
|
+
} catch (error2) {
|
|
5782
|
+
throw new InternalServerError15("Failed to get subscription.");
|
|
5783
|
+
}
|
|
5784
|
+
}
|
|
5785
|
+
async function deleteById(_id) {
|
|
5786
|
+
const { error } = Joi22.string().hex().length(24).required().validate(_id);
|
|
5787
|
+
if (error) {
|
|
5788
|
+
throw new Error(`Invalid subscription ID: ${error.message}`);
|
|
5789
|
+
}
|
|
5790
|
+
try {
|
|
5791
|
+
_id = new ObjectId18(_id);
|
|
5792
|
+
} catch (error2) {
|
|
5793
|
+
throw new BadRequestError30("Invalid subscription ID.");
|
|
5794
|
+
}
|
|
5795
|
+
try {
|
|
5796
|
+
const result = await collection.updateOne(
|
|
5797
|
+
{ _id },
|
|
5798
|
+
{ $set: { status: "deleted" } }
|
|
5799
|
+
);
|
|
5800
|
+
if (result.modifiedCount === 0) {
|
|
5801
|
+
throw new InternalServerError15("Failed to delete subscription.");
|
|
5802
|
+
}
|
|
5803
|
+
delCachedData();
|
|
5804
|
+
return "Successfully deleted subscription.";
|
|
5805
|
+
} catch (error2) {
|
|
5806
|
+
if (error2 instanceof AppError11) {
|
|
5807
|
+
throw error2;
|
|
5808
|
+
}
|
|
5809
|
+
throw new InternalServerError15("Failed to delete subscription.");
|
|
5810
|
+
}
|
|
5811
|
+
}
|
|
5812
|
+
async function updateById(_id, options, session) {
|
|
5813
|
+
const { error: errorId } = Joi22.string().hex().length(24).required().validate(_id);
|
|
5814
|
+
if (errorId) {
|
|
5815
|
+
throw new Error(`Invalid subscription ID: ${errorId.message}`);
|
|
5816
|
+
}
|
|
5817
|
+
const { error } = schemaSubscriptionUpdate.validate(options);
|
|
5818
|
+
if (error) {
|
|
5819
|
+
throw new BadRequestError30(
|
|
5820
|
+
`Invalid subscription update data: ${error.message}`
|
|
5821
|
+
);
|
|
5822
|
+
}
|
|
5823
|
+
try {
|
|
5824
|
+
_id = new ObjectId18(_id);
|
|
5825
|
+
} catch (error2) {
|
|
5826
|
+
throw new BadRequestError30("Invalid subscription ID.");
|
|
5827
|
+
}
|
|
5828
|
+
try {
|
|
5829
|
+
const result = await collection.updateOne(
|
|
5830
|
+
{ _id },
|
|
5831
|
+
{ $set: { ...options, updatedAt: /* @__PURE__ */ new Date() } },
|
|
5832
|
+
{ session }
|
|
5833
|
+
);
|
|
5834
|
+
if (result.modifiedCount === 0) {
|
|
5835
|
+
throw new InternalServerError15("Failed to update subscription.");
|
|
5836
|
+
}
|
|
5837
|
+
delCachedData();
|
|
5838
|
+
return "Successfully updated subscription.";
|
|
5839
|
+
} catch (error2) {
|
|
5840
|
+
if (error2 instanceof AppError11) {
|
|
5841
|
+
throw error2;
|
|
5842
|
+
}
|
|
5843
|
+
throw new InternalServerError15("Failed to update subscription.");
|
|
5844
|
+
}
|
|
5845
|
+
}
|
|
5846
|
+
return {
|
|
5847
|
+
add,
|
|
5848
|
+
getAll,
|
|
5849
|
+
getByOrg,
|
|
5850
|
+
getById,
|
|
5851
|
+
deleteById,
|
|
5852
|
+
updateById
|
|
5853
|
+
};
|
|
5854
|
+
}
|
|
5855
|
+
|
|
5856
|
+
// src/resources/subscription/subscription.controller.ts
|
|
5857
|
+
import Joi24 from "joi";
|
|
5858
|
+
import { BadRequestError as BadRequestError33 } from "@goweekdays/utils";
|
|
5859
|
+
|
|
5860
|
+
// src/resources/subscription/subscription.service.ts
|
|
5861
|
+
import { BadRequestError as BadRequestError32, useAtlas as useAtlas15 } from "@goweekdays/utils";
|
|
5862
|
+
|
|
5863
|
+
// src/resources/subscription/subscription.transaction.repository.ts
|
|
5864
|
+
import {
|
|
5865
|
+
AppError as AppError12,
|
|
5866
|
+
InternalServerError as InternalServerError16,
|
|
5867
|
+
logger as logger17,
|
|
5868
|
+
makeCacheKey as makeCacheKey12,
|
|
5869
|
+
paginate as paginate10,
|
|
5870
|
+
useAtlas as useAtlas14,
|
|
5871
|
+
useCache as useCache13
|
|
5872
|
+
} from "@goweekdays/utils";
|
|
5873
|
+
|
|
5874
|
+
// src/resources/subscription/subscription.transaction.model.ts
|
|
5875
|
+
import { BadRequestError as BadRequestError31 } from "@goweekdays/utils";
|
|
5876
|
+
import Joi23 from "joi";
|
|
5877
|
+
import { ObjectId as ObjectId19 } from "mongodb";
|
|
5878
|
+
var schemaSubscriptionTransaction = Joi23.object({
|
|
5879
|
+
subscription: Joi23.string().hex().length(24).required(),
|
|
5880
|
+
amount: Joi23.number().positive().required(),
|
|
5881
|
+
currency: Joi23.string().length(3).required(),
|
|
5882
|
+
type: Joi23.string().valid("initiate", "add-seat", "remove-seat", "renewal").required(),
|
|
5883
|
+
description: Joi23.string().max(255).optional().allow("", null),
|
|
5884
|
+
createdBy: Joi23.string().hex().length(24).required(),
|
|
5885
|
+
createdByName: Joi23.string().optional().allow("", null)
|
|
5886
|
+
});
|
|
5887
|
+
function modelSubscriptionTransaction(data) {
|
|
5888
|
+
const { error } = schemaSubscriptionTransaction.validate(data);
|
|
5889
|
+
if (error) {
|
|
5890
|
+
throw new BadRequestError31(
|
|
5891
|
+
`Invalid subscription transaction data: ${error.message}`
|
|
5892
|
+
);
|
|
5893
|
+
}
|
|
5894
|
+
if (data._id && typeof data._id === "string") {
|
|
5895
|
+
try {
|
|
5896
|
+
data._id = new ObjectId19(data._id);
|
|
5897
|
+
} catch (error2) {
|
|
5898
|
+
throw new BadRequestError31("Invalid subscription transaction ID.");
|
|
5899
|
+
}
|
|
5900
|
+
}
|
|
5901
|
+
if (data.subscription && typeof data.subscription === "string") {
|
|
5902
|
+
try {
|
|
5903
|
+
data.subscription = new ObjectId19(data.subscription);
|
|
5904
|
+
} catch (error2) {
|
|
5905
|
+
throw new BadRequestError31("Invalid subscription ID.");
|
|
5906
|
+
}
|
|
5907
|
+
}
|
|
5908
|
+
if (data.createdBy && typeof data.createdBy === "string") {
|
|
5909
|
+
try {
|
|
5910
|
+
data.createdBy = new ObjectId19(data.createdBy);
|
|
5911
|
+
} catch (error2) {
|
|
5912
|
+
throw new BadRequestError31("Invalid createdBy ID.");
|
|
5913
|
+
}
|
|
5914
|
+
}
|
|
5915
|
+
return {
|
|
5916
|
+
_id: data._id,
|
|
5917
|
+
subscription: data.subscription,
|
|
5918
|
+
amount: data.amount,
|
|
5919
|
+
currency: data.currency,
|
|
5920
|
+
type: data.type,
|
|
5921
|
+
description: data.description ?? "",
|
|
5922
|
+
createdBy: data.createdBy,
|
|
5923
|
+
createdByName: data.createdByName,
|
|
5924
|
+
createdAt: data.createdAt ?? /* @__PURE__ */ new Date(),
|
|
5925
|
+
updatedAt: data.updatedAt ?? ""
|
|
5926
|
+
};
|
|
5927
|
+
}
|
|
5928
|
+
|
|
5929
|
+
// src/resources/subscription/subscription.transaction.repository.ts
|
|
5930
|
+
import { ObjectId as ObjectId20 } from "mongodb";
|
|
5931
|
+
function useSubscriptionTransactionRepo() {
|
|
5932
|
+
const db = useAtlas14.getDb();
|
|
5933
|
+
if (!db) {
|
|
5934
|
+
throw new InternalServerError16("Unable to connect to server.");
|
|
5935
|
+
}
|
|
5936
|
+
const namespace_collection = "subscription.transactions";
|
|
5937
|
+
const collection = db.collection(namespace_collection);
|
|
5938
|
+
const { getCache, setCache, delNamespace } = useCache13(namespace_collection);
|
|
5939
|
+
function delCachedData() {
|
|
5940
|
+
delNamespace().then(() => {
|
|
5941
|
+
logger17.log({
|
|
5942
|
+
level: "info",
|
|
5943
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
5944
|
+
});
|
|
5945
|
+
}).catch((err) => {
|
|
5946
|
+
logger17.log({
|
|
5947
|
+
level: "error",
|
|
5948
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
5949
|
+
});
|
|
5950
|
+
});
|
|
5951
|
+
}
|
|
5952
|
+
async function createIndexes() {
|
|
5953
|
+
try {
|
|
5954
|
+
await collection.createIndexes([
|
|
5955
|
+
{
|
|
5956
|
+
key: {
|
|
5957
|
+
subscription: 1
|
|
5958
|
+
},
|
|
5959
|
+
name: "subscription_index"
|
|
5960
|
+
},
|
|
5961
|
+
{
|
|
5962
|
+
key: { subscription: 1, type: 1 },
|
|
5963
|
+
name: "subscription_type_index"
|
|
5964
|
+
},
|
|
5965
|
+
{
|
|
5966
|
+
key: { createdAt: -1 },
|
|
5967
|
+
name: "createdAt_index"
|
|
5968
|
+
}
|
|
5969
|
+
]);
|
|
5970
|
+
} catch (error) {
|
|
5971
|
+
}
|
|
5972
|
+
}
|
|
5973
|
+
createIndexes().catch((error) => {
|
|
5974
|
+
logger17.log({
|
|
5975
|
+
level: "error",
|
|
5976
|
+
message: `Failed to create indexes for subscription_transactions collection: ${error.message}`
|
|
5977
|
+
});
|
|
5978
|
+
});
|
|
5979
|
+
async function add(value, session) {
|
|
5980
|
+
try {
|
|
5981
|
+
value = modelSubscriptionTransaction(value);
|
|
5982
|
+
await collection.insertOne(value, { session });
|
|
5983
|
+
delCachedData();
|
|
5984
|
+
return "Successfully added subscription transaction.";
|
|
5985
|
+
} catch (error) {
|
|
5986
|
+
logger17.log({
|
|
5987
|
+
level: "error",
|
|
5988
|
+
message: `${error}`
|
|
5989
|
+
});
|
|
5990
|
+
if (error instanceof AppError12) {
|
|
5991
|
+
throw error;
|
|
5992
|
+
}
|
|
5993
|
+
throw new InternalServerError16("Failed to add subscription transaction.");
|
|
5994
|
+
}
|
|
5995
|
+
}
|
|
5996
|
+
async function getAll({ page = 1, limit = 10, search = "", id = "" } = {}) {
|
|
5997
|
+
page = page > 0 ? page - 1 : page;
|
|
5998
|
+
const query = {};
|
|
5999
|
+
const cacheKeyOptions = {
|
|
6000
|
+
page,
|
|
6001
|
+
limit,
|
|
6002
|
+
search,
|
|
6003
|
+
tag: "getAll"
|
|
6004
|
+
};
|
|
6005
|
+
try {
|
|
6006
|
+
query.subscription = new ObjectId20(id);
|
|
6007
|
+
cacheKeyOptions.subscription = id;
|
|
6008
|
+
} catch (error) {
|
|
6009
|
+
throw new InternalServerError16("Invalid organization ID.");
|
|
6010
|
+
}
|
|
6011
|
+
if (search) {
|
|
6012
|
+
query.$text = { $search: search };
|
|
6013
|
+
}
|
|
6014
|
+
const cacheKey = makeCacheKey12(namespace_collection, cacheKeyOptions);
|
|
6015
|
+
try {
|
|
6016
|
+
const cachedData = await getCache(
|
|
6017
|
+
cacheKey
|
|
6018
|
+
);
|
|
6019
|
+
if (cachedData) {
|
|
6020
|
+
logger17.log({
|
|
6021
|
+
level: "info",
|
|
6022
|
+
message: `Cache hit for getAll subscription transaction: ${cacheKey}`
|
|
6023
|
+
});
|
|
6024
|
+
return cachedData;
|
|
6025
|
+
}
|
|
6026
|
+
const items = await collection.aggregate([
|
|
6027
|
+
{ $match: query },
|
|
6028
|
+
{ $skip: page * limit },
|
|
6029
|
+
{ $limit: limit }
|
|
6030
|
+
]).toArray();
|
|
6031
|
+
const length = await collection.countDocuments(query);
|
|
6032
|
+
const data = paginate10(
|
|
6033
|
+
items,
|
|
6034
|
+
page,
|
|
6035
|
+
limit,
|
|
6036
|
+
length
|
|
6037
|
+
);
|
|
6038
|
+
setCache(cacheKey, data).then(() => {
|
|
6039
|
+
logger17.log({
|
|
6040
|
+
level: "info",
|
|
6041
|
+
message: `Cache set for getAll subscription transaction: ${cacheKey}`
|
|
6042
|
+
});
|
|
6043
|
+
}).catch((err) => {
|
|
6044
|
+
logger17.log({
|
|
6045
|
+
level: "error",
|
|
6046
|
+
message: `Failed to set cache for getAll subscription transaction: ${err.message}`
|
|
6047
|
+
});
|
|
6048
|
+
});
|
|
6049
|
+
return data;
|
|
6050
|
+
} catch (error) {
|
|
6051
|
+
throw new InternalServerError16("Failed to get subscription transactions.");
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
6054
|
+
return {
|
|
6055
|
+
add,
|
|
6056
|
+
getAll
|
|
6057
|
+
};
|
|
6058
|
+
}
|
|
6059
|
+
|
|
6060
|
+
// src/resources/subscription/subscription.service.ts
|
|
6061
|
+
function useSubscriptionService() {
|
|
6062
|
+
const { getById, updateById } = useSubscriptionRepo();
|
|
6063
|
+
const { add: addTransaction } = useSubscriptionTransactionRepo();
|
|
6064
|
+
const { getUserById } = useUserRepo();
|
|
6065
|
+
async function updateSeats({
|
|
6066
|
+
id = "",
|
|
6067
|
+
user = "",
|
|
6068
|
+
amount = 0,
|
|
6069
|
+
seats = 0
|
|
6070
|
+
} = {}) {
|
|
6071
|
+
const { error } = schemaSubscriptionSeats.validate({
|
|
6072
|
+
id,
|
|
6073
|
+
seats,
|
|
6074
|
+
amount,
|
|
6075
|
+
user
|
|
6076
|
+
});
|
|
6077
|
+
if (error) {
|
|
6078
|
+
throw new BadRequestError32(error.message);
|
|
6079
|
+
}
|
|
6080
|
+
const subscription = await getById(id);
|
|
6081
|
+
if (!subscription) {
|
|
6082
|
+
throw new Error("Subscription not found");
|
|
6083
|
+
}
|
|
6084
|
+
if (subscription.seats === seats) {
|
|
6085
|
+
throw new Error("Failed to update subscription, no changes detected.");
|
|
6086
|
+
}
|
|
6087
|
+
const userData = await getUserById(user);
|
|
6088
|
+
if (!userData) {
|
|
6089
|
+
throw new Error("User not found.");
|
|
6090
|
+
}
|
|
6091
|
+
const session = useAtlas15.getClient()?.startSession();
|
|
6092
|
+
if (!session) {
|
|
6093
|
+
throw new Error("Unable to start database session.");
|
|
6094
|
+
}
|
|
6095
|
+
let subscriptionAmount = subscription.amount;
|
|
6096
|
+
const seatIncreased = seats > subscription.paidSeats;
|
|
6097
|
+
let paidSeats = subscription.paidSeats;
|
|
6098
|
+
if (seatIncreased) {
|
|
6099
|
+
subscriptionAmount += amount ?? 0;
|
|
6100
|
+
paidSeats = seats;
|
|
6101
|
+
}
|
|
6102
|
+
try {
|
|
6103
|
+
session.startTransaction();
|
|
6104
|
+
await updateById(
|
|
6105
|
+
id,
|
|
6106
|
+
{ seats, amount: subscriptionAmount, paidSeats },
|
|
6107
|
+
session
|
|
6108
|
+
);
|
|
6109
|
+
if (seatIncreased) {
|
|
6110
|
+
await addTransaction(
|
|
6111
|
+
{
|
|
6112
|
+
type: "add-seat",
|
|
6113
|
+
description: `Added ${seats - subscription.paidSeats} seats.`,
|
|
6114
|
+
amount: amount ?? 0,
|
|
6115
|
+
currency: subscription.currency,
|
|
6116
|
+
subscription: id,
|
|
6117
|
+
createdBy: user,
|
|
6118
|
+
createdByName: `${userData.firstName} ${userData.lastName}`
|
|
6119
|
+
},
|
|
6120
|
+
session
|
|
6121
|
+
);
|
|
6122
|
+
}
|
|
6123
|
+
await session.commitTransaction();
|
|
6124
|
+
return "Successfully updated subscription seats.";
|
|
6125
|
+
} catch (error2) {
|
|
6126
|
+
await session.abortTransaction();
|
|
6127
|
+
throw error2;
|
|
6128
|
+
} finally {
|
|
6129
|
+
session.endSession();
|
|
6130
|
+
}
|
|
6131
|
+
}
|
|
6132
|
+
return {
|
|
6133
|
+
updateSeats
|
|
6134
|
+
};
|
|
6135
|
+
}
|
|
6136
|
+
|
|
6137
|
+
// src/resources/subscription/subscription.controller.ts
|
|
6138
|
+
function useSubscriptionController() {
|
|
6139
|
+
const {
|
|
6140
|
+
getAll: _getAll,
|
|
6141
|
+
getById: _getById,
|
|
6142
|
+
getByOrg: _getByOrg
|
|
6143
|
+
} = useSubscriptionRepo();
|
|
6144
|
+
const { updateSeats: _updateSeats } = useSubscriptionService();
|
|
6145
|
+
async function getAll(req, res, next) {
|
|
6146
|
+
const validation = Joi24.object({
|
|
6147
|
+
page: Joi24.number().min(1).max(100).optional().allow(null, "").default(1),
|
|
6148
|
+
limit: Joi24.number().min(1).max(100).optional().allow(null, "").default(10),
|
|
6149
|
+
status: Joi24.string().valid("active", "suspended").optional().default("active")
|
|
6150
|
+
});
|
|
6151
|
+
const query = req.query;
|
|
6152
|
+
const { error, value } = validation.validate(query);
|
|
6153
|
+
if (error) {
|
|
6154
|
+
next(new BadRequestError33(error.message));
|
|
6155
|
+
return;
|
|
6156
|
+
}
|
|
6157
|
+
try {
|
|
6158
|
+
const data = await _getAll(value);
|
|
6159
|
+
res.json(data);
|
|
6160
|
+
return;
|
|
6161
|
+
} catch (error2) {
|
|
6162
|
+
next(error2);
|
|
6163
|
+
}
|
|
6164
|
+
}
|
|
6165
|
+
async function getById(req, res, next) {
|
|
6166
|
+
const id = req.params.id ?? "";
|
|
6167
|
+
const validation = Joi24.object({
|
|
6168
|
+
id: Joi24.string().hex().length(24).required()
|
|
6169
|
+
});
|
|
6170
|
+
const { error, value } = validation.validate({ id });
|
|
6171
|
+
if (error) {
|
|
6172
|
+
next(new BadRequestError33(error.message));
|
|
6173
|
+
return;
|
|
6174
|
+
}
|
|
6175
|
+
try {
|
|
6176
|
+
const data = await _getById(value.id);
|
|
6177
|
+
res.json(data);
|
|
6178
|
+
return;
|
|
6179
|
+
} catch (error2) {
|
|
6180
|
+
next(error2);
|
|
6181
|
+
}
|
|
6182
|
+
}
|
|
6183
|
+
async function getByOrg(req, res, next) {
|
|
6184
|
+
const org = req.params.org ?? "";
|
|
6185
|
+
const validation = Joi24.object({
|
|
6186
|
+
org: Joi24.string().hex().length(24).required()
|
|
6187
|
+
});
|
|
6188
|
+
const { error, value } = validation.validate({ org });
|
|
6189
|
+
if (error) {
|
|
6190
|
+
next(new BadRequestError33(error.message));
|
|
6191
|
+
return;
|
|
6192
|
+
}
|
|
6193
|
+
try {
|
|
6194
|
+
const data = await _getByOrg(value.org);
|
|
6195
|
+
res.json(data);
|
|
6196
|
+
return;
|
|
6197
|
+
} catch (error2) {
|
|
6198
|
+
next(error2);
|
|
6199
|
+
}
|
|
6200
|
+
}
|
|
6201
|
+
async function updateSeats(req, res, next) {
|
|
6202
|
+
const id = req.params.id ?? "";
|
|
6203
|
+
const payload = req.body;
|
|
6204
|
+
const { error } = schemaSubscriptionSeats.validate({ ...payload, id });
|
|
6205
|
+
if (error) {
|
|
6206
|
+
next(new BadRequestError33(error.message));
|
|
6207
|
+
return;
|
|
6208
|
+
}
|
|
6209
|
+
const user = payload.user ?? "";
|
|
6210
|
+
const seats = payload.seats ?? 0;
|
|
6211
|
+
const amount = payload.amount ?? 0;
|
|
6212
|
+
try {
|
|
6213
|
+
const message = await _updateSeats({ id, seats, amount, user });
|
|
6214
|
+
res.json({ message });
|
|
6215
|
+
return;
|
|
6216
|
+
} catch (error2) {
|
|
6217
|
+
next(error2);
|
|
6218
|
+
}
|
|
6219
|
+
}
|
|
6220
|
+
return {
|
|
6221
|
+
getAll,
|
|
6222
|
+
getById,
|
|
6223
|
+
getByOrg,
|
|
6224
|
+
updateSeats
|
|
6225
|
+
};
|
|
6226
|
+
}
|
|
6227
|
+
|
|
6228
|
+
// src/resources/subscription/subscription.transaction.controller.ts
|
|
6229
|
+
import Joi25 from "joi";
|
|
6230
|
+
import { BadRequestError as BadRequestError34 } from "@goweekdays/utils";
|
|
6231
|
+
function useSubscriptionTransactionController() {
|
|
6232
|
+
const { getAll: _getAll } = useSubscriptionTransactionRepo();
|
|
6233
|
+
async function getAll(req, res, next) {
|
|
6234
|
+
const validation = Joi25.object({
|
|
6235
|
+
id: Joi25.string().hex().length(24).required(),
|
|
6236
|
+
page: Joi25.number().min(1).max(100).optional().allow(null, "").default(1),
|
|
6237
|
+
limit: Joi25.number().min(1).max(100).optional().allow(null, "").default(10)
|
|
6238
|
+
});
|
|
6239
|
+
const query = req.query;
|
|
6240
|
+
const id = req.params.id ?? "";
|
|
6241
|
+
const { error, value } = validation.validate({ ...query, id });
|
|
6242
|
+
if (error) {
|
|
6243
|
+
next(new BadRequestError34(error.message));
|
|
6244
|
+
return;
|
|
6245
|
+
}
|
|
6246
|
+
try {
|
|
6247
|
+
const data = await _getAll(value);
|
|
6248
|
+
res.json(data);
|
|
6249
|
+
return;
|
|
6250
|
+
} catch (error2) {
|
|
6251
|
+
next(error2);
|
|
6252
|
+
}
|
|
6253
|
+
}
|
|
6254
|
+
return {
|
|
6255
|
+
getAll
|
|
6256
|
+
};
|
|
6257
|
+
}
|
|
6258
|
+
|
|
6259
|
+
// src/resources/plan/plan.model.ts
|
|
6260
|
+
import Joi26 from "joi";
|
|
6261
|
+
var currencies = ["USD", "PHP"];
|
|
6262
|
+
var schemaPlan = Joi26.object({
|
|
6263
|
+
name: Joi26.string().min(3).max(100).required(),
|
|
6264
|
+
description: Joi26.string().max(255).optional().allow("", null),
|
|
6265
|
+
features: Joi26.array().items(Joi26.string().max(100)).optional(),
|
|
6266
|
+
price: Joi26.number().positive().required(),
|
|
6267
|
+
currency: Joi26.string().length(3).allow(...currencies).required(),
|
|
6268
|
+
default: Joi26.boolean().optional().allow(null, ""),
|
|
6269
|
+
billingCycle: Joi26.string().valid("monthly", "yearly").required()
|
|
6270
|
+
});
|
|
6271
|
+
function modelPlan(data) {
|
|
6272
|
+
const { error } = schemaPlan.validate(data);
|
|
6273
|
+
if (error) {
|
|
6274
|
+
throw new Error(`Invalid plan data: ${error.message}`);
|
|
6275
|
+
}
|
|
6276
|
+
return {
|
|
6277
|
+
_id: data._id,
|
|
6278
|
+
name: data.name,
|
|
6279
|
+
description: data.description,
|
|
6280
|
+
features: data.features,
|
|
6281
|
+
price: data.price,
|
|
6282
|
+
currency: data.currency,
|
|
6283
|
+
billingCycle: data.billingCycle,
|
|
6284
|
+
status: data.status ?? "active",
|
|
6285
|
+
default: data.default ?? false,
|
|
6286
|
+
createdAt: data.createdAt ?? /* @__PURE__ */ new Date(),
|
|
6287
|
+
updatedAt: data.updatedAt ?? ""
|
|
6288
|
+
};
|
|
6289
|
+
}
|
|
6290
|
+
|
|
6291
|
+
// src/resources/plan/plan.repository.ts
|
|
6292
|
+
import {
|
|
6293
|
+
AppError as AppError13,
|
|
6294
|
+
BadRequestError as BadRequestError35,
|
|
6295
|
+
InternalServerError as InternalServerError17,
|
|
6296
|
+
logger as logger18,
|
|
6297
|
+
makeCacheKey as makeCacheKey13,
|
|
6298
|
+
paginate as paginate11,
|
|
6299
|
+
useAtlas as useAtlas16,
|
|
6300
|
+
useCache as useCache14
|
|
6301
|
+
} from "@goweekdays/utils";
|
|
6302
|
+
import Joi27 from "joi";
|
|
6303
|
+
import { ObjectId as ObjectId21 } from "mongodb";
|
|
6304
|
+
function usePlanRepo() {
|
|
6305
|
+
const db = useAtlas16.getDb();
|
|
6306
|
+
if (!db) {
|
|
6307
|
+
throw new InternalServerError17("Unable to connect to server.");
|
|
6308
|
+
}
|
|
6309
|
+
const namespace_collection = "plans";
|
|
6310
|
+
const collection = db.collection(namespace_collection);
|
|
6311
|
+
const { getCache, setCache, delNamespace } = useCache14(namespace_collection);
|
|
6312
|
+
function delCachedData() {
|
|
6313
|
+
delNamespace().then(() => {
|
|
6314
|
+
logger18.log({
|
|
6315
|
+
level: "info",
|
|
6316
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
6317
|
+
});
|
|
6318
|
+
}).catch((err) => {
|
|
6319
|
+
logger18.log({
|
|
6320
|
+
level: "error",
|
|
6321
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
6322
|
+
});
|
|
6323
|
+
});
|
|
6324
|
+
}
|
|
6325
|
+
async function createIndexes() {
|
|
6326
|
+
try {
|
|
6327
|
+
await collection.createIndexes([
|
|
6328
|
+
{
|
|
6329
|
+
key: {
|
|
6330
|
+
status: 1
|
|
6331
|
+
}
|
|
6332
|
+
},
|
|
6333
|
+
{
|
|
6334
|
+
key: {
|
|
6335
|
+
name: 1
|
|
6336
|
+
}
|
|
6337
|
+
},
|
|
6338
|
+
{
|
|
6339
|
+
key: { billingCycle: 1 }
|
|
6340
|
+
},
|
|
6341
|
+
{
|
|
6342
|
+
key: { name: "text", description: "text" },
|
|
6343
|
+
name: "name_description_text_index"
|
|
6344
|
+
},
|
|
6345
|
+
{
|
|
6346
|
+
key: { name: 1, status: 1 },
|
|
6347
|
+
partialFilterExpression: { status: "active" },
|
|
6348
|
+
unique: true,
|
|
6349
|
+
name: "unique_name_index"
|
|
6350
|
+
},
|
|
6351
|
+
{
|
|
6352
|
+
key: { default: 1 },
|
|
6353
|
+
unique: true,
|
|
6354
|
+
partialFilterExpression: { status: "active" }
|
|
6355
|
+
}
|
|
6356
|
+
]);
|
|
6357
|
+
} catch (error) {
|
|
6358
|
+
}
|
|
6359
|
+
}
|
|
6360
|
+
createIndexes().catch((error) => {
|
|
6361
|
+
logger18.log({
|
|
6362
|
+
level: "error",
|
|
6363
|
+
message: `Failed to create indexes for plans collection: ${error.message}`
|
|
6364
|
+
});
|
|
6365
|
+
});
|
|
6366
|
+
async function add(value) {
|
|
6367
|
+
try {
|
|
6368
|
+
value = modelPlan(value);
|
|
6369
|
+
await collection.insertOne(value);
|
|
6370
|
+
delCachedData();
|
|
6371
|
+
return "Successfully added plan.";
|
|
6372
|
+
} catch (error) {
|
|
6373
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
6374
|
+
if (isDuplicated) {
|
|
6375
|
+
throw new BadRequestError35("Plan name already exist.");
|
|
6376
|
+
}
|
|
6377
|
+
throw new InternalServerError17("Failed to add plan.");
|
|
6378
|
+
}
|
|
6379
|
+
}
|
|
6380
|
+
async function getAll({
|
|
6381
|
+
page = 1,
|
|
6382
|
+
limit = 10,
|
|
6383
|
+
search = "",
|
|
6384
|
+
status = "active"
|
|
6385
|
+
} = {}) {
|
|
6386
|
+
page = page < 1 ? page - 1 : page;
|
|
6387
|
+
const query = { status };
|
|
6388
|
+
const cacheKeyOptions = {
|
|
6389
|
+
page,
|
|
6390
|
+
limit,
|
|
6391
|
+
search,
|
|
6392
|
+
status,
|
|
6393
|
+
tag: "getAll"
|
|
6394
|
+
};
|
|
6395
|
+
if (search) {
|
|
6396
|
+
query.$text = { $search: search };
|
|
6397
|
+
}
|
|
6398
|
+
const cacheKey = makeCacheKey13(namespace_collection, cacheKeyOptions);
|
|
6399
|
+
try {
|
|
6400
|
+
const cachedData = await getCache(cacheKey);
|
|
6401
|
+
if (cachedData) {
|
|
6402
|
+
return cachedData;
|
|
6403
|
+
}
|
|
6404
|
+
const items = await collection.aggregate([
|
|
6405
|
+
{ $match: query },
|
|
6406
|
+
{ $skip: page * limit },
|
|
6407
|
+
{ $limit: limit }
|
|
6408
|
+
]).toArray();
|
|
6409
|
+
const length = await collection.countDocuments(query);
|
|
6410
|
+
const data = paginate11(items, page, limit, length);
|
|
6411
|
+
setCache(cacheKey, data).then(() => {
|
|
6412
|
+
logger18.log({
|
|
6413
|
+
level: "info",
|
|
6414
|
+
message: `Cache set for getAll plan: ${cacheKey}`
|
|
6415
|
+
});
|
|
6416
|
+
}).catch((err) => {
|
|
6417
|
+
logger18.log({
|
|
6418
|
+
level: "error",
|
|
6419
|
+
message: `Failed to set cache for getAll plan: ${err.message}`
|
|
6420
|
+
});
|
|
6421
|
+
});
|
|
6422
|
+
return data;
|
|
6423
|
+
} catch (error) {
|
|
6424
|
+
throw new InternalServerError17("Failed to get plans.");
|
|
6425
|
+
}
|
|
6426
|
+
}
|
|
6427
|
+
async function getById(_id) {
|
|
6428
|
+
const { error } = Joi27.string().hex().length(24).required().validate(_id);
|
|
6429
|
+
if (error) {
|
|
6430
|
+
throw new Error(`Invalid plan ID: ${error.message}`);
|
|
6431
|
+
}
|
|
6432
|
+
try {
|
|
6433
|
+
_id = new ObjectId21(_id);
|
|
6434
|
+
} catch (error2) {
|
|
6435
|
+
throw new BadRequestError35("Invalid plan ID.");
|
|
6436
|
+
}
|
|
6437
|
+
try {
|
|
6438
|
+
const cacheKey = makeCacheKey13(namespace_collection, {
|
|
6439
|
+
_id: String(_id),
|
|
6440
|
+
tag: "getById"
|
|
6441
|
+
});
|
|
6442
|
+
const cachedData = await getCache(cacheKey);
|
|
6443
|
+
if (cachedData) {
|
|
6444
|
+
return cachedData;
|
|
6445
|
+
}
|
|
6446
|
+
const data = await collection.findOne({
|
|
6447
|
+
_id,
|
|
6448
|
+
status: { $ne: "deleted" }
|
|
6449
|
+
});
|
|
6450
|
+
setCache(cacheKey, data).then(() => {
|
|
6451
|
+
logger18.log({
|
|
6452
|
+
level: "info",
|
|
6453
|
+
message: `Cache set for getById plan: ${cacheKey}`
|
|
6454
|
+
});
|
|
6455
|
+
}).catch((err) => {
|
|
6456
|
+
logger18.log({
|
|
6457
|
+
level: "error",
|
|
6458
|
+
message: `Failed to set cache for getById plan: ${err.message}`
|
|
6459
|
+
});
|
|
6460
|
+
});
|
|
6461
|
+
return data;
|
|
6462
|
+
} catch (error2) {
|
|
6463
|
+
throw new InternalServerError17("Failed to get plan.");
|
|
6464
|
+
}
|
|
6465
|
+
}
|
|
6466
|
+
async function getDefault() {
|
|
6467
|
+
try {
|
|
6468
|
+
const cacheKey = makeCacheKey13(namespace_collection, {
|
|
6469
|
+
default: true,
|
|
6470
|
+
tag: "getDefault"
|
|
6471
|
+
});
|
|
6472
|
+
const cachedData = await getCache(cacheKey);
|
|
6473
|
+
if (cachedData) {
|
|
6474
|
+
return cachedData;
|
|
6475
|
+
}
|
|
6476
|
+
const data = await collection.findOne({
|
|
6477
|
+
default: true,
|
|
6478
|
+
status: "active"
|
|
6479
|
+
});
|
|
6480
|
+
setCache(cacheKey, data).then(() => {
|
|
6481
|
+
logger18.log({
|
|
6482
|
+
level: "info",
|
|
6483
|
+
message: `Cache set for default plan: ${cacheKey}`
|
|
6484
|
+
});
|
|
6485
|
+
}).catch((err) => {
|
|
6486
|
+
logger18.log({
|
|
6487
|
+
level: "error",
|
|
6488
|
+
message: `Failed to set cache for default plan: ${err.message}`
|
|
6489
|
+
});
|
|
6490
|
+
});
|
|
6491
|
+
return data;
|
|
6492
|
+
} catch (error) {
|
|
6493
|
+
throw new InternalServerError17("Failed to get default plan.");
|
|
6494
|
+
}
|
|
6495
|
+
}
|
|
6496
|
+
async function deleteById(_id) {
|
|
6497
|
+
const { error } = Joi27.string().hex().length(24).required().validate(_id);
|
|
6498
|
+
if (error) {
|
|
6499
|
+
throw new Error(`Invalid plan ID: ${error.message}`);
|
|
6500
|
+
}
|
|
6501
|
+
try {
|
|
6502
|
+
_id = new ObjectId21(_id);
|
|
6503
|
+
} catch (error2) {
|
|
6504
|
+
throw new BadRequestError35("Invalid plan ID.");
|
|
6505
|
+
}
|
|
6506
|
+
try {
|
|
6507
|
+
const result = await collection.updateOne(
|
|
6508
|
+
{ _id },
|
|
6509
|
+
{ $set: { status: "deleted" } }
|
|
6510
|
+
);
|
|
6511
|
+
if (result.modifiedCount === 0) {
|
|
6512
|
+
throw new InternalServerError17("Failed to delete plan.");
|
|
6513
|
+
}
|
|
6514
|
+
delCachedData();
|
|
6515
|
+
return "Successfully deleted plan.";
|
|
6516
|
+
} catch (error2) {
|
|
6517
|
+
if (error2 instanceof AppError13) {
|
|
6518
|
+
throw error2;
|
|
6519
|
+
}
|
|
6520
|
+
throw new InternalServerError17("Failed to delete plan.");
|
|
6521
|
+
}
|
|
6522
|
+
}
|
|
6523
|
+
return {
|
|
6524
|
+
add,
|
|
6525
|
+
getAll,
|
|
6526
|
+
getById,
|
|
6527
|
+
getDefault,
|
|
6528
|
+
deleteById
|
|
6529
|
+
};
|
|
6530
|
+
}
|
|
6531
|
+
|
|
6532
|
+
// src/resources/plan/plan.service.ts
|
|
6533
|
+
function usePlanService() {
|
|
6534
|
+
const { add } = usePlanRepo();
|
|
6535
|
+
async function addDefaultPlan() {
|
|
6536
|
+
try {
|
|
6537
|
+
await add({
|
|
6538
|
+
name: "Standard",
|
|
6539
|
+
description: "Default standard plan",
|
|
6540
|
+
price: 1e3,
|
|
6541
|
+
currency: "PHP",
|
|
6542
|
+
billingCycle: "monthly",
|
|
6543
|
+
default: true
|
|
6544
|
+
});
|
|
6545
|
+
} catch (error) {
|
|
6546
|
+
throw error;
|
|
6547
|
+
}
|
|
6548
|
+
}
|
|
6549
|
+
return {
|
|
6550
|
+
addDefaultPlan
|
|
6551
|
+
};
|
|
6552
|
+
}
|
|
6553
|
+
|
|
6554
|
+
// src/resources/plan/plan.controller.ts
|
|
6555
|
+
import Joi28 from "joi";
|
|
6556
|
+
import { BadRequestError as BadRequestError36 } from "@goweekdays/utils";
|
|
6557
|
+
function usePlanController() {
|
|
6558
|
+
const {
|
|
6559
|
+
add: _add,
|
|
6560
|
+
getAll: _getAll,
|
|
6561
|
+
getById: _getById,
|
|
6562
|
+
deleteById: _deleteById,
|
|
6563
|
+
getDefault: _getDefault
|
|
6564
|
+
} = usePlanRepo();
|
|
6565
|
+
async function add(req, res, next) {
|
|
6566
|
+
const value = req.body;
|
|
6567
|
+
const validation = Joi28.object({
|
|
6568
|
+
name: Joi28.string().min(3).max(100).required(),
|
|
6569
|
+
description: Joi28.string().max(255).optional().allow("", null),
|
|
6570
|
+
features: Joi28.array().items(Joi28.string().max(100)).optional(),
|
|
6571
|
+
price: Joi28.number().positive().required(),
|
|
6572
|
+
currency: Joi28.string().length(3).required(),
|
|
6573
|
+
billingCycle: Joi28.string().valid("monthly", "yearly").required()
|
|
6574
|
+
});
|
|
6575
|
+
const { error } = validation.validate(value);
|
|
6576
|
+
if (error) {
|
|
6577
|
+
next(new BadRequestError36(error.message));
|
|
6578
|
+
return;
|
|
6579
|
+
}
|
|
6580
|
+
try {
|
|
6581
|
+
const message = await _add(value);
|
|
6582
|
+
res.json({ message });
|
|
6583
|
+
return;
|
|
6584
|
+
} catch (error2) {
|
|
6585
|
+
next(error2);
|
|
6586
|
+
}
|
|
6587
|
+
}
|
|
6588
|
+
async function getAll(req, res, next) {
|
|
6589
|
+
const status = req.query.status ?? "active";
|
|
6590
|
+
const search = req.query.search ?? "";
|
|
6591
|
+
const page = Number(req.query.page) ?? 1;
|
|
6592
|
+
const limit = Number(req.query.limit) ?? 10;
|
|
6593
|
+
const validation = Joi28.object({
|
|
6594
|
+
status: Joi28.string().required(),
|
|
6595
|
+
search: Joi28.string().optional().allow("", null),
|
|
6596
|
+
page: Joi28.number().required(),
|
|
6597
|
+
limit: Joi28.number().required()
|
|
6598
|
+
});
|
|
6599
|
+
const { error } = validation.validate({ status, search, page, limit });
|
|
6600
|
+
if (error) {
|
|
6601
|
+
next(new BadRequestError36(error.message));
|
|
6602
|
+
return;
|
|
6603
|
+
}
|
|
6604
|
+
try {
|
|
6605
|
+
const plans = await _getAll({ status, search, page, limit });
|
|
6606
|
+
res.json(plans);
|
|
6607
|
+
return;
|
|
6608
|
+
} catch (error2) {
|
|
6609
|
+
next(error2);
|
|
6610
|
+
}
|
|
6611
|
+
}
|
|
6612
|
+
async function getById(req, res, next) {
|
|
6613
|
+
const id = req.params.id;
|
|
6614
|
+
const validation = Joi28.string().hex().length(24).required();
|
|
6615
|
+
const { error } = validation.validate(id);
|
|
6616
|
+
if (error) {
|
|
6617
|
+
next(new BadRequestError36(error.message));
|
|
6618
|
+
return;
|
|
6619
|
+
}
|
|
6620
|
+
try {
|
|
6621
|
+
const plan = await _getById(id);
|
|
6622
|
+
res.json(plan);
|
|
6623
|
+
return;
|
|
6624
|
+
} catch (error2) {
|
|
6625
|
+
next(error2);
|
|
6626
|
+
}
|
|
6627
|
+
}
|
|
6628
|
+
async function deleteById(req, res, next) {
|
|
6629
|
+
const id = req.params.id;
|
|
6630
|
+
const validation = Joi28.string().hex().length(24).required();
|
|
6631
|
+
const { error } = validation.validate(id);
|
|
6632
|
+
if (error) {
|
|
6633
|
+
next(new BadRequestError36(error.message));
|
|
6634
|
+
return;
|
|
6635
|
+
}
|
|
6636
|
+
try {
|
|
6637
|
+
const message = await _deleteById(id);
|
|
6638
|
+
res.json({ message });
|
|
6639
|
+
return;
|
|
6640
|
+
} catch (error2) {
|
|
6641
|
+
next(error2);
|
|
6642
|
+
}
|
|
6643
|
+
}
|
|
6644
|
+
async function getDefault(req, res, next) {
|
|
6645
|
+
try {
|
|
6646
|
+
const plan = await _getDefault();
|
|
6647
|
+
res.json(plan);
|
|
6648
|
+
return;
|
|
6649
|
+
} catch (error) {
|
|
6650
|
+
next(error);
|
|
6651
|
+
}
|
|
6652
|
+
}
|
|
6653
|
+
return {
|
|
6654
|
+
add,
|
|
6655
|
+
getAll,
|
|
6656
|
+
getById,
|
|
6657
|
+
deleteById,
|
|
6658
|
+
getDefault
|
|
6659
|
+
};
|
|
6660
|
+
}
|
|
6661
|
+
|
|
6662
|
+
// src/resources/organization/organization.service.ts
|
|
6663
|
+
function useOrgService() {
|
|
6664
|
+
const { add: addOrg } = useOrgRepo();
|
|
6665
|
+
const { addRole } = useRoleRepo();
|
|
6666
|
+
const { getAll: getAllPermission } = usePermissionRepo();
|
|
6667
|
+
const { add: addMember, updateRoleById: _updateRoleById } = useMemberRepo();
|
|
6668
|
+
const { getUserById } = useUserRepo();
|
|
6669
|
+
const { getDefault } = usePlanRepo();
|
|
6670
|
+
const { add: addSubscription } = useSubscriptionRepo();
|
|
6671
|
+
const { add: addSubscriptionTransaction } = useSubscriptionTransactionRepo();
|
|
6672
|
+
async function add(value) {
|
|
6673
|
+
const { error } = schemaOrgAdd.validate(value);
|
|
6674
|
+
if (error) {
|
|
6675
|
+
throw new BadRequestError37(error.message);
|
|
6676
|
+
}
|
|
6677
|
+
const session = useAtlas17.getClient()?.startSession();
|
|
6678
|
+
if (!session) {
|
|
6679
|
+
throw new BadRequestError37("Unable to start database session.");
|
|
6680
|
+
}
|
|
6681
|
+
try {
|
|
6682
|
+
session?.startTransaction();
|
|
6683
|
+
const org = await addOrg(
|
|
6684
|
+
{
|
|
6685
|
+
email: value.email,
|
|
6686
|
+
name: value.name,
|
|
6687
|
+
contact: value.contact,
|
|
6688
|
+
createdBy: value.createdBy
|
|
6689
|
+
},
|
|
6690
|
+
session
|
|
6691
|
+
);
|
|
6692
|
+
const plan = await getDefault();
|
|
6693
|
+
if (!plan) {
|
|
6694
|
+
throw new BadRequestError37(
|
|
6695
|
+
"Failed to create organization, plan not found."
|
|
6696
|
+
);
|
|
6697
|
+
}
|
|
6698
|
+
const currentDate = /* @__PURE__ */ new Date();
|
|
6699
|
+
const nextBillingDate = new Date(currentDate);
|
|
6700
|
+
nextBillingDate.setMonth(currentDate.getMonth() + 1);
|
|
6701
|
+
const amount = plan.price * value.seats;
|
|
6702
|
+
const subscriptionId = await addSubscription(
|
|
6703
|
+
{
|
|
6704
|
+
amount,
|
|
6705
|
+
org: String(org),
|
|
6706
|
+
seats: value.seats,
|
|
6707
|
+
paidSeats: value.seats,
|
|
6708
|
+
currency: plan.currency,
|
|
6709
|
+
billingCycle: plan.billingCycle,
|
|
6710
|
+
nextBillingDate
|
|
6711
|
+
},
|
|
6712
|
+
session
|
|
6713
|
+
);
|
|
6714
|
+
const createdBy = String(value.createdBy);
|
|
6715
|
+
const user = await getUserById(createdBy);
|
|
6716
|
+
if (!user) {
|
|
6717
|
+
throw new BadRequestError37("User is required to create org member.");
|
|
6718
|
+
}
|
|
6719
|
+
await addSubscriptionTransaction(
|
|
6720
|
+
{
|
|
6721
|
+
subscription: subscriptionId,
|
|
6722
|
+
type: "initiate",
|
|
6723
|
+
amount,
|
|
6724
|
+
currency: plan.currency,
|
|
6725
|
+
description: "Initial subscription transaction",
|
|
6726
|
+
createdBy: value.createdBy,
|
|
6727
|
+
createdByName: `${user.firstName} ${user.lastName}`
|
|
6728
|
+
},
|
|
6729
|
+
session
|
|
6730
|
+
);
|
|
6731
|
+
const allPermissions = await getAllPermission({
|
|
6732
|
+
app: "org",
|
|
6733
|
+
limit: 100
|
|
6734
|
+
});
|
|
6735
|
+
let permissions = [];
|
|
6736
|
+
if (allPermissions && allPermissions.items && allPermissions.items.length) {
|
|
6737
|
+
permissions = allPermissions.items.map((perm) => perm.key);
|
|
6738
|
+
}
|
|
6739
|
+
if (permissions.length === 0) {
|
|
6740
|
+
throw new Error("No permissions found for the organization type.");
|
|
6741
|
+
}
|
|
6742
|
+
const roleData = {
|
|
6743
|
+
org: String(org),
|
|
6744
|
+
name: "Owner",
|
|
6745
|
+
description: "Owner of the organization",
|
|
6746
|
+
permissions,
|
|
6747
|
+
createdBy,
|
|
6748
|
+
app: "org"
|
|
6749
|
+
};
|
|
6750
|
+
const role = await addRole(roleData, session);
|
|
6751
|
+
if (!role) {
|
|
6752
|
+
throw new BadRequestError37("Role is required to create org member.");
|
|
6753
|
+
}
|
|
6754
|
+
await addMember(
|
|
6755
|
+
{
|
|
6756
|
+
role: String(role),
|
|
6757
|
+
roleName: roleData.name,
|
|
6758
|
+
org: String(org),
|
|
6759
|
+
orgName: value.name,
|
|
6760
|
+
name: `${user.firstName} ${user.lastName}`,
|
|
6761
|
+
user: createdBy,
|
|
6762
|
+
app: "org"
|
|
6763
|
+
},
|
|
6764
|
+
session
|
|
6765
|
+
);
|
|
6766
|
+
await session?.commitTransaction();
|
|
6767
|
+
return String(org);
|
|
6768
|
+
} catch (error2) {
|
|
6769
|
+
await session?.abortTransaction();
|
|
6770
|
+
throw error2;
|
|
6771
|
+
} finally {
|
|
6772
|
+
await session?.endSession();
|
|
6773
|
+
}
|
|
6774
|
+
}
|
|
6775
|
+
return {
|
|
6776
|
+
add
|
|
6777
|
+
};
|
|
6778
|
+
}
|
|
6779
|
+
|
|
6780
|
+
// src/resources/organization/organization.controller.ts
|
|
6781
|
+
import { BadRequestError as BadRequestError38 } from "@goweekdays/utils";
|
|
6782
|
+
import Joi29 from "joi";
|
|
6783
|
+
function useOrgController() {
|
|
6784
|
+
const { add: _add } = useOrgService();
|
|
6785
|
+
const { getOrgsByMembership } = useMemberRepo();
|
|
6786
|
+
const {
|
|
6787
|
+
getByName: _getByName,
|
|
6788
|
+
getAll: getAllOrg,
|
|
6789
|
+
getById: _getById,
|
|
6790
|
+
updateById: _updateById
|
|
6791
|
+
} = useOrgRepo();
|
|
6792
|
+
async function add(req, res, next) {
|
|
6793
|
+
const value = req.body;
|
|
6794
|
+
const { error } = schemaOrgAdd.validate(value);
|
|
6795
|
+
if (error) {
|
|
6796
|
+
next(new BadRequestError38(error.message));
|
|
6797
|
+
return;
|
|
6798
|
+
}
|
|
6799
|
+
try {
|
|
6800
|
+
const org = await _add(value);
|
|
6801
|
+
res.json({
|
|
6802
|
+
message: "Organization created successfully.",
|
|
6803
|
+
data: { org }
|
|
6804
|
+
});
|
|
6805
|
+
return;
|
|
6806
|
+
} catch (error2) {
|
|
6807
|
+
next(error2);
|
|
6808
|
+
}
|
|
6809
|
+
}
|
|
6810
|
+
async function getOrgsByUserId(req, res, next) {
|
|
6811
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
6812
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
6813
|
+
const search = req.query.search ?? "";
|
|
6814
|
+
const user = req.params.user ?? "";
|
|
6815
|
+
const isPageNumber = isFinite(page);
|
|
6816
|
+
if (!isPageNumber) {
|
|
6817
|
+
next(new BadRequestError38("Invalid page number."));
|
|
6818
|
+
return;
|
|
6819
|
+
}
|
|
6820
|
+
const isLimitNumber = isFinite(limit);
|
|
6821
|
+
if (!isLimitNumber) {
|
|
6822
|
+
next(new BadRequestError38("Invalid limit number."));
|
|
6823
|
+
return;
|
|
6824
|
+
}
|
|
6825
|
+
const validation = Joi29.object({
|
|
6826
|
+
user: Joi29.string().hex().required(),
|
|
6827
|
+
page: Joi29.number().min(1).optional().allow("", null),
|
|
6828
|
+
limit: Joi29.number().min(1).optional().allow("", null),
|
|
6829
|
+
search: Joi29.string().optional().allow("", null)
|
|
6830
|
+
});
|
|
6831
|
+
const { error } = validation.validate({ user, page, limit, search });
|
|
6832
|
+
if (error) {
|
|
6833
|
+
next(new BadRequestError38(error.message));
|
|
6834
|
+
return;
|
|
6835
|
+
}
|
|
6836
|
+
try {
|
|
6837
|
+
const orgs = await getOrgsByMembership({ user, page, limit, search });
|
|
6838
|
+
res.json(orgs);
|
|
6839
|
+
return;
|
|
6840
|
+
} catch (error2) {
|
|
6841
|
+
next(error2);
|
|
6842
|
+
}
|
|
6843
|
+
}
|
|
6844
|
+
async function getAll(req, res, next) {
|
|
6845
|
+
const query = req.query;
|
|
6846
|
+
const validation = Joi29.object({
|
|
6847
|
+
page: Joi29.number().min(1).optional().allow("", null),
|
|
6848
|
+
limit: Joi29.number().min(1).optional().allow("", null),
|
|
6849
|
+
search: Joi29.string().optional().allow("", null),
|
|
6850
|
+
status: Joi29.string().valid("active", "suspended", "inactive", "deleted").optional()
|
|
6851
|
+
});
|
|
6852
|
+
const { error } = validation.validate(query);
|
|
5557
6853
|
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
5558
6854
|
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
5559
6855
|
const search = req.query.search ?? "";
|
|
5560
6856
|
const status = req.query.status ?? "active";
|
|
5561
6857
|
const isPageNumber = isFinite(page);
|
|
5562
6858
|
if (!isPageNumber) {
|
|
5563
|
-
next(new
|
|
6859
|
+
next(new BadRequestError38("Invalid page number."));
|
|
5564
6860
|
return;
|
|
5565
6861
|
}
|
|
5566
6862
|
const isLimitNumber = isFinite(limit);
|
|
5567
6863
|
if (!isLimitNumber) {
|
|
5568
|
-
next(new
|
|
6864
|
+
next(new BadRequestError38("Invalid limit number."));
|
|
5569
6865
|
return;
|
|
5570
6866
|
}
|
|
5571
6867
|
if (error) {
|
|
5572
|
-
next(new
|
|
6868
|
+
next(new BadRequestError38(error.message));
|
|
5573
6869
|
return;
|
|
5574
6870
|
}
|
|
5575
6871
|
try {
|
|
@@ -5582,12 +6878,12 @@ function useOrgController() {
|
|
|
5582
6878
|
}
|
|
5583
6879
|
async function getByName(req, res, next) {
|
|
5584
6880
|
const name = req.params.name;
|
|
5585
|
-
const validation =
|
|
5586
|
-
name:
|
|
6881
|
+
const validation = Joi29.object({
|
|
6882
|
+
name: Joi29.string().required()
|
|
5587
6883
|
});
|
|
5588
6884
|
const { error } = validation.validate({ name });
|
|
5589
6885
|
if (error) {
|
|
5590
|
-
next(new
|
|
6886
|
+
next(new BadRequestError38(error.message));
|
|
5591
6887
|
return;
|
|
5592
6888
|
}
|
|
5593
6889
|
try {
|
|
@@ -5600,12 +6896,12 @@ function useOrgController() {
|
|
|
5600
6896
|
}
|
|
5601
6897
|
async function getById(req, res, next) {
|
|
5602
6898
|
const id = req.params.id;
|
|
5603
|
-
const validation =
|
|
5604
|
-
id:
|
|
6899
|
+
const validation = Joi29.object({
|
|
6900
|
+
id: Joi29.string().hex().required()
|
|
5605
6901
|
});
|
|
5606
6902
|
const { error } = validation.validate({ id });
|
|
5607
6903
|
if (error) {
|
|
5608
|
-
next(new
|
|
6904
|
+
next(new BadRequestError38(error.message));
|
|
5609
6905
|
return;
|
|
5610
6906
|
}
|
|
5611
6907
|
try {
|
|
@@ -5616,12 +6912,29 @@ function useOrgController() {
|
|
|
5616
6912
|
next(error2);
|
|
5617
6913
|
}
|
|
5618
6914
|
}
|
|
6915
|
+
async function updateById(req, res, next) {
|
|
6916
|
+
const _id = req.params.id ?? "";
|
|
6917
|
+
const payload = req.body;
|
|
6918
|
+
const { error } = schemaOrgUpdate.validate({ _id, ...payload });
|
|
6919
|
+
if (error) {
|
|
6920
|
+
next(new BadRequestError38(error.message));
|
|
6921
|
+
return;
|
|
6922
|
+
}
|
|
6923
|
+
try {
|
|
6924
|
+
const message = await _updateById(_id, payload);
|
|
6925
|
+
res.json({ message });
|
|
6926
|
+
return;
|
|
6927
|
+
} catch (error2) {
|
|
6928
|
+
next(error2);
|
|
6929
|
+
}
|
|
6930
|
+
}
|
|
5619
6931
|
return {
|
|
5620
6932
|
add,
|
|
5621
6933
|
getOrgsByUserId,
|
|
5622
6934
|
getByName,
|
|
5623
6935
|
getAll,
|
|
5624
|
-
getById
|
|
6936
|
+
getById,
|
|
6937
|
+
updateById
|
|
5625
6938
|
};
|
|
5626
6939
|
}
|
|
5627
6940
|
|
|
@@ -5640,12 +6953,12 @@ function useUserService() {
|
|
|
5640
6953
|
const { getAll: getAllPermission } = usePermissionRepo();
|
|
5641
6954
|
const { getById: getOrgById } = useOrgRepo();
|
|
5642
6955
|
async function createDefaultUser() {
|
|
5643
|
-
const session =
|
|
6956
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5644
6957
|
try {
|
|
5645
6958
|
session?.startTransaction();
|
|
5646
6959
|
const _user = await getUserByEmail(DEFAULT_USER_EMAIL);
|
|
5647
6960
|
if (_user) {
|
|
5648
|
-
throw new
|
|
6961
|
+
throw new BadRequestError39(
|
|
5649
6962
|
`User already exists: ${DEFAULT_USER_EMAIL}.`
|
|
5650
6963
|
);
|
|
5651
6964
|
}
|
|
@@ -5695,7 +7008,7 @@ function useUserService() {
|
|
|
5695
7008
|
try {
|
|
5696
7009
|
const _user = await getUserByEmail(value.email);
|
|
5697
7010
|
if (_user) {
|
|
5698
|
-
throw new
|
|
7011
|
+
throw new BadRequestError39(`User already exists: ${value.email}.`);
|
|
5699
7012
|
}
|
|
5700
7013
|
const hashedPassword = await hashPassword(value.password);
|
|
5701
7014
|
const insertedId = await addUser({
|
|
@@ -5707,10 +7020,10 @@ function useUserService() {
|
|
|
5707
7020
|
});
|
|
5708
7021
|
return insertedId;
|
|
5709
7022
|
} catch (error) {
|
|
5710
|
-
if (error instanceof
|
|
7023
|
+
if (error instanceof AppError14) {
|
|
5711
7024
|
throw error;
|
|
5712
7025
|
} else {
|
|
5713
|
-
throw new
|
|
7026
|
+
throw new InternalServerError18(`Error creating user: ${error}`);
|
|
5714
7027
|
}
|
|
5715
7028
|
}
|
|
5716
7029
|
}
|
|
@@ -5721,22 +7034,22 @@ function useUserService() {
|
|
|
5721
7034
|
lastName = "",
|
|
5722
7035
|
password = ""
|
|
5723
7036
|
} = {}) {
|
|
5724
|
-
const session =
|
|
7037
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5725
7038
|
session?.startTransaction();
|
|
5726
7039
|
try {
|
|
5727
7040
|
const invitation = await _getVerificationById(id);
|
|
5728
7041
|
if (!invitation || !invitation.metadata?.app || !invitation.metadata?.role) {
|
|
5729
|
-
throw new
|
|
7042
|
+
throw new BadRequestError39("Invalid invitation.");
|
|
5730
7043
|
}
|
|
5731
7044
|
if (invitation.status === "complete") {
|
|
5732
|
-
throw new
|
|
7045
|
+
throw new BadRequestError39("Invitation already used.");
|
|
5733
7046
|
}
|
|
5734
7047
|
if (!invitation.expireAt) {
|
|
5735
|
-
throw new
|
|
7048
|
+
throw new BadRequestError39("Expiration date is required.");
|
|
5736
7049
|
}
|
|
5737
7050
|
const expired = new Date(invitation.expireAt) < /* @__PURE__ */ new Date();
|
|
5738
7051
|
if (invitation.status === "expired" || expired) {
|
|
5739
|
-
throw new
|
|
7052
|
+
throw new BadRequestError39("Invitation expired.");
|
|
5740
7053
|
}
|
|
5741
7054
|
const email = invitation.email;
|
|
5742
7055
|
const user = await getUserByEmail(invitation.email);
|
|
@@ -5787,10 +7100,10 @@ function useUserService() {
|
|
|
5787
7100
|
return userId;
|
|
5788
7101
|
} catch (error) {
|
|
5789
7102
|
await session?.abortTransaction();
|
|
5790
|
-
if (error instanceof
|
|
7103
|
+
if (error instanceof AppError14) {
|
|
5791
7104
|
throw error;
|
|
5792
7105
|
} else {
|
|
5793
|
-
throw new
|
|
7106
|
+
throw new InternalServerError18("Failed to create user by invite.");
|
|
5794
7107
|
}
|
|
5795
7108
|
} finally {
|
|
5796
7109
|
session?.endSession();
|
|
@@ -5802,29 +7115,29 @@ function useUserService() {
|
|
|
5802
7115
|
lastName = "",
|
|
5803
7116
|
password = ""
|
|
5804
7117
|
} = {}) {
|
|
5805
|
-
const session =
|
|
7118
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5806
7119
|
session?.startTransaction();
|
|
5807
7120
|
try {
|
|
5808
7121
|
const signUp = await _getVerificationById(id);
|
|
5809
7122
|
if (!signUp) {
|
|
5810
|
-
throw new
|
|
7123
|
+
throw new BadRequestError39("Invalid sign up link.");
|
|
5811
7124
|
}
|
|
5812
7125
|
if (signUp.status === "complete") {
|
|
5813
|
-
throw new
|
|
7126
|
+
throw new BadRequestError39(
|
|
5814
7127
|
"You have already an account created using this link."
|
|
5815
7128
|
);
|
|
5816
7129
|
}
|
|
5817
7130
|
if (!signUp.expireAt) {
|
|
5818
|
-
throw new
|
|
7131
|
+
throw new BadRequestError39("Expiration date is required.");
|
|
5819
7132
|
}
|
|
5820
7133
|
const expired = new Date(signUp.expireAt) < /* @__PURE__ */ new Date();
|
|
5821
7134
|
if (signUp.status === "expired" || expired) {
|
|
5822
|
-
throw new
|
|
7135
|
+
throw new BadRequestError39("Sign up link expired.");
|
|
5823
7136
|
}
|
|
5824
7137
|
const email = signUp.email;
|
|
5825
7138
|
const _user = await getUserByEmail(signUp.email);
|
|
5826
7139
|
if (_user) {
|
|
5827
|
-
throw new
|
|
7140
|
+
throw new BadRequestError39(`User already exists: ${email}.`);
|
|
5828
7141
|
}
|
|
5829
7142
|
const hashedPassword = await hashPassword(password);
|
|
5830
7143
|
const userId = await addUser(
|
|
@@ -5850,17 +7163,17 @@ function useUserService() {
|
|
|
5850
7163
|
const { updateStatusById: updateVerificationStatusById } = useVerificationRepo();
|
|
5851
7164
|
async function resetPassword(value) {
|
|
5852
7165
|
if (value.newPassword !== value.confirmPassword) {
|
|
5853
|
-
throw new
|
|
7166
|
+
throw new BadRequestError39("Passwords do not match.");
|
|
5854
7167
|
}
|
|
5855
7168
|
let hashedPassword = "";
|
|
5856
7169
|
try {
|
|
5857
7170
|
hashedPassword = await hashPassword(value.newPassword);
|
|
5858
7171
|
} catch (error) {
|
|
5859
|
-
throw new
|
|
7172
|
+
throw new InternalServerError18(`Error hashing password: ${error}`);
|
|
5860
7173
|
}
|
|
5861
|
-
const session =
|
|
7174
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5862
7175
|
if (!session) {
|
|
5863
|
-
throw new
|
|
7176
|
+
throw new InternalServerError18("Failed to start database session.");
|
|
5864
7177
|
}
|
|
5865
7178
|
try {
|
|
5866
7179
|
session.startTransaction();
|
|
@@ -5876,7 +7189,7 @@ function useUserService() {
|
|
|
5876
7189
|
throw new NotFoundError3("User ID is invalid.");
|
|
5877
7190
|
}
|
|
5878
7191
|
if (otpDoc.status === "used") {
|
|
5879
|
-
throw new
|
|
7192
|
+
throw new BadRequestError39("This link has already been invalidated.");
|
|
5880
7193
|
}
|
|
5881
7194
|
await updateVerificationStatusById(value.id, "used", session);
|
|
5882
7195
|
await _updateUserFieldById(
|
|
@@ -5887,31 +7200,31 @@ function useUserService() {
|
|
|
5887
7200
|
return "Successfully reset password.";
|
|
5888
7201
|
} catch (error) {
|
|
5889
7202
|
await session.abortTransaction();
|
|
5890
|
-
if (error instanceof
|
|
7203
|
+
if (error instanceof AppError14) {
|
|
5891
7204
|
throw error;
|
|
5892
7205
|
}
|
|
5893
|
-
throw new
|
|
7206
|
+
throw new InternalServerError18("Failed to reset password.");
|
|
5894
7207
|
}
|
|
5895
7208
|
}
|
|
5896
7209
|
const { updateName: updateMemberName } = useMemberRepo();
|
|
5897
7210
|
async function updateName(_id, firstName, lastName) {
|
|
5898
7211
|
if (!_id) {
|
|
5899
|
-
throw new
|
|
7212
|
+
throw new BadRequestError39("Invalid user ID");
|
|
5900
7213
|
}
|
|
5901
7214
|
if (!firstName) {
|
|
5902
|
-
throw new
|
|
7215
|
+
throw new BadRequestError39("Invalid firstName");
|
|
5903
7216
|
}
|
|
5904
7217
|
if (!lastName) {
|
|
5905
|
-
throw new
|
|
7218
|
+
throw new BadRequestError39("Invalid lastName");
|
|
5906
7219
|
}
|
|
5907
|
-
const session =
|
|
7220
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5908
7221
|
session?.startTransaction();
|
|
5909
|
-
const cacheKey =
|
|
7222
|
+
const cacheKey = makeCacheKey14("users", { user: _id });
|
|
5910
7223
|
try {
|
|
5911
|
-
|
|
5912
|
-
|
|
7224
|
+
useCache15().delCache(cacheKey).then(() => {
|
|
7225
|
+
logger19.info(`Cache cleared for user: ${_id}`);
|
|
5913
7226
|
}).catch((error) => {
|
|
5914
|
-
|
|
7227
|
+
logger19.error(`Failed to clear cache for user: ${_id}`, error);
|
|
5915
7228
|
});
|
|
5916
7229
|
await _updateName({ _id, firstName, lastName }, session);
|
|
5917
7230
|
await updateMemberName(
|
|
@@ -5929,16 +7242,16 @@ function useUserService() {
|
|
|
5929
7242
|
}
|
|
5930
7243
|
async function updateBirthday(_id, month, day, year) {
|
|
5931
7244
|
if (!_id) {
|
|
5932
|
-
throw new
|
|
7245
|
+
throw new BadRequestError39("Invalid user ID");
|
|
5933
7246
|
}
|
|
5934
7247
|
if (!month) {
|
|
5935
|
-
throw new
|
|
7248
|
+
throw new BadRequestError39("Invalid birth month.");
|
|
5936
7249
|
}
|
|
5937
7250
|
if (!day) {
|
|
5938
|
-
throw new
|
|
7251
|
+
throw new BadRequestError39("Invalid birthday.");
|
|
5939
7252
|
}
|
|
5940
7253
|
if (!year) {
|
|
5941
|
-
throw new
|
|
7254
|
+
throw new BadRequestError39("Invalid birth year.");
|
|
5942
7255
|
}
|
|
5943
7256
|
try {
|
|
5944
7257
|
await _updateBirthday({ _id, month, day, year });
|
|
@@ -5963,7 +7276,7 @@ function useUserService() {
|
|
|
5963
7276
|
bucket: SPACES_BUCKET
|
|
5964
7277
|
});
|
|
5965
7278
|
async function updateUserProfile({ file, user, previousProfile } = {}) {
|
|
5966
|
-
const session =
|
|
7279
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
5967
7280
|
session?.startTransaction();
|
|
5968
7281
|
const _file = {
|
|
5969
7282
|
name: file.originalname,
|
|
@@ -6008,11 +7321,11 @@ function useUserService() {
|
|
|
6008
7321
|
|
|
6009
7322
|
// src/resources/user/user.controller.ts
|
|
6010
7323
|
import {
|
|
6011
|
-
AppError as
|
|
6012
|
-
BadRequestError as
|
|
6013
|
-
InternalServerError as
|
|
7324
|
+
AppError as AppError15,
|
|
7325
|
+
BadRequestError as BadRequestError40,
|
|
7326
|
+
InternalServerError as InternalServerError19
|
|
6014
7327
|
} from "@goweekdays/utils";
|
|
6015
|
-
import
|
|
7328
|
+
import Joi30 from "joi";
|
|
6016
7329
|
function useUserController() {
|
|
6017
7330
|
const {
|
|
6018
7331
|
updateName: _updateName,
|
|
@@ -6028,14 +7341,14 @@ function useUserController() {
|
|
|
6028
7341
|
const status = req.query.status ?? "";
|
|
6029
7342
|
const search = req.query.search ?? "";
|
|
6030
7343
|
const page = Number(req.query.page) ?? 1;
|
|
6031
|
-
const validation =
|
|
6032
|
-
status:
|
|
6033
|
-
search:
|
|
6034
|
-
page:
|
|
7344
|
+
const validation = Joi30.object({
|
|
7345
|
+
status: Joi30.string().required(),
|
|
7346
|
+
search: Joi30.string().optional().allow("", null),
|
|
7347
|
+
page: Joi30.number().required()
|
|
6035
7348
|
});
|
|
6036
7349
|
const { error } = validation.validate({ status, search, page });
|
|
6037
7350
|
if (error) {
|
|
6038
|
-
next(new
|
|
7351
|
+
next(new BadRequestError40(error.message));
|
|
6039
7352
|
return;
|
|
6040
7353
|
}
|
|
6041
7354
|
try {
|
|
@@ -6048,14 +7361,14 @@ function useUserController() {
|
|
|
6048
7361
|
}
|
|
6049
7362
|
async function getUserById(req, res, next) {
|
|
6050
7363
|
const id = req.params.id || "";
|
|
6051
|
-
const validation =
|
|
7364
|
+
const validation = Joi30.string().hex().validate(id);
|
|
6052
7365
|
if (validation.error) {
|
|
6053
|
-
throw new
|
|
7366
|
+
throw new BadRequestError40("Invalid id.");
|
|
6054
7367
|
}
|
|
6055
7368
|
try {
|
|
6056
7369
|
const user = await _getUserById(id);
|
|
6057
7370
|
if (!user) {
|
|
6058
|
-
throw new
|
|
7371
|
+
throw new BadRequestError40("User not found.");
|
|
6059
7372
|
}
|
|
6060
7373
|
res.json(user);
|
|
6061
7374
|
} catch (error) {
|
|
@@ -6066,13 +7379,13 @@ function useUserController() {
|
|
|
6066
7379
|
const id = req.headers.user ?? "";
|
|
6067
7380
|
const firstName = req.body.firstName ?? "";
|
|
6068
7381
|
const lastName = req.body.lastName ?? "";
|
|
6069
|
-
const validation =
|
|
6070
|
-
firstName:
|
|
6071
|
-
lastName:
|
|
7382
|
+
const validation = Joi30.object({
|
|
7383
|
+
firstName: Joi30.string().required(),
|
|
7384
|
+
lastName: Joi30.string().required()
|
|
6072
7385
|
});
|
|
6073
7386
|
const { error } = validation.validate({ firstName, lastName });
|
|
6074
7387
|
if (error) {
|
|
6075
|
-
next(new
|
|
7388
|
+
next(new BadRequestError40(error.message));
|
|
6076
7389
|
return;
|
|
6077
7390
|
}
|
|
6078
7391
|
try {
|
|
@@ -6088,14 +7401,14 @@ function useUserController() {
|
|
|
6088
7401
|
const month = req.body.month ?? "";
|
|
6089
7402
|
const day = req.body.day ?? 0;
|
|
6090
7403
|
const year = req.body.year ?? 0;
|
|
6091
|
-
const validation =
|
|
6092
|
-
month:
|
|
6093
|
-
day:
|
|
6094
|
-
year:
|
|
7404
|
+
const validation = Joi30.object({
|
|
7405
|
+
month: Joi30.string().required(),
|
|
7406
|
+
day: Joi30.number().integer().min(1).max(31).required(),
|
|
7407
|
+
year: Joi30.number().integer().min(1900).max((/* @__PURE__ */ new Date()).getFullYear()).required()
|
|
6095
7408
|
});
|
|
6096
7409
|
const { error } = validation.validate({ month, day, year });
|
|
6097
7410
|
if (error) {
|
|
6098
|
-
next(new
|
|
7411
|
+
next(new BadRequestError40(error.message));
|
|
6099
7412
|
return;
|
|
6100
7413
|
}
|
|
6101
7414
|
try {
|
|
@@ -6109,18 +7422,18 @@ function useUserController() {
|
|
|
6109
7422
|
async function updateUserFieldById(req, res, next) {
|
|
6110
7423
|
const _id = req.params.id;
|
|
6111
7424
|
const { field, value } = req.body;
|
|
6112
|
-
const validation =
|
|
6113
|
-
_id:
|
|
6114
|
-
field:
|
|
6115
|
-
value:
|
|
7425
|
+
const validation = Joi30.object({
|
|
7426
|
+
_id: Joi30.string().hex().required(),
|
|
7427
|
+
field: Joi30.string().valid("gender", "email", "contact", "profile").required(),
|
|
7428
|
+
value: Joi30.alternatives().conditional("field", {
|
|
6116
7429
|
is: "email",
|
|
6117
|
-
then:
|
|
6118
|
-
otherwise:
|
|
7430
|
+
then: Joi30.string().email().required(),
|
|
7431
|
+
otherwise: Joi30.string().required()
|
|
6119
7432
|
})
|
|
6120
7433
|
});
|
|
6121
7434
|
const { error } = validation.validate({ _id, field, value });
|
|
6122
7435
|
if (error) {
|
|
6123
|
-
next(new
|
|
7436
|
+
next(new BadRequestError40(error.message));
|
|
6124
7437
|
return;
|
|
6125
7438
|
}
|
|
6126
7439
|
try {
|
|
@@ -6136,12 +7449,12 @@ function useUserController() {
|
|
|
6136
7449
|
return;
|
|
6137
7450
|
}
|
|
6138
7451
|
const previousProfile = req.body.previousProfile ?? "";
|
|
6139
|
-
const validation =
|
|
6140
|
-
previousProfile:
|
|
7452
|
+
const validation = Joi30.object({
|
|
7453
|
+
previousProfile: Joi30.string().hex().optional().allow("", null)
|
|
6141
7454
|
});
|
|
6142
7455
|
const { error } = validation.validate({ previousProfile });
|
|
6143
7456
|
if (error) {
|
|
6144
|
-
next(new
|
|
7457
|
+
next(new BadRequestError40(error.message));
|
|
6145
7458
|
return;
|
|
6146
7459
|
}
|
|
6147
7460
|
const user = req.headers["user"] ?? "";
|
|
@@ -6154,10 +7467,10 @@ function useUserController() {
|
|
|
6154
7467
|
res.json({ message: "Successfully updated profile picture." });
|
|
6155
7468
|
return;
|
|
6156
7469
|
} catch (error2) {
|
|
6157
|
-
if (error2 instanceof
|
|
7470
|
+
if (error2 instanceof AppError15) {
|
|
6158
7471
|
next(error2);
|
|
6159
7472
|
} else {
|
|
6160
|
-
next(new
|
|
7473
|
+
next(new InternalServerError19(error2));
|
|
6161
7474
|
}
|
|
6162
7475
|
}
|
|
6163
7476
|
}
|
|
@@ -6167,12 +7480,12 @@ function useUserController() {
|
|
|
6167
7480
|
const password = req.body.password ?? "";
|
|
6168
7481
|
const id = req.params.id ?? "";
|
|
6169
7482
|
const type = req.body.type ?? "";
|
|
6170
|
-
const validation =
|
|
6171
|
-
firstName:
|
|
6172
|
-
lastName:
|
|
6173
|
-
password:
|
|
6174
|
-
id:
|
|
6175
|
-
type:
|
|
7483
|
+
const validation = Joi30.object({
|
|
7484
|
+
firstName: Joi30.string().required(),
|
|
7485
|
+
lastName: Joi30.string().required(),
|
|
7486
|
+
password: Joi30.string().required(),
|
|
7487
|
+
id: Joi30.string().hex().required(),
|
|
7488
|
+
type: Joi30.string().required()
|
|
6176
7489
|
});
|
|
6177
7490
|
const { error } = validation.validate({
|
|
6178
7491
|
firstName,
|
|
@@ -6182,7 +7495,7 @@ function useUserController() {
|
|
|
6182
7495
|
type
|
|
6183
7496
|
});
|
|
6184
7497
|
if (error) {
|
|
6185
|
-
next(new
|
|
7498
|
+
next(new BadRequestError40(error.message));
|
|
6186
7499
|
return;
|
|
6187
7500
|
}
|
|
6188
7501
|
try {
|
|
@@ -6205,14 +7518,14 @@ function useUserController() {
|
|
|
6205
7518
|
}
|
|
6206
7519
|
async function resetPassword(req, res, next) {
|
|
6207
7520
|
const payload = req.body;
|
|
6208
|
-
const validation =
|
|
6209
|
-
id:
|
|
6210
|
-
newPassword:
|
|
6211
|
-
confirmPassword:
|
|
7521
|
+
const validation = Joi30.object({
|
|
7522
|
+
id: Joi30.string().hex().required(),
|
|
7523
|
+
newPassword: Joi30.string().min(8).required(),
|
|
7524
|
+
confirmPassword: Joi30.string().min(8).required()
|
|
6212
7525
|
});
|
|
6213
7526
|
const { error } = validation.validate(payload);
|
|
6214
7527
|
if (error) {
|
|
6215
|
-
next(new
|
|
7528
|
+
next(new BadRequestError40(error.message));
|
|
6216
7529
|
return;
|
|
6217
7530
|
}
|
|
6218
7531
|
try {
|
|
@@ -6237,7 +7550,7 @@ function useUserController() {
|
|
|
6237
7550
|
}
|
|
6238
7551
|
|
|
6239
7552
|
// src/resources/verification/verification.service.ts
|
|
6240
|
-
import
|
|
7553
|
+
import Joi31 from "joi";
|
|
6241
7554
|
function useVerificationService() {
|
|
6242
7555
|
const MailerConfig = {
|
|
6243
7556
|
host: MAILER_TRANSPORT_HOST,
|
|
@@ -6272,7 +7585,7 @@ function useVerificationService() {
|
|
|
6272
7585
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6273
7586
|
};
|
|
6274
7587
|
if (!metadata.app) {
|
|
6275
|
-
throw new
|
|
7588
|
+
throw new BadRequestError41("App metadata is required.");
|
|
6276
7589
|
}
|
|
6277
7590
|
try {
|
|
6278
7591
|
const user = await getUserByEmail(email);
|
|
@@ -6295,7 +7608,7 @@ function useVerificationService() {
|
|
|
6295
7608
|
html: emailContent2,
|
|
6296
7609
|
from: "GoWeekdays"
|
|
6297
7610
|
}).catch((error) => {
|
|
6298
|
-
|
|
7611
|
+
logger20.log({
|
|
6299
7612
|
level: "error",
|
|
6300
7613
|
message: `Error sending user invite email: ${error}`
|
|
6301
7614
|
});
|
|
@@ -6317,7 +7630,7 @@ function useVerificationService() {
|
|
|
6317
7630
|
html: emailContent,
|
|
6318
7631
|
from: "GoWeekdays"
|
|
6319
7632
|
}).catch((error) => {
|
|
6320
|
-
|
|
7633
|
+
logger20.log({
|
|
6321
7634
|
level: "error",
|
|
6322
7635
|
message: `Error sending user invite email: ${error}`
|
|
6323
7636
|
});
|
|
@@ -6352,14 +7665,14 @@ function useVerificationService() {
|
|
|
6352
7665
|
from: "GoWeekdays",
|
|
6353
7666
|
html: emailContent
|
|
6354
7667
|
}).catch((error) => {
|
|
6355
|
-
|
|
7668
|
+
logger20.log({
|
|
6356
7669
|
level: "error",
|
|
6357
7670
|
message: `Error sending forget password email: ${error}`
|
|
6358
7671
|
});
|
|
6359
7672
|
});
|
|
6360
7673
|
return "Successfully created a link to reset password. Please check your email.";
|
|
6361
7674
|
} catch (error) {
|
|
6362
|
-
throw new
|
|
7675
|
+
throw new InternalServerError20("Failed to create forget password link.");
|
|
6363
7676
|
}
|
|
6364
7677
|
}
|
|
6365
7678
|
async function getById(id) {
|
|
@@ -6398,34 +7711,34 @@ function useVerificationService() {
|
|
|
6398
7711
|
}
|
|
6399
7712
|
function errorByType(type, status) {
|
|
6400
7713
|
if (type === "user-invite" && status === "expired") {
|
|
6401
|
-
throw new
|
|
7714
|
+
throw new BadRequestError41(
|
|
6402
7715
|
"Invitation has already expired, please contact admin to resend the invitation."
|
|
6403
7716
|
);
|
|
6404
7717
|
}
|
|
6405
7718
|
if (type === "user-sign-up" && status === "expired") {
|
|
6406
|
-
throw new
|
|
7719
|
+
throw new BadRequestError41(
|
|
6407
7720
|
"Sign up verification has expired, please sign up again to get a new verification link."
|
|
6408
7721
|
);
|
|
6409
7722
|
}
|
|
6410
7723
|
if (type === "user-invite" && status === "complete") {
|
|
6411
|
-
throw new
|
|
7724
|
+
throw new BadRequestError41(
|
|
6412
7725
|
"User already registered, please login to continue."
|
|
6413
7726
|
);
|
|
6414
7727
|
}
|
|
6415
7728
|
if (type === "forget-password" && status === "complete") {
|
|
6416
|
-
throw new
|
|
7729
|
+
throw new BadRequestError41(
|
|
6417
7730
|
"Forget password verification has already been used, please request a new one."
|
|
6418
7731
|
);
|
|
6419
7732
|
}
|
|
6420
7733
|
if (type === "forget-password" && status === "expired") {
|
|
6421
|
-
throw new
|
|
7734
|
+
throw new BadRequestError41(
|
|
6422
7735
|
"Forget password verification has expired, please request a new one."
|
|
6423
7736
|
);
|
|
6424
7737
|
}
|
|
6425
|
-
throw new
|
|
7738
|
+
throw new BadRequestError41("Invalid verification.");
|
|
6426
7739
|
}
|
|
6427
7740
|
async function verify(id) {
|
|
6428
|
-
const session =
|
|
7741
|
+
const session = useAtlas19.getClient()?.startSession();
|
|
6429
7742
|
session?.startTransaction();
|
|
6430
7743
|
try {
|
|
6431
7744
|
const _id = await _getById(id);
|
|
@@ -6436,10 +7749,10 @@ function useVerificationService() {
|
|
|
6436
7749
|
errorByType(_id.type, "expired");
|
|
6437
7750
|
}
|
|
6438
7751
|
if (_id.status === "complete") {
|
|
6439
|
-
throw new
|
|
7752
|
+
throw new BadRequestError41("Verification already completed.");
|
|
6440
7753
|
}
|
|
6441
7754
|
if (!_id.expireAt) {
|
|
6442
|
-
throw new
|
|
7755
|
+
throw new BadRequestError41("Expiration date is required.");
|
|
6443
7756
|
}
|
|
6444
7757
|
const expiration = new Date(_id.expireAt).getTime();
|
|
6445
7758
|
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
@@ -6455,12 +7768,12 @@ function useVerificationService() {
|
|
|
6455
7768
|
throw new NotFoundError4("User not found for member invite.");
|
|
6456
7769
|
}
|
|
6457
7770
|
if (!_id.metadata?.app) {
|
|
6458
|
-
throw new
|
|
7771
|
+
throw new BadRequestError41(
|
|
6459
7772
|
"App metadata is required for member invite."
|
|
6460
7773
|
);
|
|
6461
7774
|
}
|
|
6462
7775
|
if (!_id.metadata?.role || !_id.metadata?.roleName) {
|
|
6463
|
-
throw new
|
|
7776
|
+
throw new BadRequestError41(
|
|
6464
7777
|
"Role metadata is required for member invite."
|
|
6465
7778
|
);
|
|
6466
7779
|
}
|
|
@@ -6482,7 +7795,7 @@ function useVerificationService() {
|
|
|
6482
7795
|
return _id;
|
|
6483
7796
|
} catch (error) {
|
|
6484
7797
|
await session?.abortTransaction();
|
|
6485
|
-
|
|
7798
|
+
logger20.log({
|
|
6486
7799
|
level: "info",
|
|
6487
7800
|
message: `Error verifying user invitation: ${error}`
|
|
6488
7801
|
});
|
|
@@ -6495,7 +7808,7 @@ function useVerificationService() {
|
|
|
6495
7808
|
try {
|
|
6496
7809
|
await updateStatusById(id, "cancelled");
|
|
6497
7810
|
} catch (error) {
|
|
6498
|
-
throw new
|
|
7811
|
+
throw new InternalServerError20(
|
|
6499
7812
|
`Error cancelling user invitation: ${error}`
|
|
6500
7813
|
);
|
|
6501
7814
|
}
|
|
@@ -6515,7 +7828,7 @@ function useVerificationService() {
|
|
|
6515
7828
|
try {
|
|
6516
7829
|
const user = await getUserByEmail(email);
|
|
6517
7830
|
if (user) {
|
|
6518
|
-
throw new
|
|
7831
|
+
throw new BadRequestError41(
|
|
6519
7832
|
`Email ${email} is already registered, please login to continue.`
|
|
6520
7833
|
);
|
|
6521
7834
|
}
|
|
@@ -6542,7 +7855,7 @@ function useVerificationService() {
|
|
|
6542
7855
|
html: emailContent,
|
|
6543
7856
|
from: "GoWeekdays"
|
|
6544
7857
|
}).catch((error) => {
|
|
6545
|
-
|
|
7858
|
+
logger20.log({
|
|
6546
7859
|
level: "error",
|
|
6547
7860
|
message: `Error sending user invite email: ${error}`
|
|
6548
7861
|
});
|
|
@@ -6555,7 +7868,7 @@ function useVerificationService() {
|
|
|
6555
7868
|
async function inviteMember(value) {
|
|
6556
7869
|
const { error } = schemaInviteMember.validate(value);
|
|
6557
7870
|
if (error) {
|
|
6558
|
-
throw new
|
|
7871
|
+
throw new BadRequestError41(error.message);
|
|
6559
7872
|
}
|
|
6560
7873
|
const role = await getRoleById(value.role);
|
|
6561
7874
|
if (!role) {
|
|
@@ -6599,7 +7912,7 @@ function useVerificationService() {
|
|
|
6599
7912
|
html: emailContent2,
|
|
6600
7913
|
from: "GoWeekdays"
|
|
6601
7914
|
}).catch((error2) => {
|
|
6602
|
-
|
|
7915
|
+
logger20.log({
|
|
6603
7916
|
level: "error",
|
|
6604
7917
|
message: `Error sending user invite email: ${error2}`
|
|
6605
7918
|
});
|
|
@@ -6621,24 +7934,24 @@ function useVerificationService() {
|
|
|
6621
7934
|
html: emailContent,
|
|
6622
7935
|
from: "GoWeekdays"
|
|
6623
7936
|
}).catch((error2) => {
|
|
6624
|
-
|
|
7937
|
+
logger20.log({
|
|
6625
7938
|
level: "error",
|
|
6626
7939
|
message: `Error sending user invite email: ${error2}`
|
|
6627
7940
|
});
|
|
6628
7941
|
});
|
|
6629
7942
|
return verificationId;
|
|
6630
7943
|
} catch (error2) {
|
|
6631
|
-
if (error2 instanceof
|
|
7944
|
+
if (error2 instanceof AppError16) {
|
|
6632
7945
|
throw error2;
|
|
6633
7946
|
} else {
|
|
6634
|
-
throw new
|
|
7947
|
+
throw new InternalServerError20("Failed to invite member.");
|
|
6635
7948
|
}
|
|
6636
7949
|
}
|
|
6637
7950
|
}
|
|
6638
7951
|
async function cancelInviteMember(id) {
|
|
6639
|
-
const { error } =
|
|
7952
|
+
const { error } = Joi31.string().hex().required().validate(id);
|
|
6640
7953
|
if (error) {
|
|
6641
|
-
throw new
|
|
7954
|
+
throw new BadRequestError41("Invalid verification ID.");
|
|
6642
7955
|
}
|
|
6643
7956
|
try {
|
|
6644
7957
|
const invite = await _getById(id);
|
|
@@ -6646,25 +7959,25 @@ function useVerificationService() {
|
|
|
6646
7959
|
throw new NotFoundError4("Invitation not found.");
|
|
6647
7960
|
}
|
|
6648
7961
|
if (invite.status === "cancelled") {
|
|
6649
|
-
throw new
|
|
7962
|
+
throw new BadRequestError41("Invitation already cancelled.");
|
|
6650
7963
|
}
|
|
6651
7964
|
if (invite.status === "complete") {
|
|
6652
|
-
throw new
|
|
7965
|
+
throw new BadRequestError41("Cannot cancel a completed invitation.");
|
|
6653
7966
|
}
|
|
6654
7967
|
await _updateStatusById(id, "cancelled");
|
|
6655
7968
|
return "Successfully cancelled the invitation.";
|
|
6656
7969
|
} catch (error2) {
|
|
6657
|
-
if (error2 instanceof
|
|
7970
|
+
if (error2 instanceof AppError16) {
|
|
6658
7971
|
throw error2;
|
|
6659
7972
|
} else {
|
|
6660
|
-
throw new
|
|
7973
|
+
throw new InternalServerError20("Failed to cancel the invitation.");
|
|
6661
7974
|
}
|
|
6662
7975
|
}
|
|
6663
7976
|
}
|
|
6664
7977
|
async function forgetPassword(email) {
|
|
6665
|
-
const { error } =
|
|
7978
|
+
const { error } = Joi31.string().email().required().validate(email);
|
|
6666
7979
|
if (error) {
|
|
6667
|
-
throw new
|
|
7980
|
+
throw new BadRequestError41("Invalid email address.");
|
|
6668
7981
|
}
|
|
6669
7982
|
try {
|
|
6670
7983
|
const member = await getUserByEmail(email);
|
|
@@ -6693,17 +8006,17 @@ function useVerificationService() {
|
|
|
6693
8006
|
from: "GoWeekdays",
|
|
6694
8007
|
html: emailContent
|
|
6695
8008
|
}).catch((error2) => {
|
|
6696
|
-
|
|
8009
|
+
logger20.log({
|
|
6697
8010
|
level: "error",
|
|
6698
8011
|
message: `Error sending forget password email: ${error2}`
|
|
6699
8012
|
});
|
|
6700
8013
|
});
|
|
6701
8014
|
return "Successfully created a link to reset password. Please check your email.";
|
|
6702
8015
|
} catch (error2) {
|
|
6703
|
-
if (error2 instanceof
|
|
8016
|
+
if (error2 instanceof AppError16) {
|
|
6704
8017
|
throw error2;
|
|
6705
8018
|
} else {
|
|
6706
|
-
throw new
|
|
8019
|
+
throw new InternalServerError20(
|
|
6707
8020
|
"Failed to process forget password request."
|
|
6708
8021
|
);
|
|
6709
8022
|
}
|
|
@@ -6730,13 +8043,13 @@ function useAuthController() {
|
|
|
6730
8043
|
async function login(req, res, next) {
|
|
6731
8044
|
const email = req.body.email;
|
|
6732
8045
|
const password = req.body.password;
|
|
6733
|
-
const validation =
|
|
6734
|
-
email:
|
|
6735
|
-
password:
|
|
8046
|
+
const validation = Joi32.object({
|
|
8047
|
+
email: Joi32.string().email().required(),
|
|
8048
|
+
password: Joi32.string().required()
|
|
6736
8049
|
});
|
|
6737
8050
|
const { error } = validation.validate({ email, password });
|
|
6738
8051
|
if (error) {
|
|
6739
|
-
next(new
|
|
8052
|
+
next(new BadRequestError42(error.message));
|
|
6740
8053
|
return;
|
|
6741
8054
|
}
|
|
6742
8055
|
try {
|
|
@@ -6752,14 +8065,14 @@ function useAuthController() {
|
|
|
6752
8065
|
res.cookie("sid", session.sid, cookieOptions).cookie("user", session.user, cookieOptions).json({ message: "Login successful" });
|
|
6753
8066
|
return;
|
|
6754
8067
|
} catch (error2) {
|
|
6755
|
-
|
|
8068
|
+
logger21.log({
|
|
6756
8069
|
level: "error",
|
|
6757
8070
|
message: `Error during login: ${error2.message}`
|
|
6758
8071
|
});
|
|
6759
|
-
if (error2 instanceof
|
|
8072
|
+
if (error2 instanceof AppError17) {
|
|
6760
8073
|
next(error2);
|
|
6761
8074
|
} else {
|
|
6762
|
-
next(new
|
|
8075
|
+
next(new InternalServerError21("An unexpected error occurred"));
|
|
6763
8076
|
}
|
|
6764
8077
|
return;
|
|
6765
8078
|
}
|
|
@@ -6767,17 +8080,17 @@ function useAuthController() {
|
|
|
6767
8080
|
async function logout(req, res, next) {
|
|
6768
8081
|
const sid = req.headers["authorization"] ?? "";
|
|
6769
8082
|
if (!sid) {
|
|
6770
|
-
next(new
|
|
8083
|
+
next(new BadRequestError42("Session ID is required"));
|
|
6771
8084
|
return;
|
|
6772
8085
|
}
|
|
6773
8086
|
try {
|
|
6774
8087
|
await useAuthService().logout(sid);
|
|
6775
8088
|
res.json({ message: "Logged out successfully" });
|
|
6776
8089
|
} catch (error) {
|
|
6777
|
-
if (error instanceof
|
|
8090
|
+
if (error instanceof AppError17) {
|
|
6778
8091
|
next(error);
|
|
6779
8092
|
} else {
|
|
6780
|
-
next(new
|
|
8093
|
+
next(new InternalServerError21("An unexpected error occurred"));
|
|
6781
8094
|
}
|
|
6782
8095
|
}
|
|
6783
8096
|
}
|
|
@@ -6788,64 +8101,64 @@ function useAuthController() {
|
|
|
6788
8101
|
}
|
|
6789
8102
|
|
|
6790
8103
|
// 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:
|
|
8104
|
+
import { BadRequestError as BadRequestError43, logger as logger22 } from "@goweekdays/utils";
|
|
8105
|
+
import Joi33 from "joi";
|
|
8106
|
+
import { ObjectId as ObjectId22 } from "mongodb";
|
|
8107
|
+
var schemaBuilding = Joi33.object({
|
|
8108
|
+
_id: Joi33.string().hex().optional(),
|
|
8109
|
+
school: Joi33.string().hex().required(),
|
|
8110
|
+
serial: Joi33.string().optional().allow("", null),
|
|
8111
|
+
name: Joi33.string().required(),
|
|
8112
|
+
levels: Joi33.number().integer().min(1).required(),
|
|
8113
|
+
createdAt: Joi33.date().optional().allow("", null),
|
|
8114
|
+
updatedAt: Joi33.date().optional().allow("", null),
|
|
8115
|
+
deletedAt: Joi33.date().optional().allow("", null),
|
|
8116
|
+
status: Joi33.string().optional().allow("", null)
|
|
6804
8117
|
});
|
|
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:
|
|
8118
|
+
var schemaBuildingUnit = Joi33.object({
|
|
8119
|
+
_id: Joi33.string().hex().optional(),
|
|
8120
|
+
school: Joi33.string().hex().required(),
|
|
8121
|
+
name: Joi33.string().optional().allow("", null),
|
|
8122
|
+
building: Joi33.string().hex().required(),
|
|
8123
|
+
buildingName: Joi33.string().optional().allow("", null),
|
|
8124
|
+
level: Joi33.number().integer().min(1).required(),
|
|
8125
|
+
category: Joi33.string().required(),
|
|
8126
|
+
type: Joi33.string().required(),
|
|
8127
|
+
seating_capacity: Joi33.number().integer().min(0).required(),
|
|
8128
|
+
standing_capacity: Joi33.number().integer().min(0).required(),
|
|
8129
|
+
description: Joi33.string().optional().allow("", null),
|
|
8130
|
+
unit_of_measurement: Joi33.string().valid("sqm").required(),
|
|
8131
|
+
area: Joi33.number().positive().required(),
|
|
8132
|
+
status: Joi33.string().optional().allow("", null)
|
|
6820
8133
|
});
|
|
6821
|
-
var schemaUpdateOptions =
|
|
6822
|
-
name:
|
|
6823
|
-
building:
|
|
6824
|
-
buildingName:
|
|
6825
|
-
level:
|
|
6826
|
-
category:
|
|
6827
|
-
type:
|
|
6828
|
-
seating_capacity:
|
|
6829
|
-
standing_capacity:
|
|
6830
|
-
area:
|
|
8134
|
+
var schemaUpdateOptions = Joi33.object({
|
|
8135
|
+
name: Joi33.string().optional().allow("", null),
|
|
8136
|
+
building: Joi33.string().hex().optional().allow("", null),
|
|
8137
|
+
buildingName: Joi33.string().optional().allow("", null),
|
|
8138
|
+
level: Joi33.number().integer().min(1).optional().allow("", null),
|
|
8139
|
+
category: Joi33.string().optional().allow("", null),
|
|
8140
|
+
type: Joi33.string().optional().allow("", null),
|
|
8141
|
+
seating_capacity: Joi33.number().integer().min(0).optional().allow("", null),
|
|
8142
|
+
standing_capacity: Joi33.number().integer().min(0).optional().allow("", null),
|
|
8143
|
+
area: Joi33.number().positive().optional().allow("", null)
|
|
6831
8144
|
});
|
|
6832
8145
|
function MBuilding(value) {
|
|
6833
8146
|
const { error } = schemaBuilding.validate(value);
|
|
6834
8147
|
if (error) {
|
|
6835
|
-
|
|
6836
|
-
throw new
|
|
8148
|
+
logger22.info(`Building Model: ${error.message}`);
|
|
8149
|
+
throw new BadRequestError43(error.message);
|
|
6837
8150
|
}
|
|
6838
8151
|
if (value._id && typeof value._id === "string") {
|
|
6839
8152
|
try {
|
|
6840
|
-
value._id = new
|
|
8153
|
+
value._id = new ObjectId22(value._id);
|
|
6841
8154
|
} catch (error2) {
|
|
6842
|
-
throw new
|
|
8155
|
+
throw new BadRequestError43("Invalid _id format");
|
|
6843
8156
|
}
|
|
6844
8157
|
}
|
|
6845
8158
|
try {
|
|
6846
|
-
value.school = new
|
|
8159
|
+
value.school = new ObjectId22(value.school);
|
|
6847
8160
|
} catch (error2) {
|
|
6848
|
-
throw new
|
|
8161
|
+
throw new BadRequestError43("Invalid school format");
|
|
6849
8162
|
}
|
|
6850
8163
|
return {
|
|
6851
8164
|
_id: value._id ?? void 0,
|
|
@@ -6862,25 +8175,25 @@ function MBuilding(value) {
|
|
|
6862
8175
|
function MBuildingUnit(value) {
|
|
6863
8176
|
const { error } = schemaBuildingUnit.validate(value);
|
|
6864
8177
|
if (error) {
|
|
6865
|
-
|
|
6866
|
-
throw new
|
|
8178
|
+
logger22.info(`Building Unit Model: ${error.message}`);
|
|
8179
|
+
throw new BadRequestError43(error.message);
|
|
6867
8180
|
}
|
|
6868
8181
|
if (value._id && typeof value._id === "string") {
|
|
6869
8182
|
try {
|
|
6870
|
-
value._id = new
|
|
8183
|
+
value._id = new ObjectId22(value._id);
|
|
6871
8184
|
} catch (error2) {
|
|
6872
|
-
throw new
|
|
8185
|
+
throw new BadRequestError43("Invalid ID");
|
|
6873
8186
|
}
|
|
6874
8187
|
}
|
|
6875
8188
|
try {
|
|
6876
|
-
value.school = new
|
|
8189
|
+
value.school = new ObjectId22(value.school);
|
|
6877
8190
|
} catch (error2) {
|
|
6878
|
-
throw new
|
|
8191
|
+
throw new BadRequestError43("Invalid school ID");
|
|
6879
8192
|
}
|
|
6880
8193
|
try {
|
|
6881
|
-
value.building = new
|
|
8194
|
+
value.building = new ObjectId22(value.building);
|
|
6882
8195
|
} catch (error2) {
|
|
6883
|
-
throw new
|
|
8196
|
+
throw new BadRequestError43("Invalid building ID");
|
|
6884
8197
|
}
|
|
6885
8198
|
return {
|
|
6886
8199
|
_id: value._id ?? void 0,
|
|
@@ -6905,24 +8218,24 @@ function MBuildingUnit(value) {
|
|
|
6905
8218
|
|
|
6906
8219
|
// src/resources/building/building.repository.ts
|
|
6907
8220
|
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
|
|
8221
|
+
AppError as AppError18,
|
|
8222
|
+
BadRequestError as BadRequestError44,
|
|
8223
|
+
InternalServerError as InternalServerError22,
|
|
8224
|
+
logger as logger23,
|
|
8225
|
+
makeCacheKey as makeCacheKey15,
|
|
8226
|
+
paginate as paginate12,
|
|
8227
|
+
useAtlas as useAtlas20,
|
|
8228
|
+
useCache as useCache16
|
|
6916
8229
|
} from "@goweekdays/utils";
|
|
6917
|
-
import { ObjectId as
|
|
8230
|
+
import { ObjectId as ObjectId23 } from "mongodb";
|
|
6918
8231
|
function useBuildingRepo() {
|
|
6919
|
-
const db =
|
|
8232
|
+
const db = useAtlas20.getDb();
|
|
6920
8233
|
if (!db) {
|
|
6921
8234
|
throw new Error("Unable to connect to server.");
|
|
6922
8235
|
}
|
|
6923
8236
|
const namespace_collection = "school.buildings";
|
|
6924
8237
|
const collection = db.collection(namespace_collection);
|
|
6925
|
-
const { getCache, setCache, delNamespace } =
|
|
8238
|
+
const { getCache, setCache, delNamespace } = useCache16(namespace_collection);
|
|
6926
8239
|
async function createIndexes() {
|
|
6927
8240
|
try {
|
|
6928
8241
|
await collection.createIndexes([
|
|
@@ -6935,7 +8248,7 @@ function useBuildingRepo() {
|
|
|
6935
8248
|
}
|
|
6936
8249
|
}
|
|
6937
8250
|
createIndexes().catch((error) => {
|
|
6938
|
-
|
|
8251
|
+
logger23.log({ level: "error", message: `Index creation error: ${error}` });
|
|
6939
8252
|
});
|
|
6940
8253
|
async function add(value, session) {
|
|
6941
8254
|
try {
|
|
@@ -6944,16 +8257,16 @@ function useBuildingRepo() {
|
|
|
6944
8257
|
delCachedData();
|
|
6945
8258
|
return res.insertedId;
|
|
6946
8259
|
} catch (error) {
|
|
6947
|
-
|
|
8260
|
+
logger23.log({
|
|
6948
8261
|
level: "error",
|
|
6949
8262
|
message: error.message
|
|
6950
8263
|
});
|
|
6951
|
-
if (error instanceof
|
|
8264
|
+
if (error instanceof AppError18) {
|
|
6952
8265
|
throw error;
|
|
6953
8266
|
} else {
|
|
6954
8267
|
const isDuplicated = error.message.includes("duplicate");
|
|
6955
8268
|
if (isDuplicated) {
|
|
6956
|
-
throw new
|
|
8269
|
+
throw new BadRequestError44("Building already exists.");
|
|
6957
8270
|
}
|
|
6958
8271
|
throw new Error("Failed to create building.");
|
|
6959
8272
|
}
|
|
@@ -6961,9 +8274,9 @@ function useBuildingRepo() {
|
|
|
6961
8274
|
}
|
|
6962
8275
|
async function updateById(_id, value, session) {
|
|
6963
8276
|
try {
|
|
6964
|
-
_id = new
|
|
8277
|
+
_id = new ObjectId23(_id);
|
|
6965
8278
|
} catch (error) {
|
|
6966
|
-
throw new
|
|
8279
|
+
throw new BadRequestError44("Invalid ID.");
|
|
6967
8280
|
}
|
|
6968
8281
|
try {
|
|
6969
8282
|
const res = await collection.updateOne(
|
|
@@ -6974,11 +8287,11 @@ function useBuildingRepo() {
|
|
|
6974
8287
|
delCachedData();
|
|
6975
8288
|
return res;
|
|
6976
8289
|
} catch (error) {
|
|
6977
|
-
|
|
8290
|
+
logger23.log({
|
|
6978
8291
|
level: "error",
|
|
6979
8292
|
message: error.message
|
|
6980
8293
|
});
|
|
6981
|
-
if (error instanceof
|
|
8294
|
+
if (error instanceof AppError18) {
|
|
6982
8295
|
throw error;
|
|
6983
8296
|
} else {
|
|
6984
8297
|
throw new Error("Failed to update building.");
|
|
@@ -7003,9 +8316,9 @@ function useBuildingRepo() {
|
|
|
7003
8316
|
}
|
|
7004
8317
|
if (school) {
|
|
7005
8318
|
try {
|
|
7006
|
-
query.school = new
|
|
8319
|
+
query.school = new ObjectId23(school);
|
|
7007
8320
|
} catch (error) {
|
|
7008
|
-
throw new
|
|
8321
|
+
throw new BadRequestError44("Invalid school ID.");
|
|
7009
8322
|
}
|
|
7010
8323
|
}
|
|
7011
8324
|
const cacheParams = {
|
|
@@ -7019,15 +8332,15 @@ function useBuildingRepo() {
|
|
|
7019
8332
|
cacheParams.school = school;
|
|
7020
8333
|
if (status !== "active")
|
|
7021
8334
|
cacheParams.status = status;
|
|
7022
|
-
const cacheKey =
|
|
7023
|
-
|
|
8335
|
+
const cacheKey = makeCacheKey15(namespace_collection, cacheParams);
|
|
8336
|
+
logger23.log({
|
|
7024
8337
|
level: "info",
|
|
7025
8338
|
message: `Cache key for getAll buildings: ${cacheKey}`
|
|
7026
8339
|
});
|
|
7027
8340
|
try {
|
|
7028
8341
|
const cached = await getCache(cacheKey);
|
|
7029
8342
|
if (cached) {
|
|
7030
|
-
|
|
8343
|
+
logger23.log({
|
|
7031
8344
|
level: "info",
|
|
7032
8345
|
message: `Cache hit for getAll buildings: ${cacheKey}`
|
|
7033
8346
|
});
|
|
@@ -7040,35 +8353,35 @@ function useBuildingRepo() {
|
|
|
7040
8353
|
{ $limit: limit }
|
|
7041
8354
|
]).toArray();
|
|
7042
8355
|
const length = await collection.countDocuments(query);
|
|
7043
|
-
const data =
|
|
8356
|
+
const data = paginate12(items, page, limit, length);
|
|
7044
8357
|
setCache(cacheKey, data, 600).then(() => {
|
|
7045
|
-
|
|
8358
|
+
logger23.log({
|
|
7046
8359
|
level: "info",
|
|
7047
8360
|
message: `Cache set for getAll buildings: ${cacheKey}`
|
|
7048
8361
|
});
|
|
7049
8362
|
}).catch((err) => {
|
|
7050
|
-
|
|
8363
|
+
logger23.log({
|
|
7051
8364
|
level: "error",
|
|
7052
8365
|
message: `Failed to set cache for getAll buildings: ${err.message}`
|
|
7053
8366
|
});
|
|
7054
8367
|
});
|
|
7055
8368
|
return data;
|
|
7056
8369
|
} catch (error) {
|
|
7057
|
-
|
|
8370
|
+
logger23.log({ level: "error", message: `${error}` });
|
|
7058
8371
|
throw error;
|
|
7059
8372
|
}
|
|
7060
8373
|
}
|
|
7061
8374
|
async function getById(_id) {
|
|
7062
8375
|
try {
|
|
7063
|
-
_id = new
|
|
8376
|
+
_id = new ObjectId23(_id);
|
|
7064
8377
|
} catch (error) {
|
|
7065
|
-
throw new
|
|
8378
|
+
throw new BadRequestError44("Invalid ID.");
|
|
7066
8379
|
}
|
|
7067
|
-
const cacheKey =
|
|
8380
|
+
const cacheKey = makeCacheKey15(namespace_collection, { _id: String(_id) });
|
|
7068
8381
|
try {
|
|
7069
8382
|
const cached = await getCache(cacheKey);
|
|
7070
8383
|
if (cached) {
|
|
7071
|
-
|
|
8384
|
+
logger23.log({
|
|
7072
8385
|
level: "info",
|
|
7073
8386
|
message: `Cache hit for getById building: ${cacheKey}`
|
|
7074
8387
|
});
|
|
@@ -7078,30 +8391,30 @@ function useBuildingRepo() {
|
|
|
7078
8391
|
_id
|
|
7079
8392
|
});
|
|
7080
8393
|
setCache(cacheKey, result, 300).then(() => {
|
|
7081
|
-
|
|
8394
|
+
logger23.log({
|
|
7082
8395
|
level: "info",
|
|
7083
8396
|
message: `Cache set for building by id: ${cacheKey}`
|
|
7084
8397
|
});
|
|
7085
8398
|
}).catch((err) => {
|
|
7086
|
-
|
|
8399
|
+
logger23.log({
|
|
7087
8400
|
level: "error",
|
|
7088
8401
|
message: `Failed to set cache for building by id: ${err.message}`
|
|
7089
8402
|
});
|
|
7090
8403
|
});
|
|
7091
8404
|
return result;
|
|
7092
8405
|
} catch (error) {
|
|
7093
|
-
if (error instanceof
|
|
8406
|
+
if (error instanceof AppError18) {
|
|
7094
8407
|
throw error;
|
|
7095
8408
|
} else {
|
|
7096
|
-
throw new
|
|
8409
|
+
throw new InternalServerError22("Failed to get building.");
|
|
7097
8410
|
}
|
|
7098
8411
|
}
|
|
7099
8412
|
}
|
|
7100
8413
|
async function deleteById(_id, session) {
|
|
7101
8414
|
try {
|
|
7102
|
-
_id = new
|
|
8415
|
+
_id = new ObjectId23(_id);
|
|
7103
8416
|
} catch (error) {
|
|
7104
|
-
throw new
|
|
8417
|
+
throw new BadRequestError44("Invalid ID.");
|
|
7105
8418
|
}
|
|
7106
8419
|
try {
|
|
7107
8420
|
const res = await collection.updateOne(
|
|
@@ -7111,25 +8424,25 @@ function useBuildingRepo() {
|
|
|
7111
8424
|
delCachedData();
|
|
7112
8425
|
return res;
|
|
7113
8426
|
} catch (error) {
|
|
7114
|
-
|
|
8427
|
+
logger23.log({
|
|
7115
8428
|
level: "error",
|
|
7116
8429
|
message: error.message
|
|
7117
8430
|
});
|
|
7118
|
-
if (error instanceof
|
|
8431
|
+
if (error instanceof AppError18) {
|
|
7119
8432
|
throw error;
|
|
7120
8433
|
} else {
|
|
7121
|
-
throw new
|
|
8434
|
+
throw new InternalServerError22("Failed to delete building.");
|
|
7122
8435
|
}
|
|
7123
8436
|
}
|
|
7124
8437
|
}
|
|
7125
8438
|
function delCachedData() {
|
|
7126
8439
|
delNamespace().then(() => {
|
|
7127
|
-
|
|
8440
|
+
logger23.log({
|
|
7128
8441
|
level: "info",
|
|
7129
8442
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
7130
8443
|
});
|
|
7131
8444
|
}).catch((err) => {
|
|
7132
|
-
|
|
8445
|
+
logger23.log({
|
|
7133
8446
|
level: "error",
|
|
7134
8447
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
7135
8448
|
});
|
|
@@ -7146,28 +8459,28 @@ function useBuildingRepo() {
|
|
|
7146
8459
|
}
|
|
7147
8460
|
|
|
7148
8461
|
// src/resources/building/building.service.ts
|
|
7149
|
-
import { BadRequestError as
|
|
8462
|
+
import { BadRequestError as BadRequestError46, NotFoundError as NotFoundError5, useAtlas as useAtlas22 } from "@goweekdays/utils";
|
|
7150
8463
|
|
|
7151
8464
|
// src/resources/building/building-unit.repository.ts
|
|
7152
8465
|
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
|
|
8466
|
+
AppError as AppError19,
|
|
8467
|
+
BadRequestError as BadRequestError45,
|
|
8468
|
+
InternalServerError as InternalServerError23,
|
|
8469
|
+
logger as logger24,
|
|
8470
|
+
makeCacheKey as makeCacheKey16,
|
|
8471
|
+
paginate as paginate13,
|
|
8472
|
+
useAtlas as useAtlas21,
|
|
8473
|
+
useCache as useCache17
|
|
7161
8474
|
} from "@goweekdays/utils";
|
|
7162
|
-
import { ObjectId as
|
|
8475
|
+
import { ObjectId as ObjectId24 } from "mongodb";
|
|
7163
8476
|
function useBuildingUnitRepo() {
|
|
7164
|
-
const db =
|
|
8477
|
+
const db = useAtlas21.getDb();
|
|
7165
8478
|
if (!db) {
|
|
7166
8479
|
throw new Error("Unable to connect to server.");
|
|
7167
8480
|
}
|
|
7168
8481
|
const namespace_collection = "school.building-units";
|
|
7169
8482
|
const collection = db.collection(namespace_collection);
|
|
7170
|
-
const { getCache, setCache, delNamespace } =
|
|
8483
|
+
const { getCache, setCache, delNamespace } = useCache17(namespace_collection);
|
|
7171
8484
|
async function createIndexes() {
|
|
7172
8485
|
try {
|
|
7173
8486
|
await collection.createIndexes([
|
|
@@ -7195,12 +8508,12 @@ function useBuildingUnitRepo() {
|
|
|
7195
8508
|
}
|
|
7196
8509
|
function delCachedData() {
|
|
7197
8510
|
delNamespace().then(() => {
|
|
7198
|
-
|
|
8511
|
+
logger24.log({
|
|
7199
8512
|
level: "info",
|
|
7200
8513
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
7201
8514
|
});
|
|
7202
8515
|
}).catch((err) => {
|
|
7203
|
-
|
|
8516
|
+
logger24.log({
|
|
7204
8517
|
level: "error",
|
|
7205
8518
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
7206
8519
|
});
|
|
@@ -7213,11 +8526,11 @@ function useBuildingUnitRepo() {
|
|
|
7213
8526
|
delCachedData();
|
|
7214
8527
|
return res.insertedId;
|
|
7215
8528
|
} catch (error) {
|
|
7216
|
-
|
|
8529
|
+
logger24.log({
|
|
7217
8530
|
level: "error",
|
|
7218
8531
|
message: error.message
|
|
7219
8532
|
});
|
|
7220
|
-
if (error instanceof
|
|
8533
|
+
if (error instanceof AppError19) {
|
|
7221
8534
|
throw error;
|
|
7222
8535
|
} else {
|
|
7223
8536
|
throw new Error("Failed to create building unit.");
|
|
@@ -7227,12 +8540,12 @@ function useBuildingUnitRepo() {
|
|
|
7227
8540
|
async function updateById(_id, value, session) {
|
|
7228
8541
|
const { error } = schemaUpdateOptions.validate(value);
|
|
7229
8542
|
if (error) {
|
|
7230
|
-
throw new
|
|
8543
|
+
throw new BadRequestError45(error.message);
|
|
7231
8544
|
}
|
|
7232
8545
|
try {
|
|
7233
|
-
_id = new
|
|
8546
|
+
_id = new ObjectId24(_id);
|
|
7234
8547
|
} catch (error2) {
|
|
7235
|
-
throw new
|
|
8548
|
+
throw new BadRequestError45("Invalid ID.");
|
|
7236
8549
|
}
|
|
7237
8550
|
try {
|
|
7238
8551
|
const res = await collection.updateOne(
|
|
@@ -7243,11 +8556,11 @@ function useBuildingUnitRepo() {
|
|
|
7243
8556
|
delCachedData();
|
|
7244
8557
|
return res;
|
|
7245
8558
|
} catch (error2) {
|
|
7246
|
-
|
|
8559
|
+
logger24.log({
|
|
7247
8560
|
level: "error",
|
|
7248
8561
|
message: error2.message
|
|
7249
8562
|
});
|
|
7250
|
-
if (error2 instanceof
|
|
8563
|
+
if (error2 instanceof AppError19) {
|
|
7251
8564
|
throw error2;
|
|
7252
8565
|
} else {
|
|
7253
8566
|
throw new Error("Failed to create building unit.");
|
|
@@ -7257,12 +8570,12 @@ function useBuildingUnitRepo() {
|
|
|
7257
8570
|
async function updateByBuildingId(building, value, session) {
|
|
7258
8571
|
const { error } = schemaUpdateOptions.validate(value);
|
|
7259
8572
|
if (error) {
|
|
7260
|
-
throw new
|
|
8573
|
+
throw new BadRequestError45(error.message);
|
|
7261
8574
|
}
|
|
7262
8575
|
try {
|
|
7263
|
-
building = new
|
|
8576
|
+
building = new ObjectId24(building);
|
|
7264
8577
|
} catch (error2) {
|
|
7265
|
-
throw new
|
|
8578
|
+
throw new BadRequestError45("Invalid building ID.");
|
|
7266
8579
|
}
|
|
7267
8580
|
try {
|
|
7268
8581
|
const res = await collection.updateMany(
|
|
@@ -7273,11 +8586,11 @@ function useBuildingUnitRepo() {
|
|
|
7273
8586
|
delCachedData();
|
|
7274
8587
|
return res;
|
|
7275
8588
|
} catch (error2) {
|
|
7276
|
-
|
|
8589
|
+
logger24.log({
|
|
7277
8590
|
level: "error",
|
|
7278
8591
|
message: error2.message
|
|
7279
8592
|
});
|
|
7280
|
-
if (error2 instanceof
|
|
8593
|
+
if (error2 instanceof AppError19) {
|
|
7281
8594
|
throw error2;
|
|
7282
8595
|
} else {
|
|
7283
8596
|
throw new Error("Failed to update building unit.");
|
|
@@ -7304,16 +8617,16 @@ function useBuildingUnitRepo() {
|
|
|
7304
8617
|
}
|
|
7305
8618
|
if (school) {
|
|
7306
8619
|
try {
|
|
7307
|
-
query.school = new
|
|
8620
|
+
query.school = new ObjectId24(school);
|
|
7308
8621
|
} catch (error) {
|
|
7309
|
-
throw new
|
|
8622
|
+
throw new BadRequestError45("Invalid school ID.");
|
|
7310
8623
|
}
|
|
7311
8624
|
}
|
|
7312
8625
|
if (building) {
|
|
7313
8626
|
try {
|
|
7314
|
-
query.building = new
|
|
8627
|
+
query.building = new ObjectId24(building);
|
|
7315
8628
|
} catch (error) {
|
|
7316
|
-
throw new
|
|
8629
|
+
throw new BadRequestError45("Invalid building ID.");
|
|
7317
8630
|
}
|
|
7318
8631
|
}
|
|
7319
8632
|
const cacheParams = {
|
|
@@ -7329,15 +8642,15 @@ function useBuildingUnitRepo() {
|
|
|
7329
8642
|
cacheParams.building = building;
|
|
7330
8643
|
if (status !== "active")
|
|
7331
8644
|
cacheParams.status = status;
|
|
7332
|
-
const cacheKey =
|
|
7333
|
-
|
|
8645
|
+
const cacheKey = makeCacheKey16(namespace_collection, cacheParams);
|
|
8646
|
+
logger24.log({
|
|
7334
8647
|
level: "info",
|
|
7335
8648
|
message: `Cache key for getAll building units: ${cacheKey}`
|
|
7336
8649
|
});
|
|
7337
8650
|
try {
|
|
7338
8651
|
const cached = await getCache(cacheKey);
|
|
7339
8652
|
if (cached) {
|
|
7340
|
-
|
|
8653
|
+
logger24.log({
|
|
7341
8654
|
level: "info",
|
|
7342
8655
|
message: `Cache hit for getAll building units: ${cacheKey}`
|
|
7343
8656
|
});
|
|
@@ -7350,35 +8663,35 @@ function useBuildingUnitRepo() {
|
|
|
7350
8663
|
{ $limit: limit }
|
|
7351
8664
|
]).toArray();
|
|
7352
8665
|
const length = await collection.countDocuments(query);
|
|
7353
|
-
const data =
|
|
8666
|
+
const data = paginate13(items, page, limit, length);
|
|
7354
8667
|
setCache(cacheKey, data, 600).then(() => {
|
|
7355
|
-
|
|
8668
|
+
logger24.log({
|
|
7356
8669
|
level: "info",
|
|
7357
8670
|
message: `Cache set for getAll building units: ${cacheKey}`
|
|
7358
8671
|
});
|
|
7359
8672
|
}).catch((err) => {
|
|
7360
|
-
|
|
8673
|
+
logger24.log({
|
|
7361
8674
|
level: "error",
|
|
7362
8675
|
message: `Failed to set cache for getAll building units: ${err.message}`
|
|
7363
8676
|
});
|
|
7364
8677
|
});
|
|
7365
8678
|
return data;
|
|
7366
8679
|
} catch (error) {
|
|
7367
|
-
|
|
8680
|
+
logger24.log({ level: "error", message: `${error}` });
|
|
7368
8681
|
throw error;
|
|
7369
8682
|
}
|
|
7370
8683
|
}
|
|
7371
8684
|
async function getById(_id) {
|
|
7372
8685
|
try {
|
|
7373
|
-
_id = new
|
|
8686
|
+
_id = new ObjectId24(_id);
|
|
7374
8687
|
} catch (error) {
|
|
7375
|
-
throw new
|
|
8688
|
+
throw new BadRequestError45("Invalid ID.");
|
|
7376
8689
|
}
|
|
7377
|
-
const cacheKey =
|
|
8690
|
+
const cacheKey = makeCacheKey16(namespace_collection, { _id: String(_id) });
|
|
7378
8691
|
try {
|
|
7379
8692
|
const cached = await getCache(cacheKey);
|
|
7380
8693
|
if (cached) {
|
|
7381
|
-
|
|
8694
|
+
logger24.log({
|
|
7382
8695
|
level: "info",
|
|
7383
8696
|
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
7384
8697
|
});
|
|
@@ -7389,42 +8702,42 @@ function useBuildingUnitRepo() {
|
|
|
7389
8702
|
deletedAt: { $in: ["", null] }
|
|
7390
8703
|
});
|
|
7391
8704
|
if (!result) {
|
|
7392
|
-
throw new
|
|
8705
|
+
throw new BadRequestError45("Building unit not found.");
|
|
7393
8706
|
}
|
|
7394
8707
|
setCache(cacheKey, result, 300).then(() => {
|
|
7395
|
-
|
|
8708
|
+
logger24.log({
|
|
7396
8709
|
level: "info",
|
|
7397
8710
|
message: `Cache set for building unit by id: ${cacheKey}`
|
|
7398
8711
|
});
|
|
7399
8712
|
}).catch((err) => {
|
|
7400
|
-
|
|
8713
|
+
logger24.log({
|
|
7401
8714
|
level: "error",
|
|
7402
8715
|
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
7403
8716
|
});
|
|
7404
8717
|
});
|
|
7405
8718
|
return result;
|
|
7406
8719
|
} catch (error) {
|
|
7407
|
-
if (error instanceof
|
|
8720
|
+
if (error instanceof AppError19) {
|
|
7408
8721
|
throw error;
|
|
7409
8722
|
} else {
|
|
7410
|
-
throw new
|
|
8723
|
+
throw new InternalServerError23("Failed to get building unit.");
|
|
7411
8724
|
}
|
|
7412
8725
|
}
|
|
7413
8726
|
}
|
|
7414
8727
|
async function getByBuildingLevel(building, level) {
|
|
7415
8728
|
try {
|
|
7416
|
-
building = new
|
|
8729
|
+
building = new ObjectId24(building);
|
|
7417
8730
|
} catch (error) {
|
|
7418
|
-
throw new
|
|
8731
|
+
throw new BadRequestError45("Invalid building ID.");
|
|
7419
8732
|
}
|
|
7420
|
-
const cacheKey =
|
|
8733
|
+
const cacheKey = makeCacheKey16(namespace_collection, {
|
|
7421
8734
|
building: String(building),
|
|
7422
8735
|
level
|
|
7423
8736
|
});
|
|
7424
8737
|
try {
|
|
7425
8738
|
const cached = await getCache(cacheKey);
|
|
7426
8739
|
if (cached) {
|
|
7427
|
-
|
|
8740
|
+
logger24.log({
|
|
7428
8741
|
level: "info",
|
|
7429
8742
|
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
7430
8743
|
});
|
|
@@ -7436,38 +8749,38 @@ function useBuildingUnitRepo() {
|
|
|
7436
8749
|
status: "active"
|
|
7437
8750
|
});
|
|
7438
8751
|
setCache(cacheKey, result, 300).then(() => {
|
|
7439
|
-
|
|
8752
|
+
logger24.log({
|
|
7440
8753
|
level: "info",
|
|
7441
8754
|
message: `Cache set for building unit by id: ${cacheKey}`
|
|
7442
8755
|
});
|
|
7443
8756
|
}).catch((err) => {
|
|
7444
|
-
|
|
8757
|
+
logger24.log({
|
|
7445
8758
|
level: "error",
|
|
7446
8759
|
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
7447
8760
|
});
|
|
7448
8761
|
});
|
|
7449
8762
|
return result;
|
|
7450
8763
|
} catch (error) {
|
|
7451
|
-
if (error instanceof
|
|
8764
|
+
if (error instanceof AppError19) {
|
|
7452
8765
|
throw error;
|
|
7453
8766
|
} else {
|
|
7454
|
-
throw new
|
|
8767
|
+
throw new InternalServerError23("Failed to get building unit.");
|
|
7455
8768
|
}
|
|
7456
8769
|
}
|
|
7457
8770
|
}
|
|
7458
8771
|
async function getByBuilding(building) {
|
|
7459
8772
|
try {
|
|
7460
|
-
building = new
|
|
8773
|
+
building = new ObjectId24(building);
|
|
7461
8774
|
} catch (error) {
|
|
7462
|
-
throw new
|
|
8775
|
+
throw new BadRequestError45("Invalid building ID.");
|
|
7463
8776
|
}
|
|
7464
|
-
const cacheKey =
|
|
8777
|
+
const cacheKey = makeCacheKey16(namespace_collection, {
|
|
7465
8778
|
building: String(building)
|
|
7466
8779
|
});
|
|
7467
8780
|
try {
|
|
7468
8781
|
const cached = await getCache(cacheKey);
|
|
7469
8782
|
if (cached) {
|
|
7470
|
-
|
|
8783
|
+
logger24.log({
|
|
7471
8784
|
level: "info",
|
|
7472
8785
|
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
7473
8786
|
});
|
|
@@ -7478,30 +8791,30 @@ function useBuildingUnitRepo() {
|
|
|
7478
8791
|
status: "active"
|
|
7479
8792
|
});
|
|
7480
8793
|
setCache(cacheKey, result, 300).then(() => {
|
|
7481
|
-
|
|
8794
|
+
logger24.log({
|
|
7482
8795
|
level: "info",
|
|
7483
8796
|
message: `Cache set for building unit by id: ${cacheKey}`
|
|
7484
8797
|
});
|
|
7485
8798
|
}).catch((err) => {
|
|
7486
|
-
|
|
8799
|
+
logger24.log({
|
|
7487
8800
|
level: "error",
|
|
7488
8801
|
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
7489
8802
|
});
|
|
7490
8803
|
});
|
|
7491
8804
|
return result;
|
|
7492
8805
|
} catch (error) {
|
|
7493
|
-
if (error instanceof
|
|
8806
|
+
if (error instanceof AppError19) {
|
|
7494
8807
|
throw error;
|
|
7495
8808
|
} else {
|
|
7496
|
-
throw new
|
|
8809
|
+
throw new InternalServerError23("Failed to get building unit.");
|
|
7497
8810
|
}
|
|
7498
8811
|
}
|
|
7499
8812
|
}
|
|
7500
8813
|
async function deleteById(_id, session) {
|
|
7501
8814
|
try {
|
|
7502
|
-
_id = new
|
|
8815
|
+
_id = new ObjectId24(_id);
|
|
7503
8816
|
} catch (error) {
|
|
7504
|
-
throw new
|
|
8817
|
+
throw new BadRequestError45("Invalid ID.");
|
|
7505
8818
|
}
|
|
7506
8819
|
try {
|
|
7507
8820
|
const res = await collection.updateOne(
|
|
@@ -7512,11 +8825,11 @@ function useBuildingUnitRepo() {
|
|
|
7512
8825
|
delCachedData();
|
|
7513
8826
|
return "Room/Facility deleted successfully.";
|
|
7514
8827
|
} catch (error) {
|
|
7515
|
-
|
|
8828
|
+
logger24.log({
|
|
7516
8829
|
level: "error",
|
|
7517
8830
|
message: error.message
|
|
7518
8831
|
});
|
|
7519
|
-
if (error instanceof
|
|
8832
|
+
if (error instanceof AppError19) {
|
|
7520
8833
|
throw error;
|
|
7521
8834
|
} else {
|
|
7522
8835
|
throw new Error("Failed to deleted room/facility.");
|
|
@@ -7546,7 +8859,7 @@ function useBuildingService() {
|
|
|
7546
8859
|
const { getByBuildingLevel, getByBuilding, updateByBuildingId } = useBuildingUnitRepo();
|
|
7547
8860
|
async function updateById(id, data) {
|
|
7548
8861
|
data.levels = Number(data.levels);
|
|
7549
|
-
const session =
|
|
8862
|
+
const session = useAtlas22.getClient()?.startSession();
|
|
7550
8863
|
try {
|
|
7551
8864
|
const building = await _getById(id);
|
|
7552
8865
|
if (!building) {
|
|
@@ -7555,7 +8868,7 @@ function useBuildingService() {
|
|
|
7555
8868
|
if (data.levels < building.levels) {
|
|
7556
8869
|
const unit = await getByBuildingLevel(id, building.levels);
|
|
7557
8870
|
if (unit) {
|
|
7558
|
-
throw new
|
|
8871
|
+
throw new BadRequestError46(
|
|
7559
8872
|
"Cannot reduce floors, there are existing building units at higher floors."
|
|
7560
8873
|
);
|
|
7561
8874
|
}
|
|
@@ -7577,7 +8890,7 @@ function useBuildingService() {
|
|
|
7577
8890
|
async function deleteById(id) {
|
|
7578
8891
|
const building = await getByBuilding(id);
|
|
7579
8892
|
if (building) {
|
|
7580
|
-
throw new
|
|
8893
|
+
throw new BadRequestError46(
|
|
7581
8894
|
"Cannot delete building with existing room/facility. Please delete room/facility first."
|
|
7582
8895
|
);
|
|
7583
8896
|
}
|
|
@@ -7595,24 +8908,24 @@ function useBuildingService() {
|
|
|
7595
8908
|
}
|
|
7596
8909
|
|
|
7597
8910
|
// src/resources/building/building.controller.ts
|
|
7598
|
-
import { BadRequestError as
|
|
7599
|
-
import
|
|
8911
|
+
import { BadRequestError as BadRequestError47, logger as logger25 } from "@goweekdays/utils";
|
|
8912
|
+
import Joi34 from "joi";
|
|
7600
8913
|
function useBuildingController() {
|
|
7601
8914
|
const { getAll: _getAll, getById: _getById, add: _add } = useBuildingRepo();
|
|
7602
8915
|
const { updateById: _updateById, deleteById: _deleteById } = useBuildingService();
|
|
7603
8916
|
async function createBuilding(req, res, next) {
|
|
7604
8917
|
const value = req.body;
|
|
7605
|
-
const validation =
|
|
7606
|
-
name:
|
|
7607
|
-
school:
|
|
7608
|
-
levels:
|
|
7609
|
-
serial:
|
|
7610
|
-
status:
|
|
8918
|
+
const validation = Joi34.object({
|
|
8919
|
+
name: Joi34.string().required(),
|
|
8920
|
+
school: Joi34.string().hex().required(),
|
|
8921
|
+
levels: Joi34.number().integer().min(1).required(),
|
|
8922
|
+
serial: Joi34.string().optional().allow("", null),
|
|
8923
|
+
status: Joi34.string().optional().allow("", null)
|
|
7611
8924
|
});
|
|
7612
8925
|
const { error } = validation.validate(value);
|
|
7613
8926
|
if (error) {
|
|
7614
|
-
next(new
|
|
7615
|
-
|
|
8927
|
+
next(new BadRequestError47(error.message));
|
|
8928
|
+
logger25.info(`Controller: ${error.message}`);
|
|
7616
8929
|
return;
|
|
7617
8930
|
}
|
|
7618
8931
|
try {
|
|
@@ -7626,18 +8939,18 @@ function useBuildingController() {
|
|
|
7626
8939
|
async function updateById(req, res, next) {
|
|
7627
8940
|
const value = req.body;
|
|
7628
8941
|
const id = req.params.id ?? "";
|
|
7629
|
-
const validation =
|
|
7630
|
-
id:
|
|
7631
|
-
value:
|
|
7632
|
-
name:
|
|
7633
|
-
serial:
|
|
7634
|
-
levels:
|
|
8942
|
+
const validation = Joi34.object({
|
|
8943
|
+
id: Joi34.string().hex().required(),
|
|
8944
|
+
value: Joi34.object({
|
|
8945
|
+
name: Joi34.string().required(),
|
|
8946
|
+
serial: Joi34.string().optional().allow("", null),
|
|
8947
|
+
levels: Joi34.number().integer().min(1).required()
|
|
7635
8948
|
})
|
|
7636
8949
|
});
|
|
7637
8950
|
const { error } = validation.validate({ id, value });
|
|
7638
8951
|
if (error) {
|
|
7639
|
-
next(new
|
|
7640
|
-
|
|
8952
|
+
next(new BadRequestError47(error.message));
|
|
8953
|
+
logger25.info(`Controller: ${error.message}`);
|
|
7641
8954
|
return;
|
|
7642
8955
|
}
|
|
7643
8956
|
try {
|
|
@@ -7650,16 +8963,16 @@ function useBuildingController() {
|
|
|
7650
8963
|
}
|
|
7651
8964
|
async function getAll(req, res, next) {
|
|
7652
8965
|
const query = req.query;
|
|
7653
|
-
const validation =
|
|
7654
|
-
page:
|
|
7655
|
-
limit:
|
|
7656
|
-
search:
|
|
7657
|
-
school:
|
|
7658
|
-
status:
|
|
8966
|
+
const validation = Joi34.object({
|
|
8967
|
+
page: Joi34.number().min(1).optional().allow("", null),
|
|
8968
|
+
limit: Joi34.number().min(1).optional().allow("", null),
|
|
8969
|
+
search: Joi34.string().optional().allow("", null),
|
|
8970
|
+
school: Joi34.string().hex().optional().allow("", null),
|
|
8971
|
+
status: Joi34.string().optional().allow("", null)
|
|
7659
8972
|
});
|
|
7660
8973
|
const { error } = validation.validate(query);
|
|
7661
8974
|
if (error) {
|
|
7662
|
-
next(new
|
|
8975
|
+
next(new BadRequestError47(error.message));
|
|
7663
8976
|
return;
|
|
7664
8977
|
}
|
|
7665
8978
|
const page = parseInt(req.query.page) ?? 1;
|
|
@@ -7693,12 +9006,12 @@ function useBuildingController() {
|
|
|
7693
9006
|
}
|
|
7694
9007
|
async function getById(req, res, next) {
|
|
7695
9008
|
const id = req.params.id;
|
|
7696
|
-
const validation =
|
|
7697
|
-
id:
|
|
9009
|
+
const validation = Joi34.object({
|
|
9010
|
+
id: Joi34.string().hex().required()
|
|
7698
9011
|
});
|
|
7699
9012
|
const { error } = validation.validate({ id });
|
|
7700
9013
|
if (error) {
|
|
7701
|
-
next(new
|
|
9014
|
+
next(new BadRequestError47(error.message));
|
|
7702
9015
|
return;
|
|
7703
9016
|
}
|
|
7704
9017
|
try {
|
|
@@ -7714,12 +9027,12 @@ function useBuildingController() {
|
|
|
7714
9027
|
}
|
|
7715
9028
|
async function deleteById(req, res, next) {
|
|
7716
9029
|
const id = req.params.id;
|
|
7717
|
-
const validation =
|
|
7718
|
-
id:
|
|
9030
|
+
const validation = Joi34.object({
|
|
9031
|
+
id: Joi34.string().hex().required()
|
|
7719
9032
|
});
|
|
7720
9033
|
const { error } = validation.validate({ id });
|
|
7721
9034
|
if (error) {
|
|
7722
|
-
next(new
|
|
9035
|
+
next(new BadRequestError47(error.message));
|
|
7723
9036
|
return;
|
|
7724
9037
|
}
|
|
7725
9038
|
try {
|
|
@@ -7740,11 +9053,11 @@ function useBuildingController() {
|
|
|
7740
9053
|
}
|
|
7741
9054
|
|
|
7742
9055
|
// src/resources/building/building-unit.service.ts
|
|
7743
|
-
import { useAtlas as
|
|
9056
|
+
import { useAtlas as useAtlas23 } from "@goweekdays/utils";
|
|
7744
9057
|
function useBuildingUnitService() {
|
|
7745
9058
|
const { add: _add } = useBuildingUnitRepo();
|
|
7746
9059
|
async function add(value) {
|
|
7747
|
-
const session =
|
|
9060
|
+
const session = useAtlas23.getClient()?.startSession();
|
|
7748
9061
|
if (!session) {
|
|
7749
9062
|
throw new Error("Unable to start session for building unit service.");
|
|
7750
9063
|
}
|
|
@@ -7771,8 +9084,8 @@ function useBuildingUnitService() {
|
|
|
7771
9084
|
}
|
|
7772
9085
|
|
|
7773
9086
|
// src/resources/building/building-unit.controller.ts
|
|
7774
|
-
import { BadRequestError as
|
|
7775
|
-
import
|
|
9087
|
+
import { BadRequestError as BadRequestError48 } from "@goweekdays/utils";
|
|
9088
|
+
import Joi35 from "joi";
|
|
7776
9089
|
function useBuildingUnitController() {
|
|
7777
9090
|
const {
|
|
7778
9091
|
getAll: _getAll,
|
|
@@ -7783,27 +9096,27 @@ function useBuildingUnitController() {
|
|
|
7783
9096
|
const { add: _add } = useBuildingUnitService();
|
|
7784
9097
|
async function add(req, res, next) {
|
|
7785
9098
|
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:
|
|
9099
|
+
const validation = Joi35.object({
|
|
9100
|
+
building: Joi35.object({
|
|
9101
|
+
school: Joi35.string().hex().required(),
|
|
9102
|
+
name: Joi35.string().optional().allow("", null),
|
|
9103
|
+
building: Joi35.string().hex().required(),
|
|
9104
|
+
buildingName: Joi35.string().optional().allow("", null),
|
|
9105
|
+
level: Joi35.number().integer().min(1).required(),
|
|
9106
|
+
category: Joi35.string().required(),
|
|
9107
|
+
type: Joi35.string().required(),
|
|
9108
|
+
seating_capacity: Joi35.number().integer().min(0).required(),
|
|
9109
|
+
standing_capacity: Joi35.number().integer().min(0).required(),
|
|
9110
|
+
description: Joi35.string().optional().allow("", null),
|
|
9111
|
+
unit_of_measurement: Joi35.string().valid("sqm").required(),
|
|
9112
|
+
area: Joi35.number().positive().required(),
|
|
9113
|
+
status: Joi35.string().optional().allow("", null)
|
|
7801
9114
|
}),
|
|
7802
|
-
qty:
|
|
9115
|
+
qty: Joi35.number().integer().min(1).max(20).optional().default(1)
|
|
7803
9116
|
});
|
|
7804
9117
|
const { error } = validation.validate(data);
|
|
7805
9118
|
if (error) {
|
|
7806
|
-
next(new
|
|
9119
|
+
next(new BadRequestError48(error.message));
|
|
7807
9120
|
return;
|
|
7808
9121
|
}
|
|
7809
9122
|
try {
|
|
@@ -7819,13 +9132,13 @@ function useBuildingUnitController() {
|
|
|
7819
9132
|
async function updateById(req, res, next) {
|
|
7820
9133
|
const data = req.body;
|
|
7821
9134
|
const id = req.params.id ?? "";
|
|
7822
|
-
const validation =
|
|
7823
|
-
id:
|
|
9135
|
+
const validation = Joi35.object({
|
|
9136
|
+
id: Joi35.string().hex().required(),
|
|
7824
9137
|
value: schemaUpdateOptions
|
|
7825
9138
|
});
|
|
7826
9139
|
const { error } = validation.validate({ id, value: data });
|
|
7827
9140
|
if (error) {
|
|
7828
|
-
next(new
|
|
9141
|
+
next(new BadRequestError48(error.message));
|
|
7829
9142
|
return;
|
|
7830
9143
|
}
|
|
7831
9144
|
try {
|
|
@@ -7840,17 +9153,17 @@ function useBuildingUnitController() {
|
|
|
7840
9153
|
}
|
|
7841
9154
|
async function getAll(req, res, next) {
|
|
7842
9155
|
const query = req.query;
|
|
7843
|
-
const validation =
|
|
7844
|
-
page:
|
|
7845
|
-
limit:
|
|
7846
|
-
search:
|
|
7847
|
-
school:
|
|
7848
|
-
building:
|
|
7849
|
-
status:
|
|
9156
|
+
const validation = Joi35.object({
|
|
9157
|
+
page: Joi35.number().min(1).optional().allow("", null),
|
|
9158
|
+
limit: Joi35.number().min(1).optional().allow("", null),
|
|
9159
|
+
search: Joi35.string().optional().allow("", null),
|
|
9160
|
+
school: Joi35.string().hex().optional().allow("", null),
|
|
9161
|
+
building: Joi35.string().hex().optional().allow("", null),
|
|
9162
|
+
status: Joi35.string().optional().allow("", null)
|
|
7850
9163
|
});
|
|
7851
9164
|
const { error } = validation.validate(query);
|
|
7852
9165
|
if (error) {
|
|
7853
|
-
next(new
|
|
9166
|
+
next(new BadRequestError48(error.message));
|
|
7854
9167
|
return;
|
|
7855
9168
|
}
|
|
7856
9169
|
const page = parseInt(req.query.page) ?? 1;
|
|
@@ -7886,12 +9199,12 @@ function useBuildingUnitController() {
|
|
|
7886
9199
|
}
|
|
7887
9200
|
async function getById(req, res, next) {
|
|
7888
9201
|
const id = req.params.id;
|
|
7889
|
-
const validation =
|
|
7890
|
-
id:
|
|
9202
|
+
const validation = Joi35.object({
|
|
9203
|
+
id: Joi35.string().hex().required()
|
|
7891
9204
|
});
|
|
7892
9205
|
const { error } = validation.validate({ id });
|
|
7893
9206
|
if (error) {
|
|
7894
|
-
next(new
|
|
9207
|
+
next(new BadRequestError48(error.message));
|
|
7895
9208
|
return;
|
|
7896
9209
|
}
|
|
7897
9210
|
try {
|
|
@@ -7907,12 +9220,12 @@ function useBuildingUnitController() {
|
|
|
7907
9220
|
}
|
|
7908
9221
|
async function deleteById(req, res, next) {
|
|
7909
9222
|
const id = req.params.id;
|
|
7910
|
-
const validation =
|
|
7911
|
-
id:
|
|
9223
|
+
const validation = Joi35.object({
|
|
9224
|
+
id: Joi35.string().hex().required()
|
|
7912
9225
|
});
|
|
7913
9226
|
const { error } = validation.validate({ id });
|
|
7914
9227
|
if (error) {
|
|
7915
|
-
next(new
|
|
9228
|
+
next(new BadRequestError48(error.message));
|
|
7916
9229
|
return;
|
|
7917
9230
|
}
|
|
7918
9231
|
try {
|
|
@@ -7933,14 +9246,14 @@ function useBuildingUnitController() {
|
|
|
7933
9246
|
}
|
|
7934
9247
|
|
|
7935
9248
|
// src/resources/counter/counter.model.ts
|
|
7936
|
-
import { BadRequestError as
|
|
7937
|
-
import { ObjectId as
|
|
9249
|
+
import { BadRequestError as BadRequestError49 } from "@goweekdays/utils";
|
|
9250
|
+
import { ObjectId as ObjectId25 } from "mongodb";
|
|
7938
9251
|
import { z } from "zod";
|
|
7939
9252
|
var TCounter = z.object({
|
|
7940
9253
|
_id: z.union([
|
|
7941
9254
|
z.string().length(24, "Invalid ObjectId hex string"),
|
|
7942
|
-
z.instanceof(
|
|
7943
|
-
]).transform((val) => typeof val === "string" ? new
|
|
9255
|
+
z.instanceof(ObjectId25)
|
|
9256
|
+
]).transform((val) => typeof val === "string" ? new ObjectId25(val) : val).optional(),
|
|
7944
9257
|
count: z.number().int().min(0).default(0),
|
|
7945
9258
|
type: z.string(),
|
|
7946
9259
|
createdAt: z.date().optional().default(() => /* @__PURE__ */ new Date()),
|
|
@@ -7953,7 +9266,7 @@ function useCounterModel(db) {
|
|
|
7953
9266
|
try {
|
|
7954
9267
|
return TCounter.parse(value);
|
|
7955
9268
|
} catch (error) {
|
|
7956
|
-
throw new
|
|
9269
|
+
throw new BadRequestError49(error.issues[0].message);
|
|
7957
9270
|
}
|
|
7958
9271
|
}
|
|
7959
9272
|
function validateCounter(data) {
|
|
@@ -7967,23 +9280,23 @@ function useCounterModel(db) {
|
|
|
7967
9280
|
}
|
|
7968
9281
|
|
|
7969
9282
|
// src/resources/counter/counter.repository.ts
|
|
7970
|
-
import { useAtlas as
|
|
9283
|
+
import { useAtlas as useAtlas24, useCache as useCache18, makeCacheKey as makeCacheKey17, logger as logger26 } from "@goweekdays/utils";
|
|
7971
9284
|
function useCounterRepo() {
|
|
7972
|
-
const db =
|
|
9285
|
+
const db = useAtlas24.getDb();
|
|
7973
9286
|
if (!db) {
|
|
7974
9287
|
throw new Error("Unable to connect to server.");
|
|
7975
9288
|
}
|
|
7976
9289
|
const namespace_collection = "counters";
|
|
7977
9290
|
const { collection, createCounter } = useCounterModel(db);
|
|
7978
|
-
const { getCache, setCache, delNamespace } =
|
|
9291
|
+
const { getCache, setCache, delNamespace } = useCache18(namespace_collection);
|
|
7979
9292
|
function delCachedData() {
|
|
7980
9293
|
delNamespace().then(() => {
|
|
7981
|
-
|
|
9294
|
+
logger26.log({
|
|
7982
9295
|
level: "info",
|
|
7983
9296
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
7984
9297
|
});
|
|
7985
9298
|
}).catch((err) => {
|
|
7986
|
-
|
|
9299
|
+
logger26.log({
|
|
7987
9300
|
level: "error",
|
|
7988
9301
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
7989
9302
|
});
|
|
@@ -8035,11 +9348,11 @@ function useCounterRepo() {
|
|
|
8035
9348
|
}
|
|
8036
9349
|
}
|
|
8037
9350
|
async function getByType(type) {
|
|
8038
|
-
const cacheKey =
|
|
9351
|
+
const cacheKey = makeCacheKey17(namespace_collection, { type });
|
|
8039
9352
|
try {
|
|
8040
9353
|
const cached = await getCache(cacheKey);
|
|
8041
9354
|
if (cached) {
|
|
8042
|
-
|
|
9355
|
+
logger26.log({
|
|
8043
9356
|
level: "info",
|
|
8044
9357
|
message: `Cache hit for getByType counter: ${cacheKey}`
|
|
8045
9358
|
});
|
|
@@ -8048,12 +9361,12 @@ function useCounterRepo() {
|
|
|
8048
9361
|
const data = await collection.findOne({ type });
|
|
8049
9362
|
if (data) {
|
|
8050
9363
|
setCache(cacheKey, data, 300).then(() => {
|
|
8051
|
-
|
|
9364
|
+
logger26.log({
|
|
8052
9365
|
level: "info",
|
|
8053
9366
|
message: `Cache set for counter by type: ${cacheKey}`
|
|
8054
9367
|
});
|
|
8055
9368
|
}).catch((err) => {
|
|
8056
|
-
|
|
9369
|
+
logger26.log({
|
|
8057
9370
|
level: "error",
|
|
8058
9371
|
message: `Failed to set cache for counter by type: ${err.message}`
|
|
8059
9372
|
});
|
|
@@ -8074,7 +9387,7 @@ function useCounterRepo() {
|
|
|
8074
9387
|
}
|
|
8075
9388
|
|
|
8076
9389
|
// src/resources/file/file.service.ts
|
|
8077
|
-
import { logger as
|
|
9390
|
+
import { logger as logger27, useS3 as useS32, useAtlas as useAtlas25 } from "@goweekdays/utils";
|
|
8078
9391
|
import cron from "node-cron";
|
|
8079
9392
|
import * as fs from "fs";
|
|
8080
9393
|
function useFileService() {
|
|
@@ -8092,7 +9405,7 @@ function useFileService() {
|
|
|
8092
9405
|
forcePathStyle: true
|
|
8093
9406
|
});
|
|
8094
9407
|
async function createFile(value) {
|
|
8095
|
-
const session =
|
|
9408
|
+
const session = useAtlas25.getClient()?.startSession();
|
|
8096
9409
|
session?.startTransaction();
|
|
8097
9410
|
const file = {
|
|
8098
9411
|
name: value.originalname,
|
|
@@ -8126,7 +9439,7 @@ function useFileService() {
|
|
|
8126
9439
|
}
|
|
8127
9440
|
}
|
|
8128
9441
|
async function deleteFile(id) {
|
|
8129
|
-
const session =
|
|
9442
|
+
const session = useAtlas25.getClient()?.startSession();
|
|
8130
9443
|
session?.startTransaction();
|
|
8131
9444
|
try {
|
|
8132
9445
|
await deleteFileById(id, session);
|
|
@@ -8147,12 +9460,12 @@ function useFileService() {
|
|
|
8147
9460
|
const file = files[index];
|
|
8148
9461
|
try {
|
|
8149
9462
|
await deleteFile(file._id.toString());
|
|
8150
|
-
await
|
|
9463
|
+
await logger27.log({
|
|
8151
9464
|
level: "info",
|
|
8152
9465
|
message: "Successfully deleted draft files."
|
|
8153
9466
|
});
|
|
8154
9467
|
} catch (error) {
|
|
8155
|
-
|
|
9468
|
+
logger27.log({
|
|
8156
9469
|
level: "info",
|
|
8157
9470
|
message: "Successfully deleted draft files."
|
|
8158
9471
|
});
|
|
@@ -8170,11 +9483,11 @@ function useFileService() {
|
|
|
8170
9483
|
|
|
8171
9484
|
// src/resources/file/file.controller.ts
|
|
8172
9485
|
import {
|
|
8173
|
-
AppError as
|
|
8174
|
-
BadRequestError as
|
|
8175
|
-
InternalServerError as
|
|
9486
|
+
AppError as AppError20,
|
|
9487
|
+
BadRequestError as BadRequestError50,
|
|
9488
|
+
InternalServerError as InternalServerError24
|
|
8176
9489
|
} from "@goweekdays/utils";
|
|
8177
|
-
import
|
|
9490
|
+
import Joi36 from "joi";
|
|
8178
9491
|
function useFileController() {
|
|
8179
9492
|
const { createFile, deleteFile: _deleteFile } = useFileService();
|
|
8180
9493
|
async function upload(req, res, next) {
|
|
@@ -8187,29 +9500,29 @@ function useFileController() {
|
|
|
8187
9500
|
res.json({ message: "Successfully uploaded file", id });
|
|
8188
9501
|
return;
|
|
8189
9502
|
} catch (error) {
|
|
8190
|
-
if (error instanceof
|
|
9503
|
+
if (error instanceof AppError20) {
|
|
8191
9504
|
next(error);
|
|
8192
9505
|
} else {
|
|
8193
|
-
next(new
|
|
9506
|
+
next(new InternalServerError24(error));
|
|
8194
9507
|
}
|
|
8195
9508
|
}
|
|
8196
9509
|
}
|
|
8197
9510
|
async function deleteFile(req, res, next) {
|
|
8198
9511
|
const id = req.params.id;
|
|
8199
|
-
const validation =
|
|
9512
|
+
const validation = Joi36.string().required();
|
|
8200
9513
|
const { error } = validation.validate(id);
|
|
8201
9514
|
if (error) {
|
|
8202
|
-
next(new
|
|
9515
|
+
next(new BadRequestError50(error.message));
|
|
8203
9516
|
}
|
|
8204
9517
|
try {
|
|
8205
9518
|
const message = await _deleteFile(id);
|
|
8206
9519
|
res.json({ message });
|
|
8207
9520
|
return;
|
|
8208
9521
|
} catch (error2) {
|
|
8209
|
-
if (error2 instanceof
|
|
9522
|
+
if (error2 instanceof AppError20) {
|
|
8210
9523
|
next(error2);
|
|
8211
9524
|
} else {
|
|
8212
|
-
next(new
|
|
9525
|
+
next(new InternalServerError24(error2));
|
|
8213
9526
|
}
|
|
8214
9527
|
}
|
|
8215
9528
|
}
|
|
@@ -8220,11 +9533,11 @@ function useFileController() {
|
|
|
8220
9533
|
}
|
|
8221
9534
|
|
|
8222
9535
|
// src/resources/psgc/psgc.model.ts
|
|
8223
|
-
import
|
|
8224
|
-
var schemaPSGC =
|
|
8225
|
-
code:
|
|
8226
|
-
name:
|
|
8227
|
-
type:
|
|
9536
|
+
import Joi37 from "joi";
|
|
9537
|
+
var schemaPSGC = Joi37.object({
|
|
9538
|
+
code: Joi37.string().length(10).required(),
|
|
9539
|
+
name: Joi37.string().required(),
|
|
9540
|
+
type: Joi37.string().valid("Reg", "Prov", "City", "Mun", "Bgy").required()
|
|
8228
9541
|
});
|
|
8229
9542
|
function modelPSGC(data) {
|
|
8230
9543
|
const { error } = schemaPSGC.validate(data);
|
|
@@ -8240,24 +9553,24 @@ function modelPSGC(data) {
|
|
|
8240
9553
|
|
|
8241
9554
|
// src/resources/psgc/psgc.repository.ts
|
|
8242
9555
|
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
|
|
9556
|
+
AppError as AppError21,
|
|
9557
|
+
BadRequestError as BadRequestError51,
|
|
9558
|
+
InternalServerError as InternalServerError25,
|
|
9559
|
+
logger as logger28,
|
|
9560
|
+
makeCacheKey as makeCacheKey18,
|
|
9561
|
+
paginate as paginate14,
|
|
9562
|
+
useAtlas as useAtlas26,
|
|
9563
|
+
useCache as useCache19
|
|
8251
9564
|
} from "@goweekdays/utils";
|
|
8252
|
-
import { ObjectId as
|
|
9565
|
+
import { ObjectId as ObjectId26 } from "mongodb";
|
|
8253
9566
|
function usePSGCRepo() {
|
|
8254
|
-
const db =
|
|
9567
|
+
const db = useAtlas26.getDb();
|
|
8255
9568
|
if (!db) {
|
|
8256
9569
|
throw new Error("Unable to connect to server.");
|
|
8257
9570
|
}
|
|
8258
9571
|
const namespace_collection = "psgc";
|
|
8259
9572
|
const collection = db.collection(namespace_collection);
|
|
8260
|
-
const { getCache, setCache, delNamespace } =
|
|
9573
|
+
const { getCache, setCache, delNamespace } = useCache19(namespace_collection);
|
|
8261
9574
|
async function createIndexes() {
|
|
8262
9575
|
try {
|
|
8263
9576
|
await collection.createIndexes([
|
|
@@ -8271,12 +9584,12 @@ function usePSGCRepo() {
|
|
|
8271
9584
|
}
|
|
8272
9585
|
function delCachedData() {
|
|
8273
9586
|
delNamespace().then(() => {
|
|
8274
|
-
|
|
9587
|
+
logger28.log({
|
|
8275
9588
|
level: "info",
|
|
8276
9589
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
8277
9590
|
});
|
|
8278
9591
|
}).catch((err) => {
|
|
8279
|
-
|
|
9592
|
+
logger28.log({
|
|
8280
9593
|
level: "error",
|
|
8281
9594
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
8282
9595
|
});
|
|
@@ -8289,16 +9602,16 @@ function usePSGCRepo() {
|
|
|
8289
9602
|
delCachedData();
|
|
8290
9603
|
return res.insertedId;
|
|
8291
9604
|
} catch (error) {
|
|
8292
|
-
|
|
9605
|
+
logger28.log({
|
|
8293
9606
|
level: "error",
|
|
8294
9607
|
message: error.message
|
|
8295
9608
|
});
|
|
8296
|
-
if (error instanceof
|
|
9609
|
+
if (error instanceof AppError21) {
|
|
8297
9610
|
throw error;
|
|
8298
9611
|
} else {
|
|
8299
9612
|
const isDuplicated = error.message.includes("duplicate");
|
|
8300
9613
|
if (isDuplicated) {
|
|
8301
|
-
throw new
|
|
9614
|
+
throw new BadRequestError51("Region already exists.");
|
|
8302
9615
|
}
|
|
8303
9616
|
throw new Error("Failed to create PSGC.");
|
|
8304
9617
|
}
|
|
@@ -8334,15 +9647,15 @@ function usePSGCRepo() {
|
|
|
8334
9647
|
query.$text = { $search: search };
|
|
8335
9648
|
cacheKeyOptions.search = search;
|
|
8336
9649
|
}
|
|
8337
|
-
const cacheKey =
|
|
8338
|
-
|
|
9650
|
+
const cacheKey = makeCacheKey18(namespace_collection, cacheKeyOptions);
|
|
9651
|
+
logger28.log({
|
|
8339
9652
|
level: "info",
|
|
8340
9653
|
message: `Cache key for getAll PSGC: ${cacheKey}`
|
|
8341
9654
|
});
|
|
8342
9655
|
try {
|
|
8343
9656
|
const cached = await getCache(cacheKey);
|
|
8344
9657
|
if (cached) {
|
|
8345
|
-
|
|
9658
|
+
logger28.log({
|
|
8346
9659
|
level: "info",
|
|
8347
9660
|
message: `Cache hit for getAll PSGC: ${cacheKey}`
|
|
8348
9661
|
});
|
|
@@ -8355,35 +9668,35 @@ function usePSGCRepo() {
|
|
|
8355
9668
|
{ $limit: limit }
|
|
8356
9669
|
]).toArray();
|
|
8357
9670
|
const length = await collection.countDocuments(query);
|
|
8358
|
-
const data =
|
|
9671
|
+
const data = paginate14(items, page, limit, length);
|
|
8359
9672
|
setCache(cacheKey, data, 600).then(() => {
|
|
8360
|
-
|
|
9673
|
+
logger28.log({
|
|
8361
9674
|
level: "info",
|
|
8362
9675
|
message: `Cache set for getAll PSGC: ${cacheKey}`
|
|
8363
9676
|
});
|
|
8364
9677
|
}).catch((err) => {
|
|
8365
|
-
|
|
9678
|
+
logger28.log({
|
|
8366
9679
|
level: "error",
|
|
8367
9680
|
message: `Failed to set cache for getAll PSGC: ${err.message}`
|
|
8368
9681
|
});
|
|
8369
9682
|
});
|
|
8370
9683
|
return data;
|
|
8371
9684
|
} catch (error) {
|
|
8372
|
-
|
|
9685
|
+
logger28.log({ level: "error", message: `${error}` });
|
|
8373
9686
|
throw error;
|
|
8374
9687
|
}
|
|
8375
9688
|
}
|
|
8376
9689
|
async function getById(_id) {
|
|
8377
9690
|
try {
|
|
8378
|
-
_id = new
|
|
9691
|
+
_id = new ObjectId26(_id);
|
|
8379
9692
|
} catch (error) {
|
|
8380
|
-
throw new
|
|
9693
|
+
throw new BadRequestError51("Invalid ID.");
|
|
8381
9694
|
}
|
|
8382
|
-
const cacheKey =
|
|
9695
|
+
const cacheKey = makeCacheKey18(namespace_collection, { _id: String(_id) });
|
|
8383
9696
|
try {
|
|
8384
9697
|
const cached = await getCache(cacheKey);
|
|
8385
9698
|
if (cached) {
|
|
8386
|
-
|
|
9699
|
+
logger28.log({
|
|
8387
9700
|
level: "info",
|
|
8388
9701
|
message: `Cache hit for getById PSGC: ${cacheKey}`
|
|
8389
9702
|
});
|
|
@@ -8394,25 +9707,25 @@ function usePSGCRepo() {
|
|
|
8394
9707
|
deletedAt: { $in: ["", null] }
|
|
8395
9708
|
});
|
|
8396
9709
|
if (!result) {
|
|
8397
|
-
throw new
|
|
9710
|
+
throw new BadRequestError51("Region not found.");
|
|
8398
9711
|
}
|
|
8399
9712
|
setCache(cacheKey, result, 300).then(() => {
|
|
8400
|
-
|
|
9713
|
+
logger28.log({
|
|
8401
9714
|
level: "info",
|
|
8402
9715
|
message: `Cache set for PSGC by id: ${cacheKey}`
|
|
8403
9716
|
});
|
|
8404
9717
|
}).catch((err) => {
|
|
8405
|
-
|
|
9718
|
+
logger28.log({
|
|
8406
9719
|
level: "error",
|
|
8407
9720
|
message: `Failed to set cache for PSGC by id: ${err.message}`
|
|
8408
9721
|
});
|
|
8409
9722
|
});
|
|
8410
9723
|
return result;
|
|
8411
9724
|
} catch (error) {
|
|
8412
|
-
if (error instanceof
|
|
9725
|
+
if (error instanceof AppError21) {
|
|
8413
9726
|
throw error;
|
|
8414
9727
|
} else {
|
|
8415
|
-
throw new
|
|
9728
|
+
throw new InternalServerError25("Failed to get PSGC.");
|
|
8416
9729
|
}
|
|
8417
9730
|
}
|
|
8418
9731
|
}
|
|
@@ -8436,15 +9749,15 @@ function usePSGCRepo() {
|
|
|
8436
9749
|
query.code = { $regex: `^${prefix}` };
|
|
8437
9750
|
cacheKeyOptions.prefix = prefix;
|
|
8438
9751
|
}
|
|
8439
|
-
const cacheKey =
|
|
8440
|
-
|
|
9752
|
+
const cacheKey = makeCacheKey18(namespace_collection, { name });
|
|
9753
|
+
logger28.log({
|
|
8441
9754
|
level: "info",
|
|
8442
9755
|
message: `Query for getByName PSGC: ${JSON.stringify(query)}`
|
|
8443
9756
|
});
|
|
8444
9757
|
try {
|
|
8445
9758
|
const cached = await getCache(cacheKey);
|
|
8446
9759
|
if (cached) {
|
|
8447
|
-
|
|
9760
|
+
logger28.log({
|
|
8448
9761
|
level: "info",
|
|
8449
9762
|
message: `Cache hit for getByName PSGC: ${cacheKey}`
|
|
8450
9763
|
});
|
|
@@ -8452,36 +9765,36 @@ function usePSGCRepo() {
|
|
|
8452
9765
|
}
|
|
8453
9766
|
const result = await collection.findOne(query);
|
|
8454
9767
|
setCache(cacheKey, result, 300).then(() => {
|
|
8455
|
-
|
|
9768
|
+
logger28.log({
|
|
8456
9769
|
level: "info",
|
|
8457
9770
|
message: `Cache set for PSGC by name: ${cacheKey}`
|
|
8458
9771
|
});
|
|
8459
9772
|
}).catch((err) => {
|
|
8460
|
-
|
|
9773
|
+
logger28.log({
|
|
8461
9774
|
level: "error",
|
|
8462
9775
|
message: `Failed to set cache for PSGC by name: ${err.message}`
|
|
8463
9776
|
});
|
|
8464
9777
|
});
|
|
8465
9778
|
return result;
|
|
8466
9779
|
} catch (error) {
|
|
8467
|
-
if (error instanceof
|
|
9780
|
+
if (error instanceof AppError21) {
|
|
8468
9781
|
throw error;
|
|
8469
9782
|
} else {
|
|
8470
|
-
throw new
|
|
9783
|
+
throw new InternalServerError25("Failed to get PSGC.");
|
|
8471
9784
|
}
|
|
8472
9785
|
}
|
|
8473
9786
|
}
|
|
8474
9787
|
async function updateFieldById({ _id, field, value } = {}, session) {
|
|
8475
9788
|
const allowedFields = ["name"];
|
|
8476
9789
|
if (!allowedFields.includes(field)) {
|
|
8477
|
-
throw new
|
|
9790
|
+
throw new BadRequestError51(
|
|
8478
9791
|
`Field "${field}" is not allowed to be updated.`
|
|
8479
9792
|
);
|
|
8480
9793
|
}
|
|
8481
9794
|
try {
|
|
8482
|
-
_id = new
|
|
9795
|
+
_id = new ObjectId26(_id);
|
|
8483
9796
|
} catch (error) {
|
|
8484
|
-
throw new
|
|
9797
|
+
throw new BadRequestError51("Invalid ID.");
|
|
8485
9798
|
}
|
|
8486
9799
|
try {
|
|
8487
9800
|
await collection.updateOne(
|
|
@@ -8492,14 +9805,14 @@ function usePSGCRepo() {
|
|
|
8492
9805
|
delCachedData();
|
|
8493
9806
|
return `Successfully updated PSGC ${field}.`;
|
|
8494
9807
|
} catch (error) {
|
|
8495
|
-
throw new
|
|
9808
|
+
throw new InternalServerError25(`Failed to update PSGC ${field}.`);
|
|
8496
9809
|
}
|
|
8497
9810
|
}
|
|
8498
9811
|
async function deleteById(_id) {
|
|
8499
9812
|
try {
|
|
8500
|
-
_id = new
|
|
9813
|
+
_id = new ObjectId26(_id);
|
|
8501
9814
|
} catch (error) {
|
|
8502
|
-
throw new
|
|
9815
|
+
throw new BadRequestError51("Invalid ID.");
|
|
8503
9816
|
}
|
|
8504
9817
|
try {
|
|
8505
9818
|
await collection.updateOne(
|
|
@@ -8509,7 +9822,7 @@ function usePSGCRepo() {
|
|
|
8509
9822
|
delCachedData();
|
|
8510
9823
|
return "Successfully deleted PSGC.";
|
|
8511
9824
|
} catch (error) {
|
|
8512
|
-
throw new
|
|
9825
|
+
throw new InternalServerError25("Failed to delete PSGC.");
|
|
8513
9826
|
}
|
|
8514
9827
|
}
|
|
8515
9828
|
return {
|
|
@@ -8524,8 +9837,8 @@ function usePSGCRepo() {
|
|
|
8524
9837
|
}
|
|
8525
9838
|
|
|
8526
9839
|
// src/resources/psgc/psgc.controller.ts
|
|
8527
|
-
import { BadRequestError as
|
|
8528
|
-
import
|
|
9840
|
+
import { BadRequestError as BadRequestError52 } from "@goweekdays/utils";
|
|
9841
|
+
import Joi38 from "joi";
|
|
8529
9842
|
function usePSGCController() {
|
|
8530
9843
|
const {
|
|
8531
9844
|
add: _add,
|
|
@@ -8539,7 +9852,7 @@ function usePSGCController() {
|
|
|
8539
9852
|
const value = req.body;
|
|
8540
9853
|
const { error } = schemaPSGC.validate(value);
|
|
8541
9854
|
if (error) {
|
|
8542
|
-
next(new
|
|
9855
|
+
next(new BadRequestError52(error.message));
|
|
8543
9856
|
return;
|
|
8544
9857
|
}
|
|
8545
9858
|
try {
|
|
@@ -8555,12 +9868,12 @@ function usePSGCController() {
|
|
|
8555
9868
|
}
|
|
8556
9869
|
async function getAll(req, res, next) {
|
|
8557
9870
|
const query = req.query;
|
|
8558
|
-
const validation =
|
|
8559
|
-
page:
|
|
8560
|
-
limit:
|
|
8561
|
-
search:
|
|
8562
|
-
type:
|
|
8563
|
-
prefix:
|
|
9871
|
+
const validation = Joi38.object({
|
|
9872
|
+
page: Joi38.number().min(1).optional().allow("", null),
|
|
9873
|
+
limit: Joi38.number().min(1).optional().allow("", null),
|
|
9874
|
+
search: Joi38.string().optional().allow("", null),
|
|
9875
|
+
type: Joi38.string().valid("Reg", "Prov", "City", "Mun", "Bgy").required(),
|
|
9876
|
+
prefix: Joi38.string().optional().allow("", null)
|
|
8564
9877
|
});
|
|
8565
9878
|
const { error } = validation.validate(query);
|
|
8566
9879
|
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
@@ -8570,16 +9883,16 @@ function usePSGCController() {
|
|
|
8570
9883
|
const prefix = req.query.prefix ? String(req.query.prefix) : "";
|
|
8571
9884
|
const isPageNumber = isFinite(page);
|
|
8572
9885
|
if (!isPageNumber) {
|
|
8573
|
-
next(new
|
|
9886
|
+
next(new BadRequestError52("Invalid page number."));
|
|
8574
9887
|
return;
|
|
8575
9888
|
}
|
|
8576
9889
|
const isLimitNumber = isFinite(limit);
|
|
8577
9890
|
if (!isLimitNumber) {
|
|
8578
|
-
next(new
|
|
9891
|
+
next(new BadRequestError52("Invalid limit number."));
|
|
8579
9892
|
return;
|
|
8580
9893
|
}
|
|
8581
9894
|
if (error) {
|
|
8582
|
-
next(new
|
|
9895
|
+
next(new BadRequestError52(error.message));
|
|
8583
9896
|
return;
|
|
8584
9897
|
}
|
|
8585
9898
|
try {
|
|
@@ -8598,12 +9911,12 @@ function usePSGCController() {
|
|
|
8598
9911
|
}
|
|
8599
9912
|
async function getById(req, res, next) {
|
|
8600
9913
|
const id = req.params.id;
|
|
8601
|
-
const validation =
|
|
8602
|
-
id:
|
|
9914
|
+
const validation = Joi38.object({
|
|
9915
|
+
id: Joi38.string().hex().required()
|
|
8603
9916
|
});
|
|
8604
9917
|
const { error } = validation.validate({ id });
|
|
8605
9918
|
if (error) {
|
|
8606
|
-
next(new
|
|
9919
|
+
next(new BadRequestError52(error.message));
|
|
8607
9920
|
return;
|
|
8608
9921
|
}
|
|
8609
9922
|
try {
|
|
@@ -8619,12 +9932,12 @@ function usePSGCController() {
|
|
|
8619
9932
|
}
|
|
8620
9933
|
async function getByName(req, res, next) {
|
|
8621
9934
|
const name = req.params.name;
|
|
8622
|
-
const validation =
|
|
8623
|
-
name:
|
|
9935
|
+
const validation = Joi38.object({
|
|
9936
|
+
name: Joi38.string().required()
|
|
8624
9937
|
});
|
|
8625
9938
|
const { error } = validation.validate({ name });
|
|
8626
9939
|
if (error) {
|
|
8627
|
-
next(new
|
|
9940
|
+
next(new BadRequestError52(error.message));
|
|
8628
9941
|
return;
|
|
8629
9942
|
}
|
|
8630
9943
|
try {
|
|
@@ -8641,14 +9954,14 @@ function usePSGCController() {
|
|
|
8641
9954
|
async function updateField(req, res, next) {
|
|
8642
9955
|
const _id = req.params.id;
|
|
8643
9956
|
const { field, value } = req.body;
|
|
8644
|
-
const validation =
|
|
8645
|
-
_id:
|
|
8646
|
-
field:
|
|
8647
|
-
value:
|
|
9957
|
+
const validation = Joi38.object({
|
|
9958
|
+
_id: Joi38.string().hex().required(),
|
|
9959
|
+
field: Joi38.string().valid("name", "director", "directorName").required(),
|
|
9960
|
+
value: Joi38.string().required()
|
|
8648
9961
|
});
|
|
8649
9962
|
const { error } = validation.validate({ _id, field, value });
|
|
8650
9963
|
if (error) {
|
|
8651
|
-
next(new
|
|
9964
|
+
next(new BadRequestError52(error.message));
|
|
8652
9965
|
return;
|
|
8653
9966
|
}
|
|
8654
9967
|
try {
|
|
@@ -8661,12 +9974,12 @@ function usePSGCController() {
|
|
|
8661
9974
|
}
|
|
8662
9975
|
async function deleteById(req, res, next) {
|
|
8663
9976
|
const _id = req.params.id;
|
|
8664
|
-
const validation =
|
|
8665
|
-
_id:
|
|
9977
|
+
const validation = Joi38.object({
|
|
9978
|
+
_id: Joi38.string().hex().required()
|
|
8666
9979
|
});
|
|
8667
9980
|
const { error } = validation.validate({ _id });
|
|
8668
9981
|
if (error) {
|
|
8669
|
-
next(new
|
|
9982
|
+
next(new BadRequestError52(error.message));
|
|
8670
9983
|
return;
|
|
8671
9984
|
}
|
|
8672
9985
|
try {
|
|
@@ -8688,7 +10001,7 @@ function usePSGCController() {
|
|
|
8688
10001
|
}
|
|
8689
10002
|
|
|
8690
10003
|
// src/resources/utils/github.service.ts
|
|
8691
|
-
import { AppError as
|
|
10004
|
+
import { AppError as AppError22, BadRequestError as BadRequestError53 } from "@goweekdays/utils";
|
|
8692
10005
|
import { Octokit } from "@octokit/rest";
|
|
8693
10006
|
import _sodium from "libsodium-wrappers";
|
|
8694
10007
|
function useGitHubService() {
|
|
@@ -8702,23 +10015,23 @@ function useGitHubService() {
|
|
|
8702
10015
|
try {
|
|
8703
10016
|
const { data: repoData } = await octokit.repos.get({ owner, repo });
|
|
8704
10017
|
if (!repoData.permissions?.admin) {
|
|
8705
|
-
throw new
|
|
10018
|
+
throw new BadRequestError53(
|
|
8706
10019
|
"You do not have admin access to this repository."
|
|
8707
10020
|
);
|
|
8708
10021
|
}
|
|
8709
10022
|
} catch (error) {
|
|
8710
10023
|
if (error.status === 404) {
|
|
8711
|
-
throw new
|
|
10024
|
+
throw new BadRequestError53(
|
|
8712
10025
|
"Repository not found or you don't have access to it."
|
|
8713
10026
|
);
|
|
8714
10027
|
} else if (error.status === 401) {
|
|
8715
|
-
throw new
|
|
10028
|
+
throw new BadRequestError53(
|
|
8716
10029
|
"Invalid GitHub token or insufficient permissions."
|
|
8717
10030
|
);
|
|
8718
10031
|
} else if (error.message.includes("admin access")) {
|
|
8719
10032
|
throw error;
|
|
8720
10033
|
} else {
|
|
8721
|
-
throw new
|
|
10034
|
+
throw new BadRequestError53(
|
|
8722
10035
|
`Failed to check repository permissions: ${error.message}`
|
|
8723
10036
|
);
|
|
8724
10037
|
}
|
|
@@ -8767,7 +10080,7 @@ function useGitHubService() {
|
|
|
8767
10080
|
key_id: publicKeyRes.key_id
|
|
8768
10081
|
});
|
|
8769
10082
|
} catch (encryptionError) {
|
|
8770
|
-
throw new
|
|
10083
|
+
throw new BadRequestError53(
|
|
8771
10084
|
`Failed to encrypt secret '${key}': ${encryptionError.message}`
|
|
8772
10085
|
);
|
|
8773
10086
|
}
|
|
@@ -8797,22 +10110,22 @@ function useGitHubService() {
|
|
|
8797
10110
|
}
|
|
8798
10111
|
return `Successfully set ${lines.length} ${type} variables/secrets in environment '${environment}'`;
|
|
8799
10112
|
} catch (error) {
|
|
8800
|
-
if (error instanceof
|
|
10113
|
+
if (error instanceof AppError22)
|
|
8801
10114
|
throw error;
|
|
8802
10115
|
if (error.status === 422) {
|
|
8803
|
-
throw new
|
|
10116
|
+
throw new BadRequestError53(
|
|
8804
10117
|
`GitHub API validation error: ${error.message}`
|
|
8805
10118
|
);
|
|
8806
10119
|
} else if (error.status === 404) {
|
|
8807
|
-
throw new
|
|
10120
|
+
throw new BadRequestError53("Environment or repository not found.");
|
|
8808
10121
|
} else if (error.status === 403) {
|
|
8809
|
-
throw new
|
|
10122
|
+
throw new BadRequestError53(
|
|
8810
10123
|
"Forbidden: Insufficient permissions or rate limit exceeded."
|
|
8811
10124
|
);
|
|
8812
10125
|
} else if (error.message.includes("admin access") || error.message.includes("permissions")) {
|
|
8813
10126
|
throw error;
|
|
8814
10127
|
} else {
|
|
8815
|
-
throw new
|
|
10128
|
+
throw new BadRequestError53(
|
|
8816
10129
|
`Failed to set GitHub variables: ${error.message}`
|
|
8817
10130
|
);
|
|
8818
10131
|
}
|
|
@@ -8824,12 +10137,12 @@ function useGitHubService() {
|
|
|
8824
10137
|
}
|
|
8825
10138
|
|
|
8826
10139
|
// src/resources/utils/util.controller.ts
|
|
8827
|
-
import
|
|
10140
|
+
import Joi39 from "joi";
|
|
8828
10141
|
import {
|
|
8829
|
-
AppError as
|
|
8830
|
-
BadRequestError as
|
|
8831
|
-
InternalServerError as
|
|
8832
|
-
logger as
|
|
10142
|
+
AppError as AppError23,
|
|
10143
|
+
BadRequestError as BadRequestError54,
|
|
10144
|
+
InternalServerError as InternalServerError26,
|
|
10145
|
+
logger as logger29
|
|
8833
10146
|
} from "@goweekdays/utils";
|
|
8834
10147
|
function useUtilController() {
|
|
8835
10148
|
async function healthCheck(req, res, next) {
|
|
@@ -8846,32 +10159,32 @@ function useUtilController() {
|
|
|
8846
10159
|
}
|
|
8847
10160
|
});
|
|
8848
10161
|
} catch (error) {
|
|
8849
|
-
|
|
8850
|
-
next(new
|
|
10162
|
+
logger29.error("Health check failed", { error: error.message });
|
|
10163
|
+
next(new InternalServerError26("Health check failed"));
|
|
8851
10164
|
}
|
|
8852
10165
|
}
|
|
8853
10166
|
async function setGitHubVariables(req, res, next) {
|
|
8854
10167
|
try {
|
|
8855
10168
|
const { githubToken, repoUrl, environment, type, keyValues } = req.body;
|
|
8856
|
-
const validation =
|
|
8857
|
-
githubToken:
|
|
10169
|
+
const validation = Joi39.object({
|
|
10170
|
+
githubToken: Joi39.string().required().messages({
|
|
8858
10171
|
"string.empty": "GitHub token is required",
|
|
8859
10172
|
"any.required": "GitHub token is required"
|
|
8860
10173
|
}),
|
|
8861
|
-
repoUrl:
|
|
10174
|
+
repoUrl: Joi39.string().uri().required().messages({
|
|
8862
10175
|
"string.empty": "Repository URL is required",
|
|
8863
10176
|
"string.uri": "Repository URL must be a valid URL",
|
|
8864
10177
|
"any.required": "Repository URL is required"
|
|
8865
10178
|
}),
|
|
8866
|
-
environment:
|
|
10179
|
+
environment: Joi39.string().required().messages({
|
|
8867
10180
|
"string.empty": "Environment name is required",
|
|
8868
10181
|
"any.required": "Environment name is required"
|
|
8869
10182
|
}),
|
|
8870
|
-
type:
|
|
10183
|
+
type: Joi39.string().valid("env", "secret").required().messages({
|
|
8871
10184
|
"any.only": 'Type must be either "env" or "secret"',
|
|
8872
10185
|
"any.required": "Type is required"
|
|
8873
10186
|
}),
|
|
8874
|
-
keyValues:
|
|
10187
|
+
keyValues: Joi39.string().required().messages({
|
|
8875
10188
|
"string.empty": "Key-value pairs are required",
|
|
8876
10189
|
"any.required": "Key-value pairs are required"
|
|
8877
10190
|
})
|
|
@@ -8884,13 +10197,13 @@ function useUtilController() {
|
|
|
8884
10197
|
keyValues
|
|
8885
10198
|
});
|
|
8886
10199
|
if (error) {
|
|
8887
|
-
next(new
|
|
10200
|
+
next(new BadRequestError54(error.message));
|
|
8888
10201
|
return;
|
|
8889
10202
|
}
|
|
8890
10203
|
const repoUrlPattern = /github\.com[:\/]([^\/]+)\/(.+)\.git$/;
|
|
8891
10204
|
if (!repoUrlPattern.test(repoUrl)) {
|
|
8892
10205
|
next(
|
|
8893
|
-
new
|
|
10206
|
+
new BadRequestError54(
|
|
8894
10207
|
"Invalid GitHub repository URL format. Expected format: https://github.com/owner/repo.git"
|
|
8895
10208
|
)
|
|
8896
10209
|
);
|
|
@@ -8902,7 +10215,7 @@ function useUtilController() {
|
|
|
8902
10215
|
);
|
|
8903
10216
|
if (invalidLines.length > 0) {
|
|
8904
10217
|
next(
|
|
8905
|
-
new
|
|
10218
|
+
new BadRequestError54(
|
|
8906
10219
|
"Invalid key-value format. Each pair should be in format: KEY=value. Pairs should be separated by semicolons."
|
|
8907
10220
|
)
|
|
8908
10221
|
);
|
|
@@ -8916,7 +10229,7 @@ function useUtilController() {
|
|
|
8916
10229
|
type,
|
|
8917
10230
|
keyValues
|
|
8918
10231
|
});
|
|
8919
|
-
|
|
10232
|
+
logger29.info(`GitHub variables set successfully`, {
|
|
8920
10233
|
repoUrl,
|
|
8921
10234
|
environment,
|
|
8922
10235
|
type,
|
|
@@ -8933,15 +10246,15 @@ function useUtilController() {
|
|
|
8933
10246
|
}
|
|
8934
10247
|
});
|
|
8935
10248
|
} catch (error) {
|
|
8936
|
-
|
|
10249
|
+
logger29.error("Failed to set GitHub variables", {
|
|
8937
10250
|
error: error.message,
|
|
8938
10251
|
stack: error.stack
|
|
8939
10252
|
});
|
|
8940
|
-
if (error instanceof
|
|
10253
|
+
if (error instanceof AppError23) {
|
|
8941
10254
|
next(error);
|
|
8942
10255
|
} else {
|
|
8943
10256
|
next(
|
|
8944
|
-
new
|
|
10257
|
+
new InternalServerError26(
|
|
8945
10258
|
`Failed to set GitHub variables: ${error.message}`
|
|
8946
10259
|
)
|
|
8947
10260
|
);
|
|
@@ -8955,35 +10268,35 @@ function useUtilController() {
|
|
|
8955
10268
|
}
|
|
8956
10269
|
|
|
8957
10270
|
// 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:
|
|
10271
|
+
import Joi40 from "joi";
|
|
10272
|
+
var transactionSchema = Joi40.object({
|
|
10273
|
+
_id: Joi40.string().hex().optional().allow("", null),
|
|
10274
|
+
payment: Joi40.string().required(),
|
|
10275
|
+
user: Joi40.string().hex().optional().allow("", null),
|
|
10276
|
+
org: Joi40.string().hex().optional().allow("", null),
|
|
10277
|
+
type: Joi40.string().required(),
|
|
10278
|
+
amount: Joi40.number().positive().min(0).required(),
|
|
10279
|
+
currency: Joi40.string().required(),
|
|
10280
|
+
description: Joi40.string().optional().allow("", null),
|
|
10281
|
+
metadata: Joi40.object({
|
|
10282
|
+
subscriptionId: Joi40.string().hex().optional().allow("", null),
|
|
10283
|
+
cycle: Joi40.number().optional().allow("", null),
|
|
10284
|
+
seats: Joi40.number().optional().allow("", null),
|
|
10285
|
+
promoCode: Joi40.string().optional().allow("", null)
|
|
8973
10286
|
}).optional().allow("", null),
|
|
8974
|
-
status:
|
|
8975
|
-
createdAt:
|
|
8976
|
-
updatedAt:
|
|
8977
|
-
deletedAt:
|
|
10287
|
+
status: Joi40.string().optional().allow("", null),
|
|
10288
|
+
createdAt: Joi40.string().optional().allow("", null),
|
|
10289
|
+
updatedAt: Joi40.string().optional().allow("", null),
|
|
10290
|
+
deletedAt: Joi40.string().optional().allow("", null)
|
|
8978
10291
|
});
|
|
8979
10292
|
|
|
8980
10293
|
// src/resources/verification/verification.controller.ts
|
|
8981
10294
|
import {
|
|
8982
|
-
AppError as
|
|
8983
|
-
BadRequestError as
|
|
8984
|
-
InternalServerError as
|
|
10295
|
+
AppError as AppError24,
|
|
10296
|
+
BadRequestError as BadRequestError55,
|
|
10297
|
+
InternalServerError as InternalServerError27
|
|
8985
10298
|
} from "@goweekdays/utils";
|
|
8986
|
-
import
|
|
10299
|
+
import Joi41 from "joi";
|
|
8987
10300
|
function useVerificationController() {
|
|
8988
10301
|
const {
|
|
8989
10302
|
createUserInvite: _createUserInvite,
|
|
@@ -8997,17 +10310,17 @@ function useVerificationController() {
|
|
|
8997
10310
|
} = useVerificationService();
|
|
8998
10311
|
const { getVerifications: _getVerifications } = useVerificationRepo();
|
|
8999
10312
|
async function createUserInvite(req, res, next) {
|
|
9000
|
-
const validation =
|
|
9001
|
-
email:
|
|
9002
|
-
app:
|
|
9003
|
-
role:
|
|
9004
|
-
roleName:
|
|
9005
|
-
org:
|
|
9006
|
-
orgName:
|
|
10313
|
+
const validation = Joi41.object({
|
|
10314
|
+
email: Joi41.string().email().required(),
|
|
10315
|
+
app: Joi41.string().required(),
|
|
10316
|
+
role: Joi41.string().hex().required(),
|
|
10317
|
+
roleName: Joi41.string().required(),
|
|
10318
|
+
org: Joi41.string().hex().optional().optional().allow("", null),
|
|
10319
|
+
orgName: Joi41.string().optional().optional().allow("", null)
|
|
9007
10320
|
});
|
|
9008
10321
|
const { error } = validation.validate(req.body);
|
|
9009
10322
|
if (error) {
|
|
9010
|
-
next(new
|
|
10323
|
+
next(new BadRequestError55(error.message));
|
|
9011
10324
|
return;
|
|
9012
10325
|
}
|
|
9013
10326
|
const email = req.body.email ?? "";
|
|
@@ -9035,10 +10348,10 @@ function useVerificationController() {
|
|
|
9035
10348
|
}
|
|
9036
10349
|
async function createForgetPassword(req, res, next) {
|
|
9037
10350
|
const email = req.body.email || "";
|
|
9038
|
-
const validation =
|
|
10351
|
+
const validation = Joi41.string().email().required();
|
|
9039
10352
|
const { error } = validation.validate(email);
|
|
9040
10353
|
if (error) {
|
|
9041
|
-
next(new
|
|
10354
|
+
next(new BadRequestError55(error.message));
|
|
9042
10355
|
return;
|
|
9043
10356
|
}
|
|
9044
10357
|
try {
|
|
@@ -9048,26 +10361,26 @@ function useVerificationController() {
|
|
|
9048
10361
|
});
|
|
9049
10362
|
return;
|
|
9050
10363
|
} catch (error2) {
|
|
9051
|
-
if (error2 instanceof
|
|
10364
|
+
if (error2 instanceof AppError24) {
|
|
9052
10365
|
next(error2);
|
|
9053
10366
|
} else {
|
|
9054
|
-
next(new
|
|
10367
|
+
next(new InternalServerError27("An unexpected error occurred"));
|
|
9055
10368
|
}
|
|
9056
10369
|
}
|
|
9057
10370
|
}
|
|
9058
10371
|
async function getVerifications(req, res, next) {
|
|
9059
|
-
const validation =
|
|
9060
|
-
status:
|
|
9061
|
-
search:
|
|
9062
|
-
page:
|
|
9063
|
-
type:
|
|
9064
|
-
email:
|
|
9065
|
-
app:
|
|
9066
|
-
org:
|
|
10372
|
+
const validation = Joi41.object({
|
|
10373
|
+
status: Joi41.string().required(),
|
|
10374
|
+
search: Joi41.string().optional().allow("", null),
|
|
10375
|
+
page: Joi41.number().required(),
|
|
10376
|
+
type: Joi41.string().optional().allow("", null),
|
|
10377
|
+
email: Joi41.string().optional().allow("", null),
|
|
10378
|
+
app: Joi41.string().optional().allow("", null),
|
|
10379
|
+
org: Joi41.string().optional().allow("", null)
|
|
9067
10380
|
});
|
|
9068
10381
|
const { error } = validation.validate(req.query);
|
|
9069
10382
|
if (error) {
|
|
9070
|
-
next(new
|
|
10383
|
+
next(new BadRequestError55(error.message));
|
|
9071
10384
|
return;
|
|
9072
10385
|
}
|
|
9073
10386
|
const status = req.query.status ?? "";
|
|
@@ -9100,10 +10413,10 @@ function useVerificationController() {
|
|
|
9100
10413
|
}
|
|
9101
10414
|
async function verify(req, res, next) {
|
|
9102
10415
|
const id = req.params.id || "";
|
|
9103
|
-
const validation =
|
|
10416
|
+
const validation = Joi41.string().hex().required();
|
|
9104
10417
|
const { error } = validation.validate(id);
|
|
9105
10418
|
if (error) {
|
|
9106
|
-
next(new
|
|
10419
|
+
next(new BadRequestError55(error.message));
|
|
9107
10420
|
return;
|
|
9108
10421
|
}
|
|
9109
10422
|
try {
|
|
@@ -9116,10 +10429,10 @@ function useVerificationController() {
|
|
|
9116
10429
|
}
|
|
9117
10430
|
async function cancelUserInvitation(req, res, next) {
|
|
9118
10431
|
const otpId = req.params.id || "";
|
|
9119
|
-
const validation =
|
|
10432
|
+
const validation = Joi41.string().hex().required();
|
|
9120
10433
|
const { error } = validation.validate(otpId);
|
|
9121
10434
|
if (error) {
|
|
9122
|
-
next(new
|
|
10435
|
+
next(new BadRequestError55(error.message));
|
|
9123
10436
|
return;
|
|
9124
10437
|
}
|
|
9125
10438
|
try {
|
|
@@ -9132,10 +10445,10 @@ function useVerificationController() {
|
|
|
9132
10445
|
}
|
|
9133
10446
|
}
|
|
9134
10447
|
async function signUp(req, res, next) {
|
|
9135
|
-
const validation =
|
|
10448
|
+
const validation = Joi41.string().email().required();
|
|
9136
10449
|
const { error } = validation.validate(req.body.email);
|
|
9137
10450
|
if (error) {
|
|
9138
|
-
next(new
|
|
10451
|
+
next(new BadRequestError55(error.message));
|
|
9139
10452
|
return;
|
|
9140
10453
|
}
|
|
9141
10454
|
const email = req.body.email ?? "";
|
|
@@ -9150,7 +10463,7 @@ function useVerificationController() {
|
|
|
9150
10463
|
async function inviteMember(req, res, next) {
|
|
9151
10464
|
const { error } = schemaInviteMember.validate(req.body);
|
|
9152
10465
|
if (error) {
|
|
9153
|
-
next(new
|
|
10466
|
+
next(new BadRequestError55(error.message));
|
|
9154
10467
|
return;
|
|
9155
10468
|
}
|
|
9156
10469
|
try {
|
|
@@ -9163,10 +10476,10 @@ function useVerificationController() {
|
|
|
9163
10476
|
}
|
|
9164
10477
|
async function cancelInviteMember(req, res, next) {
|
|
9165
10478
|
const id = req.params.id || "";
|
|
9166
|
-
const validation =
|
|
10479
|
+
const validation = Joi41.string().hex().required();
|
|
9167
10480
|
const { error } = validation.validate(id);
|
|
9168
10481
|
if (error) {
|
|
9169
|
-
next(new
|
|
10482
|
+
next(new BadRequestError55(error.message));
|
|
9170
10483
|
return;
|
|
9171
10484
|
}
|
|
9172
10485
|
try {
|
|
@@ -9179,10 +10492,10 @@ function useVerificationController() {
|
|
|
9179
10492
|
}
|
|
9180
10493
|
async function forgetPassword(req, res, next) {
|
|
9181
10494
|
const email = req.body.email ?? "";
|
|
9182
|
-
const validation =
|
|
10495
|
+
const validation = Joi41.string().email().required();
|
|
9183
10496
|
const { error } = validation.validate(email);
|
|
9184
10497
|
if (error) {
|
|
9185
|
-
next(new
|
|
10498
|
+
next(new BadRequestError55(error.message));
|
|
9186
10499
|
return;
|
|
9187
10500
|
}
|
|
9188
10501
|
try {
|
|
@@ -9192,10 +10505,10 @@ function useVerificationController() {
|
|
|
9192
10505
|
});
|
|
9193
10506
|
return;
|
|
9194
10507
|
} catch (error2) {
|
|
9195
|
-
if (error2 instanceof
|
|
10508
|
+
if (error2 instanceof AppError24) {
|
|
9196
10509
|
next(error2);
|
|
9197
10510
|
} else {
|
|
9198
|
-
next(new
|
|
10511
|
+
next(new InternalServerError27("An unexpected error occurred"));
|
|
9199
10512
|
}
|
|
9200
10513
|
}
|
|
9201
10514
|
}
|
|
@@ -9252,6 +10565,7 @@ export {
|
|
|
9252
10565
|
XENDIT_BASE_URL,
|
|
9253
10566
|
XENDIT_SECRET_KEY,
|
|
9254
10567
|
addressSchema,
|
|
10568
|
+
currencies,
|
|
9255
10569
|
isDev,
|
|
9256
10570
|
modelApp,
|
|
9257
10571
|
modelMember,
|
|
@@ -9259,7 +10573,10 @@ export {
|
|
|
9259
10573
|
modelPSGC,
|
|
9260
10574
|
modelPermission,
|
|
9261
10575
|
modelPermissionGroup,
|
|
10576
|
+
modelPlan,
|
|
9262
10577
|
modelRole,
|
|
10578
|
+
modelSubscription,
|
|
10579
|
+
modelSubscriptionTransaction,
|
|
9263
10580
|
modelUser,
|
|
9264
10581
|
modelVerification,
|
|
9265
10582
|
schemaApp,
|
|
@@ -9271,13 +10588,20 @@ export {
|
|
|
9271
10588
|
schemaMemberRole,
|
|
9272
10589
|
schemaMemberStatus,
|
|
9273
10590
|
schemaOrg,
|
|
10591
|
+
schemaOrgAdd,
|
|
10592
|
+
schemaOrgUpdate,
|
|
9274
10593
|
schemaPSGC,
|
|
9275
10594
|
schemaPermission,
|
|
9276
10595
|
schemaPermissionGroup,
|
|
9277
10596
|
schemaPermissionGroupUpdate,
|
|
9278
10597
|
schemaPermissionUpdate,
|
|
10598
|
+
schemaPlan,
|
|
9279
10599
|
schemaRole,
|
|
9280
10600
|
schemaRoleUpdate,
|
|
10601
|
+
schemaSubscription,
|
|
10602
|
+
schemaSubscriptionSeats,
|
|
10603
|
+
schemaSubscriptionTransaction,
|
|
10604
|
+
schemaSubscriptionUpdate,
|
|
9281
10605
|
schemaUpdateOptions,
|
|
9282
10606
|
schemaUser,
|
|
9283
10607
|
schemaVerification,
|
|
@@ -9314,9 +10638,16 @@ export {
|
|
|
9314
10638
|
usePermissionGroupService,
|
|
9315
10639
|
usePermissionRepo,
|
|
9316
10640
|
usePermissionService,
|
|
10641
|
+
usePlanController,
|
|
10642
|
+
usePlanRepo,
|
|
10643
|
+
usePlanService,
|
|
9317
10644
|
useRoleController,
|
|
9318
10645
|
useRoleRepo,
|
|
9319
10646
|
useRoleService,
|
|
10647
|
+
useSubscriptionController,
|
|
10648
|
+
useSubscriptionRepo,
|
|
10649
|
+
useSubscriptionTransactionController,
|
|
10650
|
+
useSubscriptionTransactionRepo,
|
|
9320
10651
|
useUserController,
|
|
9321
10652
|
useUserRepo,
|
|
9322
10653
|
useUserService,
|