dt-common-device
Version:
A secure and robust device management library for IoT applications
301 lines (300 loc) • 9.31 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.IssueSchema = exports.IssueModel = void 0;
const mongoose_1 = __importStar(require("mongoose"));
const issue_types_1 = require("./issue.types");
// Comment sub-schema
const CommentSchema = new mongoose_1.Schema({
id: { type: String, required: true },
userId: { type: String, required: true },
content: { type: String, required: true },
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date },
}, { _id: false });
// Main Issue schema
const IssueSchema = new mongoose_1.Schema({
category: {
type: String,
enum: Object.values(issue_types_1.IssuesCategory),
required: true,
},
propertyId: {
type: String,
required: true,
index: true,
},
zoneId: {
type: String,
required: false,
index: true,
},
zoneName: {
type: String,
required: false,
},
title: {
type: String,
required: true,
trim: true,
},
description: {
type: String,
required: true,
trim: true,
},
entityId: {
type: String,
index: true,
},
entityType: {
type: String,
enum: Object.values(issue_types_1.EntityType),
required: true,
index: true,
},
entitySubType: {
type: String,
enum: Object.values(issue_types_1.EntitySubType),
required: true,
index: true,
},
status: {
type: String,
enum: Object.values(issue_types_1.IssueStatus),
default: issue_types_1.IssueStatus.PENDING,
index: true,
},
type: {
type: String,
enum: Object.values(issue_types_1.IssueType),
required: true,
},
priority: {
type: String,
enum: Object.values(issue_types_1.IssuePriority),
default: issue_types_1.IssuePriority.LOW,
},
assignedTo: {
type: String,
index: true,
},
createdBy: {
type: String,
required: true,
},
updatedBy: {
type: String,
},
isDeleted: {
type: Boolean,
default: false,
},
createdAt: {
type: Date,
default: Date.now,
},
updatedAt: {
type: Date,
default: Date.now,
},
resolvedAt: {
type: Date,
},
dueDate: {
type: Date,
},
comments: {
type: [CommentSchema],
default: [],
},
}, {
collection: "dt_issues",
toJSON: { virtuals: true },
toObject: { virtuals: true },
id: false, // Disable the virtual id field since we're handling it manually
});
exports.IssueSchema = IssueSchema;
IssueSchema.index({ propertyId: 1, status: 1 });
IssueSchema.index({ zoneId: 1, status: 1 });
IssueSchema.index({ assignedTo: 1, status: 1 });
IssueSchema.index({ entityId: 1, entityType: 1 });
// Pre-save middleware to update the updatedAt field
IssueSchema.pre("save", function (next) {
this.updatedAt = new Date();
next();
});
// Pre-update middleware to update the updatedAt field
IssueSchema.pre(["updateOne", "findOneAndUpdate", "updateMany"], function (next) {
this.set({ updatedAt: new Date() });
next();
});
// Post middleware to transform all find results to plain objects
IssueSchema.post(/^find/, function (result) {
if (!result)
return;
// Handle array results (find)
if (Array.isArray(result)) {
result.forEach((doc) => {
if (doc && typeof doc.toObject === "function") {
const plainDoc = doc.toObject();
// Transform _id to id and remove __v
plainDoc.id = plainDoc._id ? plainDoc._id.toString() : plainDoc._id;
delete plainDoc._id;
delete plainDoc.__v;
// Replace the document with plain object
Object.assign(doc, plainDoc);
}
});
}
// Handle single document results (findOne, findById, etc.)
else if (result && typeof result.toObject === "function") {
const plainDoc = result.toObject();
// Transform _id to id and remove __v
plainDoc.id = plainDoc._id ? plainDoc._id.toString() : plainDoc._id;
delete plainDoc._id;
delete plainDoc.__v;
// Replace the document with plain object
Object.assign(result, plainDoc);
}
});
// Instance methods
IssueSchema.methods.addComment = function (commentData) {
const comment = {
id: new mongoose_1.default.Types.ObjectId().toString(),
userId: commentData.userId,
content: commentData.content,
createdAt: new Date(),
};
if (!this.comments) {
this.comments = [];
}
this.comments.push(comment);
};
IssueSchema.methods.updateComment = function (commentId, content, userId) {
if (!this.comments)
return false;
const comment = this.comments.find((c) => c.id === commentId);
if (comment) {
comment.content = content;
comment.updatedAt = new Date();
return true;
}
return false;
};
IssueSchema.methods.removeComment = function (commentId) {
if (!this.comments)
return false;
const initialLength = this.comments.length;
this.comments = this.comments.filter((c) => c.id !== commentId);
return this.comments.length < initialLength;
};
IssueSchema.methods.resolve = function (resolvedBy) {
this.status = issue_types_1.IssueStatus.RESOLVED;
this.resolvedAt = new Date();
this.updatedBy = resolvedBy;
};
IssueSchema.methods.reopen = function (updatedBy) {
this.status = issue_types_1.IssueStatus.PENDING;
this.resolvedAt = undefined;
this.updatedBy = updatedBy;
};
IssueSchema.methods.assign = function (userId, assignedBy) {
this.assignedTo = userId;
this.updatedBy = assignedBy;
};
IssueSchema.methods.unassign = function (unassignedBy) {
this.assignedTo = undefined;
this.updatedBy = unassignedBy;
};
// Static methods
IssueSchema.statics.findByAssignee = function (assignedTo, includeDeleted = false) {
const query = { assignedTo };
if (!includeDeleted) {
query.isDeleted = false;
}
return this.find(query).sort({ priority: -1, createdAt: -1 });
};
IssueSchema.statics.findOverdue = function (includeDeleted = false) {
const query = {
dueDate: { $lt: new Date() },
status: {
$nin: [issue_types_1.IssueStatus.RESOLVED, issue_types_1.IssueStatus.CLOSED, issue_types_1.IssueStatus.CANCELLED],
},
};
if (!includeDeleted) {
query.isDeleted = false;
}
return this.find(query).sort({ dueDate: 1 });
};
IssueSchema.statics.findUpcoming = function (days = 7, includeDeleted = false) {
const futureDate = new Date();
futureDate.setDate(futureDate.getDate() + days);
const query = {
dueDate: { $gte: new Date(), $lte: futureDate },
status: {
$nin: [issue_types_1.IssueStatus.RESOLVED, issue_types_1.IssueStatus.CLOSED, issue_types_1.IssueStatus.CANCELLED],
},
};
if (!includeDeleted) {
query.isDeleted = false;
}
return this.find(query).sort({ dueDate: 1 });
};
// Virtual for soft delete
IssueSchema.virtual("isActive").get(function () {
return !this.isDeleted;
});
// Ensure virtuals are serialized and transform to plain objects
IssueSchema.set("toJSON", {
virtuals: true,
transform: function (doc, ret) {
ret.id = ret._id ? ret._id.toString() : ret._id;
delete ret._id;
delete ret.__v;
return ret;
},
});
IssueSchema.set("toObject", {
virtuals: true,
transform: function (doc, ret) {
ret.id = ret._id ? ret._id.toString() : ret._id;
delete ret._id;
delete ret.__v;
return ret;
},
});
// Create and export the model
exports.IssueModel = mongoose_1.default.model("Issue", IssueSchema);