Compare commits
No commits in common. "master" and "master" have entirely different histories.
14 changed files with 369 additions and 677 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,4 +4,3 @@ built
|
||||||
config/config.json
|
config/config.json
|
||||||
*.log
|
*.log
|
||||||
.env
|
.env
|
||||||
storage/files/*
|
|
|
@ -1,8 +1,6 @@
|
||||||
![in the database 2](./assets/full.png "in the database 2")
|
![in the database 2](./assets/full.png "in the database 2")
|
||||||
|
|
||||||
a database site for notitg modcharts, currently very very unfinished
|
a database site for notitg modcharts, currently very very unfinished, basically just a boilerplate
|
||||||
|
|
||||||
you can login with discord, upload and download files, thats about it, but im still proud of it
|
|
||||||
|
|
||||||
## setup
|
## setup
|
||||||
|
|
||||||
|
|
BIN
assets/icon.ico
BIN
assets/icon.ico
Binary file not shown.
Before Width: | Height: | Size: 70 KiB |
682
package-lock.json
generated
682
package-lock.json
generated
File diff suppressed because it is too large
Load diff
18
package.json
18
package.json
|
@ -12,24 +12,20 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/express": "github:types/express",
|
"@types/express": "github:types/express",
|
||||||
"adm-zip": "^0.5.1",
|
"@types/mongoose": "^5.7.36",
|
||||||
"axios": "^0.20.0",
|
"axios": "^0.20.0",
|
||||||
"connect-mongo": "^3.2.0",
|
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-fileupload": "^1.2.0",
|
"express-fileupload": "^1.2.0",
|
||||||
"express-session": "^1.17.1",
|
"mongoose": "^5.10.2",
|
||||||
"mongoose": "^5.11.8",
|
|
||||||
"mongoose-int32": "^0.4.1",
|
"mongoose-int32": "^0.4.1",
|
||||||
"serve-favicon": "^2.5.0",
|
"node-stream-zip": "^1.11.3",
|
||||||
"typescript": "^4.1.3",
|
"typescript": "^4.0.2",
|
||||||
"uuid": "^8.3.2",
|
|
||||||
"winston": "^3.3.3"
|
"winston": "^3.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express-session": "^1.17.3",
|
"@typescript-eslint/eslint-plugin": "^4.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.11.0",
|
"@typescript-eslint/parser": "^4.0.1",
|
||||||
"@typescript-eslint/parser": "^4.11.0",
|
"eslint": "^7.8.1"
|
||||||
"eslint": "^7.16.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Index</title>
|
<title>Index</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<h1>Hi</h1>
|
<h1>Hi</h1>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -1,42 +1,36 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>list</title>
|
<title>list</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="doc-list">
|
<div id="doc-list">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/axios@0.20.0/dist/axios.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/axios@0.20.0/dist/axios.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
axios.get('/api/list').then(({ data }) => {
|
axios.get('/api/list').then(({ data }) => {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
const el = document.getElementById('doc-list');
|
const el = document.getElementById('doc-list');
|
||||||
for (const doc of data) {
|
for (const doc of data) {
|
||||||
let p = document.createElement('p');
|
let p = document.createElement('p');
|
||||||
p.innerHTML = `<b>${doc.artist} - ${doc.title}</b> by ${doc.credit}\nuploaded by ${doc.uploaderJSON.username}#${doc.uploaderJSON.discriminator}\n<a href="files/${doc.id}.zip">download</a>`;
|
p.innerText = `${doc.artist} - ${doc.title} by ${doc.credit}`;
|
||||||
|
el.insertAdjacentElement('beforeend', p);
|
||||||
|
|
||||||
if (doc.editable) {
|
let charts = document.createElement('ul');
|
||||||
p.innerHTML += ` <a href="../${doc.id}/edit">edit</a>`
|
for (const chart of doc.charts) {
|
||||||
}
|
let l = document.createElement('li');
|
||||||
|
l.innerText = `${chart.difficulty} ${chart.rating} - ${chart.name}`
|
||||||
el.insertAdjacentElement('beforeend', p);
|
charts.insertAdjacentElement('beforeend', l);
|
||||||
|
}
|
||||||
let charts = document.createElement('ul');
|
el.insertAdjacentElement('beforeend', charts);
|
||||||
for (const chart of doc.charts) {
|
}
|
||||||
let l = document.createElement('li');
|
});
|
||||||
l.innerHTML = `${chart.difficulty} ${chart.rating} - <b>${chart.name}</b><br>` +
|
</script>
|
||||||
`${chart.steps} steps, ${chart.mines} mines, ${chart.jumps} jumps, ${chart.hands} hands, ${chart.holds} holds, ${chart.rolls} rolls`
|
</body>
|
||||||
charts.insertAdjacentElement('beforeend', l);
|
|
||||||
}
|
|
||||||
el.insertAdjacentElement('beforeend', charts);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
</html>
|
47
src/auth.ts
47
src/auth.ts
|
@ -1,6 +1,3 @@
|
||||||
import { User } from './schema';
|
|
||||||
import * as uuid from 'uuid';
|
|
||||||
|
|
||||||
const API_ENDPOINT = 'https://discord.com/api/v6';
|
const API_ENDPOINT = 'https://discord.com/api/v6';
|
||||||
|
|
||||||
const axios = require('axios').default;
|
const axios = require('axios').default;
|
||||||
|
@ -8,7 +5,6 @@ const axios = require('axios').default;
|
||||||
export function run(app) {
|
export function run(app) {
|
||||||
app.get('/discordauth', async (req, res) => {
|
app.get('/discordauth', async (req, res) => {
|
||||||
const code = req.query.code;
|
const code = req.query.code;
|
||||||
const url = `http://${req.headers.host}/discordauth`;
|
|
||||||
|
|
||||||
if (code) {
|
if (code) {
|
||||||
try {
|
try {
|
||||||
|
@ -17,7 +13,7 @@ export function run(app) {
|
||||||
client_secret: process.env.DISCORD_OAUTH_CLIENTSECRET,
|
client_secret: process.env.DISCORD_OAUTH_CLIENTSECRET,
|
||||||
grant_type: 'authorization_code',
|
grant_type: 'authorization_code',
|
||||||
code: code,
|
code: code,
|
||||||
redirect_uri: url,
|
redirect_uri: 'http://localhost:8080/discordauth',
|
||||||
scope: 'identify'
|
scope: 'identify'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -32,49 +28,12 @@ export function run(app) {
|
||||||
authorization: `${postRes.data.token_type} ${postRes.data.access_token}`
|
authorization: `${postRes.data.token_type} ${postRes.data.access_token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
res.send(`hi ${userInfo.data.username}#${userInfo.data.discriminator}<br><img src="https://media.discordapp.net/avatars/${userInfo.data.id}/${userInfo.data.avatar}.png">`);
|
||||||
const users = await User.find({id: String(userInfo.data.id)});
|
|
||||||
let userUuid = '';
|
|
||||||
|
|
||||||
if (users.length === 0) {
|
|
||||||
let newUuid = uuid.v4();
|
|
||||||
|
|
||||||
while (User.find({uuid: newUuid})[0]) {
|
|
||||||
newUuid = uuid.v4();
|
|
||||||
}
|
|
||||||
|
|
||||||
const newUser = new User({
|
|
||||||
id: String(userInfo.data.id),
|
|
||||||
createdAt: new Date(),
|
|
||||||
|
|
||||||
username: userInfo.data.username,
|
|
||||||
discriminator: userInfo.data.discriminator,
|
|
||||||
avatar: userInfo.data.avatar,
|
|
||||||
|
|
||||||
uuid: newUuid,
|
|
||||||
});
|
|
||||||
|
|
||||||
userUuid = newUser.get('uuid');
|
|
||||||
newUser.save();
|
|
||||||
} else {
|
|
||||||
const user = users[0];
|
|
||||||
userUuid = user.get('uuid');
|
|
||||||
|
|
||||||
user.set('id', String(userInfo.data.id));
|
|
||||||
user.set('username', userInfo.data.username);
|
|
||||||
user.set('discriminator', userInfo.data.discriminator);
|
|
||||||
user.set('avatar', userInfo.data.avatar);
|
|
||||||
}
|
|
||||||
|
|
||||||
req.session!.discord = userInfo.data;
|
|
||||||
req.session!.uuid = userUuid;
|
|
||||||
res.send(`logged in as ${userInfo.data.username}#${userInfo.data.discriminator}<br><img src="https://media.discordapp.net/avatars/${userInfo.data.id}/${userInfo.data.avatar}.png"><br>ur useruuid is ${userUuid}`);
|
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
res.send(`whoooops<br>${err}`);
|
res.send(`whoooops<br>${err}`);
|
||||||
console.error(err);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.send(`<a href="https://discord.com/api/oauth2/authorize?client_id=${process.env.DISCORD_OAUTH_CLIENTID}&redirect_uri=${encodeURI(url)}&response_type=code&scope=identify">Click here!!</a>`);
|
res.send(`<a href="https://discord.com/api/oauth2/authorize?client_id=${process.env.DISCORD_OAUTH_CLIENTID}&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fdiscordauth&response_type=code&scope=identify">Click here!!</a>`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
38
src/index.ts
38
src/index.ts
|
@ -3,12 +3,9 @@ import * as mongoose from 'mongoose';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as winston from 'winston';
|
import * as winston from 'winston';
|
||||||
import * as fileUpload from 'express-fileupload';
|
import * as fileUpload from 'express-fileupload';
|
||||||
import * as session from 'express-session';
|
|
||||||
import * as favicon from 'serve-favicon';
|
|
||||||
const MongoStore = require('connect-mongo')(session);
|
|
||||||
|
|
||||||
import * as format from './lib/format';
|
import * as format from './lib/format';
|
||||||
import { File, User } from './schema';
|
import { File } from './schema';
|
||||||
|
|
||||||
import * as upload from './upload';
|
import * as upload from './upload';
|
||||||
import * as auth from './auth';
|
import * as auth from './auth';
|
||||||
|
@ -55,22 +52,8 @@ db.then(() => {
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
app.use(express.urlencoded({extended: true}));
|
app.use(express.urlencoded({extended: true}));
|
||||||
app.use(favicon('assets/icon.ico'));
|
|
||||||
app.use(fileUpload({limits: { fileSize: 50 * 1024 * 1024 }}));
|
app.use(fileUpload({limits: { fileSize: 50 * 1024 * 1024 }}));
|
||||||
app.use(express.static('public', {extensions: ['html', 'htm']}));
|
app.use(express.static('public', {extensions: ['html', 'htm']}));
|
||||||
app.use(express.static('storage', {extensions: ['zip']}));
|
|
||||||
app.use(session({
|
|
||||||
name: 'funnyuserdata',
|
|
||||||
secret: 'wenis',
|
|
||||||
store: new MongoStore({ mongooseConnection: mongoose.connection }),
|
|
||||||
cookie: {
|
|
||||||
maxAge: 1000 * 60 * 60 * 24 * 365 * 10, // 10 years
|
|
||||||
httpOnly: true,
|
|
||||||
sameSite: 'lax',
|
|
||||||
},
|
|
||||||
resave: false,
|
|
||||||
saveUninitialized: true
|
|
||||||
}));
|
|
||||||
app.use('/assets', express.static('assets'));
|
app.use('/assets', express.static('assets'));
|
||||||
|
|
||||||
app.set('db', db);
|
app.set('db', db);
|
||||||
|
@ -80,23 +63,8 @@ db.then(() => {
|
||||||
upload.run(app);
|
upload.run(app);
|
||||||
auth.run(app);
|
auth.run(app);
|
||||||
|
|
||||||
app.get('/api/list', async (req, res) => {
|
app.get('/api/list', async (req, res) => { // only for testing
|
||||||
const files = await File.find({});
|
const docs = await File.find({});
|
||||||
|
|
||||||
const docs = [];
|
|
||||||
for (const doc of files) {
|
|
||||||
const d: any = doc.toJSON();
|
|
||||||
|
|
||||||
d.editable = false;
|
|
||||||
if (req.session) d.editable = req.session.uuid === d.uploader;
|
|
||||||
|
|
||||||
const user = await User.find({uuid: d.uploader});
|
|
||||||
if (user) {
|
|
||||||
d.uploaderJSON = user[0].toJSON(); // this is built upon 20 layers of metajank and i despise it
|
|
||||||
docs.push(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: filter out _id and __v? possibly more
|
// TODO: filter out _id and __v? possibly more
|
||||||
res.send(docs);
|
res.send(docs);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
export function parseSM(data: string) {
|
export function parseSM(data: string) {
|
||||||
|
data = data.replace(/[\n\r]/g,'');
|
||||||
|
|
||||||
// steps
|
// steps
|
||||||
const difficulties = [];
|
const difficulties = [];
|
||||||
const steps = data.split('#NOTES:');
|
const steps = data.split('#NOTES:');
|
||||||
|
@ -16,25 +18,11 @@ export function parseSM(data: string) {
|
||||||
diff.rating = Number(stepsSplit[3]);
|
diff.rating = Number(stepsSplit[3]);
|
||||||
diff.radarvalues = stepsSplit[4].split(',').map(v => Number(v));
|
diff.radarvalues = stepsSplit[4].split(',').map(v => Number(v));
|
||||||
|
|
||||||
const chart = stepsSplit[5];
|
|
||||||
diff.rawChart = chart;
|
|
||||||
|
|
||||||
diff.steps = chart.split(/[124]/g).length - 1;
|
|
||||||
diff.mines = chart.split('M').length - 1;
|
|
||||||
diff.jumps = chart.split(/[124]0{0,2}[124]/g).length - 1;
|
|
||||||
diff.hands = chart.split(/[124]0{0,1}[124]0{0,1}[124]/g).length - 1;
|
|
||||||
diff.holds = chart.split('2').length - 1;
|
|
||||||
diff.rolls = chart.split('4').length - 1;
|
|
||||||
|
|
||||||
diff.steps -= diff.jumps; // jumps are counted as 1 step
|
|
||||||
|
|
||||||
difficulties.push(diff);
|
difficulties.push(diff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data = data.replace(/[\n\r]/g,'');
|
|
||||||
|
|
||||||
// metadata
|
// metadata
|
||||||
const lines = data.split(';').filter(l => l.startsWith('#'));
|
const lines = data.split(';').filter(l => l.startsWith('#'));
|
||||||
const obj: any = {};
|
const obj: any = {};
|
||||||
|
@ -53,7 +41,7 @@ export function parseSM(data: string) {
|
||||||
const map = {};
|
const map = {};
|
||||||
|
|
||||||
for (const i in keys) {
|
for (const i in keys) {
|
||||||
map[String(Number(keys[i])).replace('.', ',')] = Number(values[i]); // afaik maps are only numbers?
|
map[Number(keys[i])] = Number(values[i]); // afaik maps are only numbers?
|
||||||
}
|
}
|
||||||
|
|
||||||
value = map;
|
value = map;
|
||||||
|
|
10
src/lib/util.ts
Normal file
10
src/lib/util.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
export function returnStatic(page) {
|
||||||
|
return (req, res) => {
|
||||||
|
fs.readFile(`src/html/${page}`, 'utf8', (err, data) => {
|
||||||
|
if (err) throw err;
|
||||||
|
res.send(data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,118 +1,39 @@
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
import * as mongoose from 'mongoose';
|
import * as mongoose from 'mongoose';
|
||||||
|
|
||||||
const Schema = mongoose.Schema;
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
export enum SMVersion {
|
|
||||||
OPENITG,
|
|
||||||
FUCKEXE,
|
|
||||||
NOTITG_V1,
|
|
||||||
NOTITG_V2,
|
|
||||||
NOTITG_V3,
|
|
||||||
NOTITG_V3_1,
|
|
||||||
NOTITG_V4,
|
|
||||||
NOTITG_V4_0_1,
|
|
||||||
STEPMANIA_3_95,
|
|
||||||
STEPMANIA_5_0,
|
|
||||||
STEPMANIA_5_1,
|
|
||||||
STEPMANIA_5_2,
|
|
||||||
STEPMANIA_5_3,
|
|
||||||
}
|
|
||||||
|
|
||||||
const Sample = new Schema({
|
const Sample = new Schema({
|
||||||
start: {type: Number, default: 0},
|
start: {type: Number, default: 0},
|
||||||
length: {type: Number, default: 0}
|
length: {type: Number, default: 0}
|
||||||
});
|
});
|
||||||
|
|
||||||
const UserRating = new Schema({
|
|
||||||
rating: {type: Number, default: 0},
|
|
||||||
createdAt: Date,
|
|
||||||
user: {type: String, default: '00000000-0000-4000-a000-000000000000'}
|
|
||||||
});
|
|
||||||
|
|
||||||
const Chart = new Schema({
|
const Chart = new Schema({
|
||||||
type: {type: String, default: 'dance-single'},
|
type: {type: String, default: 'dance-single'},
|
||||||
name: {type: String, default: ''},
|
name: {type: String, default: ''},
|
||||||
difficulty: {type: String, default: 'Challenge'},
|
difficulty: {type: String, default: 'Challenge'},
|
||||||
radarvalues: [Number],
|
|
||||||
|
|
||||||
rating: {type: Number, default: 0},
|
rating: {type: Number, default: 0},
|
||||||
ratingsVote: {type: [UserRating], default: []},
|
radarvalues: [Number]
|
||||||
|
|
||||||
spoilered: {type: Boolean, default: false},
|
|
||||||
hidden: {type: Boolean, default: false},
|
|
||||||
|
|
||||||
steps: {type: Number, default: 0},
|
|
||||||
mines: {type: Number, default: 0},
|
|
||||||
jumps: {type: Number, default: 0},
|
|
||||||
hands: {type: Number, default: 0},
|
|
||||||
holds: {type: Number, default: 0},
|
|
||||||
rolls: {type: Number, default: 0},
|
|
||||||
});
|
|
||||||
|
|
||||||
const Comment = new Schema({
|
|
||||||
author: {type: String, default: '00000000-0000-4000-a000-000000000000'},
|
|
||||||
createdAt: Date,
|
|
||||||
content: {type: String, default: ''}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const FileSchema = new Schema({
|
const FileSchema = new Schema({
|
||||||
id: {type: Number, default: 0},
|
|
||||||
|
|
||||||
title: {type: String, default: 'unknown'},
|
title: {type: String, default: 'unknown'},
|
||||||
titleTranslit: String,
|
titleTranslit: String,
|
||||||
artist: {type: String, default: 'unknown'},
|
artist: {type: String, default: 'unknown'},
|
||||||
artistTranslit: String,
|
artistTranslit: String,
|
||||||
subtitle: String,
|
subtitle: String,
|
||||||
subtitleTranslit: String,
|
subtitleTranslit: String,
|
||||||
|
|
||||||
credit: String,
|
credit: String,
|
||||||
uploader: {type: String, default: '00000000-0000-4000-a000-000000000000'},
|
uploader: {type: String, default: '00000000-0000-4000-a000-000000000000'},
|
||||||
|
|
||||||
sample: Sample,
|
sample: Sample,
|
||||||
bpms: {type: Object, default: {'0': 0}},
|
bpms: {type: Object, default: {'0': 0}},
|
||||||
|
charts: [Chart]
|
||||||
charts: {type: [Chart], default: []},
|
|
||||||
|
|
||||||
description: {type: String, default: ''},
|
|
||||||
createdAt: Date,
|
|
||||||
smVersion: {type: Number, default: 0}, // see SMVersion enum
|
|
||||||
ytLink: String,
|
|
||||||
customLink: String,
|
|
||||||
hidden: {type: Boolean, default: false},
|
|
||||||
|
|
||||||
comments: {type: [Comment], default: []},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const File = mongoose.model('File', FileSchema);
|
export const File = mongoose.model('File', FileSchema);
|
||||||
|
|
||||||
const UserSchema = new Schema({ // this is pretty much just a discord user lol
|
const UserSchema = new Schema({ // this is pretty much just a discord user lol
|
||||||
id: {type: String, default: 'notgiven!!!!!!!!!!!!'}, // discord id, cus longass number
|
id: String, // cus longass number
|
||||||
createdAt: Date,
|
approved: Boolean
|
||||||
|
|
||||||
// caching
|
|
||||||
username: {type: String, default: 'User'},
|
|
||||||
discriminator: {type: String, default: '0000'},
|
|
||||||
avatar: String,
|
|
||||||
|
|
||||||
// used internally
|
|
||||||
uuid: {type: String, default: '00000000-0000-4000-a000-000000000000'},
|
|
||||||
|
|
||||||
approvedUpload: {type: Boolean, default: false},
|
|
||||||
approvedRate: {type: Boolean, default: false},
|
|
||||||
approvedComment: {type: Boolean, default: false},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const User = mongoose.model('User', UserSchema);
|
export const User = mongoose.model('User', UserSchema);
|
||||||
|
|
||||||
const PackSchema = new Schema({
|
|
||||||
author: {type: String, default: '00000000-0000-4000-a000-000000000000'},
|
|
||||||
files: {type: [Number], default: []}, // ids
|
|
||||||
name: {type: String, default: 'Pack'},
|
|
||||||
description: {type: String, default: ''},
|
|
||||||
createdAt: Date,
|
|
||||||
|
|
||||||
hidden: {type: Boolean, default: false},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Pack = mongoose.model('Pack', PackSchema);
|
|
|
@ -1,75 +1,54 @@
|
||||||
import { tmpdir } from 'os';
|
import { tmpdir } from 'os';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as AdmZip from 'adm-zip';
|
const StreamZip = require('node-stream-zip');
|
||||||
|
|
||||||
|
import { returnStatic } from './lib/util';
|
||||||
import { parseSM } from './lib/smparse';
|
import { parseSM } from './lib/smparse';
|
||||||
import { File, User } from './schema';
|
import { File } from './schema';
|
||||||
|
|
||||||
export function run(app) {
|
export function run(app) {
|
||||||
const logger = app.get('logger');
|
const logger = app.get('logger');
|
||||||
|
|
||||||
app.post('/api/upload', async (req, res) => { // only for testing, very abusable
|
app.post('/api/upload', async (req, res) => { // only for testing, very abusable
|
||||||
if (!req.files) return res.status(400).send('No files were given');
|
if (!req.files) return res.status(400).send('No files were given');
|
||||||
if (!req.session.uuid) return res.status(401).send('Not authorized, use /discordauth');
|
|
||||||
|
|
||||||
const user = (await User.find({uuid: req.session.uuid}))[0];
|
|
||||||
if (!user) return res.status(401).send('User doesn\'t exist, try re-logging in');
|
|
||||||
if (!user.get('approvedUpload')) return res.status(403).send('Your account is not allowed to upload files! Contact a moderator to verify your account');
|
|
||||||
|
|
||||||
const file = req.files.file;
|
const file = req.files.file;
|
||||||
|
|
||||||
if (file.mimetype !== 'application/zip' && file.mimetype !== 'application/x-zip-compressed') return res.status(400).send('Invalid filetype');
|
if (file.mimetype !== 'application/zip' && file.mimetype !== 'application/x-zip-compressed') return res.status(400).send('Invalid filetype');
|
||||||
|
|
||||||
const dir = tmpdir() + '/' + file.md5;
|
const dir = tmpdir() + '/' + file.md5;
|
||||||
fs.writeFile(dir, file.data, async (err) => {
|
fs.writeFile(dir, file.data, (err) => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
try {
|
const zip = new StreamZip({
|
||||||
const zip = new AdmZip(dir);
|
file: dir,
|
||||||
const zipEntries = zip.getEntries();
|
storeEntries: true
|
||||||
|
});
|
||||||
|
|
||||||
const smFile: any = Object.values(zipEntries).find((f: any) =>
|
zip.on('ready', () => {
|
||||||
!f.isDirectory && (f.entryName.endsWith('.sm'))
|
const smFile = Object.values(zip.entries()).find((f: any) =>
|
||||||
|
!f.isDirectory && (f.name.endsWith('.sm'))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!smFile) {
|
if (!smFile) {
|
||||||
res.status(400).send('No .sm found');
|
res.status(400).send('No .sm found');
|
||||||
} else {
|
} else {
|
||||||
const data = smFile.getData().toString('utf8');
|
const data = zip.entryDataSync((smFile as any).name);
|
||||||
const chart = parseSM(data.toString());
|
const chart = parseSM(data.toString());
|
||||||
|
|
||||||
logger.info(`${chart.artist} - ${chart.title} was just uploaded`);
|
logger.info(`${chart.artist} - ${chart.title} was just uploaded`);
|
||||||
|
|
||||||
let id = 0;
|
const file = new File(chart);
|
||||||
for (const f of await File.find({})) {
|
file.save();
|
||||||
id = Math.max(Number(f.id), id);
|
|
||||||
}
|
|
||||||
chart.id = id + 1;
|
|
||||||
|
|
||||||
chart.uploader = req.session.uuid;
|
// TODO: filter out _id and __v? possibly more
|
||||||
|
res.send(chart);
|
||||||
chart.createdAt = new Date();
|
|
||||||
|
|
||||||
fs.writeFile('./storage/files/' + (id + 1) + '.zip', file.data, (err) => {
|
|
||||||
if (err) throw err;
|
|
||||||
|
|
||||||
const file = new File(chart);
|
|
||||||
file.save();
|
|
||||||
|
|
||||||
// TODO: filter out _id and __v? possibly more
|
|
||||||
res.send(chart);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zip.close();
|
||||||
fs.unlink(dir, (err) => {
|
fs.unlink(dir, (err) => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
});
|
});
|
||||||
} catch(err) {
|
});
|
||||||
logger.error(err.toString());
|
|
||||||
console.error(err);
|
|
||||||
res.status(400);
|
|
||||||
res.send(err.toString());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
Loading…
Reference in a new issue