Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | 1x 1x 1x 1x 1x 1x 5x 5x 5x 8x 1x 1x 4x 4x 4x 3x 3x 3x 3x 3x 3x 3x 3x 3x 5x 5x 5x 5x 5x 5x 3x 3x 3x 2x 2x 2x 2x 3x 2x 2x 3x 3x 3x 2x 2x 1x 2x 2x 3x 1x 2x 2x 2x 1x | 'use strict';
const _ = require('lodash');
const Config = use('Config');
const Logger = use('Logger');
const AwsService = use('C2C/Services/AwsService');
const cleanUpSalonPhotosCron = Config.get('modules.salon.general.cleanUpSalonPhotosCron');
const defaultTimezone = Config.get('app.defaultTimezone');
class CleanUpSalonPhotos {
constructor() {
this.aws = new AwsService();
const salonConfigs = Config.get('modules.salon.general');
this.salonService = make(`${salonConfigs.namespace}/Services/SalonService`);
}
static get key() {
return 'CleanUpSalonPhotos-job';
}
static get concurrency() {
return 1;
}
static get options() {
return {
repeat: {
cron: cleanUpSalonPhotosCron,
tz: defaultTimezone,
},
};
}
async handle() {
let totalRowProcess = 0;
// count all photos with deletedAt < today 00:00:00
const countPhotosForCleanUp = await this.salonService.countPhotosForCleanUp();
if (countPhotosForCleanUp === 0) return totalRowProcess;
const limit = 1000; // api deleteObjects support delete up to 1000 Key
const totalPage = Math.ceil(countPhotosForCleanUp / limit);
for (let i = 1; i <= totalPage; i++) {
// get all photos with deletedAt < today 00:00:00 with limit = 1000
const photos = await this.salonService.getPhotosForCleanUp(limit);
Iif (photos.rows.length === 0) {
break;
}
const rowProcess = await this._deleteListS3Url(photos);
totalRowProcess += rowProcess;
}
return totalRowProcess;
}
async _deleteListS3Url(photos) {
// 1. set up data
const { mapS3WillDelete, uniqUrls } = photos.rows.reduce(
(m, p) => {
const key = 'images' + p.url.split('/images')[1];
const photoIdsWillDelete = m.mapS3WillDelete[key];
Eif (!photoIdsWillDelete) {
m.mapS3WillDelete[key] = [p.id];
m.uniqUrls.push(p.url);
} else {
photoIdsWillDelete.push(p.id);
}
return m;
},
{ mapS3WillDelete: {}, uniqUrls: [] },
);
// 2. get list photos still active by list urls
const listPhotoIgnore = await this.salonService.getPhotosByListUrls(uniqUrls);
// 3. Remove photo key still active and save list photo ids will hard delete in DB.
const photoIdsWillHardDelete = [];
listPhotoIgnore.rows.forEach((p) => {
const key = 'images' + p.url.split('/images')[1];
const photoIds = mapS3WillDelete[key];
photoIds && photoIdsWillHardDelete.push(...photoIds);
delete mapS3WillDelete[key];
});
// 4. Delete unused photos on S3
if (!_.isEmpty(mapS3WillDelete)) {
// Must decodeURIComponent image url to s3 key format since the image url is encoded string
const mapS3Key = {};
const s3Objects = Object.keys(mapS3WillDelete).map((key) => {
const decodeKey = decodeURIComponent(key);
mapS3Key[decodeKey] = mapS3WillDelete[key];
return { Key: decodeKey };
});
const s3DeleteResult = await this.aws.deleteObjects(s3Objects);
if (s3DeleteResult) {
// Add photoIds which have been deleted success on S3 to hard delete in DB.
s3DeleteResult.Deleted.forEach((item) => {
const photoIds = mapS3Key[item.Key];
photoIds && photoIdsWillHardDelete.push(...photoIds);
});
}
}
if (photoIdsWillHardDelete.length === 0) {
return 0;
}
// 5. force hard delete
const resultHardDelete = await this.salonService.forceDeletePhotos(photoIdsWillHardDelete);
// 6. logger
Logger.info(
`[CleanUpSalonPhotos._deleteListS3Url] - Deleted photos: %s`,
JSON.stringify({
photoIds: photoIdsWillHardDelete,
countPhotoIds: photoIdsWillHardDelete.length,
resultHardDelete,
}),
);
return photoIdsWillHardDelete.length;
}
}
module.exports = CleanUpSalonPhotos;
|