@goweekdays/core 2.6.1 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.d.ts +83 -2
- package/dist/index.js +1812 -1035
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1938 -1159
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -491,25 +491,25 @@ function useAuthService() {
|
|
|
491
491
|
}
|
|
492
492
|
|
|
493
493
|
// src/resources/auth/auth.controller.ts
|
|
494
|
-
import
|
|
494
|
+
import Joi36 from "joi";
|
|
495
495
|
import {
|
|
496
|
-
AppError as
|
|
497
|
-
BadRequestError as
|
|
498
|
-
InternalServerError as
|
|
499
|
-
logger as
|
|
496
|
+
AppError as AppError19,
|
|
497
|
+
BadRequestError as BadRequestError43,
|
|
498
|
+
InternalServerError as InternalServerError23,
|
|
499
|
+
logger as logger22
|
|
500
500
|
} from "@goweekdays/utils";
|
|
501
501
|
|
|
502
502
|
// src/resources/verification/verification.service.ts
|
|
503
503
|
import {
|
|
504
504
|
useMailer,
|
|
505
505
|
compileHandlebar,
|
|
506
|
-
logger as
|
|
506
|
+
logger as logger21,
|
|
507
507
|
getDirectory,
|
|
508
|
-
BadRequestError as
|
|
508
|
+
BadRequestError as BadRequestError42,
|
|
509
509
|
NotFoundError as NotFoundError3,
|
|
510
|
-
InternalServerError as
|
|
511
|
-
useAtlas as
|
|
512
|
-
AppError as
|
|
510
|
+
InternalServerError as InternalServerError22,
|
|
511
|
+
useAtlas as useAtlas19,
|
|
512
|
+
AppError as AppError18
|
|
513
513
|
} from "@goweekdays/utils";
|
|
514
514
|
|
|
515
515
|
// src/resources/verification/verification.model.ts
|
|
@@ -532,7 +532,11 @@ var schemaVerification = Joi2.object({
|
|
|
532
532
|
roleName: Joi2.string().optional().allow("", null),
|
|
533
533
|
referralCode: Joi2.string().optional().allow("", null),
|
|
534
534
|
org: Joi2.string().hex().optional().allow("", null),
|
|
535
|
-
orgName: Joi2.string().optional().allow("", null)
|
|
535
|
+
orgName: Joi2.string().optional().allow("", null),
|
|
536
|
+
contact: Joi2.string().optional().allow("", null),
|
|
537
|
+
seats: Joi2.number().optional().allow("", null),
|
|
538
|
+
createdBy: Joi2.string().optional().allow("", null),
|
|
539
|
+
amount: Joi2.number().optional().allow("", null)
|
|
536
540
|
}).optional(),
|
|
537
541
|
expireAt: Joi2.date().optional().allow("", null)
|
|
538
542
|
});
|
|
@@ -914,15 +918,15 @@ var APP_ORG = process.env.APP_ORG || "http://localhost/organizations/create";
|
|
|
914
918
|
|
|
915
919
|
// src/resources/user/user.service.ts
|
|
916
920
|
import {
|
|
917
|
-
AppError as
|
|
918
|
-
BadRequestError as
|
|
919
|
-
InternalServerError as
|
|
921
|
+
AppError as AppError16,
|
|
922
|
+
BadRequestError as BadRequestError40,
|
|
923
|
+
InternalServerError as InternalServerError20,
|
|
920
924
|
NotFoundError as NotFoundError2,
|
|
921
925
|
hashPassword,
|
|
922
|
-
logger as
|
|
923
|
-
makeCacheKey as
|
|
924
|
-
useAtlas as
|
|
925
|
-
useCache as
|
|
926
|
+
logger as logger20,
|
|
927
|
+
makeCacheKey as makeCacheKey14,
|
|
928
|
+
useAtlas as useAtlas18,
|
|
929
|
+
useCache as useCache15,
|
|
926
930
|
useS3
|
|
927
931
|
} from "@goweekdays/utils";
|
|
928
932
|
|
|
@@ -1538,9 +1542,6 @@ function useMemberRepo() {
|
|
|
1538
1542
|
{
|
|
1539
1543
|
$match: query
|
|
1540
1544
|
},
|
|
1541
|
-
{
|
|
1542
|
-
$sort: { _id: -1 }
|
|
1543
|
-
},
|
|
1544
1545
|
{
|
|
1545
1546
|
$limit: limit
|
|
1546
1547
|
},
|
|
@@ -4379,6 +4380,7 @@ import {
|
|
|
4379
4380
|
useCache as useCache10
|
|
4380
4381
|
} from "@goweekdays/utils";
|
|
4381
4382
|
import { ObjectId as ObjectId14 } from "mongodb";
|
|
4383
|
+
import Joi16 from "joi";
|
|
4382
4384
|
function useOrgRepo() {
|
|
4383
4385
|
const db = useAtlas11.getDb();
|
|
4384
4386
|
if (!db) {
|
|
@@ -4554,10 +4556,9 @@ function useOrgRepo() {
|
|
|
4554
4556
|
});
|
|
4555
4557
|
return cached;
|
|
4556
4558
|
}
|
|
4557
|
-
const result = await collection.findOne({
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
}
|
|
4559
|
+
const result = await collection.findOne({
|
|
4560
|
+
name: { $regex: name, $options: "i" }
|
|
4561
|
+
});
|
|
4561
4562
|
setCache(cacheKey, result, 300).then(() => {
|
|
4562
4563
|
logger14.log({
|
|
4563
4564
|
level: "info",
|
|
@@ -4578,6 +4579,42 @@ function useOrgRepo() {
|
|
|
4578
4579
|
}
|
|
4579
4580
|
}
|
|
4580
4581
|
}
|
|
4582
|
+
async function getByEmail(email) {
|
|
4583
|
+
const { error } = Joi16.string().email().required().validate(email);
|
|
4584
|
+
if (error) {
|
|
4585
|
+
throw new BadRequestError21(error.message);
|
|
4586
|
+
}
|
|
4587
|
+
const cacheKey = makeCacheKey9(namespace_collection, { email });
|
|
4588
|
+
try {
|
|
4589
|
+
const cached = await getCache(cacheKey);
|
|
4590
|
+
if (cached) {
|
|
4591
|
+
logger14.log({
|
|
4592
|
+
level: "info",
|
|
4593
|
+
message: `Cache hit for getByEmail organization: ${cacheKey}`
|
|
4594
|
+
});
|
|
4595
|
+
return cached;
|
|
4596
|
+
}
|
|
4597
|
+
const result = await collection.findOne({ email });
|
|
4598
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
4599
|
+
logger14.log({
|
|
4600
|
+
level: "info",
|
|
4601
|
+
message: `Cache set for organization by email: ${cacheKey}`
|
|
4602
|
+
});
|
|
4603
|
+
}).catch((err) => {
|
|
4604
|
+
logger14.log({
|
|
4605
|
+
level: "error",
|
|
4606
|
+
message: `Failed to set cache for organization by email: ${err.message}`
|
|
4607
|
+
});
|
|
4608
|
+
});
|
|
4609
|
+
return result;
|
|
4610
|
+
} catch (error2) {
|
|
4611
|
+
if (error2 instanceof AppError8) {
|
|
4612
|
+
throw error2;
|
|
4613
|
+
} else {
|
|
4614
|
+
throw new InternalServerError11("Failed to get organization.");
|
|
4615
|
+
}
|
|
4616
|
+
}
|
|
4617
|
+
}
|
|
4581
4618
|
async function updateFieldById({ _id, field, value } = {}, session) {
|
|
4582
4619
|
const allowedFields = ["name", "description"];
|
|
4583
4620
|
if (!allowedFields.includes(field)) {
|
|
@@ -4652,15 +4689,16 @@ function useOrgRepo() {
|
|
|
4652
4689
|
updateFieldById,
|
|
4653
4690
|
deleteById,
|
|
4654
4691
|
getByName,
|
|
4692
|
+
getByEmail,
|
|
4655
4693
|
updateById
|
|
4656
4694
|
};
|
|
4657
4695
|
}
|
|
4658
4696
|
|
|
4659
4697
|
// src/resources/organization/organization.service.ts
|
|
4660
|
-
import { BadRequestError as
|
|
4698
|
+
import { BadRequestError as BadRequestError38, useAtlas as useAtlas17 } from "@goweekdays/utils";
|
|
4661
4699
|
|
|
4662
4700
|
// src/resources/member/member.controller.ts
|
|
4663
|
-
import
|
|
4701
|
+
import Joi19 from "joi";
|
|
4664
4702
|
import { BadRequestError as BadRequestError25 } from "@goweekdays/utils";
|
|
4665
4703
|
|
|
4666
4704
|
// src/resources/member/member.service.ts
|
|
@@ -4700,7 +4738,7 @@ function useRoleService() {
|
|
|
4700
4738
|
}
|
|
4701
4739
|
|
|
4702
4740
|
// src/resources/role/role.controller.ts
|
|
4703
|
-
import
|
|
4741
|
+
import Joi17 from "joi";
|
|
4704
4742
|
import { BadRequestError as BadRequestError23 } from "@goweekdays/utils";
|
|
4705
4743
|
function useRoleController() {
|
|
4706
4744
|
const {
|
|
@@ -4733,12 +4771,12 @@ function useRoleController() {
|
|
|
4733
4771
|
const limit = parseInt(req.query.limit ?? "10");
|
|
4734
4772
|
const app = req.query.app ?? "";
|
|
4735
4773
|
const org = req.query.org ?? "";
|
|
4736
|
-
const validation =
|
|
4737
|
-
search:
|
|
4738
|
-
page:
|
|
4739
|
-
limit:
|
|
4740
|
-
app:
|
|
4741
|
-
org:
|
|
4774
|
+
const validation = Joi17.object({
|
|
4775
|
+
search: Joi17.string().optional().allow("", null),
|
|
4776
|
+
page: Joi17.number().required(),
|
|
4777
|
+
limit: Joi17.number().required(),
|
|
4778
|
+
app: Joi17.string().optional().allow("", null),
|
|
4779
|
+
org: Joi17.string().hex().optional().allow("", null)
|
|
4742
4780
|
});
|
|
4743
4781
|
const { error } = validation.validate({ search, page, limit, app, org });
|
|
4744
4782
|
if (error) {
|
|
@@ -4755,8 +4793,8 @@ function useRoleController() {
|
|
|
4755
4793
|
}
|
|
4756
4794
|
async function getRoleByUserId(req, res, next) {
|
|
4757
4795
|
const userId = req.params.userId;
|
|
4758
|
-
const validation =
|
|
4759
|
-
userId:
|
|
4796
|
+
const validation = Joi17.object({
|
|
4797
|
+
userId: Joi17.string().required()
|
|
4760
4798
|
});
|
|
4761
4799
|
const { error } = validation.validate({ userId });
|
|
4762
4800
|
if (error) {
|
|
@@ -4773,8 +4811,8 @@ function useRoleController() {
|
|
|
4773
4811
|
}
|
|
4774
4812
|
async function getRoleById(req, res, next) {
|
|
4775
4813
|
const _id = req.params.id;
|
|
4776
|
-
const validation =
|
|
4777
|
-
_id:
|
|
4814
|
+
const validation = Joi17.object({
|
|
4815
|
+
_id: Joi17.string().hex().required()
|
|
4778
4816
|
});
|
|
4779
4817
|
const { error } = validation.validate({ _id });
|
|
4780
4818
|
if (error) {
|
|
@@ -4793,10 +4831,10 @@ function useRoleController() {
|
|
|
4793
4831
|
const _id = req.params.id;
|
|
4794
4832
|
const name = req.body.name ?? "";
|
|
4795
4833
|
const permissions = req.body.permissions ?? [];
|
|
4796
|
-
const validation =
|
|
4797
|
-
_id:
|
|
4798
|
-
name:
|
|
4799
|
-
permissions:
|
|
4834
|
+
const validation = Joi17.object({
|
|
4835
|
+
_id: Joi17.string().required(),
|
|
4836
|
+
name: Joi17.string().required(),
|
|
4837
|
+
permissions: Joi17.array().items(Joi17.string()).required()
|
|
4800
4838
|
});
|
|
4801
4839
|
const { error } = validation.validate({ _id, name, permissions });
|
|
4802
4840
|
if (error) {
|
|
@@ -4814,9 +4852,9 @@ function useRoleController() {
|
|
|
4814
4852
|
async function updatePermissionsById(req, res, next) {
|
|
4815
4853
|
const _id = req.params.id;
|
|
4816
4854
|
const permissions = req.body.permissions ?? [];
|
|
4817
|
-
const validation =
|
|
4818
|
-
_id:
|
|
4819
|
-
permissions:
|
|
4855
|
+
const validation = Joi17.object({
|
|
4856
|
+
_id: Joi17.string().required(),
|
|
4857
|
+
permissions: Joi17.array().items(Joi17.string()).required()
|
|
4820
4858
|
});
|
|
4821
4859
|
const { error } = validation.validate({ _id, permissions });
|
|
4822
4860
|
if (error) {
|
|
@@ -4833,8 +4871,8 @@ function useRoleController() {
|
|
|
4833
4871
|
}
|
|
4834
4872
|
async function deleteRole(req, res, next) {
|
|
4835
4873
|
const _id = req.params.id;
|
|
4836
|
-
const validation =
|
|
4837
|
-
_id:
|
|
4874
|
+
const validation = Joi17.object({
|
|
4875
|
+
_id: Joi17.string().required()
|
|
4838
4876
|
});
|
|
4839
4877
|
const { error } = validation.validate({ _id });
|
|
4840
4878
|
if (error) {
|
|
@@ -4861,7 +4899,7 @@ function useRoleController() {
|
|
|
4861
4899
|
}
|
|
4862
4900
|
|
|
4863
4901
|
// src/resources/member/member.service.ts
|
|
4864
|
-
import
|
|
4902
|
+
import Joi18 from "joi";
|
|
4865
4903
|
function useMemberService() {
|
|
4866
4904
|
const { getById: getRoleById } = useRoleRepo();
|
|
4867
4905
|
const {
|
|
@@ -4914,7 +4952,7 @@ function useMemberService() {
|
|
|
4914
4952
|
}
|
|
4915
4953
|
}
|
|
4916
4954
|
async function deleteById(id) {
|
|
4917
|
-
const { error } =
|
|
4955
|
+
const { error } = Joi18.string().hex().required().validate(id);
|
|
4918
4956
|
if (error) {
|
|
4919
4957
|
throw new BadRequestError24(error.message);
|
|
4920
4958
|
}
|
|
@@ -4957,8 +4995,8 @@ function useMemberController() {
|
|
|
4957
4995
|
} = useMemberService();
|
|
4958
4996
|
async function getByUserId(req, res, next) {
|
|
4959
4997
|
const userId = req.params.id;
|
|
4960
|
-
const validation =
|
|
4961
|
-
id:
|
|
4998
|
+
const validation = Joi19.object({
|
|
4999
|
+
id: Joi19.string().hex().required()
|
|
4962
5000
|
});
|
|
4963
5001
|
const { error } = validation.validate({ id: userId });
|
|
4964
5002
|
if (error) {
|
|
@@ -4977,10 +5015,10 @@ function useMemberController() {
|
|
|
4977
5015
|
}
|
|
4978
5016
|
}
|
|
4979
5017
|
async function getByUserType(req, res, next) {
|
|
4980
|
-
const validation =
|
|
4981
|
-
org:
|
|
4982
|
-
user:
|
|
4983
|
-
app:
|
|
5018
|
+
const validation = Joi19.object({
|
|
5019
|
+
org: Joi19.string().hex().optional().allow("", null),
|
|
5020
|
+
user: Joi19.string().hex().required(),
|
|
5021
|
+
app: Joi19.string().required()
|
|
4984
5022
|
});
|
|
4985
5023
|
const { error } = validation.validate({ ...req.params, ...req.query });
|
|
4986
5024
|
if (error) {
|
|
@@ -5002,10 +5040,10 @@ function useMemberController() {
|
|
|
5002
5040
|
}
|
|
5003
5041
|
}
|
|
5004
5042
|
async function getByApp(req, res, next) {
|
|
5005
|
-
const validation =
|
|
5006
|
-
org:
|
|
5007
|
-
user:
|
|
5008
|
-
app:
|
|
5043
|
+
const validation = Joi19.object({
|
|
5044
|
+
org: Joi19.string().hex().optional().allow("", null),
|
|
5045
|
+
user: Joi19.string().hex().required(),
|
|
5046
|
+
app: Joi19.string().required()
|
|
5009
5047
|
});
|
|
5010
5048
|
const app = req.params.app ?? "";
|
|
5011
5049
|
const org = req.query.org;
|
|
@@ -5034,14 +5072,14 @@ function useMemberController() {
|
|
|
5034
5072
|
const org = req.query.org ?? "";
|
|
5035
5073
|
const app = req.params.app ?? "";
|
|
5036
5074
|
const status = req.query.status ?? "active";
|
|
5037
|
-
const validation =
|
|
5038
|
-
limit:
|
|
5039
|
-
search:
|
|
5040
|
-
page:
|
|
5041
|
-
user:
|
|
5042
|
-
org:
|
|
5043
|
-
app:
|
|
5044
|
-
status:
|
|
5075
|
+
const validation = Joi19.object({
|
|
5076
|
+
limit: Joi19.number().min(10).max(50).required(),
|
|
5077
|
+
search: Joi19.string().optional().allow("", null),
|
|
5078
|
+
page: Joi19.number().required(),
|
|
5079
|
+
user: Joi19.string().hex().optional().allow("", null),
|
|
5080
|
+
org: Joi19.string().hex().optional().allow("", null),
|
|
5081
|
+
app: Joi19.string().required(),
|
|
5082
|
+
status: Joi19.string().required()
|
|
5045
5083
|
});
|
|
5046
5084
|
const { error } = validation.validate({
|
|
5047
5085
|
search,
|
|
@@ -5078,12 +5116,12 @@ function useMemberController() {
|
|
|
5078
5116
|
const page = Number(req.query.page) ?? 1;
|
|
5079
5117
|
const user = req.params.user ?? "";
|
|
5080
5118
|
const app = req.params.app ?? "";
|
|
5081
|
-
const validation =
|
|
5082
|
-
limit:
|
|
5083
|
-
search:
|
|
5084
|
-
page:
|
|
5085
|
-
app:
|
|
5086
|
-
user:
|
|
5119
|
+
const validation = Joi19.object({
|
|
5120
|
+
limit: Joi19.number().min(10).max(200).allow(null, ""),
|
|
5121
|
+
search: Joi19.string().optional().allow("", null),
|
|
5122
|
+
page: Joi19.number().optional().allow(null, ""),
|
|
5123
|
+
app: Joi19.string().required(),
|
|
5124
|
+
user: Joi19.string().hex().required()
|
|
5087
5125
|
});
|
|
5088
5126
|
const { error } = validation.validate({
|
|
5089
5127
|
search,
|
|
@@ -5115,11 +5153,11 @@ function useMemberController() {
|
|
|
5115
5153
|
const search = req.query.search ?? "";
|
|
5116
5154
|
const page = Number(req.query.page) ?? 1;
|
|
5117
5155
|
const user = req.query.user ?? "";
|
|
5118
|
-
const validation =
|
|
5119
|
-
limit:
|
|
5120
|
-
search:
|
|
5121
|
-
page:
|
|
5122
|
-
user:
|
|
5156
|
+
const validation = Joi19.object({
|
|
5157
|
+
limit: Joi19.number().min(10).max(50).required(),
|
|
5158
|
+
search: Joi19.string().optional().allow("", null),
|
|
5159
|
+
page: Joi19.number().required(),
|
|
5160
|
+
user: Joi19.string().hex().optional().allow("", null)
|
|
5123
5161
|
});
|
|
5124
5162
|
const { error } = validation.validate({
|
|
5125
5163
|
search,
|
|
@@ -5144,9 +5182,9 @@ function useMemberController() {
|
|
|
5144
5182
|
}
|
|
5145
5183
|
}
|
|
5146
5184
|
async function updateStatusByUserId(req, res, next) {
|
|
5147
|
-
const validation =
|
|
5148
|
-
id:
|
|
5149
|
-
status:
|
|
5185
|
+
const validation = Joi19.object({
|
|
5186
|
+
id: Joi19.string().hex().required(),
|
|
5187
|
+
status: Joi19.string().valid("active", "suspended", "deleted").required()
|
|
5150
5188
|
});
|
|
5151
5189
|
const { error } = validation.validate(req.params);
|
|
5152
5190
|
if (error) {
|
|
@@ -5195,7 +5233,7 @@ function useMemberController() {
|
|
|
5195
5233
|
async function deleteById(req, res, next) {
|
|
5196
5234
|
const payload = req.body;
|
|
5197
5235
|
const _id = req.params.id ?? "";
|
|
5198
|
-
const { error } =
|
|
5236
|
+
const { error } = Joi19.string().hex().required().validate(_id);
|
|
5199
5237
|
if (error) {
|
|
5200
5238
|
next(new BadRequestError25(error.message));
|
|
5201
5239
|
return;
|
|
@@ -5223,30 +5261,30 @@ function useMemberController() {
|
|
|
5223
5261
|
|
|
5224
5262
|
// src/resources/subscription/subscription.model.ts
|
|
5225
5263
|
import { BadRequestError as BadRequestError26 } from "@goweekdays/utils";
|
|
5226
|
-
import
|
|
5264
|
+
import Joi20 from "joi";
|
|
5227
5265
|
import { ObjectId as ObjectId15 } from "mongodb";
|
|
5228
5266
|
var schema2 = {
|
|
5229
|
-
seats:
|
|
5230
|
-
paidSeats:
|
|
5231
|
-
amount:
|
|
5232
|
-
promoCode:
|
|
5233
|
-
nextBillingDate:
|
|
5267
|
+
seats: Joi20.number().integer().min(1).required(),
|
|
5268
|
+
paidSeats: Joi20.number().integer().min(0).required(),
|
|
5269
|
+
amount: Joi20.number().positive().required(),
|
|
5270
|
+
promoCode: Joi20.string().optional().allow("", null),
|
|
5271
|
+
nextBillingDate: Joi20.date().optional().allow("", null)
|
|
5234
5272
|
};
|
|
5235
|
-
var schemaSubscription =
|
|
5273
|
+
var schemaSubscription = Joi20.object({
|
|
5236
5274
|
...schema2,
|
|
5237
|
-
org:
|
|
5238
|
-
currency:
|
|
5239
|
-
billingCycle:
|
|
5275
|
+
org: Joi20.string().hex().length(24).required(),
|
|
5276
|
+
currency: Joi20.string().length(3).required(),
|
|
5277
|
+
billingCycle: Joi20.string().valid("monthly", "yearly").required()
|
|
5240
5278
|
});
|
|
5241
|
-
var schemaSubscriptionUpdate =
|
|
5279
|
+
var schemaSubscriptionUpdate = Joi20.object({
|
|
5242
5280
|
...schema2,
|
|
5243
|
-
status:
|
|
5281
|
+
status: Joi20.string().optional().allow("", null)
|
|
5244
5282
|
});
|
|
5245
|
-
var schemaSubscriptionSeats =
|
|
5246
|
-
id:
|
|
5247
|
-
seats:
|
|
5248
|
-
amount:
|
|
5249
|
-
user:
|
|
5283
|
+
var schemaSubscriptionSeats = Joi20.object({
|
|
5284
|
+
id: Joi20.string().hex().length(24).required(),
|
|
5285
|
+
seats: Joi20.number().integer().min(1).required(),
|
|
5286
|
+
amount: Joi20.number().positive().optional().allow(null, 0),
|
|
5287
|
+
user: Joi20.string().hex().length(24).required()
|
|
5250
5288
|
});
|
|
5251
5289
|
function modelSubscription(data) {
|
|
5252
5290
|
const { error } = schemaSubscription.validate(data);
|
|
@@ -5292,7 +5330,7 @@ import {
|
|
|
5292
5330
|
useAtlas as useAtlas12,
|
|
5293
5331
|
useCache as useCache11
|
|
5294
5332
|
} from "@goweekdays/utils";
|
|
5295
|
-
import
|
|
5333
|
+
import Joi21 from "joi";
|
|
5296
5334
|
import { ObjectId as ObjectId16 } from "mongodb";
|
|
5297
5335
|
function useSubscriptionRepo() {
|
|
5298
5336
|
const db = useAtlas12.getDb();
|
|
@@ -5402,7 +5440,7 @@ function useSubscriptionRepo() {
|
|
|
5402
5440
|
}
|
|
5403
5441
|
}
|
|
5404
5442
|
async function getByOrg(org) {
|
|
5405
|
-
const { error } =
|
|
5443
|
+
const { error } = Joi21.string().hex().length(24).required().validate(org);
|
|
5406
5444
|
if (error) {
|
|
5407
5445
|
throw new Error(`Invalid org ID: ${error.message}`);
|
|
5408
5446
|
}
|
|
@@ -5441,7 +5479,7 @@ function useSubscriptionRepo() {
|
|
|
5441
5479
|
}
|
|
5442
5480
|
}
|
|
5443
5481
|
async function getById(_id) {
|
|
5444
|
-
const { error } =
|
|
5482
|
+
const { error } = Joi21.string().hex().length(24).required().validate(_id);
|
|
5445
5483
|
if (error) {
|
|
5446
5484
|
throw new Error(`Invalid subscription ID: ${error.message}`);
|
|
5447
5485
|
}
|
|
@@ -5480,7 +5518,7 @@ function useSubscriptionRepo() {
|
|
|
5480
5518
|
}
|
|
5481
5519
|
}
|
|
5482
5520
|
async function deleteById(_id) {
|
|
5483
|
-
const { error } =
|
|
5521
|
+
const { error } = Joi21.string().hex().length(24).required().validate(_id);
|
|
5484
5522
|
if (error) {
|
|
5485
5523
|
throw new Error(`Invalid subscription ID: ${error.message}`);
|
|
5486
5524
|
}
|
|
@@ -5507,7 +5545,7 @@ function useSubscriptionRepo() {
|
|
|
5507
5545
|
}
|
|
5508
5546
|
}
|
|
5509
5547
|
async function updateById(_id, options, session) {
|
|
5510
|
-
const { error: errorId } =
|
|
5548
|
+
const { error: errorId } = Joi21.string().hex().length(24).required().validate(_id);
|
|
5511
5549
|
if (errorId) {
|
|
5512
5550
|
throw new Error(`Invalid subscription ID: ${errorId.message}`);
|
|
5513
5551
|
}
|
|
@@ -5552,7 +5590,7 @@ function useSubscriptionRepo() {
|
|
|
5552
5590
|
}
|
|
5553
5591
|
|
|
5554
5592
|
// src/resources/subscription/subscription.controller.ts
|
|
5555
|
-
import
|
|
5593
|
+
import Joi23 from "joi";
|
|
5556
5594
|
import { BadRequestError as BadRequestError30 } from "@goweekdays/utils";
|
|
5557
5595
|
|
|
5558
5596
|
// src/resources/subscription/subscription.service.ts
|
|
@@ -5571,16 +5609,16 @@ import {
|
|
|
5571
5609
|
|
|
5572
5610
|
// src/resources/subscription/subscription.transaction.model.ts
|
|
5573
5611
|
import { BadRequestError as BadRequestError28 } from "@goweekdays/utils";
|
|
5574
|
-
import
|
|
5612
|
+
import Joi22 from "joi";
|
|
5575
5613
|
import { ObjectId as ObjectId17 } from "mongodb";
|
|
5576
|
-
var schemaSubscriptionTransaction =
|
|
5577
|
-
subscription:
|
|
5578
|
-
amount:
|
|
5579
|
-
currency:
|
|
5580
|
-
type:
|
|
5581
|
-
description:
|
|
5582
|
-
createdBy:
|
|
5583
|
-
createdByName:
|
|
5614
|
+
var schemaSubscriptionTransaction = Joi22.object({
|
|
5615
|
+
subscription: Joi22.string().hex().length(24).required(),
|
|
5616
|
+
amount: Joi22.number().positive().required(),
|
|
5617
|
+
currency: Joi22.string().length(3).required(),
|
|
5618
|
+
type: Joi22.string().valid("initiate", "add-seat", "remove-seat", "renewal").required(),
|
|
5619
|
+
description: Joi22.string().max(255).optional().allow("", null),
|
|
5620
|
+
createdBy: Joi22.string().hex().length(24).required(),
|
|
5621
|
+
createdByName: Joi22.string().optional().allow("", null)
|
|
5584
5622
|
});
|
|
5585
5623
|
function modelSubscriptionTransaction(data) {
|
|
5586
5624
|
const { error } = schemaSubscriptionTransaction.validate(data);
|
|
@@ -5836,10 +5874,10 @@ function useSubscriptionController() {
|
|
|
5836
5874
|
} = useSubscriptionRepo();
|
|
5837
5875
|
const { updateSeats: _updateSeats } = useSubscriptionService();
|
|
5838
5876
|
async function getAll(req, res, next) {
|
|
5839
|
-
const validation =
|
|
5840
|
-
page:
|
|
5841
|
-
limit:
|
|
5842
|
-
status:
|
|
5877
|
+
const validation = Joi23.object({
|
|
5878
|
+
page: Joi23.number().min(1).max(100).optional().allow(null, "").default(1),
|
|
5879
|
+
limit: Joi23.number().min(1).max(100).optional().allow(null, "").default(10),
|
|
5880
|
+
status: Joi23.string().valid("active", "suspended").optional().default("active")
|
|
5843
5881
|
});
|
|
5844
5882
|
const query = req.query;
|
|
5845
5883
|
const { error, value } = validation.validate(query);
|
|
@@ -5857,8 +5895,8 @@ function useSubscriptionController() {
|
|
|
5857
5895
|
}
|
|
5858
5896
|
async function getById(req, res, next) {
|
|
5859
5897
|
const id = req.params.id ?? "";
|
|
5860
|
-
const validation =
|
|
5861
|
-
id:
|
|
5898
|
+
const validation = Joi23.object({
|
|
5899
|
+
id: Joi23.string().hex().length(24).required()
|
|
5862
5900
|
});
|
|
5863
5901
|
const { error, value } = validation.validate({ id });
|
|
5864
5902
|
if (error) {
|
|
@@ -5875,8 +5913,8 @@ function useSubscriptionController() {
|
|
|
5875
5913
|
}
|
|
5876
5914
|
async function getByOrg(req, res, next) {
|
|
5877
5915
|
const org = req.params.org ?? "";
|
|
5878
|
-
const validation =
|
|
5879
|
-
org:
|
|
5916
|
+
const validation = Joi23.object({
|
|
5917
|
+
org: Joi23.string().hex().length(24).required()
|
|
5880
5918
|
});
|
|
5881
5919
|
const { error, value } = validation.validate({ org });
|
|
5882
5920
|
if (error) {
|
|
@@ -5919,15 +5957,15 @@ function useSubscriptionController() {
|
|
|
5919
5957
|
}
|
|
5920
5958
|
|
|
5921
5959
|
// src/resources/subscription/subscription.transaction.controller.ts
|
|
5922
|
-
import
|
|
5960
|
+
import Joi24 from "joi";
|
|
5923
5961
|
import { BadRequestError as BadRequestError31 } from "@goweekdays/utils";
|
|
5924
5962
|
function useSubscriptionTransactionController() {
|
|
5925
5963
|
const { getAll: _getAll } = useSubscriptionTransactionRepo();
|
|
5926
5964
|
async function getAll(req, res, next) {
|
|
5927
|
-
const validation =
|
|
5928
|
-
id:
|
|
5929
|
-
page:
|
|
5930
|
-
limit:
|
|
5965
|
+
const validation = Joi24.object({
|
|
5966
|
+
id: Joi24.string().hex().length(24).required(),
|
|
5967
|
+
page: Joi24.number().min(1).max(100).optional().allow(null, "").default(1),
|
|
5968
|
+
limit: Joi24.number().min(1).max(100).optional().allow(null, "").default(10)
|
|
5931
5969
|
});
|
|
5932
5970
|
const query = req.query;
|
|
5933
5971
|
const id = req.params.id ?? "";
|
|
@@ -5950,16 +5988,16 @@ function useSubscriptionTransactionController() {
|
|
|
5950
5988
|
}
|
|
5951
5989
|
|
|
5952
5990
|
// src/resources/plan/plan.model.ts
|
|
5953
|
-
import
|
|
5991
|
+
import Joi25 from "joi";
|
|
5954
5992
|
var currencies = ["USD", "PHP"];
|
|
5955
|
-
var schemaPlan =
|
|
5956
|
-
name:
|
|
5957
|
-
description:
|
|
5958
|
-
features:
|
|
5959
|
-
price:
|
|
5960
|
-
currency:
|
|
5961
|
-
default:
|
|
5962
|
-
billingCycle:
|
|
5993
|
+
var schemaPlan = Joi25.object({
|
|
5994
|
+
name: Joi25.string().min(3).max(100).required(),
|
|
5995
|
+
description: Joi25.string().max(255).optional().allow("", null),
|
|
5996
|
+
features: Joi25.array().items(Joi25.string().max(100)).optional(),
|
|
5997
|
+
price: Joi25.number().positive().required(),
|
|
5998
|
+
currency: Joi25.string().length(3).allow(...currencies).required(),
|
|
5999
|
+
default: Joi25.boolean().optional().allow(null, ""),
|
|
6000
|
+
billingCycle: Joi25.string().valid("monthly", "yearly").required()
|
|
5963
6001
|
});
|
|
5964
6002
|
function modelPlan(data) {
|
|
5965
6003
|
const { error } = schemaPlan.validate(data);
|
|
@@ -5992,7 +6030,7 @@ import {
|
|
|
5992
6030
|
useAtlas as useAtlas15,
|
|
5993
6031
|
useCache as useCache13
|
|
5994
6032
|
} from "@goweekdays/utils";
|
|
5995
|
-
import
|
|
6033
|
+
import Joi26 from "joi";
|
|
5996
6034
|
import { ObjectId as ObjectId19 } from "mongodb";
|
|
5997
6035
|
function usePlanRepo() {
|
|
5998
6036
|
const db = useAtlas15.getDb();
|
|
@@ -6112,7 +6150,7 @@ function usePlanRepo() {
|
|
|
6112
6150
|
}
|
|
6113
6151
|
}
|
|
6114
6152
|
async function getById(_id) {
|
|
6115
|
-
const { error } =
|
|
6153
|
+
const { error } = Joi26.string().hex().length(24).required().validate(_id);
|
|
6116
6154
|
if (error) {
|
|
6117
6155
|
throw new Error(`Invalid plan ID: ${error.message}`);
|
|
6118
6156
|
}
|
|
@@ -6181,7 +6219,7 @@ function usePlanRepo() {
|
|
|
6181
6219
|
}
|
|
6182
6220
|
}
|
|
6183
6221
|
async function deleteById(_id) {
|
|
6184
|
-
const { error } =
|
|
6222
|
+
const { error } = Joi26.string().hex().length(24).required().validate(_id);
|
|
6185
6223
|
if (error) {
|
|
6186
6224
|
throw new Error(`Invalid plan ID: ${error.message}`);
|
|
6187
6225
|
}
|
|
@@ -6240,7 +6278,7 @@ function usePlanService() {
|
|
|
6240
6278
|
}
|
|
6241
6279
|
|
|
6242
6280
|
// src/resources/plan/plan.controller.ts
|
|
6243
|
-
import
|
|
6281
|
+
import Joi27 from "joi";
|
|
6244
6282
|
import { BadRequestError as BadRequestError33 } from "@goweekdays/utils";
|
|
6245
6283
|
function usePlanController() {
|
|
6246
6284
|
const {
|
|
@@ -6252,13 +6290,13 @@ function usePlanController() {
|
|
|
6252
6290
|
} = usePlanRepo();
|
|
6253
6291
|
async function add(req, res, next) {
|
|
6254
6292
|
const value = req.body;
|
|
6255
|
-
const validation =
|
|
6256
|
-
name:
|
|
6257
|
-
description:
|
|
6258
|
-
features:
|
|
6259
|
-
price:
|
|
6260
|
-
currency:
|
|
6261
|
-
billingCycle:
|
|
6293
|
+
const validation = Joi27.object({
|
|
6294
|
+
name: Joi27.string().min(3).max(100).required(),
|
|
6295
|
+
description: Joi27.string().max(255).optional().allow("", null),
|
|
6296
|
+
features: Joi27.array().items(Joi27.string().max(100)).optional(),
|
|
6297
|
+
price: Joi27.number().positive().required(),
|
|
6298
|
+
currency: Joi27.string().length(3).required(),
|
|
6299
|
+
billingCycle: Joi27.string().valid("monthly", "yearly").required()
|
|
6262
6300
|
});
|
|
6263
6301
|
const { error } = validation.validate(value);
|
|
6264
6302
|
if (error) {
|
|
@@ -6278,11 +6316,11 @@ function usePlanController() {
|
|
|
6278
6316
|
const search = req.query.search ?? "";
|
|
6279
6317
|
const page = Number(req.query.page) ?? 1;
|
|
6280
6318
|
const limit = Number(req.query.limit) ?? 10;
|
|
6281
|
-
const validation =
|
|
6282
|
-
status:
|
|
6283
|
-
search:
|
|
6284
|
-
page:
|
|
6285
|
-
limit:
|
|
6319
|
+
const validation = Joi27.object({
|
|
6320
|
+
status: Joi27.string().required(),
|
|
6321
|
+
search: Joi27.string().optional().allow("", null),
|
|
6322
|
+
page: Joi27.number().required(),
|
|
6323
|
+
limit: Joi27.number().required()
|
|
6286
6324
|
});
|
|
6287
6325
|
const { error } = validation.validate({ status, search, page, limit });
|
|
6288
6326
|
if (error) {
|
|
@@ -6299,7 +6337,7 @@ function usePlanController() {
|
|
|
6299
6337
|
}
|
|
6300
6338
|
async function getById(req, res, next) {
|
|
6301
6339
|
const id = req.params.id;
|
|
6302
|
-
const validation =
|
|
6340
|
+
const validation = Joi27.string().hex().length(24).required();
|
|
6303
6341
|
const { error } = validation.validate(id);
|
|
6304
6342
|
if (error) {
|
|
6305
6343
|
next(new BadRequestError33(error.message));
|
|
@@ -6315,7 +6353,7 @@ function usePlanController() {
|
|
|
6315
6353
|
}
|
|
6316
6354
|
async function deleteById(req, res, next) {
|
|
6317
6355
|
const id = req.params.id;
|
|
6318
|
-
const validation =
|
|
6356
|
+
const validation = Joi27.string().hex().length(24).required();
|
|
6319
6357
|
const { error } = validation.validate(id);
|
|
6320
6358
|
if (error) {
|
|
6321
6359
|
next(new BadRequestError33(error.message));
|
|
@@ -6357,6 +6395,7 @@ import {
|
|
|
6357
6395
|
} from "@paypal/paypal-server-sdk";
|
|
6358
6396
|
import crypto3 from "crypto";
|
|
6359
6397
|
import crc32 from "buffer-crc32";
|
|
6398
|
+
import { logger as logger18 } from "@goweekdays/utils";
|
|
6360
6399
|
var certCache = /* @__PURE__ */ new Map();
|
|
6361
6400
|
function usePaypalService() {
|
|
6362
6401
|
const paypalClient = new Client({
|
|
@@ -6420,11 +6459,14 @@ function usePaypalService() {
|
|
|
6420
6459
|
const certUrl = headers["paypal-cert-url"];
|
|
6421
6460
|
const transmissionSig = headers["paypal-transmission-sig"];
|
|
6422
6461
|
if (!transmissionId || !timeStamp || !certUrl || !transmissionSig) {
|
|
6462
|
+
logger18.log({
|
|
6463
|
+
level: "error",
|
|
6464
|
+
message: "Missing required PayPal webhook headers"
|
|
6465
|
+
});
|
|
6423
6466
|
return false;
|
|
6424
6467
|
}
|
|
6425
|
-
const
|
|
6426
|
-
const
|
|
6427
|
-
const message = `${transmissionId}|${timeStamp}|${webhookId}|${crcValue}`;
|
|
6468
|
+
const crc = parseInt("0x" + crc32(rawBody).toString("hex"));
|
|
6469
|
+
const message = `${transmissionId}|${timeStamp}|${webhookId}|${crc}`;
|
|
6428
6470
|
try {
|
|
6429
6471
|
const certPem = await downloadAndCacheCert(certUrl);
|
|
6430
6472
|
const signatureBuffer = Buffer.from(transmissionSig, "base64");
|
|
@@ -6432,7 +6474,10 @@ function usePaypalService() {
|
|
|
6432
6474
|
verifier.update(message);
|
|
6433
6475
|
return verifier.verify(certPem, signatureBuffer);
|
|
6434
6476
|
} catch (error) {
|
|
6435
|
-
|
|
6477
|
+
logger18.log({
|
|
6478
|
+
level: "error",
|
|
6479
|
+
message: `PayPal webhook verification error: ${error}`
|
|
6480
|
+
});
|
|
6436
6481
|
throw new Error("Failed to verify PayPal webhook signature.");
|
|
6437
6482
|
}
|
|
6438
6483
|
}
|
|
@@ -6444,331 +6489,1005 @@ function usePaypalService() {
|
|
|
6444
6489
|
}
|
|
6445
6490
|
|
|
6446
6491
|
// src/resources/organization/organization.service.ts
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6492
|
+
import Joi32 from "joi";
|
|
6493
|
+
|
|
6494
|
+
// src/resources/verification/verification.controller.ts
|
|
6495
|
+
import {
|
|
6496
|
+
AppError as AppError14,
|
|
6497
|
+
BadRequestError as BadRequestError34,
|
|
6498
|
+
InternalServerError as InternalServerError18
|
|
6499
|
+
} from "@goweekdays/utils";
|
|
6500
|
+
import Joi28 from "joi";
|
|
6501
|
+
function useVerificationController() {
|
|
6502
|
+
const {
|
|
6503
|
+
createUserInvite: _createUserInvite,
|
|
6504
|
+
createForgetPassword: _createForgetPassword,
|
|
6505
|
+
cancelUserInvitation: _cancelUserInvitation,
|
|
6506
|
+
verify: _verify,
|
|
6507
|
+
inviteMember: _inviteMember,
|
|
6508
|
+
signUp: _signUp,
|
|
6509
|
+
cancelInviteMember: _cancelInviteMember,
|
|
6510
|
+
forgetPassword: _forgetPassword,
|
|
6511
|
+
orgSetupFee: _orgSetupFee
|
|
6512
|
+
} = useVerificationService();
|
|
6513
|
+
const { getVerifications: _getVerifications } = useVerificationRepo();
|
|
6514
|
+
async function createUserInvite(req, res, next) {
|
|
6515
|
+
const validation = Joi28.object({
|
|
6516
|
+
email: Joi28.string().email().required(),
|
|
6517
|
+
app: Joi28.string().required(),
|
|
6518
|
+
role: Joi28.string().hex().required(),
|
|
6519
|
+
roleName: Joi28.string().required(),
|
|
6520
|
+
org: Joi28.string().hex().optional().optional().allow("", null),
|
|
6521
|
+
orgName: Joi28.string().optional().optional().allow("", null)
|
|
6522
|
+
});
|
|
6523
|
+
const { error } = validation.validate(req.body);
|
|
6459
6524
|
if (error) {
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
const session = useAtlas16.getClient()?.startSession();
|
|
6463
|
-
if (!session) {
|
|
6464
|
-
throw new BadRequestError34("Unable to start database session.");
|
|
6525
|
+
next(new BadRequestError34(error.message));
|
|
6526
|
+
return;
|
|
6465
6527
|
}
|
|
6528
|
+
const email = req.body.email ?? "";
|
|
6529
|
+
const app = req.body.app ?? "";
|
|
6530
|
+
const role = req.body.role ?? "";
|
|
6531
|
+
const roleName = req.body.roleName ?? "";
|
|
6532
|
+
const org = req.body.org ?? "";
|
|
6533
|
+
const orgName = req.body.orgName ?? "";
|
|
6466
6534
|
try {
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
{
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
);
|
|
6477
|
-
const plan = await getDefault();
|
|
6478
|
-
if (!plan) {
|
|
6479
|
-
throw new BadRequestError34(
|
|
6480
|
-
"Failed to create organization, plan not found."
|
|
6481
|
-
);
|
|
6482
|
-
}
|
|
6483
|
-
const currentDate = /* @__PURE__ */ new Date();
|
|
6484
|
-
const nextBillingDate = new Date(currentDate);
|
|
6485
|
-
nextBillingDate.setMonth(currentDate.getMonth() + 1);
|
|
6486
|
-
const amount = plan.price * value.seats;
|
|
6487
|
-
const subscriptionId = await addSubscription(
|
|
6488
|
-
{
|
|
6489
|
-
amount,
|
|
6490
|
-
org: String(org),
|
|
6491
|
-
seats: value.seats,
|
|
6492
|
-
paidSeats: value.seats,
|
|
6493
|
-
currency: plan.currency,
|
|
6494
|
-
billingCycle: plan.billingCycle,
|
|
6495
|
-
nextBillingDate
|
|
6496
|
-
},
|
|
6497
|
-
session
|
|
6498
|
-
);
|
|
6499
|
-
const createdBy = String(value.createdBy);
|
|
6500
|
-
const user = await getUserById(createdBy);
|
|
6501
|
-
if (!user) {
|
|
6502
|
-
throw new BadRequestError34("User is required to create org member.");
|
|
6503
|
-
}
|
|
6504
|
-
await addSubscriptionTransaction(
|
|
6505
|
-
{
|
|
6506
|
-
subscription: subscriptionId,
|
|
6507
|
-
type: "initiate",
|
|
6508
|
-
amount,
|
|
6509
|
-
currency: plan.currency,
|
|
6510
|
-
description: "Initial subscription transaction",
|
|
6511
|
-
createdBy: value.createdBy,
|
|
6512
|
-
createdByName: `${user.firstName} ${user.lastName}`
|
|
6513
|
-
},
|
|
6514
|
-
session
|
|
6515
|
-
);
|
|
6516
|
-
const allPermissions = await getAllPermission({
|
|
6517
|
-
app: "org",
|
|
6518
|
-
limit: 100
|
|
6519
|
-
});
|
|
6520
|
-
let permissions = [];
|
|
6521
|
-
if (allPermissions && allPermissions.items && allPermissions.items.length) {
|
|
6522
|
-
permissions = allPermissions.items.map((perm) => perm.key);
|
|
6523
|
-
}
|
|
6524
|
-
if (permissions.length === 0) {
|
|
6525
|
-
throw new Error("No permissions found for the organization type.");
|
|
6526
|
-
}
|
|
6527
|
-
const roleData = {
|
|
6528
|
-
org: String(org),
|
|
6529
|
-
name: "Owner",
|
|
6530
|
-
description: "Owner of the organization",
|
|
6531
|
-
permissions,
|
|
6532
|
-
createdBy,
|
|
6533
|
-
app: "org"
|
|
6534
|
-
};
|
|
6535
|
-
const role = await addRole(roleData, session);
|
|
6536
|
-
if (!role) {
|
|
6537
|
-
throw new BadRequestError34("Role is required to create org member.");
|
|
6538
|
-
}
|
|
6539
|
-
await addMember(
|
|
6540
|
-
{
|
|
6541
|
-
role: String(role),
|
|
6542
|
-
roleName: roleData.name,
|
|
6543
|
-
org: String(org),
|
|
6544
|
-
orgName: value.name,
|
|
6545
|
-
name: `${user.firstName} ${user.lastName}`,
|
|
6546
|
-
user: createdBy,
|
|
6547
|
-
app: "org"
|
|
6548
|
-
},
|
|
6549
|
-
session
|
|
6550
|
-
);
|
|
6551
|
-
const order = await addPaypalOrder({
|
|
6552
|
-
amount,
|
|
6553
|
-
currency: plan.currency,
|
|
6554
|
-
customId: subscriptionId,
|
|
6555
|
-
returnUrl: `${APP_ORG}/organizations/success`,
|
|
6556
|
-
cancelUrl: `${APP_ORG}/organizations/cancel`,
|
|
6557
|
-
action: "pay"
|
|
6535
|
+
await _createUserInvite({
|
|
6536
|
+
email,
|
|
6537
|
+
metadata: {
|
|
6538
|
+
app,
|
|
6539
|
+
role,
|
|
6540
|
+
roleName,
|
|
6541
|
+
org,
|
|
6542
|
+
orgName
|
|
6543
|
+
}
|
|
6558
6544
|
});
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
(link) => link.rel === "approve"
|
|
6562
|
-
);
|
|
6563
|
-
return {
|
|
6564
|
-
org: String(org),
|
|
6565
|
-
paypalOrderLink: paypalOrderLink ? paypalOrderLink.href : ""
|
|
6566
|
-
};
|
|
6545
|
+
res.json({ message: "Successfully invited user." });
|
|
6546
|
+
return;
|
|
6567
6547
|
} catch (error2) {
|
|
6568
|
-
|
|
6569
|
-
throw error2;
|
|
6570
|
-
} finally {
|
|
6571
|
-
await session?.endSession();
|
|
6548
|
+
next(error2);
|
|
6572
6549
|
}
|
|
6573
6550
|
}
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
}
|
|
6578
|
-
|
|
6579
|
-
// src/resources/organization/organization.controller.ts
|
|
6580
|
-
import { BadRequestError as BadRequestError35 } from "@goweekdays/utils";
|
|
6581
|
-
import Joi27 from "joi";
|
|
6582
|
-
function useOrgController() {
|
|
6583
|
-
const { add: _add } = useOrgService();
|
|
6584
|
-
const { getOrgsByMembership } = useMemberRepo();
|
|
6585
|
-
const {
|
|
6586
|
-
getByName: _getByName,
|
|
6587
|
-
getAll: getAllOrg,
|
|
6588
|
-
getById: _getById,
|
|
6589
|
-
updateById: _updateById
|
|
6590
|
-
} = useOrgRepo();
|
|
6591
|
-
async function add(req, res, next) {
|
|
6592
|
-
const value = req.body;
|
|
6593
|
-
const { error } = schemaOrgAdd.validate(value);
|
|
6551
|
+
async function createForgetPassword(req, res, next) {
|
|
6552
|
+
const email = req.body.email || "";
|
|
6553
|
+
const validation = Joi28.string().email().required();
|
|
6554
|
+
const { error } = validation.validate(email);
|
|
6594
6555
|
if (error) {
|
|
6595
|
-
next(new
|
|
6556
|
+
next(new BadRequestError34(error.message));
|
|
6596
6557
|
return;
|
|
6597
6558
|
}
|
|
6598
6559
|
try {
|
|
6599
|
-
|
|
6560
|
+
await _createForgetPassword(email);
|
|
6600
6561
|
res.json({
|
|
6601
|
-
message: "
|
|
6602
|
-
data
|
|
6562
|
+
message: "Check your email to verify it before resetting your password."
|
|
6603
6563
|
});
|
|
6604
6564
|
return;
|
|
6605
6565
|
} catch (error2) {
|
|
6606
|
-
|
|
6566
|
+
if (error2 instanceof AppError14) {
|
|
6567
|
+
next(error2);
|
|
6568
|
+
} else {
|
|
6569
|
+
next(new InternalServerError18("An unexpected error occurred"));
|
|
6570
|
+
}
|
|
6607
6571
|
}
|
|
6608
6572
|
}
|
|
6609
|
-
async function
|
|
6610
|
-
const
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6573
|
+
async function getVerifications(req, res, next) {
|
|
6574
|
+
const validation = Joi28.object({
|
|
6575
|
+
status: Joi28.string().required(),
|
|
6576
|
+
search: Joi28.string().optional().allow("", null),
|
|
6577
|
+
page: Joi28.number().required(),
|
|
6578
|
+
type: Joi28.string().optional().allow("", null),
|
|
6579
|
+
email: Joi28.string().optional().allow("", null),
|
|
6580
|
+
app: Joi28.string().optional().allow("", null),
|
|
6581
|
+
org: Joi28.string().optional().allow("", null)
|
|
6582
|
+
});
|
|
6583
|
+
const { error } = validation.validate(req.query);
|
|
6584
|
+
if (error) {
|
|
6585
|
+
next(new BadRequestError34(error.message));
|
|
6617
6586
|
return;
|
|
6618
6587
|
}
|
|
6619
|
-
const
|
|
6620
|
-
|
|
6621
|
-
|
|
6588
|
+
const status = req.query.status ?? "";
|
|
6589
|
+
const search = req.query.search ?? "";
|
|
6590
|
+
const page = Number(req.query.page) ?? 1;
|
|
6591
|
+
let type = req.query.type ?? "";
|
|
6592
|
+
const email = req.query.email ?? "";
|
|
6593
|
+
const app = req.query.app ?? "";
|
|
6594
|
+
const org = req.query.org ?? "";
|
|
6595
|
+
const hasMultipleTypes = type.includes(",");
|
|
6596
|
+
let splitType = [];
|
|
6597
|
+
if (hasMultipleTypes) {
|
|
6598
|
+
splitType = type.split(",");
|
|
6599
|
+
}
|
|
6600
|
+
try {
|
|
6601
|
+
const items = await _getVerifications({
|
|
6602
|
+
status,
|
|
6603
|
+
search,
|
|
6604
|
+
page,
|
|
6605
|
+
type: hasMultipleTypes ? splitType : type,
|
|
6606
|
+
email,
|
|
6607
|
+
app,
|
|
6608
|
+
org
|
|
6609
|
+
});
|
|
6610
|
+
res.json(items);
|
|
6622
6611
|
return;
|
|
6612
|
+
} catch (error2) {
|
|
6613
|
+
next(error2);
|
|
6623
6614
|
}
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
});
|
|
6630
|
-
const { error } = validation.validate({ user, page, limit, search });
|
|
6615
|
+
}
|
|
6616
|
+
async function verify(req, res, next) {
|
|
6617
|
+
const id = req.params.id || "";
|
|
6618
|
+
const validation = Joi28.string().hex().required();
|
|
6619
|
+
const { error } = validation.validate(id);
|
|
6631
6620
|
if (error) {
|
|
6632
|
-
next(new
|
|
6621
|
+
next(new BadRequestError34(error.message));
|
|
6633
6622
|
return;
|
|
6634
6623
|
}
|
|
6635
6624
|
try {
|
|
6636
|
-
const
|
|
6637
|
-
res.json(
|
|
6625
|
+
const message = await _verify(id);
|
|
6626
|
+
res.json(message);
|
|
6638
6627
|
return;
|
|
6639
6628
|
} catch (error2) {
|
|
6640
6629
|
next(error2);
|
|
6641
6630
|
}
|
|
6642
6631
|
}
|
|
6643
|
-
async function
|
|
6644
|
-
const
|
|
6645
|
-
const validation =
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
status: Joi27.string().valid("active", "suspended", "inactive", "deleted").optional()
|
|
6650
|
-
});
|
|
6651
|
-
const { error } = validation.validate(query);
|
|
6652
|
-
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
6653
|
-
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
6654
|
-
const search = req.query.search ?? "";
|
|
6655
|
-
const status = req.query.status ?? "active";
|
|
6656
|
-
const isPageNumber = isFinite(page);
|
|
6657
|
-
if (!isPageNumber) {
|
|
6658
|
-
next(new BadRequestError35("Invalid page number."));
|
|
6632
|
+
async function cancelUserInvitation(req, res, next) {
|
|
6633
|
+
const otpId = req.params.id || "";
|
|
6634
|
+
const validation = Joi28.string().hex().required();
|
|
6635
|
+
const { error } = validation.validate(otpId);
|
|
6636
|
+
if (error) {
|
|
6637
|
+
next(new BadRequestError34(error.message));
|
|
6659
6638
|
return;
|
|
6660
6639
|
}
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6640
|
+
try {
|
|
6641
|
+
await _cancelUserInvitation(otpId);
|
|
6642
|
+
return res.json({
|
|
6643
|
+
message: "User invite has been cancelled."
|
|
6644
|
+
});
|
|
6645
|
+
} catch (error2) {
|
|
6646
|
+
throw error2;
|
|
6665
6647
|
}
|
|
6648
|
+
}
|
|
6649
|
+
async function signUp(req, res, next) {
|
|
6650
|
+
const validation = Joi28.string().email().required();
|
|
6651
|
+
const { error } = validation.validate(req.body.email);
|
|
6666
6652
|
if (error) {
|
|
6667
|
-
next(new
|
|
6653
|
+
next(new BadRequestError34(error.message));
|
|
6668
6654
|
return;
|
|
6669
6655
|
}
|
|
6656
|
+
const email = req.body.email ?? "";
|
|
6670
6657
|
try {
|
|
6671
|
-
|
|
6672
|
-
res.json(
|
|
6658
|
+
await _signUp({ email });
|
|
6659
|
+
res.json({ message: "Successfully signed up user." });
|
|
6673
6660
|
return;
|
|
6674
6661
|
} catch (error2) {
|
|
6675
6662
|
next(error2);
|
|
6676
6663
|
}
|
|
6677
6664
|
}
|
|
6678
|
-
async function
|
|
6679
|
-
const
|
|
6680
|
-
const validation = Joi27.object({
|
|
6681
|
-
name: Joi27.string().required()
|
|
6682
|
-
});
|
|
6683
|
-
const { error } = validation.validate({ name });
|
|
6665
|
+
async function inviteMember(req, res, next) {
|
|
6666
|
+
const { error } = schemaInviteMember.validate(req.body);
|
|
6684
6667
|
if (error) {
|
|
6685
|
-
next(new
|
|
6668
|
+
next(new BadRequestError34(error.message));
|
|
6686
6669
|
return;
|
|
6687
6670
|
}
|
|
6688
6671
|
try {
|
|
6689
|
-
|
|
6690
|
-
res.json(
|
|
6672
|
+
await _inviteMember(req.body);
|
|
6673
|
+
res.json({ message: "Successfully invited member." });
|
|
6691
6674
|
return;
|
|
6692
6675
|
} catch (error2) {
|
|
6693
6676
|
next(error2);
|
|
6694
6677
|
}
|
|
6695
6678
|
}
|
|
6696
|
-
async function
|
|
6697
|
-
const id = req.params.id;
|
|
6698
|
-
const validation =
|
|
6699
|
-
|
|
6700
|
-
});
|
|
6701
|
-
const { error } = validation.validate({ id });
|
|
6679
|
+
async function cancelInviteMember(req, res, next) {
|
|
6680
|
+
const id = req.params.id || "";
|
|
6681
|
+
const validation = Joi28.string().hex().required();
|
|
6682
|
+
const { error } = validation.validate(id);
|
|
6702
6683
|
if (error) {
|
|
6703
|
-
next(new
|
|
6684
|
+
next(new BadRequestError34(error.message));
|
|
6704
6685
|
return;
|
|
6705
6686
|
}
|
|
6706
6687
|
try {
|
|
6707
|
-
const
|
|
6708
|
-
res.json(
|
|
6688
|
+
const message = await _cancelInviteMember(id);
|
|
6689
|
+
res.json({ message });
|
|
6709
6690
|
return;
|
|
6710
6691
|
} catch (error2) {
|
|
6711
6692
|
next(error2);
|
|
6712
6693
|
}
|
|
6713
6694
|
}
|
|
6714
|
-
async function
|
|
6715
|
-
const
|
|
6716
|
-
const
|
|
6717
|
-
const { error } =
|
|
6695
|
+
async function forgetPassword(req, res, next) {
|
|
6696
|
+
const email = req.body.email ?? "";
|
|
6697
|
+
const validation = Joi28.string().email().required();
|
|
6698
|
+
const { error } = validation.validate(email);
|
|
6718
6699
|
if (error) {
|
|
6719
|
-
next(new
|
|
6700
|
+
next(new BadRequestError34(error.message));
|
|
6720
6701
|
return;
|
|
6721
6702
|
}
|
|
6722
6703
|
try {
|
|
6723
|
-
const message = await
|
|
6724
|
-
res.json({
|
|
6704
|
+
const message = await _forgetPassword(email);
|
|
6705
|
+
res.json({
|
|
6706
|
+
message
|
|
6707
|
+
});
|
|
6708
|
+
return;
|
|
6709
|
+
} catch (error2) {
|
|
6710
|
+
if (error2 instanceof AppError14) {
|
|
6711
|
+
next(error2);
|
|
6712
|
+
} else {
|
|
6713
|
+
next(new InternalServerError18("An unexpected error occurred"));
|
|
6714
|
+
}
|
|
6715
|
+
}
|
|
6716
|
+
}
|
|
6717
|
+
async function orgSetupFee(req, res, next) {
|
|
6718
|
+
const value = req.body;
|
|
6719
|
+
const { error } = schemaOrgAdd.validate(value);
|
|
6720
|
+
if (error) {
|
|
6721
|
+
next(new BadRequestError34(error.message));
|
|
6722
|
+
return;
|
|
6723
|
+
}
|
|
6724
|
+
try {
|
|
6725
|
+
const data = await _orgSetupFee(value);
|
|
6726
|
+
res.json(data);
|
|
6725
6727
|
return;
|
|
6726
6728
|
} catch (error2) {
|
|
6727
6729
|
next(error2);
|
|
6728
6730
|
}
|
|
6729
6731
|
}
|
|
6730
6732
|
return {
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6733
|
+
getVerifications,
|
|
6734
|
+
createUserInvite,
|
|
6735
|
+
createForgetPassword,
|
|
6736
|
+
verify,
|
|
6737
|
+
cancelUserInvitation,
|
|
6738
|
+
inviteMember,
|
|
6739
|
+
signUp,
|
|
6740
|
+
cancelInviteMember,
|
|
6741
|
+
forgetPassword,
|
|
6742
|
+
orgSetupFee
|
|
6737
6743
|
};
|
|
6738
6744
|
}
|
|
6739
6745
|
|
|
6740
|
-
// src/resources/
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6746
|
+
// src/resources/ledger/ledger.billing.model.ts
|
|
6747
|
+
import { BadRequestError as BadRequestError35 } from "@goweekdays/utils";
|
|
6748
|
+
import Joi29 from "joi";
|
|
6749
|
+
import { ObjectId as ObjectId20 } from "mongodb";
|
|
6750
|
+
var ledgerBillTypes = ["setup-fee", "subscription"];
|
|
6751
|
+
var ledgerBillStatuses = ["pending", "completed", "overdue"];
|
|
6752
|
+
var schemaLedgerBill = Joi29.object({
|
|
6753
|
+
org: Joi29.string().hex().length(24).required(),
|
|
6754
|
+
type: Joi29.string().valid(...ledgerBillTypes).required(),
|
|
6755
|
+
description: Joi29.string().max(255).required(),
|
|
6756
|
+
amount: Joi29.number().positive().required(),
|
|
6757
|
+
currency: Joi29.string().length(3).required(),
|
|
6758
|
+
status: Joi29.string().valid(...ledgerBillStatuses).required(),
|
|
6759
|
+
billingFrom: Joi29.date().optional().allow("", null),
|
|
6760
|
+
billingTo: Joi29.date().optional().allow("", null),
|
|
6761
|
+
paidAt: Joi29.date().optional().allow("", null),
|
|
6762
|
+
dueDate: Joi29.date().optional().allow("", null)
|
|
6763
|
+
});
|
|
6764
|
+
function modelLedgerBill(value) {
|
|
6765
|
+
const { error } = schemaLedgerBill.validate(value);
|
|
6766
|
+
if (error) {
|
|
6767
|
+
throw new Error(`Ledger bill model validation error: ${error.message}`);
|
|
6768
|
+
}
|
|
6769
|
+
try {
|
|
6770
|
+
value.org = new ObjectId20(value.org);
|
|
6771
|
+
} catch (error2) {
|
|
6772
|
+
throw new BadRequestError35("Invalid org ID.");
|
|
6773
|
+
}
|
|
6774
|
+
return {
|
|
6775
|
+
_id: value._id,
|
|
6776
|
+
org: value.org,
|
|
6777
|
+
type: value.type,
|
|
6778
|
+
description: value.description,
|
|
6779
|
+
amount: value.amount,
|
|
6780
|
+
currency: value.currency,
|
|
6781
|
+
status: value.status,
|
|
6782
|
+
billingFrom: value.billingFrom ?? "",
|
|
6783
|
+
billingTo: value.billingTo ?? "",
|
|
6784
|
+
paidAt: value.paidAt ?? "",
|
|
6785
|
+
dueDate: value.dueDate ?? "",
|
|
6786
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date()
|
|
6787
|
+
};
|
|
6788
|
+
}
|
|
6789
|
+
|
|
6790
|
+
// src/resources/ledger/ledger.billing.repository.ts
|
|
6791
|
+
import {
|
|
6792
|
+
AppError as AppError15,
|
|
6793
|
+
BadRequestError as BadRequestError36,
|
|
6794
|
+
InternalServerError as InternalServerError19,
|
|
6795
|
+
logger as logger19,
|
|
6796
|
+
makeCacheKey as makeCacheKey13,
|
|
6797
|
+
paginate as paginate12,
|
|
6798
|
+
useAtlas as useAtlas16,
|
|
6799
|
+
useCache as useCache14
|
|
6800
|
+
} from "@goweekdays/utils";
|
|
6801
|
+
import { ObjectId as ObjectId21 } from "mongodb";
|
|
6802
|
+
import Joi30 from "joi";
|
|
6803
|
+
function useLedgerBillingRepo() {
|
|
6804
|
+
const db = useAtlas16.getDb();
|
|
6805
|
+
if (!db) {
|
|
6806
|
+
throw new Error("Unable to connect to server.");
|
|
6807
|
+
}
|
|
6808
|
+
const namespace_collection = "ledger.billings";
|
|
6809
|
+
const collection = db.collection(namespace_collection);
|
|
6810
|
+
const { getCache, setCache, delNamespace } = useCache14(namespace_collection);
|
|
6811
|
+
function delCachedData() {
|
|
6812
|
+
delNamespace().then(() => {
|
|
6813
|
+
logger19.log({
|
|
6814
|
+
level: "info",
|
|
6815
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
6816
|
+
});
|
|
6817
|
+
}).catch((err) => {
|
|
6818
|
+
logger19.log({
|
|
6819
|
+
level: "error",
|
|
6820
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
6821
|
+
});
|
|
6822
|
+
});
|
|
6823
|
+
}
|
|
6824
|
+
async function createIndexes() {
|
|
6756
6825
|
try {
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6826
|
+
await collection.createIndexes([
|
|
6827
|
+
{ key: { org: 1 } },
|
|
6828
|
+
{ key: { status: 1 } },
|
|
6829
|
+
{ key: { description: "text" }, name: "text_index" }
|
|
6830
|
+
]);
|
|
6831
|
+
return "Successfully created ledger billing indexes.";
|
|
6832
|
+
} catch (error) {
|
|
6833
|
+
throw new BadRequestError36("Failed to create ledger billing indexes.");
|
|
6834
|
+
}
|
|
6835
|
+
}
|
|
6836
|
+
async function add(value, session) {
|
|
6837
|
+
try {
|
|
6838
|
+
value = modelLedgerBill(value);
|
|
6839
|
+
const result = await collection.insertOne(value, { session });
|
|
6840
|
+
delCachedData();
|
|
6841
|
+
return result.insertedId;
|
|
6842
|
+
} catch (error) {
|
|
6843
|
+
if (error instanceof AppError15) {
|
|
6844
|
+
throw error;
|
|
6763
6845
|
}
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6846
|
+
throw new BadRequestError36(
|
|
6847
|
+
`Failed to add ledger billing: ${error.message}`
|
|
6848
|
+
);
|
|
6849
|
+
}
|
|
6850
|
+
}
|
|
6851
|
+
async function getAll({
|
|
6852
|
+
org = "",
|
|
6853
|
+
search = "",
|
|
6854
|
+
page = 1,
|
|
6855
|
+
limit = 10,
|
|
6856
|
+
status = ""
|
|
6857
|
+
} = {}) {
|
|
6858
|
+
page = page > 0 ? page - 1 : 0;
|
|
6859
|
+
const query = { status: { $ne: "deleted" } };
|
|
6860
|
+
const cacheKeyOptions = {
|
|
6861
|
+
search,
|
|
6862
|
+
page,
|
|
6863
|
+
limit,
|
|
6864
|
+
tag: "getAll"
|
|
6865
|
+
};
|
|
6866
|
+
try {
|
|
6867
|
+
query.org = new ObjectId21(org);
|
|
6868
|
+
cacheKeyOptions.org = org;
|
|
6869
|
+
} catch (error) {
|
|
6870
|
+
throw new BadRequestError36("Invalid organization ID.");
|
|
6871
|
+
}
|
|
6872
|
+
if (status) {
|
|
6873
|
+
query.status = status;
|
|
6874
|
+
cacheKeyOptions.status = status;
|
|
6875
|
+
}
|
|
6876
|
+
if (search) {
|
|
6877
|
+
query.$text = { $search: search };
|
|
6878
|
+
}
|
|
6879
|
+
const cacheKey = makeCacheKey13(namespace_collection, cacheKeyOptions);
|
|
6880
|
+
logger19.log({
|
|
6881
|
+
level: "info",
|
|
6882
|
+
message: `Cache key for getAll ledger billings: ${cacheKey}`
|
|
6883
|
+
});
|
|
6884
|
+
try {
|
|
6885
|
+
const cached = await getCache(cacheKey);
|
|
6886
|
+
if (cached) {
|
|
6887
|
+
logger19.log({
|
|
6888
|
+
level: "info",
|
|
6889
|
+
message: `Cache hit for getAll ledger billings: ${cacheKey}`
|
|
6890
|
+
});
|
|
6891
|
+
return cached;
|
|
6892
|
+
}
|
|
6893
|
+
const items = await collection.aggregate([
|
|
6894
|
+
{ $match: query },
|
|
6895
|
+
{ $skip: page * limit },
|
|
6896
|
+
{ $limit: limit }
|
|
6897
|
+
]).toArray();
|
|
6898
|
+
const length = await collection.countDocuments(query);
|
|
6899
|
+
const data = paginate12(items, page, limit, length);
|
|
6900
|
+
setCache(cacheKey, data, 600).then(() => {
|
|
6901
|
+
logger19.log({
|
|
6902
|
+
level: "info",
|
|
6903
|
+
message: `Cache set for getAll ledger billings: ${cacheKey}`
|
|
6904
|
+
});
|
|
6905
|
+
}).catch((err) => {
|
|
6906
|
+
logger19.log({
|
|
6907
|
+
level: "error",
|
|
6908
|
+
message: `Failed to set cache for getAll ledger billings: ${err.message}`
|
|
6909
|
+
});
|
|
6910
|
+
});
|
|
6911
|
+
return data;
|
|
6912
|
+
} catch (error) {
|
|
6913
|
+
logger19.log({ level: "error", message: `${error}` });
|
|
6914
|
+
throw error;
|
|
6915
|
+
}
|
|
6916
|
+
}
|
|
6917
|
+
async function getById(_id) {
|
|
6918
|
+
const { error } = Joi30.string().hex().length(24).required().validate(_id);
|
|
6919
|
+
if (error) {
|
|
6920
|
+
throw new Error(`Invalid ledger billing ID: ${error.message}`);
|
|
6921
|
+
}
|
|
6922
|
+
try {
|
|
6923
|
+
_id = new ObjectId21(_id);
|
|
6924
|
+
} catch (error2) {
|
|
6925
|
+
throw new BadRequestError36("Invalid ledger billing ID.");
|
|
6926
|
+
}
|
|
6927
|
+
try {
|
|
6928
|
+
const cacheKey = makeCacheKey13(namespace_collection, {
|
|
6929
|
+
_id: String(_id),
|
|
6930
|
+
tag: "getById"
|
|
6931
|
+
});
|
|
6932
|
+
const cachedData = await getCache(cacheKey);
|
|
6933
|
+
if (cachedData) {
|
|
6934
|
+
return cachedData;
|
|
6935
|
+
}
|
|
6936
|
+
const data = await collection.findOne({
|
|
6937
|
+
_id,
|
|
6938
|
+
status: { $ne: "deleted" }
|
|
6939
|
+
});
|
|
6940
|
+
setCache(cacheKey, data).then(() => {
|
|
6941
|
+
logger19.log({
|
|
6942
|
+
level: "info",
|
|
6943
|
+
message: `Cache set for getById ledger billing: ${cacheKey}`
|
|
6944
|
+
});
|
|
6945
|
+
}).catch((err) => {
|
|
6946
|
+
logger19.log({
|
|
6947
|
+
level: "error",
|
|
6948
|
+
message: `Failed to set cache for getById ledger billing: ${err.message}`
|
|
6949
|
+
});
|
|
6950
|
+
});
|
|
6951
|
+
return data;
|
|
6952
|
+
} catch (error2) {
|
|
6953
|
+
throw new InternalServerError19("Failed to get ledger billing.");
|
|
6954
|
+
}
|
|
6955
|
+
}
|
|
6956
|
+
return {
|
|
6957
|
+
delCachedData,
|
|
6958
|
+
createIndexes,
|
|
6959
|
+
add,
|
|
6960
|
+
getAll,
|
|
6961
|
+
getById
|
|
6962
|
+
};
|
|
6963
|
+
}
|
|
6964
|
+
|
|
6965
|
+
// src/resources/ledger/ledger.billing.controller.ts
|
|
6966
|
+
import Joi31 from "joi";
|
|
6967
|
+
import { BadRequestError as BadRequestError37 } from "@goweekdays/utils";
|
|
6968
|
+
function useLedgerBillingController() {
|
|
6969
|
+
const { getAll: _getAll, getById: _getById } = useLedgerBillingRepo();
|
|
6970
|
+
async function getAll(req, res, next) {
|
|
6971
|
+
const query = req.query;
|
|
6972
|
+
const validation = Joi31.object({
|
|
6973
|
+
org: Joi31.string().hex().optional().allow("", null),
|
|
6974
|
+
page: Joi31.number().min(1).optional().allow("", null),
|
|
6975
|
+
limit: Joi31.number().min(1).optional().allow("", null),
|
|
6976
|
+
search: Joi31.string().optional().allow("", null),
|
|
6977
|
+
status: Joi31.string().optional().allow("", null)
|
|
6978
|
+
});
|
|
6979
|
+
const { error } = validation.validate(query);
|
|
6980
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
6981
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
6982
|
+
const search = req.query.search ?? "";
|
|
6983
|
+
const org = req.query.org ?? "";
|
|
6984
|
+
const status = req.query.status ?? "";
|
|
6985
|
+
const isPageNumber = isFinite(page);
|
|
6986
|
+
if (!isPageNumber) {
|
|
6987
|
+
next(new BadRequestError37("Invalid page number."));
|
|
6988
|
+
return;
|
|
6989
|
+
}
|
|
6990
|
+
const isLimitNumber = isFinite(limit);
|
|
6991
|
+
if (!isLimitNumber) {
|
|
6992
|
+
next(new BadRequestError37("Invalid limit number."));
|
|
6993
|
+
return;
|
|
6994
|
+
}
|
|
6995
|
+
if (error) {
|
|
6996
|
+
next(new BadRequestError37(error.message));
|
|
6997
|
+
return;
|
|
6998
|
+
}
|
|
6999
|
+
try {
|
|
7000
|
+
const orgs = await _getAll({ org, page, limit, search, status });
|
|
7001
|
+
res.json(orgs);
|
|
7002
|
+
return;
|
|
7003
|
+
} catch (error2) {
|
|
7004
|
+
next(error2);
|
|
7005
|
+
}
|
|
7006
|
+
}
|
|
7007
|
+
async function getById(req, res, next) {
|
|
7008
|
+
const id = req.params.id;
|
|
7009
|
+
const validation = Joi31.object({
|
|
7010
|
+
id: Joi31.string().hex().required()
|
|
7011
|
+
});
|
|
7012
|
+
const { error } = validation.validate({ id });
|
|
7013
|
+
if (error) {
|
|
7014
|
+
next(new BadRequestError37(error.message));
|
|
7015
|
+
return;
|
|
7016
|
+
}
|
|
7017
|
+
try {
|
|
7018
|
+
const org = await _getById(id);
|
|
7019
|
+
res.json(org);
|
|
7020
|
+
return;
|
|
7021
|
+
} catch (error2) {
|
|
7022
|
+
next(error2);
|
|
7023
|
+
}
|
|
7024
|
+
}
|
|
7025
|
+
return {
|
|
7026
|
+
getAll,
|
|
7027
|
+
getById
|
|
7028
|
+
};
|
|
7029
|
+
}
|
|
7030
|
+
|
|
7031
|
+
// src/resources/organization/organization.service.ts
|
|
7032
|
+
function useOrgService() {
|
|
7033
|
+
const { add: addOrg } = useOrgRepo();
|
|
7034
|
+
const { addRole } = useRoleRepo();
|
|
7035
|
+
const { getAll: getAllPermission } = usePermissionRepo();
|
|
7036
|
+
const { add: addMember, updateRoleById: _updateRoleById } = useMemberRepo();
|
|
7037
|
+
const { getUserById } = useUserRepo();
|
|
7038
|
+
const { getDefault } = usePlanRepo();
|
|
7039
|
+
const { add: addSubscription } = useSubscriptionRepo();
|
|
7040
|
+
const { add: addSubscriptionTransaction } = useSubscriptionTransactionRepo();
|
|
7041
|
+
const { addOrder: addPaypalOrder } = usePaypalService();
|
|
7042
|
+
async function add(value) {
|
|
7043
|
+
const { error } = schemaOrgAdd.validate(value);
|
|
7044
|
+
if (error) {
|
|
7045
|
+
throw new BadRequestError38(error.message);
|
|
7046
|
+
}
|
|
7047
|
+
const session = useAtlas17.getClient()?.startSession();
|
|
7048
|
+
if (!session) {
|
|
7049
|
+
throw new BadRequestError38("Unable to start database session.");
|
|
7050
|
+
}
|
|
7051
|
+
try {
|
|
7052
|
+
session?.startTransaction();
|
|
7053
|
+
const org = await addOrg(
|
|
7054
|
+
{
|
|
7055
|
+
email: value.email,
|
|
7056
|
+
name: value.name,
|
|
7057
|
+
contact: value.contact,
|
|
7058
|
+
createdBy: value.createdBy
|
|
7059
|
+
},
|
|
7060
|
+
session
|
|
7061
|
+
);
|
|
7062
|
+
const plan = await getDefault();
|
|
7063
|
+
if (!plan) {
|
|
7064
|
+
throw new BadRequestError38(
|
|
7065
|
+
"Failed to create organization, plan not found."
|
|
7066
|
+
);
|
|
7067
|
+
}
|
|
7068
|
+
const currentDate = /* @__PURE__ */ new Date();
|
|
7069
|
+
const nextBillingDate = new Date(currentDate);
|
|
7070
|
+
nextBillingDate.setMonth(currentDate.getMonth() + 1);
|
|
7071
|
+
const amount = plan.price * value.seats;
|
|
7072
|
+
const subscriptionId = await addSubscription(
|
|
7073
|
+
{
|
|
7074
|
+
amount,
|
|
7075
|
+
org: String(org),
|
|
7076
|
+
seats: value.seats,
|
|
7077
|
+
paidSeats: value.seats,
|
|
7078
|
+
currency: plan.currency,
|
|
7079
|
+
billingCycle: plan.billingCycle,
|
|
7080
|
+
nextBillingDate
|
|
7081
|
+
},
|
|
7082
|
+
session
|
|
7083
|
+
);
|
|
7084
|
+
const createdBy = String(value.createdBy);
|
|
7085
|
+
const user = await getUserById(createdBy);
|
|
7086
|
+
if (!user) {
|
|
7087
|
+
throw new BadRequestError38("User is required to create org member.");
|
|
7088
|
+
}
|
|
7089
|
+
await addSubscriptionTransaction(
|
|
7090
|
+
{
|
|
7091
|
+
subscription: subscriptionId,
|
|
7092
|
+
type: "initiate",
|
|
7093
|
+
amount,
|
|
7094
|
+
currency: plan.currency,
|
|
7095
|
+
description: "Initial subscription transaction",
|
|
7096
|
+
createdBy: value.createdBy,
|
|
7097
|
+
createdByName: `${user.firstName} ${user.lastName}`
|
|
7098
|
+
},
|
|
7099
|
+
session
|
|
7100
|
+
);
|
|
7101
|
+
const allPermissions = await getAllPermission({
|
|
7102
|
+
app: "org",
|
|
7103
|
+
limit: 100
|
|
7104
|
+
});
|
|
7105
|
+
let permissions = [];
|
|
7106
|
+
if (allPermissions && allPermissions.items && allPermissions.items.length) {
|
|
7107
|
+
permissions = allPermissions.items.map((perm) => perm.key);
|
|
7108
|
+
}
|
|
7109
|
+
if (permissions.length === 0) {
|
|
7110
|
+
throw new Error("No permissions found for the organization type.");
|
|
7111
|
+
}
|
|
7112
|
+
const roleData = {
|
|
7113
|
+
org: String(org),
|
|
7114
|
+
name: "Owner",
|
|
7115
|
+
description: "Owner of the organization",
|
|
7116
|
+
permissions,
|
|
7117
|
+
createdBy,
|
|
7118
|
+
app: "org"
|
|
7119
|
+
};
|
|
7120
|
+
const role = await addRole(roleData, session);
|
|
7121
|
+
if (!role) {
|
|
7122
|
+
throw new BadRequestError38("Role is required to create org member.");
|
|
7123
|
+
}
|
|
7124
|
+
await addMember(
|
|
7125
|
+
{
|
|
7126
|
+
role: String(role),
|
|
7127
|
+
roleName: roleData.name,
|
|
7128
|
+
org: String(org),
|
|
7129
|
+
orgName: value.name,
|
|
7130
|
+
name: `${user.firstName} ${user.lastName}`,
|
|
7131
|
+
user: createdBy,
|
|
7132
|
+
app: "org"
|
|
7133
|
+
},
|
|
7134
|
+
session
|
|
7135
|
+
);
|
|
7136
|
+
const order = await addPaypalOrder({
|
|
7137
|
+
amount,
|
|
7138
|
+
currency: plan.currency,
|
|
7139
|
+
customId: subscriptionId,
|
|
7140
|
+
returnUrl: `${APP_ORG}/organizations/success`,
|
|
7141
|
+
cancelUrl: `${APP_ORG}/organizations/cancel`,
|
|
7142
|
+
action: "pay"
|
|
7143
|
+
});
|
|
7144
|
+
await session?.commitTransaction();
|
|
7145
|
+
const paypalOrderLink = JSON.parse(order.body.toString()).links.find(
|
|
7146
|
+
(link) => link.rel === "approve"
|
|
7147
|
+
);
|
|
7148
|
+
return {
|
|
7149
|
+
org: String(org),
|
|
7150
|
+
paypalOrderLink: paypalOrderLink ? paypalOrderLink.href : ""
|
|
7151
|
+
};
|
|
7152
|
+
} catch (error2) {
|
|
7153
|
+
await session?.abortTransaction();
|
|
7154
|
+
throw error2;
|
|
7155
|
+
} finally {
|
|
7156
|
+
await session?.endSession();
|
|
7157
|
+
}
|
|
7158
|
+
}
|
|
7159
|
+
const { getById, updateStatusById: updateVerificationStatus } = useVerificationRepo();
|
|
7160
|
+
const { add: addLedgerBilling } = useLedgerBillingRepo();
|
|
7161
|
+
async function addWithVerification(id) {
|
|
7162
|
+
const { error } = Joi32.string().hex().required().validate(id);
|
|
7163
|
+
if (error) {
|
|
7164
|
+
throw new BadRequestError38(error.message);
|
|
7165
|
+
}
|
|
7166
|
+
const session = useAtlas17.getClient()?.startSession();
|
|
7167
|
+
if (!session) {
|
|
7168
|
+
throw new BadRequestError38("Unable to start database session.");
|
|
7169
|
+
}
|
|
7170
|
+
try {
|
|
7171
|
+
session?.startTransaction();
|
|
7172
|
+
const verification = await getById(id);
|
|
7173
|
+
await updateVerificationStatus(id, "complete", session);
|
|
7174
|
+
if (!verification) {
|
|
7175
|
+
throw new BadRequestError38("Verification not found.");
|
|
7176
|
+
}
|
|
7177
|
+
if (!verification.metadata?.orgName) {
|
|
7178
|
+
throw new BadRequestError38("Organization name is required.");
|
|
7179
|
+
}
|
|
7180
|
+
if (!verification.metadata?.seats) {
|
|
7181
|
+
throw new BadRequestError38("Number of seats is required.");
|
|
7182
|
+
}
|
|
7183
|
+
if (!verification.metadata?.createdBy) {
|
|
7184
|
+
throw new BadRequestError38("CreatedBy is required.");
|
|
7185
|
+
}
|
|
7186
|
+
if (!verification.metadata?.contact) {
|
|
7187
|
+
throw new BadRequestError38("Contact is required.");
|
|
7188
|
+
}
|
|
7189
|
+
const org = await addOrg(
|
|
7190
|
+
{
|
|
7191
|
+
email: verification.email,
|
|
7192
|
+
name: verification.metadata.orgName,
|
|
7193
|
+
contact: verification.metadata.contact,
|
|
7194
|
+
createdBy: verification.metadata.createdBy
|
|
7195
|
+
},
|
|
7196
|
+
session
|
|
7197
|
+
);
|
|
7198
|
+
const plan = await getDefault();
|
|
7199
|
+
if (!plan) {
|
|
7200
|
+
throw new BadRequestError38(
|
|
7201
|
+
"Failed to create organization, plan not found."
|
|
7202
|
+
);
|
|
7203
|
+
}
|
|
7204
|
+
const currentDate = /* @__PURE__ */ new Date();
|
|
7205
|
+
const nextBillingDate = new Date(currentDate);
|
|
7206
|
+
nextBillingDate.setMonth(currentDate.getMonth() + 1);
|
|
7207
|
+
const amount = plan.price * verification.metadata.seats;
|
|
7208
|
+
const subscriptionId = await addSubscription(
|
|
7209
|
+
{
|
|
7210
|
+
amount,
|
|
7211
|
+
org: String(org),
|
|
7212
|
+
seats: verification.metadata.seats,
|
|
7213
|
+
paidSeats: verification.metadata.seats,
|
|
7214
|
+
currency: plan.currency,
|
|
7215
|
+
billingCycle: plan.billingCycle,
|
|
7216
|
+
nextBillingDate
|
|
7217
|
+
},
|
|
7218
|
+
session
|
|
7219
|
+
);
|
|
7220
|
+
const createdBy = String(verification.metadata.createdBy);
|
|
7221
|
+
const user = await getUserById(createdBy);
|
|
7222
|
+
if (!user) {
|
|
7223
|
+
throw new BadRequestError38("User is required to create org member.");
|
|
7224
|
+
}
|
|
7225
|
+
await addSubscriptionTransaction(
|
|
7226
|
+
{
|
|
7227
|
+
subscription: subscriptionId,
|
|
7228
|
+
type: "initiate",
|
|
7229
|
+
amount,
|
|
7230
|
+
currency: plan.currency,
|
|
7231
|
+
description: "Initial subscription transaction",
|
|
7232
|
+
createdBy,
|
|
7233
|
+
createdByName: `${user.firstName} ${user.lastName}`
|
|
7234
|
+
},
|
|
7235
|
+
session
|
|
7236
|
+
);
|
|
7237
|
+
await addLedgerBilling(
|
|
7238
|
+
{
|
|
7239
|
+
org: String(org),
|
|
7240
|
+
amount: verification.metadata?.amount ?? 0,
|
|
7241
|
+
description: "Setup payment during organization creation",
|
|
7242
|
+
currency: plan.currency,
|
|
7243
|
+
type: "setup-fee",
|
|
7244
|
+
status: "completed"
|
|
7245
|
+
},
|
|
7246
|
+
session
|
|
7247
|
+
);
|
|
7248
|
+
const allPermissions = await getAllPermission({
|
|
7249
|
+
app: "org",
|
|
7250
|
+
limit: 100
|
|
7251
|
+
});
|
|
7252
|
+
let permissions = [];
|
|
7253
|
+
if (allPermissions && allPermissions.items && allPermissions.items.length) {
|
|
7254
|
+
permissions = allPermissions.items.map((perm) => perm.key);
|
|
7255
|
+
}
|
|
7256
|
+
if (permissions.length === 0) {
|
|
7257
|
+
throw new Error("No permissions found for the organization type.");
|
|
7258
|
+
}
|
|
7259
|
+
const roleData = {
|
|
7260
|
+
org: String(org),
|
|
7261
|
+
name: "Owner",
|
|
7262
|
+
description: "Owner of the organization",
|
|
7263
|
+
permissions,
|
|
7264
|
+
createdBy,
|
|
7265
|
+
app: "org"
|
|
7266
|
+
};
|
|
7267
|
+
const role = await addRole(roleData, session);
|
|
7268
|
+
if (!role) {
|
|
7269
|
+
throw new BadRequestError38("Role is required to create org member.");
|
|
7270
|
+
}
|
|
7271
|
+
await addMember(
|
|
7272
|
+
{
|
|
7273
|
+
role: String(role),
|
|
7274
|
+
roleName: roleData.name,
|
|
7275
|
+
org: String(org),
|
|
7276
|
+
orgName: verification.metadata.orgName,
|
|
7277
|
+
name: `${user.firstName} ${user.lastName}`,
|
|
7278
|
+
user: createdBy,
|
|
7279
|
+
app: "org"
|
|
7280
|
+
},
|
|
7281
|
+
session
|
|
7282
|
+
);
|
|
7283
|
+
await session?.commitTransaction();
|
|
7284
|
+
return "Successfully created organization with verification.";
|
|
7285
|
+
} catch (error2) {
|
|
7286
|
+
await session?.abortTransaction();
|
|
7287
|
+
throw error2;
|
|
7288
|
+
} finally {
|
|
7289
|
+
await session?.endSession();
|
|
7290
|
+
}
|
|
7291
|
+
}
|
|
7292
|
+
return {
|
|
7293
|
+
add,
|
|
7294
|
+
addWithVerification
|
|
7295
|
+
};
|
|
7296
|
+
}
|
|
7297
|
+
|
|
7298
|
+
// src/resources/organization/organization.controller.ts
|
|
7299
|
+
import { BadRequestError as BadRequestError39 } from "@goweekdays/utils";
|
|
7300
|
+
import Joi33 from "joi";
|
|
7301
|
+
function useOrgController() {
|
|
7302
|
+
const { add: _add } = useOrgService();
|
|
7303
|
+
const { getOrgsByMembership } = useMemberRepo();
|
|
7304
|
+
const {
|
|
7305
|
+
getByName: _getByName,
|
|
7306
|
+
getAll: getAllOrg,
|
|
7307
|
+
getById: _getById,
|
|
7308
|
+
updateById: _updateById
|
|
7309
|
+
} = useOrgRepo();
|
|
7310
|
+
async function add(req, res, next) {
|
|
7311
|
+
const value = req.body;
|
|
7312
|
+
const { error } = schemaOrgAdd.validate(value);
|
|
7313
|
+
if (error) {
|
|
7314
|
+
next(new BadRequestError39(error.message));
|
|
7315
|
+
return;
|
|
7316
|
+
}
|
|
7317
|
+
try {
|
|
7318
|
+
const data = await _add(value);
|
|
7319
|
+
res.json({
|
|
7320
|
+
message: "Organization created successfully.",
|
|
7321
|
+
data
|
|
7322
|
+
});
|
|
7323
|
+
return;
|
|
7324
|
+
} catch (error2) {
|
|
7325
|
+
next(error2);
|
|
7326
|
+
}
|
|
7327
|
+
}
|
|
7328
|
+
async function getOrgsByUserId(req, res, next) {
|
|
7329
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
7330
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
7331
|
+
const search = req.query.search ?? "";
|
|
7332
|
+
const user = req.params.user ?? "";
|
|
7333
|
+
const isPageNumber = isFinite(page);
|
|
7334
|
+
if (!isPageNumber) {
|
|
7335
|
+
next(new BadRequestError39("Invalid page number."));
|
|
7336
|
+
return;
|
|
7337
|
+
}
|
|
7338
|
+
const isLimitNumber = isFinite(limit);
|
|
7339
|
+
if (!isLimitNumber) {
|
|
7340
|
+
next(new BadRequestError39("Invalid limit number."));
|
|
7341
|
+
return;
|
|
7342
|
+
}
|
|
7343
|
+
const validation = Joi33.object({
|
|
7344
|
+
user: Joi33.string().hex().required(),
|
|
7345
|
+
page: Joi33.number().min(1).optional().allow("", null),
|
|
7346
|
+
limit: Joi33.number().min(1).optional().allow("", null),
|
|
7347
|
+
search: Joi33.string().optional().allow("", null)
|
|
7348
|
+
});
|
|
7349
|
+
const { error } = validation.validate({ user, page, limit, search });
|
|
7350
|
+
if (error) {
|
|
7351
|
+
next(new BadRequestError39(error.message));
|
|
7352
|
+
return;
|
|
7353
|
+
}
|
|
7354
|
+
try {
|
|
7355
|
+
const orgs = await getOrgsByMembership({ user, page, limit, search });
|
|
7356
|
+
res.json(orgs);
|
|
7357
|
+
return;
|
|
7358
|
+
} catch (error2) {
|
|
7359
|
+
next(error2);
|
|
7360
|
+
}
|
|
7361
|
+
}
|
|
7362
|
+
async function getAll(req, res, next) {
|
|
7363
|
+
const query = req.query;
|
|
7364
|
+
const validation = Joi33.object({
|
|
7365
|
+
page: Joi33.number().min(1).optional().allow("", null),
|
|
7366
|
+
limit: Joi33.number().min(1).optional().allow("", null),
|
|
7367
|
+
search: Joi33.string().optional().allow("", null),
|
|
7368
|
+
status: Joi33.string().valid("active", "suspended", "inactive", "deleted").optional()
|
|
7369
|
+
});
|
|
7370
|
+
const { error } = validation.validate(query);
|
|
7371
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
7372
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
7373
|
+
const search = req.query.search ?? "";
|
|
7374
|
+
const status = req.query.status ?? "active";
|
|
7375
|
+
const isPageNumber = isFinite(page);
|
|
7376
|
+
if (!isPageNumber) {
|
|
7377
|
+
next(new BadRequestError39("Invalid page number."));
|
|
7378
|
+
return;
|
|
7379
|
+
}
|
|
7380
|
+
const isLimitNumber = isFinite(limit);
|
|
7381
|
+
if (!isLimitNumber) {
|
|
7382
|
+
next(new BadRequestError39("Invalid limit number."));
|
|
7383
|
+
return;
|
|
7384
|
+
}
|
|
7385
|
+
if (error) {
|
|
7386
|
+
next(new BadRequestError39(error.message));
|
|
7387
|
+
return;
|
|
7388
|
+
}
|
|
7389
|
+
try {
|
|
7390
|
+
const orgs = await getAllOrg({ page, limit, search, status });
|
|
7391
|
+
res.json(orgs);
|
|
7392
|
+
return;
|
|
7393
|
+
} catch (error2) {
|
|
7394
|
+
next(error2);
|
|
7395
|
+
}
|
|
7396
|
+
}
|
|
7397
|
+
async function getByName(req, res, next) {
|
|
7398
|
+
const name = req.params.name;
|
|
7399
|
+
const validation = Joi33.object({
|
|
7400
|
+
name: Joi33.string().required()
|
|
7401
|
+
});
|
|
7402
|
+
const { error } = validation.validate({ name });
|
|
7403
|
+
if (error) {
|
|
7404
|
+
next(new BadRequestError39(error.message));
|
|
7405
|
+
return;
|
|
7406
|
+
}
|
|
7407
|
+
try {
|
|
7408
|
+
const org = await _getByName(name);
|
|
7409
|
+
res.json(org);
|
|
7410
|
+
return;
|
|
7411
|
+
} catch (error2) {
|
|
7412
|
+
next(error2);
|
|
7413
|
+
}
|
|
7414
|
+
}
|
|
7415
|
+
async function getById(req, res, next) {
|
|
7416
|
+
const id = req.params.id;
|
|
7417
|
+
const validation = Joi33.object({
|
|
7418
|
+
id: Joi33.string().hex().required()
|
|
7419
|
+
});
|
|
7420
|
+
const { error } = validation.validate({ id });
|
|
7421
|
+
if (error) {
|
|
7422
|
+
next(new BadRequestError39(error.message));
|
|
7423
|
+
return;
|
|
7424
|
+
}
|
|
7425
|
+
try {
|
|
7426
|
+
const org = await _getById(id);
|
|
7427
|
+
res.json(org);
|
|
7428
|
+
return;
|
|
7429
|
+
} catch (error2) {
|
|
7430
|
+
next(error2);
|
|
7431
|
+
}
|
|
7432
|
+
}
|
|
7433
|
+
async function updateById(req, res, next) {
|
|
7434
|
+
const _id = req.params.id ?? "";
|
|
7435
|
+
const payload = req.body;
|
|
7436
|
+
const { error } = schemaOrgUpdate.validate({ _id, ...payload });
|
|
7437
|
+
if (error) {
|
|
7438
|
+
next(new BadRequestError39(error.message));
|
|
7439
|
+
return;
|
|
7440
|
+
}
|
|
7441
|
+
try {
|
|
7442
|
+
const message = await _updateById(_id, payload);
|
|
7443
|
+
res.json({ message });
|
|
7444
|
+
return;
|
|
7445
|
+
} catch (error2) {
|
|
7446
|
+
next(error2);
|
|
7447
|
+
}
|
|
7448
|
+
}
|
|
7449
|
+
return {
|
|
7450
|
+
add,
|
|
7451
|
+
getOrgsByUserId,
|
|
7452
|
+
getByName,
|
|
7453
|
+
getAll,
|
|
7454
|
+
getById,
|
|
7455
|
+
updateById
|
|
7456
|
+
};
|
|
7457
|
+
}
|
|
7458
|
+
|
|
7459
|
+
// src/resources/user/user.service.ts
|
|
7460
|
+
function useUserService() {
|
|
7461
|
+
const {
|
|
7462
|
+
add: addUser,
|
|
7463
|
+
getUserByEmail,
|
|
7464
|
+
getUserById: _getById,
|
|
7465
|
+
updateName: _updateName,
|
|
7466
|
+
updateBirthday: _updateBirthday,
|
|
7467
|
+
updateUserFieldById: _updateUserFieldById
|
|
7468
|
+
} = useUserRepo();
|
|
7469
|
+
const { addRole, getById: getRoleById } = useRoleRepo();
|
|
7470
|
+
const { add: addMember } = useMemberRepo();
|
|
7471
|
+
const { getAll: getAllPermission } = usePermissionRepo();
|
|
7472
|
+
const { getById: getOrgById } = useOrgRepo();
|
|
7473
|
+
async function createDefaultUser() {
|
|
7474
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
7475
|
+
try {
|
|
7476
|
+
session?.startTransaction();
|
|
7477
|
+
const _user = await getUserByEmail(DEFAULT_USER_EMAIL);
|
|
7478
|
+
if (_user) {
|
|
7479
|
+
throw new BadRequestError40(
|
|
7480
|
+
`User already exists: ${DEFAULT_USER_EMAIL}.`
|
|
7481
|
+
);
|
|
7482
|
+
}
|
|
7483
|
+
const hashedPassword = await hashPassword(DEFAULT_USER_PASSWORD);
|
|
7484
|
+
const userId = await addUser(
|
|
7485
|
+
{
|
|
7486
|
+
email: DEFAULT_USER_EMAIL,
|
|
7487
|
+
password: hashedPassword,
|
|
7488
|
+
firstName: DEFAULT_USER_FIRST_NAME,
|
|
7489
|
+
lastName: DEFAULT_USER_LAST_NAME
|
|
7490
|
+
},
|
|
6772
7491
|
session
|
|
6773
7492
|
);
|
|
6774
7493
|
const permissions = await getAllPermission({ app: "admin", limit: 200 });
|
|
@@ -6807,7 +7526,7 @@ function useUserService() {
|
|
|
6807
7526
|
try {
|
|
6808
7527
|
const _user = await getUserByEmail(value.email);
|
|
6809
7528
|
if (_user) {
|
|
6810
|
-
throw new
|
|
7529
|
+
throw new BadRequestError40(`User already exists: ${value.email}.`);
|
|
6811
7530
|
}
|
|
6812
7531
|
const hashedPassword = await hashPassword(value.password);
|
|
6813
7532
|
const insertedId = await addUser({
|
|
@@ -6819,10 +7538,10 @@ function useUserService() {
|
|
|
6819
7538
|
});
|
|
6820
7539
|
return insertedId;
|
|
6821
7540
|
} catch (error) {
|
|
6822
|
-
if (error instanceof
|
|
7541
|
+
if (error instanceof AppError16) {
|
|
6823
7542
|
throw error;
|
|
6824
7543
|
} else {
|
|
6825
|
-
throw new
|
|
7544
|
+
throw new InternalServerError20(`Error creating user: ${error}`);
|
|
6826
7545
|
}
|
|
6827
7546
|
}
|
|
6828
7547
|
}
|
|
@@ -6833,22 +7552,22 @@ function useUserService() {
|
|
|
6833
7552
|
lastName = "",
|
|
6834
7553
|
password = ""
|
|
6835
7554
|
} = {}) {
|
|
6836
|
-
const session =
|
|
7555
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
6837
7556
|
session?.startTransaction();
|
|
6838
7557
|
try {
|
|
6839
7558
|
const invitation = await _getVerificationById(id);
|
|
6840
7559
|
if (!invitation || !invitation.metadata?.app || !invitation.metadata?.role) {
|
|
6841
|
-
throw new
|
|
7560
|
+
throw new BadRequestError40("Invalid invitation.");
|
|
6842
7561
|
}
|
|
6843
7562
|
if (invitation.status === "complete") {
|
|
6844
|
-
throw new
|
|
7563
|
+
throw new BadRequestError40("Invitation already used.");
|
|
6845
7564
|
}
|
|
6846
7565
|
if (!invitation.expireAt) {
|
|
6847
|
-
throw new
|
|
7566
|
+
throw new BadRequestError40("Expiration date is required.");
|
|
6848
7567
|
}
|
|
6849
7568
|
const expired = new Date(invitation.expireAt) < /* @__PURE__ */ new Date();
|
|
6850
7569
|
if (invitation.status === "expired" || expired) {
|
|
6851
|
-
throw new
|
|
7570
|
+
throw new BadRequestError40("Invitation expired.");
|
|
6852
7571
|
}
|
|
6853
7572
|
const email = invitation.email;
|
|
6854
7573
|
const user = await getUserByEmail(invitation.email);
|
|
@@ -6899,10 +7618,10 @@ function useUserService() {
|
|
|
6899
7618
|
return userId;
|
|
6900
7619
|
} catch (error) {
|
|
6901
7620
|
await session?.abortTransaction();
|
|
6902
|
-
if (error instanceof
|
|
7621
|
+
if (error instanceof AppError16) {
|
|
6903
7622
|
throw error;
|
|
6904
7623
|
} else {
|
|
6905
|
-
throw new
|
|
7624
|
+
throw new InternalServerError20("Failed to create user by invite.");
|
|
6906
7625
|
}
|
|
6907
7626
|
} finally {
|
|
6908
7627
|
session?.endSession();
|
|
@@ -6914,29 +7633,29 @@ function useUserService() {
|
|
|
6914
7633
|
lastName = "",
|
|
6915
7634
|
password = ""
|
|
6916
7635
|
} = {}) {
|
|
6917
|
-
const session =
|
|
7636
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
6918
7637
|
session?.startTransaction();
|
|
6919
7638
|
try {
|
|
6920
7639
|
const signUp = await _getVerificationById(id);
|
|
6921
7640
|
if (!signUp) {
|
|
6922
|
-
throw new
|
|
7641
|
+
throw new BadRequestError40("Invalid sign up link.");
|
|
6923
7642
|
}
|
|
6924
7643
|
if (signUp.status === "complete") {
|
|
6925
|
-
throw new
|
|
7644
|
+
throw new BadRequestError40(
|
|
6926
7645
|
"You have already an account created using this link."
|
|
6927
7646
|
);
|
|
6928
7647
|
}
|
|
6929
7648
|
if (!signUp.expireAt) {
|
|
6930
|
-
throw new
|
|
7649
|
+
throw new BadRequestError40("Expiration date is required.");
|
|
6931
7650
|
}
|
|
6932
7651
|
const expired = new Date(signUp.expireAt) < /* @__PURE__ */ new Date();
|
|
6933
7652
|
if (signUp.status === "expired" || expired) {
|
|
6934
|
-
throw new
|
|
7653
|
+
throw new BadRequestError40("Sign up link expired.");
|
|
6935
7654
|
}
|
|
6936
7655
|
const email = signUp.email;
|
|
6937
7656
|
const _user = await getUserByEmail(signUp.email);
|
|
6938
7657
|
if (_user) {
|
|
6939
|
-
throw new
|
|
7658
|
+
throw new BadRequestError40(`User already exists: ${email}.`);
|
|
6940
7659
|
}
|
|
6941
7660
|
const hashedPassword = await hashPassword(password);
|
|
6942
7661
|
const userId = await addUser(
|
|
@@ -6962,17 +7681,17 @@ function useUserService() {
|
|
|
6962
7681
|
const { updateStatusById: updateVerificationStatusById } = useVerificationRepo();
|
|
6963
7682
|
async function resetPassword(value) {
|
|
6964
7683
|
if (value.newPassword !== value.confirmPassword) {
|
|
6965
|
-
throw new
|
|
7684
|
+
throw new BadRequestError40("Passwords do not match.");
|
|
6966
7685
|
}
|
|
6967
7686
|
let hashedPassword = "";
|
|
6968
7687
|
try {
|
|
6969
7688
|
hashedPassword = await hashPassword(value.newPassword);
|
|
6970
7689
|
} catch (error) {
|
|
6971
|
-
throw new
|
|
7690
|
+
throw new InternalServerError20(`Error hashing password: ${error}`);
|
|
6972
7691
|
}
|
|
6973
|
-
const session =
|
|
7692
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
6974
7693
|
if (!session) {
|
|
6975
|
-
throw new
|
|
7694
|
+
throw new InternalServerError20("Failed to start database session.");
|
|
6976
7695
|
}
|
|
6977
7696
|
try {
|
|
6978
7697
|
session.startTransaction();
|
|
@@ -6988,7 +7707,7 @@ function useUserService() {
|
|
|
6988
7707
|
throw new NotFoundError2("User ID is invalid.");
|
|
6989
7708
|
}
|
|
6990
7709
|
if (otpDoc.status === "used") {
|
|
6991
|
-
throw new
|
|
7710
|
+
throw new BadRequestError40("This link has already been invalidated.");
|
|
6992
7711
|
}
|
|
6993
7712
|
await updateVerificationStatusById(value.id, "used", session);
|
|
6994
7713
|
await _updateUserFieldById(
|
|
@@ -6999,31 +7718,31 @@ function useUserService() {
|
|
|
6999
7718
|
return "Successfully reset password.";
|
|
7000
7719
|
} catch (error) {
|
|
7001
7720
|
await session.abortTransaction();
|
|
7002
|
-
if (error instanceof
|
|
7721
|
+
if (error instanceof AppError16) {
|
|
7003
7722
|
throw error;
|
|
7004
7723
|
}
|
|
7005
|
-
throw new
|
|
7724
|
+
throw new InternalServerError20("Failed to reset password.");
|
|
7006
7725
|
}
|
|
7007
7726
|
}
|
|
7008
7727
|
const { updateName: updateMemberName } = useMemberRepo();
|
|
7009
7728
|
async function updateName(_id, firstName, lastName) {
|
|
7010
7729
|
if (!_id) {
|
|
7011
|
-
throw new
|
|
7730
|
+
throw new BadRequestError40("Invalid user ID");
|
|
7012
7731
|
}
|
|
7013
7732
|
if (!firstName) {
|
|
7014
|
-
throw new
|
|
7733
|
+
throw new BadRequestError40("Invalid firstName");
|
|
7015
7734
|
}
|
|
7016
7735
|
if (!lastName) {
|
|
7017
|
-
throw new
|
|
7736
|
+
throw new BadRequestError40("Invalid lastName");
|
|
7018
7737
|
}
|
|
7019
|
-
const session =
|
|
7738
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
7020
7739
|
session?.startTransaction();
|
|
7021
|
-
const cacheKey =
|
|
7740
|
+
const cacheKey = makeCacheKey14("users", { user: _id });
|
|
7022
7741
|
try {
|
|
7023
|
-
|
|
7024
|
-
|
|
7742
|
+
useCache15().delCache(cacheKey).then(() => {
|
|
7743
|
+
logger20.info(`Cache cleared for user: ${_id}`);
|
|
7025
7744
|
}).catch((error) => {
|
|
7026
|
-
|
|
7745
|
+
logger20.error(`Failed to clear cache for user: ${_id}`, error);
|
|
7027
7746
|
});
|
|
7028
7747
|
await _updateName({ _id, firstName, lastName }, session);
|
|
7029
7748
|
await updateMemberName(
|
|
@@ -7041,16 +7760,16 @@ function useUserService() {
|
|
|
7041
7760
|
}
|
|
7042
7761
|
async function updateBirthday(_id, month, day, year) {
|
|
7043
7762
|
if (!_id) {
|
|
7044
|
-
throw new
|
|
7763
|
+
throw new BadRequestError40("Invalid user ID");
|
|
7045
7764
|
}
|
|
7046
7765
|
if (!month) {
|
|
7047
|
-
throw new
|
|
7766
|
+
throw new BadRequestError40("Invalid birth month.");
|
|
7048
7767
|
}
|
|
7049
7768
|
if (!day) {
|
|
7050
|
-
throw new
|
|
7769
|
+
throw new BadRequestError40("Invalid birthday.");
|
|
7051
7770
|
}
|
|
7052
7771
|
if (!year) {
|
|
7053
|
-
throw new
|
|
7772
|
+
throw new BadRequestError40("Invalid birth year.");
|
|
7054
7773
|
}
|
|
7055
7774
|
try {
|
|
7056
7775
|
await _updateBirthday({ _id, month, day, year });
|
|
@@ -7075,7 +7794,7 @@ function useUserService() {
|
|
|
7075
7794
|
bucket: SPACES_BUCKET
|
|
7076
7795
|
});
|
|
7077
7796
|
async function updateUserProfile({ file, user, previousProfile } = {}) {
|
|
7078
|
-
const session =
|
|
7797
|
+
const session = useAtlas18.getClient()?.startSession();
|
|
7079
7798
|
session?.startTransaction();
|
|
7080
7799
|
const _file = {
|
|
7081
7800
|
name: file.originalname,
|
|
@@ -7120,11 +7839,11 @@ function useUserService() {
|
|
|
7120
7839
|
|
|
7121
7840
|
// src/resources/user/user.controller.ts
|
|
7122
7841
|
import {
|
|
7123
|
-
AppError as
|
|
7124
|
-
BadRequestError as
|
|
7125
|
-
InternalServerError as
|
|
7842
|
+
AppError as AppError17,
|
|
7843
|
+
BadRequestError as BadRequestError41,
|
|
7844
|
+
InternalServerError as InternalServerError21
|
|
7126
7845
|
} from "@goweekdays/utils";
|
|
7127
|
-
import
|
|
7846
|
+
import Joi34 from "joi";
|
|
7128
7847
|
function useUserController() {
|
|
7129
7848
|
const {
|
|
7130
7849
|
updateName: _updateName,
|
|
@@ -7140,14 +7859,14 @@ function useUserController() {
|
|
|
7140
7859
|
const status = req.query.status ?? "";
|
|
7141
7860
|
const search = req.query.search ?? "";
|
|
7142
7861
|
const page = Number(req.query.page) ?? 1;
|
|
7143
|
-
const validation =
|
|
7144
|
-
status:
|
|
7145
|
-
search:
|
|
7146
|
-
page:
|
|
7862
|
+
const validation = Joi34.object({
|
|
7863
|
+
status: Joi34.string().required(),
|
|
7864
|
+
search: Joi34.string().optional().allow("", null),
|
|
7865
|
+
page: Joi34.number().required()
|
|
7147
7866
|
});
|
|
7148
7867
|
const { error } = validation.validate({ status, search, page });
|
|
7149
7868
|
if (error) {
|
|
7150
|
-
next(new
|
|
7869
|
+
next(new BadRequestError41(error.message));
|
|
7151
7870
|
return;
|
|
7152
7871
|
}
|
|
7153
7872
|
try {
|
|
@@ -7160,14 +7879,14 @@ function useUserController() {
|
|
|
7160
7879
|
}
|
|
7161
7880
|
async function getUserById(req, res, next) {
|
|
7162
7881
|
const id = req.params.id || "";
|
|
7163
|
-
const validation =
|
|
7882
|
+
const validation = Joi34.string().hex().validate(id);
|
|
7164
7883
|
if (validation.error) {
|
|
7165
|
-
throw new
|
|
7884
|
+
throw new BadRequestError41("Invalid id.");
|
|
7166
7885
|
}
|
|
7167
7886
|
try {
|
|
7168
7887
|
const user = await _getUserById(id);
|
|
7169
7888
|
if (!user) {
|
|
7170
|
-
throw new
|
|
7889
|
+
throw new BadRequestError41("User not found.");
|
|
7171
7890
|
}
|
|
7172
7891
|
res.json(user);
|
|
7173
7892
|
} catch (error) {
|
|
@@ -7178,13 +7897,13 @@ function useUserController() {
|
|
|
7178
7897
|
const id = req.headers.user ?? "";
|
|
7179
7898
|
const firstName = req.body.firstName ?? "";
|
|
7180
7899
|
const lastName = req.body.lastName ?? "";
|
|
7181
|
-
const validation =
|
|
7182
|
-
firstName:
|
|
7183
|
-
lastName:
|
|
7900
|
+
const validation = Joi34.object({
|
|
7901
|
+
firstName: Joi34.string().required(),
|
|
7902
|
+
lastName: Joi34.string().required()
|
|
7184
7903
|
});
|
|
7185
7904
|
const { error } = validation.validate({ firstName, lastName });
|
|
7186
7905
|
if (error) {
|
|
7187
|
-
next(new
|
|
7906
|
+
next(new BadRequestError41(error.message));
|
|
7188
7907
|
return;
|
|
7189
7908
|
}
|
|
7190
7909
|
try {
|
|
@@ -7200,14 +7919,14 @@ function useUserController() {
|
|
|
7200
7919
|
const month = req.body.month ?? "";
|
|
7201
7920
|
const day = req.body.day ?? 0;
|
|
7202
7921
|
const year = req.body.year ?? 0;
|
|
7203
|
-
const validation =
|
|
7204
|
-
month:
|
|
7205
|
-
day:
|
|
7206
|
-
year:
|
|
7922
|
+
const validation = Joi34.object({
|
|
7923
|
+
month: Joi34.string().required(),
|
|
7924
|
+
day: Joi34.number().integer().min(1).max(31).required(),
|
|
7925
|
+
year: Joi34.number().integer().min(1900).max((/* @__PURE__ */ new Date()).getFullYear()).required()
|
|
7207
7926
|
});
|
|
7208
7927
|
const { error } = validation.validate({ month, day, year });
|
|
7209
7928
|
if (error) {
|
|
7210
|
-
next(new
|
|
7929
|
+
next(new BadRequestError41(error.message));
|
|
7211
7930
|
return;
|
|
7212
7931
|
}
|
|
7213
7932
|
try {
|
|
@@ -7221,18 +7940,18 @@ function useUserController() {
|
|
|
7221
7940
|
async function updateUserFieldById(req, res, next) {
|
|
7222
7941
|
const _id = req.params.id;
|
|
7223
7942
|
const { field, value } = req.body;
|
|
7224
|
-
const validation =
|
|
7225
|
-
_id:
|
|
7226
|
-
field:
|
|
7227
|
-
value:
|
|
7943
|
+
const validation = Joi34.object({
|
|
7944
|
+
_id: Joi34.string().hex().required(),
|
|
7945
|
+
field: Joi34.string().valid("gender", "email", "contact", "profile").required(),
|
|
7946
|
+
value: Joi34.alternatives().conditional("field", {
|
|
7228
7947
|
is: "email",
|
|
7229
|
-
then:
|
|
7230
|
-
otherwise:
|
|
7948
|
+
then: Joi34.string().email().required(),
|
|
7949
|
+
otherwise: Joi34.string().required()
|
|
7231
7950
|
})
|
|
7232
7951
|
});
|
|
7233
7952
|
const { error } = validation.validate({ _id, field, value });
|
|
7234
7953
|
if (error) {
|
|
7235
|
-
next(new
|
|
7954
|
+
next(new BadRequestError41(error.message));
|
|
7236
7955
|
return;
|
|
7237
7956
|
}
|
|
7238
7957
|
try {
|
|
@@ -7248,12 +7967,12 @@ function useUserController() {
|
|
|
7248
7967
|
return;
|
|
7249
7968
|
}
|
|
7250
7969
|
const previousProfile = req.body.previousProfile ?? "";
|
|
7251
|
-
const validation =
|
|
7252
|
-
previousProfile:
|
|
7970
|
+
const validation = Joi34.object({
|
|
7971
|
+
previousProfile: Joi34.string().hex().optional().allow("", null)
|
|
7253
7972
|
});
|
|
7254
7973
|
const { error } = validation.validate({ previousProfile });
|
|
7255
7974
|
if (error) {
|
|
7256
|
-
next(new
|
|
7975
|
+
next(new BadRequestError41(error.message));
|
|
7257
7976
|
return;
|
|
7258
7977
|
}
|
|
7259
7978
|
const user = req.headers["user"] ?? "";
|
|
@@ -7266,10 +7985,10 @@ function useUserController() {
|
|
|
7266
7985
|
res.json({ message: "Successfully updated profile picture." });
|
|
7267
7986
|
return;
|
|
7268
7987
|
} catch (error2) {
|
|
7269
|
-
if (error2 instanceof
|
|
7988
|
+
if (error2 instanceof AppError17) {
|
|
7270
7989
|
next(error2);
|
|
7271
7990
|
} else {
|
|
7272
|
-
next(new
|
|
7991
|
+
next(new InternalServerError21(error2));
|
|
7273
7992
|
}
|
|
7274
7993
|
}
|
|
7275
7994
|
}
|
|
@@ -7279,12 +7998,12 @@ function useUserController() {
|
|
|
7279
7998
|
const password = req.body.password ?? "";
|
|
7280
7999
|
const id = req.params.id ?? "";
|
|
7281
8000
|
const type = req.body.type ?? "";
|
|
7282
|
-
const validation =
|
|
7283
|
-
firstName:
|
|
7284
|
-
lastName:
|
|
7285
|
-
password:
|
|
7286
|
-
id:
|
|
7287
|
-
type:
|
|
8001
|
+
const validation = Joi34.object({
|
|
8002
|
+
firstName: Joi34.string().required(),
|
|
8003
|
+
lastName: Joi34.string().required(),
|
|
8004
|
+
password: Joi34.string().required(),
|
|
8005
|
+
id: Joi34.string().hex().required(),
|
|
8006
|
+
type: Joi34.string().required()
|
|
7288
8007
|
});
|
|
7289
8008
|
const { error } = validation.validate({
|
|
7290
8009
|
firstName,
|
|
@@ -7294,7 +8013,7 @@ function useUserController() {
|
|
|
7294
8013
|
type
|
|
7295
8014
|
});
|
|
7296
8015
|
if (error) {
|
|
7297
|
-
next(new
|
|
8016
|
+
next(new BadRequestError41(error.message));
|
|
7298
8017
|
return;
|
|
7299
8018
|
}
|
|
7300
8019
|
try {
|
|
@@ -7317,14 +8036,14 @@ function useUserController() {
|
|
|
7317
8036
|
}
|
|
7318
8037
|
async function resetPassword(req, res, next) {
|
|
7319
8038
|
const payload = req.body;
|
|
7320
|
-
const validation =
|
|
7321
|
-
id:
|
|
7322
|
-
newPassword:
|
|
7323
|
-
confirmPassword:
|
|
8039
|
+
const validation = Joi34.object({
|
|
8040
|
+
id: Joi34.string().hex().required(),
|
|
8041
|
+
newPassword: Joi34.string().min(8).required(),
|
|
8042
|
+
confirmPassword: Joi34.string().min(8).required()
|
|
7324
8043
|
});
|
|
7325
8044
|
const { error } = validation.validate(payload);
|
|
7326
8045
|
if (error) {
|
|
7327
|
-
next(new
|
|
8046
|
+
next(new BadRequestError41(error.message));
|
|
7328
8047
|
return;
|
|
7329
8048
|
}
|
|
7330
8049
|
try {
|
|
@@ -7349,7 +8068,7 @@ function useUserController() {
|
|
|
7349
8068
|
}
|
|
7350
8069
|
|
|
7351
8070
|
// src/resources/verification/verification.service.ts
|
|
7352
|
-
import
|
|
8071
|
+
import Joi35 from "joi";
|
|
7353
8072
|
function useVerificationService() {
|
|
7354
8073
|
const MailerConfig = {
|
|
7355
8074
|
host: MAILER_TRANSPORT_HOST,
|
|
@@ -7384,7 +8103,7 @@ function useVerificationService() {
|
|
|
7384
8103
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7385
8104
|
};
|
|
7386
8105
|
if (!metadata.app) {
|
|
7387
|
-
throw new
|
|
8106
|
+
throw new BadRequestError42("App metadata is required.");
|
|
7388
8107
|
}
|
|
7389
8108
|
try {
|
|
7390
8109
|
const user = await getUserByEmail(email);
|
|
@@ -7407,7 +8126,7 @@ function useVerificationService() {
|
|
|
7407
8126
|
html: emailContent2,
|
|
7408
8127
|
from: "GoWeekdays"
|
|
7409
8128
|
}).catch((error) => {
|
|
7410
|
-
|
|
8129
|
+
logger21.log({
|
|
7411
8130
|
level: "error",
|
|
7412
8131
|
message: `Error sending user invite email: ${error}`
|
|
7413
8132
|
});
|
|
@@ -7429,7 +8148,7 @@ function useVerificationService() {
|
|
|
7429
8148
|
html: emailContent,
|
|
7430
8149
|
from: "GoWeekdays"
|
|
7431
8150
|
}).catch((error) => {
|
|
7432
|
-
|
|
8151
|
+
logger21.log({
|
|
7433
8152
|
level: "error",
|
|
7434
8153
|
message: `Error sending user invite email: ${error}`
|
|
7435
8154
|
});
|
|
@@ -7464,14 +8183,14 @@ function useVerificationService() {
|
|
|
7464
8183
|
from: "GoWeekdays",
|
|
7465
8184
|
html: emailContent
|
|
7466
8185
|
}).catch((error) => {
|
|
7467
|
-
|
|
8186
|
+
logger21.log({
|
|
7468
8187
|
level: "error",
|
|
7469
8188
|
message: `Error sending forget password email: ${error}`
|
|
7470
8189
|
});
|
|
7471
8190
|
});
|
|
7472
8191
|
return "Successfully created a link to reset password. Please check your email.";
|
|
7473
8192
|
} catch (error) {
|
|
7474
|
-
throw new
|
|
8193
|
+
throw new InternalServerError22("Failed to create forget password link.");
|
|
7475
8194
|
}
|
|
7476
8195
|
}
|
|
7477
8196
|
async function getById(id) {
|
|
@@ -7510,34 +8229,34 @@ function useVerificationService() {
|
|
|
7510
8229
|
}
|
|
7511
8230
|
function errorByType(type, status) {
|
|
7512
8231
|
if (type === "user-invite" && status === "expired") {
|
|
7513
|
-
throw new
|
|
8232
|
+
throw new BadRequestError42(
|
|
7514
8233
|
"Invitation has already expired, please contact admin to resend the invitation."
|
|
7515
8234
|
);
|
|
7516
8235
|
}
|
|
7517
8236
|
if (type === "user-sign-up" && status === "expired") {
|
|
7518
|
-
throw new
|
|
8237
|
+
throw new BadRequestError42(
|
|
7519
8238
|
"Sign up verification has expired, please sign up again to get a new verification link."
|
|
7520
8239
|
);
|
|
7521
8240
|
}
|
|
7522
8241
|
if (type === "user-invite" && status === "complete") {
|
|
7523
|
-
throw new
|
|
8242
|
+
throw new BadRequestError42(
|
|
7524
8243
|
"User already registered, please login to continue."
|
|
7525
8244
|
);
|
|
7526
8245
|
}
|
|
7527
8246
|
if (type === "forget-password" && status === "complete") {
|
|
7528
|
-
throw new
|
|
8247
|
+
throw new BadRequestError42(
|
|
7529
8248
|
"Forget password verification has already been used, please request a new one."
|
|
7530
8249
|
);
|
|
7531
8250
|
}
|
|
7532
8251
|
if (type === "forget-password" && status === "expired") {
|
|
7533
|
-
throw new
|
|
8252
|
+
throw new BadRequestError42(
|
|
7534
8253
|
"Forget password verification has expired, please request a new one."
|
|
7535
8254
|
);
|
|
7536
8255
|
}
|
|
7537
|
-
throw new
|
|
8256
|
+
throw new BadRequestError42("Invalid verification.");
|
|
7538
8257
|
}
|
|
7539
8258
|
async function verify(id) {
|
|
7540
|
-
const session =
|
|
8259
|
+
const session = useAtlas19.getClient()?.startSession();
|
|
7541
8260
|
session?.startTransaction();
|
|
7542
8261
|
try {
|
|
7543
8262
|
const _id = await _getById(id);
|
|
@@ -7548,10 +8267,10 @@ function useVerificationService() {
|
|
|
7548
8267
|
errorByType(_id.type, "expired");
|
|
7549
8268
|
}
|
|
7550
8269
|
if (_id.status === "complete") {
|
|
7551
|
-
throw new
|
|
8270
|
+
throw new BadRequestError42("Verification already completed.");
|
|
7552
8271
|
}
|
|
7553
8272
|
if (!_id.expireAt) {
|
|
7554
|
-
throw new
|
|
8273
|
+
throw new BadRequestError42("Expiration date is required.");
|
|
7555
8274
|
}
|
|
7556
8275
|
const expiration = new Date(_id.expireAt).getTime();
|
|
7557
8276
|
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
@@ -7567,12 +8286,12 @@ function useVerificationService() {
|
|
|
7567
8286
|
throw new NotFoundError3("User not found for member invite.");
|
|
7568
8287
|
}
|
|
7569
8288
|
if (!_id.metadata?.app) {
|
|
7570
|
-
throw new
|
|
8289
|
+
throw new BadRequestError42(
|
|
7571
8290
|
"App metadata is required for member invite."
|
|
7572
8291
|
);
|
|
7573
8292
|
}
|
|
7574
8293
|
if (!_id.metadata?.role || !_id.metadata?.roleName) {
|
|
7575
|
-
throw new
|
|
8294
|
+
throw new BadRequestError42(
|
|
7576
8295
|
"Role metadata is required for member invite."
|
|
7577
8296
|
);
|
|
7578
8297
|
}
|
|
@@ -7594,7 +8313,7 @@ function useVerificationService() {
|
|
|
7594
8313
|
return _id;
|
|
7595
8314
|
} catch (error) {
|
|
7596
8315
|
await session?.abortTransaction();
|
|
7597
|
-
|
|
8316
|
+
logger21.log({
|
|
7598
8317
|
level: "info",
|
|
7599
8318
|
message: `Error verifying user invitation: ${error}`
|
|
7600
8319
|
});
|
|
@@ -7607,7 +8326,7 @@ function useVerificationService() {
|
|
|
7607
8326
|
try {
|
|
7608
8327
|
await updateStatusById(id, "cancelled");
|
|
7609
8328
|
} catch (error) {
|
|
7610
|
-
throw new
|
|
8329
|
+
throw new InternalServerError22(
|
|
7611
8330
|
`Error cancelling user invitation: ${error}`
|
|
7612
8331
|
);
|
|
7613
8332
|
}
|
|
@@ -7627,7 +8346,7 @@ function useVerificationService() {
|
|
|
7627
8346
|
try {
|
|
7628
8347
|
const user = await getUserByEmail(email);
|
|
7629
8348
|
if (user) {
|
|
7630
|
-
throw new
|
|
8349
|
+
throw new BadRequestError42(
|
|
7631
8350
|
`Email ${email} is already registered, please login to continue.`
|
|
7632
8351
|
);
|
|
7633
8352
|
}
|
|
@@ -7654,7 +8373,7 @@ function useVerificationService() {
|
|
|
7654
8373
|
html: emailContent,
|
|
7655
8374
|
from: "GoWeekdays"
|
|
7656
8375
|
}).catch((error) => {
|
|
7657
|
-
|
|
8376
|
+
logger21.log({
|
|
7658
8377
|
level: "error",
|
|
7659
8378
|
message: `Error sending user invite email: ${error}`
|
|
7660
8379
|
});
|
|
@@ -7667,7 +8386,7 @@ function useVerificationService() {
|
|
|
7667
8386
|
async function inviteMember(value) {
|
|
7668
8387
|
const { error } = schemaInviteMember.validate(value);
|
|
7669
8388
|
if (error) {
|
|
7670
|
-
throw new
|
|
8389
|
+
throw new BadRequestError42(error.message);
|
|
7671
8390
|
}
|
|
7672
8391
|
const role = await getRoleById(value.role);
|
|
7673
8392
|
if (!role) {
|
|
@@ -7712,7 +8431,7 @@ function useVerificationService() {
|
|
|
7712
8431
|
html: emailContent2,
|
|
7713
8432
|
from: "GoWeekdays"
|
|
7714
8433
|
}).catch((error2) => {
|
|
7715
|
-
|
|
8434
|
+
logger21.log({
|
|
7716
8435
|
level: "error",
|
|
7717
8436
|
message: `Error sending user invite email: ${error2}`
|
|
7718
8437
|
});
|
|
@@ -7734,24 +8453,24 @@ function useVerificationService() {
|
|
|
7734
8453
|
html: emailContent,
|
|
7735
8454
|
from: "GoWeekdays"
|
|
7736
8455
|
}).catch((error2) => {
|
|
7737
|
-
|
|
8456
|
+
logger21.log({
|
|
7738
8457
|
level: "error",
|
|
7739
8458
|
message: `Error sending user invite email: ${error2}`
|
|
7740
8459
|
});
|
|
7741
8460
|
});
|
|
7742
8461
|
return verificationId;
|
|
7743
8462
|
} catch (error2) {
|
|
7744
|
-
if (error2 instanceof
|
|
8463
|
+
if (error2 instanceof AppError18) {
|
|
7745
8464
|
throw error2;
|
|
7746
8465
|
} else {
|
|
7747
|
-
throw new
|
|
8466
|
+
throw new InternalServerError22("Failed to invite member.");
|
|
7748
8467
|
}
|
|
7749
8468
|
}
|
|
7750
8469
|
}
|
|
7751
8470
|
async function cancelInviteMember(id) {
|
|
7752
|
-
const { error } =
|
|
8471
|
+
const { error } = Joi35.string().hex().required().validate(id);
|
|
7753
8472
|
if (error) {
|
|
7754
|
-
throw new
|
|
8473
|
+
throw new BadRequestError42("Invalid verification ID.");
|
|
7755
8474
|
}
|
|
7756
8475
|
try {
|
|
7757
8476
|
const invite = await _getById(id);
|
|
@@ -7759,25 +8478,25 @@ function useVerificationService() {
|
|
|
7759
8478
|
throw new NotFoundError3("Invitation not found.");
|
|
7760
8479
|
}
|
|
7761
8480
|
if (invite.status === "cancelled") {
|
|
7762
|
-
throw new
|
|
8481
|
+
throw new BadRequestError42("Invitation already cancelled.");
|
|
7763
8482
|
}
|
|
7764
8483
|
if (invite.status === "complete") {
|
|
7765
|
-
throw new
|
|
8484
|
+
throw new BadRequestError42("Cannot cancel a completed invitation.");
|
|
7766
8485
|
}
|
|
7767
8486
|
await _updateStatusById(id, "cancelled");
|
|
7768
8487
|
return "Successfully cancelled the invitation.";
|
|
7769
8488
|
} catch (error2) {
|
|
7770
|
-
if (error2 instanceof
|
|
8489
|
+
if (error2 instanceof AppError18) {
|
|
7771
8490
|
throw error2;
|
|
7772
8491
|
} else {
|
|
7773
|
-
throw new
|
|
8492
|
+
throw new InternalServerError22("Failed to cancel the invitation.");
|
|
7774
8493
|
}
|
|
7775
8494
|
}
|
|
7776
8495
|
}
|
|
7777
8496
|
async function forgetPassword(email) {
|
|
7778
|
-
const { error } =
|
|
8497
|
+
const { error } = Joi35.string().email().required().validate(email);
|
|
7779
8498
|
if (error) {
|
|
7780
|
-
throw new
|
|
8499
|
+
throw new BadRequestError42("Invalid email address.");
|
|
7781
8500
|
}
|
|
7782
8501
|
try {
|
|
7783
8502
|
const member = await getUserByEmail(email);
|
|
@@ -7806,20 +8525,76 @@ function useVerificationService() {
|
|
|
7806
8525
|
from: "GoWeekdays",
|
|
7807
8526
|
html: emailContent
|
|
7808
8527
|
}).catch((error2) => {
|
|
7809
|
-
|
|
8528
|
+
logger21.log({
|
|
7810
8529
|
level: "error",
|
|
7811
8530
|
message: `Error sending forget password email: ${error2}`
|
|
7812
8531
|
});
|
|
7813
8532
|
});
|
|
7814
|
-
return "Successfully created a link to reset password. Please check your email.";
|
|
7815
|
-
} catch (error2) {
|
|
7816
|
-
if (error2 instanceof
|
|
7817
|
-
throw error2;
|
|
7818
|
-
} else {
|
|
7819
|
-
throw new
|
|
7820
|
-
"Failed to process forget password request."
|
|
7821
|
-
);
|
|
8533
|
+
return "Successfully created a link to reset password. Please check your email.";
|
|
8534
|
+
} catch (error2) {
|
|
8535
|
+
if (error2 instanceof AppError18) {
|
|
8536
|
+
throw error2;
|
|
8537
|
+
} else {
|
|
8538
|
+
throw new InternalServerError22(
|
|
8539
|
+
"Failed to process forget password request."
|
|
8540
|
+
);
|
|
8541
|
+
}
|
|
8542
|
+
}
|
|
8543
|
+
}
|
|
8544
|
+
const { addOrder: addPaypalOrder } = usePaypalService();
|
|
8545
|
+
const { getByEmail: getOrgByEmail, getByName: getOrgByName } = useOrgRepo();
|
|
8546
|
+
async function orgSetupFee(value) {
|
|
8547
|
+
const session = useAtlas19.getClient()?.startSession();
|
|
8548
|
+
if (!session) {
|
|
8549
|
+
throw new BadRequestError42("Unable to start database session.");
|
|
8550
|
+
}
|
|
8551
|
+
try {
|
|
8552
|
+
session.startTransaction();
|
|
8553
|
+
const orgExistingByName = await getOrgByName(value.name);
|
|
8554
|
+
if (orgExistingByName) {
|
|
8555
|
+
throw new BadRequestError42(`Name ${value.name} is already taken.`);
|
|
8556
|
+
}
|
|
8557
|
+
const orgExistingByEmail = await getOrgByEmail(value.email);
|
|
8558
|
+
if (orgExistingByEmail) {
|
|
8559
|
+
throw new BadRequestError42(`Email ${value.email} is already taken.`);
|
|
8560
|
+
}
|
|
8561
|
+
const amount = 100;
|
|
8562
|
+
const verificationId = await add(
|
|
8563
|
+
{
|
|
8564
|
+
type: "org-setup-fee",
|
|
8565
|
+
email: value.email,
|
|
8566
|
+
metadata: {
|
|
8567
|
+
seats: value.seats,
|
|
8568
|
+
contact: value.contact,
|
|
8569
|
+
orgName: value.name,
|
|
8570
|
+
createdBy: value.createdBy,
|
|
8571
|
+
amount
|
|
8572
|
+
}
|
|
8573
|
+
},
|
|
8574
|
+
session
|
|
8575
|
+
);
|
|
8576
|
+
const order = await addPaypalOrder({
|
|
8577
|
+
amount,
|
|
8578
|
+
currency: "PHP",
|
|
8579
|
+
customId: String(verificationId),
|
|
8580
|
+
returnUrl: `${APP_ORG}/organizations/success`,
|
|
8581
|
+
cancelUrl: `${APP_ORG}/organizations/cancel`,
|
|
8582
|
+
action: "pay"
|
|
8583
|
+
});
|
|
8584
|
+
await session?.commitTransaction();
|
|
8585
|
+
const paypalOrderLink = JSON.parse(order.body.toString()).links.find(
|
|
8586
|
+
(link) => link.rel === "approve"
|
|
8587
|
+
);
|
|
8588
|
+
return {
|
|
8589
|
+
paypalOrderLink: paypalOrderLink ? paypalOrderLink.href : ""
|
|
8590
|
+
};
|
|
8591
|
+
} catch (error) {
|
|
8592
|
+
if (error instanceof AppError18) {
|
|
8593
|
+
throw error;
|
|
7822
8594
|
}
|
|
8595
|
+
throw new InternalServerError22(
|
|
8596
|
+
"Failed to process organization setup fee."
|
|
8597
|
+
);
|
|
7823
8598
|
}
|
|
7824
8599
|
}
|
|
7825
8600
|
return {
|
|
@@ -7833,7 +8608,8 @@ function useVerificationService() {
|
|
|
7833
8608
|
signUp,
|
|
7834
8609
|
inviteMember,
|
|
7835
8610
|
cancelInviteMember,
|
|
7836
|
-
forgetPassword
|
|
8611
|
+
forgetPassword,
|
|
8612
|
+
orgSetupFee
|
|
7837
8613
|
};
|
|
7838
8614
|
}
|
|
7839
8615
|
|
|
@@ -7843,13 +8619,13 @@ function useAuthController() {
|
|
|
7843
8619
|
async function login(req, res, next) {
|
|
7844
8620
|
const email = req.body.email;
|
|
7845
8621
|
const password = req.body.password;
|
|
7846
|
-
const validation =
|
|
7847
|
-
email:
|
|
7848
|
-
password:
|
|
8622
|
+
const validation = Joi36.object({
|
|
8623
|
+
email: Joi36.string().email().required(),
|
|
8624
|
+
password: Joi36.string().required()
|
|
7849
8625
|
});
|
|
7850
8626
|
const { error } = validation.validate({ email, password });
|
|
7851
8627
|
if (error) {
|
|
7852
|
-
next(new
|
|
8628
|
+
next(new BadRequestError43(error.message));
|
|
7853
8629
|
return;
|
|
7854
8630
|
}
|
|
7855
8631
|
try {
|
|
@@ -7865,14 +8641,14 @@ function useAuthController() {
|
|
|
7865
8641
|
res.cookie("sid", session.sid, cookieOptions).cookie("user", session.user, cookieOptions).json({ message: "Login successful" });
|
|
7866
8642
|
return;
|
|
7867
8643
|
} catch (error2) {
|
|
7868
|
-
|
|
8644
|
+
logger22.log({
|
|
7869
8645
|
level: "error",
|
|
7870
8646
|
message: `Error during login: ${error2.message}`
|
|
7871
8647
|
});
|
|
7872
|
-
if (error2 instanceof
|
|
8648
|
+
if (error2 instanceof AppError19) {
|
|
7873
8649
|
next(error2);
|
|
7874
8650
|
} else {
|
|
7875
|
-
next(new
|
|
8651
|
+
next(new InternalServerError23("An unexpected error occurred"));
|
|
7876
8652
|
}
|
|
7877
8653
|
return;
|
|
7878
8654
|
}
|
|
@@ -7880,17 +8656,17 @@ function useAuthController() {
|
|
|
7880
8656
|
async function logout(req, res, next) {
|
|
7881
8657
|
const sid = req.headers["authorization"] ?? "";
|
|
7882
8658
|
if (!sid) {
|
|
7883
|
-
next(new
|
|
8659
|
+
next(new BadRequestError43("Session ID is required"));
|
|
7884
8660
|
return;
|
|
7885
8661
|
}
|
|
7886
8662
|
try {
|
|
7887
8663
|
await useAuthService().logout(sid);
|
|
7888
8664
|
res.json({ message: "Logged out successfully" });
|
|
7889
8665
|
} catch (error) {
|
|
7890
|
-
if (error instanceof
|
|
8666
|
+
if (error instanceof AppError19) {
|
|
7891
8667
|
next(error);
|
|
7892
8668
|
} else {
|
|
7893
|
-
next(new
|
|
8669
|
+
next(new InternalServerError23("An unexpected error occurred"));
|
|
7894
8670
|
}
|
|
7895
8671
|
}
|
|
7896
8672
|
}
|
|
@@ -7901,64 +8677,64 @@ function useAuthController() {
|
|
|
7901
8677
|
}
|
|
7902
8678
|
|
|
7903
8679
|
// src/resources/building/building.model.ts
|
|
7904
|
-
import { BadRequestError as
|
|
7905
|
-
import
|
|
7906
|
-
import { ObjectId as
|
|
7907
|
-
var schemaBuilding =
|
|
7908
|
-
_id:
|
|
7909
|
-
school:
|
|
7910
|
-
serial:
|
|
7911
|
-
name:
|
|
7912
|
-
levels:
|
|
7913
|
-
createdAt:
|
|
7914
|
-
updatedAt:
|
|
7915
|
-
deletedAt:
|
|
7916
|
-
status:
|
|
8680
|
+
import { BadRequestError as BadRequestError44, logger as logger23 } from "@goweekdays/utils";
|
|
8681
|
+
import Joi37 from "joi";
|
|
8682
|
+
import { ObjectId as ObjectId22 } from "mongodb";
|
|
8683
|
+
var schemaBuilding = Joi37.object({
|
|
8684
|
+
_id: Joi37.string().hex().optional(),
|
|
8685
|
+
school: Joi37.string().hex().required(),
|
|
8686
|
+
serial: Joi37.string().optional().allow("", null),
|
|
8687
|
+
name: Joi37.string().required(),
|
|
8688
|
+
levels: Joi37.number().integer().min(1).required(),
|
|
8689
|
+
createdAt: Joi37.date().optional().allow("", null),
|
|
8690
|
+
updatedAt: Joi37.date().optional().allow("", null),
|
|
8691
|
+
deletedAt: Joi37.date().optional().allow("", null),
|
|
8692
|
+
status: Joi37.string().optional().allow("", null)
|
|
7917
8693
|
});
|
|
7918
|
-
var schemaBuildingUnit =
|
|
7919
|
-
_id:
|
|
7920
|
-
school:
|
|
7921
|
-
name:
|
|
7922
|
-
building:
|
|
7923
|
-
buildingName:
|
|
7924
|
-
level:
|
|
7925
|
-
category:
|
|
7926
|
-
type:
|
|
7927
|
-
seating_capacity:
|
|
7928
|
-
standing_capacity:
|
|
7929
|
-
description:
|
|
7930
|
-
unit_of_measurement:
|
|
7931
|
-
area:
|
|
7932
|
-
status:
|
|
8694
|
+
var schemaBuildingUnit = Joi37.object({
|
|
8695
|
+
_id: Joi37.string().hex().optional(),
|
|
8696
|
+
school: Joi37.string().hex().required(),
|
|
8697
|
+
name: Joi37.string().optional().allow("", null),
|
|
8698
|
+
building: Joi37.string().hex().required(),
|
|
8699
|
+
buildingName: Joi37.string().optional().allow("", null),
|
|
8700
|
+
level: Joi37.number().integer().min(1).required(),
|
|
8701
|
+
category: Joi37.string().required(),
|
|
8702
|
+
type: Joi37.string().required(),
|
|
8703
|
+
seating_capacity: Joi37.number().integer().min(0).required(),
|
|
8704
|
+
standing_capacity: Joi37.number().integer().min(0).required(),
|
|
8705
|
+
description: Joi37.string().optional().allow("", null),
|
|
8706
|
+
unit_of_measurement: Joi37.string().valid("sqm").required(),
|
|
8707
|
+
area: Joi37.number().positive().required(),
|
|
8708
|
+
status: Joi37.string().optional().allow("", null)
|
|
7933
8709
|
});
|
|
7934
|
-
var schemaUpdateOptions =
|
|
7935
|
-
name:
|
|
7936
|
-
building:
|
|
7937
|
-
buildingName:
|
|
7938
|
-
level:
|
|
7939
|
-
category:
|
|
7940
|
-
type:
|
|
7941
|
-
seating_capacity:
|
|
7942
|
-
standing_capacity:
|
|
7943
|
-
area:
|
|
8710
|
+
var schemaUpdateOptions = Joi37.object({
|
|
8711
|
+
name: Joi37.string().optional().allow("", null),
|
|
8712
|
+
building: Joi37.string().hex().optional().allow("", null),
|
|
8713
|
+
buildingName: Joi37.string().optional().allow("", null),
|
|
8714
|
+
level: Joi37.number().integer().min(1).optional().allow("", null),
|
|
8715
|
+
category: Joi37.string().optional().allow("", null),
|
|
8716
|
+
type: Joi37.string().optional().allow("", null),
|
|
8717
|
+
seating_capacity: Joi37.number().integer().min(0).optional().allow("", null),
|
|
8718
|
+
standing_capacity: Joi37.number().integer().min(0).optional().allow("", null),
|
|
8719
|
+
area: Joi37.number().positive().optional().allow("", null)
|
|
7944
8720
|
});
|
|
7945
8721
|
function MBuilding(value) {
|
|
7946
8722
|
const { error } = schemaBuilding.validate(value);
|
|
7947
8723
|
if (error) {
|
|
7948
|
-
|
|
7949
|
-
throw new
|
|
8724
|
+
logger23.info(`Building Model: ${error.message}`);
|
|
8725
|
+
throw new BadRequestError44(error.message);
|
|
7950
8726
|
}
|
|
7951
8727
|
if (value._id && typeof value._id === "string") {
|
|
7952
8728
|
try {
|
|
7953
|
-
value._id = new
|
|
8729
|
+
value._id = new ObjectId22(value._id);
|
|
7954
8730
|
} catch (error2) {
|
|
7955
|
-
throw new
|
|
8731
|
+
throw new BadRequestError44("Invalid _id format");
|
|
7956
8732
|
}
|
|
7957
8733
|
}
|
|
7958
8734
|
try {
|
|
7959
|
-
value.school = new
|
|
8735
|
+
value.school = new ObjectId22(value.school);
|
|
7960
8736
|
} catch (error2) {
|
|
7961
|
-
throw new
|
|
8737
|
+
throw new BadRequestError44("Invalid school format");
|
|
7962
8738
|
}
|
|
7963
8739
|
return {
|
|
7964
8740
|
_id: value._id ?? void 0,
|
|
@@ -7975,25 +8751,25 @@ function MBuilding(value) {
|
|
|
7975
8751
|
function MBuildingUnit(value) {
|
|
7976
8752
|
const { error } = schemaBuildingUnit.validate(value);
|
|
7977
8753
|
if (error) {
|
|
7978
|
-
|
|
7979
|
-
throw new
|
|
8754
|
+
logger23.info(`Building Unit Model: ${error.message}`);
|
|
8755
|
+
throw new BadRequestError44(error.message);
|
|
7980
8756
|
}
|
|
7981
8757
|
if (value._id && typeof value._id === "string") {
|
|
7982
8758
|
try {
|
|
7983
|
-
value._id = new
|
|
8759
|
+
value._id = new ObjectId22(value._id);
|
|
7984
8760
|
} catch (error2) {
|
|
7985
|
-
throw new
|
|
8761
|
+
throw new BadRequestError44("Invalid ID");
|
|
7986
8762
|
}
|
|
7987
8763
|
}
|
|
7988
8764
|
try {
|
|
7989
|
-
value.school = new
|
|
8765
|
+
value.school = new ObjectId22(value.school);
|
|
7990
8766
|
} catch (error2) {
|
|
7991
|
-
throw new
|
|
8767
|
+
throw new BadRequestError44("Invalid school ID");
|
|
7992
8768
|
}
|
|
7993
8769
|
try {
|
|
7994
|
-
value.building = new
|
|
8770
|
+
value.building = new ObjectId22(value.building);
|
|
7995
8771
|
} catch (error2) {
|
|
7996
|
-
throw new
|
|
8772
|
+
throw new BadRequestError44("Invalid building ID");
|
|
7997
8773
|
}
|
|
7998
8774
|
return {
|
|
7999
8775
|
_id: value._id ?? void 0,
|
|
@@ -8018,24 +8794,24 @@ function MBuildingUnit(value) {
|
|
|
8018
8794
|
|
|
8019
8795
|
// src/resources/building/building.repository.ts
|
|
8020
8796
|
import {
|
|
8021
|
-
AppError as
|
|
8022
|
-
BadRequestError as
|
|
8023
|
-
InternalServerError as
|
|
8024
|
-
logger as
|
|
8025
|
-
makeCacheKey as
|
|
8026
|
-
paginate as
|
|
8027
|
-
useAtlas as
|
|
8028
|
-
useCache as
|
|
8797
|
+
AppError as AppError20,
|
|
8798
|
+
BadRequestError as BadRequestError45,
|
|
8799
|
+
InternalServerError as InternalServerError24,
|
|
8800
|
+
logger as logger24,
|
|
8801
|
+
makeCacheKey as makeCacheKey15,
|
|
8802
|
+
paginate as paginate13,
|
|
8803
|
+
useAtlas as useAtlas20,
|
|
8804
|
+
useCache as useCache16
|
|
8029
8805
|
} from "@goweekdays/utils";
|
|
8030
|
-
import { ObjectId as
|
|
8806
|
+
import { ObjectId as ObjectId23 } from "mongodb";
|
|
8031
8807
|
function useBuildingRepo() {
|
|
8032
|
-
const db =
|
|
8808
|
+
const db = useAtlas20.getDb();
|
|
8033
8809
|
if (!db) {
|
|
8034
8810
|
throw new Error("Unable to connect to server.");
|
|
8035
8811
|
}
|
|
8036
8812
|
const namespace_collection = "school.buildings";
|
|
8037
8813
|
const collection = db.collection(namespace_collection);
|
|
8038
|
-
const { getCache, setCache, delNamespace } =
|
|
8814
|
+
const { getCache, setCache, delNamespace } = useCache16(namespace_collection);
|
|
8039
8815
|
async function createIndexes() {
|
|
8040
8816
|
try {
|
|
8041
8817
|
await collection.createIndexes([
|
|
@@ -8054,16 +8830,16 @@ function useBuildingRepo() {
|
|
|
8054
8830
|
delCachedData();
|
|
8055
8831
|
return res.insertedId;
|
|
8056
8832
|
} catch (error) {
|
|
8057
|
-
|
|
8833
|
+
logger24.log({
|
|
8058
8834
|
level: "error",
|
|
8059
8835
|
message: error.message
|
|
8060
8836
|
});
|
|
8061
|
-
if (error instanceof
|
|
8837
|
+
if (error instanceof AppError20) {
|
|
8062
8838
|
throw error;
|
|
8063
8839
|
} else {
|
|
8064
8840
|
const isDuplicated = error.message.includes("duplicate");
|
|
8065
8841
|
if (isDuplicated) {
|
|
8066
|
-
throw new
|
|
8842
|
+
throw new BadRequestError45("Building already exists.");
|
|
8067
8843
|
}
|
|
8068
8844
|
throw new Error("Failed to create building.");
|
|
8069
8845
|
}
|
|
@@ -8071,9 +8847,9 @@ function useBuildingRepo() {
|
|
|
8071
8847
|
}
|
|
8072
8848
|
async function updateById(_id, value, session) {
|
|
8073
8849
|
try {
|
|
8074
|
-
_id = new
|
|
8850
|
+
_id = new ObjectId23(_id);
|
|
8075
8851
|
} catch (error) {
|
|
8076
|
-
throw new
|
|
8852
|
+
throw new BadRequestError45("Invalid ID.");
|
|
8077
8853
|
}
|
|
8078
8854
|
try {
|
|
8079
8855
|
const res = await collection.updateOne(
|
|
@@ -8084,11 +8860,11 @@ function useBuildingRepo() {
|
|
|
8084
8860
|
delCachedData();
|
|
8085
8861
|
return res;
|
|
8086
8862
|
} catch (error) {
|
|
8087
|
-
|
|
8863
|
+
logger24.log({
|
|
8088
8864
|
level: "error",
|
|
8089
8865
|
message: error.message
|
|
8090
8866
|
});
|
|
8091
|
-
if (error instanceof
|
|
8867
|
+
if (error instanceof AppError20) {
|
|
8092
8868
|
throw error;
|
|
8093
8869
|
} else {
|
|
8094
8870
|
throw new Error("Failed to update building.");
|
|
@@ -8113,9 +8889,9 @@ function useBuildingRepo() {
|
|
|
8113
8889
|
}
|
|
8114
8890
|
if (school) {
|
|
8115
8891
|
try {
|
|
8116
|
-
query.school = new
|
|
8892
|
+
query.school = new ObjectId23(school);
|
|
8117
8893
|
} catch (error) {
|
|
8118
|
-
throw new
|
|
8894
|
+
throw new BadRequestError45("Invalid school ID.");
|
|
8119
8895
|
}
|
|
8120
8896
|
}
|
|
8121
8897
|
const cacheParams = {
|
|
@@ -8129,15 +8905,15 @@ function useBuildingRepo() {
|
|
|
8129
8905
|
cacheParams.school = school;
|
|
8130
8906
|
if (status !== "active")
|
|
8131
8907
|
cacheParams.status = status;
|
|
8132
|
-
const cacheKey =
|
|
8133
|
-
|
|
8908
|
+
const cacheKey = makeCacheKey15(namespace_collection, cacheParams);
|
|
8909
|
+
logger24.log({
|
|
8134
8910
|
level: "info",
|
|
8135
8911
|
message: `Cache key for getAll buildings: ${cacheKey}`
|
|
8136
8912
|
});
|
|
8137
8913
|
try {
|
|
8138
8914
|
const cached = await getCache(cacheKey);
|
|
8139
8915
|
if (cached) {
|
|
8140
|
-
|
|
8916
|
+
logger24.log({
|
|
8141
8917
|
level: "info",
|
|
8142
8918
|
message: `Cache hit for getAll buildings: ${cacheKey}`
|
|
8143
8919
|
});
|
|
@@ -8150,35 +8926,35 @@ function useBuildingRepo() {
|
|
|
8150
8926
|
{ $limit: limit }
|
|
8151
8927
|
]).toArray();
|
|
8152
8928
|
const length = await collection.countDocuments(query);
|
|
8153
|
-
const data =
|
|
8929
|
+
const data = paginate13(items, page, limit, length);
|
|
8154
8930
|
setCache(cacheKey, data, 600).then(() => {
|
|
8155
|
-
|
|
8931
|
+
logger24.log({
|
|
8156
8932
|
level: "info",
|
|
8157
8933
|
message: `Cache set for getAll buildings: ${cacheKey}`
|
|
8158
8934
|
});
|
|
8159
8935
|
}).catch((err) => {
|
|
8160
|
-
|
|
8936
|
+
logger24.log({
|
|
8161
8937
|
level: "error",
|
|
8162
8938
|
message: `Failed to set cache for getAll buildings: ${err.message}`
|
|
8163
8939
|
});
|
|
8164
8940
|
});
|
|
8165
8941
|
return data;
|
|
8166
8942
|
} catch (error) {
|
|
8167
|
-
|
|
8943
|
+
logger24.log({ level: "error", message: `${error}` });
|
|
8168
8944
|
throw error;
|
|
8169
8945
|
}
|
|
8170
8946
|
}
|
|
8171
8947
|
async function getById(_id) {
|
|
8172
8948
|
try {
|
|
8173
|
-
_id = new
|
|
8949
|
+
_id = new ObjectId23(_id);
|
|
8174
8950
|
} catch (error) {
|
|
8175
|
-
throw new
|
|
8951
|
+
throw new BadRequestError45("Invalid ID.");
|
|
8176
8952
|
}
|
|
8177
|
-
const cacheKey =
|
|
8953
|
+
const cacheKey = makeCacheKey15(namespace_collection, { _id: String(_id) });
|
|
8178
8954
|
try {
|
|
8179
8955
|
const cached = await getCache(cacheKey);
|
|
8180
8956
|
if (cached) {
|
|
8181
|
-
|
|
8957
|
+
logger24.log({
|
|
8182
8958
|
level: "info",
|
|
8183
8959
|
message: `Cache hit for getById building: ${cacheKey}`
|
|
8184
8960
|
});
|
|
@@ -8188,30 +8964,30 @@ function useBuildingRepo() {
|
|
|
8188
8964
|
_id
|
|
8189
8965
|
});
|
|
8190
8966
|
setCache(cacheKey, result, 300).then(() => {
|
|
8191
|
-
|
|
8967
|
+
logger24.log({
|
|
8192
8968
|
level: "info",
|
|
8193
8969
|
message: `Cache set for building by id: ${cacheKey}`
|
|
8194
8970
|
});
|
|
8195
8971
|
}).catch((err) => {
|
|
8196
|
-
|
|
8972
|
+
logger24.log({
|
|
8197
8973
|
level: "error",
|
|
8198
8974
|
message: `Failed to set cache for building by id: ${err.message}`
|
|
8199
8975
|
});
|
|
8200
8976
|
});
|
|
8201
8977
|
return result;
|
|
8202
8978
|
} catch (error) {
|
|
8203
|
-
if (error instanceof
|
|
8979
|
+
if (error instanceof AppError20) {
|
|
8204
8980
|
throw error;
|
|
8205
8981
|
} else {
|
|
8206
|
-
throw new
|
|
8982
|
+
throw new InternalServerError24("Failed to get building.");
|
|
8207
8983
|
}
|
|
8208
8984
|
}
|
|
8209
8985
|
}
|
|
8210
8986
|
async function deleteById(_id, session) {
|
|
8211
8987
|
try {
|
|
8212
|
-
_id = new
|
|
8988
|
+
_id = new ObjectId23(_id);
|
|
8213
8989
|
} catch (error) {
|
|
8214
|
-
throw new
|
|
8990
|
+
throw new BadRequestError45("Invalid ID.");
|
|
8215
8991
|
}
|
|
8216
8992
|
try {
|
|
8217
8993
|
const res = await collection.updateOne(
|
|
@@ -8221,25 +8997,25 @@ function useBuildingRepo() {
|
|
|
8221
8997
|
delCachedData();
|
|
8222
8998
|
return res;
|
|
8223
8999
|
} catch (error) {
|
|
8224
|
-
|
|
9000
|
+
logger24.log({
|
|
8225
9001
|
level: "error",
|
|
8226
9002
|
message: error.message
|
|
8227
9003
|
});
|
|
8228
|
-
if (error instanceof
|
|
9004
|
+
if (error instanceof AppError20) {
|
|
8229
9005
|
throw error;
|
|
8230
9006
|
} else {
|
|
8231
|
-
throw new
|
|
9007
|
+
throw new InternalServerError24("Failed to delete building.");
|
|
8232
9008
|
}
|
|
8233
9009
|
}
|
|
8234
9010
|
}
|
|
8235
9011
|
function delCachedData() {
|
|
8236
9012
|
delNamespace().then(() => {
|
|
8237
|
-
|
|
9013
|
+
logger24.log({
|
|
8238
9014
|
level: "info",
|
|
8239
9015
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
8240
9016
|
});
|
|
8241
9017
|
}).catch((err) => {
|
|
8242
|
-
|
|
9018
|
+
logger24.log({
|
|
8243
9019
|
level: "error",
|
|
8244
9020
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
8245
9021
|
});
|
|
@@ -8256,28 +9032,28 @@ function useBuildingRepo() {
|
|
|
8256
9032
|
}
|
|
8257
9033
|
|
|
8258
9034
|
// src/resources/building/building.service.ts
|
|
8259
|
-
import { BadRequestError as
|
|
9035
|
+
import { BadRequestError as BadRequestError47, NotFoundError as NotFoundError4, useAtlas as useAtlas22 } from "@goweekdays/utils";
|
|
8260
9036
|
|
|
8261
9037
|
// src/resources/building/building-unit.repository.ts
|
|
8262
9038
|
import {
|
|
8263
|
-
AppError as
|
|
8264
|
-
BadRequestError as
|
|
8265
|
-
InternalServerError as
|
|
8266
|
-
logger as
|
|
8267
|
-
makeCacheKey as
|
|
8268
|
-
paginate as
|
|
8269
|
-
useAtlas as
|
|
8270
|
-
useCache as
|
|
9039
|
+
AppError as AppError21,
|
|
9040
|
+
BadRequestError as BadRequestError46,
|
|
9041
|
+
InternalServerError as InternalServerError25,
|
|
9042
|
+
logger as logger25,
|
|
9043
|
+
makeCacheKey as makeCacheKey16,
|
|
9044
|
+
paginate as paginate14,
|
|
9045
|
+
useAtlas as useAtlas21,
|
|
9046
|
+
useCache as useCache17
|
|
8271
9047
|
} from "@goweekdays/utils";
|
|
8272
|
-
import { ObjectId as
|
|
9048
|
+
import { ObjectId as ObjectId24 } from "mongodb";
|
|
8273
9049
|
function useBuildingUnitRepo() {
|
|
8274
|
-
const db =
|
|
9050
|
+
const db = useAtlas21.getDb();
|
|
8275
9051
|
if (!db) {
|
|
8276
9052
|
throw new Error("Unable to connect to server.");
|
|
8277
9053
|
}
|
|
8278
9054
|
const namespace_collection = "school.building-units";
|
|
8279
9055
|
const collection = db.collection(namespace_collection);
|
|
8280
|
-
const { getCache, setCache, delNamespace } =
|
|
9056
|
+
const { getCache, setCache, delNamespace } = useCache17(namespace_collection);
|
|
8281
9057
|
async function createIndexes() {
|
|
8282
9058
|
try {
|
|
8283
9059
|
await collection.createIndexes([
|
|
@@ -8305,12 +9081,12 @@ function useBuildingUnitRepo() {
|
|
|
8305
9081
|
}
|
|
8306
9082
|
function delCachedData() {
|
|
8307
9083
|
delNamespace().then(() => {
|
|
8308
|
-
|
|
9084
|
+
logger25.log({
|
|
8309
9085
|
level: "info",
|
|
8310
9086
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
8311
9087
|
});
|
|
8312
9088
|
}).catch((err) => {
|
|
8313
|
-
|
|
9089
|
+
logger25.log({
|
|
8314
9090
|
level: "error",
|
|
8315
9091
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
8316
9092
|
});
|
|
@@ -8323,11 +9099,11 @@ function useBuildingUnitRepo() {
|
|
|
8323
9099
|
delCachedData();
|
|
8324
9100
|
return res.insertedId;
|
|
8325
9101
|
} catch (error) {
|
|
8326
|
-
|
|
9102
|
+
logger25.log({
|
|
8327
9103
|
level: "error",
|
|
8328
9104
|
message: error.message
|
|
8329
9105
|
});
|
|
8330
|
-
if (error instanceof
|
|
9106
|
+
if (error instanceof AppError21) {
|
|
8331
9107
|
throw error;
|
|
8332
9108
|
} else {
|
|
8333
9109
|
throw new Error("Failed to create building unit.");
|
|
@@ -8337,12 +9113,12 @@ function useBuildingUnitRepo() {
|
|
|
8337
9113
|
async function updateById(_id, value, session) {
|
|
8338
9114
|
const { error } = schemaUpdateOptions.validate(value);
|
|
8339
9115
|
if (error) {
|
|
8340
|
-
throw new
|
|
9116
|
+
throw new BadRequestError46(error.message);
|
|
8341
9117
|
}
|
|
8342
9118
|
try {
|
|
8343
|
-
_id = new
|
|
9119
|
+
_id = new ObjectId24(_id);
|
|
8344
9120
|
} catch (error2) {
|
|
8345
|
-
throw new
|
|
9121
|
+
throw new BadRequestError46("Invalid ID.");
|
|
8346
9122
|
}
|
|
8347
9123
|
try {
|
|
8348
9124
|
const res = await collection.updateOne(
|
|
@@ -8353,11 +9129,11 @@ function useBuildingUnitRepo() {
|
|
|
8353
9129
|
delCachedData();
|
|
8354
9130
|
return res;
|
|
8355
9131
|
} catch (error2) {
|
|
8356
|
-
|
|
9132
|
+
logger25.log({
|
|
8357
9133
|
level: "error",
|
|
8358
9134
|
message: error2.message
|
|
8359
9135
|
});
|
|
8360
|
-
if (error2 instanceof
|
|
9136
|
+
if (error2 instanceof AppError21) {
|
|
8361
9137
|
throw error2;
|
|
8362
9138
|
} else {
|
|
8363
9139
|
throw new Error("Failed to create building unit.");
|
|
@@ -8367,12 +9143,12 @@ function useBuildingUnitRepo() {
|
|
|
8367
9143
|
async function updateByBuildingId(building, value, session) {
|
|
8368
9144
|
const { error } = schemaUpdateOptions.validate(value);
|
|
8369
9145
|
if (error) {
|
|
8370
|
-
throw new
|
|
9146
|
+
throw new BadRequestError46(error.message);
|
|
8371
9147
|
}
|
|
8372
9148
|
try {
|
|
8373
|
-
building = new
|
|
9149
|
+
building = new ObjectId24(building);
|
|
8374
9150
|
} catch (error2) {
|
|
8375
|
-
throw new
|
|
9151
|
+
throw new BadRequestError46("Invalid building ID.");
|
|
8376
9152
|
}
|
|
8377
9153
|
try {
|
|
8378
9154
|
const res = await collection.updateMany(
|
|
@@ -8383,11 +9159,11 @@ function useBuildingUnitRepo() {
|
|
|
8383
9159
|
delCachedData();
|
|
8384
9160
|
return res;
|
|
8385
9161
|
} catch (error2) {
|
|
8386
|
-
|
|
9162
|
+
logger25.log({
|
|
8387
9163
|
level: "error",
|
|
8388
9164
|
message: error2.message
|
|
8389
9165
|
});
|
|
8390
|
-
if (error2 instanceof
|
|
9166
|
+
if (error2 instanceof AppError21) {
|
|
8391
9167
|
throw error2;
|
|
8392
9168
|
} else {
|
|
8393
9169
|
throw new Error("Failed to update building unit.");
|
|
@@ -8414,16 +9190,16 @@ function useBuildingUnitRepo() {
|
|
|
8414
9190
|
}
|
|
8415
9191
|
if (school) {
|
|
8416
9192
|
try {
|
|
8417
|
-
query.school = new
|
|
9193
|
+
query.school = new ObjectId24(school);
|
|
8418
9194
|
} catch (error) {
|
|
8419
|
-
throw new
|
|
9195
|
+
throw new BadRequestError46("Invalid school ID.");
|
|
8420
9196
|
}
|
|
8421
9197
|
}
|
|
8422
9198
|
if (building) {
|
|
8423
9199
|
try {
|
|
8424
|
-
query.building = new
|
|
9200
|
+
query.building = new ObjectId24(building);
|
|
8425
9201
|
} catch (error) {
|
|
8426
|
-
throw new
|
|
9202
|
+
throw new BadRequestError46("Invalid building ID.");
|
|
8427
9203
|
}
|
|
8428
9204
|
}
|
|
8429
9205
|
const cacheParams = {
|
|
@@ -8439,15 +9215,15 @@ function useBuildingUnitRepo() {
|
|
|
8439
9215
|
cacheParams.building = building;
|
|
8440
9216
|
if (status !== "active")
|
|
8441
9217
|
cacheParams.status = status;
|
|
8442
|
-
const cacheKey =
|
|
8443
|
-
|
|
9218
|
+
const cacheKey = makeCacheKey16(namespace_collection, cacheParams);
|
|
9219
|
+
logger25.log({
|
|
8444
9220
|
level: "info",
|
|
8445
9221
|
message: `Cache key for getAll building units: ${cacheKey}`
|
|
8446
9222
|
});
|
|
8447
9223
|
try {
|
|
8448
9224
|
const cached = await getCache(cacheKey);
|
|
8449
9225
|
if (cached) {
|
|
8450
|
-
|
|
9226
|
+
logger25.log({
|
|
8451
9227
|
level: "info",
|
|
8452
9228
|
message: `Cache hit for getAll building units: ${cacheKey}`
|
|
8453
9229
|
});
|
|
@@ -8460,35 +9236,35 @@ function useBuildingUnitRepo() {
|
|
|
8460
9236
|
{ $limit: limit }
|
|
8461
9237
|
]).toArray();
|
|
8462
9238
|
const length = await collection.countDocuments(query);
|
|
8463
|
-
const data =
|
|
9239
|
+
const data = paginate14(items, page, limit, length);
|
|
8464
9240
|
setCache(cacheKey, data, 600).then(() => {
|
|
8465
|
-
|
|
9241
|
+
logger25.log({
|
|
8466
9242
|
level: "info",
|
|
8467
9243
|
message: `Cache set for getAll building units: ${cacheKey}`
|
|
8468
9244
|
});
|
|
8469
9245
|
}).catch((err) => {
|
|
8470
|
-
|
|
9246
|
+
logger25.log({
|
|
8471
9247
|
level: "error",
|
|
8472
9248
|
message: `Failed to set cache for getAll building units: ${err.message}`
|
|
8473
9249
|
});
|
|
8474
9250
|
});
|
|
8475
9251
|
return data;
|
|
8476
9252
|
} catch (error) {
|
|
8477
|
-
|
|
9253
|
+
logger25.log({ level: "error", message: `${error}` });
|
|
8478
9254
|
throw error;
|
|
8479
9255
|
}
|
|
8480
9256
|
}
|
|
8481
9257
|
async function getById(_id) {
|
|
8482
9258
|
try {
|
|
8483
|
-
_id = new
|
|
9259
|
+
_id = new ObjectId24(_id);
|
|
8484
9260
|
} catch (error) {
|
|
8485
|
-
throw new
|
|
9261
|
+
throw new BadRequestError46("Invalid ID.");
|
|
8486
9262
|
}
|
|
8487
|
-
const cacheKey =
|
|
9263
|
+
const cacheKey = makeCacheKey16(namespace_collection, { _id: String(_id) });
|
|
8488
9264
|
try {
|
|
8489
9265
|
const cached = await getCache(cacheKey);
|
|
8490
9266
|
if (cached) {
|
|
8491
|
-
|
|
9267
|
+
logger25.log({
|
|
8492
9268
|
level: "info",
|
|
8493
9269
|
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
8494
9270
|
});
|
|
@@ -8499,42 +9275,42 @@ function useBuildingUnitRepo() {
|
|
|
8499
9275
|
deletedAt: { $in: ["", null] }
|
|
8500
9276
|
});
|
|
8501
9277
|
if (!result) {
|
|
8502
|
-
throw new
|
|
9278
|
+
throw new BadRequestError46("Building unit not found.");
|
|
8503
9279
|
}
|
|
8504
9280
|
setCache(cacheKey, result, 300).then(() => {
|
|
8505
|
-
|
|
9281
|
+
logger25.log({
|
|
8506
9282
|
level: "info",
|
|
8507
9283
|
message: `Cache set for building unit by id: ${cacheKey}`
|
|
8508
9284
|
});
|
|
8509
9285
|
}).catch((err) => {
|
|
8510
|
-
|
|
9286
|
+
logger25.log({
|
|
8511
9287
|
level: "error",
|
|
8512
9288
|
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
8513
9289
|
});
|
|
8514
9290
|
});
|
|
8515
9291
|
return result;
|
|
8516
9292
|
} catch (error) {
|
|
8517
|
-
if (error instanceof
|
|
9293
|
+
if (error instanceof AppError21) {
|
|
8518
9294
|
throw error;
|
|
8519
9295
|
} else {
|
|
8520
|
-
throw new
|
|
9296
|
+
throw new InternalServerError25("Failed to get building unit.");
|
|
8521
9297
|
}
|
|
8522
9298
|
}
|
|
8523
9299
|
}
|
|
8524
9300
|
async function getByBuildingLevel(building, level) {
|
|
8525
9301
|
try {
|
|
8526
|
-
building = new
|
|
9302
|
+
building = new ObjectId24(building);
|
|
8527
9303
|
} catch (error) {
|
|
8528
|
-
throw new
|
|
9304
|
+
throw new BadRequestError46("Invalid building ID.");
|
|
8529
9305
|
}
|
|
8530
|
-
const cacheKey =
|
|
9306
|
+
const cacheKey = makeCacheKey16(namespace_collection, {
|
|
8531
9307
|
building: String(building),
|
|
8532
9308
|
level
|
|
8533
9309
|
});
|
|
8534
9310
|
try {
|
|
8535
9311
|
const cached = await getCache(cacheKey);
|
|
8536
9312
|
if (cached) {
|
|
8537
|
-
|
|
9313
|
+
logger25.log({
|
|
8538
9314
|
level: "info",
|
|
8539
9315
|
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
8540
9316
|
});
|
|
@@ -8546,38 +9322,38 @@ function useBuildingUnitRepo() {
|
|
|
8546
9322
|
status: "active"
|
|
8547
9323
|
});
|
|
8548
9324
|
setCache(cacheKey, result, 300).then(() => {
|
|
8549
|
-
|
|
9325
|
+
logger25.log({
|
|
8550
9326
|
level: "info",
|
|
8551
9327
|
message: `Cache set for building unit by id: ${cacheKey}`
|
|
8552
9328
|
});
|
|
8553
9329
|
}).catch((err) => {
|
|
8554
|
-
|
|
9330
|
+
logger25.log({
|
|
8555
9331
|
level: "error",
|
|
8556
9332
|
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
8557
9333
|
});
|
|
8558
9334
|
});
|
|
8559
9335
|
return result;
|
|
8560
9336
|
} catch (error) {
|
|
8561
|
-
if (error instanceof
|
|
9337
|
+
if (error instanceof AppError21) {
|
|
8562
9338
|
throw error;
|
|
8563
9339
|
} else {
|
|
8564
|
-
throw new
|
|
9340
|
+
throw new InternalServerError25("Failed to get building unit.");
|
|
8565
9341
|
}
|
|
8566
9342
|
}
|
|
8567
9343
|
}
|
|
8568
9344
|
async function getByBuilding(building) {
|
|
8569
9345
|
try {
|
|
8570
|
-
building = new
|
|
9346
|
+
building = new ObjectId24(building);
|
|
8571
9347
|
} catch (error) {
|
|
8572
|
-
throw new
|
|
9348
|
+
throw new BadRequestError46("Invalid building ID.");
|
|
8573
9349
|
}
|
|
8574
|
-
const cacheKey =
|
|
9350
|
+
const cacheKey = makeCacheKey16(namespace_collection, {
|
|
8575
9351
|
building: String(building)
|
|
8576
9352
|
});
|
|
8577
9353
|
try {
|
|
8578
9354
|
const cached = await getCache(cacheKey);
|
|
8579
9355
|
if (cached) {
|
|
8580
|
-
|
|
9356
|
+
logger25.log({
|
|
8581
9357
|
level: "info",
|
|
8582
9358
|
message: `Cache hit for getById building unit: ${cacheKey}`
|
|
8583
9359
|
});
|
|
@@ -8588,30 +9364,30 @@ function useBuildingUnitRepo() {
|
|
|
8588
9364
|
status: "active"
|
|
8589
9365
|
});
|
|
8590
9366
|
setCache(cacheKey, result, 300).then(() => {
|
|
8591
|
-
|
|
9367
|
+
logger25.log({
|
|
8592
9368
|
level: "info",
|
|
8593
9369
|
message: `Cache set for building unit by id: ${cacheKey}`
|
|
8594
9370
|
});
|
|
8595
9371
|
}).catch((err) => {
|
|
8596
|
-
|
|
9372
|
+
logger25.log({
|
|
8597
9373
|
level: "error",
|
|
8598
9374
|
message: `Failed to set cache for building unit by id: ${err.message}`
|
|
8599
9375
|
});
|
|
8600
9376
|
});
|
|
8601
9377
|
return result;
|
|
8602
9378
|
} catch (error) {
|
|
8603
|
-
if (error instanceof
|
|
9379
|
+
if (error instanceof AppError21) {
|
|
8604
9380
|
throw error;
|
|
8605
9381
|
} else {
|
|
8606
|
-
throw new
|
|
9382
|
+
throw new InternalServerError25("Failed to get building unit.");
|
|
8607
9383
|
}
|
|
8608
9384
|
}
|
|
8609
9385
|
}
|
|
8610
9386
|
async function deleteById(_id, session) {
|
|
8611
9387
|
try {
|
|
8612
|
-
_id = new
|
|
9388
|
+
_id = new ObjectId24(_id);
|
|
8613
9389
|
} catch (error) {
|
|
8614
|
-
throw new
|
|
9390
|
+
throw new BadRequestError46("Invalid ID.");
|
|
8615
9391
|
}
|
|
8616
9392
|
try {
|
|
8617
9393
|
const res = await collection.updateOne(
|
|
@@ -8622,11 +9398,11 @@ function useBuildingUnitRepo() {
|
|
|
8622
9398
|
delCachedData();
|
|
8623
9399
|
return "Room/Facility deleted successfully.";
|
|
8624
9400
|
} catch (error) {
|
|
8625
|
-
|
|
9401
|
+
logger25.log({
|
|
8626
9402
|
level: "error",
|
|
8627
9403
|
message: error.message
|
|
8628
9404
|
});
|
|
8629
|
-
if (error instanceof
|
|
9405
|
+
if (error instanceof AppError21) {
|
|
8630
9406
|
throw error;
|
|
8631
9407
|
} else {
|
|
8632
9408
|
throw new Error("Failed to deleted room/facility.");
|
|
@@ -8656,7 +9432,7 @@ function useBuildingService() {
|
|
|
8656
9432
|
const { getByBuildingLevel, getByBuilding, updateByBuildingId } = useBuildingUnitRepo();
|
|
8657
9433
|
async function updateById(id, data) {
|
|
8658
9434
|
data.levels = Number(data.levels);
|
|
8659
|
-
const session =
|
|
9435
|
+
const session = useAtlas22.getClient()?.startSession();
|
|
8660
9436
|
try {
|
|
8661
9437
|
const building = await _getById(id);
|
|
8662
9438
|
if (!building) {
|
|
@@ -8665,7 +9441,7 @@ function useBuildingService() {
|
|
|
8665
9441
|
if (data.levels < building.levels) {
|
|
8666
9442
|
const unit = await getByBuildingLevel(id, building.levels);
|
|
8667
9443
|
if (unit) {
|
|
8668
|
-
throw new
|
|
9444
|
+
throw new BadRequestError47(
|
|
8669
9445
|
"Cannot reduce floors, there are existing building units at higher floors."
|
|
8670
9446
|
);
|
|
8671
9447
|
}
|
|
@@ -8687,7 +9463,7 @@ function useBuildingService() {
|
|
|
8687
9463
|
async function deleteById(id) {
|
|
8688
9464
|
const building = await getByBuilding(id);
|
|
8689
9465
|
if (building) {
|
|
8690
|
-
throw new
|
|
9466
|
+
throw new BadRequestError47(
|
|
8691
9467
|
"Cannot delete building with existing room/facility. Please delete room/facility first."
|
|
8692
9468
|
);
|
|
8693
9469
|
}
|
|
@@ -8705,24 +9481,24 @@ function useBuildingService() {
|
|
|
8705
9481
|
}
|
|
8706
9482
|
|
|
8707
9483
|
// src/resources/building/building.controller.ts
|
|
8708
|
-
import { BadRequestError as
|
|
8709
|
-
import
|
|
9484
|
+
import { BadRequestError as BadRequestError48, logger as logger26 } from "@goweekdays/utils";
|
|
9485
|
+
import Joi38 from "joi";
|
|
8710
9486
|
function useBuildingController() {
|
|
8711
9487
|
const { getAll: _getAll, getById: _getById, add: _add } = useBuildingRepo();
|
|
8712
9488
|
const { updateById: _updateById, deleteById: _deleteById } = useBuildingService();
|
|
8713
9489
|
async function createBuilding(req, res, next) {
|
|
8714
9490
|
const value = req.body;
|
|
8715
|
-
const validation =
|
|
8716
|
-
name:
|
|
8717
|
-
school:
|
|
8718
|
-
levels:
|
|
8719
|
-
serial:
|
|
8720
|
-
status:
|
|
9491
|
+
const validation = Joi38.object({
|
|
9492
|
+
name: Joi38.string().required(),
|
|
9493
|
+
school: Joi38.string().hex().required(),
|
|
9494
|
+
levels: Joi38.number().integer().min(1).required(),
|
|
9495
|
+
serial: Joi38.string().optional().allow("", null),
|
|
9496
|
+
status: Joi38.string().optional().allow("", null)
|
|
8721
9497
|
});
|
|
8722
9498
|
const { error } = validation.validate(value);
|
|
8723
9499
|
if (error) {
|
|
8724
|
-
next(new
|
|
8725
|
-
|
|
9500
|
+
next(new BadRequestError48(error.message));
|
|
9501
|
+
logger26.info(`Controller: ${error.message}`);
|
|
8726
9502
|
return;
|
|
8727
9503
|
}
|
|
8728
9504
|
try {
|
|
@@ -8736,18 +9512,18 @@ function useBuildingController() {
|
|
|
8736
9512
|
async function updateById(req, res, next) {
|
|
8737
9513
|
const value = req.body;
|
|
8738
9514
|
const id = req.params.id ?? "";
|
|
8739
|
-
const validation =
|
|
8740
|
-
id:
|
|
8741
|
-
value:
|
|
8742
|
-
name:
|
|
8743
|
-
serial:
|
|
8744
|
-
levels:
|
|
9515
|
+
const validation = Joi38.object({
|
|
9516
|
+
id: Joi38.string().hex().required(),
|
|
9517
|
+
value: Joi38.object({
|
|
9518
|
+
name: Joi38.string().required(),
|
|
9519
|
+
serial: Joi38.string().optional().allow("", null),
|
|
9520
|
+
levels: Joi38.number().integer().min(1).required()
|
|
8745
9521
|
})
|
|
8746
9522
|
});
|
|
8747
9523
|
const { error } = validation.validate({ id, value });
|
|
8748
9524
|
if (error) {
|
|
8749
|
-
next(new
|
|
8750
|
-
|
|
9525
|
+
next(new BadRequestError48(error.message));
|
|
9526
|
+
logger26.info(`Controller: ${error.message}`);
|
|
8751
9527
|
return;
|
|
8752
9528
|
}
|
|
8753
9529
|
try {
|
|
@@ -8760,16 +9536,16 @@ function useBuildingController() {
|
|
|
8760
9536
|
}
|
|
8761
9537
|
async function getAll(req, res, next) {
|
|
8762
9538
|
const query = req.query;
|
|
8763
|
-
const validation =
|
|
8764
|
-
page:
|
|
8765
|
-
limit:
|
|
8766
|
-
search:
|
|
8767
|
-
school:
|
|
8768
|
-
status:
|
|
9539
|
+
const validation = Joi38.object({
|
|
9540
|
+
page: Joi38.number().min(1).optional().allow("", null),
|
|
9541
|
+
limit: Joi38.number().min(1).optional().allow("", null),
|
|
9542
|
+
search: Joi38.string().optional().allow("", null),
|
|
9543
|
+
school: Joi38.string().hex().optional().allow("", null),
|
|
9544
|
+
status: Joi38.string().optional().allow("", null)
|
|
8769
9545
|
});
|
|
8770
9546
|
const { error } = validation.validate(query);
|
|
8771
9547
|
if (error) {
|
|
8772
|
-
next(new
|
|
9548
|
+
next(new BadRequestError48(error.message));
|
|
8773
9549
|
return;
|
|
8774
9550
|
}
|
|
8775
9551
|
const page = parseInt(req.query.page) ?? 1;
|
|
@@ -8803,12 +9579,12 @@ function useBuildingController() {
|
|
|
8803
9579
|
}
|
|
8804
9580
|
async function getById(req, res, next) {
|
|
8805
9581
|
const id = req.params.id;
|
|
8806
|
-
const validation =
|
|
8807
|
-
id:
|
|
9582
|
+
const validation = Joi38.object({
|
|
9583
|
+
id: Joi38.string().hex().required()
|
|
8808
9584
|
});
|
|
8809
9585
|
const { error } = validation.validate({ id });
|
|
8810
9586
|
if (error) {
|
|
8811
|
-
next(new
|
|
9587
|
+
next(new BadRequestError48(error.message));
|
|
8812
9588
|
return;
|
|
8813
9589
|
}
|
|
8814
9590
|
try {
|
|
@@ -8824,12 +9600,12 @@ function useBuildingController() {
|
|
|
8824
9600
|
}
|
|
8825
9601
|
async function deleteById(req, res, next) {
|
|
8826
9602
|
const id = req.params.id;
|
|
8827
|
-
const validation =
|
|
8828
|
-
id:
|
|
9603
|
+
const validation = Joi38.object({
|
|
9604
|
+
id: Joi38.string().hex().required()
|
|
8829
9605
|
});
|
|
8830
9606
|
const { error } = validation.validate({ id });
|
|
8831
9607
|
if (error) {
|
|
8832
|
-
next(new
|
|
9608
|
+
next(new BadRequestError48(error.message));
|
|
8833
9609
|
return;
|
|
8834
9610
|
}
|
|
8835
9611
|
try {
|
|
@@ -8850,11 +9626,11 @@ function useBuildingController() {
|
|
|
8850
9626
|
}
|
|
8851
9627
|
|
|
8852
9628
|
// src/resources/building/building-unit.service.ts
|
|
8853
|
-
import { useAtlas as
|
|
9629
|
+
import { useAtlas as useAtlas23 } from "@goweekdays/utils";
|
|
8854
9630
|
function useBuildingUnitService() {
|
|
8855
9631
|
const { add: _add } = useBuildingUnitRepo();
|
|
8856
9632
|
async function add(value) {
|
|
8857
|
-
const session =
|
|
9633
|
+
const session = useAtlas23.getClient()?.startSession();
|
|
8858
9634
|
if (!session) {
|
|
8859
9635
|
throw new Error("Unable to start session for building unit service.");
|
|
8860
9636
|
}
|
|
@@ -8881,8 +9657,8 @@ function useBuildingUnitService() {
|
|
|
8881
9657
|
}
|
|
8882
9658
|
|
|
8883
9659
|
// src/resources/building/building-unit.controller.ts
|
|
8884
|
-
import { BadRequestError as
|
|
8885
|
-
import
|
|
9660
|
+
import { BadRequestError as BadRequestError49 } from "@goweekdays/utils";
|
|
9661
|
+
import Joi39 from "joi";
|
|
8886
9662
|
function useBuildingUnitController() {
|
|
8887
9663
|
const {
|
|
8888
9664
|
getAll: _getAll,
|
|
@@ -8893,27 +9669,27 @@ function useBuildingUnitController() {
|
|
|
8893
9669
|
const { add: _add } = useBuildingUnitService();
|
|
8894
9670
|
async function add(req, res, next) {
|
|
8895
9671
|
const data = req.body;
|
|
8896
|
-
const validation =
|
|
8897
|
-
building:
|
|
8898
|
-
school:
|
|
8899
|
-
name:
|
|
8900
|
-
building:
|
|
8901
|
-
buildingName:
|
|
8902
|
-
level:
|
|
8903
|
-
category:
|
|
8904
|
-
type:
|
|
8905
|
-
seating_capacity:
|
|
8906
|
-
standing_capacity:
|
|
8907
|
-
description:
|
|
8908
|
-
unit_of_measurement:
|
|
8909
|
-
area:
|
|
8910
|
-
status:
|
|
9672
|
+
const validation = Joi39.object({
|
|
9673
|
+
building: Joi39.object({
|
|
9674
|
+
school: Joi39.string().hex().required(),
|
|
9675
|
+
name: Joi39.string().optional().allow("", null),
|
|
9676
|
+
building: Joi39.string().hex().required(),
|
|
9677
|
+
buildingName: Joi39.string().optional().allow("", null),
|
|
9678
|
+
level: Joi39.number().integer().min(1).required(),
|
|
9679
|
+
category: Joi39.string().required(),
|
|
9680
|
+
type: Joi39.string().required(),
|
|
9681
|
+
seating_capacity: Joi39.number().integer().min(0).required(),
|
|
9682
|
+
standing_capacity: Joi39.number().integer().min(0).required(),
|
|
9683
|
+
description: Joi39.string().optional().allow("", null),
|
|
9684
|
+
unit_of_measurement: Joi39.string().valid("sqm").required(),
|
|
9685
|
+
area: Joi39.number().positive().required(),
|
|
9686
|
+
status: Joi39.string().optional().allow("", null)
|
|
8911
9687
|
}),
|
|
8912
|
-
qty:
|
|
9688
|
+
qty: Joi39.number().integer().min(1).max(20).optional().default(1)
|
|
8913
9689
|
});
|
|
8914
9690
|
const { error } = validation.validate(data);
|
|
8915
9691
|
if (error) {
|
|
8916
|
-
next(new
|
|
9692
|
+
next(new BadRequestError49(error.message));
|
|
8917
9693
|
return;
|
|
8918
9694
|
}
|
|
8919
9695
|
try {
|
|
@@ -8929,13 +9705,13 @@ function useBuildingUnitController() {
|
|
|
8929
9705
|
async function updateById(req, res, next) {
|
|
8930
9706
|
const data = req.body;
|
|
8931
9707
|
const id = req.params.id ?? "";
|
|
8932
|
-
const validation =
|
|
8933
|
-
id:
|
|
9708
|
+
const validation = Joi39.object({
|
|
9709
|
+
id: Joi39.string().hex().required(),
|
|
8934
9710
|
value: schemaUpdateOptions
|
|
8935
9711
|
});
|
|
8936
9712
|
const { error } = validation.validate({ id, value: data });
|
|
8937
9713
|
if (error) {
|
|
8938
|
-
next(new
|
|
9714
|
+
next(new BadRequestError49(error.message));
|
|
8939
9715
|
return;
|
|
8940
9716
|
}
|
|
8941
9717
|
try {
|
|
@@ -8950,17 +9726,17 @@ function useBuildingUnitController() {
|
|
|
8950
9726
|
}
|
|
8951
9727
|
async function getAll(req, res, next) {
|
|
8952
9728
|
const query = req.query;
|
|
8953
|
-
const validation =
|
|
8954
|
-
page:
|
|
8955
|
-
limit:
|
|
8956
|
-
search:
|
|
8957
|
-
school:
|
|
8958
|
-
building:
|
|
8959
|
-
status:
|
|
9729
|
+
const validation = Joi39.object({
|
|
9730
|
+
page: Joi39.number().min(1).optional().allow("", null),
|
|
9731
|
+
limit: Joi39.number().min(1).optional().allow("", null),
|
|
9732
|
+
search: Joi39.string().optional().allow("", null),
|
|
9733
|
+
school: Joi39.string().hex().optional().allow("", null),
|
|
9734
|
+
building: Joi39.string().hex().optional().allow("", null),
|
|
9735
|
+
status: Joi39.string().optional().allow("", null)
|
|
8960
9736
|
});
|
|
8961
9737
|
const { error } = validation.validate(query);
|
|
8962
9738
|
if (error) {
|
|
8963
|
-
next(new
|
|
9739
|
+
next(new BadRequestError49(error.message));
|
|
8964
9740
|
return;
|
|
8965
9741
|
}
|
|
8966
9742
|
const page = parseInt(req.query.page) ?? 1;
|
|
@@ -8996,12 +9772,12 @@ function useBuildingUnitController() {
|
|
|
8996
9772
|
}
|
|
8997
9773
|
async function getById(req, res, next) {
|
|
8998
9774
|
const id = req.params.id;
|
|
8999
|
-
const validation =
|
|
9000
|
-
id:
|
|
9775
|
+
const validation = Joi39.object({
|
|
9776
|
+
id: Joi39.string().hex().required()
|
|
9001
9777
|
});
|
|
9002
9778
|
const { error } = validation.validate({ id });
|
|
9003
9779
|
if (error) {
|
|
9004
|
-
next(new
|
|
9780
|
+
next(new BadRequestError49(error.message));
|
|
9005
9781
|
return;
|
|
9006
9782
|
}
|
|
9007
9783
|
try {
|
|
@@ -9017,12 +9793,12 @@ function useBuildingUnitController() {
|
|
|
9017
9793
|
}
|
|
9018
9794
|
async function deleteById(req, res, next) {
|
|
9019
9795
|
const id = req.params.id;
|
|
9020
|
-
const validation =
|
|
9021
|
-
id:
|
|
9796
|
+
const validation = Joi39.object({
|
|
9797
|
+
id: Joi39.string().hex().required()
|
|
9022
9798
|
});
|
|
9023
9799
|
const { error } = validation.validate({ id });
|
|
9024
9800
|
if (error) {
|
|
9025
|
-
next(new
|
|
9801
|
+
next(new BadRequestError49(error.message));
|
|
9026
9802
|
return;
|
|
9027
9803
|
}
|
|
9028
9804
|
try {
|
|
@@ -9043,14 +9819,14 @@ function useBuildingUnitController() {
|
|
|
9043
9819
|
}
|
|
9044
9820
|
|
|
9045
9821
|
// src/resources/counter/counter.model.ts
|
|
9046
|
-
import { BadRequestError as
|
|
9047
|
-
import { ObjectId as
|
|
9822
|
+
import { BadRequestError as BadRequestError50 } from "@goweekdays/utils";
|
|
9823
|
+
import { ObjectId as ObjectId25 } from "mongodb";
|
|
9048
9824
|
import { z } from "zod";
|
|
9049
9825
|
var TCounter = z.object({
|
|
9050
9826
|
_id: z.union([
|
|
9051
9827
|
z.string().length(24, "Invalid ObjectId hex string"),
|
|
9052
|
-
z.instanceof(
|
|
9053
|
-
]).transform((val) => typeof val === "string" ? new
|
|
9828
|
+
z.instanceof(ObjectId25)
|
|
9829
|
+
]).transform((val) => typeof val === "string" ? new ObjectId25(val) : val).optional(),
|
|
9054
9830
|
count: z.number().int().min(0).default(0),
|
|
9055
9831
|
type: z.string(),
|
|
9056
9832
|
createdAt: z.date().optional().default(() => /* @__PURE__ */ new Date()),
|
|
@@ -9063,7 +9839,7 @@ function useCounterModel(db) {
|
|
|
9063
9839
|
try {
|
|
9064
9840
|
return TCounter.parse(value);
|
|
9065
9841
|
} catch (error) {
|
|
9066
|
-
throw new
|
|
9842
|
+
throw new BadRequestError50(error.issues[0].message);
|
|
9067
9843
|
}
|
|
9068
9844
|
}
|
|
9069
9845
|
function validateCounter(data) {
|
|
@@ -9077,23 +9853,23 @@ function useCounterModel(db) {
|
|
|
9077
9853
|
}
|
|
9078
9854
|
|
|
9079
9855
|
// src/resources/counter/counter.repository.ts
|
|
9080
|
-
import { useAtlas as
|
|
9856
|
+
import { useAtlas as useAtlas24, useCache as useCache18, makeCacheKey as makeCacheKey17, logger as logger27 } from "@goweekdays/utils";
|
|
9081
9857
|
function useCounterRepo() {
|
|
9082
|
-
const db =
|
|
9858
|
+
const db = useAtlas24.getDb();
|
|
9083
9859
|
if (!db) {
|
|
9084
9860
|
throw new Error("Unable to connect to server.");
|
|
9085
9861
|
}
|
|
9086
9862
|
const namespace_collection = "counters";
|
|
9087
9863
|
const { collection, createCounter } = useCounterModel(db);
|
|
9088
|
-
const { getCache, setCache, delNamespace } =
|
|
9864
|
+
const { getCache, setCache, delNamespace } = useCache18(namespace_collection);
|
|
9089
9865
|
function delCachedData() {
|
|
9090
9866
|
delNamespace().then(() => {
|
|
9091
|
-
|
|
9867
|
+
logger27.log({
|
|
9092
9868
|
level: "info",
|
|
9093
9869
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
9094
9870
|
});
|
|
9095
9871
|
}).catch((err) => {
|
|
9096
|
-
|
|
9872
|
+
logger27.log({
|
|
9097
9873
|
level: "error",
|
|
9098
9874
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
9099
9875
|
});
|
|
@@ -9137,11 +9913,11 @@ function useCounterRepo() {
|
|
|
9137
9913
|
}
|
|
9138
9914
|
}
|
|
9139
9915
|
async function getByType(type) {
|
|
9140
|
-
const cacheKey =
|
|
9916
|
+
const cacheKey = makeCacheKey17(namespace_collection, { type });
|
|
9141
9917
|
try {
|
|
9142
9918
|
const cached = await getCache(cacheKey);
|
|
9143
9919
|
if (cached) {
|
|
9144
|
-
|
|
9920
|
+
logger27.log({
|
|
9145
9921
|
level: "info",
|
|
9146
9922
|
message: `Cache hit for getByType counter: ${cacheKey}`
|
|
9147
9923
|
});
|
|
@@ -9150,12 +9926,12 @@ function useCounterRepo() {
|
|
|
9150
9926
|
const data = await collection.findOne({ type });
|
|
9151
9927
|
if (data) {
|
|
9152
9928
|
setCache(cacheKey, data, 300).then(() => {
|
|
9153
|
-
|
|
9929
|
+
logger27.log({
|
|
9154
9930
|
level: "info",
|
|
9155
9931
|
message: `Cache set for counter by type: ${cacheKey}`
|
|
9156
9932
|
});
|
|
9157
9933
|
}).catch((err) => {
|
|
9158
|
-
|
|
9934
|
+
logger27.log({
|
|
9159
9935
|
level: "error",
|
|
9160
9936
|
message: `Failed to set cache for counter by type: ${err.message}`
|
|
9161
9937
|
});
|
|
@@ -9175,7 +9951,7 @@ function useCounterRepo() {
|
|
|
9175
9951
|
}
|
|
9176
9952
|
|
|
9177
9953
|
// src/resources/file/file.service.ts
|
|
9178
|
-
import { logger as
|
|
9954
|
+
import { logger as logger28, useS3 as useS32, useAtlas as useAtlas25 } from "@goweekdays/utils";
|
|
9179
9955
|
import cron from "node-cron";
|
|
9180
9956
|
import * as fs from "fs";
|
|
9181
9957
|
function useFileService() {
|
|
@@ -9193,7 +9969,7 @@ function useFileService() {
|
|
|
9193
9969
|
forcePathStyle: true
|
|
9194
9970
|
});
|
|
9195
9971
|
async function createFile(value) {
|
|
9196
|
-
const session =
|
|
9972
|
+
const session = useAtlas25.getClient()?.startSession();
|
|
9197
9973
|
session?.startTransaction();
|
|
9198
9974
|
const file = {
|
|
9199
9975
|
name: value.originalname,
|
|
@@ -9227,7 +10003,7 @@ function useFileService() {
|
|
|
9227
10003
|
}
|
|
9228
10004
|
}
|
|
9229
10005
|
async function deleteFile(id) {
|
|
9230
|
-
const session =
|
|
10006
|
+
const session = useAtlas25.getClient()?.startSession();
|
|
9231
10007
|
session?.startTransaction();
|
|
9232
10008
|
try {
|
|
9233
10009
|
await deleteFileById(id, session);
|
|
@@ -9248,12 +10024,12 @@ function useFileService() {
|
|
|
9248
10024
|
const file = files[index];
|
|
9249
10025
|
try {
|
|
9250
10026
|
await deleteFile(file._id.toString());
|
|
9251
|
-
await
|
|
10027
|
+
await logger28.log({
|
|
9252
10028
|
level: "info",
|
|
9253
10029
|
message: "Successfully deleted draft files."
|
|
9254
10030
|
});
|
|
9255
10031
|
} catch (error) {
|
|
9256
|
-
|
|
10032
|
+
logger28.log({
|
|
9257
10033
|
level: "info",
|
|
9258
10034
|
message: "Successfully deleted draft files."
|
|
9259
10035
|
});
|
|
@@ -9271,11 +10047,11 @@ function useFileService() {
|
|
|
9271
10047
|
|
|
9272
10048
|
// src/resources/file/file.controller.ts
|
|
9273
10049
|
import {
|
|
9274
|
-
AppError as
|
|
9275
|
-
BadRequestError as
|
|
9276
|
-
InternalServerError as
|
|
10050
|
+
AppError as AppError22,
|
|
10051
|
+
BadRequestError as BadRequestError51,
|
|
10052
|
+
InternalServerError as InternalServerError26
|
|
9277
10053
|
} from "@goweekdays/utils";
|
|
9278
|
-
import
|
|
10054
|
+
import Joi40 from "joi";
|
|
9279
10055
|
function useFileController() {
|
|
9280
10056
|
const { createFile, deleteFile: _deleteFile } = useFileService();
|
|
9281
10057
|
async function upload(req, res, next) {
|
|
@@ -9288,29 +10064,29 @@ function useFileController() {
|
|
|
9288
10064
|
res.json({ message: "Successfully uploaded file", id });
|
|
9289
10065
|
return;
|
|
9290
10066
|
} catch (error) {
|
|
9291
|
-
if (error instanceof
|
|
10067
|
+
if (error instanceof AppError22) {
|
|
9292
10068
|
next(error);
|
|
9293
10069
|
} else {
|
|
9294
|
-
next(new
|
|
10070
|
+
next(new InternalServerError26(error));
|
|
9295
10071
|
}
|
|
9296
10072
|
}
|
|
9297
10073
|
}
|
|
9298
10074
|
async function deleteFile(req, res, next) {
|
|
9299
10075
|
const id = req.params.id;
|
|
9300
|
-
const validation =
|
|
10076
|
+
const validation = Joi40.string().required();
|
|
9301
10077
|
const { error } = validation.validate(id);
|
|
9302
10078
|
if (error) {
|
|
9303
|
-
next(new
|
|
10079
|
+
next(new BadRequestError51(error.message));
|
|
9304
10080
|
}
|
|
9305
10081
|
try {
|
|
9306
10082
|
const message = await _deleteFile(id);
|
|
9307
10083
|
res.json({ message });
|
|
9308
10084
|
return;
|
|
9309
10085
|
} catch (error2) {
|
|
9310
|
-
if (error2 instanceof
|
|
10086
|
+
if (error2 instanceof AppError22) {
|
|
9311
10087
|
next(error2);
|
|
9312
10088
|
} else {
|
|
9313
|
-
next(new
|
|
10089
|
+
next(new InternalServerError26(error2));
|
|
9314
10090
|
}
|
|
9315
10091
|
}
|
|
9316
10092
|
}
|
|
@@ -9321,35 +10097,35 @@ function useFileController() {
|
|
|
9321
10097
|
}
|
|
9322
10098
|
|
|
9323
10099
|
// src/resources/promo/promo.model.ts
|
|
9324
|
-
import
|
|
9325
|
-
var schemaPromo =
|
|
9326
|
-
code:
|
|
9327
|
-
description:
|
|
9328
|
-
type:
|
|
9329
|
-
flatRate:
|
|
10100
|
+
import Joi41 from "joi";
|
|
10101
|
+
var schemaPromo = Joi41.object({
|
|
10102
|
+
code: Joi41.string().min(3).max(50).required(),
|
|
10103
|
+
description: Joi41.string().max(255).optional().allow("", null),
|
|
10104
|
+
type: Joi41.string().valid("flat", "fixed", "tiered").required(),
|
|
10105
|
+
flatRate: Joi41.number().positive().when("type", {
|
|
9330
10106
|
is: "flat",
|
|
9331
|
-
then:
|
|
9332
|
-
otherwise:
|
|
10107
|
+
then: Joi41.required(),
|
|
10108
|
+
otherwise: Joi41.forbidden()
|
|
9333
10109
|
}).optional().allow(null, 0),
|
|
9334
|
-
fixedRate:
|
|
10110
|
+
fixedRate: Joi41.number().positive().when("type", {
|
|
9335
10111
|
is: "fixed",
|
|
9336
|
-
then:
|
|
9337
|
-
otherwise:
|
|
10112
|
+
then: Joi41.required(),
|
|
10113
|
+
otherwise: Joi41.forbidden()
|
|
9338
10114
|
}).optional().allow(null, 0),
|
|
9339
|
-
tiers:
|
|
9340
|
-
|
|
9341
|
-
minSeats:
|
|
9342
|
-
maxSeats:
|
|
9343
|
-
rate:
|
|
10115
|
+
tiers: Joi41.array().items(
|
|
10116
|
+
Joi41.object({
|
|
10117
|
+
minSeats: Joi41.number().integer().min(1).required(),
|
|
10118
|
+
maxSeats: Joi41.number().integer().min(Joi41.ref("minSeats")).required(),
|
|
10119
|
+
rate: Joi41.number().positive().required()
|
|
9344
10120
|
})
|
|
9345
10121
|
).when("type", {
|
|
9346
10122
|
is: "tiered",
|
|
9347
|
-
then:
|
|
9348
|
-
otherwise:
|
|
10123
|
+
then: Joi41.required(),
|
|
10124
|
+
otherwise: Joi41.forbidden()
|
|
9349
10125
|
}),
|
|
9350
|
-
currency:
|
|
9351
|
-
startDate:
|
|
9352
|
-
endDate:
|
|
10126
|
+
currency: Joi41.string().length(3).required(),
|
|
10127
|
+
startDate: Joi41.date().required(),
|
|
10128
|
+
endDate: Joi41.date().greater(Joi41.ref("startDate")).optional().allow(null, "")
|
|
9353
10129
|
});
|
|
9354
10130
|
function modelPromo(data) {
|
|
9355
10131
|
const { error } = schemaPromo.validate(data);
|
|
@@ -9378,33 +10154,33 @@ function modelPromo(data) {
|
|
|
9378
10154
|
|
|
9379
10155
|
// src/resources/promo/promo.repository.ts
|
|
9380
10156
|
import {
|
|
9381
|
-
AppError as
|
|
9382
|
-
BadRequestError as
|
|
9383
|
-
InternalServerError as
|
|
9384
|
-
logger as
|
|
9385
|
-
makeCacheKey as
|
|
9386
|
-
paginate as
|
|
9387
|
-
useAtlas as
|
|
9388
|
-
useCache as
|
|
10157
|
+
AppError as AppError23,
|
|
10158
|
+
BadRequestError as BadRequestError52,
|
|
10159
|
+
InternalServerError as InternalServerError27,
|
|
10160
|
+
logger as logger29,
|
|
10161
|
+
makeCacheKey as makeCacheKey18,
|
|
10162
|
+
paginate as paginate15,
|
|
10163
|
+
useAtlas as useAtlas26,
|
|
10164
|
+
useCache as useCache19
|
|
9389
10165
|
} from "@goweekdays/utils";
|
|
9390
|
-
import
|
|
9391
|
-
import { ObjectId as
|
|
10166
|
+
import Joi42 from "joi";
|
|
10167
|
+
import { ObjectId as ObjectId26 } from "mongodb";
|
|
9392
10168
|
function usePromoRepo() {
|
|
9393
|
-
const db =
|
|
10169
|
+
const db = useAtlas26.getDb();
|
|
9394
10170
|
if (!db) {
|
|
9395
|
-
throw new
|
|
10171
|
+
throw new InternalServerError27("Unable to connect to server.");
|
|
9396
10172
|
}
|
|
9397
10173
|
const namespace_collection = "users";
|
|
9398
10174
|
const collection = db.collection(namespace_collection);
|
|
9399
|
-
const { getCache, setCache, delNamespace } =
|
|
10175
|
+
const { getCache, setCache, delNamespace } = useCache19(namespace_collection);
|
|
9400
10176
|
function delCachedData() {
|
|
9401
10177
|
delNamespace().then(() => {
|
|
9402
|
-
|
|
10178
|
+
logger29.log({
|
|
9403
10179
|
level: "info",
|
|
9404
10180
|
message: `Cache namespace cleared for ${namespace_collection}`
|
|
9405
10181
|
});
|
|
9406
10182
|
}).catch((err) => {
|
|
9407
|
-
|
|
10183
|
+
logger29.log({
|
|
9408
10184
|
level: "error",
|
|
9409
10185
|
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
9410
10186
|
});
|
|
@@ -9436,7 +10212,7 @@ function usePromoRepo() {
|
|
|
9436
10212
|
delCachedData();
|
|
9437
10213
|
return "Successfully added promo.";
|
|
9438
10214
|
} catch (error) {
|
|
9439
|
-
throw new
|
|
10215
|
+
throw new InternalServerError27("Failed to add promo.");
|
|
9440
10216
|
}
|
|
9441
10217
|
}
|
|
9442
10218
|
async function getAll({
|
|
@@ -9457,7 +10233,7 @@ function usePromoRepo() {
|
|
|
9457
10233
|
if (search) {
|
|
9458
10234
|
query.$text = { $search: search };
|
|
9459
10235
|
}
|
|
9460
|
-
const cacheKey =
|
|
10236
|
+
const cacheKey = makeCacheKey18(namespace_collection, cacheKeyOptions);
|
|
9461
10237
|
try {
|
|
9462
10238
|
const cachedData = await getCache(cacheKey);
|
|
9463
10239
|
if (cachedData) {
|
|
@@ -9469,30 +10245,30 @@ function usePromoRepo() {
|
|
|
9469
10245
|
{ $limit: limit }
|
|
9470
10246
|
]).toArray();
|
|
9471
10247
|
const length = await collection.countDocuments(query);
|
|
9472
|
-
const data =
|
|
10248
|
+
const data = paginate15(items, page, limit, length);
|
|
9473
10249
|
setCache(cacheKey, data).then(() => {
|
|
9474
|
-
|
|
10250
|
+
logger29.log({
|
|
9475
10251
|
level: "info",
|
|
9476
10252
|
message: `Cache set for getAll promo: ${cacheKey}`
|
|
9477
10253
|
});
|
|
9478
10254
|
}).catch((err) => {
|
|
9479
|
-
|
|
10255
|
+
logger29.log({
|
|
9480
10256
|
level: "error",
|
|
9481
10257
|
message: `Failed to set cache for getAll promo: ${err.message}`
|
|
9482
10258
|
});
|
|
9483
10259
|
});
|
|
9484
10260
|
return data;
|
|
9485
10261
|
} catch (error) {
|
|
9486
|
-
throw new
|
|
10262
|
+
throw new InternalServerError27("Failed to get promos.");
|
|
9487
10263
|
}
|
|
9488
10264
|
}
|
|
9489
10265
|
async function getByCode(code) {
|
|
9490
|
-
const { error } =
|
|
10266
|
+
const { error } = Joi42.string().min(3).max(50).required().validate(code);
|
|
9491
10267
|
if (error) {
|
|
9492
10268
|
throw new Error(`Invalid promo code: ${error.message}`);
|
|
9493
10269
|
}
|
|
9494
10270
|
try {
|
|
9495
|
-
const cacheKey =
|
|
10271
|
+
const cacheKey = makeCacheKey18(namespace_collection, {
|
|
9496
10272
|
code,
|
|
9497
10273
|
tag: "getByCode"
|
|
9498
10274
|
});
|
|
@@ -9505,33 +10281,33 @@ function usePromoRepo() {
|
|
|
9505
10281
|
status: { $ne: "deleted" }
|
|
9506
10282
|
});
|
|
9507
10283
|
setCache(cacheKey, data).then(() => {
|
|
9508
|
-
|
|
10284
|
+
logger29.log({
|
|
9509
10285
|
level: "info",
|
|
9510
10286
|
message: `Cache set for getByCode promo: ${cacheKey}`
|
|
9511
10287
|
});
|
|
9512
10288
|
}).catch((err) => {
|
|
9513
|
-
|
|
10289
|
+
logger29.log({
|
|
9514
10290
|
level: "error",
|
|
9515
10291
|
message: `Failed to set cache for getByCode promo: ${err.message}`
|
|
9516
10292
|
});
|
|
9517
10293
|
});
|
|
9518
10294
|
return data;
|
|
9519
10295
|
} catch (error2) {
|
|
9520
|
-
throw new
|
|
10296
|
+
throw new InternalServerError27("Failed to get promo.");
|
|
9521
10297
|
}
|
|
9522
10298
|
}
|
|
9523
10299
|
async function getById(_id) {
|
|
9524
|
-
const { error } =
|
|
10300
|
+
const { error } = Joi42.string().hex().length(24).required().validate(_id);
|
|
9525
10301
|
if (error) {
|
|
9526
10302
|
throw new Error(`Invalid promo ID: ${error.message}`);
|
|
9527
10303
|
}
|
|
9528
10304
|
try {
|
|
9529
|
-
_id = new
|
|
10305
|
+
_id = new ObjectId26(_id);
|
|
9530
10306
|
} catch (error2) {
|
|
9531
|
-
throw new
|
|
10307
|
+
throw new BadRequestError52("Invalid promo ID.");
|
|
9532
10308
|
}
|
|
9533
10309
|
try {
|
|
9534
|
-
const cacheKey =
|
|
10310
|
+
const cacheKey = makeCacheKey18(namespace_collection, {
|
|
9535
10311
|
_id: String(_id),
|
|
9536
10312
|
tag: "getById"
|
|
9537
10313
|
});
|
|
@@ -9544,30 +10320,30 @@ function usePromoRepo() {
|
|
|
9544
10320
|
status: { $ne: "deleted" }
|
|
9545
10321
|
});
|
|
9546
10322
|
setCache(cacheKey, data).then(() => {
|
|
9547
|
-
|
|
10323
|
+
logger29.log({
|
|
9548
10324
|
level: "info",
|
|
9549
10325
|
message: `Cache set for getById promo: ${cacheKey}`
|
|
9550
10326
|
});
|
|
9551
10327
|
}).catch((err) => {
|
|
9552
|
-
|
|
10328
|
+
logger29.log({
|
|
9553
10329
|
level: "error",
|
|
9554
10330
|
message: `Failed to set cache for getById promo: ${err.message}`
|
|
9555
10331
|
});
|
|
9556
10332
|
});
|
|
9557
10333
|
return data;
|
|
9558
10334
|
} catch (error2) {
|
|
9559
|
-
throw new
|
|
10335
|
+
throw new InternalServerError27("Failed to get promo.");
|
|
9560
10336
|
}
|
|
9561
10337
|
}
|
|
9562
10338
|
async function deleteById(_id) {
|
|
9563
|
-
const { error } =
|
|
10339
|
+
const { error } = Joi42.string().hex().length(24).required().validate(_id);
|
|
9564
10340
|
if (error) {
|
|
9565
10341
|
throw new Error(`Invalid promo ID: ${error.message}`);
|
|
9566
10342
|
}
|
|
9567
10343
|
try {
|
|
9568
|
-
_id = new
|
|
10344
|
+
_id = new ObjectId26(_id);
|
|
9569
10345
|
} catch (error2) {
|
|
9570
|
-
throw new
|
|
10346
|
+
throw new BadRequestError52("Invalid promo ID.");
|
|
9571
10347
|
}
|
|
9572
10348
|
try {
|
|
9573
10349
|
const result = await collection.updateOne(
|
|
@@ -9575,15 +10351,15 @@ function usePromoRepo() {
|
|
|
9575
10351
|
{ $set: { status: "deleted" } }
|
|
9576
10352
|
);
|
|
9577
10353
|
if (result.modifiedCount === 0) {
|
|
9578
|
-
throw new
|
|
10354
|
+
throw new InternalServerError27("Failed to delete promo.");
|
|
9579
10355
|
}
|
|
9580
10356
|
delCachedData();
|
|
9581
10357
|
return "Successfully deleted promo.";
|
|
9582
10358
|
} catch (error2) {
|
|
9583
|
-
if (error2 instanceof
|
|
10359
|
+
if (error2 instanceof AppError23) {
|
|
9584
10360
|
throw error2;
|
|
9585
10361
|
}
|
|
9586
|
-
throw new
|
|
10362
|
+
throw new InternalServerError27("Failed to delete promo.");
|
|
9587
10363
|
}
|
|
9588
10364
|
}
|
|
9589
10365
|
return {
|
|
@@ -9597,7 +10373,7 @@ function usePromoRepo() {
|
|
|
9597
10373
|
}
|
|
9598
10374
|
|
|
9599
10375
|
// src/resources/utils/github.service.ts
|
|
9600
|
-
import { AppError as
|
|
10376
|
+
import { AppError as AppError24, BadRequestError as BadRequestError53 } from "@goweekdays/utils";
|
|
9601
10377
|
import { Octokit } from "@octokit/rest";
|
|
9602
10378
|
import _sodium from "libsodium-wrappers";
|
|
9603
10379
|
function useGitHubService() {
|
|
@@ -9611,23 +10387,23 @@ function useGitHubService() {
|
|
|
9611
10387
|
try {
|
|
9612
10388
|
const { data: repoData } = await octokit.repos.get({ owner, repo });
|
|
9613
10389
|
if (!repoData.permissions?.admin) {
|
|
9614
|
-
throw new
|
|
10390
|
+
throw new BadRequestError53(
|
|
9615
10391
|
"You do not have admin access to this repository."
|
|
9616
10392
|
);
|
|
9617
10393
|
}
|
|
9618
10394
|
} catch (error) {
|
|
9619
10395
|
if (error.status === 404) {
|
|
9620
|
-
throw new
|
|
10396
|
+
throw new BadRequestError53(
|
|
9621
10397
|
"Repository not found or you don't have access to it."
|
|
9622
10398
|
);
|
|
9623
10399
|
} else if (error.status === 401) {
|
|
9624
|
-
throw new
|
|
10400
|
+
throw new BadRequestError53(
|
|
9625
10401
|
"Invalid GitHub token or insufficient permissions."
|
|
9626
10402
|
);
|
|
9627
10403
|
} else if (error.message.includes("admin access")) {
|
|
9628
10404
|
throw error;
|
|
9629
10405
|
} else {
|
|
9630
|
-
throw new
|
|
10406
|
+
throw new BadRequestError53(
|
|
9631
10407
|
`Failed to check repository permissions: ${error.message}`
|
|
9632
10408
|
);
|
|
9633
10409
|
}
|
|
@@ -9676,7 +10452,7 @@ function useGitHubService() {
|
|
|
9676
10452
|
key_id: publicKeyRes.key_id
|
|
9677
10453
|
});
|
|
9678
10454
|
} catch (encryptionError) {
|
|
9679
|
-
throw new
|
|
10455
|
+
throw new BadRequestError53(
|
|
9680
10456
|
`Failed to encrypt secret '${key}': ${encryptionError.message}`
|
|
9681
10457
|
);
|
|
9682
10458
|
}
|
|
@@ -9706,22 +10482,22 @@ function useGitHubService() {
|
|
|
9706
10482
|
}
|
|
9707
10483
|
return `Successfully set ${lines.length} ${type} variables/secrets in environment '${environment}'`;
|
|
9708
10484
|
} catch (error) {
|
|
9709
|
-
if (error instanceof
|
|
10485
|
+
if (error instanceof AppError24)
|
|
9710
10486
|
throw error;
|
|
9711
10487
|
if (error.status === 422) {
|
|
9712
|
-
throw new
|
|
10488
|
+
throw new BadRequestError53(
|
|
9713
10489
|
`GitHub API validation error: ${error.message}`
|
|
9714
10490
|
);
|
|
9715
10491
|
} else if (error.status === 404) {
|
|
9716
|
-
throw new
|
|
10492
|
+
throw new BadRequestError53("Environment or repository not found.");
|
|
9717
10493
|
} else if (error.status === 403) {
|
|
9718
|
-
throw new
|
|
10494
|
+
throw new BadRequestError53(
|
|
9719
10495
|
"Forbidden: Insufficient permissions or rate limit exceeded."
|
|
9720
10496
|
);
|
|
9721
10497
|
} else if (error.message.includes("admin access") || error.message.includes("permissions")) {
|
|
9722
10498
|
throw error;
|
|
9723
10499
|
} else {
|
|
9724
|
-
throw new
|
|
10500
|
+
throw new BadRequestError53(
|
|
9725
10501
|
`Failed to set GitHub variables: ${error.message}`
|
|
9726
10502
|
);
|
|
9727
10503
|
}
|
|
@@ -9733,12 +10509,12 @@ function useGitHubService() {
|
|
|
9733
10509
|
}
|
|
9734
10510
|
|
|
9735
10511
|
// src/resources/utils/util.controller.ts
|
|
9736
|
-
import
|
|
10512
|
+
import Joi43 from "joi";
|
|
9737
10513
|
import {
|
|
9738
|
-
AppError as
|
|
9739
|
-
BadRequestError as
|
|
9740
|
-
InternalServerError as
|
|
9741
|
-
logger as
|
|
10514
|
+
AppError as AppError25,
|
|
10515
|
+
BadRequestError as BadRequestError54,
|
|
10516
|
+
InternalServerError as InternalServerError28,
|
|
10517
|
+
logger as logger30
|
|
9742
10518
|
} from "@goweekdays/utils";
|
|
9743
10519
|
function useUtilController() {
|
|
9744
10520
|
async function healthCheck(req, res, next) {
|
|
@@ -9755,32 +10531,32 @@ function useUtilController() {
|
|
|
9755
10531
|
}
|
|
9756
10532
|
});
|
|
9757
10533
|
} catch (error) {
|
|
9758
|
-
|
|
9759
|
-
next(new
|
|
10534
|
+
logger30.error("Health check failed", { error: error.message });
|
|
10535
|
+
next(new InternalServerError28("Health check failed"));
|
|
9760
10536
|
}
|
|
9761
10537
|
}
|
|
9762
10538
|
async function setGitHubVariables(req, res, next) {
|
|
9763
10539
|
try {
|
|
9764
10540
|
const { githubToken, repoUrl, environment, type, keyValues } = req.body;
|
|
9765
|
-
const validation =
|
|
9766
|
-
githubToken:
|
|
10541
|
+
const validation = Joi43.object({
|
|
10542
|
+
githubToken: Joi43.string().required().messages({
|
|
9767
10543
|
"string.empty": "GitHub token is required",
|
|
9768
10544
|
"any.required": "GitHub token is required"
|
|
9769
10545
|
}),
|
|
9770
|
-
repoUrl:
|
|
10546
|
+
repoUrl: Joi43.string().uri().required().messages({
|
|
9771
10547
|
"string.empty": "Repository URL is required",
|
|
9772
10548
|
"string.uri": "Repository URL must be a valid URL",
|
|
9773
10549
|
"any.required": "Repository URL is required"
|
|
9774
10550
|
}),
|
|
9775
|
-
environment:
|
|
10551
|
+
environment: Joi43.string().required().messages({
|
|
9776
10552
|
"string.empty": "Environment name is required",
|
|
9777
10553
|
"any.required": "Environment name is required"
|
|
9778
10554
|
}),
|
|
9779
|
-
type:
|
|
10555
|
+
type: Joi43.string().valid("env", "secret").required().messages({
|
|
9780
10556
|
"any.only": 'Type must be either "env" or "secret"',
|
|
9781
10557
|
"any.required": "Type is required"
|
|
9782
10558
|
}),
|
|
9783
|
-
keyValues:
|
|
10559
|
+
keyValues: Joi43.string().required().messages({
|
|
9784
10560
|
"string.empty": "Key-value pairs are required",
|
|
9785
10561
|
"any.required": "Key-value pairs are required"
|
|
9786
10562
|
})
|
|
@@ -9793,13 +10569,13 @@ function useUtilController() {
|
|
|
9793
10569
|
keyValues
|
|
9794
10570
|
});
|
|
9795
10571
|
if (error) {
|
|
9796
|
-
next(new
|
|
10572
|
+
next(new BadRequestError54(error.message));
|
|
9797
10573
|
return;
|
|
9798
10574
|
}
|
|
9799
10575
|
const repoUrlPattern = /github\.com[:\/]([^\/]+)\/(.+)\.git$/;
|
|
9800
10576
|
if (!repoUrlPattern.test(repoUrl)) {
|
|
9801
10577
|
next(
|
|
9802
|
-
new
|
|
10578
|
+
new BadRequestError54(
|
|
9803
10579
|
"Invalid GitHub repository URL format. Expected format: https://github.com/owner/repo.git"
|
|
9804
10580
|
)
|
|
9805
10581
|
);
|
|
@@ -9811,7 +10587,7 @@ function useUtilController() {
|
|
|
9811
10587
|
);
|
|
9812
10588
|
if (invalidLines.length > 0) {
|
|
9813
10589
|
next(
|
|
9814
|
-
new
|
|
10590
|
+
new BadRequestError54(
|
|
9815
10591
|
"Invalid key-value format. Each pair should be in format: KEY=value. Pairs should be separated by semicolons."
|
|
9816
10592
|
)
|
|
9817
10593
|
);
|
|
@@ -9825,7 +10601,7 @@ function useUtilController() {
|
|
|
9825
10601
|
type,
|
|
9826
10602
|
keyValues
|
|
9827
10603
|
});
|
|
9828
|
-
|
|
10604
|
+
logger30.info(`GitHub variables set successfully`, {
|
|
9829
10605
|
repoUrl,
|
|
9830
10606
|
environment,
|
|
9831
10607
|
type,
|
|
@@ -9836,319 +10612,311 @@ function useUtilController() {
|
|
|
9836
10612
|
message: result,
|
|
9837
10613
|
data: {
|
|
9838
10614
|
repoUrl,
|
|
9839
|
-
environment,
|
|
9840
|
-
type,
|
|
9841
|
-
variablesSet: lines.length
|
|
9842
|
-
}
|
|
9843
|
-
});
|
|
9844
|
-
} catch (error) {
|
|
9845
|
-
logger28.error("Failed to set GitHub variables", {
|
|
9846
|
-
error: error.message,
|
|
9847
|
-
stack: error.stack
|
|
9848
|
-
});
|
|
9849
|
-
if (error instanceof AppError23) {
|
|
9850
|
-
next(error);
|
|
9851
|
-
} else {
|
|
9852
|
-
next(
|
|
9853
|
-
new InternalServerError26(
|
|
9854
|
-
`Failed to set GitHub variables: ${error.message}`
|
|
9855
|
-
)
|
|
9856
|
-
);
|
|
9857
|
-
}
|
|
9858
|
-
}
|
|
9859
|
-
}
|
|
9860
|
-
const { verifySignature } = usePaypalService();
|
|
9861
|
-
async function paypalWebhook(req, res, next) {
|
|
9862
|
-
try {
|
|
9863
|
-
const headers = req.headers;
|
|
9864
|
-
const event = req.body;
|
|
9865
|
-
const data = JSON.parse(event);
|
|
9866
|
-
console.log(`headers`, headers);
|
|
9867
|
-
console.log(`parsed json`, JSON.stringify(data, null, 2));
|
|
9868
|
-
console.log(`raw event: ${event}`);
|
|
9869
|
-
const isSignatureValid = await verifySignature(
|
|
9870
|
-
event,
|
|
9871
|
-
headers,
|
|
9872
|
-
PAYPAL_WEBHOOK_ID
|
|
9873
|
-
);
|
|
9874
|
-
if (isSignatureValid) {
|
|
9875
|
-
console.log("Signature is valid.");
|
|
9876
|
-
console.log(`Received event`, JSON.stringify(data, null, 2));
|
|
9877
|
-
} else {
|
|
9878
|
-
console.log(
|
|
9879
|
-
`Signature is not valid for ${data?.id} ${headers?.["correlation-id"]}`
|
|
9880
|
-
);
|
|
9881
|
-
}
|
|
9882
|
-
res.sendStatus(200);
|
|
9883
|
-
} catch (error) {
|
|
9884
|
-
logger28.log({
|
|
9885
|
-
level: "error",
|
|
9886
|
-
message: `${error}`
|
|
9887
|
-
});
|
|
9888
|
-
}
|
|
9889
|
-
}
|
|
9890
|
-
return {
|
|
9891
|
-
healthCheck,
|
|
9892
|
-
setGitHubVariables,
|
|
9893
|
-
paypalWebhook
|
|
9894
|
-
};
|
|
9895
|
-
}
|
|
9896
|
-
|
|
9897
|
-
// src/resources/utils/transaction.schema.ts
|
|
9898
|
-
import Joi38 from "joi";
|
|
9899
|
-
var transactionSchema = Joi38.object({
|
|
9900
|
-
_id: Joi38.string().hex().optional().allow("", null),
|
|
9901
|
-
payment: Joi38.string().required(),
|
|
9902
|
-
user: Joi38.string().hex().optional().allow("", null),
|
|
9903
|
-
org: Joi38.string().hex().optional().allow("", null),
|
|
9904
|
-
type: Joi38.string().required(),
|
|
9905
|
-
amount: Joi38.number().positive().min(0).required(),
|
|
9906
|
-
currency: Joi38.string().required(),
|
|
9907
|
-
description: Joi38.string().optional().allow("", null),
|
|
9908
|
-
metadata: Joi38.object({
|
|
9909
|
-
subscriptionId: Joi38.string().hex().optional().allow("", null),
|
|
9910
|
-
cycle: Joi38.number().optional().allow("", null),
|
|
9911
|
-
seats: Joi38.number().optional().allow("", null),
|
|
9912
|
-
promoCode: Joi38.string().optional().allow("", null)
|
|
9913
|
-
}).optional().allow("", null),
|
|
9914
|
-
status: Joi38.string().optional().allow("", null),
|
|
9915
|
-
createdAt: Joi38.string().optional().allow("", null),
|
|
9916
|
-
updatedAt: Joi38.string().optional().allow("", null),
|
|
9917
|
-
deletedAt: Joi38.string().optional().allow("", null)
|
|
9918
|
-
});
|
|
9919
|
-
|
|
9920
|
-
// src/resources/verification/verification.controller.ts
|
|
9921
|
-
import {
|
|
9922
|
-
AppError as AppError24,
|
|
9923
|
-
BadRequestError as BadRequestError51,
|
|
9924
|
-
InternalServerError as InternalServerError27
|
|
9925
|
-
} from "@goweekdays/utils";
|
|
9926
|
-
import Joi39 from "joi";
|
|
9927
|
-
function useVerificationController() {
|
|
9928
|
-
const {
|
|
9929
|
-
createUserInvite: _createUserInvite,
|
|
9930
|
-
createForgetPassword: _createForgetPassword,
|
|
9931
|
-
cancelUserInvitation: _cancelUserInvitation,
|
|
9932
|
-
verify: _verify,
|
|
9933
|
-
inviteMember: _inviteMember,
|
|
9934
|
-
signUp: _signUp,
|
|
9935
|
-
cancelInviteMember: _cancelInviteMember,
|
|
9936
|
-
forgetPassword: _forgetPassword
|
|
9937
|
-
} = useVerificationService();
|
|
9938
|
-
const { getVerifications: _getVerifications } = useVerificationRepo();
|
|
9939
|
-
async function createUserInvite(req, res, next) {
|
|
9940
|
-
const validation = Joi39.object({
|
|
9941
|
-
email: Joi39.string().email().required(),
|
|
9942
|
-
app: Joi39.string().required(),
|
|
9943
|
-
role: Joi39.string().hex().required(),
|
|
9944
|
-
roleName: Joi39.string().required(),
|
|
9945
|
-
org: Joi39.string().hex().optional().optional().allow("", null),
|
|
9946
|
-
orgName: Joi39.string().optional().optional().allow("", null)
|
|
9947
|
-
});
|
|
9948
|
-
const { error } = validation.validate(req.body);
|
|
9949
|
-
if (error) {
|
|
9950
|
-
next(new BadRequestError51(error.message));
|
|
9951
|
-
return;
|
|
9952
|
-
}
|
|
9953
|
-
const email = req.body.email ?? "";
|
|
9954
|
-
const app = req.body.app ?? "";
|
|
9955
|
-
const role = req.body.role ?? "";
|
|
9956
|
-
const roleName = req.body.roleName ?? "";
|
|
9957
|
-
const org = req.body.org ?? "";
|
|
9958
|
-
const orgName = req.body.orgName ?? "";
|
|
9959
|
-
try {
|
|
9960
|
-
await _createUserInvite({
|
|
9961
|
-
email,
|
|
9962
|
-
metadata: {
|
|
9963
|
-
app,
|
|
9964
|
-
role,
|
|
9965
|
-
roleName,
|
|
9966
|
-
org,
|
|
9967
|
-
orgName
|
|
10615
|
+
environment,
|
|
10616
|
+
type,
|
|
10617
|
+
variablesSet: lines.length
|
|
9968
10618
|
}
|
|
9969
10619
|
});
|
|
9970
|
-
|
|
9971
|
-
|
|
9972
|
-
|
|
9973
|
-
|
|
9974
|
-
}
|
|
9975
|
-
}
|
|
9976
|
-
async function createForgetPassword(req, res, next) {
|
|
9977
|
-
const email = req.body.email || "";
|
|
9978
|
-
const validation = Joi39.string().email().required();
|
|
9979
|
-
const { error } = validation.validate(email);
|
|
9980
|
-
if (error) {
|
|
9981
|
-
next(new BadRequestError51(error.message));
|
|
9982
|
-
return;
|
|
9983
|
-
}
|
|
9984
|
-
try {
|
|
9985
|
-
await _createForgetPassword(email);
|
|
9986
|
-
res.json({
|
|
9987
|
-
message: "Check your email to verify it before resetting your password."
|
|
10620
|
+
} catch (error) {
|
|
10621
|
+
logger30.error("Failed to set GitHub variables", {
|
|
10622
|
+
error: error.message,
|
|
10623
|
+
stack: error.stack
|
|
9988
10624
|
});
|
|
9989
|
-
|
|
9990
|
-
|
|
9991
|
-
if (error2 instanceof AppError24) {
|
|
9992
|
-
next(error2);
|
|
10625
|
+
if (error instanceof AppError25) {
|
|
10626
|
+
next(error);
|
|
9993
10627
|
} else {
|
|
9994
|
-
next(
|
|
10628
|
+
next(
|
|
10629
|
+
new InternalServerError28(
|
|
10630
|
+
`Failed to set GitHub variables: ${error.message}`
|
|
10631
|
+
)
|
|
10632
|
+
);
|
|
9995
10633
|
}
|
|
9996
10634
|
}
|
|
9997
10635
|
}
|
|
9998
|
-
|
|
9999
|
-
|
|
10000
|
-
|
|
10001
|
-
search: Joi39.string().optional().allow("", null),
|
|
10002
|
-
page: Joi39.number().required(),
|
|
10003
|
-
type: Joi39.string().optional().allow("", null),
|
|
10004
|
-
email: Joi39.string().optional().allow("", null),
|
|
10005
|
-
app: Joi39.string().optional().allow("", null),
|
|
10006
|
-
org: Joi39.string().optional().allow("", null)
|
|
10007
|
-
});
|
|
10008
|
-
const { error } = validation.validate(req.query);
|
|
10009
|
-
if (error) {
|
|
10010
|
-
next(new BadRequestError51(error.message));
|
|
10011
|
-
return;
|
|
10012
|
-
}
|
|
10013
|
-
const status = req.query.status ?? "";
|
|
10014
|
-
const search = req.query.search ?? "";
|
|
10015
|
-
const page = Number(req.query.page) ?? 1;
|
|
10016
|
-
let type = req.query.type ?? "";
|
|
10017
|
-
const email = req.query.email ?? "";
|
|
10018
|
-
const app = req.query.app ?? "";
|
|
10019
|
-
const org = req.query.org ?? "";
|
|
10020
|
-
const hasMultipleTypes = type.includes(",");
|
|
10021
|
-
let splitType = [];
|
|
10022
|
-
if (hasMultipleTypes) {
|
|
10023
|
-
splitType = type.split(",");
|
|
10024
|
-
}
|
|
10636
|
+
const { verifySignature, captureOrder } = usePaypalService();
|
|
10637
|
+
const { addWithVerification } = useOrgService();
|
|
10638
|
+
async function paypalWebhook(req, res, next) {
|
|
10025
10639
|
try {
|
|
10026
|
-
const
|
|
10027
|
-
|
|
10028
|
-
|
|
10029
|
-
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10640
|
+
const isSignatureValid = await verifySignature(
|
|
10641
|
+
req.body,
|
|
10642
|
+
req.headers,
|
|
10643
|
+
PAYPAL_WEBHOOK_ID
|
|
10644
|
+
);
|
|
10645
|
+
if (isSignatureValid) {
|
|
10646
|
+
const payload = JSON.parse(req.body);
|
|
10647
|
+
const eventType = payload.event_type;
|
|
10648
|
+
const resource = payload.resource;
|
|
10649
|
+
switch (eventType) {
|
|
10650
|
+
case "CHECKOUT.ORDER.APPROVED": {
|
|
10651
|
+
const orderId = resource.id;
|
|
10652
|
+
await captureOrder(orderId);
|
|
10653
|
+
break;
|
|
10654
|
+
}
|
|
10655
|
+
case "PAYMENT.CAPTURE.COMPLETED": {
|
|
10656
|
+
const customId = resource?.custom_id || resource?.purchase_units?.[0]?.custom_id;
|
|
10657
|
+
if (!customId) {
|
|
10658
|
+
throw new Error("Missing PayPal customId");
|
|
10659
|
+
}
|
|
10660
|
+
await addWithVerification(customId);
|
|
10661
|
+
break;
|
|
10662
|
+
}
|
|
10663
|
+
default:
|
|
10664
|
+
break;
|
|
10665
|
+
}
|
|
10666
|
+
} else {
|
|
10667
|
+
next(new BadRequestError54("Invalid PayPal webhook signature."));
|
|
10668
|
+
return;
|
|
10669
|
+
}
|
|
10670
|
+
res.sendStatus(200);
|
|
10036
10671
|
return;
|
|
10037
|
-
} catch (
|
|
10038
|
-
|
|
10672
|
+
} catch (error) {
|
|
10673
|
+
logger30.log({
|
|
10674
|
+
level: "error",
|
|
10675
|
+
message: `${error}`
|
|
10676
|
+
});
|
|
10677
|
+
next(new InternalServerError28(`PayPal webhook error: ${error.message}`));
|
|
10039
10678
|
}
|
|
10040
10679
|
}
|
|
10041
|
-
|
|
10042
|
-
|
|
10043
|
-
|
|
10044
|
-
|
|
10045
|
-
|
|
10046
|
-
|
|
10047
|
-
|
|
10048
|
-
|
|
10680
|
+
return {
|
|
10681
|
+
healthCheck,
|
|
10682
|
+
setGitHubVariables,
|
|
10683
|
+
paypalWebhook
|
|
10684
|
+
};
|
|
10685
|
+
}
|
|
10686
|
+
|
|
10687
|
+
// src/resources/utils/transaction.schema.ts
|
|
10688
|
+
import Joi44 from "joi";
|
|
10689
|
+
var transactionSchema = Joi44.object({
|
|
10690
|
+
_id: Joi44.string().hex().optional().allow("", null),
|
|
10691
|
+
payment: Joi44.string().required(),
|
|
10692
|
+
user: Joi44.string().hex().optional().allow("", null),
|
|
10693
|
+
org: Joi44.string().hex().optional().allow("", null),
|
|
10694
|
+
type: Joi44.string().required(),
|
|
10695
|
+
amount: Joi44.number().positive().min(0).required(),
|
|
10696
|
+
currency: Joi44.string().required(),
|
|
10697
|
+
description: Joi44.string().optional().allow("", null),
|
|
10698
|
+
metadata: Joi44.object({
|
|
10699
|
+
subscriptionId: Joi44.string().hex().optional().allow("", null),
|
|
10700
|
+
cycle: Joi44.number().optional().allow("", null),
|
|
10701
|
+
seats: Joi44.number().optional().allow("", null),
|
|
10702
|
+
promoCode: Joi44.string().optional().allow("", null)
|
|
10703
|
+
}).optional().allow("", null),
|
|
10704
|
+
status: Joi44.string().optional().allow("", null),
|
|
10705
|
+
createdAt: Joi44.string().optional().allow("", null),
|
|
10706
|
+
updatedAt: Joi44.string().optional().allow("", null),
|
|
10707
|
+
deletedAt: Joi44.string().optional().allow("", null)
|
|
10708
|
+
});
|
|
10709
|
+
|
|
10710
|
+
// src/resources/job-post/job.post.model.ts
|
|
10711
|
+
import { BadRequestError as BadRequestError55 } from "@goweekdays/utils";
|
|
10712
|
+
import Joi45 from "joi";
|
|
10713
|
+
import { ObjectId as ObjectId27 } from "mongodb";
|
|
10714
|
+
var schemaJobPost = Joi45.object({
|
|
10715
|
+
_id: Joi45.string().hex().optional(),
|
|
10716
|
+
org: Joi45.string().hex().optional(),
|
|
10717
|
+
title: Joi45.string().trim().required(),
|
|
10718
|
+
setup: Joi45.string().trim().required(),
|
|
10719
|
+
location: Joi45.string().trim().required(),
|
|
10720
|
+
type: Joi45.string().trim().required(),
|
|
10721
|
+
description: Joi45.string().trim().required(),
|
|
10722
|
+
status: Joi45.string().trim().required(),
|
|
10723
|
+
createdAt: Joi45.date().optional(),
|
|
10724
|
+
updatedAt: Joi45.date().optional(),
|
|
10725
|
+
deletedAt: Joi45.date().optional()
|
|
10726
|
+
});
|
|
10727
|
+
function modelJobPost(value) {
|
|
10728
|
+
const { error } = schemaJobPost.validate(value);
|
|
10729
|
+
if (error) {
|
|
10730
|
+
throw new BadRequestError55(`Invalid job post: ${error.message}`);
|
|
10731
|
+
}
|
|
10732
|
+
if (!value._id) {
|
|
10049
10733
|
try {
|
|
10050
|
-
|
|
10051
|
-
res.json(message);
|
|
10052
|
-
return;
|
|
10734
|
+
value._id = new ObjectId27();
|
|
10053
10735
|
} catch (error2) {
|
|
10054
|
-
|
|
10736
|
+
throw new BadRequestError55("Invalid job post ID.");
|
|
10055
10737
|
}
|
|
10056
10738
|
}
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
10061
|
-
|
|
10062
|
-
|
|
10063
|
-
|
|
10739
|
+
try {
|
|
10740
|
+
value.org = new ObjectId27(value.org);
|
|
10741
|
+
} catch (error2) {
|
|
10742
|
+
throw new BadRequestError55("Invalid Org ID");
|
|
10743
|
+
}
|
|
10744
|
+
return {
|
|
10745
|
+
_id: value._id,
|
|
10746
|
+
org: value.org,
|
|
10747
|
+
title: value.title,
|
|
10748
|
+
setup: value.setup,
|
|
10749
|
+
location: value.location,
|
|
10750
|
+
type: value.type,
|
|
10751
|
+
description: value.description,
|
|
10752
|
+
status: value.status ?? "active",
|
|
10753
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
10754
|
+
updatedAt: value.updatedAt,
|
|
10755
|
+
deletedAt: value.deletedAt
|
|
10756
|
+
};
|
|
10757
|
+
}
|
|
10758
|
+
|
|
10759
|
+
// src/resources/job-post/job.post.controller.ts
|
|
10760
|
+
import { BadRequestError as BadRequestError58, logger as logger32 } from "@goweekdays/utils";
|
|
10761
|
+
|
|
10762
|
+
// src/resources/job-post/job.post.repository.ts
|
|
10763
|
+
import { BadRequestError as BadRequestError56, useAtlas as useAtlas27, useCache as useCache20, logger as logger31, InternalServerError as InternalServerError29 } from "@goweekdays/utils";
|
|
10764
|
+
import { ObjectId as ObjectId28 } from "mongodb";
|
|
10765
|
+
function useJobPostRepo() {
|
|
10766
|
+
const db = useAtlas27.getDb();
|
|
10767
|
+
if (!db) {
|
|
10768
|
+
throw new BadRequestError56("Unable to connect to server.");
|
|
10769
|
+
}
|
|
10770
|
+
const namespace_collection = "job.posts";
|
|
10771
|
+
const collection = db.collection(namespace_collection);
|
|
10772
|
+
const { delNamespace } = useCache20(namespace_collection);
|
|
10773
|
+
function delCachedData() {
|
|
10774
|
+
delNamespace().then(() => {
|
|
10775
|
+
logger31.log({
|
|
10776
|
+
level: "info",
|
|
10777
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
10778
|
+
});
|
|
10779
|
+
}).catch((err) => {
|
|
10780
|
+
logger31.log({
|
|
10781
|
+
level: "error",
|
|
10782
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
10783
|
+
});
|
|
10784
|
+
});
|
|
10785
|
+
}
|
|
10786
|
+
async function createIndexes() {
|
|
10787
|
+
try {
|
|
10788
|
+
await collection.createIndexes([
|
|
10789
|
+
{ key: { title: 1 } },
|
|
10790
|
+
{ key: { setup: 1 } },
|
|
10791
|
+
{ key: { location: 1 } },
|
|
10792
|
+
{ key: { type: 1 } },
|
|
10793
|
+
{
|
|
10794
|
+
key: {
|
|
10795
|
+
title: "text",
|
|
10796
|
+
setup: "text",
|
|
10797
|
+
location: "text",
|
|
10798
|
+
type: "text"
|
|
10799
|
+
},
|
|
10800
|
+
name: "jobpost_text_search"
|
|
10801
|
+
}
|
|
10802
|
+
]);
|
|
10803
|
+
return "Successfully created job post indexes.";
|
|
10804
|
+
} catch (error) {
|
|
10805
|
+
throw new BadRequestError56("Failed to create job post indexes.");
|
|
10064
10806
|
}
|
|
10807
|
+
}
|
|
10808
|
+
async function add(value, session) {
|
|
10065
10809
|
try {
|
|
10066
|
-
|
|
10067
|
-
|
|
10068
|
-
|
|
10810
|
+
value = modelJobPost(value);
|
|
10811
|
+
const res = await collection.insertOne(value, { session });
|
|
10812
|
+
delCachedData();
|
|
10813
|
+
return res.insertedId;
|
|
10814
|
+
} catch (error) {
|
|
10815
|
+
logger31.log({
|
|
10816
|
+
level: "error",
|
|
10817
|
+
message: error.message
|
|
10069
10818
|
});
|
|
10070
|
-
|
|
10071
|
-
throw error2;
|
|
10819
|
+
throw new BadRequestError56(`Failed to create job post: ${error.message}`);
|
|
10072
10820
|
}
|
|
10073
10821
|
}
|
|
10074
|
-
async function
|
|
10075
|
-
|
|
10076
|
-
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
return;
|
|
10822
|
+
async function deleteById(_id, session) {
|
|
10823
|
+
try {
|
|
10824
|
+
_id = new ObjectId28(_id);
|
|
10825
|
+
} catch (error) {
|
|
10826
|
+
throw new BadRequestError56("Invalid ID.");
|
|
10080
10827
|
}
|
|
10081
|
-
const email = req.body.email ?? "";
|
|
10082
10828
|
try {
|
|
10083
|
-
await
|
|
10084
|
-
|
|
10085
|
-
|
|
10086
|
-
|
|
10087
|
-
|
|
10829
|
+
await collection.updateOne(
|
|
10830
|
+
{ _id },
|
|
10831
|
+
{
|
|
10832
|
+
$set: {
|
|
10833
|
+
status: "deleted",
|
|
10834
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
10835
|
+
deletedAt: /* @__PURE__ */ new Date()
|
|
10836
|
+
}
|
|
10837
|
+
},
|
|
10838
|
+
{ session }
|
|
10839
|
+
);
|
|
10840
|
+
delCachedData();
|
|
10841
|
+
return "Successfully deleted job post.";
|
|
10842
|
+
} catch (error) {
|
|
10843
|
+
throw new InternalServerError29("Failed to delete job post.");
|
|
10088
10844
|
}
|
|
10089
10845
|
}
|
|
10090
|
-
|
|
10091
|
-
|
|
10846
|
+
return {
|
|
10847
|
+
createIndexes,
|
|
10848
|
+
add,
|
|
10849
|
+
deleteById
|
|
10850
|
+
};
|
|
10851
|
+
}
|
|
10852
|
+
|
|
10853
|
+
// src/resources/job-post/job.post.service.ts
|
|
10854
|
+
import {
|
|
10855
|
+
AppError as AppError26,
|
|
10856
|
+
BadRequestError as BadRequestError57,
|
|
10857
|
+
InternalServerError as InternalServerError30
|
|
10858
|
+
} from "@goweekdays/utils";
|
|
10859
|
+
import Joi46 from "joi";
|
|
10860
|
+
function useJobPostService() {
|
|
10861
|
+
const { deleteById: _deleteById } = useJobPostRepo();
|
|
10862
|
+
async function deleteById(id) {
|
|
10863
|
+
const { error } = Joi46.string().hex().required().validate(id);
|
|
10092
10864
|
if (error) {
|
|
10093
|
-
|
|
10094
|
-
return;
|
|
10865
|
+
throw new BadRequestError57(error.message);
|
|
10095
10866
|
}
|
|
10096
10867
|
try {
|
|
10097
|
-
await
|
|
10098
|
-
|
|
10099
|
-
return;
|
|
10868
|
+
await _deleteById(id);
|
|
10869
|
+
return "Successfully deleted job post.";
|
|
10100
10870
|
} catch (error2) {
|
|
10101
|
-
|
|
10871
|
+
if (error2 instanceof AppError26) {
|
|
10872
|
+
throw error2;
|
|
10873
|
+
} else {
|
|
10874
|
+
throw new InternalServerError30("Failed to delete job post.");
|
|
10875
|
+
}
|
|
10102
10876
|
}
|
|
10103
10877
|
}
|
|
10104
|
-
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10878
|
+
return {
|
|
10879
|
+
deleteById
|
|
10880
|
+
};
|
|
10881
|
+
}
|
|
10882
|
+
|
|
10883
|
+
// src/resources/job-post/job.post.controller.ts
|
|
10884
|
+
function useJobPostController() {
|
|
10885
|
+
const { add: _add } = useJobPostRepo();
|
|
10886
|
+
const { deleteById: _deleteById } = useJobPostService();
|
|
10887
|
+
async function add(req, res, next) {
|
|
10888
|
+
const value = req.body;
|
|
10889
|
+
const { error } = schemaJobPost.validate(value);
|
|
10108
10890
|
if (error) {
|
|
10109
|
-
next(new
|
|
10891
|
+
next(new BadRequestError58(error.message));
|
|
10892
|
+
logger32.info(`Controller: ${error.message}`);
|
|
10110
10893
|
return;
|
|
10111
10894
|
}
|
|
10112
10895
|
try {
|
|
10113
|
-
const
|
|
10114
|
-
res.json({ message });
|
|
10896
|
+
const result = await _add(value);
|
|
10897
|
+
res.json({ message: "Successfully created job post.", data: { result } });
|
|
10115
10898
|
return;
|
|
10116
10899
|
} catch (error2) {
|
|
10117
10900
|
next(error2);
|
|
10118
10901
|
}
|
|
10119
10902
|
}
|
|
10120
|
-
async function
|
|
10121
|
-
const
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
if (error) {
|
|
10125
|
-
next(new BadRequestError51(error.message));
|
|
10903
|
+
async function deleteById(req, res, next) {
|
|
10904
|
+
const id = req.params.id;
|
|
10905
|
+
if (!id) {
|
|
10906
|
+
next(new BadRequestError58("Job Post ID is required."));
|
|
10126
10907
|
return;
|
|
10127
10908
|
}
|
|
10128
10909
|
try {
|
|
10129
|
-
const message = await
|
|
10130
|
-
res.json(
|
|
10131
|
-
message
|
|
10132
|
-
});
|
|
10910
|
+
const message = await _deleteById(id);
|
|
10911
|
+
res.json(message);
|
|
10133
10912
|
return;
|
|
10134
|
-
} catch (
|
|
10135
|
-
|
|
10136
|
-
next(error2);
|
|
10137
|
-
} else {
|
|
10138
|
-
next(new InternalServerError27("An unexpected error occurred"));
|
|
10139
|
-
}
|
|
10913
|
+
} catch (error) {
|
|
10914
|
+
next(error);
|
|
10140
10915
|
}
|
|
10141
10916
|
}
|
|
10142
10917
|
return {
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
createForgetPassword,
|
|
10146
|
-
verify,
|
|
10147
|
-
cancelUserInvitation,
|
|
10148
|
-
inviteMember,
|
|
10149
|
-
signUp,
|
|
10150
|
-
cancelInviteMember,
|
|
10151
|
-
forgetPassword
|
|
10918
|
+
add,
|
|
10919
|
+
deleteById
|
|
10152
10920
|
};
|
|
10153
10921
|
}
|
|
10154
10922
|
export {
|
|
@@ -10194,7 +10962,11 @@ export {
|
|
|
10194
10962
|
XENDIT_SECRET_KEY,
|
|
10195
10963
|
currencies,
|
|
10196
10964
|
isDev,
|
|
10965
|
+
ledgerBillStatuses,
|
|
10966
|
+
ledgerBillTypes,
|
|
10197
10967
|
modelApp,
|
|
10968
|
+
modelJobPost,
|
|
10969
|
+
modelLedgerBill,
|
|
10198
10970
|
modelMember,
|
|
10199
10971
|
modelOrg,
|
|
10200
10972
|
modelPermission,
|
|
@@ -10211,6 +10983,8 @@ export {
|
|
|
10211
10983
|
schemaBuilding,
|
|
10212
10984
|
schemaBuildingUnit,
|
|
10213
10985
|
schemaInviteMember,
|
|
10986
|
+
schemaJobPost,
|
|
10987
|
+
schemaLedgerBill,
|
|
10214
10988
|
schemaMember,
|
|
10215
10989
|
schemaMemberRole,
|
|
10216
10990
|
schemaMemberStatus,
|
|
@@ -10250,6 +11024,11 @@ export {
|
|
|
10250
11024
|
useFileRepo,
|
|
10251
11025
|
useFileService,
|
|
10252
11026
|
useGitHubService,
|
|
11027
|
+
useJobPostController,
|
|
11028
|
+
useJobPostRepo,
|
|
11029
|
+
useJobPostService,
|
|
11030
|
+
useLedgerBillingController,
|
|
11031
|
+
useLedgerBillingRepo,
|
|
10253
11032
|
useMemberController,
|
|
10254
11033
|
useMemberRepo,
|
|
10255
11034
|
useOrgController,
|