@eeplatform/core 1.4.4 → 1.5.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 +12 -0
- package/dist/index.d.ts +177 -19
- package/dist/index.js +2060 -255
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2070 -256
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -1
package/dist/index.mjs
CHANGED
|
@@ -10389,7 +10389,7 @@ var require_ms = __commonJS({
|
|
|
10389
10389
|
options = options || {};
|
|
10390
10390
|
var type = typeof val;
|
|
10391
10391
|
if (type === "string" && val.length > 0) {
|
|
10392
|
-
return
|
|
10392
|
+
return parse4(val);
|
|
10393
10393
|
} else if (type === "number" && isNaN(val) === false) {
|
|
10394
10394
|
return options.long ? fmtLong(val) : fmtShort(val);
|
|
10395
10395
|
}
|
|
@@ -10397,7 +10397,7 @@ var require_ms = __commonJS({
|
|
|
10397
10397
|
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
|
|
10398
10398
|
);
|
|
10399
10399
|
};
|
|
10400
|
-
function
|
|
10400
|
+
function parse4(str) {
|
|
10401
10401
|
str = String(str);
|
|
10402
10402
|
if (str.length > 100) {
|
|
10403
10403
|
return;
|
|
@@ -10844,7 +10844,7 @@ var require_follow_redirects = __commonJS({
|
|
|
10844
10844
|
(function detectUnsupportedEnvironment() {
|
|
10845
10845
|
var looksLikeNode = typeof process !== "undefined";
|
|
10846
10846
|
var looksLikeBrowser = typeof window !== "undefined" && typeof document !== "undefined";
|
|
10847
|
-
var looksLikeV8 =
|
|
10847
|
+
var looksLikeV8 = isFunction3(Error.captureStackTrace);
|
|
10848
10848
|
if (!looksLikeNode && (looksLikeBrowser || !looksLikeV8)) {
|
|
10849
10849
|
console.warn("The follow-redirects package should be excluded from browser builds.");
|
|
10850
10850
|
}
|
|
@@ -10939,7 +10939,7 @@ var require_follow_redirects = __commonJS({
|
|
|
10939
10939
|
if (!isString2(data) && !isBuffer2(data)) {
|
|
10940
10940
|
throw new TypeError("data should be a string, Buffer or Uint8Array");
|
|
10941
10941
|
}
|
|
10942
|
-
if (
|
|
10942
|
+
if (isFunction3(encoding)) {
|
|
10943
10943
|
callback = encoding;
|
|
10944
10944
|
encoding = null;
|
|
10945
10945
|
}
|
|
@@ -10959,10 +10959,10 @@ var require_follow_redirects = __commonJS({
|
|
|
10959
10959
|
}
|
|
10960
10960
|
};
|
|
10961
10961
|
RedirectableRequest.prototype.end = function(data, encoding, callback) {
|
|
10962
|
-
if (
|
|
10962
|
+
if (isFunction3(data)) {
|
|
10963
10963
|
callback = data;
|
|
10964
10964
|
data = encoding = null;
|
|
10965
|
-
} else if (
|
|
10965
|
+
} else if (isFunction3(encoding)) {
|
|
10966
10966
|
callback = encoding;
|
|
10967
10967
|
encoding = null;
|
|
10968
10968
|
}
|
|
@@ -11163,7 +11163,7 @@ var require_follow_redirects = __commonJS({
|
|
|
11163
11163
|
if (redirectUrl.protocol !== currentUrlParts.protocol && redirectUrl.protocol !== "https:" || redirectUrl.host !== currentHost && !isSubdomain(redirectUrl.host, currentHost)) {
|
|
11164
11164
|
removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this._options.headers);
|
|
11165
11165
|
}
|
|
11166
|
-
if (
|
|
11166
|
+
if (isFunction3(beforeRedirect)) {
|
|
11167
11167
|
var responseDetails = {
|
|
11168
11168
|
headers: response.headers,
|
|
11169
11169
|
statusCode
|
|
@@ -11198,7 +11198,7 @@ var require_follow_redirects = __commonJS({
|
|
|
11198
11198
|
options = validateUrl(input);
|
|
11199
11199
|
input = { protocol };
|
|
11200
11200
|
}
|
|
11201
|
-
if (
|
|
11201
|
+
if (isFunction3(options)) {
|
|
11202
11202
|
callback = options;
|
|
11203
11203
|
options = null;
|
|
11204
11204
|
}
|
|
@@ -11278,7 +11278,7 @@ var require_follow_redirects = __commonJS({
|
|
|
11278
11278
|
}
|
|
11279
11279
|
function createErrorType(code, message, baseClass) {
|
|
11280
11280
|
function CustomError(properties) {
|
|
11281
|
-
if (
|
|
11281
|
+
if (isFunction3(Error.captureStackTrace)) {
|
|
11282
11282
|
Error.captureStackTrace(this, this.constructor);
|
|
11283
11283
|
}
|
|
11284
11284
|
Object.assign(this, properties || {});
|
|
@@ -11313,7 +11313,7 @@ var require_follow_redirects = __commonJS({
|
|
|
11313
11313
|
function isString2(value) {
|
|
11314
11314
|
return typeof value === "string" || value instanceof String;
|
|
11315
11315
|
}
|
|
11316
|
-
function
|
|
11316
|
+
function isFunction3(value) {
|
|
11317
11317
|
return typeof value === "function";
|
|
11318
11318
|
}
|
|
11319
11319
|
function isBuffer2(value) {
|
|
@@ -13569,7 +13569,7 @@ var _global = (() => {
|
|
|
13569
13569
|
})();
|
|
13570
13570
|
var isContextDefined = (context) => !isUndefined(context) && context !== _global;
|
|
13571
13571
|
function merge() {
|
|
13572
|
-
const { caseless } = isContextDefined(this) && this || {};
|
|
13572
|
+
const { caseless, skipUndefined } = isContextDefined(this) && this || {};
|
|
13573
13573
|
const result = {};
|
|
13574
13574
|
const assignValue = (val, key) => {
|
|
13575
13575
|
const targetKey = caseless && findKey(result, key) || key;
|
|
@@ -13579,7 +13579,7 @@ function merge() {
|
|
|
13579
13579
|
result[targetKey] = merge({}, val);
|
|
13580
13580
|
} else if (isArray(val)) {
|
|
13581
13581
|
result[targetKey] = val.slice();
|
|
13582
|
-
} else {
|
|
13582
|
+
} else if (!skipUndefined || !isUndefined(val)) {
|
|
13583
13583
|
result[targetKey] = val;
|
|
13584
13584
|
}
|
|
13585
13585
|
};
|
|
@@ -13915,9 +13915,13 @@ AxiosError.from = (error, code, config2, request, response, customProps) => {
|
|
|
13915
13915
|
}, (prop) => {
|
|
13916
13916
|
return prop !== "isAxiosError";
|
|
13917
13917
|
});
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
axiosError
|
|
13918
|
+
const msg = error && error.message ? error.message : "Error";
|
|
13919
|
+
const errCode = code == null && error ? error.code : code;
|
|
13920
|
+
AxiosError.call(axiosError, msg, errCode, config2, request, response);
|
|
13921
|
+
if (error && axiosError.cause == null) {
|
|
13922
|
+
Object.defineProperty(axiosError, "cause", { value: error, configurable: true });
|
|
13923
|
+
}
|
|
13924
|
+
axiosError.name = error && error.name || "Error";
|
|
13921
13925
|
customProps && Object.assign(axiosError, customProps);
|
|
13922
13926
|
return axiosError;
|
|
13923
13927
|
};
|
|
@@ -14080,7 +14084,7 @@ var AxiosURLSearchParams_default = AxiosURLSearchParams;
|
|
|
14080
14084
|
|
|
14081
14085
|
// node_modules/axios/lib/helpers/buildURL.js
|
|
14082
14086
|
function encode2(val) {
|
|
14083
|
-
return encodeURIComponent(val).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+")
|
|
14087
|
+
return encodeURIComponent(val).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+");
|
|
14084
14088
|
}
|
|
14085
14089
|
function buildURL(url2, params, options) {
|
|
14086
14090
|
if (!params) {
|
|
@@ -14378,7 +14382,7 @@ var defaults = {
|
|
|
14378
14382
|
const silentJSONParsing = transitional2 && transitional2.silentJSONParsing;
|
|
14379
14383
|
const strictJSONParsing = !silentJSONParsing && JSONRequested;
|
|
14380
14384
|
try {
|
|
14381
|
-
return JSON.parse(data);
|
|
14385
|
+
return JSON.parse(data, this.parseReviver);
|
|
14382
14386
|
} catch (e) {
|
|
14383
14387
|
if (strictJSONParsing) {
|
|
14384
14388
|
if (e.name === "SyntaxError") {
|
|
@@ -14765,7 +14769,7 @@ import util2 from "util";
|
|
|
14765
14769
|
import zlib from "zlib";
|
|
14766
14770
|
|
|
14767
14771
|
// node_modules/axios/lib/env/data.js
|
|
14768
|
-
var VERSION = "1.
|
|
14772
|
+
var VERSION = "1.12.2";
|
|
14769
14773
|
|
|
14770
14774
|
// node_modules/axios/lib/helpers/parseProtocol.js
|
|
14771
14775
|
function parseProtocol(url2) {
|
|
@@ -15164,6 +15168,60 @@ var progressEventDecorator = (total, throttled) => {
|
|
|
15164
15168
|
};
|
|
15165
15169
|
var asyncDecorator = (fn) => (...args) => utils_default.asap(() => fn(...args));
|
|
15166
15170
|
|
|
15171
|
+
// node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js
|
|
15172
|
+
function estimateDataURLDecodedBytes(url2) {
|
|
15173
|
+
if (!url2 || typeof url2 !== "string")
|
|
15174
|
+
return 0;
|
|
15175
|
+
if (!url2.startsWith("data:"))
|
|
15176
|
+
return 0;
|
|
15177
|
+
const comma = url2.indexOf(",");
|
|
15178
|
+
if (comma < 0)
|
|
15179
|
+
return 0;
|
|
15180
|
+
const meta = url2.slice(5, comma);
|
|
15181
|
+
const body = url2.slice(comma + 1);
|
|
15182
|
+
const isBase64 = /;base64/i.test(meta);
|
|
15183
|
+
if (isBase64) {
|
|
15184
|
+
let effectiveLen = body.length;
|
|
15185
|
+
const len = body.length;
|
|
15186
|
+
for (let i = 0; i < len; i++) {
|
|
15187
|
+
if (body.charCodeAt(i) === 37 && i + 2 < len) {
|
|
15188
|
+
const a = body.charCodeAt(i + 1);
|
|
15189
|
+
const b = body.charCodeAt(i + 2);
|
|
15190
|
+
const isHex = (a >= 48 && a <= 57 || a >= 65 && a <= 70 || a >= 97 && a <= 102) && (b >= 48 && b <= 57 || b >= 65 && b <= 70 || b >= 97 && b <= 102);
|
|
15191
|
+
if (isHex) {
|
|
15192
|
+
effectiveLen -= 2;
|
|
15193
|
+
i += 2;
|
|
15194
|
+
}
|
|
15195
|
+
}
|
|
15196
|
+
}
|
|
15197
|
+
let pad = 0;
|
|
15198
|
+
let idx = len - 1;
|
|
15199
|
+
const tailIsPct3D = (j) => j >= 2 && body.charCodeAt(j - 2) === 37 && // '%'
|
|
15200
|
+
body.charCodeAt(j - 1) === 51 && // '3'
|
|
15201
|
+
(body.charCodeAt(j) === 68 || body.charCodeAt(j) === 100);
|
|
15202
|
+
if (idx >= 0) {
|
|
15203
|
+
if (body.charCodeAt(idx) === 61) {
|
|
15204
|
+
pad++;
|
|
15205
|
+
idx--;
|
|
15206
|
+
} else if (tailIsPct3D(idx)) {
|
|
15207
|
+
pad++;
|
|
15208
|
+
idx -= 3;
|
|
15209
|
+
}
|
|
15210
|
+
}
|
|
15211
|
+
if (pad === 1 && idx >= 0) {
|
|
15212
|
+
if (body.charCodeAt(idx) === 61) {
|
|
15213
|
+
pad++;
|
|
15214
|
+
} else if (tailIsPct3D(idx)) {
|
|
15215
|
+
pad++;
|
|
15216
|
+
}
|
|
15217
|
+
}
|
|
15218
|
+
const groups = Math.floor(effectiveLen / 4);
|
|
15219
|
+
const bytes = groups * 3 - (pad || 0);
|
|
15220
|
+
return bytes > 0 ? bytes : 0;
|
|
15221
|
+
}
|
|
15222
|
+
return Buffer.byteLength(body, "utf8");
|
|
15223
|
+
}
|
|
15224
|
+
|
|
15167
15225
|
// node_modules/axios/lib/adapters/http.js
|
|
15168
15226
|
var zlibOptions = {
|
|
15169
15227
|
flush: zlib.constants.Z_SYNC_FLUSH,
|
|
@@ -15307,6 +15365,17 @@ var http_default = isHttpAdapterSupported && function httpAdapter(config2) {
|
|
|
15307
15365
|
const parsed = new URL(fullPath, platform_default.hasBrowserEnv ? platform_default.origin : void 0);
|
|
15308
15366
|
const protocol = parsed.protocol || supportedProtocols[0];
|
|
15309
15367
|
if (protocol === "data:") {
|
|
15368
|
+
if (config2.maxContentLength > -1) {
|
|
15369
|
+
const dataUrl = String(config2.url || fullPath || "");
|
|
15370
|
+
const estimated = estimateDataURLDecodedBytes(dataUrl);
|
|
15371
|
+
if (estimated > config2.maxContentLength) {
|
|
15372
|
+
return reject(new AxiosError_default(
|
|
15373
|
+
"maxContentLength size of " + config2.maxContentLength + " exceeded",
|
|
15374
|
+
AxiosError_default.ERR_BAD_RESPONSE,
|
|
15375
|
+
config2
|
|
15376
|
+
));
|
|
15377
|
+
}
|
|
15378
|
+
}
|
|
15310
15379
|
let convertedData;
|
|
15311
15380
|
if (method !== "GET") {
|
|
15312
15381
|
return settle(resolve, reject, {
|
|
@@ -15802,13 +15871,17 @@ var resolveConfig_default = (config2) => {
|
|
|
15802
15871
|
"Basic " + btoa((auth.username || "") + ":" + (auth.password ? unescape(encodeURIComponent(auth.password)) : ""))
|
|
15803
15872
|
);
|
|
15804
15873
|
}
|
|
15805
|
-
let contentType;
|
|
15806
15874
|
if (utils_default.isFormData(data)) {
|
|
15807
15875
|
if (platform_default.hasStandardBrowserEnv || platform_default.hasStandardBrowserWebWorkerEnv) {
|
|
15808
15876
|
headers.setContentType(void 0);
|
|
15809
|
-
} else if ((
|
|
15810
|
-
const
|
|
15811
|
-
|
|
15877
|
+
} else if (utils_default.isFunction(data.getHeaders)) {
|
|
15878
|
+
const formHeaders = data.getHeaders();
|
|
15879
|
+
const allowedHeaders = ["content-type", "content-length"];
|
|
15880
|
+
Object.entries(formHeaders).forEach(([key, val]) => {
|
|
15881
|
+
if (allowedHeaders.includes(key.toLowerCase())) {
|
|
15882
|
+
headers.set(key, val);
|
|
15883
|
+
}
|
|
15884
|
+
});
|
|
15812
15885
|
}
|
|
15813
15886
|
}
|
|
15814
15887
|
if (platform_default.hasStandardBrowserEnv) {
|
|
@@ -15888,8 +15961,11 @@ var xhr_default = isXHRAdapterSupported && function(config2) {
|
|
|
15888
15961
|
reject(new AxiosError_default("Request aborted", AxiosError_default.ECONNABORTED, config2, request));
|
|
15889
15962
|
request = null;
|
|
15890
15963
|
};
|
|
15891
|
-
request.onerror = function handleError() {
|
|
15892
|
-
|
|
15964
|
+
request.onerror = function handleError(event) {
|
|
15965
|
+
const msg = event && event.message ? event.message : "Network Error";
|
|
15966
|
+
const err = new AxiosError_default(msg, AxiosError_default.ERR_NETWORK, config2, request);
|
|
15967
|
+
err.event = event || null;
|
|
15968
|
+
reject(err);
|
|
15893
15969
|
request = null;
|
|
15894
15970
|
};
|
|
15895
15971
|
request.ontimeout = function handleTimeout() {
|
|
@@ -16064,9 +16140,16 @@ var trackStream = (stream4, chunkSize, onProgress, onFinish) => {
|
|
|
16064
16140
|
};
|
|
16065
16141
|
|
|
16066
16142
|
// node_modules/axios/lib/adapters/fetch.js
|
|
16067
|
-
var
|
|
16068
|
-
var
|
|
16069
|
-
var
|
|
16143
|
+
var DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|
16144
|
+
var { isFunction: isFunction2 } = utils_default;
|
|
16145
|
+
var globalFetchAPI = (({ Request, Response }) => ({
|
|
16146
|
+
Request,
|
|
16147
|
+
Response
|
|
16148
|
+
}))(utils_default.global);
|
|
16149
|
+
var {
|
|
16150
|
+
ReadableStream: ReadableStream2,
|
|
16151
|
+
TextEncoder: TextEncoder2
|
|
16152
|
+
} = utils_default.global;
|
|
16070
16153
|
var test = (fn, ...args) => {
|
|
16071
16154
|
try {
|
|
16072
16155
|
return !!fn(...args);
|
|
@@ -16074,164 +16157,204 @@ var test = (fn, ...args) => {
|
|
|
16074
16157
|
return false;
|
|
16075
16158
|
}
|
|
16076
16159
|
};
|
|
16077
|
-
var
|
|
16078
|
-
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
|
|
16082
|
-
|
|
16083
|
-
|
|
16084
|
-
|
|
16085
|
-
|
|
16086
|
-
|
|
16087
|
-
return duplexAccessed && !hasContentType;
|
|
16088
|
-
});
|
|
16089
|
-
var DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|
16090
|
-
var supportsResponseStream = isReadableStreamSupported && test(() => utils_default.isReadableStream(new Response("").body));
|
|
16091
|
-
var resolvers = {
|
|
16092
|
-
stream: supportsResponseStream && ((res) => res.body)
|
|
16093
|
-
};
|
|
16094
|
-
isFetchSupported && ((res) => {
|
|
16095
|
-
["text", "arrayBuffer", "blob", "formData", "stream"].forEach((type) => {
|
|
16096
|
-
!resolvers[type] && (resolvers[type] = utils_default.isFunction(res[type]) ? (res2) => res2[type]() : (_, config2) => {
|
|
16097
|
-
throw new AxiosError_default(`Response type '${type}' is not supported`, AxiosError_default.ERR_NOT_SUPPORT, config2);
|
|
16098
|
-
});
|
|
16099
|
-
});
|
|
16100
|
-
})(new Response());
|
|
16101
|
-
var getBodyLength = async (body) => {
|
|
16102
|
-
if (body == null) {
|
|
16103
|
-
return 0;
|
|
16104
|
-
}
|
|
16105
|
-
if (utils_default.isBlob(body)) {
|
|
16106
|
-
return body.size;
|
|
16160
|
+
var factory = (env) => {
|
|
16161
|
+
env = utils_default.merge.call({
|
|
16162
|
+
skipUndefined: true
|
|
16163
|
+
}, globalFetchAPI, env);
|
|
16164
|
+
const { fetch: envFetch, Request, Response } = env;
|
|
16165
|
+
const isFetchSupported = envFetch ? isFunction2(envFetch) : typeof fetch === "function";
|
|
16166
|
+
const isRequestSupported = isFunction2(Request);
|
|
16167
|
+
const isResponseSupported = isFunction2(Response);
|
|
16168
|
+
if (!isFetchSupported) {
|
|
16169
|
+
return false;
|
|
16107
16170
|
}
|
|
16108
|
-
|
|
16109
|
-
|
|
16171
|
+
const isReadableStreamSupported = isFetchSupported && isFunction2(ReadableStream2);
|
|
16172
|
+
const encodeText = isFetchSupported && (typeof TextEncoder2 === "function" ? ((encoder) => (str) => encoder.encode(str))(new TextEncoder2()) : async (str) => new Uint8Array(await new Request(str).arrayBuffer()));
|
|
16173
|
+
const supportsRequestStream = isRequestSupported && isReadableStreamSupported && test(() => {
|
|
16174
|
+
let duplexAccessed = false;
|
|
16175
|
+
const hasContentType = new Request(platform_default.origin, {
|
|
16176
|
+
body: new ReadableStream2(),
|
|
16110
16177
|
method: "POST",
|
|
16111
|
-
|
|
16112
|
-
|
|
16113
|
-
|
|
16114
|
-
|
|
16115
|
-
|
|
16116
|
-
return
|
|
16117
|
-
}
|
|
16118
|
-
if (utils_default.isURLSearchParams(body)) {
|
|
16119
|
-
body = body + "";
|
|
16120
|
-
}
|
|
16121
|
-
if (utils_default.isString(body)) {
|
|
16122
|
-
return (await encodeText(body)).byteLength;
|
|
16123
|
-
}
|
|
16124
|
-
};
|
|
16125
|
-
var resolveBodyLength = async (headers, body) => {
|
|
16126
|
-
const length = utils_default.toFiniteNumber(headers.getContentLength());
|
|
16127
|
-
return length == null ? getBodyLength(body) : length;
|
|
16128
|
-
};
|
|
16129
|
-
var fetch_default = isFetchSupported && (async (config2) => {
|
|
16130
|
-
let {
|
|
16131
|
-
url: url2,
|
|
16132
|
-
method,
|
|
16133
|
-
data,
|
|
16134
|
-
signal,
|
|
16135
|
-
cancelToken,
|
|
16136
|
-
timeout,
|
|
16137
|
-
onDownloadProgress,
|
|
16138
|
-
onUploadProgress,
|
|
16139
|
-
responseType,
|
|
16140
|
-
headers,
|
|
16141
|
-
withCredentials = "same-origin",
|
|
16142
|
-
fetchOptions
|
|
16143
|
-
} = resolveConfig_default(config2);
|
|
16144
|
-
responseType = responseType ? (responseType + "").toLowerCase() : "text";
|
|
16145
|
-
let composedSignal = composeSignals_default([signal, cancelToken && cancelToken.toAbortSignal()], timeout);
|
|
16146
|
-
let request;
|
|
16147
|
-
const unsubscribe = composedSignal && composedSignal.unsubscribe && (() => {
|
|
16148
|
-
composedSignal.unsubscribe();
|
|
16178
|
+
get duplex() {
|
|
16179
|
+
duplexAccessed = true;
|
|
16180
|
+
return "half";
|
|
16181
|
+
}
|
|
16182
|
+
}).headers.has("Content-Type");
|
|
16183
|
+
return duplexAccessed && !hasContentType;
|
|
16149
16184
|
});
|
|
16150
|
-
|
|
16151
|
-
|
|
16152
|
-
|
|
16153
|
-
|
|
16185
|
+
const supportsResponseStream = isResponseSupported && isReadableStreamSupported && test(() => utils_default.isReadableStream(new Response("").body));
|
|
16186
|
+
const resolvers = {
|
|
16187
|
+
stream: supportsResponseStream && ((res) => res.body)
|
|
16188
|
+
};
|
|
16189
|
+
isFetchSupported && (() => {
|
|
16190
|
+
["text", "arrayBuffer", "blob", "formData", "stream"].forEach((type) => {
|
|
16191
|
+
!resolvers[type] && (resolvers[type] = (res, config2) => {
|
|
16192
|
+
let method = res && res[type];
|
|
16193
|
+
if (method) {
|
|
16194
|
+
return method.call(res);
|
|
16195
|
+
}
|
|
16196
|
+
throw new AxiosError_default(`Response type '${type}' is not supported`, AxiosError_default.ERR_NOT_SUPPORT, config2);
|
|
16197
|
+
});
|
|
16198
|
+
});
|
|
16199
|
+
})();
|
|
16200
|
+
const getBodyLength = async (body) => {
|
|
16201
|
+
if (body == null) {
|
|
16202
|
+
return 0;
|
|
16203
|
+
}
|
|
16204
|
+
if (utils_default.isBlob(body)) {
|
|
16205
|
+
return body.size;
|
|
16206
|
+
}
|
|
16207
|
+
if (utils_default.isSpecCompliantForm(body)) {
|
|
16208
|
+
const _request = new Request(platform_default.origin, {
|
|
16154
16209
|
method: "POST",
|
|
16155
|
-
body
|
|
16156
|
-
duplex: "half"
|
|
16210
|
+
body
|
|
16157
16211
|
});
|
|
16158
|
-
|
|
16159
|
-
if (utils_default.isFormData(data) && (contentTypeHeader = _request.headers.get("content-type"))) {
|
|
16160
|
-
headers.setContentType(contentTypeHeader);
|
|
16161
|
-
}
|
|
16162
|
-
if (_request.body) {
|
|
16163
|
-
const [onProgress, flush] = progressEventDecorator(
|
|
16164
|
-
requestContentLength,
|
|
16165
|
-
progressEventReducer(asyncDecorator(onUploadProgress))
|
|
16166
|
-
);
|
|
16167
|
-
data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush);
|
|
16168
|
-
}
|
|
16212
|
+
return (await _request.arrayBuffer()).byteLength;
|
|
16169
16213
|
}
|
|
16170
|
-
if (
|
|
16171
|
-
|
|
16214
|
+
if (utils_default.isArrayBufferView(body) || utils_default.isArrayBuffer(body)) {
|
|
16215
|
+
return body.byteLength;
|
|
16172
16216
|
}
|
|
16173
|
-
|
|
16174
|
-
|
|
16175
|
-
...fetchOptions,
|
|
16176
|
-
signal: composedSignal,
|
|
16177
|
-
method: method.toUpperCase(),
|
|
16178
|
-
headers: headers.normalize().toJSON(),
|
|
16179
|
-
body: data,
|
|
16180
|
-
duplex: "half",
|
|
16181
|
-
credentials: isCredentialsSupported ? withCredentials : void 0
|
|
16182
|
-
});
|
|
16183
|
-
let response = await fetch(request, fetchOptions);
|
|
16184
|
-
const isStreamResponse = supportsResponseStream && (responseType === "stream" || responseType === "response");
|
|
16185
|
-
if (supportsResponseStream && (onDownloadProgress || isStreamResponse && unsubscribe)) {
|
|
16186
|
-
const options = {};
|
|
16187
|
-
["status", "statusText", "headers"].forEach((prop) => {
|
|
16188
|
-
options[prop] = response[prop];
|
|
16189
|
-
});
|
|
16190
|
-
const responseContentLength = utils_default.toFiniteNumber(response.headers.get("content-length"));
|
|
16191
|
-
const [onProgress, flush] = onDownloadProgress && progressEventDecorator(
|
|
16192
|
-
responseContentLength,
|
|
16193
|
-
progressEventReducer(asyncDecorator(onDownloadProgress), true)
|
|
16194
|
-
) || [];
|
|
16195
|
-
response = new Response(
|
|
16196
|
-
trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => {
|
|
16197
|
-
flush && flush();
|
|
16198
|
-
unsubscribe && unsubscribe();
|
|
16199
|
-
}),
|
|
16200
|
-
options
|
|
16201
|
-
);
|
|
16217
|
+
if (utils_default.isURLSearchParams(body)) {
|
|
16218
|
+
body = body + "";
|
|
16202
16219
|
}
|
|
16203
|
-
|
|
16204
|
-
|
|
16205
|
-
|
|
16206
|
-
|
|
16207
|
-
|
|
16208
|
-
|
|
16209
|
-
|
|
16210
|
-
|
|
16211
|
-
|
|
16212
|
-
|
|
16213
|
-
|
|
16214
|
-
|
|
16220
|
+
if (utils_default.isString(body)) {
|
|
16221
|
+
return (await encodeText(body)).byteLength;
|
|
16222
|
+
}
|
|
16223
|
+
};
|
|
16224
|
+
const resolveBodyLength = async (headers, body) => {
|
|
16225
|
+
const length = utils_default.toFiniteNumber(headers.getContentLength());
|
|
16226
|
+
return length == null ? getBodyLength(body) : length;
|
|
16227
|
+
};
|
|
16228
|
+
return async (config2) => {
|
|
16229
|
+
let {
|
|
16230
|
+
url: url2,
|
|
16231
|
+
method,
|
|
16232
|
+
data,
|
|
16233
|
+
signal,
|
|
16234
|
+
cancelToken,
|
|
16235
|
+
timeout,
|
|
16236
|
+
onDownloadProgress,
|
|
16237
|
+
onUploadProgress,
|
|
16238
|
+
responseType,
|
|
16239
|
+
headers,
|
|
16240
|
+
withCredentials = "same-origin",
|
|
16241
|
+
fetchOptions
|
|
16242
|
+
} = resolveConfig_default(config2);
|
|
16243
|
+
let _fetch = envFetch || fetch;
|
|
16244
|
+
responseType = responseType ? (responseType + "").toLowerCase() : "text";
|
|
16245
|
+
let composedSignal = composeSignals_default([signal, cancelToken && cancelToken.toAbortSignal()], timeout);
|
|
16246
|
+
let request = null;
|
|
16247
|
+
const unsubscribe = composedSignal && composedSignal.unsubscribe && (() => {
|
|
16248
|
+
composedSignal.unsubscribe();
|
|
16215
16249
|
});
|
|
16216
|
-
|
|
16217
|
-
|
|
16218
|
-
|
|
16219
|
-
|
|
16220
|
-
|
|
16221
|
-
|
|
16222
|
-
|
|
16250
|
+
let requestContentLength;
|
|
16251
|
+
try {
|
|
16252
|
+
if (onUploadProgress && supportsRequestStream && method !== "get" && method !== "head" && (requestContentLength = await resolveBodyLength(headers, data)) !== 0) {
|
|
16253
|
+
let _request = new Request(url2, {
|
|
16254
|
+
method: "POST",
|
|
16255
|
+
body: data,
|
|
16256
|
+
duplex: "half"
|
|
16257
|
+
});
|
|
16258
|
+
let contentTypeHeader;
|
|
16259
|
+
if (utils_default.isFormData(data) && (contentTypeHeader = _request.headers.get("content-type"))) {
|
|
16260
|
+
headers.setContentType(contentTypeHeader);
|
|
16223
16261
|
}
|
|
16224
|
-
|
|
16262
|
+
if (_request.body) {
|
|
16263
|
+
const [onProgress, flush] = progressEventDecorator(
|
|
16264
|
+
requestContentLength,
|
|
16265
|
+
progressEventReducer(asyncDecorator(onUploadProgress))
|
|
16266
|
+
);
|
|
16267
|
+
data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush);
|
|
16268
|
+
}
|
|
16269
|
+
}
|
|
16270
|
+
if (!utils_default.isString(withCredentials)) {
|
|
16271
|
+
withCredentials = withCredentials ? "include" : "omit";
|
|
16272
|
+
}
|
|
16273
|
+
const isCredentialsSupported = isRequestSupported && "credentials" in Request.prototype;
|
|
16274
|
+
const resolvedOptions = {
|
|
16275
|
+
...fetchOptions,
|
|
16276
|
+
signal: composedSignal,
|
|
16277
|
+
method: method.toUpperCase(),
|
|
16278
|
+
headers: headers.normalize().toJSON(),
|
|
16279
|
+
body: data,
|
|
16280
|
+
duplex: "half",
|
|
16281
|
+
credentials: isCredentialsSupported ? withCredentials : void 0
|
|
16282
|
+
};
|
|
16283
|
+
request = isRequestSupported && new Request(url2, resolvedOptions);
|
|
16284
|
+
let response = await (isRequestSupported ? _fetch(request, fetchOptions) : _fetch(url2, resolvedOptions));
|
|
16285
|
+
const isStreamResponse = supportsResponseStream && (responseType === "stream" || responseType === "response");
|
|
16286
|
+
if (supportsResponseStream && (onDownloadProgress || isStreamResponse && unsubscribe)) {
|
|
16287
|
+
const options = {};
|
|
16288
|
+
["status", "statusText", "headers"].forEach((prop) => {
|
|
16289
|
+
options[prop] = response[prop];
|
|
16290
|
+
});
|
|
16291
|
+
const responseContentLength = utils_default.toFiniteNumber(response.headers.get("content-length"));
|
|
16292
|
+
const [onProgress, flush] = onDownloadProgress && progressEventDecorator(
|
|
16293
|
+
responseContentLength,
|
|
16294
|
+
progressEventReducer(asyncDecorator(onDownloadProgress), true)
|
|
16295
|
+
) || [];
|
|
16296
|
+
response = new Response(
|
|
16297
|
+
trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => {
|
|
16298
|
+
flush && flush();
|
|
16299
|
+
unsubscribe && unsubscribe();
|
|
16300
|
+
}),
|
|
16301
|
+
options
|
|
16302
|
+
);
|
|
16303
|
+
}
|
|
16304
|
+
responseType = responseType || "text";
|
|
16305
|
+
let responseData = await resolvers[utils_default.findKey(resolvers, responseType) || "text"](response, config2);
|
|
16306
|
+
!isStreamResponse && unsubscribe && unsubscribe();
|
|
16307
|
+
return await new Promise((resolve, reject) => {
|
|
16308
|
+
settle(resolve, reject, {
|
|
16309
|
+
data: responseData,
|
|
16310
|
+
headers: AxiosHeaders_default.from(response.headers),
|
|
16311
|
+
status: response.status,
|
|
16312
|
+
statusText: response.statusText,
|
|
16313
|
+
config: config2,
|
|
16314
|
+
request
|
|
16315
|
+
});
|
|
16316
|
+
});
|
|
16317
|
+
} catch (err) {
|
|
16318
|
+
unsubscribe && unsubscribe();
|
|
16319
|
+
if (err && err.name === "TypeError" && /Load failed|fetch/i.test(err.message)) {
|
|
16320
|
+
throw Object.assign(
|
|
16321
|
+
new AxiosError_default("Network Error", AxiosError_default.ERR_NETWORK, config2, request),
|
|
16322
|
+
{
|
|
16323
|
+
cause: err.cause || err
|
|
16324
|
+
}
|
|
16325
|
+
);
|
|
16326
|
+
}
|
|
16327
|
+
throw AxiosError_default.from(err, err && err.code, config2, request);
|
|
16225
16328
|
}
|
|
16226
|
-
|
|
16227
|
-
|
|
16228
|
-
|
|
16329
|
+
};
|
|
16330
|
+
};
|
|
16331
|
+
var seedCache = /* @__PURE__ */ new Map();
|
|
16332
|
+
var getFetch = (config2) => {
|
|
16333
|
+
let env = config2 ? config2.env : {};
|
|
16334
|
+
const { fetch: fetch2, Request, Response } = env;
|
|
16335
|
+
const seeds = [
|
|
16336
|
+
Request,
|
|
16337
|
+
Response,
|
|
16338
|
+
fetch2
|
|
16339
|
+
];
|
|
16340
|
+
let len = seeds.length, i = len, seed, target, map = seedCache;
|
|
16341
|
+
while (i--) {
|
|
16342
|
+
seed = seeds[i];
|
|
16343
|
+
target = map.get(seed);
|
|
16344
|
+
target === void 0 && map.set(seed, target = i ? /* @__PURE__ */ new Map() : factory(env));
|
|
16345
|
+
map = target;
|
|
16346
|
+
}
|
|
16347
|
+
return target;
|
|
16348
|
+
};
|
|
16349
|
+
var adapter = getFetch();
|
|
16229
16350
|
|
|
16230
16351
|
// node_modules/axios/lib/adapters/adapters.js
|
|
16231
16352
|
var knownAdapters = {
|
|
16232
16353
|
http: http_default,
|
|
16233
16354
|
xhr: xhr_default,
|
|
16234
|
-
fetch:
|
|
16355
|
+
fetch: {
|
|
16356
|
+
get: getFetch
|
|
16357
|
+
}
|
|
16235
16358
|
};
|
|
16236
16359
|
utils_default.forEach(knownAdapters, (fn, value) => {
|
|
16237
16360
|
if (fn) {
|
|
@@ -16243,30 +16366,30 @@ utils_default.forEach(knownAdapters, (fn, value) => {
|
|
|
16243
16366
|
}
|
|
16244
16367
|
});
|
|
16245
16368
|
var renderReason = (reason) => `- ${reason}`;
|
|
16246
|
-
var isResolvedHandle = (
|
|
16369
|
+
var isResolvedHandle = (adapter2) => utils_default.isFunction(adapter2) || adapter2 === null || adapter2 === false;
|
|
16247
16370
|
var adapters_default = {
|
|
16248
|
-
getAdapter: (adapters) => {
|
|
16371
|
+
getAdapter: (adapters, config2) => {
|
|
16249
16372
|
adapters = utils_default.isArray(adapters) ? adapters : [adapters];
|
|
16250
16373
|
const { length } = adapters;
|
|
16251
16374
|
let nameOrAdapter;
|
|
16252
|
-
let
|
|
16375
|
+
let adapter2;
|
|
16253
16376
|
const rejectedReasons = {};
|
|
16254
16377
|
for (let i = 0; i < length; i++) {
|
|
16255
16378
|
nameOrAdapter = adapters[i];
|
|
16256
16379
|
let id;
|
|
16257
|
-
|
|
16380
|
+
adapter2 = nameOrAdapter;
|
|
16258
16381
|
if (!isResolvedHandle(nameOrAdapter)) {
|
|
16259
|
-
|
|
16260
|
-
if (
|
|
16382
|
+
adapter2 = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];
|
|
16383
|
+
if (adapter2 === void 0) {
|
|
16261
16384
|
throw new AxiosError_default(`Unknown adapter '${id}'`);
|
|
16262
16385
|
}
|
|
16263
16386
|
}
|
|
16264
|
-
if (
|
|
16387
|
+
if (adapter2 && (utils_default.isFunction(adapter2) || (adapter2 = adapter2.get(config2)))) {
|
|
16265
16388
|
break;
|
|
16266
16389
|
}
|
|
16267
|
-
rejectedReasons[id || "#" + i] =
|
|
16390
|
+
rejectedReasons[id || "#" + i] = adapter2;
|
|
16268
16391
|
}
|
|
16269
|
-
if (!
|
|
16392
|
+
if (!adapter2) {
|
|
16270
16393
|
const reasons = Object.entries(rejectedReasons).map(
|
|
16271
16394
|
([id, state]) => `adapter ${id} ` + (state === false ? "is not supported by the environment" : "is not available in the build")
|
|
16272
16395
|
);
|
|
@@ -16276,7 +16399,7 @@ var adapters_default = {
|
|
|
16276
16399
|
"ERR_NOT_SUPPORT"
|
|
16277
16400
|
);
|
|
16278
16401
|
}
|
|
16279
|
-
return
|
|
16402
|
+
return adapter2;
|
|
16280
16403
|
},
|
|
16281
16404
|
adapters: knownAdapters
|
|
16282
16405
|
};
|
|
@@ -16300,8 +16423,8 @@ function dispatchRequest(config2) {
|
|
|
16300
16423
|
if (["post", "put", "patch"].indexOf(config2.method) !== -1) {
|
|
16301
16424
|
config2.headers.setContentType("application/x-www-form-urlencoded", false);
|
|
16302
16425
|
}
|
|
16303
|
-
const
|
|
16304
|
-
return
|
|
16426
|
+
const adapter2 = adapters_default.getAdapter(config2.adapter || defaults_default.adapter, config2);
|
|
16427
|
+
return adapter2(config2).then(function onAdapterResolution(response) {
|
|
16305
16428
|
throwIfCancellationRequested(config2);
|
|
16306
16429
|
response.data = transformData.call(
|
|
16307
16430
|
config2,
|
|
@@ -16507,7 +16630,6 @@ var Axios = class {
|
|
|
16507
16630
|
}
|
|
16508
16631
|
len = requestInterceptorChain.length;
|
|
16509
16632
|
let newConfig = config2;
|
|
16510
|
-
i = 0;
|
|
16511
16633
|
while (i < len) {
|
|
16512
16634
|
const onFulfilled = requestInterceptorChain[i++];
|
|
16513
16635
|
const onRejected = requestInterceptorChain[i++];
|
|
@@ -26365,11 +26487,8 @@ function useDivisionController() {
|
|
|
26365
26487
|
return;
|
|
26366
26488
|
}
|
|
26367
26489
|
try {
|
|
26368
|
-
const
|
|
26369
|
-
res.json(
|
|
26370
|
-
message: "Successfully retrieved division.",
|
|
26371
|
-
data: { division }
|
|
26372
|
-
});
|
|
26490
|
+
const data = await _getById(id);
|
|
26491
|
+
res.json(data);
|
|
26373
26492
|
return;
|
|
26374
26493
|
} catch (error2) {
|
|
26375
26494
|
next(error2);
|
|
@@ -26456,16 +26575,17 @@ import Joi31 from "joi";
|
|
|
26456
26575
|
import { ObjectId as ObjectId37 } from "mongodb";
|
|
26457
26576
|
var schemaSchool = Joi31.object({
|
|
26458
26577
|
_id: Joi31.string().hex().optional().allow("", null),
|
|
26459
|
-
id: Joi31.string().
|
|
26460
|
-
name: Joi31.string().
|
|
26461
|
-
country: Joi31.string().
|
|
26462
|
-
address: Joi31.string().
|
|
26578
|
+
id: Joi31.string().optional().allow("", null),
|
|
26579
|
+
name: Joi31.string().optional().allow("", null),
|
|
26580
|
+
country: Joi31.string().optional().allow("", null),
|
|
26581
|
+
address: Joi31.string().optional().allow("", null),
|
|
26463
26582
|
continuedAddress: Joi31.string().optional().allow("", null),
|
|
26464
|
-
city: Joi31.string().required(),
|
|
26465
|
-
province: Joi31.string().required(),
|
|
26466
|
-
|
|
26467
|
-
|
|
26468
|
-
|
|
26583
|
+
city: Joi31.string().required().allow("", null),
|
|
26584
|
+
province: Joi31.string().required().allow("", null),
|
|
26585
|
+
district: Joi31.string().optional().allow("", null),
|
|
26586
|
+
postalCode: Joi31.string().required().allow("", null),
|
|
26587
|
+
courses: Joi31.array().items(Joi31.string()).optional(),
|
|
26588
|
+
principalName: Joi31.string().required().allow("", null),
|
|
26469
26589
|
principalEmail: Joi31.string().email().optional().allow("", null),
|
|
26470
26590
|
principalNumber: Joi31.string().optional().allow("", null),
|
|
26471
26591
|
region: Joi31.string().hex().required(),
|
|
@@ -26475,7 +26595,7 @@ var schemaSchool = Joi31.object({
|
|
|
26475
26595
|
status: Joi31.string().optional().allow(null, ""),
|
|
26476
26596
|
createdAt: Joi31.date().optional().allow("", null),
|
|
26477
26597
|
updatedAt: Joi31.date().optional().allow("", null),
|
|
26478
|
-
createdBy: Joi31.string().hex().
|
|
26598
|
+
createdBy: Joi31.string().hex().optional().allow("", null)
|
|
26479
26599
|
});
|
|
26480
26600
|
function MSchool(value) {
|
|
26481
26601
|
const { error } = schemaSchool.validate(value);
|
|
@@ -26514,15 +26634,15 @@ function MSchool(value) {
|
|
|
26514
26634
|
_id: value._id ? value._id : new ObjectId37(),
|
|
26515
26635
|
id: value.id,
|
|
26516
26636
|
name: value.name,
|
|
26517
|
-
country: value.country,
|
|
26518
|
-
address: value.address,
|
|
26637
|
+
country: value.country ?? "",
|
|
26638
|
+
address: value.address ?? "",
|
|
26519
26639
|
continuedAddress: value.continuedAddress ?? "",
|
|
26520
|
-
city: value.city,
|
|
26521
|
-
province: value.province,
|
|
26522
|
-
postalCode: value.postalCode,
|
|
26640
|
+
city: value.city ?? "",
|
|
26641
|
+
province: value.province ?? "",
|
|
26642
|
+
postalCode: value.postalCode ?? "",
|
|
26523
26643
|
courses: value.courses || [],
|
|
26524
|
-
principalName: value.principalName,
|
|
26525
|
-
principalEmail: value.principalEmail,
|
|
26644
|
+
principalName: value.principalName ?? "",
|
|
26645
|
+
principalEmail: value.principalEmail ?? "",
|
|
26526
26646
|
principalNumber: value.principalNumber ?? "",
|
|
26527
26647
|
region: value.region,
|
|
26528
26648
|
regionName: value.regionName ?? "",
|
|
@@ -26531,7 +26651,7 @@ function MSchool(value) {
|
|
|
26531
26651
|
createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
26532
26652
|
updatedAt: value.updatedAt ?? "",
|
|
26533
26653
|
status: value.status ?? "pending",
|
|
26534
|
-
createdBy: value.createdBy
|
|
26654
|
+
createdBy: value.createdBy ?? ""
|
|
26535
26655
|
};
|
|
26536
26656
|
}
|
|
26537
26657
|
|
|
@@ -26806,8 +26926,16 @@ function useSchoolRepo() {
|
|
|
26806
26926
|
|
|
26807
26927
|
// src/services/school.service.ts
|
|
26808
26928
|
import { BadRequestError as BadRequestError57, useAtlas as useAtlas30, logger as logger28 } from "@eeplatform/nodejs-utils";
|
|
26929
|
+
import * as XLSX from "xlsx";
|
|
26930
|
+
import * as Papa from "papaparse";
|
|
26931
|
+
import * as BSON from "bson";
|
|
26809
26932
|
function useSchoolService() {
|
|
26810
|
-
const {
|
|
26933
|
+
const {
|
|
26934
|
+
add: addSchool,
|
|
26935
|
+
getPendingByCreatedBy,
|
|
26936
|
+
updateStatusById,
|
|
26937
|
+
getPendingById
|
|
26938
|
+
} = useSchoolRepo();
|
|
26811
26939
|
const { addRole } = useRoleRepo();
|
|
26812
26940
|
const { getUserById } = useUserRepo();
|
|
26813
26941
|
const { add: addMember } = useMemberRepo();
|
|
@@ -26824,7 +26952,7 @@ function useSchoolService() {
|
|
|
26824
26952
|
}
|
|
26825
26953
|
try {
|
|
26826
26954
|
value.status = "pending";
|
|
26827
|
-
await
|
|
26955
|
+
await addSchool(value);
|
|
26828
26956
|
return "Request to register school has been sent successfully. Please wait for approval.";
|
|
26829
26957
|
} catch (error2) {
|
|
26830
26958
|
throw error2;
|
|
@@ -26843,7 +26971,7 @@ function useSchoolService() {
|
|
|
26843
26971
|
session.startTransaction();
|
|
26844
26972
|
school.status = "approved";
|
|
26845
26973
|
await updateStatusById(id, "active", session);
|
|
26846
|
-
const roleType = "school";
|
|
26974
|
+
const roleType = "basic-edu-school";
|
|
26847
26975
|
const roleName = "Admin";
|
|
26848
26976
|
const roleId = await addRole(
|
|
26849
26977
|
{
|
|
@@ -26888,9 +27016,245 @@ function useSchoolService() {
|
|
|
26888
27016
|
await session.endSession();
|
|
26889
27017
|
}
|
|
26890
27018
|
}
|
|
27019
|
+
async function add(value) {
|
|
27020
|
+
const { error } = schemaSchool.validate(value);
|
|
27021
|
+
if (error) {
|
|
27022
|
+
throw new BadRequestError57(error.message);
|
|
27023
|
+
}
|
|
27024
|
+
const session = useAtlas30.getClient()?.startSession();
|
|
27025
|
+
if (!session) {
|
|
27026
|
+
throw new Error("Unable to start session for school service.");
|
|
27027
|
+
}
|
|
27028
|
+
try {
|
|
27029
|
+
session.startTransaction();
|
|
27030
|
+
value.status = "active";
|
|
27031
|
+
const schoolId = await addSchool(value, session);
|
|
27032
|
+
const roleType = "basic-edu-school";
|
|
27033
|
+
const roleName = "Admin";
|
|
27034
|
+
const roleId = await addRole(
|
|
27035
|
+
{
|
|
27036
|
+
id: schoolId.toString(),
|
|
27037
|
+
type: roleType,
|
|
27038
|
+
name: roleName,
|
|
27039
|
+
permissions: ["*"],
|
|
27040
|
+
status: "active",
|
|
27041
|
+
default: true
|
|
27042
|
+
},
|
|
27043
|
+
session
|
|
27044
|
+
);
|
|
27045
|
+
if (!value.createdBy) {
|
|
27046
|
+
throw new BadRequestError57("School must have a creator.");
|
|
27047
|
+
}
|
|
27048
|
+
const user = await getUserById(value.createdBy ?? "");
|
|
27049
|
+
if (!user) {
|
|
27050
|
+
throw new BadRequestError57("User not found for the school creator.");
|
|
27051
|
+
}
|
|
27052
|
+
await addMember(
|
|
27053
|
+
{
|
|
27054
|
+
org: schoolId.toString(),
|
|
27055
|
+
orgName: value.name,
|
|
27056
|
+
user: value.createdBy.toString(),
|
|
27057
|
+
name: `${user.firstName} ${user.lastName}`,
|
|
27058
|
+
role: roleId.toString(),
|
|
27059
|
+
roleName,
|
|
27060
|
+
type: roleType
|
|
27061
|
+
},
|
|
27062
|
+
session
|
|
27063
|
+
);
|
|
27064
|
+
await session.commitTransaction();
|
|
27065
|
+
return "School has been added and activated successfully.";
|
|
27066
|
+
} catch (error2) {
|
|
27067
|
+
logger28.log({
|
|
27068
|
+
level: "error",
|
|
27069
|
+
message: `Error adding school: ${error2.message}`
|
|
27070
|
+
});
|
|
27071
|
+
await session.abortTransaction();
|
|
27072
|
+
throw error2;
|
|
27073
|
+
} finally {
|
|
27074
|
+
await session.endSession();
|
|
27075
|
+
}
|
|
27076
|
+
}
|
|
27077
|
+
async function addBulk(file, region, division) {
|
|
27078
|
+
const MAX_SIZE = 16 * 1024 * 1024;
|
|
27079
|
+
if (file.size > MAX_SIZE) {
|
|
27080
|
+
throw new BadRequestError57(
|
|
27081
|
+
"File size exceeds 16MB limit. Please use a smaller file to ensure transaction compatibility."
|
|
27082
|
+
);
|
|
27083
|
+
}
|
|
27084
|
+
let schools = [];
|
|
27085
|
+
const validatedSchools = [];
|
|
27086
|
+
const totalSize = validatedSchools.reduce(
|
|
27087
|
+
(sum, school) => sum + BSON.calculateObjectSize(school),
|
|
27088
|
+
0
|
|
27089
|
+
);
|
|
27090
|
+
try {
|
|
27091
|
+
if (file.mimetype.includes("sheet") || file.originalname.endsWith(".xlsx") || file.originalname.endsWith(".xls")) {
|
|
27092
|
+
const workbook = XLSX.read(file.buffer);
|
|
27093
|
+
const sheetName = workbook.SheetNames[0];
|
|
27094
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
27095
|
+
schools = XLSX.utils.sheet_to_json(worksheet);
|
|
27096
|
+
} else if (file.mimetype.includes("csv") || file.originalname.endsWith(".csv")) {
|
|
27097
|
+
const csvText = file.buffer.toString("utf8");
|
|
27098
|
+
const parseResult = Papa.parse(csvText, {
|
|
27099
|
+
header: true,
|
|
27100
|
+
skipEmptyLines: true,
|
|
27101
|
+
transformHeader: (header) => header.trim()
|
|
27102
|
+
});
|
|
27103
|
+
if (parseResult.errors.length > 0) {
|
|
27104
|
+
throw new BadRequestError57(
|
|
27105
|
+
`CSV parsing error: ${parseResult.errors[0].message}`
|
|
27106
|
+
);
|
|
27107
|
+
}
|
|
27108
|
+
schools = parseResult.data;
|
|
27109
|
+
} else {
|
|
27110
|
+
throw new BadRequestError57(
|
|
27111
|
+
"Unsupported file type. Please upload an Excel (.xlsx, .xls) or CSV (.csv) file."
|
|
27112
|
+
);
|
|
27113
|
+
}
|
|
27114
|
+
if (!schools || schools.length === 0) {
|
|
27115
|
+
throw new BadRequestError57("No data found in the uploaded file.");
|
|
27116
|
+
}
|
|
27117
|
+
const errors = [];
|
|
27118
|
+
for (let i = 0; i < schools.length; i++) {
|
|
27119
|
+
const schoolData = schools[i];
|
|
27120
|
+
const rowNumber = i + 1;
|
|
27121
|
+
try {
|
|
27122
|
+
const schoolName = schoolData.schoolName || schoolData.name || "";
|
|
27123
|
+
const schoolId = schoolData.schoolId || schoolData.id || "";
|
|
27124
|
+
const district = schoolData.district || "";
|
|
27125
|
+
if (!schoolName.trim()) {
|
|
27126
|
+
errors.push(`Row ${rowNumber}: School name is required`);
|
|
27127
|
+
continue;
|
|
27128
|
+
}
|
|
27129
|
+
if (!schoolId.trim()) {
|
|
27130
|
+
errors.push(`Row ${rowNumber}: School ID is required`);
|
|
27131
|
+
continue;
|
|
27132
|
+
}
|
|
27133
|
+
if (!district.trim()) {
|
|
27134
|
+
errors.push(`Row ${rowNumber}: District is required`);
|
|
27135
|
+
continue;
|
|
27136
|
+
}
|
|
27137
|
+
const school = {
|
|
27138
|
+
id: schoolId.trim(),
|
|
27139
|
+
name: schoolName.trim(),
|
|
27140
|
+
country: "Philippines",
|
|
27141
|
+
// Default country
|
|
27142
|
+
address: district.trim(),
|
|
27143
|
+
// Use district as address
|
|
27144
|
+
continuedAddress: "",
|
|
27145
|
+
city: district.trim(),
|
|
27146
|
+
// Use district as city
|
|
27147
|
+
province: "",
|
|
27148
|
+
// Will need to be set based on region/division
|
|
27149
|
+
postalCode: "",
|
|
27150
|
+
courses: [],
|
|
27151
|
+
// Empty array for courses
|
|
27152
|
+
principalName: "",
|
|
27153
|
+
principalEmail: "",
|
|
27154
|
+
principalNumber: "",
|
|
27155
|
+
region,
|
|
27156
|
+
regionName: "",
|
|
27157
|
+
// Will be populated from region lookup
|
|
27158
|
+
division,
|
|
27159
|
+
divisionName: "",
|
|
27160
|
+
// Will be populated from division lookup
|
|
27161
|
+
status: "active"
|
|
27162
|
+
};
|
|
27163
|
+
const { error } = schemaSchool.validate(school);
|
|
27164
|
+
if (error) {
|
|
27165
|
+
errors.push(`Row ${rowNumber}: ${error.message}`);
|
|
27166
|
+
continue;
|
|
27167
|
+
}
|
|
27168
|
+
validatedSchools.push(school);
|
|
27169
|
+
} catch (error) {
|
|
27170
|
+
errors.push(
|
|
27171
|
+
`Row ${rowNumber}: ${error.message || "Invalid data format"}`
|
|
27172
|
+
);
|
|
27173
|
+
}
|
|
27174
|
+
}
|
|
27175
|
+
if (errors.length > 0) {
|
|
27176
|
+
throw new BadRequestError57(
|
|
27177
|
+
`Validation errors found:
|
|
27178
|
+
${errors.slice(0, 10).join("\n")}${errors.length > 10 ? `
|
|
27179
|
+
... and ${errors.length - 10} more errors` : ""}`
|
|
27180
|
+
);
|
|
27181
|
+
}
|
|
27182
|
+
if (validatedSchools.length === 0) {
|
|
27183
|
+
throw new BadRequestError57(
|
|
27184
|
+
"No valid school records found after validation."
|
|
27185
|
+
);
|
|
27186
|
+
}
|
|
27187
|
+
if (totalSize > MAX_SIZE) {
|
|
27188
|
+
throw new BadRequestError57(
|
|
27189
|
+
`Data payload (${Math.round(
|
|
27190
|
+
totalSize / 1024 / 1024
|
|
27191
|
+
)}MB) exceeds MongoDB transaction limit of 16MB. Please reduce the number of records or split into smaller files.`
|
|
27192
|
+
);
|
|
27193
|
+
}
|
|
27194
|
+
} catch (error) {
|
|
27195
|
+
if (error instanceof BadRequestError57) {
|
|
27196
|
+
throw error;
|
|
27197
|
+
}
|
|
27198
|
+
throw new BadRequestError57(`File processing error: ${error.message}`);
|
|
27199
|
+
}
|
|
27200
|
+
const session = useAtlas30.getClient()?.startSession();
|
|
27201
|
+
if (!session) {
|
|
27202
|
+
throw new Error("Unable to start session for bulk school upload.");
|
|
27203
|
+
}
|
|
27204
|
+
try {
|
|
27205
|
+
session.startTransaction();
|
|
27206
|
+
const results = {
|
|
27207
|
+
successful: 0,
|
|
27208
|
+
failed: 0,
|
|
27209
|
+
errors: []
|
|
27210
|
+
};
|
|
27211
|
+
for (const school of validatedSchools) {
|
|
27212
|
+
try {
|
|
27213
|
+
const schoolId = await addSchool(school, session);
|
|
27214
|
+
await addRole(
|
|
27215
|
+
{
|
|
27216
|
+
id: schoolId.toString(),
|
|
27217
|
+
type: "basic-edu-school",
|
|
27218
|
+
name: "Admin",
|
|
27219
|
+
permissions: ["*"],
|
|
27220
|
+
status: "active",
|
|
27221
|
+
default: true
|
|
27222
|
+
},
|
|
27223
|
+
session
|
|
27224
|
+
);
|
|
27225
|
+
results.successful++;
|
|
27226
|
+
} catch (error) {
|
|
27227
|
+
results.failed++;
|
|
27228
|
+
results.errors.push(`School "${school.name}": ${error.message}`);
|
|
27229
|
+
}
|
|
27230
|
+
}
|
|
27231
|
+
await session.commitTransaction();
|
|
27232
|
+
return {
|
|
27233
|
+
message: `Bulk upload completed. ${results.successful} schools added successfully.`,
|
|
27234
|
+
details: {
|
|
27235
|
+
successful: results.successful,
|
|
27236
|
+
failed: results.failed,
|
|
27237
|
+
total: validatedSchools.length,
|
|
27238
|
+
totalSizeMB: Math.round(totalSize / 1024 / 1024 * 100) / 100,
|
|
27239
|
+
errors: results.errors
|
|
27240
|
+
}
|
|
27241
|
+
};
|
|
27242
|
+
} catch (error) {
|
|
27243
|
+
logger28.log({
|
|
27244
|
+
level: "error",
|
|
27245
|
+
message: `Error in bulk school upload: ${error.message}`
|
|
27246
|
+
});
|
|
27247
|
+
await session.abortTransaction();
|
|
27248
|
+
throw error;
|
|
27249
|
+
} finally {
|
|
27250
|
+
await session.endSession();
|
|
27251
|
+
}
|
|
27252
|
+
}
|
|
26891
27253
|
return {
|
|
26892
27254
|
register,
|
|
26893
|
-
approve
|
|
27255
|
+
approve,
|
|
27256
|
+
add,
|
|
27257
|
+
addBulk
|
|
26894
27258
|
};
|
|
26895
27259
|
}
|
|
26896
27260
|
|
|
@@ -26899,11 +27263,16 @@ import { BadRequestError as BadRequestError58 } from "@eeplatform/nodejs-utils";
|
|
|
26899
27263
|
import Joi32 from "joi";
|
|
26900
27264
|
function useSchoolController() {
|
|
26901
27265
|
const {
|
|
26902
|
-
add: _add,
|
|
26903
27266
|
getAll: _getAll,
|
|
26904
27267
|
getPendingByCreatedBy: _getPendingByCreatedBy,
|
|
26905
27268
|
updateStatusById: _updateStatusById
|
|
26906
27269
|
} = useSchoolRepo();
|
|
27270
|
+
const {
|
|
27271
|
+
add: _addSchool,
|
|
27272
|
+
register: _registerSchool,
|
|
27273
|
+
approve,
|
|
27274
|
+
addBulk: _addBulk
|
|
27275
|
+
} = useSchoolService();
|
|
26907
27276
|
async function add(req, res, next) {
|
|
26908
27277
|
const payload = req.body;
|
|
26909
27278
|
const { error } = schemaSchool.validate(payload);
|
|
@@ -26912,8 +27281,8 @@ function useSchoolController() {
|
|
|
26912
27281
|
return;
|
|
26913
27282
|
}
|
|
26914
27283
|
try {
|
|
26915
|
-
const
|
|
26916
|
-
res.status(201).json(
|
|
27284
|
+
const result = await _addSchool(payload);
|
|
27285
|
+
res.status(201).json({ message: result });
|
|
26917
27286
|
return;
|
|
26918
27287
|
} catch (error2) {
|
|
26919
27288
|
next(error2);
|
|
@@ -27003,7 +27372,6 @@ function useSchoolController() {
|
|
|
27003
27372
|
next(error2);
|
|
27004
27373
|
}
|
|
27005
27374
|
}
|
|
27006
|
-
const { register: _registerSchool, approve } = useSchoolService();
|
|
27007
27375
|
async function registerSchool(req, res, next) {
|
|
27008
27376
|
const payload = req.body;
|
|
27009
27377
|
const { error } = schemaSchool.validate(payload);
|
|
@@ -27038,13 +27406,38 @@ function useSchoolController() {
|
|
|
27038
27406
|
next(error2);
|
|
27039
27407
|
}
|
|
27040
27408
|
}
|
|
27409
|
+
async function addBulk(req, res, next) {
|
|
27410
|
+
if (!req.file) {
|
|
27411
|
+
res.status(400).send("File is required!");
|
|
27412
|
+
return;
|
|
27413
|
+
}
|
|
27414
|
+
const { region, division } = req.body;
|
|
27415
|
+
const validation = Joi32.object({
|
|
27416
|
+
region: Joi32.string().hex().required(),
|
|
27417
|
+
division: Joi32.string().hex().required()
|
|
27418
|
+
});
|
|
27419
|
+
const { error } = validation.validate({ region, division });
|
|
27420
|
+
if (error) {
|
|
27421
|
+
next(new BadRequestError58(`Validation error: ${error.message}`));
|
|
27422
|
+
return;
|
|
27423
|
+
}
|
|
27424
|
+
try {
|
|
27425
|
+
const result = await _addBulk(req.file, region, division);
|
|
27426
|
+
res.status(201).json(result);
|
|
27427
|
+
return;
|
|
27428
|
+
} catch (error2) {
|
|
27429
|
+
next(error2);
|
|
27430
|
+
return;
|
|
27431
|
+
}
|
|
27432
|
+
}
|
|
27041
27433
|
return {
|
|
27042
27434
|
add,
|
|
27043
27435
|
getAll,
|
|
27044
27436
|
getByCreatedBy,
|
|
27045
27437
|
updateStatusById,
|
|
27046
27438
|
registerSchool,
|
|
27047
|
-
approveSchool
|
|
27439
|
+
approveSchool,
|
|
27440
|
+
addBulk
|
|
27048
27441
|
};
|
|
27049
27442
|
}
|
|
27050
27443
|
|
|
@@ -28017,7 +28410,10 @@ function useBuildingUnitService() {
|
|
|
28017
28410
|
try {
|
|
28018
28411
|
await session.startTransaction();
|
|
28019
28412
|
for (let index = 0; index < value.qty; index++) {
|
|
28020
|
-
await _add(
|
|
28413
|
+
await _add(
|
|
28414
|
+
{ ...value.building, name: `${value.building.name} ${index + 1}` },
|
|
28415
|
+
session
|
|
28416
|
+
);
|
|
28021
28417
|
}
|
|
28022
28418
|
await session.commitTransaction();
|
|
28023
28419
|
return "Building unit added successfully.";
|
|
@@ -29532,12 +29928,23 @@ import Joi41 from "joi";
|
|
|
29532
29928
|
import { ObjectId as ObjectId46 } from "mongodb";
|
|
29533
29929
|
var schemaPlantilla = Joi41.object({
|
|
29534
29930
|
_id: Joi41.string().hex().optional().allow(null, ""),
|
|
29931
|
+
org: Joi41.string().hex().required(),
|
|
29932
|
+
orgUnitCode: Joi41.string().optional().allow(null, ""),
|
|
29933
|
+
employmentType: Joi41.string().optional().allow(null, ""),
|
|
29934
|
+
personnelType: Joi41.string().required(),
|
|
29535
29935
|
itemNumber: Joi41.string().required(),
|
|
29536
29936
|
positionTitle: Joi41.string().required(),
|
|
29537
|
-
|
|
29538
|
-
|
|
29937
|
+
positionCategory: Joi41.string().required(),
|
|
29938
|
+
region: Joi41.string().hex().optional().allow(null, ""),
|
|
29939
|
+
regionName: Joi41.string().optional().allow(null, ""),
|
|
29940
|
+
division: Joi41.string().hex().optional().allow(null, ""),
|
|
29941
|
+
divisionName: Joi41.string().optional().allow(null, ""),
|
|
29942
|
+
salaryGrade: Joi41.number().required(),
|
|
29943
|
+
employeeName: Joi41.string().optional().allow(null, ""),
|
|
29944
|
+
annualSalary: Joi41.number().optional().allow(null, 0),
|
|
29945
|
+
monthlySalary: Joi41.number().optional().allow(null, 0),
|
|
29539
29946
|
status: Joi41.string().required(),
|
|
29540
|
-
|
|
29947
|
+
employee: Joi41.string().hex().optional().allow(null, ""),
|
|
29541
29948
|
createdAt: Joi41.date().iso().optional().allow(null, ""),
|
|
29542
29949
|
updatedAt: Joi41.date().iso().optional().allow(null, ""),
|
|
29543
29950
|
deletedAt: Joi41.date().iso().optional().allow(null, "")
|
|
@@ -29554,21 +29961,25 @@ function MPlantilla(data) {
|
|
|
29554
29961
|
throw new BadRequestError74("Invalid _id.");
|
|
29555
29962
|
}
|
|
29556
29963
|
}
|
|
29557
|
-
if (data.employeeId && typeof data.employeeId === "string") {
|
|
29558
|
-
try {
|
|
29559
|
-
data.employeeId = new ObjectId46(data.employeeId);
|
|
29560
|
-
} catch (error2) {
|
|
29561
|
-
throw new BadRequestError74("Invalid employeeId.");
|
|
29562
|
-
}
|
|
29563
|
-
}
|
|
29564
29964
|
return {
|
|
29565
29965
|
_id: data._id,
|
|
29566
29966
|
itemNumber: data.itemNumber ?? "",
|
|
29567
29967
|
positionTitle: data.positionTitle ?? "",
|
|
29568
|
-
|
|
29569
|
-
officeAssignment: data.officeAssignment ?? "",
|
|
29968
|
+
positionCategory: data.positionCategory ?? "",
|
|
29570
29969
|
status: data.status ?? "active",
|
|
29571
|
-
|
|
29970
|
+
salaryGrade: data.salaryGrade ?? 0,
|
|
29971
|
+
monthlySalary: data.monthlySalary ?? 0,
|
|
29972
|
+
annualSalary: data.annualSalary ?? 0,
|
|
29973
|
+
region: data.region ?? "",
|
|
29974
|
+
regionName: data.regionName ?? "",
|
|
29975
|
+
division: data.division ?? "",
|
|
29976
|
+
divisionName: data.divisionName ?? "",
|
|
29977
|
+
org: data.org ?? "",
|
|
29978
|
+
orgUnitCode: data.orgUnitCode ?? "",
|
|
29979
|
+
employmentType: data.employmentType ?? "",
|
|
29980
|
+
personnelType: data.personnelType ?? "",
|
|
29981
|
+
employee: data.employee ?? "",
|
|
29982
|
+
employeeName: data.employeeName ?? "",
|
|
29572
29983
|
createdAt: data.createdAt ? new Date(data.createdAt) : /* @__PURE__ */ new Date(),
|
|
29573
29984
|
updatedAt: data.updatedAt ? new Date(data.updatedAt) : "",
|
|
29574
29985
|
deletedAt: data.deletedAt ? new Date(data.deletedAt) : ""
|
|
@@ -29606,11 +30017,14 @@ function usePlantillaRepo() {
|
|
|
29606
30017
|
throw new Error("Failed to create index on plantillas.");
|
|
29607
30018
|
}
|
|
29608
30019
|
}
|
|
29609
|
-
async function add(value, session) {
|
|
30020
|
+
async function add(value, session, clearCache = true) {
|
|
30021
|
+
console.log(value);
|
|
29610
30022
|
try {
|
|
29611
30023
|
value = MPlantilla(value);
|
|
29612
30024
|
const res = await collection.insertOne(value, { session });
|
|
29613
|
-
|
|
30025
|
+
if (clearCache) {
|
|
30026
|
+
delCachedData();
|
|
30027
|
+
}
|
|
29614
30028
|
return res.insertedId;
|
|
29615
30029
|
} catch (error) {
|
|
29616
30030
|
logger36.log({
|
|
@@ -29811,34 +30225,243 @@ function usePlantillaRepo() {
|
|
|
29811
30225
|
getAll,
|
|
29812
30226
|
getById,
|
|
29813
30227
|
updateById,
|
|
29814
|
-
deleteById
|
|
30228
|
+
deleteById,
|
|
30229
|
+
delCachedData
|
|
29815
30230
|
};
|
|
29816
30231
|
}
|
|
29817
30232
|
|
|
29818
30233
|
// src/controllers/plantilla.controller.ts
|
|
29819
|
-
import { BadRequestError as
|
|
30234
|
+
import { BadRequestError as BadRequestError77 } from "@eeplatform/nodejs-utils";
|
|
29820
30235
|
import Joi42 from "joi";
|
|
29821
|
-
|
|
29822
|
-
|
|
29823
|
-
|
|
29824
|
-
|
|
29825
|
-
|
|
29826
|
-
|
|
29827
|
-
|
|
30236
|
+
|
|
30237
|
+
// src/services/plantilla.service.ts
|
|
30238
|
+
import { BadRequestError as BadRequestError76, useAtlas as useAtlas39, logger as logger37 } from "@eeplatform/nodejs-utils";
|
|
30239
|
+
import * as XLSX2 from "xlsx";
|
|
30240
|
+
import * as Papa2 from "papaparse";
|
|
30241
|
+
function usePlantillaService() {
|
|
30242
|
+
const { add: addPlantilla, delCachedData } = usePlantillaRepo();
|
|
30243
|
+
async function addBulk(file, region, division) {
|
|
30244
|
+
logger37.log({
|
|
30245
|
+
level: "info",
|
|
30246
|
+
message: `Starting plantilla bulk upload. File: ${file.originalname}, Size: ${file.size} bytes`
|
|
30247
|
+
});
|
|
30248
|
+
const MAX_SIZE = 16 * 1024 * 1024;
|
|
30249
|
+
let plantillas = [];
|
|
30250
|
+
let totalSize = 0;
|
|
30251
|
+
let validatedPlantillas = [];
|
|
30252
|
+
if (!file.buffer) {
|
|
30253
|
+
throw new BadRequestError76("File buffer is empty or corrupted");
|
|
30254
|
+
}
|
|
30255
|
+
try {
|
|
30256
|
+
const fileExtension = file.originalname.split(".").pop()?.toLowerCase();
|
|
30257
|
+
if (fileExtension === "csv") {
|
|
30258
|
+
const csvData = file.buffer.toString("utf-8");
|
|
30259
|
+
totalSize = Buffer.byteLength(csvData, "utf8");
|
|
30260
|
+
const parseResult = Papa2.parse(csvData, {
|
|
30261
|
+
header: true,
|
|
30262
|
+
skipEmptyLines: true,
|
|
30263
|
+
transformHeader: (header) => {
|
|
30264
|
+
return header.toLowerCase().replace(/\s+/g, "").replace(/[^\w]/g, "");
|
|
30265
|
+
}
|
|
30266
|
+
});
|
|
30267
|
+
if (parseResult.errors.length > 0) {
|
|
30268
|
+
throw new BadRequestError76(
|
|
30269
|
+
`CSV parsing errors: ${parseResult.errors.map((e) => e.message).join(", ")}`
|
|
30270
|
+
);
|
|
30271
|
+
}
|
|
30272
|
+
plantillas = parseResult.data;
|
|
30273
|
+
} else if (fileExtension === "xlsx" || fileExtension === "xls") {
|
|
30274
|
+
totalSize = file.buffer.length;
|
|
30275
|
+
const workbook = XLSX2.read(file.buffer, { type: "buffer" });
|
|
30276
|
+
const sheetName = workbook.SheetNames[0];
|
|
30277
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
30278
|
+
plantillas = XLSX2.utils.sheet_to_json(worksheet, {
|
|
30279
|
+
header: 1,
|
|
30280
|
+
defval: ""
|
|
30281
|
+
});
|
|
30282
|
+
if (plantillas.length === 0) {
|
|
30283
|
+
throw new BadRequestError76("Excel file is empty.");
|
|
30284
|
+
}
|
|
30285
|
+
const headers = plantillas[0];
|
|
30286
|
+
const normalizedHeaders = headers.map(
|
|
30287
|
+
(header) => header.toLowerCase().replace(/\s+/g, "").replace(/[^\w]/g, "")
|
|
30288
|
+
);
|
|
30289
|
+
plantillas = plantillas.slice(1).map((row) => {
|
|
30290
|
+
const obj = {};
|
|
30291
|
+
normalizedHeaders.forEach((header, index) => {
|
|
30292
|
+
obj[header] = row[index] || "";
|
|
30293
|
+
});
|
|
30294
|
+
return obj;
|
|
30295
|
+
});
|
|
30296
|
+
} else {
|
|
30297
|
+
throw new BadRequestError76(
|
|
30298
|
+
"Unsupported file type. Please upload an Excel (.xlsx, .xls) or CSV (.csv) file."
|
|
30299
|
+
);
|
|
30300
|
+
}
|
|
30301
|
+
if (!plantillas || plantillas.length === 0) {
|
|
30302
|
+
throw new BadRequestError76("No data found in the uploaded file.");
|
|
30303
|
+
}
|
|
30304
|
+
const errors = [];
|
|
30305
|
+
for (let i = 0; i < plantillas.length; i++) {
|
|
30306
|
+
const plantillaData = plantillas[i];
|
|
30307
|
+
const rowNumber = i + 1;
|
|
30308
|
+
try {
|
|
30309
|
+
const itemNumber = plantillaData.itemnumber || plantillaData.item_number || "";
|
|
30310
|
+
const positionTitle = plantillaData.positiontitle || plantillaData.position_title || plantillaData.title || "";
|
|
30311
|
+
const positionCategory = plantillaData.positioncategory || plantillaData.position_category || "";
|
|
30312
|
+
const status = plantillaData.status || "active";
|
|
30313
|
+
if (!itemNumber.trim()) {
|
|
30314
|
+
errors.push(`Row ${rowNumber}: Item Number is required`);
|
|
30315
|
+
continue;
|
|
30316
|
+
}
|
|
30317
|
+
if (!positionTitle.trim()) {
|
|
30318
|
+
errors.push(`Row ${rowNumber}: Position Title is required`);
|
|
30319
|
+
continue;
|
|
30320
|
+
}
|
|
30321
|
+
if (!positionCategory.trim()) {
|
|
30322
|
+
errors.push(`Row ${rowNumber}: Position Category is required`);
|
|
30323
|
+
continue;
|
|
30324
|
+
}
|
|
30325
|
+
const plantilla = {
|
|
30326
|
+
itemNumber: itemNumber.trim(),
|
|
30327
|
+
positionTitle: positionTitle.trim(),
|
|
30328
|
+
positionCategory: positionCategory.trim(),
|
|
30329
|
+
salaryGrade: parseInt(
|
|
30330
|
+
plantillaData.salarygrade || plantillaData.salary_grade || "1"
|
|
30331
|
+
) || 1,
|
|
30332
|
+
org: "",
|
|
30333
|
+
personnelType: "",
|
|
30334
|
+
status: status.trim() || "active"
|
|
30335
|
+
};
|
|
30336
|
+
if (region)
|
|
30337
|
+
plantilla.region = region;
|
|
30338
|
+
if (division)
|
|
30339
|
+
plantilla.division = division;
|
|
30340
|
+
if (plantillaData.regionname || plantillaData.region_name) {
|
|
30341
|
+
plantilla.regionName = plantillaData.regionname || plantillaData.region_name;
|
|
30342
|
+
}
|
|
30343
|
+
if (plantillaData.divisionname || plantillaData.division_name) {
|
|
30344
|
+
plantilla.divisionName = plantillaData.divisionname || plantillaData.division_name;
|
|
30345
|
+
}
|
|
30346
|
+
if (plantillaData.employee) {
|
|
30347
|
+
plantilla.employee = plantillaData.employee;
|
|
30348
|
+
}
|
|
30349
|
+
if (plantillaData.annualsalary || plantillaData.annual_salary) {
|
|
30350
|
+
plantilla.annualSalary = parseFloat(
|
|
30351
|
+
plantillaData.annualsalary || plantillaData.annual_salary
|
|
30352
|
+
) || void 0;
|
|
30353
|
+
}
|
|
30354
|
+
if (plantillaData.monthlysalary || plantillaData.monthly_salary) {
|
|
30355
|
+
plantilla.monthlySalary = parseFloat(
|
|
30356
|
+
plantillaData.monthlysalary || plantillaData.monthly_salary
|
|
30357
|
+
) || void 0;
|
|
30358
|
+
}
|
|
30359
|
+
if (!plantilla.itemNumber || !plantilla.positionTitle || !plantilla.positionCategory) {
|
|
30360
|
+
errors.push(`Row ${rowNumber}: Missing required fields`);
|
|
30361
|
+
continue;
|
|
30362
|
+
}
|
|
30363
|
+
validatedPlantillas.push(plantilla);
|
|
30364
|
+
} catch (error) {
|
|
30365
|
+
errors.push(
|
|
30366
|
+
`Row ${rowNumber}: ${error.message || "Invalid data format"}`
|
|
30367
|
+
);
|
|
30368
|
+
}
|
|
30369
|
+
}
|
|
30370
|
+
if (errors.length > 0) {
|
|
30371
|
+
throw new BadRequestError76(
|
|
30372
|
+
`Validation errors found:
|
|
30373
|
+
${errors.slice(0, 10).join("\n")}${errors.length > 10 ? `
|
|
30374
|
+
... and ${errors.length - 10} more errors` : ""}`
|
|
30375
|
+
);
|
|
30376
|
+
}
|
|
30377
|
+
if (validatedPlantillas.length === 0) {
|
|
30378
|
+
throw new BadRequestError76(
|
|
30379
|
+
"No valid plantilla records found after validation."
|
|
30380
|
+
);
|
|
30381
|
+
}
|
|
30382
|
+
if (totalSize > MAX_SIZE) {
|
|
30383
|
+
throw new BadRequestError76(
|
|
30384
|
+
`Data payload (${Math.round(
|
|
30385
|
+
totalSize / 1024 / 1024
|
|
30386
|
+
)}MB) exceeds MongoDB transaction limit of 16MB. Please reduce the number of records or split into smaller files.`
|
|
30387
|
+
);
|
|
30388
|
+
}
|
|
30389
|
+
} catch (error) {
|
|
30390
|
+
if (error instanceof BadRequestError76) {
|
|
30391
|
+
throw error;
|
|
30392
|
+
}
|
|
30393
|
+
throw new BadRequestError76(`File processing error: ${error.message}`);
|
|
30394
|
+
}
|
|
30395
|
+
const session = useAtlas39.getClient()?.startSession();
|
|
30396
|
+
if (!session) {
|
|
30397
|
+
throw new Error("Unable to start session for bulk plantilla upload.");
|
|
30398
|
+
}
|
|
30399
|
+
logger37.log({
|
|
30400
|
+
level: "info",
|
|
30401
|
+
message: `Starting bulk plantilla upload with ${validatedPlantillas.length} records`
|
|
30402
|
+
});
|
|
30403
|
+
try {
|
|
30404
|
+
session.startTransaction();
|
|
30405
|
+
const results = {
|
|
30406
|
+
successful: 0,
|
|
30407
|
+
failed: 0,
|
|
30408
|
+
errors: []
|
|
30409
|
+
};
|
|
30410
|
+
const promises = [];
|
|
30411
|
+
for (let i = 0; i < validatedPlantillas.length; i++) {
|
|
30412
|
+
const plantilla = validatedPlantillas[i];
|
|
30413
|
+
promises.push(addPlantilla(plantilla, session, false));
|
|
30414
|
+
}
|
|
30415
|
+
await Promise.all(promises);
|
|
30416
|
+
await delCachedData();
|
|
30417
|
+
await session.commitTransaction();
|
|
30418
|
+
return {
|
|
30419
|
+
message: `Bulk upload completed. ${results.successful} plantillas added successfully.`,
|
|
30420
|
+
details: {
|
|
30421
|
+
successful: results.successful,
|
|
30422
|
+
failed: results.failed,
|
|
30423
|
+
total: validatedPlantillas.length,
|
|
30424
|
+
totalSizeMB: Math.round(totalSize / 1024 / 1024 * 100) / 100,
|
|
30425
|
+
errors: results.errors
|
|
30426
|
+
}
|
|
30427
|
+
};
|
|
30428
|
+
} catch (error) {
|
|
30429
|
+
logger37.log({
|
|
30430
|
+
level: "error",
|
|
30431
|
+
message: `Error in bulk plantilla upload: ${error.message}`
|
|
30432
|
+
});
|
|
30433
|
+
await session.abortTransaction();
|
|
30434
|
+
throw error;
|
|
30435
|
+
} finally {
|
|
30436
|
+
await session.endSession();
|
|
30437
|
+
}
|
|
30438
|
+
}
|
|
30439
|
+
return {
|
|
30440
|
+
addBulk
|
|
30441
|
+
};
|
|
30442
|
+
}
|
|
30443
|
+
|
|
30444
|
+
// src/controllers/plantilla.controller.ts
|
|
30445
|
+
function usePlantillaController() {
|
|
30446
|
+
const {
|
|
30447
|
+
add: _addPlantilla,
|
|
30448
|
+
getAll: _getAllPlantillas,
|
|
30449
|
+
getById: _getPlantillaById,
|
|
30450
|
+
updateById: _updatePlantillaById,
|
|
30451
|
+
deleteById: _deletePlantillaById
|
|
29828
30452
|
} = usePlantillaRepo();
|
|
30453
|
+
const { addBulk: _addBulk } = usePlantillaService();
|
|
29829
30454
|
async function createPlantilla(req, res, next) {
|
|
29830
30455
|
const value = req.body;
|
|
29831
30456
|
const validation = Joi42.object({
|
|
29832
30457
|
itemNumber: Joi42.string().required(),
|
|
29833
30458
|
positionTitle: Joi42.string().required(),
|
|
29834
|
-
|
|
29835
|
-
|
|
29836
|
-
status: Joi42.string().required(),
|
|
29837
|
-
employeeId: Joi42.string().hex().optional().allow(null, "")
|
|
30459
|
+
positionCategory: Joi42.string().required(),
|
|
30460
|
+
status: Joi42.string().required()
|
|
29838
30461
|
});
|
|
29839
30462
|
const { error } = validation.validate(value);
|
|
29840
30463
|
if (error) {
|
|
29841
|
-
next(new
|
|
30464
|
+
next(new BadRequestError77(error.message));
|
|
29842
30465
|
return;
|
|
29843
30466
|
}
|
|
29844
30467
|
try {
|
|
@@ -29856,12 +30479,12 @@ function usePlantillaController() {
|
|
|
29856
30479
|
const org = req.query.org ?? "";
|
|
29857
30480
|
const isPageNumber = isFinite(page);
|
|
29858
30481
|
if (!isPageNumber) {
|
|
29859
|
-
next(new
|
|
30482
|
+
next(new BadRequestError77("Invalid page number."));
|
|
29860
30483
|
return;
|
|
29861
30484
|
}
|
|
29862
30485
|
const isLimitNumber = isFinite(limit);
|
|
29863
30486
|
if (!isLimitNumber) {
|
|
29864
|
-
next(new
|
|
30487
|
+
next(new BadRequestError77("Invalid limit number."));
|
|
29865
30488
|
return;
|
|
29866
30489
|
}
|
|
29867
30490
|
const validation = Joi42.object({
|
|
@@ -29872,7 +30495,7 @@ function usePlantillaController() {
|
|
|
29872
30495
|
});
|
|
29873
30496
|
const { error } = validation.validate({ page, limit, search, org });
|
|
29874
30497
|
if (error) {
|
|
29875
|
-
next(new
|
|
30498
|
+
next(new BadRequestError77(error.message));
|
|
29876
30499
|
return;
|
|
29877
30500
|
}
|
|
29878
30501
|
try {
|
|
@@ -29895,13 +30518,13 @@ function usePlantillaController() {
|
|
|
29895
30518
|
});
|
|
29896
30519
|
const { error } = validation.validate({ id });
|
|
29897
30520
|
if (error) {
|
|
29898
|
-
next(new
|
|
30521
|
+
next(new BadRequestError77(error.message));
|
|
29899
30522
|
return;
|
|
29900
30523
|
}
|
|
29901
30524
|
try {
|
|
29902
30525
|
const plantilla = await _getPlantillaById(id);
|
|
29903
30526
|
if (!plantilla) {
|
|
29904
|
-
next(new
|
|
30527
|
+
next(new BadRequestError77("Plantilla not found."));
|
|
29905
30528
|
return;
|
|
29906
30529
|
}
|
|
29907
30530
|
res.json(plantilla);
|
|
@@ -29915,19 +30538,20 @@ function usePlantillaController() {
|
|
|
29915
30538
|
const value = req.body;
|
|
29916
30539
|
const validation = Joi42.object({
|
|
29917
30540
|
id: Joi42.string().hex().required(),
|
|
29918
|
-
|
|
30541
|
+
employee: Joi42.string().hex().optional().allow(null, ""),
|
|
29919
30542
|
status: Joi42.string().optional(),
|
|
29920
|
-
positionTitle: Joi42.string().optional()
|
|
30543
|
+
positionTitle: Joi42.string().optional(),
|
|
30544
|
+
positionCategory: Joi42.string().optional()
|
|
29921
30545
|
});
|
|
29922
30546
|
const { error } = validation.validate({ id, ...value });
|
|
29923
30547
|
if (error) {
|
|
29924
|
-
next(new
|
|
30548
|
+
next(new BadRequestError77(error.message));
|
|
29925
30549
|
return;
|
|
29926
30550
|
}
|
|
29927
30551
|
try {
|
|
29928
30552
|
const result = await _updatePlantillaById(id, value);
|
|
29929
30553
|
if (result.matchedCount === 0) {
|
|
29930
|
-
next(new
|
|
30554
|
+
next(new BadRequestError77("Plantilla not found."));
|
|
29931
30555
|
return;
|
|
29932
30556
|
}
|
|
29933
30557
|
res.json({ message: "Plantilla updated successfully" });
|
|
@@ -29943,13 +30567,13 @@ function usePlantillaController() {
|
|
|
29943
30567
|
});
|
|
29944
30568
|
const { error } = validation.validate({ id });
|
|
29945
30569
|
if (error) {
|
|
29946
|
-
next(new
|
|
30570
|
+
next(new BadRequestError77(error.message));
|
|
29947
30571
|
return;
|
|
29948
30572
|
}
|
|
29949
30573
|
try {
|
|
29950
30574
|
const result = await _deletePlantillaById(id);
|
|
29951
30575
|
if (result.matchedCount === 0) {
|
|
29952
|
-
next(new
|
|
30576
|
+
next(new BadRequestError77("Plantilla not found."));
|
|
29953
30577
|
return;
|
|
29954
30578
|
}
|
|
29955
30579
|
res.json({ message: "Plantilla deleted successfully" });
|
|
@@ -29958,12 +30582,1193 @@ function usePlantillaController() {
|
|
|
29958
30582
|
next(error2);
|
|
29959
30583
|
}
|
|
29960
30584
|
}
|
|
30585
|
+
async function bulkAddPlantillas(req, res, next) {
|
|
30586
|
+
if (!req.file) {
|
|
30587
|
+
res.status(400).send("File is required!");
|
|
30588
|
+
return;
|
|
30589
|
+
}
|
|
30590
|
+
const { region, division } = req.body;
|
|
30591
|
+
const validation = Joi42.object({
|
|
30592
|
+
region: Joi42.string().hex().optional(),
|
|
30593
|
+
division: Joi42.string().hex().optional()
|
|
30594
|
+
});
|
|
30595
|
+
const { error } = validation.validate({ region, division });
|
|
30596
|
+
if (error) {
|
|
30597
|
+
next(new BadRequestError77(`Validation error: ${error.message}`));
|
|
30598
|
+
return;
|
|
30599
|
+
}
|
|
30600
|
+
if (!region && !division) {
|
|
30601
|
+
next(
|
|
30602
|
+
new BadRequestError77(
|
|
30603
|
+
"At least one of region or division must be provided"
|
|
30604
|
+
)
|
|
30605
|
+
);
|
|
30606
|
+
return;
|
|
30607
|
+
}
|
|
30608
|
+
try {
|
|
30609
|
+
const result = await _addBulk(req.file, region, division);
|
|
30610
|
+
res.status(201).json(result);
|
|
30611
|
+
return;
|
|
30612
|
+
} catch (error2) {
|
|
30613
|
+
next(error2);
|
|
30614
|
+
return;
|
|
30615
|
+
}
|
|
30616
|
+
}
|
|
29961
30617
|
return {
|
|
29962
30618
|
createPlantilla,
|
|
29963
30619
|
getAllPlantillas,
|
|
29964
30620
|
getPlantillaById,
|
|
29965
30621
|
updatePlantilla,
|
|
29966
|
-
deletePlantilla
|
|
30622
|
+
deletePlantilla,
|
|
30623
|
+
bulkAddPlantillas
|
|
30624
|
+
};
|
|
30625
|
+
}
|
|
30626
|
+
|
|
30627
|
+
// src/models/office.model.ts
|
|
30628
|
+
import { BadRequestError as BadRequestError78 } from "@eeplatform/nodejs-utils";
|
|
30629
|
+
import Joi43 from "joi";
|
|
30630
|
+
import { ObjectId as ObjectId48 } from "mongodb";
|
|
30631
|
+
var schemaOffice = Joi43.object({
|
|
30632
|
+
_id: Joi43.string().hex().optional().allow(null, ""),
|
|
30633
|
+
name: Joi43.string().required(),
|
|
30634
|
+
code: Joi43.string().required(),
|
|
30635
|
+
type: Joi43.string().required(),
|
|
30636
|
+
parent: Joi43.string().hex().optional().allow(null, ""),
|
|
30637
|
+
path: Joi43.string().required(),
|
|
30638
|
+
status: Joi43.string().required(),
|
|
30639
|
+
createdAt: Joi43.date().iso().optional().allow(null, ""),
|
|
30640
|
+
updatedAt: Joi43.date().iso().optional().allow(null, ""),
|
|
30641
|
+
deletedAt: Joi43.date().iso().optional().allow(null, "")
|
|
30642
|
+
});
|
|
30643
|
+
function MOffice(data) {
|
|
30644
|
+
const { error } = schemaOffice.validate(data);
|
|
30645
|
+
if (error) {
|
|
30646
|
+
throw new BadRequestError78(error.message);
|
|
30647
|
+
}
|
|
30648
|
+
if (data._id && typeof data._id === "string") {
|
|
30649
|
+
try {
|
|
30650
|
+
data._id = new ObjectId48(data._id);
|
|
30651
|
+
} catch (error2) {
|
|
30652
|
+
throw new BadRequestError78("Invalid _id.");
|
|
30653
|
+
}
|
|
30654
|
+
}
|
|
30655
|
+
if (data.parent && typeof data.parent === "string") {
|
|
30656
|
+
try {
|
|
30657
|
+
data.parent = new ObjectId48(data.parent);
|
|
30658
|
+
} catch (error2) {
|
|
30659
|
+
throw new BadRequestError78("Invalid parent.");
|
|
30660
|
+
}
|
|
30661
|
+
}
|
|
30662
|
+
return {
|
|
30663
|
+
_id: data._id,
|
|
30664
|
+
name: data.name ?? "",
|
|
30665
|
+
code: data.code ?? "",
|
|
30666
|
+
type: data.type ?? "",
|
|
30667
|
+
parent: data.parent ?? "",
|
|
30668
|
+
path: data.path ?? "",
|
|
30669
|
+
status: data.status ?? "active",
|
|
30670
|
+
createdAt: data.createdAt ? new Date(data.createdAt) : /* @__PURE__ */ new Date(),
|
|
30671
|
+
updatedAt: data.updatedAt ? new Date(data.updatedAt) : "",
|
|
30672
|
+
deletedAt: data.deletedAt ? new Date(data.deletedAt) : ""
|
|
30673
|
+
};
|
|
30674
|
+
}
|
|
30675
|
+
|
|
30676
|
+
// src/repositories/office.repository.ts
|
|
30677
|
+
import {
|
|
30678
|
+
AppError as AppError19,
|
|
30679
|
+
BadRequestError as BadRequestError79,
|
|
30680
|
+
InternalServerError as InternalServerError29,
|
|
30681
|
+
logger as logger38,
|
|
30682
|
+
makeCacheKey as makeCacheKey24,
|
|
30683
|
+
paginate as paginate20,
|
|
30684
|
+
useAtlas as useAtlas40,
|
|
30685
|
+
useCache as useCache25
|
|
30686
|
+
} from "@eeplatform/nodejs-utils";
|
|
30687
|
+
import { ObjectId as ObjectId49 } from "mongodb";
|
|
30688
|
+
function useOfficeRepo() {
|
|
30689
|
+
const db = useAtlas40.getDb();
|
|
30690
|
+
if (!db) {
|
|
30691
|
+
throw new Error("Unable to connect to server.");
|
|
30692
|
+
}
|
|
30693
|
+
const namespace_collection = "offices";
|
|
30694
|
+
const collection = db.collection(namespace_collection);
|
|
30695
|
+
const { getCache, setCache, delNamespace } = useCache25(namespace_collection);
|
|
30696
|
+
async function createIndexes() {
|
|
30697
|
+
try {
|
|
30698
|
+
await collection.createIndexes([
|
|
30699
|
+
{
|
|
30700
|
+
key: { name: 1, code: 1 },
|
|
30701
|
+
unique: true,
|
|
30702
|
+
name: "unique_name_code_index"
|
|
30703
|
+
},
|
|
30704
|
+
{ key: { type: 1 } },
|
|
30705
|
+
{ key: { parent: 1 } },
|
|
30706
|
+
{ key: { status: 1 } }
|
|
30707
|
+
]);
|
|
30708
|
+
} catch (error) {
|
|
30709
|
+
throw new Error("Failed to create index on offices.");
|
|
30710
|
+
}
|
|
30711
|
+
}
|
|
30712
|
+
async function add(value, session, clearCache = true) {
|
|
30713
|
+
try {
|
|
30714
|
+
value = MOffice(value);
|
|
30715
|
+
const res = await collection.insertOne(value, { session });
|
|
30716
|
+
if (clearCache) {
|
|
30717
|
+
delCachedData();
|
|
30718
|
+
}
|
|
30719
|
+
return res.insertedId;
|
|
30720
|
+
} catch (error) {
|
|
30721
|
+
logger38.log({
|
|
30722
|
+
level: "error",
|
|
30723
|
+
message: error.message
|
|
30724
|
+
});
|
|
30725
|
+
if (error instanceof AppError19) {
|
|
30726
|
+
throw error;
|
|
30727
|
+
} else {
|
|
30728
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
30729
|
+
if (isDuplicated) {
|
|
30730
|
+
throw new BadRequestError79("Office already exists.");
|
|
30731
|
+
}
|
|
30732
|
+
throw new Error("Failed to create office.");
|
|
30733
|
+
}
|
|
30734
|
+
}
|
|
30735
|
+
}
|
|
30736
|
+
async function updateById(_id, value, session) {
|
|
30737
|
+
try {
|
|
30738
|
+
_id = new ObjectId49(_id);
|
|
30739
|
+
} catch (error) {
|
|
30740
|
+
throw new BadRequestError79("Invalid ID.");
|
|
30741
|
+
}
|
|
30742
|
+
value.updatedAt = /* @__PURE__ */ new Date();
|
|
30743
|
+
try {
|
|
30744
|
+
const res = await collection.updateOne(
|
|
30745
|
+
{ _id },
|
|
30746
|
+
{ $set: value },
|
|
30747
|
+
{ session }
|
|
30748
|
+
);
|
|
30749
|
+
delCachedData();
|
|
30750
|
+
return res;
|
|
30751
|
+
} catch (error) {
|
|
30752
|
+
logger38.log({
|
|
30753
|
+
level: "error",
|
|
30754
|
+
message: error.message
|
|
30755
|
+
});
|
|
30756
|
+
if (error instanceof AppError19) {
|
|
30757
|
+
throw error;
|
|
30758
|
+
} else {
|
|
30759
|
+
throw new Error("Failed to update office.");
|
|
30760
|
+
}
|
|
30761
|
+
}
|
|
30762
|
+
}
|
|
30763
|
+
async function getAll({
|
|
30764
|
+
search = "",
|
|
30765
|
+
page = 1,
|
|
30766
|
+
limit = 10,
|
|
30767
|
+
sort = {},
|
|
30768
|
+
type = "",
|
|
30769
|
+
parent = "",
|
|
30770
|
+
status = "active"
|
|
30771
|
+
} = {}) {
|
|
30772
|
+
page = page > 0 ? page - 1 : 0;
|
|
30773
|
+
const query = {
|
|
30774
|
+
status
|
|
30775
|
+
};
|
|
30776
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
30777
|
+
if (search) {
|
|
30778
|
+
query.$text = { $search: search };
|
|
30779
|
+
}
|
|
30780
|
+
if (type) {
|
|
30781
|
+
query.type = type;
|
|
30782
|
+
}
|
|
30783
|
+
if (parent) {
|
|
30784
|
+
try {
|
|
30785
|
+
query.parent = new ObjectId49(parent);
|
|
30786
|
+
} catch (error) {
|
|
30787
|
+
throw new BadRequestError79("Invalid parent ID.");
|
|
30788
|
+
}
|
|
30789
|
+
}
|
|
30790
|
+
const cacheParams = {
|
|
30791
|
+
page,
|
|
30792
|
+
limit,
|
|
30793
|
+
sort: JSON.stringify(sort)
|
|
30794
|
+
};
|
|
30795
|
+
if (search)
|
|
30796
|
+
cacheParams.search = search;
|
|
30797
|
+
if (type)
|
|
30798
|
+
cacheParams.type = type;
|
|
30799
|
+
if (parent)
|
|
30800
|
+
cacheParams.parent = parent;
|
|
30801
|
+
if (status !== "active")
|
|
30802
|
+
cacheParams.status = status;
|
|
30803
|
+
const cacheKey = makeCacheKey24(namespace_collection, cacheParams);
|
|
30804
|
+
logger38.log({
|
|
30805
|
+
level: "info",
|
|
30806
|
+
message: `Cache key for getAll offices: ${cacheKey}`
|
|
30807
|
+
});
|
|
30808
|
+
try {
|
|
30809
|
+
const cached = await getCache(cacheKey);
|
|
30810
|
+
if (cached) {
|
|
30811
|
+
logger38.log({
|
|
30812
|
+
level: "info",
|
|
30813
|
+
message: `Cache hit for getAll offices: ${cacheKey}`
|
|
30814
|
+
});
|
|
30815
|
+
return cached;
|
|
30816
|
+
}
|
|
30817
|
+
const items = await collection.aggregate([
|
|
30818
|
+
{ $match: query },
|
|
30819
|
+
{ $sort: sort },
|
|
30820
|
+
{ $skip: page * limit },
|
|
30821
|
+
{ $limit: limit }
|
|
30822
|
+
]).toArray();
|
|
30823
|
+
const length = await collection.countDocuments(query);
|
|
30824
|
+
const data = paginate20(items, page, limit, length);
|
|
30825
|
+
setCache(cacheKey, data, 600).then(() => {
|
|
30826
|
+
logger38.log({
|
|
30827
|
+
level: "info",
|
|
30828
|
+
message: `Cache set for getAll offices: ${cacheKey}`
|
|
30829
|
+
});
|
|
30830
|
+
}).catch((err) => {
|
|
30831
|
+
logger38.log({
|
|
30832
|
+
level: "error",
|
|
30833
|
+
message: `Failed to set cache for getAll offices: ${err.message}`
|
|
30834
|
+
});
|
|
30835
|
+
});
|
|
30836
|
+
return data;
|
|
30837
|
+
} catch (error) {
|
|
30838
|
+
logger38.log({ level: "error", message: `${error}` });
|
|
30839
|
+
throw error;
|
|
30840
|
+
}
|
|
30841
|
+
}
|
|
30842
|
+
async function getById(_id) {
|
|
30843
|
+
try {
|
|
30844
|
+
_id = new ObjectId49(_id);
|
|
30845
|
+
} catch (error) {
|
|
30846
|
+
throw new BadRequestError79("Invalid ID.");
|
|
30847
|
+
}
|
|
30848
|
+
const cacheKey = makeCacheKey24(namespace_collection, { _id: String(_id) });
|
|
30849
|
+
try {
|
|
30850
|
+
const cached = await getCache(cacheKey);
|
|
30851
|
+
if (cached) {
|
|
30852
|
+
logger38.log({
|
|
30853
|
+
level: "info",
|
|
30854
|
+
message: `Cache hit for getById office: ${cacheKey}`
|
|
30855
|
+
});
|
|
30856
|
+
return cached;
|
|
30857
|
+
}
|
|
30858
|
+
const result = await collection.findOne({
|
|
30859
|
+
_id
|
|
30860
|
+
});
|
|
30861
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
30862
|
+
logger38.log({
|
|
30863
|
+
level: "info",
|
|
30864
|
+
message: `Cache set for office by id: ${cacheKey}`
|
|
30865
|
+
});
|
|
30866
|
+
}).catch((err) => {
|
|
30867
|
+
logger38.log({
|
|
30868
|
+
level: "error",
|
|
30869
|
+
message: `Failed to set cache for office by id: ${err.message}`
|
|
30870
|
+
});
|
|
30871
|
+
});
|
|
30872
|
+
return result;
|
|
30873
|
+
} catch (error) {
|
|
30874
|
+
if (error instanceof AppError19) {
|
|
30875
|
+
throw error;
|
|
30876
|
+
} else {
|
|
30877
|
+
throw new InternalServerError29("Failed to get office.");
|
|
30878
|
+
}
|
|
30879
|
+
}
|
|
30880
|
+
}
|
|
30881
|
+
async function deleteById(_id, session) {
|
|
30882
|
+
try {
|
|
30883
|
+
_id = new ObjectId49(_id);
|
|
30884
|
+
} catch (error) {
|
|
30885
|
+
throw new BadRequestError79("Invalid ID.");
|
|
30886
|
+
}
|
|
30887
|
+
try {
|
|
30888
|
+
const res = await collection.updateOne(
|
|
30889
|
+
{ _id },
|
|
30890
|
+
{ $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
|
|
30891
|
+
);
|
|
30892
|
+
delCachedData();
|
|
30893
|
+
return res;
|
|
30894
|
+
} catch (error) {
|
|
30895
|
+
logger38.log({
|
|
30896
|
+
level: "error",
|
|
30897
|
+
message: error.message
|
|
30898
|
+
});
|
|
30899
|
+
if (error instanceof AppError19) {
|
|
30900
|
+
throw error;
|
|
30901
|
+
} else {
|
|
30902
|
+
throw new InternalServerError29("Failed to delete office.");
|
|
30903
|
+
}
|
|
30904
|
+
}
|
|
30905
|
+
}
|
|
30906
|
+
function delCachedData() {
|
|
30907
|
+
delNamespace().then(() => {
|
|
30908
|
+
logger38.log({
|
|
30909
|
+
level: "info",
|
|
30910
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
30911
|
+
});
|
|
30912
|
+
}).catch((err) => {
|
|
30913
|
+
logger38.log({
|
|
30914
|
+
level: "error",
|
|
30915
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
30916
|
+
});
|
|
30917
|
+
});
|
|
30918
|
+
}
|
|
30919
|
+
return {
|
|
30920
|
+
createIndexes,
|
|
30921
|
+
add,
|
|
30922
|
+
getAll,
|
|
30923
|
+
getById,
|
|
30924
|
+
updateById,
|
|
30925
|
+
deleteById,
|
|
30926
|
+
delCachedData
|
|
30927
|
+
};
|
|
30928
|
+
}
|
|
30929
|
+
|
|
30930
|
+
// src/services/office.service.ts
|
|
30931
|
+
import { BadRequestError as BadRequestError80, useAtlas as useAtlas41, logger as logger39 } from "@eeplatform/nodejs-utils";
|
|
30932
|
+
import * as XLSX3 from "xlsx";
|
|
30933
|
+
import * as Papa3 from "papaparse";
|
|
30934
|
+
function useOfficeService() {
|
|
30935
|
+
const { add: addOffice, delCachedData } = useOfficeRepo();
|
|
30936
|
+
async function addBulk(file) {
|
|
30937
|
+
logger39.log({
|
|
30938
|
+
level: "info",
|
|
30939
|
+
message: `Starting office bulk upload. File: ${file.originalname}, Size: ${file.size} bytes`
|
|
30940
|
+
});
|
|
30941
|
+
const MAX_SIZE = 16 * 1024 * 1024;
|
|
30942
|
+
let offices = [];
|
|
30943
|
+
let totalSize = 0;
|
|
30944
|
+
let validatedOffices = [];
|
|
30945
|
+
if (!file.buffer) {
|
|
30946
|
+
throw new BadRequestError80("File buffer is empty or corrupted");
|
|
30947
|
+
}
|
|
30948
|
+
try {
|
|
30949
|
+
const fileExtension = file.originalname.split(".").pop()?.toLowerCase();
|
|
30950
|
+
if (fileExtension === "csv") {
|
|
30951
|
+
const csvData = file.buffer.toString("utf-8");
|
|
30952
|
+
totalSize = Buffer.byteLength(csvData, "utf8");
|
|
30953
|
+
if (totalSize > MAX_SIZE) {
|
|
30954
|
+
throw new BadRequestError80(
|
|
30955
|
+
`File size exceeds limit. Maximum allowed: ${MAX_SIZE / 1024 / 1024}MB, Received: ${(totalSize / 1024 / 1024).toFixed(2)}MB`
|
|
30956
|
+
);
|
|
30957
|
+
}
|
|
30958
|
+
const parseResult = Papa3.parse(csvData, {
|
|
30959
|
+
header: true,
|
|
30960
|
+
skipEmptyLines: true,
|
|
30961
|
+
transformHeader: (header) => {
|
|
30962
|
+
return header.toLowerCase().replace(/\s+/g, "").replace(/[^\w]/g, "");
|
|
30963
|
+
}
|
|
30964
|
+
});
|
|
30965
|
+
if (parseResult.errors.length > 0) {
|
|
30966
|
+
throw new BadRequestError80(
|
|
30967
|
+
`CSV parsing errors: ${parseResult.errors.map((e) => e.message).join(", ")}`
|
|
30968
|
+
);
|
|
30969
|
+
}
|
|
30970
|
+
offices = parseResult.data || [];
|
|
30971
|
+
} else if (["xlsx", "xls"].includes(fileExtension || "")) {
|
|
30972
|
+
totalSize = file.buffer.length;
|
|
30973
|
+
if (totalSize > MAX_SIZE) {
|
|
30974
|
+
throw new BadRequestError80(
|
|
30975
|
+
`File size exceeds limit. Maximum allowed: ${MAX_SIZE / 1024 / 1024}MB, Received: ${(totalSize / 1024 / 1024).toFixed(2)}MB`
|
|
30976
|
+
);
|
|
30977
|
+
}
|
|
30978
|
+
const workbook = XLSX3.read(file.buffer, { type: "buffer" });
|
|
30979
|
+
const sheetName = workbook.SheetNames[0];
|
|
30980
|
+
if (!sheetName) {
|
|
30981
|
+
throw new BadRequestError80("Excel file contains no sheets");
|
|
30982
|
+
}
|
|
30983
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
30984
|
+
offices = XLSX3.utils.sheet_to_json(worksheet, {
|
|
30985
|
+
header: 1,
|
|
30986
|
+
defval: ""
|
|
30987
|
+
});
|
|
30988
|
+
if (offices.length > 0) {
|
|
30989
|
+
const headers = offices[0];
|
|
30990
|
+
offices = offices.slice(1).map((row) => {
|
|
30991
|
+
const obj = {};
|
|
30992
|
+
headers.forEach((header, index) => {
|
|
30993
|
+
obj[header.trim()] = row[index] || "";
|
|
30994
|
+
});
|
|
30995
|
+
return obj;
|
|
30996
|
+
});
|
|
30997
|
+
}
|
|
30998
|
+
} else {
|
|
30999
|
+
throw new BadRequestError80(
|
|
31000
|
+
"Unsupported file format. Please upload CSV, XLS, or XLSX files."
|
|
31001
|
+
);
|
|
31002
|
+
}
|
|
31003
|
+
if (!offices || offices.length === 0) {
|
|
31004
|
+
throw new BadRequestError80("File is empty or contains no valid data");
|
|
31005
|
+
}
|
|
31006
|
+
const results = {
|
|
31007
|
+
total: offices.length,
|
|
31008
|
+
successful: 0,
|
|
31009
|
+
failed: 0,
|
|
31010
|
+
errors: []
|
|
31011
|
+
};
|
|
31012
|
+
logger39.log({
|
|
31013
|
+
level: "info",
|
|
31014
|
+
message: `Processing ${offices.length} offices from file`
|
|
31015
|
+
});
|
|
31016
|
+
for (let i = 0; i < offices.length; i++) {
|
|
31017
|
+
const officeData = offices[i];
|
|
31018
|
+
try {
|
|
31019
|
+
const cleanOffice = {
|
|
31020
|
+
name: String(officeData.name || "").trim(),
|
|
31021
|
+
code: String(officeData.code || "").trim(),
|
|
31022
|
+
type: String(officeData.type || "").trim(),
|
|
31023
|
+
path: String(officeData.path || "").trim(),
|
|
31024
|
+
status: String(officeData.status || "active").trim()
|
|
31025
|
+
};
|
|
31026
|
+
if (officeData.parent && String(officeData.parent).trim()) {
|
|
31027
|
+
cleanOffice.parent = String(officeData.parent).trim();
|
|
31028
|
+
}
|
|
31029
|
+
const { error } = schemaOffice.validate(cleanOffice);
|
|
31030
|
+
if (error) {
|
|
31031
|
+
results.errors.push(`Row ${i + 1}: ${error.message}`);
|
|
31032
|
+
results.failed++;
|
|
31033
|
+
continue;
|
|
31034
|
+
}
|
|
31035
|
+
validatedOffices.push(cleanOffice);
|
|
31036
|
+
} catch (error) {
|
|
31037
|
+
results.errors.push(`Row ${i + 1}: ${error.message}`);
|
|
31038
|
+
results.failed++;
|
|
31039
|
+
}
|
|
31040
|
+
}
|
|
31041
|
+
if (validatedOffices.length === 0) {
|
|
31042
|
+
throw new BadRequestError80(
|
|
31043
|
+
"No valid offices found in file. Please check the format and data."
|
|
31044
|
+
);
|
|
31045
|
+
}
|
|
31046
|
+
const db = useAtlas41.getDb();
|
|
31047
|
+
if (!db) {
|
|
31048
|
+
throw new Error("Database connection not available");
|
|
31049
|
+
}
|
|
31050
|
+
const session = db.client.startSession();
|
|
31051
|
+
try {
|
|
31052
|
+
await session.withTransaction(async () => {
|
|
31053
|
+
const batchSize = 100;
|
|
31054
|
+
for (let i = 0; i < validatedOffices.length; i += batchSize) {
|
|
31055
|
+
const batch = validatedOffices.slice(i, i + batchSize);
|
|
31056
|
+
for (const office of batch) {
|
|
31057
|
+
try {
|
|
31058
|
+
await addOffice(office, session, false);
|
|
31059
|
+
results.successful++;
|
|
31060
|
+
} catch (error) {
|
|
31061
|
+
results.failed++;
|
|
31062
|
+
results.errors.push(
|
|
31063
|
+
`Failed to insert office "${office.name}": ${error.message}`
|
|
31064
|
+
);
|
|
31065
|
+
logger39.log({
|
|
31066
|
+
level: "error",
|
|
31067
|
+
message: `Failed to insert office: ${error.message}`
|
|
31068
|
+
});
|
|
31069
|
+
}
|
|
31070
|
+
}
|
|
31071
|
+
}
|
|
31072
|
+
});
|
|
31073
|
+
delCachedData();
|
|
31074
|
+
logger39.log({
|
|
31075
|
+
level: "info",
|
|
31076
|
+
message: `Bulk upload completed. Successful: ${results.successful}, Failed: ${results.failed}`
|
|
31077
|
+
});
|
|
31078
|
+
return results;
|
|
31079
|
+
} catch (error) {
|
|
31080
|
+
logger39.log({
|
|
31081
|
+
level: "error",
|
|
31082
|
+
message: `Transaction failed: ${error.message}`
|
|
31083
|
+
});
|
|
31084
|
+
throw new BadRequestError80(`Bulk upload failed: ${error.message}`);
|
|
31085
|
+
} finally {
|
|
31086
|
+
await session.endSession();
|
|
31087
|
+
}
|
|
31088
|
+
} catch (error) {
|
|
31089
|
+
logger39.log({
|
|
31090
|
+
level: "error",
|
|
31091
|
+
message: `Bulk office upload failed: ${error.message}`
|
|
31092
|
+
});
|
|
31093
|
+
if (error instanceof BadRequestError80) {
|
|
31094
|
+
throw error;
|
|
31095
|
+
}
|
|
31096
|
+
throw new BadRequestError80(`File processing failed: ${error.message}`);
|
|
31097
|
+
}
|
|
31098
|
+
}
|
|
31099
|
+
return {
|
|
31100
|
+
addBulk
|
|
31101
|
+
};
|
|
31102
|
+
}
|
|
31103
|
+
|
|
31104
|
+
// src/controllers/office.controller.ts
|
|
31105
|
+
import { BadRequestError as BadRequestError81 } from "@eeplatform/nodejs-utils";
|
|
31106
|
+
import Joi44 from "joi";
|
|
31107
|
+
function useOfficeController() {
|
|
31108
|
+
const {
|
|
31109
|
+
add: _add,
|
|
31110
|
+
getAll: _getAll,
|
|
31111
|
+
getById: _getById,
|
|
31112
|
+
updateById: _updateByIdById,
|
|
31113
|
+
deleteById: _deleteByIdById
|
|
31114
|
+
} = useOfficeRepo();
|
|
31115
|
+
const { addBulk: _addBulk } = useOfficeService();
|
|
31116
|
+
async function add(req, res, next) {
|
|
31117
|
+
const value = req.body;
|
|
31118
|
+
const validation = Joi44.object({
|
|
31119
|
+
name: Joi44.string().required(),
|
|
31120
|
+
code: Joi44.string().required(),
|
|
31121
|
+
type: Joi44.string().required(),
|
|
31122
|
+
path: Joi44.string().required(),
|
|
31123
|
+
parent: Joi44.string().hex().optional().allow(null, ""),
|
|
31124
|
+
status: Joi44.string().optional().allow(null, "")
|
|
31125
|
+
});
|
|
31126
|
+
const { error } = validation.validate(value);
|
|
31127
|
+
if (error) {
|
|
31128
|
+
next(new BadRequestError81(error.message));
|
|
31129
|
+
return;
|
|
31130
|
+
}
|
|
31131
|
+
try {
|
|
31132
|
+
const id = await _add(value);
|
|
31133
|
+
res.json({ message: "Office created successfully", id });
|
|
31134
|
+
return;
|
|
31135
|
+
} catch (error2) {
|
|
31136
|
+
next(error2);
|
|
31137
|
+
}
|
|
31138
|
+
}
|
|
31139
|
+
async function getAll(req, res, next) {
|
|
31140
|
+
const page = typeof req.query.page === "string" ? Number(req.query.page) : 1;
|
|
31141
|
+
const limit = typeof req.query.limit === "string" ? Number(req.query.limit) : 10;
|
|
31142
|
+
const search = req.query.search ?? "";
|
|
31143
|
+
const type = req.query.type ?? "";
|
|
31144
|
+
const parent = req.query.parent ?? "";
|
|
31145
|
+
const status = req.query.status ?? "active";
|
|
31146
|
+
const isPageNumber = isFinite(page);
|
|
31147
|
+
if (!isPageNumber) {
|
|
31148
|
+
next(new BadRequestError81("Invalid page number."));
|
|
31149
|
+
return;
|
|
31150
|
+
}
|
|
31151
|
+
const isLimitNumber = isFinite(limit);
|
|
31152
|
+
if (!isLimitNumber) {
|
|
31153
|
+
next(new BadRequestError81("Invalid limit number."));
|
|
31154
|
+
return;
|
|
31155
|
+
}
|
|
31156
|
+
const validation = Joi44.object({
|
|
31157
|
+
page: Joi44.number().min(1).optional().allow("", null),
|
|
31158
|
+
limit: Joi44.number().min(1).optional().allow("", null),
|
|
31159
|
+
search: Joi44.string().optional().allow("", null),
|
|
31160
|
+
type: Joi44.string().optional().allow("", null),
|
|
31161
|
+
parent: Joi44.string().optional().allow("", null),
|
|
31162
|
+
status: Joi44.string().optional().allow("", null)
|
|
31163
|
+
});
|
|
31164
|
+
const { error } = validation.validate({
|
|
31165
|
+
page,
|
|
31166
|
+
limit,
|
|
31167
|
+
search,
|
|
31168
|
+
type,
|
|
31169
|
+
parent,
|
|
31170
|
+
status
|
|
31171
|
+
});
|
|
31172
|
+
if (error) {
|
|
31173
|
+
next(new BadRequestError81(error.message));
|
|
31174
|
+
return;
|
|
31175
|
+
}
|
|
31176
|
+
try {
|
|
31177
|
+
const offices = await _getAll({
|
|
31178
|
+
search,
|
|
31179
|
+
page,
|
|
31180
|
+
limit,
|
|
31181
|
+
type,
|
|
31182
|
+
parent,
|
|
31183
|
+
status
|
|
31184
|
+
});
|
|
31185
|
+
res.json(offices);
|
|
31186
|
+
return;
|
|
31187
|
+
} catch (error2) {
|
|
31188
|
+
next(error2);
|
|
31189
|
+
}
|
|
31190
|
+
}
|
|
31191
|
+
async function getById(req, res, next) {
|
|
31192
|
+
const id = req.params.id;
|
|
31193
|
+
const validation = Joi44.object({
|
|
31194
|
+
id: Joi44.string().hex().required()
|
|
31195
|
+
});
|
|
31196
|
+
const { error } = validation.validate({ id });
|
|
31197
|
+
if (error) {
|
|
31198
|
+
next(new BadRequestError81(error.message));
|
|
31199
|
+
return;
|
|
31200
|
+
}
|
|
31201
|
+
try {
|
|
31202
|
+
const office = await _getById(id);
|
|
31203
|
+
if (!office) {
|
|
31204
|
+
next(new BadRequestError81("Office not found."));
|
|
31205
|
+
return;
|
|
31206
|
+
}
|
|
31207
|
+
res.json(office);
|
|
31208
|
+
return;
|
|
31209
|
+
} catch (error2) {
|
|
31210
|
+
next(error2);
|
|
31211
|
+
}
|
|
31212
|
+
}
|
|
31213
|
+
async function updateById(req, res, next) {
|
|
31214
|
+
const id = req.params.id;
|
|
31215
|
+
const value = req.body;
|
|
31216
|
+
const validation = Joi44.object({
|
|
31217
|
+
id: Joi44.string().hex().required(),
|
|
31218
|
+
name: Joi44.string().optional(),
|
|
31219
|
+
code: Joi44.string().optional(),
|
|
31220
|
+
type: Joi44.string().optional(),
|
|
31221
|
+
parent: Joi44.string().hex().optional().allow(null, ""),
|
|
31222
|
+
path: Joi44.string().optional(),
|
|
31223
|
+
status: Joi44.string().optional()
|
|
31224
|
+
});
|
|
31225
|
+
const { error } = validation.validate({ id, ...value });
|
|
31226
|
+
if (error) {
|
|
31227
|
+
next(new BadRequestError81(error.message));
|
|
31228
|
+
return;
|
|
31229
|
+
}
|
|
31230
|
+
try {
|
|
31231
|
+
const result = await _updateByIdById(id, value);
|
|
31232
|
+
if (result.matchedCount === 0) {
|
|
31233
|
+
next(new BadRequestError81("Office not found."));
|
|
31234
|
+
return;
|
|
31235
|
+
}
|
|
31236
|
+
res.json({ message: "Office updated successfully" });
|
|
31237
|
+
return;
|
|
31238
|
+
} catch (error2) {
|
|
31239
|
+
next(error2);
|
|
31240
|
+
}
|
|
31241
|
+
}
|
|
31242
|
+
async function deleteById(req, res, next) {
|
|
31243
|
+
const id = req.params.id;
|
|
31244
|
+
const validation = Joi44.object({
|
|
31245
|
+
id: Joi44.string().hex().required()
|
|
31246
|
+
});
|
|
31247
|
+
const { error } = validation.validate({ id });
|
|
31248
|
+
if (error) {
|
|
31249
|
+
next(new BadRequestError81(error.message));
|
|
31250
|
+
return;
|
|
31251
|
+
}
|
|
31252
|
+
try {
|
|
31253
|
+
const result = await _deleteByIdById(id);
|
|
31254
|
+
if (result.matchedCount === 0) {
|
|
31255
|
+
next(new BadRequestError81("Office not found."));
|
|
31256
|
+
return;
|
|
31257
|
+
}
|
|
31258
|
+
res.json({ message: "Office deleted successfully" });
|
|
31259
|
+
return;
|
|
31260
|
+
} catch (error2) {
|
|
31261
|
+
next(error2);
|
|
31262
|
+
}
|
|
31263
|
+
}
|
|
31264
|
+
async function bulkAddOffices(req, res, next) {
|
|
31265
|
+
if (!req.file) {
|
|
31266
|
+
res.status(400).send("File is required!");
|
|
31267
|
+
return;
|
|
31268
|
+
}
|
|
31269
|
+
try {
|
|
31270
|
+
const result = await _addBulk(req.file);
|
|
31271
|
+
res.status(201).json(result);
|
|
31272
|
+
return;
|
|
31273
|
+
} catch (error) {
|
|
31274
|
+
next(error);
|
|
31275
|
+
return;
|
|
31276
|
+
}
|
|
31277
|
+
}
|
|
31278
|
+
return {
|
|
31279
|
+
add,
|
|
31280
|
+
getAll,
|
|
31281
|
+
getById,
|
|
31282
|
+
updateById,
|
|
31283
|
+
deleteById,
|
|
31284
|
+
bulkAddOffices
|
|
31285
|
+
};
|
|
31286
|
+
}
|
|
31287
|
+
|
|
31288
|
+
// src/models/curriculum.model.ts
|
|
31289
|
+
import { BadRequestError as BadRequestError82, logger as logger40 } from "@eeplatform/nodejs-utils";
|
|
31290
|
+
import Joi45 from "joi";
|
|
31291
|
+
import { ObjectId as ObjectId50 } from "mongodb";
|
|
31292
|
+
var schemaCurriculum = Joi45.object({
|
|
31293
|
+
_id: Joi45.string().hex().optional(),
|
|
31294
|
+
school: Joi45.string().hex().required(),
|
|
31295
|
+
code: Joi45.string().required(),
|
|
31296
|
+
educationLevel: Joi45.string().required(),
|
|
31297
|
+
gradeLevel: Joi45.string().required(),
|
|
31298
|
+
subjectCode: Joi45.string().required(),
|
|
31299
|
+
subjectName: Joi45.string().required(),
|
|
31300
|
+
subjectType: Joi45.string().required(),
|
|
31301
|
+
sessionFrequency: Joi45.number().integer().min(0).required(),
|
|
31302
|
+
sessionDuration: Joi45.number().integer().min(0).required(),
|
|
31303
|
+
totalMinutesPerWeek: Joi45.number().integer().min(0).required(),
|
|
31304
|
+
curriculumMemoRef: Joi45.string().optional().allow("", null),
|
|
31305
|
+
status: Joi45.string().optional().allow("", null),
|
|
31306
|
+
createdAt: Joi45.date().optional().allow("", null),
|
|
31307
|
+
updatedAt: Joi45.date().optional().allow("", null),
|
|
31308
|
+
deletedAt: Joi45.date().optional().allow("", null),
|
|
31309
|
+
createdBy: Joi45.string().optional().allow("", null),
|
|
31310
|
+
updatedBy: Joi45.string().optional().allow("", null),
|
|
31311
|
+
deletedBy: Joi45.string().optional().allow("", null)
|
|
31312
|
+
});
|
|
31313
|
+
function MCurriculum(value) {
|
|
31314
|
+
const { error } = schemaCurriculum.validate(value);
|
|
31315
|
+
if (error) {
|
|
31316
|
+
logger40.info(`Curriculum Model: ${error.message}`);
|
|
31317
|
+
throw new BadRequestError82(error.message);
|
|
31318
|
+
}
|
|
31319
|
+
if (value._id && typeof value._id === "string") {
|
|
31320
|
+
try {
|
|
31321
|
+
value._id = new ObjectId50(value._id);
|
|
31322
|
+
} catch (error2) {
|
|
31323
|
+
throw new BadRequestError82("Invalid _id format");
|
|
31324
|
+
}
|
|
31325
|
+
}
|
|
31326
|
+
return {
|
|
31327
|
+
_id: value._id ?? void 0,
|
|
31328
|
+
school: value.school ?? "",
|
|
31329
|
+
code: value.code ?? "",
|
|
31330
|
+
educationLevel: value.educationLevel ?? "",
|
|
31331
|
+
gradeLevel: value.gradeLevel ?? "",
|
|
31332
|
+
subjectCode: value.subjectCode ?? "",
|
|
31333
|
+
subjectName: value.subjectName ?? "",
|
|
31334
|
+
subjectType: value.subjectType ?? "",
|
|
31335
|
+
sessionFrequency: value.sessionFrequency ?? 0,
|
|
31336
|
+
sessionDuration: value.sessionDuration ?? 0,
|
|
31337
|
+
totalMinutesPerWeek: value.totalMinutesPerWeek ?? 0,
|
|
31338
|
+
curriculumMemoRef: value.curriculumMemoRef ?? "",
|
|
31339
|
+
status: value.status ?? "active",
|
|
31340
|
+
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
31341
|
+
updatedAt: value.updatedAt ?? "",
|
|
31342
|
+
deletedAt: value.deletedAt ?? "",
|
|
31343
|
+
createdBy: value.createdBy ?? "",
|
|
31344
|
+
updatedBy: value.updatedBy ?? "",
|
|
31345
|
+
deletedBy: value.deletedBy ?? ""
|
|
31346
|
+
};
|
|
31347
|
+
}
|
|
31348
|
+
|
|
31349
|
+
// src/repositories/curriculum.repository.ts
|
|
31350
|
+
import {
|
|
31351
|
+
AppError as AppError20,
|
|
31352
|
+
BadRequestError as BadRequestError83,
|
|
31353
|
+
InternalServerError as InternalServerError30,
|
|
31354
|
+
logger as logger41,
|
|
31355
|
+
makeCacheKey as makeCacheKey25,
|
|
31356
|
+
paginate as paginate21,
|
|
31357
|
+
useAtlas as useAtlas42,
|
|
31358
|
+
useCache as useCache26
|
|
31359
|
+
} from "@eeplatform/nodejs-utils";
|
|
31360
|
+
import { ObjectId as ObjectId51 } from "mongodb";
|
|
31361
|
+
function useCurriculumRepo() {
|
|
31362
|
+
const db = useAtlas42.getDb();
|
|
31363
|
+
if (!db) {
|
|
31364
|
+
throw new Error("Unable to connect to server.");
|
|
31365
|
+
}
|
|
31366
|
+
const namespace_collection = "school.curriculums";
|
|
31367
|
+
const collection = db.collection(namespace_collection);
|
|
31368
|
+
const { getCache, setCache, delNamespace } = useCache26(namespace_collection);
|
|
31369
|
+
async function createIndexes() {
|
|
31370
|
+
try {
|
|
31371
|
+
await collection.createIndexes([
|
|
31372
|
+
{ key: { code: 1 }, unique: true, name: "unique_code_index" },
|
|
31373
|
+
{ key: { educationLevel: 1 } },
|
|
31374
|
+
{ key: { gradeLevel: 1 } },
|
|
31375
|
+
{ key: { subjectCode: 1 } },
|
|
31376
|
+
{ key: { status: 1 } }
|
|
31377
|
+
]);
|
|
31378
|
+
} catch (error) {
|
|
31379
|
+
throw new Error("Failed to create index on curriculums.");
|
|
31380
|
+
}
|
|
31381
|
+
}
|
|
31382
|
+
async function add(value, session) {
|
|
31383
|
+
try {
|
|
31384
|
+
value = MCurriculum(value);
|
|
31385
|
+
const res = await collection.insertOne(value, { session });
|
|
31386
|
+
delCachedData();
|
|
31387
|
+
return res.insertedId;
|
|
31388
|
+
} catch (error) {
|
|
31389
|
+
logger41.log({
|
|
31390
|
+
level: "error",
|
|
31391
|
+
message: error.message
|
|
31392
|
+
});
|
|
31393
|
+
if (error instanceof AppError20) {
|
|
31394
|
+
throw error;
|
|
31395
|
+
} else {
|
|
31396
|
+
const isDuplicated = error.message.includes("duplicate");
|
|
31397
|
+
if (isDuplicated) {
|
|
31398
|
+
throw new BadRequestError83("Curriculum already exists.");
|
|
31399
|
+
}
|
|
31400
|
+
throw new Error("Failed to create curriculum.");
|
|
31401
|
+
}
|
|
31402
|
+
}
|
|
31403
|
+
}
|
|
31404
|
+
async function updateById(_id, value, session) {
|
|
31405
|
+
try {
|
|
31406
|
+
_id = new ObjectId51(_id);
|
|
31407
|
+
} catch (error) {
|
|
31408
|
+
throw new BadRequestError83("Invalid ID.");
|
|
31409
|
+
}
|
|
31410
|
+
try {
|
|
31411
|
+
const res = await collection.updateOne(
|
|
31412
|
+
{ _id },
|
|
31413
|
+
{ $set: { ...value, updatedAt: /* @__PURE__ */ new Date() } },
|
|
31414
|
+
{ session }
|
|
31415
|
+
);
|
|
31416
|
+
delCachedData();
|
|
31417
|
+
return res;
|
|
31418
|
+
} catch (error) {
|
|
31419
|
+
logger41.log({
|
|
31420
|
+
level: "error",
|
|
31421
|
+
message: error.message
|
|
31422
|
+
});
|
|
31423
|
+
if (error instanceof AppError20) {
|
|
31424
|
+
throw error;
|
|
31425
|
+
} else {
|
|
31426
|
+
throw new Error("Failed to update curriculum.");
|
|
31427
|
+
}
|
|
31428
|
+
}
|
|
31429
|
+
}
|
|
31430
|
+
async function getAll({
|
|
31431
|
+
search = "",
|
|
31432
|
+
page = 1,
|
|
31433
|
+
limit = 10,
|
|
31434
|
+
sort = {},
|
|
31435
|
+
educationLevel = "",
|
|
31436
|
+
gradeLevel = "",
|
|
31437
|
+
subjectCode = "",
|
|
31438
|
+
status = "active"
|
|
31439
|
+
} = {}) {
|
|
31440
|
+
page = page > 0 ? page - 1 : 0;
|
|
31441
|
+
const query = {
|
|
31442
|
+
status
|
|
31443
|
+
};
|
|
31444
|
+
sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
|
|
31445
|
+
if (search) {
|
|
31446
|
+
query.$or = [
|
|
31447
|
+
{ code: { $regex: search, $options: "i" } },
|
|
31448
|
+
{ subjectName: { $regex: search, $options: "i" } },
|
|
31449
|
+
{ subjectCode: { $regex: search, $options: "i" } }
|
|
31450
|
+
];
|
|
31451
|
+
}
|
|
31452
|
+
if (educationLevel) {
|
|
31453
|
+
query.educationLevel = educationLevel;
|
|
31454
|
+
}
|
|
31455
|
+
if (gradeLevel) {
|
|
31456
|
+
query.gradeLevel = gradeLevel;
|
|
31457
|
+
}
|
|
31458
|
+
if (subjectCode) {
|
|
31459
|
+
query.subjectCode = subjectCode;
|
|
31460
|
+
}
|
|
31461
|
+
const cacheParams = {
|
|
31462
|
+
page,
|
|
31463
|
+
limit,
|
|
31464
|
+
sort: JSON.stringify(sort)
|
|
31465
|
+
};
|
|
31466
|
+
if (search)
|
|
31467
|
+
cacheParams.search = search;
|
|
31468
|
+
if (educationLevel)
|
|
31469
|
+
cacheParams.educationLevel = educationLevel;
|
|
31470
|
+
if (gradeLevel)
|
|
31471
|
+
cacheParams.gradeLevel = gradeLevel;
|
|
31472
|
+
if (subjectCode)
|
|
31473
|
+
cacheParams.subjectCode = subjectCode;
|
|
31474
|
+
if (status !== "active")
|
|
31475
|
+
cacheParams.status = status;
|
|
31476
|
+
const cacheKey = makeCacheKey25(namespace_collection, cacheParams);
|
|
31477
|
+
logger41.log({
|
|
31478
|
+
level: "info",
|
|
31479
|
+
message: `Cache key for getAll curriculums: ${cacheKey}`
|
|
31480
|
+
});
|
|
31481
|
+
try {
|
|
31482
|
+
const cached = await getCache(cacheKey);
|
|
31483
|
+
if (cached) {
|
|
31484
|
+
logger41.log({
|
|
31485
|
+
level: "info",
|
|
31486
|
+
message: `Cache hit for getAll curriculums: ${cacheKey}`
|
|
31487
|
+
});
|
|
31488
|
+
return cached;
|
|
31489
|
+
}
|
|
31490
|
+
const items = await collection.aggregate([
|
|
31491
|
+
{ $match: query },
|
|
31492
|
+
{ $sort: sort },
|
|
31493
|
+
{ $skip: page * limit },
|
|
31494
|
+
{ $limit: limit }
|
|
31495
|
+
]).toArray();
|
|
31496
|
+
const length = await collection.countDocuments(query);
|
|
31497
|
+
const data = paginate21(items, page, limit, length);
|
|
31498
|
+
setCache(cacheKey, data, 600).then(() => {
|
|
31499
|
+
logger41.log({
|
|
31500
|
+
level: "info",
|
|
31501
|
+
message: `Cache set for getAll curriculums: ${cacheKey}`
|
|
31502
|
+
});
|
|
31503
|
+
}).catch((err) => {
|
|
31504
|
+
logger41.log({
|
|
31505
|
+
level: "error",
|
|
31506
|
+
message: `Failed to set cache for getAll curriculums: ${err.message}`
|
|
31507
|
+
});
|
|
31508
|
+
});
|
|
31509
|
+
return data;
|
|
31510
|
+
} catch (error) {
|
|
31511
|
+
logger41.log({ level: "error", message: `${error}` });
|
|
31512
|
+
throw error;
|
|
31513
|
+
}
|
|
31514
|
+
}
|
|
31515
|
+
async function getById(_id) {
|
|
31516
|
+
try {
|
|
31517
|
+
_id = new ObjectId51(_id);
|
|
31518
|
+
} catch (error) {
|
|
31519
|
+
throw new BadRequestError83("Invalid ID.");
|
|
31520
|
+
}
|
|
31521
|
+
const cacheKey = makeCacheKey25(namespace_collection, { _id: String(_id) });
|
|
31522
|
+
try {
|
|
31523
|
+
const cached = await getCache(cacheKey);
|
|
31524
|
+
if (cached) {
|
|
31525
|
+
logger41.log({
|
|
31526
|
+
level: "info",
|
|
31527
|
+
message: `Cache hit for getById curriculum: ${cacheKey}`
|
|
31528
|
+
});
|
|
31529
|
+
return cached;
|
|
31530
|
+
}
|
|
31531
|
+
const result = await collection.findOne({
|
|
31532
|
+
_id
|
|
31533
|
+
});
|
|
31534
|
+
setCache(cacheKey, result, 300).then(() => {
|
|
31535
|
+
logger41.log({
|
|
31536
|
+
level: "info",
|
|
31537
|
+
message: `Cache set for curriculum by id: ${cacheKey}`
|
|
31538
|
+
});
|
|
31539
|
+
}).catch((err) => {
|
|
31540
|
+
logger41.log({
|
|
31541
|
+
level: "error",
|
|
31542
|
+
message: `Failed to set cache for curriculum by id: ${err.message}`
|
|
31543
|
+
});
|
|
31544
|
+
});
|
|
31545
|
+
return result;
|
|
31546
|
+
} catch (error) {
|
|
31547
|
+
if (error instanceof AppError20) {
|
|
31548
|
+
throw error;
|
|
31549
|
+
} else {
|
|
31550
|
+
throw new InternalServerError30("Failed to get curriculum.");
|
|
31551
|
+
}
|
|
31552
|
+
}
|
|
31553
|
+
}
|
|
31554
|
+
async function deleteById(_id, session) {
|
|
31555
|
+
try {
|
|
31556
|
+
_id = new ObjectId51(_id);
|
|
31557
|
+
} catch (error) {
|
|
31558
|
+
throw new BadRequestError83("Invalid ID.");
|
|
31559
|
+
}
|
|
31560
|
+
try {
|
|
31561
|
+
const res = await collection.updateOne(
|
|
31562
|
+
{ _id },
|
|
31563
|
+
{ $set: { status: "deleted", deletedAt: /* @__PURE__ */ new Date() } }
|
|
31564
|
+
);
|
|
31565
|
+
delCachedData();
|
|
31566
|
+
return res;
|
|
31567
|
+
} catch (error) {
|
|
31568
|
+
logger41.log({
|
|
31569
|
+
level: "error",
|
|
31570
|
+
message: error.message
|
|
31571
|
+
});
|
|
31572
|
+
if (error instanceof AppError20) {
|
|
31573
|
+
throw error;
|
|
31574
|
+
} else {
|
|
31575
|
+
throw new InternalServerError30("Failed to delete curriculum.");
|
|
31576
|
+
}
|
|
31577
|
+
}
|
|
31578
|
+
}
|
|
31579
|
+
function delCachedData() {
|
|
31580
|
+
delNamespace().then(() => {
|
|
31581
|
+
logger41.log({
|
|
31582
|
+
level: "info",
|
|
31583
|
+
message: `Cache namespace cleared for ${namespace_collection}`
|
|
31584
|
+
});
|
|
31585
|
+
}).catch((err) => {
|
|
31586
|
+
logger41.log({
|
|
31587
|
+
level: "error",
|
|
31588
|
+
message: `Failed to clear cache namespace for ${namespace_collection}: ${err.message}`
|
|
31589
|
+
});
|
|
31590
|
+
});
|
|
31591
|
+
}
|
|
31592
|
+
return {
|
|
31593
|
+
createIndexes,
|
|
31594
|
+
add,
|
|
31595
|
+
getAll,
|
|
31596
|
+
getById,
|
|
31597
|
+
updateById,
|
|
31598
|
+
deleteById
|
|
31599
|
+
};
|
|
31600
|
+
}
|
|
31601
|
+
|
|
31602
|
+
// src/controllers/curriculum.controller.ts
|
|
31603
|
+
import { BadRequestError as BadRequestError84, logger as logger42 } from "@eeplatform/nodejs-utils";
|
|
31604
|
+
import Joi46 from "joi";
|
|
31605
|
+
function useCurriculumController() {
|
|
31606
|
+
const {
|
|
31607
|
+
getAll: _getAll,
|
|
31608
|
+
getById: _getById,
|
|
31609
|
+
add: _add,
|
|
31610
|
+
updateById: _updateById,
|
|
31611
|
+
deleteById: _deleteById
|
|
31612
|
+
} = useCurriculumRepo();
|
|
31613
|
+
async function add(req, res, next) {
|
|
31614
|
+
const value = req.body;
|
|
31615
|
+
const validation = Joi46.object({
|
|
31616
|
+
code: Joi46.string().required(),
|
|
31617
|
+
school: Joi46.string().hex().required(),
|
|
31618
|
+
educationLevel: Joi46.string().required(),
|
|
31619
|
+
gradeLevel: Joi46.string().required(),
|
|
31620
|
+
subjectCode: Joi46.string().required(),
|
|
31621
|
+
subjectName: Joi46.string().required(),
|
|
31622
|
+
subjectType: Joi46.string().required(),
|
|
31623
|
+
sessionFrequency: Joi46.number().integer().min(0).required(),
|
|
31624
|
+
sessionDuration: Joi46.number().integer().min(0).required(),
|
|
31625
|
+
totalMinutesPerWeek: Joi46.number().integer().min(0).required(),
|
|
31626
|
+
curriculumMemoRef: Joi46.string().optional().allow("", null),
|
|
31627
|
+
status: Joi46.string().optional().allow("", null)
|
|
31628
|
+
});
|
|
31629
|
+
const { error } = validation.validate(value);
|
|
31630
|
+
if (error) {
|
|
31631
|
+
next(new BadRequestError84(error.message));
|
|
31632
|
+
logger42.info(`Controller: ${error.message}`);
|
|
31633
|
+
return;
|
|
31634
|
+
}
|
|
31635
|
+
try {
|
|
31636
|
+
const result = await _add(value);
|
|
31637
|
+
res.json(result);
|
|
31638
|
+
return;
|
|
31639
|
+
} catch (error2) {
|
|
31640
|
+
next(error2);
|
|
31641
|
+
}
|
|
31642
|
+
}
|
|
31643
|
+
async function updateById(req, res, next) {
|
|
31644
|
+
const value = req.body;
|
|
31645
|
+
const id = req.params.id ?? "";
|
|
31646
|
+
const validation = Joi46.object({
|
|
31647
|
+
id: Joi46.string().hex().required(),
|
|
31648
|
+
value: Joi46.object({
|
|
31649
|
+
code: Joi46.string().optional(),
|
|
31650
|
+
educationLevel: Joi46.string().optional(),
|
|
31651
|
+
gradeLevel: Joi46.string().optional(),
|
|
31652
|
+
subjectCode: Joi46.string().optional(),
|
|
31653
|
+
subjectName: Joi46.string().optional(),
|
|
31654
|
+
subjectType: Joi46.string().optional(),
|
|
31655
|
+
sessionFrequency: Joi46.number().integer().min(0).optional(),
|
|
31656
|
+
sessionDuration: Joi46.number().integer().min(0).optional(),
|
|
31657
|
+
totalMinutesPerWeek: Joi46.number().integer().min(0).optional(),
|
|
31658
|
+
curriculumMemoRef: Joi46.string().optional().allow("", null)
|
|
31659
|
+
}).min(1)
|
|
31660
|
+
});
|
|
31661
|
+
const { error } = validation.validate({ id, value });
|
|
31662
|
+
if (error) {
|
|
31663
|
+
next(new BadRequestError84(error.message));
|
|
31664
|
+
logger42.info(`Controller: ${error.message}`);
|
|
31665
|
+
return;
|
|
31666
|
+
}
|
|
31667
|
+
try {
|
|
31668
|
+
const result = await _updateById(id, value);
|
|
31669
|
+
res.json(result);
|
|
31670
|
+
return;
|
|
31671
|
+
} catch (error2) {
|
|
31672
|
+
next(error2);
|
|
31673
|
+
}
|
|
31674
|
+
}
|
|
31675
|
+
async function getAll(req, res, next) {
|
|
31676
|
+
const query = req.query;
|
|
31677
|
+
const validation = Joi46.object({
|
|
31678
|
+
page: Joi46.number().min(1).optional().allow("", null),
|
|
31679
|
+
limit: Joi46.number().min(1).optional().allow("", null),
|
|
31680
|
+
search: Joi46.string().optional().allow("", null),
|
|
31681
|
+
educationLevel: Joi46.string().optional().allow("", null),
|
|
31682
|
+
gradeLevel: Joi46.string().optional().allow("", null),
|
|
31683
|
+
subjectCode: Joi46.string().optional().allow("", null),
|
|
31684
|
+
status: Joi46.string().optional().allow("", null)
|
|
31685
|
+
});
|
|
31686
|
+
const { error } = validation.validate(query);
|
|
31687
|
+
if (error) {
|
|
31688
|
+
next(new BadRequestError84(error.message));
|
|
31689
|
+
return;
|
|
31690
|
+
}
|
|
31691
|
+
const page = parseInt(req.query.page) ?? 1;
|
|
31692
|
+
let limit = parseInt(req.query.limit) ?? 20;
|
|
31693
|
+
limit = isNaN(limit) ? 20 : limit;
|
|
31694
|
+
const sort = req.query.sort ? String(req.query.sort).split(",") : "";
|
|
31695
|
+
const sortOrder = req.query.sortOrder ? String(req.query.sortOrder).split(",") : "";
|
|
31696
|
+
const sortObj = {};
|
|
31697
|
+
if (sort && Array.isArray(sort) && sort.length && sortOrder && Array.isArray(sortOrder) && sortOrder.length) {
|
|
31698
|
+
sort.forEach((field, index) => {
|
|
31699
|
+
sortObj[field] = sortOrder[index] === "desc" ? -1 : 1;
|
|
31700
|
+
});
|
|
31701
|
+
}
|
|
31702
|
+
const status = req.query.status ?? "active";
|
|
31703
|
+
const educationLevel = req.query.educationLevel ?? "";
|
|
31704
|
+
const gradeLevel = req.query.gradeLevel ?? "";
|
|
31705
|
+
const subjectCode = req.query.subjectCode ?? "";
|
|
31706
|
+
const search = req.query.search ?? "";
|
|
31707
|
+
try {
|
|
31708
|
+
const curriculums = await _getAll({
|
|
31709
|
+
page,
|
|
31710
|
+
limit,
|
|
31711
|
+
sort: sortObj,
|
|
31712
|
+
status,
|
|
31713
|
+
educationLevel,
|
|
31714
|
+
gradeLevel,
|
|
31715
|
+
subjectCode,
|
|
31716
|
+
search
|
|
31717
|
+
});
|
|
31718
|
+
res.json(curriculums);
|
|
31719
|
+
return;
|
|
31720
|
+
} catch (error2) {
|
|
31721
|
+
next(error2);
|
|
31722
|
+
}
|
|
31723
|
+
}
|
|
31724
|
+
async function getById(req, res, next) {
|
|
31725
|
+
const id = req.params.id;
|
|
31726
|
+
const validation = Joi46.object({
|
|
31727
|
+
id: Joi46.string().hex().required()
|
|
31728
|
+
});
|
|
31729
|
+
const { error } = validation.validate({ id });
|
|
31730
|
+
if (error) {
|
|
31731
|
+
next(new BadRequestError84(error.message));
|
|
31732
|
+
return;
|
|
31733
|
+
}
|
|
31734
|
+
try {
|
|
31735
|
+
const curriculum = await _getById(id);
|
|
31736
|
+
res.json({
|
|
31737
|
+
message: "Successfully retrieved curriculum.",
|
|
31738
|
+
data: { curriculum }
|
|
31739
|
+
});
|
|
31740
|
+
return;
|
|
31741
|
+
} catch (error2) {
|
|
31742
|
+
next(error2);
|
|
31743
|
+
}
|
|
31744
|
+
}
|
|
31745
|
+
async function deleteById(req, res, next) {
|
|
31746
|
+
const id = req.params.id;
|
|
31747
|
+
const validation = Joi46.object({
|
|
31748
|
+
id: Joi46.string().hex().required()
|
|
31749
|
+
});
|
|
31750
|
+
const { error } = validation.validate({ id });
|
|
31751
|
+
if (error) {
|
|
31752
|
+
next(new BadRequestError84(error.message));
|
|
31753
|
+
return;
|
|
31754
|
+
}
|
|
31755
|
+
try {
|
|
31756
|
+
const result = await _deleteById(id);
|
|
31757
|
+
res.json({
|
|
31758
|
+
message: "Successfully deleted curriculum.",
|
|
31759
|
+
data: result
|
|
31760
|
+
});
|
|
31761
|
+
return;
|
|
31762
|
+
} catch (error2) {
|
|
31763
|
+
next(error2);
|
|
31764
|
+
}
|
|
31765
|
+
}
|
|
31766
|
+
return {
|
|
31767
|
+
add,
|
|
31768
|
+
getAll,
|
|
31769
|
+
getById,
|
|
31770
|
+
updateById,
|
|
31771
|
+
deleteById
|
|
29967
31772
|
};
|
|
29968
31773
|
}
|
|
29969
31774
|
export {
|
|
@@ -29987,12 +31792,14 @@ export {
|
|
|
29987
31792
|
MAsset,
|
|
29988
31793
|
MBuilding,
|
|
29989
31794
|
MBuildingUnit,
|
|
31795
|
+
MCurriculum,
|
|
29990
31796
|
MDivision,
|
|
29991
31797
|
MEntity,
|
|
29992
31798
|
MFile,
|
|
29993
31799
|
MMember,
|
|
29994
31800
|
MONGO_DB,
|
|
29995
31801
|
MONGO_URI,
|
|
31802
|
+
MOffice,
|
|
29996
31803
|
MOrder,
|
|
29997
31804
|
MOrg,
|
|
29998
31805
|
MPaymentMethod,
|
|
@@ -30033,7 +31840,9 @@ export {
|
|
|
30033
31840
|
schemaAssetUpdateOption,
|
|
30034
31841
|
schemaBuilding,
|
|
30035
31842
|
schemaBuildingUnit,
|
|
31843
|
+
schemaCurriculum,
|
|
30036
31844
|
schemaDivision,
|
|
31845
|
+
schemaOffice,
|
|
30037
31846
|
schemaPlantilla,
|
|
30038
31847
|
schemaRegion,
|
|
30039
31848
|
schemaSchool,
|
|
@@ -30051,6 +31860,8 @@ export {
|
|
|
30051
31860
|
useBuildingUnitRepo,
|
|
30052
31861
|
useCounterModel,
|
|
30053
31862
|
useCounterRepo,
|
|
31863
|
+
useCurriculumController,
|
|
31864
|
+
useCurriculumRepo,
|
|
30054
31865
|
useDivisionController,
|
|
30055
31866
|
useDivisionRepo,
|
|
30056
31867
|
useDivisionService,
|
|
@@ -30066,6 +31877,9 @@ export {
|
|
|
30066
31877
|
useInvoiceService,
|
|
30067
31878
|
useMemberController,
|
|
30068
31879
|
useMemberRepo,
|
|
31880
|
+
useOfficeController,
|
|
31881
|
+
useOfficeRepo,
|
|
31882
|
+
useOfficeService,
|
|
30069
31883
|
useOrderController,
|
|
30070
31884
|
useOrderRepo,
|
|
30071
31885
|
useOrgController,
|