forked from engineering/cloudservices
Compare commits
3 Commits
master
...
refactor/m
Author | SHA1 | Date |
---|---|---|
Hiroyuki | aa3c071c2b | |
Hiroyuki | 6de47a7e0d | |
Hiroyuki | b9d4a28c4f |
|
@ -39,6 +39,7 @@
|
|||
"import/prefer-default-export": "off",
|
||||
"no-useless-constructor": "off",
|
||||
"@typescript-eslint/no-useless-constructor": 2,
|
||||
"import/extensions": "off"
|
||||
"import/extensions": "off",
|
||||
"max-classes-per-file": "off"
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"eslint.enable": true,
|
||||
"eslint.validate": [
|
||||
{
|
||||
"language": "typescript",
|
||||
"autoFix": true
|
||||
}
|
||||
],
|
||||
"editor.tabSize": 2
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
"mongoose": "^5.7.4",
|
||||
"nodemailer": "^6.3.1",
|
||||
"signale": "^1.4.0",
|
||||
"@typegoose/typegoose": "^7.6.2",
|
||||
"uuid": "^3.3.3",
|
||||
"x509": "bsian03/node-x509"
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import express from 'express';
|
||||
import { AccountInterface } from '../models';
|
||||
import { Account } from '../models';
|
||||
|
||||
export interface Req extends express.Request {
|
||||
account: AccountInterface
|
||||
account: Account
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import axios from 'axios';
|
||||
import moment from 'moment';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { AccountInterface } from '../models';
|
||||
import { Client } from '..';
|
||||
|
||||
export default class AccountUtil {
|
||||
|
@ -19,7 +18,7 @@ export default class AccountUtil {
|
|||
* @param data.emailAddress The user's email address.
|
||||
* @param moderator The Discord user ID for the Staff member that created the account.
|
||||
*/
|
||||
public async createAccount(data: { userID: string, username: string, emailAddress: string }, moderator: string): Promise<{ account: AccountInterface, tempPass: string }> {
|
||||
public async createAccount(data: { userID: string, username: string, emailAddress: string }, moderator: string) {
|
||||
const moderatorMember = this.client.guilds.get('446067825673633794').members.get(moderator);
|
||||
const tempPass = this.client.util.randomPassword();
|
||||
let passHash = await this.client.util.createHash(tempPass); passHash = passHash.replace(/[$]/g, '\\$').replace('\n', '');
|
||||
|
@ -74,15 +73,15 @@ export default class AccountUtil {
|
|||
this.client.guilds.get('446067825673633794').members.get(data.userID).addRole('546457886440685578');
|
||||
const dmChannel = await this.client.getDMChannel(data.userID).catch();
|
||||
dmChannel.createMessage('<:loc:607695848612167700> **Thank you for creating an account with us!** <:loc:607695848612167700>\n'
|
||||
+ `Please log into your account by running \`ssh ${data.username}@cloud.libraryofcode.org\` in your terminal, then use the password \`${tempPass}\` to log in.\n`
|
||||
+ `You will be asked to change your password, \`(current) UNIX password\` is \`${tempPass}\`, then create a password that is at least 12 characters long, with at least one number, special character, and an uppercase letter\n`
|
||||
+ 'Bear in mind that when you enter your password, it will be blank, so be careful not to type in your password incorrectly.\n\n'
|
||||
+ 'An email containing some useful information has also been sent.\n'
|
||||
+ `Your support key is \`${code}\`. Pin this message, you may need this key to contact Library of Code in the future.`).catch();
|
||||
+ `Please log into your account by running \`ssh ${data.username}@cloud.libraryofcode.org\` in your terminal, then use the password \`${tempPass}\` to log in.\n`
|
||||
+ `You will be asked to change your password, \`(current) UNIX password\` is \`${tempPass}\`, then create a password that is at least 12 characters long, with at least one number, special character, and an uppercase letter\n`
|
||||
+ 'Bear in mind that when you enter your password, it will be blank, so be careful not to type in your password incorrectly.\n\n'
|
||||
+ 'An email containing some useful information has also been sent.\n'
|
||||
+ `Your support key is \`${code}\`. Pin this message, you may need this key to contact Library of Code in the future.`).catch();
|
||||
return { account: accountInterface, tempPass };
|
||||
}
|
||||
|
||||
public async lock(username: string, moderatorID: string, data?: { reason?: string, time?: number}) {
|
||||
public async lock(username: string, moderatorID: string, data?: { reason?: string, time?: number }) {
|
||||
const account = await this.client.db.Account.findOne({ username });
|
||||
if (!account) throw new Error('Account does not exist.');
|
||||
if (account.locked) throw new Error('Account is already locked.');
|
||||
|
|
|
@ -3,10 +3,11 @@ import Redis from 'ioredis';
|
|||
import mongoose from 'mongoose';
|
||||
import signale from 'signale';
|
||||
import fs from 'fs-extra';
|
||||
import { getModelForClass } from '@typegoose/typegoose';
|
||||
import config from '../config.json';
|
||||
import { Account, AccountInterface, Moderation, ModerationInterface, Domain, DomainInterface, Tier, TierInterface } from '../models';
|
||||
import { Account, Moderation, Domain, Tier } from '../models';
|
||||
import { emojis } from '../stores';
|
||||
import { Command, CSCLI, Util, Collection, Server, Event } from '.';
|
||||
import { Command, Util, Collection, Server, Event } from '.';
|
||||
|
||||
|
||||
export default class Client extends Eris.Client {
|
||||
|
@ -18,7 +19,12 @@ export default class Client extends Eris.Client {
|
|||
|
||||
public events: Collection<Event>;
|
||||
|
||||
public db: { Account: mongoose.Model<AccountInterface>; Domain: mongoose.Model<DomainInterface>; Moderation: mongoose.Model<ModerationInterface>; Tier: mongoose.Model<TierInterface>; };
|
||||
public db = {
|
||||
Account: getModelForClass(Account),
|
||||
Domain: getModelForClass(Domain),
|
||||
Moderation: getModelForClass(Moderation),
|
||||
Tier: getModelForClass(Tier),
|
||||
}
|
||||
|
||||
public redis: Redis.Redis;
|
||||
|
||||
|
@ -43,7 +49,6 @@ export default class Client extends Eris.Client {
|
|||
this.commands = new Collection<Command>();
|
||||
this.events = new Collection<Event>();
|
||||
this.functions = new Collection<Function>();
|
||||
this.db = { Account, Domain, Moderation, Tier };
|
||||
this.redis = new Redis();
|
||||
this.stores = { emojis };
|
||||
this.signale = signale;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import jwt from 'jsonwebtoken';
|
||||
import { Request } from 'express';
|
||||
import { Client } from '.';
|
||||
import { AccountInterface } from '../models';
|
||||
|
||||
export default class Security {
|
||||
public client: Client;
|
||||
|
@ -36,7 +35,7 @@ export default class Security {
|
|||
* If the bearer token is valid, will return the Account, else will return null.
|
||||
* @param bearer The bearer token provided.
|
||||
*/
|
||||
public async checkBearer(bearer: string): Promise<null | AccountInterface> {
|
||||
public async checkBearer(bearer: string) {
|
||||
try {
|
||||
const res: any = jwt.verify(bearer, this.keys.key, { issuer: 'Library of Code sp-us | CSD' });
|
||||
const account = await this.client.db.Account.findOne({ _id: res.id });
|
||||
|
|
|
@ -10,7 +10,6 @@ import moment from 'moment';
|
|||
import fs from 'fs';
|
||||
import { getUserByUid } from '../functions';
|
||||
import { AccountUtil, Client, Command, RichEmbed } from '.';
|
||||
import { ModerationInterface, AccountInterface, Account } from '../models';
|
||||
|
||||
export default class Util {
|
||||
public client: Client;
|
||||
|
@ -36,7 +35,7 @@ export default class Util {
|
|||
public async exec(command: string, options: childProcess.ExecOptions = {}): Promise<string> {
|
||||
return new Promise((res, rej) => {
|
||||
let output = '';
|
||||
const writeFunction = (data: string|Buffer|Error) => {
|
||||
const writeFunction = (data: string | Buffer | Error) => {
|
||||
output += `${data}`;
|
||||
};
|
||||
const cmd = childProcess.exec(command, options);
|
||||
|
@ -47,7 +46,7 @@ export default class Util {
|
|||
cmd.stdout.off('data', writeFunction);
|
||||
cmd.stderr.off('data', writeFunction);
|
||||
cmd.off('error', writeFunction);
|
||||
setTimeout(() => {}, 1000);
|
||||
setTimeout(() => { }, 1000);
|
||||
if (code !== 0) rej(new Error(`Command failed: ${command}\n${output}`));
|
||||
res(output);
|
||||
});
|
||||
|
@ -99,7 +98,7 @@ export default class Util {
|
|||
* @param query Command input
|
||||
* @param message Only used to check for errors
|
||||
*/
|
||||
public resolveCommand(query: string | string[], message?: Message): Promise<{cmd: Command, args: string[] }> {
|
||||
public resolveCommand(query: string | string[], message?: Message): Promise<{ cmd: Command, args: string[] }> {
|
||||
try {
|
||||
let resolvedCommand: Command;
|
||||
if (typeof query === 'string') query = query.split(' ');
|
||||
|
@ -153,7 +152,7 @@ export default class Util {
|
|||
|
||||
public splitFields(fields: { name: string, value: string, inline?: boolean }[]): { name: string, value: string, inline?: boolean }[][] {
|
||||
let index = 0;
|
||||
const array: {name: string, value: string, inline?: boolean}[][] = [[]];
|
||||
const array: { name: string, value: string, inline?: boolean }[][] = [[]];
|
||||
while (fields.length) {
|
||||
if (array[index].length >= 25) { index += 1; array[index] = []; }
|
||||
array[index].push(fields[0]); fields.shift();
|
||||
|
@ -198,7 +197,7 @@ export default class Util {
|
|||
return tempPass;
|
||||
}
|
||||
|
||||
public async createAccount(hash: string, etcPasswd: string, username: string, userID: string, emailAddress: string, moderatorID: string, code: string): Promise<AccountInterface> {
|
||||
public async createAccount(hash: string, etcPasswd: string, username: string, userID: string, emailAddress: string, moderatorID: string, code: string) {
|
||||
await this.exec(`useradd -m -p ${hash} -c ${etcPasswd} -s /bin/bash ${username}`);
|
||||
await this.exec(`chage -d0 ${username}`);
|
||||
const tier = await this.client.db.Tier.findOne({ id: 1 });
|
||||
|
@ -222,7 +221,7 @@ export default class Util {
|
|||
await Promise.all(tasks);
|
||||
}
|
||||
|
||||
public async messageCollector(message: Message, question: string, timeout: number, shouldDelete = false, choices: string[] = null, filter = (msg: Message): boolean|void => {}): Promise<Message> {
|
||||
public async messageCollector(message: Message, question: string, timeout: number, shouldDelete = false, choices: string[] = null, filter = (msg: Message): boolean | void => { }): Promise<Message> {
|
||||
const msg = await message.channel.createMessage(question);
|
||||
return new Promise((res, rej) => {
|
||||
const func = (Msg: Message) => {
|
||||
|
@ -250,12 +249,12 @@ export default class Util {
|
|||
*
|
||||
* `4` - Delete
|
||||
*/
|
||||
public async createModerationLog(user: string, moderator: Member|User, type: number, reason?: string, duration?: number): Promise<ModerationInterface> {
|
||||
public async createModerationLog(user: string, moderator: Member | User, type: number, reason?: string, duration?: number) {
|
||||
const moderatorID = moderator.id;
|
||||
const account = await this.client.db.Account.findOne({ $or: [{ username: user }, { userID: user }] });
|
||||
if (!account) return Promise.reject(new Error(`Account ${user} not found`));
|
||||
const { username, userID } = account;
|
||||
const logInput: { username: string, userID: string, logID: string, moderatorID: string, reason?: string, type: number, date: Date, expiration?: { date: Date, processed: boolean }} = {
|
||||
const logInput: { username: string, userID: string, logID: string, moderatorID: string, reason?: string, type: number, date: Date, expiration?: { date: Date, processed: boolean } } = {
|
||||
username, userID, logID: uuid(), moderatorID, type, date: new Date(),
|
||||
};
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import fs, { writeFile, unlink } from 'fs-extra';
|
|||
import axios from 'axios';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { Message } from 'eris';
|
||||
import { AccountInterface } from '../models';
|
||||
import { Account } from '../models';
|
||||
import { Client, Command, RichEmbed } from '../class';
|
||||
import { parseCertificate } from '../functions';
|
||||
|
||||
|
@ -144,7 +144,7 @@ export default class CWG_Create extends Command {
|
|||
* @param x509Certificate The contents the certificate and key files.
|
||||
* @example await CWG.createDomain(account, 'mydomain.cloud.libraryofcode.org', 6781);
|
||||
*/
|
||||
public async createDomain(account: AccountInterface, domain: string, port: number, x509Certificate: { cert?: string, key?: string }) {
|
||||
public async createDomain(account: Account, domain: string, port: number, x509Certificate: { cert?: string, key?: string }) {
|
||||
try {
|
||||
if (port <= 1024 || port >= 65535) throw new RangeError(`Port range must be between 1024 and 65535, received ${port}.`);
|
||||
if (await this.client.db.Domain.exists({ domain })) throw new Error(`Domain ${domain} already exists in the database.`);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import moment from 'moment';
|
||||
import { Message, GuildTextableChannel, Member, Role } from 'eris';
|
||||
import { Client, Command, Report, RichEmbed } from '../class';
|
||||
import { Client, Command, RichEmbed } from '../class';
|
||||
import { dataConversion } from '../functions';
|
||||
import { AccountInterface } from '../models';
|
||||
import { Account } from '../models';
|
||||
|
||||
export default class Whois extends Command {
|
||||
constructor(client: Client) {
|
||||
|
@ -21,7 +21,7 @@ export default class Whois extends Command {
|
|||
public async run(message: Message<GuildTextableChannel>, args: string[]) {
|
||||
try {
|
||||
let full = false;
|
||||
let account: AccountInterface;
|
||||
let account: Account;
|
||||
if (args[1] === '--full' && this.fullRoles.some((r) => message.member.roles.includes(r) || message.author.id === '554168666938277889')) full = true;
|
||||
|
||||
const user = args[0] || message.author.id;
|
||||
|
@ -68,7 +68,7 @@ export default class Whois extends Command {
|
|||
}
|
||||
}
|
||||
|
||||
public async full(account: AccountInterface, embed: RichEmbed, member: Member) {
|
||||
public async full(account: Account, embed: RichEmbed, member: Member) {
|
||||
const [cpuUsage, data, fingerInformation, chage, memory] = await Promise.all([
|
||||
this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`),
|
||||
this.client.redis.get(`storage-${account.username}`),
|
||||
|
@ -92,7 +92,7 @@ export default class Whois extends Command {
|
|||
embed.addField('Storage', data ? dataConversion(Number(data)) : 'N/A', true);
|
||||
}
|
||||
|
||||
public async default(account: AccountInterface, embed: RichEmbed) {
|
||||
public async default(account: Account, embed: RichEmbed) {
|
||||
const [cpuUsage, data, memory] = await Promise.all([
|
||||
this.client.util.exec(`top -b -n 1 -u ${account.username} | awk 'NR>7 { sum += $9; } END { print sum; }'`),
|
||||
this.client.redis.get(`storage-${account.username}`),
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
/* eslint-disable no-continue */
|
||||
/* eslint-disable no-await-in-loop */
|
||||
import { Client, RichEmbed } from '../class';
|
||||
import { Tiers } from '../models';
|
||||
|
||||
const channelID = '691824484230889546';
|
||||
|
||||
|
@ -18,8 +17,7 @@ export default function memory(client: Client) {
|
|||
// memory in megabytes
|
||||
const memoryConversion = mem / 1024 / 1024;
|
||||
const userLimits: { soft?: number, hard?: number } = {};
|
||||
// @ts-ignore
|
||||
const tier: Tiers = await client.db.Tier.findOne({ id: acc.tier }).lean().exec();
|
||||
const tier = await client.db.Tier.findOne({ id: acc.tier }).lean().exec();
|
||||
userLimits.soft = acc.ramLimitNotification;
|
||||
userLimits.hard = tier.resourceLimits.ram;
|
||||
if ((memoryConversion <= userLimits.soft) && (acc.ramLimitNotification !== 0)) {
|
||||
|
|
|
@ -1,53 +1,72 @@
|
|||
import { Document, Schema, model } from 'mongoose';
|
||||
import { modelOptions, prop } from '@typegoose/typegoose';
|
||||
import { Base } from '@typegoose/typegoose/lib/defaultClasses';
|
||||
|
||||
export interface AccountInterface extends Document {
|
||||
username: string,
|
||||
userID: string,
|
||||
homepath: string,
|
||||
emailAddress: string,
|
||||
createdBy: string,
|
||||
createdAt: Date,
|
||||
locked: boolean,
|
||||
tier: number,
|
||||
supportKey: string,
|
||||
referralCode: string,
|
||||
totalReferrals: number,
|
||||
permissions: {
|
||||
staff: boolean,
|
||||
technician: boolean,
|
||||
director: boolean,
|
||||
},
|
||||
ramLimitNotification: number,
|
||||
root: boolean,
|
||||
hash: boolean,
|
||||
salt: string,
|
||||
authTag: Buffer
|
||||
revokedBearers: string[],
|
||||
export type Tier = 1 | 2 | 3;
|
||||
|
||||
class Permissions {
|
||||
@prop()
|
||||
staff?: boolean;
|
||||
|
||||
@prop()
|
||||
technician?: boolean;
|
||||
|
||||
@prop()
|
||||
director?: boolean;
|
||||
}
|
||||
|
||||
const Account = new Schema<AccountInterface>({
|
||||
username: String,
|
||||
userID: String,
|
||||
homepath: String,
|
||||
emailAddress: String,
|
||||
createdBy: String,
|
||||
createdAt: Date,
|
||||
locked: Boolean,
|
||||
tier: Number,
|
||||
supportKey: String,
|
||||
referralCode: String,
|
||||
totalReferrals: Number,
|
||||
permissions: {
|
||||
staff: Boolean,
|
||||
technician: Boolean,
|
||||
director: Boolean,
|
||||
},
|
||||
ramLimitNotification: Number,
|
||||
root: Boolean,
|
||||
hash: Boolean,
|
||||
salt: String,
|
||||
authTag: Buffer,
|
||||
revokedBearers: Array,
|
||||
});
|
||||
@modelOptions({ schemaOptions: { collection: 'Account' } })
|
||||
export default class Account extends Base {
|
||||
@prop({ required: true, unique: true })
|
||||
username: string;
|
||||
|
||||
export default model<AccountInterface>('Account', Account);
|
||||
@prop({ required: true, unique: true })
|
||||
userID: string;
|
||||
|
||||
@prop({ required: true, unique: true })
|
||||
homepath: string;
|
||||
|
||||
@prop({ required: true })
|
||||
emailAddress: string;
|
||||
|
||||
@prop({ required: true })
|
||||
createdBy: string;
|
||||
|
||||
@prop({ required: true })
|
||||
createdAt: Date;
|
||||
|
||||
@prop({ required: true, default: false })
|
||||
locked: boolean;
|
||||
|
||||
@prop({ required: true, default: 1 })
|
||||
tier: Tier;
|
||||
|
||||
@prop({ required: true })
|
||||
supportKey: string;
|
||||
|
||||
@prop({ required: true, unique: true })
|
||||
referralCode: string;
|
||||
|
||||
@prop({ required: true, default: 0 })
|
||||
totalReferrals: number;
|
||||
|
||||
@prop()
|
||||
permissions?: Permissions;
|
||||
|
||||
@prop()
|
||||
ramLimitNotification: number;
|
||||
|
||||
@prop()
|
||||
root: boolean;
|
||||
|
||||
@prop()
|
||||
hash: boolean;
|
||||
|
||||
@prop()
|
||||
salt: string;
|
||||
|
||||
@prop()
|
||||
authTag: Buffer;
|
||||
|
||||
@prop({ type: () => String })
|
||||
revokedBearers: string[];
|
||||
}
|
||||
|
|
|
@ -1,24 +1,28 @@
|
|||
import { Document, Schema, model } from 'mongoose';
|
||||
import { AccountInterface } from './Account';
|
||||
import { modelOptions, prop } from '@typegoose/typegoose';
|
||||
import { Account } from '.';
|
||||
|
||||
export interface DomainInterface extends Document {
|
||||
account: AccountInterface,
|
||||
domain: string,
|
||||
port: number,
|
||||
// Below is the full absolute path to the location of the x509 certificate and key files.
|
||||
x509: {
|
||||
cert: string,
|
||||
key: string
|
||||
},
|
||||
enabled: true
|
||||
class X509 {
|
||||
@prop({ required: true })
|
||||
cert: string;
|
||||
|
||||
@prop({ required: true })
|
||||
key: string;
|
||||
}
|
||||
|
||||
const Domain = new Schema<DomainInterface>({
|
||||
account: Object,
|
||||
domain: String,
|
||||
port: Number,
|
||||
x509: { cert: String, key: String },
|
||||
enabled: Boolean,
|
||||
});
|
||||
@modelOptions({ schemaOptions: { collection: 'Domain' } })
|
||||
export default class Domain {
|
||||
@prop({ type: () => Account, required: true })
|
||||
account: Account;
|
||||
|
||||
export default model<DomainInterface>('Domain', Domain);
|
||||
@prop({ required: true, unique: true })
|
||||
domain: string;
|
||||
|
||||
@prop({ required: true })
|
||||
port: number;
|
||||
|
||||
@prop({ required: true, type: () => X509 })
|
||||
x509: X509;
|
||||
|
||||
@prop({ required: true })
|
||||
enabled: boolean;
|
||||
}
|
||||
|
|
|
@ -1,38 +1,45 @@
|
|||
import { Document, Schema, model } from 'mongoose';
|
||||
import { modelOptions, prop } from '@typegoose/typegoose';
|
||||
|
||||
export interface ModerationInterface extends Document {
|
||||
username: string,
|
||||
userID: string,
|
||||
logID: string,
|
||||
moderatorID: string,
|
||||
reason: string,
|
||||
/**
|
||||
* @field 0 - Create
|
||||
* @field 1 - Warn
|
||||
* @field 2 - Lock
|
||||
* @field 3 - Unlock
|
||||
* @field 4 - Delete
|
||||
*/
|
||||
type: 0 | 1 | 2 | 3 | 4
|
||||
date: Date,
|
||||
expiration: {
|
||||
date: Date,
|
||||
processed: boolean
|
||||
}
|
||||
|
||||
class Expiration {
|
||||
@prop({ required: true })
|
||||
date: Date;
|
||||
|
||||
@prop({ required: true, default: false })
|
||||
processed: boolean;
|
||||
}
|
||||
|
||||
const Moderation = new Schema<ModerationInterface>({
|
||||
username: String,
|
||||
userID: String,
|
||||
logID: String,
|
||||
moderatorID: String,
|
||||
reason: String,
|
||||
type: Number,
|
||||
date: Date,
|
||||
expiration: {
|
||||
date: Date,
|
||||
processed: Boolean,
|
||||
},
|
||||
});
|
||||
enum Type {
|
||||
Create,
|
||||
Warn,
|
||||
Lock,
|
||||
Unlock,
|
||||
Delete
|
||||
}
|
||||
|
||||
export default model<ModerationInterface>('Moderation', Moderation);
|
||||
@modelOptions({ schemaOptions: { collection: 'Moderation' } })
|
||||
export default class Moderation {
|
||||
@prop({ required: true })
|
||||
username: string;
|
||||
|
||||
@prop({ required: true })
|
||||
userID: string;
|
||||
|
||||
@prop({ required: true, unique: true })
|
||||
logID: string;
|
||||
|
||||
@prop({ required: true })
|
||||
moderatorID: string;
|
||||
|
||||
@prop()
|
||||
reason?: string;
|
||||
|
||||
@prop({ enum: Type, required: true })
|
||||
type: Type;
|
||||
|
||||
@prop({ required: true })
|
||||
date: Date;
|
||||
|
||||
@prop()
|
||||
expiration?: Expiration;
|
||||
}
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
import { Document, Schema, model } from 'mongoose';
|
||||
import { modelOptions, prop } from '@typegoose/typegoose';
|
||||
|
||||
export interface Tiers {
|
||||
id: number,
|
||||
resourceLimits: {
|
||||
// In MB
|
||||
ram: number, storage: number
|
||||
}
|
||||
class ResourceLimits {
|
||||
@prop({ required: true })
|
||||
ram: number;
|
||||
|
||||
@prop({ required: true })
|
||||
storage: number;
|
||||
}
|
||||
|
||||
export interface TierInterface extends Tiers, Document {
|
||||
id: number;
|
||||
}
|
||||
|
||||
const Tier = new Schema<TierInterface>({
|
||||
id: Number,
|
||||
resourceLimits: {
|
||||
ram: Number,
|
||||
storage: Number,
|
||||
@modelOptions({
|
||||
schemaOptions: {
|
||||
_id: false,
|
||||
collection: 'Tier',
|
||||
},
|
||||
}, { id: false });
|
||||
})
|
||||
export default class Tier {
|
||||
@prop({ required: true, unique: true })
|
||||
id: number;
|
||||
|
||||
export default model<TierInterface>('Tier', Tier);
|
||||
@prop({ required: true, type: () => ResourceLimits })
|
||||
resourceLimits: ResourceLimits;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export { default as Account, AccountInterface } from './Account';
|
||||
export { default as Domain, DomainInterface } from './Domain';
|
||||
export { default as Moderation, ModerationInterface } from './Moderation';
|
||||
export { default as Tier, TierInterface, Tiers } from './Tier';
|
||||
export { default as Account } from './Account';
|
||||
export { default as Domain } from './Domain';
|
||||
export { default as Moderation } from './Moderation';
|
||||
export { default as Tier } from './Tier';
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
|
@ -58,7 +58,7 @@
|
|||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
"emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue