Skip to content

Commit

Permalink
feat: #14
Browse files Browse the repository at this point in the history
- Add deleteStatus == 0 in every query to filter not delete items
  • Loading branch information
Chinlinlee committed Aug 15, 2023
1 parent 221a740 commit fb151c3
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 91 deletions.
93 changes: 26 additions & 67 deletions api/dicom-web/controller/WADO-RS/deletion/service/delete.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,111 +12,70 @@ class DeleteService {
* @param {import("express").Response} res
* @param { "study" | "series" | "instance" } level
*/
constructor(req, res, level="study") {
constructor(req, res, level = "study") {
this.request = req;
this.response = res;
this.level = level;
}

async delete() {
let deleteFns = {};
deleteFns["study"] = async() => this.deleteStudy();
deleteFns["series"] = async() => this.deleteSeries();
deleteFns["instance"] = async() => this.deleteInstance();
deleteFns["study"] = async () => this.deleteStudy();
deleteFns["series"] = async () => this.deleteSeries();
deleteFns["instance"] = async () => this.deleteInstance();

await deleteFns[this.level]();
}

async deleteStudy() {
let studyImagesPathObjs = await dicomStudyModel.getPathGroupOfInstances({
let study = await dicomStudyModel.findOne({
...this.request.params
});

if(studyImagesPathObjs.length == 0) {
if (!study) {
throw new NotFoundInstanceError(`Can not found studyUID: ${this.request.params.studyUID} instances' files`);
}

for(let imagePathObj of studyImagesPathObjs) {
try {
await Promise.all([
dicomStudyModel.deleteOne({
studyUID: imagePathObj.studyUID
}),
dicomSeriesModel.deleteMany({
studyUID: imagePathObj.studyUID
}),
dicomModel.deleteMany({
studyUID: imagePathObj.studyUID
})
]);
await fsP.unlink(imagePathObj.instancePath);
} catch(e) {
console.error(e);
throw e;
}
try {
await study.incrementDeleteStatus();
} catch (e) {
console.error(e);
throw e;
}

}

async deleteSeries() {
let seriesImagesPathObjs = await dicomSeriesModel.getPathGroupOfInstances({
let aSeries = await dicomSeriesModel.findOne({
...this.request.params
});

if(seriesImagesPathObjs.length == 0) {
if (!aSeries) {
throw new NotFoundInstanceError(`Can not found studyUID: ${this.request.params.studyUID}, seriesUID: ${this.request.params.seriesUID}' files`);
}

for(let imagePathObj of seriesImagesPathObjs) {
try {
await Promise.all([
dicomSeriesModel.deleteMany({
$and: [
{
studyUID: imagePathObj.studyUID
},
{
seriesUID: imagePathObj.seriesUID
}
]

}),
dicomModel.deleteMany({
$and: [
{
studyUID: imagePathObj.studyUID
},
{
seriesUID: imagePathObj.seriesUID
}
]

})
]);
await fsP.unlink(imagePathObj.instancePath);
} catch(e) {
console.error(e);
throw e;
}
try {
await aSeries.incrementDeleteStatus();
} catch (e) {
console.error(e);
throw e;
}
}


async deleteInstance() {
let imagePathObj = await dicomModel.getPathOfInstance({
let instance = await dicomModel.findOne({
...this.request.params
});

if(!imagePathObj) {
if (!instance) {
throw new NotFoundInstanceError(`Can not found studyUID: ${this.request.params.studyUID}, seriesUID: ${this.request.params.seriesUID}, instanceUID: ${this.request.params.instanceUID} instances' files`);
}

try {
await Promise.all([
dicomModel.deleteOne({
instanceUID: imagePathObj.instanceUID
})
]);
await fsP.unlink(imagePathObj.instancePath);
} catch(e) {
await instance.incrementDeleteStatus();

} catch (e) {
console.error(e);
throw e;
}
Expand Down
5 changes: 5 additions & 0 deletions api/dicom-web/controller/WADO-RS/service/rendered.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,11 @@ async function getInstanceFrameObj(iParam, otherFields={}) {
"00080016.Value": {
$nin: notImageSOPClass
}
},
{
deleteStatus: {
$eq: 0
}
}
]
};
Expand Down
1 change: 1 addition & 0 deletions models/DICOM/dicom-json-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class DicomJsonModel {
instancePath: dicomFileSaveInfo.relativePath
});
_.merge(dicomJsonClone, mediaStorage);
_.set(dicomJsonClone, "deleteStatus", 0);

delete dicomJsonClone.sopClass;
delete dicomJsonClone.sopInstanceUID;
Expand Down
101 changes: 101 additions & 0 deletions models/mongodb/deleteSchedule.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
const schedule = require("node-schedule");
const moment = require("moment");
const { logger } = require("@root/utils/logs/log");
const dicomStudyModel = require("./models/dicomStudy");
const dicomModel = require("./models/dicom");
const dicomSeriesModel = require("./models/dicomSeries");

// Delete dicom with delete status >= 2
schedule.scheduleJob("*/5 * * * * *", async function () {
deleteExpireStudies().catch((e) => {
logger.error(e);
});
deleteExpireSeries().catch((e) => {
logger.error(e);
});
deleteExpireInstances().catch((e) => {
logger.error(e);
});
});


async function deleteExpireStudies() {
let deletedStudies = await dicomStudyModel.find({
deleteStatus: {
$gte: 2
}
});

for (let deletedStudy of deletedStudies) {
let updateAtDate = moment(deletedStudy.updatedAt);
let now = moment();
let diff = now.diff(updateAtDate, "seconds");
if (diff >= 30) {
let studyUID = deletedStudy.studyUID;

logger.info("delete expired study: " + studyUID);
await Promise.all([
dicomModel.deleteMany({
studyUID
}),
dicomSeriesModel.deleteMany({
studyUID
}),
deletedStudy.delete()
]);

await deletedStudy.deleteStudyFolder();
}
}
}

async function deleteExpireSeries() {
let deletedSeries = await dicomSeriesModel.find({
deleteStatus: {
$gte: 2
}
});

for (let aDeletedSeries of deletedSeries) {
let updateAtDate = moment(aDeletedSeries.updatedAt);
let now = moment();
let diff = now.diff(updateAtDate, "seconds");
if (diff >= 30) {
let {studyUID, seriesUID} = aDeletedSeries;

logger.info("delete expired series: " + seriesUID);
await Promise.all([
dicomModel.deleteMany({
$and: [
{ x0020000D: studyUID },
{ x0020000E: seriesUID }
]
}),
aDeletedSeries.delete()
]);

await aDeletedSeries.deleteSeriesFolder();
}
}
}

async function deleteExpireInstances() {
let deletedInstances = await dicomModel.find({
deleteStatus: {
$gte: 2
}
});

for (let deletedInstance of deletedInstances) {
let {instanceUID} = deletedInstance;

let updateAtDate = moment(deletedInstance.updatedAt);
let now = moment();
let diff = now.diff(updateAtDate, "days");
if (diff >= 30) {
logger.info("delete expired instance: " + instanceUID);
await deletedInstance.deleteInstance();
await deletedInstance.delete();
}
}
}
1 change: 1 addition & 0 deletions models/mongodb/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
const myMongoDB = require("./connector")();
require("./deleteSchedule");
module.exports = myMongoDB;
58 changes: 53 additions & 5 deletions models/mongodb/models/dicom.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const fsP = require("fs/promises");
const path = require("path");
const _ = require("lodash");
const mongoose = require("mongoose");
const {
Expand All @@ -24,6 +26,9 @@ let verifyingObserverSchema = new mongoose.Schema(
}
);

/**
* @constructs dicomModelSchema
*/
let dicomModelSchema = new mongoose.Schema(
{
"studyUID": {
Expand All @@ -44,6 +49,10 @@ let dicomModelSchema = new mongoose.Schema(
index: true,
required: true
},
"deleteStatus": {
type: Number,
default: 0
},
"00080020": new mongoose.Schema(dicomJsonAttributeDASchema, {
_id: false,
id: false,
Expand Down Expand Up @@ -116,7 +125,29 @@ let dicomModelSchema = new mongoose.Schema(
versionKey: false,
toObject: {
getters: true
}
},
methods: {
async incrementDeleteStatus() {
this.deleteStatus = this.deleteStatus + 1;
await this.save();
},
async deleteInstance() {
let instancePath = this.instancePath;
try {
logger.warn("Permanently delete instance: " + instancePath);

await fsP.unlink(
path.join(
raccoonConfig.dicomWebConfig.storeRootPath,
instancePath
)
);
} catch (e) {
console.error(e);
}
}
},
timestamps: true
}
);

Expand Down Expand Up @@ -340,7 +371,12 @@ dicomModelSchema.statics.getDicomJson = async function (queryOptions) {

let docs = await mongoose
.model("dicom")
.find(queryOptions.query, {
.find({
...queryOptions.query,
deleteStatus: {
$eq: 0
}
}, {
...instanceFields
})
.setOptions({
Expand Down Expand Up @@ -398,6 +434,11 @@ dicomModelSchema.statics.getPathOfInstance = async function (iParam) {
},
{
instanceUID: instanceUID
},
{
deleteStatus: {
$eq: 0
}
}
]
};
Expand Down Expand Up @@ -430,7 +471,16 @@ dicomModelSchema.statics.getPathOfInstance = async function (iParam) {
*/
dicomModelSchema.statics.getInstanceOfMedianIndex = async function (query) {
let instanceCountOfStudy = await mongoose.model("dicom").countDocuments({
studyUID: query.studyUID
$and: [
{
studyUID: query.studyUID
},
{
deleteStatus: {
$eq: 0
}
}
]
});

return await mongoose.model("dicom").findOne(query, {
Expand Down Expand Up @@ -461,8 +511,6 @@ dicomModelSchema.statics.getInstanceOfMedianIndex = async function (query) {
*
*/


/** @type {DicomModelSchema} */
let dicomModel = mongoose.model("dicom", dicomModelSchema, "dicom");

/** @type {DicomModelSchema} */
Expand Down
Loading

0 comments on commit fb151c3

Please sign in to comment.