Add size and owner fields to files

This commit is contained in:
Alice Gaudon 2020-06-14 18:10:01 +02:00
parent f6d9db6243
commit 6db8b1cd21
4 changed files with 29 additions and 5 deletions

View File

@ -1,7 +1,7 @@
import Controller from "wms-core/Controller"; import Controller from "wms-core/Controller";
import {REQUIRE_AUTH_MIDDLEWARE} from "wms-core/auth/AuthComponent"; import {REQUIRE_AUTH_MIDDLEWARE} from "wms-core/auth/AuthComponent";
import {Request, Response, Router} from "express"; import {Request, Response, Router} from "express";
import {BadRequestError, NotFoundHttpError, ServerError} from "wms-core/HttpError"; import {BadRequestError, ForbiddenHttpError, NotFoundHttpError, ServerError} from "wms-core/HttpError";
import FileModel from "../models/FileModel"; import FileModel from "../models/FileModel";
import {cryptoRandomDictionary} from "wms-core/Utils"; import {cryptoRandomDictionary} from "wms-core/Utils";
import config from "config"; import config from "config";
@ -19,10 +19,10 @@ export default class FileController extends Controller {
this.get('/files/:page?', this.getFileManager, 'file-manager', REQUIRE_AUTH_MIDDLEWARE); this.get('/files/:page?', this.getFileManager, 'file-manager', REQUIRE_AUTH_MIDDLEWARE);
this.get('/files/delete/:slug', this.deleteFile, 'delete-file-frontend', REQUIRE_AUTH_MIDDLEWARE); this.get('/files/delete/:slug', this.deleteFile, 'delete-file-frontend', REQUIRE_AUTH_MIDDLEWARE);
this.get('/:slug', this.downloadFile, 'get-file');
this.post('/', this.postFile, 'post-file', REQUIRE_AUTH_MIDDLEWARE); this.post('/', this.postFile, 'post-file', REQUIRE_AUTH_MIDDLEWARE);
this.delete('/delete/:slug', this.deleteFile, 'delete-file', REQUIRE_AUTH_MIDDLEWARE);
this.get('/:slug', this.downloadFile, 'get-file');
this.put('/:slug', this.putFile, 'put-file', REQUIRE_AUTH_MIDDLEWARE); this.put('/:slug', this.putFile, 'put-file', REQUIRE_AUTH_MIDDLEWARE);
this.delete('/:slug', this.deleteFile, 'delete-file', REQUIRE_AUTH_MIDDLEWARE);
} }
protected async getFileManager(req: Request, res: Response): Promise<void> { protected async getFileManager(req: Request, res: Response): Promise<void> {
@ -33,6 +33,7 @@ export default class FileController extends Controller {
} }
protected async downloadFile(req: Request, res: Response): Promise<void> { protected async downloadFile(req: Request, res: Response): Promise<void> {
console.log('heeey');
const file = await FileModel.getBySlug(req.params.slug); const file = await FileModel.getBySlug(req.params.slug);
if (!file || file.shouldBeDeleted()) throw new NotFoundHttpError('File', req.url); if (!file || file.shouldBeDeleted()) throw new NotFoundHttpError('File', req.url);
@ -71,10 +72,12 @@ export default class FileController extends Controller {
else if (req.body.expire_after_days !== undefined) ttl = parseInt(req.body.expire_after_days) * 24 * 3600; else if (req.body.expire_after_days !== undefined) ttl = parseInt(req.body.expire_after_days) * 24 * 3600;
const file = new FileModel({ const file = new FileModel({
user_id: req.models.user!.id,
slug: slug, slug: slug,
real_name: upload.originalname, real_name: upload.originalname,
storage_type: 'local', storage_type: 'local',
storage_path: 'storage/uploads/' + slug, storage_path: 'storage/uploads/' + slug,
size: upload.size,
ttl: ttl, ttl: ttl,
}); });
@ -94,8 +97,12 @@ export default class FileController extends Controller {
} }
protected async deleteFile(req: Request, res: Response): Promise<void> { protected async deleteFile(req: Request, res: Response): Promise<void> {
const slug = req.params.slug;
if (!slug) throw new BadRequestError('Cannot delete nothing.', 'Please provide a slug.', req.url);
const file = await FileModel.getBySlug(req.params.slug); const file = await FileModel.getBySlug(req.params.slug);
if (!file) throw new NotFoundHttpError('File', req.url); if (!file) throw new NotFoundHttpError('File', req.url);
if (!file.canDelete(req.models.user!.id!)) throw new ForbiddenHttpError('file', req.url);
switch (file.storage_type) { switch (file.storage_type) {
case 'local': case 'local':

View File

@ -5,10 +5,12 @@ export default class CreateFilesTable extends Migration {
public async install(connection: Connection): Promise<void> { public async install(connection: Connection): Promise<void> {
await this.query('CREATE TABLE files(' + await this.query('CREATE TABLE files(' +
'id INT NOT NULL AUTO_INCREMENT,' + 'id INT NOT NULL AUTO_INCREMENT,' +
'user_id INT NOT NULL,' +
'slug VARCHAR(259) UNIQUE NOT NULL,' + 'slug VARCHAR(259) UNIQUE NOT NULL,' +
'real_name VARCHAR(259) NOT NULL,' + 'real_name VARCHAR(259) NOT NULL,' +
'storage_type VARCHAR(64) NOT NULL,' + 'storage_type VARCHAR(64) NOT NULL,' +
'storage_path VARCHAR(1745) NOT NULL,' + 'storage_path VARCHAR(1745) NOT NULL,' +
'size INT UNSIGNED NOT NULL,' +
'created_at DATETIME NOT NULL DEFAULT NOW(),' + 'created_at DATETIME NOT NULL DEFAULT NOW(),' +
'ttl INT UNSIGNED NOT NULL,' + 'ttl INT UNSIGNED NOT NULL,' +
'PRIMARY KEY (id)' + 'PRIMARY KEY (id)' +

View File

@ -2,6 +2,7 @@ import Model from "wms-core/db/Model";
import Validator from "wms-core/db/Validator"; import Validator from "wms-core/db/Validator";
import Controller from "wms-core/Controller"; import Controller from "wms-core/Controller";
import config from "config"; import config from "config";
import User from "wms-core/auth/models/User";
export default class FileModel extends Model { export default class FileModel extends Model {
public static get table(): string { public static get table(): string {
@ -13,18 +14,22 @@ export default class FileModel extends Model {
return models.length > 0 ? models[0] : null; return models.length > 0 ? models[0] : null;
} }
public readonly user_id!: number;
public readonly slug!: string; public readonly slug!: string;
public readonly real_name!: string; public readonly real_name!: string;
public readonly storage_type!: FileStorage; public readonly storage_type!: FileStorage;
public readonly storage_path!: string; public readonly storage_path!: string;
public readonly size!: number;
public created_at?: Date; public created_at?: Date;
public readonly ttl!: number; public readonly ttl!: number;
protected defineProperties() { protected defineProperties() {
this.defineProperty('user_id', new Validator().defined().exists(User, 'id'));
this.defineProperty('slug', new Validator().defined().minLength(1).maxLength(259).unique(this, 'slug')); this.defineProperty('slug', new Validator().defined().minLength(1).maxLength(259).unique(this, 'slug'));
this.defineProperty('real_name', new Validator().defined().minLength(1).maxLength(259)); this.defineProperty('real_name', new Validator().defined().minLength(1).maxLength(259));
this.defineProperty('storage_type', new Validator().defined().maxLength(64)); this.defineProperty('storage_type', new Validator().defined().maxLength(64));
this.defineProperty('storage_path', new Validator().defined().maxLength(1745)); this.defineProperty('storage_path', new Validator().defined().maxLength(1745));
this.defineProperty('size', new Validator().defined().min(0));
this.defineProperty('created_at', new Validator()); this.defineProperty('created_at', new Validator());
this.defineProperty('ttl', new Validator().defined().min(0).max(4294967295)); this.defineProperty('ttl', new Validator().defined().min(0).max(4294967295));
} }
@ -47,6 +52,10 @@ export default class FileModel extends Model {
if (!expirationDate) return false; if (!expirationDate) return false;
return new Date().getTime() >= expirationDate.getTime(); return new Date().getTime() >= expirationDate.getTime();
} }
public canDelete(user_id: number): boolean {
return this.user_id === user_id;
}
} }
export type FileStorage = 'local'; export type FileStorage = 'local';

View File

@ -34,9 +34,11 @@
<thead> <thead>
<tr> <tr>
<th>#</th> <th>#</th>
<th>url</th> <th>URL</th>
<th>name</th> <th>Name</th>
<th>Size</th>
<th>Expires at</th> <th>Expires at</th>
<th>Actions</th>
</tr> </tr>
</thead> </thead>
@ -51,8 +53,12 @@
</div> </div>
</td> </td>
<td>{{ file.real_name }}</td> <td>{{ file.real_name }}</td>
<td>{{ (file.size / (1024 * 1024)).toFixed(2) }}MB</td>
{% set expires_at = file.getExpirationDate() %} {% set expires_at = file.getExpirationDate() %}
<td>{% if expires_at %}{{ expires_at.toISOString() }}{% else %}Never{% endif %}</td> <td>{% if expires_at %}{{ expires_at.toISOString() }}{% else %}Never{% endif %}</td>
<td>
<a href="{{ route('delete-file-frontend', file.slug) }}" class="button danger"><i data-feather="trash"></i> Delete</a>
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>