tango-app-api-trax 3.9.30 → 3.9.32

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.
Files changed (51) hide show
  1. package/index.js +2 -1
  2. package/package.json +1 -1
  3. package/src/controllers/internalTrax.controller.js +112 -73
  4. package/src/controllers/mobileTrax.controller.js +69 -29
  5. package/src/controllers/trax.controller.js +3 -2
  6. package/src/controllers/traxDashboard.controllers.js +63 -54
  7. package/src/hbs/flag.hbs +1 -1
  8. package/src/hbs/login-otp.hbs +943 -943
  9. package/src/hbs/template.hbs +7 -0
  10. package/src/hbs/visit-checklist.hbs +51 -1
  11. package/src/logging/activityLogFlusher.js +59 -0
  12. package/src/logging/activityLogMiddleware.js +45 -0
  13. package/src/logging/activityLogStore.js +91 -0
  14. package/src/logging/compressBatches.js +83 -0
  15. package/src/logging/config.js +24 -0
  16. package/src/logging/createLoggableService.js +46 -0
  17. package/src/logging/logExternalCall.js +37 -0
  18. package/src/services/app.service.js +20 -14
  19. package/src/services/approver.service.js +28 -20
  20. package/src/services/authentication.service.js +12 -6
  21. package/src/services/camera.service.js +24 -18
  22. package/src/services/checklist.service.js +36 -31
  23. package/src/services/checklistAssign.service.js +44 -39
  24. package/src/services/checklistQuestion.service.js +40 -35
  25. package/src/services/checklistlog.service.js +40 -35
  26. package/src/services/clientRequest.service.js +12 -5
  27. package/src/services/clients.services.js +23 -18
  28. package/src/services/cluster.service.js +36 -28
  29. package/src/services/domain.service.js +33 -28
  30. package/src/services/download.services.js +48 -38
  31. package/src/services/group.service.js +28 -22
  32. package/src/services/lenskartEmployeeMapping.service.js +20 -15
  33. package/src/services/locus.service.js +41 -34
  34. package/src/services/notification.service.js +40 -31
  35. package/src/services/otp.service.js +24 -17
  36. package/src/services/planogram.service.js +12 -5
  37. package/src/services/processedTaskConfig.service.js +40 -32
  38. package/src/services/processedTaskList.service.js +36 -30
  39. package/src/services/processedchecklist.services.js +56 -48
  40. package/src/services/processedchecklistconfig.services.js +40 -35
  41. package/src/services/recurringFlagTracker.service.js +40 -33
  42. package/src/services/runAIFeatures.services.js +36 -31
  43. package/src/services/runAIRequest.services.js +44 -39
  44. package/src/services/store.service.js +36 -31
  45. package/src/services/tagging.service.js +12 -5
  46. package/src/services/taskConfig.service.js +40 -32
  47. package/src/services/teams.service.js +41 -30
  48. package/src/services/ticket.service.js +20 -15
  49. package/src/services/user.service.js +32 -25
  50. package/src/services/userAssignedstores.service.js +17 -10
  51. package/src/utils/visitChecklistPdf.utils.js +114 -11
@@ -267,6 +267,13 @@
267
267
  <img src="{{this}}" alt="test" width="200" height="180">
268
268
  {{/each}}
269
269
  </div>
270
+ {{#if validationVideo.length}}
271
+ <div class="Reference"><span>Uploaded Video</span><br>
272
+ {{#each validationVideo}}
273
+ <a href="{{this}}" target="_blank" style="text-decoration: underline;color:#0085D2">{{this}}</a><br>
274
+ {{/each}}
275
+ </div>
276
+ {{/if}}
270
277
  {{/eq}}
271
278
  </td>
272
279
  </tr>
@@ -75,6 +75,13 @@
75
75
  .q-answer-link{font-size:12px;color:#0085D2;text-decoration:underline;word-break:break-all}
76
76
  .q-answer-caption{font-size:11px;color:#666;margin-bottom:4px}
77
77
  .q-answer-remarks{font-size:11px;color:#666;margin-top:6px;white-space:pre-line}
78
+ /* User verification (Submitted By) */
79
+ .user-verify{margin-top:28px;padding-top:18px;border-top:1px solid #d9d9d9;break-inside:avoid}
80
+ .user-verify-title{font-size:15px;font-weight:700;color:#1a1a1a;margin-bottom:14px}
81
+ .user-verify-photo{display:block;width:200px;height:240px;object-fit:cover;border-radius:8px;margin-bottom:10px}
82
+ .user-verify-name{font-size:14px;color:#1a1a1a;font-weight:600}
83
+ .user-verify-sign-label{font-size:12px;color:#666;margin-top:16px;margin-bottom:6px;font-weight:600}
84
+ .user-verify-signature{display:block;width:220px;height:auto;max-height:110px;object-fit:contain;border:1px solid #eee;border-radius:6px;padding:6px;background:#fff}
78
85
  /* Footer */
79
86
  .page-footer{position:absolute;bottom:20px;left:40px;right:40px;display:flex;justify-content:space-between;align-items:center;font-size:11px;color:#999;border-top:1px solid #d9d9d9;padding-top:10px}
80
87
  .footer-brand{display:flex;align-items:center;gap:8px;font-weight:600;color:#0066CC;font-size:11px}
@@ -275,6 +282,30 @@
275
282
  {{/if}}
276
283
  {{/eq}}
277
284
  {{/neq}}
285
+ {{#unless this.hasReferenceImage}}
286
+ {{#if this.validation}}
287
+ {{#eq this.validationDisplayType 'image'}}
288
+ {{#if this.validationAnswer}}
289
+ <div class="q-answer-caption">Validation Image</div>
290
+ <img src="{{this.validationAnswer}}" alt="Validation Image" />
291
+ {{/if}}
292
+ {{/eq}}
293
+ {{#eq this.validationDisplayType 'multiImage'}}
294
+ {{#if this.validationImage.length}}
295
+ <div class="q-answer-caption">Validation Image</div>
296
+ {{#each this.validationImage}}
297
+ <img src="{{this}}" alt="Validation Image" />
298
+ {{/each}}
299
+ {{/if}}
300
+ {{#if this.validationVideo.length}}
301
+ <div class="q-answer-caption">Validation Video</div>
302
+ {{#each this.validationVideo}}
303
+ <a class="q-answer-link" href="{{this}}" target="_blank">{{this}}</a>
304
+ {{/each}}
305
+ {{/if}}
306
+ {{/eq}}
307
+ {{/if}}
308
+ {{/unless}}
278
309
  </td>
279
310
  <td style="width:50%;vertical-align:top;padding-left:8px">
280
311
  {{#eq this.answerType 'image'}}
@@ -294,13 +325,14 @@
294
325
  {{/neq}}
295
326
  {{/if}}
296
327
  {{/eq}}
328
+ {{#if this.hasReferenceImage}}
297
329
  {{#if this.validation}}
298
330
  {{#eq this.validationDisplayType 'image'}}
299
331
  {{#if this.validationAnswer}}
300
332
  <div class="q-answer-caption">Validation Image</div>
301
333
  <img src="{{this.validationAnswer}}" alt="Validation Image" />
302
334
  {{/if}}
303
- {{/eq}}
335
+ {{/eq}}
304
336
  {{#eq this.validationDisplayType 'multiImage'}}
305
337
  {{#if this.validationImage.length}}
306
338
  <div class="q-answer-caption">Validation Image</div>
@@ -308,8 +340,15 @@
308
340
  <img src="{{this}}" alt="Validation Image" />
309
341
  {{/each}}
310
342
  {{/if}}
343
+ {{#if this.validationVideo.length}}
344
+ <div class="q-answer-caption">Validation Video</div>
345
+ {{#each this.validationVideo}}
346
+ <a class="q-answer-link" href="{{this}}" target="_blank">{{this}}</a>
347
+ {{/each}}
348
+ {{/if}}
311
349
  {{/eq}}
312
350
  {{/if}}
351
+ {{/if}}
313
352
  </td>
314
353
  </tr></table>
315
354
  </div>
@@ -324,6 +363,17 @@
324
363
  {{/each}}
325
364
  </div>
326
365
  {{/each}}
366
+ {{#if showUserVerification}}
367
+ <div class="user-verify">
368
+ <div class="user-verify-title">Submitted By</div>
369
+ {{#if userImage}}
370
+ <img class="user-verify-photo" src="{{userImage}}" alt="Submitted by photo" />
371
+ {{/if}}
372
+ {{#if submittedBy}}
373
+ <div class="user-verify-name">{{submittedBy}}</div>
374
+ {{/if}}
375
+ </div>
376
+ {{/if}}
327
377
  </div>
328
378
 
329
379
  </body>
@@ -0,0 +1,59 @@
1
+ import { insertOpenSearchData, logger } from 'tango-app-api-middleware';
2
+ import { loggingConfig } from './config.js';
3
+ import { compressBatches } from './compressBatches.js';
4
+
5
+ export async function flushActivityLog( ctx, status ) {
6
+ if ( !loggingConfig.enabled ) return;
7
+ if ( !ctx ) return;
8
+
9
+ if ( ctx.steps.length === 0 && !ctx.error ) return;
10
+
11
+ const compressedSteps = safeCompress( ctx.steps );
12
+
13
+ const doc = {
14
+ version: loggingConfig.version,
15
+ requestId: ctx.requestId,
16
+ timestamp: new Date( ctx.startTime ).toISOString(),
17
+ duration: Date.now() - ctx.startTime,
18
+ user: ctx.user,
19
+ api: {
20
+ method: ctx.api.method,
21
+ path: ctx.api.path,
22
+ action: ctx.api.action,
23
+ body: stringifyBody( ctx.api.body ),
24
+ },
25
+ response: {
26
+ code: ctx.response?.code ?? null,
27
+ body: stringifyBody( ctx.response?.body ),
28
+ },
29
+ status,
30
+ steps: compressedSteps,
31
+ error: ctx.error,
32
+ };
33
+
34
+ try {
35
+ await insertOpenSearchData( loggingConfig.index, doc );
36
+ } catch ( e ) {
37
+ logger.error( { functionName: 'flushActivityLog', error: e } );
38
+ }
39
+ }
40
+
41
+ function safeCompress( steps ) {
42
+ try {
43
+ return compressBatches( steps );
44
+ } catch ( _e ) {
45
+ // Never let compression failure block log delivery — fall back to raw steps.
46
+ return steps;
47
+ }
48
+ }
49
+
50
+ function stringifyBody( body ) {
51
+ if ( body === null || body === undefined ) return null;
52
+ if ( typeof body === 'string' ) return body;
53
+ if ( body instanceof Error ) return body.message || String( body );
54
+ try {
55
+ return JSON.stringify( body );
56
+ } catch ( _e ) {
57
+ return '[unserializable]';
58
+ }
59
+ }
@@ -0,0 +1,45 @@
1
+ import { activityLogStore, createLogContext } from './activityLogStore.js';
2
+ import { flushActivityLog } from './activityLogFlusher.js';
3
+ import { loggingConfig } from './config.js';
4
+
5
+ function refreshUser( ctx, req ) {
6
+ if ( req?.user ) {
7
+ ctx.user = {
8
+ _id: req.user._id,
9
+ userName: req.user.userName,
10
+ email: req.user.email,
11
+ };
12
+ }
13
+ }
14
+
15
+ export default function traxActivityLogMiddleware( req, res, next ) {
16
+ if ( !loggingConfig.enabled ) return next();
17
+
18
+ const WRITE_METHODS = [ 'POST', 'PUT', 'PATCH', 'DELETE' ];
19
+ if ( !WRITE_METHODS.includes( req.method ) ) return next();
20
+
21
+ const ctx = createLogContext( req );
22
+
23
+ activityLogStore.run( ctx, () => {
24
+ const originalSendSuccess = res.sendSuccess;
25
+ const originalSendError = res.sendError;
26
+
27
+ res.sendSuccess = ( data ) => {
28
+ refreshUser( ctx, req );
29
+ ctx.response.code = 200;
30
+ ctx.response.body = data;
31
+ originalSendSuccess( data );
32
+ setImmediate( () => flushActivityLog( ctx, 'success' ).catch( () => {} ) );
33
+ };
34
+
35
+ res.sendError = ( message, code ) => {
36
+ refreshUser( ctx, req );
37
+ ctx.response.code = code ?? 500;
38
+ ctx.response.body = message;
39
+ originalSendError( message, code );
40
+ setImmediate( () => flushActivityLog( ctx, 'failed' ).catch( () => {} ) );
41
+ };
42
+
43
+ next();
44
+ } );
45
+ }
@@ -0,0 +1,91 @@
1
+ import { AsyncLocalStorage } from 'async_hooks';
2
+ import { randomUUID } from 'crypto';
3
+
4
+ export const activityLogStore = new AsyncLocalStorage();
5
+
6
+ const SENSITIVE_KEYS = [ 'password', 'token', 'secret', 'authorization' ];
7
+
8
+ export function createLogContext( req ) {
9
+ return {
10
+ requestId: randomUUID(),
11
+ startTime: Date.now(),
12
+ user: req.user ? {
13
+ _id: req.user._id,
14
+ userName: req.user.userName,
15
+ email: req.user.email,
16
+ } : null,
17
+ api: {
18
+ method: req.method,
19
+ path: req.path,
20
+ action: `${ req.method } ${ req.path }`,
21
+ body: sanitizeBody( req.body ),
22
+ },
23
+ response: {
24
+ code: null,
25
+ body: null,
26
+ },
27
+ steps: [],
28
+ stepCounter: 0,
29
+ error: null,
30
+ };
31
+ }
32
+
33
+ export function getLogContext() {
34
+ return activityLogStore.getStore();
35
+ }
36
+
37
+ export function pushStep( entry ) {
38
+ const ctx = getLogContext();
39
+ if ( !ctx ) return;
40
+
41
+ const last = ctx.steps[ctx.steps.length - 1];
42
+ if (
43
+ last &&
44
+ last.name === entry.name &&
45
+ last.type === entry.type &&
46
+ last.status === 'success' &&
47
+ entry.status === 'success'
48
+ ) {
49
+ last.count = ( last.count || 1 ) + 1;
50
+ last.ms += entry.ms;
51
+ return;
52
+ }
53
+
54
+ ctx.stepCounter++;
55
+ ctx.steps.push( {
56
+ stepIndex: ctx.stepCounter,
57
+ name: entry.name,
58
+ type: entry.type,
59
+ status: entry.status,
60
+ ms: entry.ms,
61
+ } );
62
+ }
63
+
64
+ export function pushStepFailure( entry, error ) {
65
+ const ctx = getLogContext();
66
+ if ( !ctx ) return;
67
+ ctx.stepCounter++;
68
+ const message = error?.message || String( error );
69
+ ctx.steps.push( {
70
+ stepIndex: ctx.stepCounter,
71
+ name: entry.name,
72
+ type: entry.type,
73
+ status: 'failed',
74
+ ms: entry.ms,
75
+ error: message,
76
+ } );
77
+ ctx.error = {
78
+ message,
79
+ failedAtStepIndex: ctx.stepCounter,
80
+ failedStepName: entry.name,
81
+ };
82
+ }
83
+
84
+ function sanitizeBody( body ) {
85
+ if ( !body || typeof body !== 'object' ) return body;
86
+ const cleaned = { ...body };
87
+ for ( const key of SENSITIVE_KEYS ) {
88
+ if ( cleaned[key] !== undefined ) cleaned[key] = '[REDACTED]';
89
+ }
90
+ return cleaned;
91
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Post-process a steps array to compress repeated adjacent cycles into a single
3
+ * "batch" entry. Complements the push-time collapse of identical adjacent
4
+ * steps (which merges A,A,A into A×3) by merging repeated *sequences*
5
+ * (A,B,C,A,B,C,A,B,C → batch[A→B→C]×3).
6
+ *
7
+ * Rules:
8
+ * - A cycle is detected only if the same ordered sequence of step names/types
9
+ * appears ≥ 2 times back-to-back.
10
+ * - Failed steps are never included in cycles — each failure stands alone so
11
+ * you can see exactly which iteration broke.
12
+ * - Greedy: smallest cycle length (≥ 2) wins. This gives the most compact,
13
+ * most readable output.
14
+ * - Cycle length is bounded to keep the O(n·k) scan cheap.
15
+ */
16
+
17
+ const MIN_CYCLE_LEN = 2;
18
+ const MAX_CYCLE_LEN = 10;
19
+
20
+ export function compressBatches( rawSteps ) {
21
+ if ( !Array.isArray( rawSteps ) || rawSteps.length < MIN_CYCLE_LEN * 2 ) return rawSteps;
22
+
23
+ const out = [];
24
+ let i = 0;
25
+ while ( i < rawSteps.length ) {
26
+ let absorbed = false;
27
+ const maxK = Math.min( MAX_CYCLE_LEN, Math.floor( ( rawSteps.length - i ) / 2 ) );
28
+
29
+ for ( let k = MIN_CYCLE_LEN; k <= maxK; k++ ) {
30
+ if ( !cycleEquals( rawSteps, i, k, i + k ) ) continue;
31
+
32
+ // At least 2 repeats confirmed. Count forward.
33
+ let repeats = 2;
34
+ let j = i + 2 * k;
35
+ while ( cycleEquals( rawSteps, i, k, j ) ) {
36
+ repeats++;
37
+ j += k;
38
+ }
39
+
40
+ const patternSteps = rawSteps.slice( i, i + k );
41
+ const totalMs = rawSteps.slice( i, j ).reduce( ( sum, s ) => sum + ( s.ms || 0 ), 0 );
42
+
43
+ out.push( {
44
+ stepIndex: out.length + 1,
45
+ name: patternSteps.map( ( s ) => s.count ? `${ s.name }×${ s.count }` : s.name ).join( ' → ' ),
46
+ type: 'batch',
47
+ status: 'success',
48
+ count: repeats,
49
+ ms: totalMs,
50
+ pattern: patternSteps.map( ( s ) => ( {
51
+ name: s.name,
52
+ type: s.type,
53
+ count: s.count ?? 1,
54
+ } ) ),
55
+ } );
56
+
57
+ i = j;
58
+ absorbed = true;
59
+ break;
60
+ }
61
+
62
+ if ( !absorbed ) {
63
+ out.push( { ...rawSteps[i], stepIndex: out.length + 1 } );
64
+ i++;
65
+ }
66
+ }
67
+
68
+ return out;
69
+ }
70
+
71
+ function cycleEquals( steps, patternStart, patternLen, checkStart ) {
72
+ if ( checkStart + patternLen > steps.length ) return false;
73
+ for ( let i = 0; i < patternLen; i++ ) {
74
+ const a = steps[patternStart + i];
75
+ const b = steps[checkStart + i];
76
+ if ( !a || !b ) return false;
77
+ if ( a.status === 'failed' || b.status === 'failed' ) return false;
78
+ if ( a.name !== b.name ) return false;
79
+ if ( a.type !== b.type ) return false;
80
+ if ( a.status !== b.status ) return false;
81
+ }
82
+ return true;
83
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Self-contained configuration for the activity logging module.
3
+ *
4
+ * Read directly from process.env so this module has zero dependency on
5
+ * consumers' env.js layout. Getters (not cached values) so dotenv can load
6
+ * after this module is imported.
7
+ */
8
+
9
+ const DEFAULT_INDEX = 'trax-activity-logs-test';
10
+ const LOG_VERSION = 'v1';
11
+
12
+ export const loggingConfig = {
13
+ get enabled() {
14
+ return process.env.TRAX_ACTIVITY_LOGGING === 'true';
15
+ },
16
+ get index() {
17
+ try {
18
+ return JSON.parse( process.env.OPENSEARCH || '{}' )?.traxActivityLog || DEFAULT_INDEX;
19
+ } catch ( _e ) {
20
+ return DEFAULT_INDEX;
21
+ }
22
+ },
23
+ version: LOG_VERSION,
24
+ };
@@ -0,0 +1,46 @@
1
+ import { getLogContext, pushStep, pushStepFailure } from './activityLogStore.js';
2
+ import { loggingConfig } from './config.js';
3
+
4
+ const WRITE_OPS = [
5
+ 'create',
6
+ 'updateOne',
7
+ 'updateMany',
8
+ 'deleteOne',
9
+ 'deleteMany',
10
+ 'upsertOne',
11
+ 'insertMany',
12
+ 'bulkUpsert',
13
+ 'bulkWrite',
14
+ 'removeKeys',
15
+ 'findOneAndUpdate',
16
+ 'findOneAndUpdate2',
17
+ 'updateOneArrayItem',
18
+ 'update',
19
+ ];
20
+
21
+ export function createLoggableService( serviceModule, collectionName ) {
22
+ // Install the proxy unconditionally. The enabled-check happens at call time
23
+ // inside the `get` trap so env vars loaded after module import (via dotenv)
24
+ // are observed correctly.
25
+ return new Proxy( serviceModule, {
26
+ get( target, prop ) {
27
+ const original = target[prop];
28
+ if ( !WRITE_OPS.includes( prop ) || typeof original !== 'function' ) return original;
29
+ if ( !loggingConfig.enabled ) return original;
30
+
31
+ return async function( ...args ) {
32
+ const ctx = getLogContext();
33
+ const start = Date.now();
34
+ const stepName = `${ collectionName }.${ prop }`;
35
+ try {
36
+ const result = await original.apply( target, args );
37
+ if ( ctx ) pushStep( { name: stepName, type: 'db', status: 'success', ms: Date.now() - start } );
38
+ return result;
39
+ } catch ( e ) {
40
+ if ( ctx ) pushStepFailure( { name: stepName, type: 'db', ms: Date.now() - start }, e );
41
+ throw e;
42
+ }
43
+ };
44
+ },
45
+ } );
46
+ }
@@ -0,0 +1,37 @@
1
+ import { pushStep, pushStepFailure } from './activityLogStore.js';
2
+
3
+ export async function logExternalCall( serviceName, url, options = {} ) {
4
+ const start = Date.now();
5
+ const stepName = `external.${ serviceName }`;
6
+ try {
7
+ const res = await fetch( url, options );
8
+ pushStep( {
9
+ name: stepName,
10
+ type: 'external',
11
+ status: res.ok ? 'success' : 'failed',
12
+ ms: Date.now() - start,
13
+ } );
14
+ return res;
15
+ } catch ( e ) {
16
+ pushStepFailure( { name: stepName, type: 'external', ms: Date.now() - start }, e );
17
+ throw e;
18
+ }
19
+ }
20
+
21
+ export async function logQueueMessage( serviceName, queueUrl, messageBody, sendMessageToQueueFn ) {
22
+ const start = Date.now();
23
+ const stepName = `external.${ serviceName }`;
24
+ try {
25
+ const result = await sendMessageToQueueFn( queueUrl, messageBody );
26
+ pushStep( {
27
+ name: stepName,
28
+ type: 'external',
29
+ status: 'success',
30
+ ms: Date.now() - start,
31
+ } );
32
+ return result;
33
+ } catch ( e ) {
34
+ pushStepFailure( { name: stepName, type: 'external', ms: Date.now() - start }, e );
35
+ throw e;
36
+ }
37
+ }
@@ -1,14 +1,20 @@
1
- import model from 'tango-api-schema';
2
-
3
- export const aggregate = async ( query ={} ) => {
4
- return model.appVersionModel.aggregate( query );
5
- };
6
-
7
- export const updateOne = async ( query, record ) => {
8
- return model.appVersionModel.updateOne( query, { $set: record }, { upsert: true } );
9
- };
10
-
11
- export const findOne = async ( query ={}, field={} ) => {
12
- return model.appVersionModel.findOne( query, field );
13
- };
14
-
1
+ import model from 'tango-api-schema';
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
3
+
4
+ const _methods = {
5
+ async aggregate( query ={} ) {
6
+ return model.appVersionModel.aggregate( query );
7
+ },
8
+ async updateOne( query, record ) {
9
+ return model.appVersionModel.updateOne( query, { $set: record }, { upsert: true } );
10
+ },
11
+ async findOne( query ={}, field={} ) {
12
+ return model.appVersionModel.findOne( query, field );
13
+ },
14
+ };
15
+
16
+ const _svc = createLoggableService( _methods, 'appversions' );
17
+
18
+ export const aggregate = ( ...args ) => _svc.aggregate( ...args );
19
+ export const updateOne = ( ...args ) => _svc.updateOne( ...args );
20
+ export const findOne = ( ...args ) => _svc.findOne( ...args );
@@ -1,20 +1,28 @@
1
- import model from 'tango-api-schema';
2
-
3
- export const create = async ( data ) => {
4
- return model.traxApproverModel.create( data );
5
- };
6
-
7
- export const updateMany = async ( query={}, record={} ) => {
8
- return model.traxApproverModel.updateMany( query, { $set: record } );
9
- };
10
-
11
- export const insertMany = async ( data = [] ) => {
12
- return model.traxApproverModel.insertMany( data );
13
- };
14
-
15
- export const find = async ( query ={}, field={} ) => {
16
- return model.traxApproverModel.find( query, field );
17
- };
18
- export const findOne = async ( query ={}, field={} ) => {
19
- return model.traxApproverModel.findOne( query, field );
20
- };
1
+ import model from 'tango-api-schema';
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
3
+
4
+ const _methods = {
5
+ async create( data ) {
6
+ return model.traxApproverModel.create( data );
7
+ },
8
+ async updateMany( query={}, record={} ) {
9
+ return model.traxApproverModel.updateMany( query, { $set: record } );
10
+ },
11
+ async insertMany( data = [] ) {
12
+ return model.traxApproverModel.insertMany( data );
13
+ },
14
+ async find( query ={}, field={} ) {
15
+ return model.traxApproverModel.find( query, field );
16
+ },
17
+ async findOne( query ={}, field={} ) {
18
+ return model.traxApproverModel.findOne( query, field );
19
+ },
20
+ };
21
+
22
+ const _svc = createLoggableService( _methods, 'approvers' );
23
+
24
+ export const create = ( ...args ) => _svc.create( ...args );
25
+ export const updateMany = ( ...args ) => _svc.updateMany( ...args );
26
+ export const insertMany = ( ...args ) => _svc.insertMany( ...args );
27
+ export const find = ( ...args ) => _svc.find( ...args );
28
+ export const findOne = ( ...args ) => _svc.findOne( ...args );
@@ -1,6 +1,12 @@
1
- import authenticationModel from 'tango-api-schema/schema/authentication.model.js';
2
-
3
- export async function create( data ) {
4
- return authenticationModel.create( data );
5
- }
6
-
1
+ import authenticationModel from 'tango-api-schema/schema/authentication.model.js';
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
3
+
4
+ const _methods = {
5
+ async create( data ) {
6
+ return authenticationModel.create( data );
7
+ },
8
+ };
9
+
10
+ const _svc = createLoggableService( _methods, 'authentications' );
11
+
12
+ export const create = ( ...args ) => _svc.create( ...args );
@@ -1,18 +1,24 @@
1
- import model from 'tango-api-schema';
2
-
3
- export const aggregate = async ( query ={} ) => {
4
- return model.cameraModel.aggregate( query );
5
- };
6
-
7
- export const updateOne = async ( query, record ) => {
8
- return model.cameraModel.updateOne( query, { $set: record }, { upsert: true } );
9
- };
10
-
11
- export const findOne = async ( query ={}, field={} ) => {
12
- return model.cameraModel.findOne( query, field );
13
- };
14
-
15
- export const find = async ( query ={}, field={} ) => {
16
- return model.cameraModel.find( query, field );
17
- };
18
-
1
+ import model from 'tango-api-schema';
2
+ import { createLoggableService } from '../logging/createLoggableService.js';
3
+
4
+ const _methods = {
5
+ async aggregate( query ={} ) {
6
+ return model.cameraModel.aggregate( query );
7
+ },
8
+ async updateOne( query, record ) {
9
+ return model.cameraModel.updateOne( query, { $set: record }, { upsert: true } );
10
+ },
11
+ async findOne( query ={}, field={} ) {
12
+ return model.cameraModel.findOne( query, field );
13
+ },
14
+ async find( query ={}, field={} ) {
15
+ return model.cameraModel.find( query, field );
16
+ },
17
+ };
18
+
19
+ const _svc = createLoggableService( _methods, 'cameras' );
20
+
21
+ export const aggregate = ( ...args ) => _svc.aggregate( ...args );
22
+ export const updateOne = ( ...args ) => _svc.updateOne( ...args );
23
+ export const findOne = ( ...args ) => _svc.findOne( ...args );
24
+ export const find = ( ...args ) => _svc.find( ...args );