tango-app-api-trax 3.7.13-qid-halfshutter-6 → 3.7.13-qid-halfshutter-8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tango-app-api-trax",
3
- "version": "3.7.13-qid-halfshutter-6",
3
+ "version": "3.7.13-qid-halfshutter-8",
4
4
  "description": "Trax",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1,4 +1,4 @@
1
- import { logger, signedUrl, fileUpload, getOtp, sendEmailWithSES, getUuid, insertOpenSearchData } from 'tango-app-api-middleware';
1
+ import { logger, signedUrl, fileUpload, getOtp, sendEmailWithSES, getUuid, insertOpenSearchData, listFileByPath, getObject, deleteFiles } from 'tango-app-api-middleware';
2
2
  import * as processedchecklist from '../services/processedchecklist.services.js';
3
3
  import * as processedtask from '../services/processedTaskList.service.js';
4
4
  import * as PCLconfig from '../services/processedchecklistconfig.services.js';
@@ -19,23 +19,13 @@ import timeZone from 'dayjs/plugin/timezone.js';
19
19
  import { findOTP, updateOneOTP } from '../services/otp.service.js';
20
20
  import * as clientService from '../services/clients.services.js';
21
21
  import { create } from '../services/authentication.service.js';
22
- import * as fs from 'fs';
23
- import { join, dirname } from 'path';
22
+ import { join } from 'path';
24
23
  import handlebars from 'handlebars';
25
24
  dayjs.extend( customParseFormat );
26
25
  dayjs.extend( timeZone );
27
26
  import isSameOrBefore from 'dayjs/plugin/isSameOrBefore.js';
28
27
  import * as cameraService from '../services/camera.service.js';
29
28
  dayjs.extend( isSameOrBefore );
30
- import { fileURLToPath } from 'url';
31
- const fsp = fs.promises;
32
-
33
- const __filename = fileURLToPath( import.meta.url );
34
- const __dirname = dirname( __filename );
35
- const UPLOAD_DIR = join( __dirname, '/uploads' );
36
- if ( !fs.existsSync( UPLOAD_DIR ) ) {
37
- fs.mkdirSync( UPLOAD_DIR, { recursive: true } );
38
- }
39
29
 
40
30
  export async function storeList( req, res ) {
41
31
  try {
@@ -3781,7 +3771,7 @@ export async function uploadAnswerImage( req, res ) {
3781
3771
  let imageUrl;
3782
3772
  let filePath = `${folder}/${req.user.clientId}/${date}/${input.checklistId}/${input.sectionName.replace( ' ', '' )}/${input.questionNo}/`;
3783
3773
  let params = {
3784
- fileName: `${Date.now()}-${Math.floor( 1000 + Math.random() * 9000 )}.${req.files.answerImage.name.split( '.' )[1]}`,
3774
+ fileName: `${Date.now()}-${Math.floor( 1000 + Math.random() * 9000 )}-${req.files.answerImage.name}`,
3785
3775
  Key: filePath,
3786
3776
  Bucket: bucket.sop,
3787
3777
  body: req.files.answerImage.data,
@@ -4402,64 +4392,52 @@ export async function questionListV1( req, res ) {
4402
4392
  export async function chunkUpload( req, res ) {
4403
4393
  try {
4404
4394
  const { chunkIndex, totalChunks } = req.body;
4405
-
4406
- if ( !req.files || !req.files.answerImage ) {
4407
- return res.status( 400 ).json( { error: 'No chunk file uploaded' } );
4395
+ if ( chunkIndex === undefined || !totalChunks || !req.files || !req.files.answerImage ) {
4396
+ return res.status( 400 ).json( { error: 'Missing required params or file.' } );
4408
4397
  }
4409
-
4410
- if ( chunkIndex > totalChunks ) {
4411
- return res.sendError( 'Chunk index is wrong', 400 );
4398
+ const chunkNum = Number( chunkIndex );
4399
+ const chunkTotal = Number( totalChunks );
4400
+ const chunkFile = req.files.answerImage;
4401
+ const chunkKey = `traxVideoChunks/${req.user._id}/${chunkNum}`;
4402
+ let bucket;
4403
+ try {
4404
+ bucket = JSON.parse( process.env.BUCKET )?.sop;
4405
+ } catch {
4406
+ return res.sendError( 'Bucket config error', 500 );
4412
4407
  }
4413
-
4414
- const uploadedChunk = req.files.answerImage;
4415
- const baseName = uploadedChunk.name.split( '.' )[0];
4416
- const partPath = join( UPLOAD_DIR, `${baseName}.part_${chunkIndex}` );
4417
-
4418
- fs.rename( uploadedChunk.tempFilePath, partPath, async ( err ) => {
4419
- if ( err ) {
4420
- return res.sendError( 'Chunk save failed', 500 );
4421
- }
4422
-
4423
- // If not final chunk
4424
- if ( chunkIndex < totalChunks ) {
4425
- return res.sendSuccess( { message: 'Chunk received', chunkIndex } );
4426
- }
4427
-
4428
- // Final chunk received: Merge now
4429
- try {
4430
- const finalPath = join( UPLOAD_DIR, uploadedChunk.name );
4431
- const writeStream = fs.createWriteStream( finalPath );
4432
-
4433
- for ( let i = 1; i <= totalChunks; i++ ) {
4434
- const chunkPath = join( UPLOAD_DIR, `${baseName}.part_${i}` );
4435
- const data = await fsp.readFile( chunkPath );
4436
- writeStream.write( data );
4437
- await fsp.unlink( chunkPath ); // delete part after writing
4438
- }
4439
-
4440
- writeStream.end();
4441
-
4442
- writeStream.on( 'finish', async () => {
4443
- try {
4444
- const fileData = await fsp.readFile( finalPath );
4445
-
4446
- req.files.answerImage = {
4447
- data: fileData,
4448
- name: uploadedChunk.name,
4449
- mimetype: uploadedChunk.mimetype,
4450
- };
4451
-
4452
- await fsp.unlink( finalPath );
4453
-
4454
- uploadAnswerImage( req, res );
4455
- } catch ( err ) {
4456
- return res.sendError( 'Final file error', 500 );
4457
- }
4458
- } );
4459
- } catch ( err ) {
4460
- return res.sendError( 'Chunk merge failed', 500 );
4461
- }
4408
+ await fileUpload( {
4409
+ fileName: '',
4410
+ Key: chunkKey,
4411
+ Bucket: bucket,
4412
+ ContentType: chunkFile.mimetype,
4413
+ body: chunkFile.data,
4414
+ } );
4415
+ if ( chunkNum < chunkTotal ) {
4416
+ return res.sendSuccess( { message: 'Chunk uploaded to S3', chunkIndex: chunkNum } );
4417
+ }
4418
+ const prefix = `traxVideoChunks/${req.user._id}/`;
4419
+ const s3FilesResp = await listFileByPath( { Bucket: bucket, file_path: prefix, MaxKeys: chunkTotal } );
4420
+ const chunkObjs = s3FilesResp?.data || [];
4421
+ chunkObjs.sort( ( a, b ) => {
4422
+ const ai = Number( a.Key.split( '/' ).pop() );
4423
+ const bi = Number( b.Key.split( '/' ).pop() );
4424
+ return ai - bi;
4462
4425
  } );
4426
+ const buffers = [];
4427
+ for ( const obj of chunkObjs ) {
4428
+ const s3Obj = await getObject( { Bucket: bucket, Key: obj.Key } );
4429
+ buffers.push( Buffer.from( s3Obj.Body ) );
4430
+ }
4431
+ const finalBuffer = Buffer.concat( buffers );
4432
+ try {
4433
+ await deleteFiles( bucket, prefix );
4434
+ } catch ( e ) {}
4435
+ req.files.answerImage = {
4436
+ data: finalBuffer,
4437
+ name: chunkFile.name,
4438
+ mimetype: chunkFile.mimetype,
4439
+ };
4440
+ return uploadAnswerImage( req, res );
4463
4441
  } catch ( e ) {
4464
4442
  logger.error( { functionName: 'chunkUpload', error: e } );
4465
4443
  return res.sendError( e, 500 );