feat: Media attachment system

This commit is contained in:
Ahmed Bouhuolia
2020-04-23 21:02:17 +02:00
parent 11e3d4c1a9
commit 1c6a067db7
6 changed files with 178 additions and 1 deletions

View File

@@ -22,4 +22,11 @@ module.exports = {
superUser: 'root',
superPassword: '123123123',
},
mail: {
host: 'smtp.mailtrap.io',
port: 587,
secure: false,
username: '842f331d3dc005',
password: '172f97b34f1a17',
}
};

View File

@@ -0,0 +1,12 @@
exports.up = function(knex) {
return knex.schema.createTable('media', (table) => {
table.increments();
table.string('attachment_file');
table.timestamps();
});
};
exports.down = function(knex) {
return knex.schema.dropTableIfExists('media');
};

View File

@@ -147,11 +147,11 @@ export default {
const hashedPassword = await hashPassword(form.password);
const userInsert = {
...pick(form, ['first_name', 'last_name', 'email', 'phone_number']),
password: hashedPassword,
active: true,
};
const registeredUser = await SystemUser.query().insert({
...userInsert,
password: hashedPassword,
tenant_id: tenantOrganization.id,
});
await dbManager.createDb(`bigcapital_tenant_${organizationId}`);

View File

@@ -0,0 +1,146 @@
import express from 'express';
import { check, param, query, validationResult } from 'express-validator';
import fs from 'fs';
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
import TenancyMiddleware from '@/http/middleware/TenancyMiddleware';
import jwtAuth from '@/http/middleware/jwtAuth';
import Logger from '@/services/Logger';
const fsPromises = fs.promises;
export default {
/**
* Router constructor.
*/
router() {
const router = express.Router();
router.use(jwtAuth);
router.use(TenancyMiddleware);
router.post('/upload',
this.upload.validation,
asyncMiddleware(this.upload.handler));
router.delete('/delete/:id',
this.delete.validation,
asyncMiddleware(this.delete.handler));
router.get('/',
this.get.validation,
asyncMiddleware(this.get.handler));
return router;
},
/**
* Retrieve all or the given attachment ids.
*/
get: {
validation: [
query('ids'),
],
async handler(req, res) {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.boom.badData(null, {
code: 'validation_error', ...validationErrors,
});
}
const { Media } = req.models;
const media = await Media.query().onBuild((builder) => {
if (req.query.ids) {
const ids = Array.isArray(req.query.ids) ? req.query.ids : [req.query.ids];
builder.whereIn('id', ids);
}
});
return res.status(200).send({ media });
},
},
/**
* Uploads the given attachment file.
*/
upload: {
validation: [
// check('attachment').exists(),
],
async handler(req, res) {
if (!req.files.attachment) {
return res.status(400).send({
errors: [{ type: 'ATTACHMENT.NOT.FOUND', code: 200 }],
});
}
const publicPath = 'storage/app/public/';
const attachmentsMimes = ['image/png', 'image/jpeg'];
const { attachment } = req.files;
const { Media } = req.models;
const errorReasons = [];
// Validate the attachment.
if (attachment && attachmentsMimes.indexOf(attachment.mimetype) === -1) {
errorReasons.push({ type: 'ATTACHMENT.MINETYPE.NOT.SUPPORTED', code: 160 });
}
// Catch all error reasons to response 400.
if (errorReasons.length > 0) {
return res.status(400).send({ errors: errorReasons });
}
try {
await attachment.mv(`${publicPath}${req.organizationId}/${attachment.md5}.png`);
Logger.log('info', 'Attachment uploaded successfully');
} catch (error) {
Logger.log('info', 'Attachment uploading failed.', { error });
}
const media = await Media.query().insert({
attachment_file: `${attachment.md5}.png`,
});
return res.status(200).send({ media });
},
},
/**
* Deletes the given attachment ids from file system and database.
*/
delete: {
validation: [
param('id').exists().isNumeric().toInt(),
],
async handler(req, res) {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.boom.badData(null, {
code: 'validation_error', ...validationErrors,
});
}
const { Media } = req.models;
const { id } = req.params;
const media = await Media.query().where('id', id).first();
if (!media) {
return res.status(400).send({
errors: [{ type: 'MEDIA.ID.NOT.FOUND', code: 200 }],
});
}
const publicPath = 'storage/app/public/';
const tenantPath = `${publicPath}${req.organizationId}`;
try {
await fsPromises.unlink(`${tenantPath}/${media.attachmentFile}`);
Logger.log('error', 'Attachment file has been deleted.');
} catch (error) {
Logger.log('error', 'Delete item attachment file delete failed.', { error });
}
await Media.query().where('id', media.id).delete();
return res.status(200).send();
},
},
};

View File

@@ -25,6 +25,7 @@ import Resources from './controllers/Resources';
import ExchangeRates from '@/http/controllers/ExchangeRates';
// import SalesReports from '@/http/controllers/SalesReports';
// import PurchasesReports from '@/http/controllers/PurchasesReports';
import Media from '@/http/controllers/Media';
export default (app) => {
// app.use('/api/oauth2', OAuth2.router());
@@ -51,6 +52,7 @@ export default (app) => {
// app.use('/api/budget', Budget.router());
app.use('/api/resources', Resources.router());
app.use('/api/exchange_rates', ExchangeRates.router());
app.use('/api/media', Media.router());
// app.use('/api/currency_adjustment', CurrencyAdjustment.router());
// app.use('/api/reports/sales', SalesReports.router());
// app.use('/api/reports/purchases', PurchasesReports.router());

View File

@@ -0,0 +1,10 @@
import TenantModel from '@/models/TenantModel';
export default class Media extends TenantModel {
/**
* Table name
*/
static get tableName() {
return 'media';
}
}