@goweekdays/core 2.11.16 → 2.11.18

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/dist/index.mjs CHANGED
@@ -1947,6 +1947,49 @@ function useMemberRepo() {
1947
1947
  );
1948
1948
  }
1949
1949
  }
1950
+ async function getByUserOrg(user, org) {
1951
+ try {
1952
+ org = new ObjectId7(org);
1953
+ } catch (error) {
1954
+ throw new BadRequestError7("Invalid organization ID.");
1955
+ }
1956
+ try {
1957
+ user = new ObjectId7(user);
1958
+ } catch (error) {
1959
+ throw new BadRequestError7("Invalid user ID.");
1960
+ }
1961
+ try {
1962
+ const cacheKey = makeCacheKey4(namespace_collection, {
1963
+ user: String(user),
1964
+ org: String(org)
1965
+ });
1966
+ const cached = await getCache(cacheKey);
1967
+ if (cached) {
1968
+ logger4.log({
1969
+ level: "info",
1970
+ message: `Cache hit for getByUserOrg member: ${cacheKey}`
1971
+ });
1972
+ return cached;
1973
+ }
1974
+ const data = await collection.findOne({ user, org });
1975
+ setCache(cacheKey, data, 300).then(() => {
1976
+ logger4.log({
1977
+ level: "info",
1978
+ message: `Cache set for member by user and org: ${cacheKey}`
1979
+ });
1980
+ }).catch((err) => {
1981
+ logger4.log({
1982
+ level: "error",
1983
+ message: `Failed to set cache for member by user and org: ${err.message}`
1984
+ });
1985
+ });
1986
+ return data;
1987
+ } catch (error) {
1988
+ throw new InternalServerError5(
1989
+ "Internal server error, failed to retrieve member."
1990
+ );
1991
+ }
1992
+ }
1950
1993
  return {
1951
1994
  createIndexes,
1952
1995
  add,
@@ -1966,7 +2009,8 @@ function useMemberRepo() {
1966
2009
  updateStatusById,
1967
2010
  deleteById,
1968
2011
  updateStatusByOrg,
1969
- countUserByOrg
2012
+ countUserByOrg,
2013
+ getByUserOrg
1970
2014
  };
1971
2015
  }
1972
2016
 
@@ -10806,7 +10850,11 @@ function useVerificationService() {
10806
10850
  getVerifications: _getVerifications
10807
10851
  } = useVerificationRepo();
10808
10852
  const { getUserByEmail } = useUserRepo();
10809
- const { add: addMember, countUserByOrg } = useMemberRepo();
10853
+ const {
10854
+ add: addMember,
10855
+ countUserByOrg,
10856
+ getByUserOrg: getMemberByUserOrg
10857
+ } = useMemberRepo();
10810
10858
  const { getById: getOrgById } = useOrgRepo();
10811
10859
  const { getById: getRoleById } = useRoleRepo();
10812
10860
  async function createUserInvite({
@@ -11138,8 +11186,17 @@ function useVerificationService() {
11138
11186
  );
11139
11187
  }
11140
11188
  }
11189
+ const user = await getUserByEmail(value.email);
11190
+ let userId = "";
11191
+ if (user) {
11192
+ userId = String(user._id);
11193
+ }
11141
11194
  const memberCount = await countUserByOrg(String(value.org));
11142
- if (subscription.seats <= memberCount) {
11195
+ const existingMember = await getMemberByUserOrg(
11196
+ userId,
11197
+ String(value.org)
11198
+ );
11199
+ if (subscription.seats <= memberCount && !existingMember) {
11143
11200
  throw new BadRequestError49(
11144
11201
  "Organization has reached the maximum number of members for its subscription plan."
11145
11202
  );
@@ -12964,10 +13021,12 @@ function modelJobPost(value) {
12964
13021
  } catch (error2) {
12965
13022
  throw new BadRequestError59("Invalid Org ID");
12966
13023
  }
12967
- try {
12968
- value.company = new ObjectId29(value.company);
12969
- } catch (error2) {
12970
- throw new BadRequestError59("Invalid Company ID");
13024
+ if (value.company && typeof value.company === "string" && value.company.length === 24) {
13025
+ try {
13026
+ value.company = new ObjectId29(value.company);
13027
+ } catch (error2) {
13028
+ throw new BadRequestError59("Invalid Company ID");
13029
+ }
12971
13030
  }
12972
13031
  return {
12973
13032
  _id: value._id,
@@ -13101,7 +13160,11 @@ function useJobPostRepo() {
13101
13160
  {
13102
13161
  $project: {
13103
13162
  _id: 1,
13163
+ org: 1,
13104
13164
  orgName: 1,
13165
+ company: 1,
13166
+ companyName: 1,
13167
+ description: 1,
13105
13168
  minSalary: 1,
13106
13169
  maxSalary: 1,
13107
13170
  currency: 1,
@@ -13909,6 +13972,295 @@ function useJobPostController() {
13909
13972
  getCurrencies
13910
13973
  };
13911
13974
  }
13975
+
13976
+ // src/resources/job-applications/job.applications.model.ts
13977
+ import { BadRequestError as BadRequestError65 } from "@goweekdays/utils";
13978
+ import Joi54 from "joi";
13979
+ import { ObjectId as ObjectId32 } from "mongodb";
13980
+ var jobApplicationStatuses = [
13981
+ "new",
13982
+ "shortlisted",
13983
+ "interview-scheduled",
13984
+ "interviewed",
13985
+ "offer-extended",
13986
+ "hired",
13987
+ "on-hold",
13988
+ "withdrawn",
13989
+ "rejected",
13990
+ // Agency specific
13991
+ "contacted",
13992
+ "endorsed",
13993
+ "client-interested",
13994
+ "pooled",
13995
+ // HR specific
13996
+ "under-review",
13997
+ "for-approval"
13998
+ ];
13999
+ var schemaJobApplication = Joi54.object({
14000
+ post: Joi54.string().required(),
14001
+ jobTitle: Joi54.string().optional().allow(""),
14002
+ company: Joi54.string().hex().optional().allow(""),
14003
+ companyName: Joi54.string().optional().allow(""),
14004
+ location: Joi54.string().optional().allow(""),
14005
+ user: Joi54.string().required(),
14006
+ name: Joi54.string().required(),
14007
+ email: Joi54.string().email().required(),
14008
+ contact: Joi54.string().optional().allow(""),
14009
+ metadata: Joi54.object({
14010
+ resume: Joi54.string().optional().allow(""),
14011
+ resumeUrl: Joi54.string().uri().optional().allow(""),
14012
+ portfolio: Joi54.string().optional().allow(""),
14013
+ portfolioUrl: Joi54.string().uri().optional().allow(""),
14014
+ coverLetter: Joi54.string().optional().allow(""),
14015
+ coverLetterUrl: Joi54.string().uri().optional().allow("")
14016
+ }).optional()
14017
+ });
14018
+ function modelJobApplication(data) {
14019
+ const { error } = schemaJobApplication.validate(data);
14020
+ if (error) {
14021
+ throw new BadRequestError65(`Invalid job application data: ${error.message}`);
14022
+ }
14023
+ if (data._id && typeof data._id === "string") {
14024
+ try {
14025
+ data._id = new ObjectId32(data._id);
14026
+ } catch (error2) {
14027
+ throw new BadRequestError65(`Invalid job application _id: ${data._id}`);
14028
+ }
14029
+ }
14030
+ try {
14031
+ data.post = new ObjectId32(data.post);
14032
+ } catch (error2) {
14033
+ throw new BadRequestError65(`Invalid job application post id: ${data.post}`);
14034
+ }
14035
+ if (data.company && typeof data.company === "string") {
14036
+ try {
14037
+ data.company = new ObjectId32(data.company);
14038
+ } catch (error2) {
14039
+ throw new BadRequestError65(
14040
+ `Invalid job application company id: ${data.company}`
14041
+ );
14042
+ }
14043
+ }
14044
+ return {
14045
+ _id: data._id,
14046
+ post: data.post,
14047
+ jobTitle: data.jobTitle,
14048
+ company: data.company,
14049
+ companyName: data.companyName ?? "",
14050
+ location: data.location ?? "",
14051
+ user: data.user,
14052
+ name: data.name,
14053
+ email: data.email,
14054
+ contact: data.contact ?? "",
14055
+ metadata: data.metadata ?? {},
14056
+ status: data.status ?? "new",
14057
+ createdAt: data.createdAt ?? /* @__PURE__ */ new Date(),
14058
+ updatedAt: data.updatedAt ?? "",
14059
+ deletedAt: data.deletedAt ?? ""
14060
+ };
14061
+ }
14062
+
14063
+ // src/resources/job-applications/job.application.repository.ts
14064
+ import {
14065
+ AppError as AppError32,
14066
+ BadRequestError as BadRequestError66,
14067
+ logger as logger37,
14068
+ makeCacheKey as makeCacheKey22,
14069
+ paginate as paginate19,
14070
+ useAtlas as useAtlas31,
14071
+ useCache as useCache23
14072
+ } from "@goweekdays/utils";
14073
+ function useJobApplicationRepo() {
14074
+ const db = useAtlas31.getDb();
14075
+ if (!db) {
14076
+ throw new BadRequestError66("Unable to connect to server.");
14077
+ }
14078
+ const namespace_collection = "job.applications";
14079
+ const collection = db.collection(namespace_collection);
14080
+ const { getCache, setCache, delNamespace } = useCache23(namespace_collection);
14081
+ function delCachedData() {
14082
+ delNamespace().then(() => {
14083
+ logger37.log({
14084
+ level: "info",
14085
+ message: `Cache namespace cleared for ${namespace_collection}`
14086
+ });
14087
+ }).catch((err) => {
14088
+ logger37.log({
14089
+ level: "error",
14090
+ message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
14091
+ });
14092
+ });
14093
+ }
14094
+ async function createIndexes() {
14095
+ try {
14096
+ await collection.createIndexes([
14097
+ { key: { jobTitle: 1 } },
14098
+ { key: { company: 1 } },
14099
+ { key: { companyName: 1 } },
14100
+ { key: { location: 1 } },
14101
+ { key: { user: 1 } },
14102
+ { key: { email: 1 } },
14103
+ {
14104
+ key: {
14105
+ jobTitle: "text",
14106
+ company: "text",
14107
+ companyName: "text",
14108
+ location: "text",
14109
+ name: "text"
14110
+ },
14111
+ name: "job_application_text_search"
14112
+ }
14113
+ ]);
14114
+ return "Successfully created job application indexes.";
14115
+ } catch (error) {
14116
+ throw new BadRequestError66("Failed to create job application indexes.");
14117
+ }
14118
+ }
14119
+ async function add(data) {
14120
+ const { error } = schemaJobApplication.validate(data);
14121
+ if (error) {
14122
+ throw new BadRequestError66(
14123
+ `Invalid job application data: ${error.message}`
14124
+ );
14125
+ }
14126
+ try {
14127
+ data = modelJobApplication(data);
14128
+ const res = await collection.insertOne(data);
14129
+ delCachedData();
14130
+ return res.insertedId;
14131
+ } catch (error2) {
14132
+ if (error2 instanceof AppError32) {
14133
+ throw error2;
14134
+ }
14135
+ throw new BadRequestError66(
14136
+ `Failed to create job application: ${error2.message}`
14137
+ );
14138
+ }
14139
+ }
14140
+ async function getAll({
14141
+ page = 1,
14142
+ limit = 10,
14143
+ search = "",
14144
+ status = "new"
14145
+ } = {}) {
14146
+ page = page > 0 ? page - 1 : 0;
14147
+ const query = { status };
14148
+ const cacheKeyOptions = {
14149
+ page,
14150
+ limit,
14151
+ status,
14152
+ tag: "getAll"
14153
+ };
14154
+ if (search) {
14155
+ query.$text = { $search: search };
14156
+ cacheKeyOptions.search = search;
14157
+ }
14158
+ const cacheKey = makeCacheKey22(namespace_collection, cacheKeyOptions);
14159
+ const cachedData = await getCache(cacheKey);
14160
+ if (cachedData) {
14161
+ return cachedData;
14162
+ }
14163
+ try {
14164
+ const items = await collection.aggregate([
14165
+ { $match: query },
14166
+ { $skip: page * limit },
14167
+ { $limit: limit }
14168
+ ]).toArray();
14169
+ const length = await collection.countDocuments(query);
14170
+ const data = paginate19(items, page, limit, length);
14171
+ setCache(cacheKey, data).then(() => {
14172
+ logger37.log({
14173
+ level: "info",
14174
+ message: `Cache set for getAll job applications: ${cacheKey}`
14175
+ });
14176
+ }).catch((err) => {
14177
+ logger37.log({
14178
+ level: "error",
14179
+ message: `Failed to set cache for getAll job applications: ${cacheKey}, error: ${err.message}`
14180
+ });
14181
+ });
14182
+ return data;
14183
+ } catch (error) {
14184
+ if (error instanceof AppError32) {
14185
+ throw error;
14186
+ }
14187
+ throw new BadRequestError66(
14188
+ `Failed to get job applications: ${error.message}`
14189
+ );
14190
+ }
14191
+ }
14192
+ return {
14193
+ createIndexes,
14194
+ delCachedData,
14195
+ add,
14196
+ getAll
14197
+ };
14198
+ }
14199
+
14200
+ // src/resources/job-applications/job.application.controller.ts
14201
+ import { AppError as AppError33, BadRequestError as BadRequestError67 } from "@goweekdays/utils";
14202
+ import Joi55 from "joi";
14203
+ function useJobApplicationController() {
14204
+ const { add: _add, getAll: _getAll } = useJobApplicationRepo();
14205
+ async function add(req, res, next) {
14206
+ const { error } = schemaJobApplication.validate(req.body);
14207
+ if (error) {
14208
+ next(
14209
+ new BadRequestError67(`Invalid job application data: ${error.message}`)
14210
+ );
14211
+ return;
14212
+ }
14213
+ try {
14214
+ const message = await _add(req.body);
14215
+ res.json({ message });
14216
+ return;
14217
+ } catch (error2) {
14218
+ if (error2 instanceof AppError33) {
14219
+ next(error2);
14220
+ return;
14221
+ }
14222
+ next(
14223
+ new BadRequestError67(
14224
+ `Failed to create job application: ${error2.message}`
14225
+ )
14226
+ );
14227
+ }
14228
+ }
14229
+ async function getAll(req, res, next) {
14230
+ const validation = Joi55.object({
14231
+ page: Joi55.number().integer().min(1).optional(),
14232
+ limit: Joi55.number().integer().min(1).max(100).optional(),
14233
+ search: Joi55.string().optional().allow(""),
14234
+ status: Joi55.string().valid(...jobApplicationStatuses).optional()
14235
+ });
14236
+ const { error } = validation.validate(req.query);
14237
+ if (error) {
14238
+ next(new BadRequestError67(`Invalid query parameters: ${error.message}`));
14239
+ return;
14240
+ }
14241
+ const page = req.query.page ? parseInt(req.query.page) : 1;
14242
+ const limit = req.query.limit ? parseInt(req.query.limit) : 10;
14243
+ const search = req.query.search ? req.query.search : "";
14244
+ const status = req.query.status ? req.query.status : "new";
14245
+ try {
14246
+ const data = await _getAll({ page, limit, search, status });
14247
+ res.json(data);
14248
+ return;
14249
+ } catch (error2) {
14250
+ if (error2 instanceof AppError33) {
14251
+ next(error2);
14252
+ return;
14253
+ }
14254
+ next(
14255
+ new BadRequestError67(`Failed to get job applications: ${error2.message}`)
14256
+ );
14257
+ }
14258
+ }
14259
+ return {
14260
+ add,
14261
+ getAll
14262
+ };
14263
+ }
13912
14264
  export {
13913
14265
  ACCESS_TOKEN_EXPIRY,
13914
14266
  ACCESS_TOKEN_SECRET,
@@ -13952,9 +14304,11 @@ export {
13952
14304
  XENDIT_SECRET_KEY,
13953
14305
  currencies,
13954
14306
  isDev,
14307
+ jobApplicationStatuses,
13955
14308
  ledgerBillStatuses,
13956
14309
  ledgerBillTypes,
13957
14310
  modelApp,
14311
+ modelJobApplication,
13958
14312
  modelJobPost,
13959
14313
  modelLedgerBill,
13960
14314
  modelMember,
@@ -13973,6 +14327,7 @@ export {
13973
14327
  schemaBuilding,
13974
14328
  schemaBuildingUnit,
13975
14329
  schemaInviteMember,
14330
+ schemaJobApplication,
13976
14331
  schemaJobPost,
13977
14332
  schemaJobPostUpdate,
13978
14333
  schemaLedgerBill,
@@ -14021,6 +14376,8 @@ export {
14021
14376
  useFileRepo,
14022
14377
  useFileService,
14023
14378
  useGitHubService,
14379
+ useJobApplicationController,
14380
+ useJobApplicationRepo,
14024
14381
  useJobPostController,
14025
14382
  useJobPostRepo,
14026
14383
  useJobPostService,