modpacksio-common
Version:
Common code for Modpacks.io services
177 lines (169 loc) • 5.08 kB
JavaScript
const Schema = require('mongoose').Schema;
const id = require('../id');
const SLUG_REGEX = /^[0-9a-zA-Z-]*$/;
const SEM_VER_REGEX = /^([0-9]|[1-9][0-9]*)\.([0-9]|[1-9][0-9]*)\.([0-9]|[1-9][0-9]*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))$|^([0-9]|[1-9][0-9]*)\.([0-9]|[1-9][0-9]*)\.([0-9]|[1-9][0-9]*)$/;
const icons = ['https://i.imgur.com/DISt7j6.png', 'https://i.imgur.com/gV5yjzG.png', 'https://i.imgur.com/Ldw4ITJ.png', 'https://i.imgur.com/KDj4QRV.png', 'https://i.imgur.com/Yt5vjBW.png', 'https://i.imgur.com/qhFTgTR.png', 'https://i.imgur.com/tUgdmEV.png', 'https://i.imgur.com/C12dO93.png', 'https://i.imgur.com/HqJ0UuY.png', 'https://i.imgur.com/UMhLly3.png'];
// Author
const author = new Schema({
id: Number,
primary: {
type: Boolean,
default: false
},
role: {
type: String,
minlength: [ 2, 'Author role must be at least 2 characters long.'],
maxlength: [ 16, 'Author role must be a max of 16 characters.']
}
}, { _id: false, id: false });
// Image
const image = new Schema({
id: Number,
name: String,
description: String,
url: String //todo validation on these fields
}, { _id: false, id: false });
// File
const file = new Schema({
id: Number,
created: {
type: Number,
default: new Date().getTime()
},
approved: {
type: Boolean,
default: false
},
type: {
type: String,
required: [ true, 'A file must have a type' ],
validate: {
validator: type => ['fabric', 'forge'].includes(type),
message: props => `${props.value} is not a valid type. Must be 'mod' or 'modpack'`
}
},
pre: {
type: Boolean,
default: false
},
name: {
type: String,
minlength: [2, 'Summary must be at least 2 characters long.'],
maxlength: [50, 'Summary must be a max of 50 characters.']
},
changelog: String,
version: {
type: String,
validate: {
validator: slug => SEM_VER_REGEX.test(slug),
message: props => `${props.value} must follow semantic versioning format.`
}
},
gameVersion: [{
type: String,
//todo validation
}],
javaVersion: [{
type: String,
//todo validation
}],
sha1: String,
url: String
}, { _id: false, id: false });
// Project
const project = new Schema({
_id: {
alias: 'id',
type: Number,
default: id.nextId()
},
type: {
type: String,
required: [ true, 'A project must have a type' ],
validate: {
validator: type => ['mod', 'modpack'].includes(type),
message: props => `${props.value} is not a valid type. Must be 'mod' or 'modpack'`
}
},
approved: {
type: Boolean,
default: false
},
created: {
type: Number,
default: new Date().getTime()
},
updated: {
type: Number,
default: new Date().getTime()
},
name: String,
slug: {
type: String,
validate: {
validator: slug => SLUG_REGEX.test(slug),
message: props => `${props.value} is not a valid url member.`
}
},
summary: {
type: String,
minlength: [ 10, 'Summary must be at least 10 characters long.'],
maxlength: [ 100, 'Summary must be a max of 100 characters.']
},
description: String,
downloads: {
type: Number,
default: 0,
},
license: {
title: {
type: String,
default: 'All Rights Reserved'
},
body: {
type: String,
default: 'All Rights Reserved unless otherwise explicitly stated.'
}
},
authors: [author],
categories: [Number],
icon: {
type: String,
default: icons[icons.length * Math.random() | 0]
},
images: [image],
languages: [String], //todo language validation
files: [file],
_status: {
approvedBy: Number,
approvedAt: Number
}
});
project.methods.populate = async function () {
// Populate Authors
const { User } = require('../database');
const raw = this.toObject({ virtuals: true, versionKey: false });
delete raw._id;
for (let i = 0; i < raw.authors.length; i++) {
const user = await User.findOne({ _id: raw.authors[i].id }).select('username icon');
if (user == null)
throw new Error(`Project contains invalid user! (${raw.authors[i].id})`);
const rtn = { ...raw.authors[i], ...user.toObject({ }) };
delete rtn._id;
raw.authors[i] = rtn;
}
// Populate Categories
// todo
return raw;
};
project.methods.toPublic = async function (status = false, shard = false) {
const doc = await this.populate();
doc.files = doc.files.filter(file => file.approved);
if (!status)
delete doc._status;
if (!shard)
delete doc._shard;
delete doc.type;
return doc;
};
module.exports = { project, file };