File model

The File model provides a file upload. It supports asynchronous uploading from web forms. Downloaded files are not used directly, but only as a source of data in other models.

Disable the updatedAttr attribute of the timestamp behavior. Downloaded files can not be edited, but only either deleted or used for re-saving in some models.

The STORE_DIR constant creates an absolute path to the directory of file allocation.


const Base = require('areto/db/ActiveRecord');
const path = require('path');

module.exports = class File extends Base {

  static getConstants () {
    return {
      TABLE: 'file',
      ATTRS: [
      RULES: [
        ['file', 'required'],
        ['file', 'file']
      BEHAVIORS: {
        timestamp: {
          Class: require('areto/behaviors/Timestamp'),
          updatedAttr: false
      STORE_DIR: path.join(__dirname, '../uploads/temp')

const fs = require('fs');
const multer = require('multer');
const mkdirp = require('mkdirp');
const CommonHelper = require('areto/helper/CommonHelper');

The findExpired method finds all files older than specified period.


findExpired (elapsedSeconds = 3600) {
  const expired = new Date( - parseInt(timeout) * 1000);
  return this.find(['<', 'updatedAt', expired]);

The model title is formed from original file name and stored name.


getTitle () {
  return `${this.get('originalName')} (${this.get('filename')})`;

The isImage method recognizes a image file.


isImage () {
  return this.get('mime').indexOf('image') === 0;

The getPath method returns absolute path of a saved file.


getPath () {
  return path.join(this.STORE_DIR, this.get('filename'));

The upload method saves a file to a server, using the multer npm-module.


async upload (req, res, user) {
  const uploader = this.createSingleUploader();
  await PromiseHelper.promise(uploader.bind(this, req, res));
  this.populateFileStats(req.file, user);
  this.set('file', this.getFileStats());

createSingleUploader () {
  return multer({
    storage: this.createUploaderStorage()

createUploaderStorage () {
  return multer.diskStorage({
    destination: this.generateStoreDir.bind(this),
    filename: this.generateFilename.bind(this)

The generateStoreDir, generateFilename methods create a directory and generate a file name to save.


generateStoreDir (req, file, callback) {
  mkdirp(this.STORE_DIR, err => callback(err, this.STORE_DIR));

generateFilename (req, file, callback) {
  callback(null, + CommonHelper.getRandom(11, 99));

The populateFileStats method extracts values of a file and request.


populateFileStats (file, req, user) {
    userId: user.getId(),
    originalName: file.originalname,
    filename: file.filename,
    mime: file.mimetype,
    extension: path.extname(file.originalname).substring(1).toLowerCase(),
    size: file.size,
    ip: req.ip

The getFileStats method returns data needed to validate a uploaded file.


getFileStats () {
  return {
    model: this,
    path: this.getPath(),
    size: this.get('size'),
    extension: this.get('extension'),
    mime: this.get('mime')

The afterDelete handler deletes a file from file system. It is called after the deletion of model.


async afterDelete () {
  await super.afterDelete();