DTP Social Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

186 lines
5.5 KiB

// cache.js
// Copyright (C) 2022 DTP Technologies, LLC
// License: Apache-2.0
'use strict';
const mongoose = require('mongoose');
const Attachment = mongoose.model('Attachment');
const { SiteService } = require('../../lib/site-lib');
class AttachmentService extends SiteService {
constructor (dtp) {
super(dtp, module.exports);
}
async start ( ) {
await super.start();
const { user: userService } = this.dtp.services;
this.populateAttachment = [
{
path: 'item',
},
{
path: 'owner',
select: userService.USER_SELECT,
},
];
this.queue = this.getJobQueue('media');
// this.template = this.loadViewTemplate('attachment/components/attachment-standalone.pug');
}
async create (owner, attachmentDefinition, file) {
const { minio: minioService } = this.dtp.services;
const NOW = new Date();
/*
* Fill in as much of the attachment as we can prior to uploading
*/
let attachment = new Attachment();
attachment.created = NOW;
attachment.ownerType = owner.type;
attachment.owner = owner._id;
attachment.itemType = attachmentDefinition.itemType;
attachment.item = mongoose.Types.ObjectId(attachmentDefinition.item._id || attachmentDefinition.item);
attachment.flags.isSensitive = attachmentDefinition.isSensitive === 'on';
/*
* Upload the original file to storage
*/
const attachmentId = attachment._id.toString();
attachment.original.bucket = process.env.MINIO_ATTACHMENT_BUCKET || 'dtp-attachments';
attachment.original.key = this.getAttachmentKey(attachment, 'original');
attachment.original.mime = file.mimetype;
attachment.original.size = file.size;
const response = await minioService.uploadFile({
bucket: attachment.file.bucket,
key: attachment.file.key,
filePath: file.path,
metadata: {
'X-DTP-Attachment-ID': attachmentId,
'Content-Type': attachment.metadata.mime,
'Content-Length': file.size,
},
});
/*
* Complete the attachment definition, and save it.
*/
attachment.original.etag = response.etag;
await attachment.save();
attachment = await this.getById(attachment._id);
await this.queue.add('attachment-ingest', { attachmentId: attachment._id });
return attachment;
}
getAttachmentKey (attachment, slug) {
const attachmentId = attachment._id.toString();
const prefix = attachmentId.slice(-4); // last 4 for best entropy
return `/attachment/${prefix}/${attachmentId}/${attachmentId}-${slug}}`;
}
/**
* Retrieves populated Attachment documents attached to an item.
* @param {String} itemType The type of item (ex: 'ChatMessage')
* @param {*} itemId The _id of the item (ex: message._id)
* @returns Array of attachments associated with the item.
*/
async getForItem (itemType, itemId) {
const attachments = await Attachment
.find({ itemType, item: itemId })
.sort({ order: 1, created: 1 })
.populate(this.populateAttachment)
.lean();
return attachments;
}
/**
* Retrieves populated Attachment documents created by a specific owner.
* @param {User} owner The owner for which Attachments are being fetched.
* @param {*} pagination Optional pagination of data set
* @returns Array of attachments owned by the specified owner.
*/
async getForOwner (owner, pagination) {
const attachments = await Attachment
.find({ ownerType: owner.type, owner: owner._id })
.sort({ order: 1, created: 1 })
.skip(pagination.skip)
.limit(pagination.cpp)
.populate(this.populateAttachment)
.lean();
return attachments;
}
/**
*
* @param {mongoose.Types.ObjectId} attachmentId The ID of the attachment
* @param {Object} options `withOriginal` true|false
* @returns A populated Attachment document configured per options.
*/
async getById (attachmentId, options) {
options = Object.assign({
withOriginal: false,
}, options || { });
let q = Attachment.findById(attachmentId);
if (options.withOriginal) {
q = q.select('+original');
}
const attachment = await q.populate(this.populateAttachment).lean();
return attachment;
}
/**
* Updates the status of an Attachment.
* @param {Attachment} attachment The attachment being modified.
* @param {*} status The new status of the attachment
*/
async setStatus (attachment, status) {
await Attachment.updateOne({ _id: attachment._id }, { $set: { status } });
}
/**
* Passes an attachment and options through a Pug template to generate HTML
* output ready to be inserted into a DOM to present the attachment in the UI.
* @param {Attachment} attachment
* @param {Object} attachmentOptions Additional options passed to the template
* @returns HTML output of the template
*/
async render (attachment, attachmentOptions) {
return this.attachmentTemplate({ attachment, attachmentOptions });
}
/**
* Creates a Bull Queue job to delete an Attachment including it's processed
* and original media files.
* @param {Attachment} attachment The attachment to be deleted.
* @returns Bull Queue job handle for the newly created job to delete the
* attachment.
*/
async remove (attachment) {
this.log.info('creating job to delete attachment', { attachmentId: attachment._id });
return await this.queue.add('attachment-delete', { attachmentId: attachment._id });
}
}
module.exports = {
slug: 'attachment',
name: 'attachment',
create: (dtp) => { return new AttachmentService(dtp); },
};