Restructured in preparation for admin panel
This commit is contained in:
parent
1febe41516
commit
a07c9a3ef7
93
index.js
93
index.js
@ -4,6 +4,7 @@ const config = require('./config');
|
||||
const Repository = require('./lib/repository');
|
||||
|
||||
const _ = require('lodash');
|
||||
const fs = require('fs');
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const tus = require('tus-node-server');
|
||||
@ -16,33 +17,16 @@ const webpackHotMiddleware = require('webpack-hot-middleware');
|
||||
const webpackConfig = require('./webpack.config.js');
|
||||
|
||||
|
||||
function checkAuthorization(req, res, onVerified)
|
||||
{
|
||||
if (!req.headers.authorization || req.headers.authorization.split(' ')[0] !== 'Bearer')
|
||||
{
|
||||
res.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
var token = req.headers.authorization.split(' ')[1];
|
||||
jwt.verify(token, config.jwtSecret, (err, decoded) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
res.sendStatus(403);
|
||||
return;
|
||||
}
|
||||
|
||||
onVerified(decoded);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
(async function()
|
||||
{
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production';
|
||||
|
||||
const repository = new Repository(config.database);
|
||||
await repository.load()
|
||||
.catch((err) =>
|
||||
{
|
||||
console.log(err);
|
||||
});
|
||||
|
||||
|
||||
const tusServer = new tus.Server();
|
||||
@ -57,66 +41,25 @@ function checkAuthorization(req, res, onVerified)
|
||||
app.use(bodyParser.json());
|
||||
|
||||
|
||||
// Token API
|
||||
app.post('/token/upload', async (req, res) =>
|
||||
|
||||
const registerAPI = (name) => { require('./lib/api/' + name)(app, repository) }
|
||||
|
||||
fs.readdir('./lib/api', (err, files) =>
|
||||
{
|
||||
if (!req.body.code)
|
||||
if (err)
|
||||
{
|
||||
res.sendStatus(400);
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
|
||||
var userId = await repository.findCodeUserId(req.body.code);
|
||||
if (userId !== null)
|
||||
_.forEach(files, (fileName) =>
|
||||
{
|
||||
jwt.sign({
|
||||
code: req.body.code,
|
||||
userId: userId
|
||||
}, config.jwtSecret, (err, token) =>
|
||||
{
|
||||
if (err)
|
||||
res.sendStatus(500);
|
||||
else
|
||||
res.send(token);
|
||||
});
|
||||
}
|
||||
else
|
||||
res.sendStatus(403);
|
||||
});
|
||||
|
||||
|
||||
// Upload API
|
||||
app.post('/complete', (req, res) =>
|
||||
{
|
||||
if (!req.body.files)
|
||||
{
|
||||
res.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
checkAuthorization(req, res, async (decoded) =>
|
||||
{
|
||||
console.log('1');
|
||||
var uploadId = await repository.addUpload(decoded.userId, req.body.files);
|
||||
console.log(uploadId);
|
||||
res.send({ id: uploadId });
|
||||
console.log('Loading API ' + fileName + '...');
|
||||
registerAPI(fileName);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Tus upload
|
||||
const uploadApp = express();
|
||||
uploadApp.all('*', (req, res) =>
|
||||
{
|
||||
checkAuthorization(req, res, (decoded) =>
|
||||
{
|
||||
tusServer.handle(req, res);
|
||||
});
|
||||
});
|
||||
|
||||
app.use('/upload', uploadApp);
|
||||
|
||||
|
||||
// Frontend
|
||||
if (isDevelopment)
|
||||
{
|
||||
@ -131,5 +74,11 @@ function checkAuthorization(req, res, onVerified)
|
||||
|
||||
app.use(express.static(path.join(__dirname, 'public', 'dist')));
|
||||
|
||||
|
||||
// Redirects to make Vue-router URLs less quirky
|
||||
app.get('/c/:code', (req, res) => { res.redirect(301, '/#/c/' + req.params.code) });
|
||||
app.get('/admin', (req, res) => { res.redirect(301, '/#/admin/') });
|
||||
|
||||
|
||||
var server = app.listen(config.port, () => console.log('Recv running on port ' + server.address().port));
|
||||
})();
|
32
lib/api/token.js
Normal file
32
lib/api/token.js
Normal file
@ -0,0 +1,32 @@
|
||||
const config = require('../../config');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
|
||||
module.exports = (app, repository) =>
|
||||
{
|
||||
app.post('/token/upload', async (req, res) =>
|
||||
{
|
||||
if (!req.body.code)
|
||||
{
|
||||
res.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
var userId = await repository.codes.findCodeUserId(req.body.code);
|
||||
if (userId !== null)
|
||||
{
|
||||
jwt.sign({
|
||||
code: req.body.code,
|
||||
userId: userId
|
||||
}, config.jwtSecret, (err, token) =>
|
||||
{
|
||||
if (err)
|
||||
res.sendStatus(500);
|
||||
else
|
||||
res.send(token);
|
||||
});
|
||||
}
|
||||
else
|
||||
res.sendStatus(403);
|
||||
});
|
||||
}
|
60
lib/api/upload.js
Normal file
60
lib/api/upload.js
Normal file
@ -0,0 +1,60 @@
|
||||
const config = require('../../config');
|
||||
const express = require('express');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
|
||||
function checkAuthorization(req, res, onVerified)
|
||||
{
|
||||
if (!req.headers.authorization || req.headers.authorization.split(' ')[0] !== 'Bearer')
|
||||
{
|
||||
res.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
var token = req.headers.authorization.split(' ')[1];
|
||||
jwt.verify(token, config.jwtSecret, (err, decoded) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
res.sendStatus(403);
|
||||
return;
|
||||
}
|
||||
|
||||
onVerified(decoded);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = (app, repository) =>
|
||||
{
|
||||
// Upload API
|
||||
app.post('/complete', (req, res) =>
|
||||
{
|
||||
if (!req.body.files)
|
||||
{
|
||||
res.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
|
||||
checkAuthorization(req, res, async (decoded) =>
|
||||
{
|
||||
var expiration = null; // TODO set expiration properties
|
||||
var uploadId = await repository.uploads.addUpload(decoded.userId, req.body.files, expiration);
|
||||
res.send({ id: uploadId });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Tus upload
|
||||
const uploadApp = express();
|
||||
uploadApp.all('*', (req, res) =>
|
||||
{
|
||||
checkAuthorization(req, res, (decoded) =>
|
||||
{
|
||||
tusServer.handle(req, res);
|
||||
});
|
||||
});
|
||||
|
||||
app.use('/upload', uploadApp);
|
||||
}
|
@ -1,208 +0,0 @@
|
||||
//const debug = require('debug')('recv:users');
|
||||
const _ = require('lodash');
|
||||
const path = require('path');
|
||||
const mkdirp = require('mkdirp');
|
||||
const bcrypt = require('bcrypt');
|
||||
const Datastore = require('nedb');
|
||||
const shortid = require('shortid');
|
||||
const retry = require('async-retry')
|
||||
|
||||
|
||||
class Repository
|
||||
{
|
||||
constructor(config)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
const initStore = (filename) =>
|
||||
{
|
||||
var store = new Datastore({
|
||||
filename: path.join(config.path, filename),
|
||||
autoload: true
|
||||
});
|
||||
|
||||
store.persistence.setAutocompactionInterval(config.autocompactionInterval);
|
||||
return store;
|
||||
};
|
||||
|
||||
mkdirp(config.path, (err) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
|
||||
self.db = {
|
||||
users: initStore('users.db'),
|
||||
codes: initStore('codes.db'),
|
||||
uploads: initStore('uploads.db')
|
||||
};
|
||||
|
||||
|
||||
// Initialize database if empty
|
||||
self.db.users.count({}, (err, count) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
self.addUser('admin', null, 'test');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async isValidUser(username, password)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
self.db.users.findOne({ username: username }, (err, doc) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (doc == null)
|
||||
{
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
bcrypt.compare(password, doc.password, (err, res) =>
|
||||
{
|
||||
if (err)
|
||||
reject(err)
|
||||
else
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async addUser(username, email, password)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
bcrypt.hash(password, 10, function(err, hash)
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
var user = {
|
||||
username: username,
|
||||
email: email,
|
||||
password: hash
|
||||
};
|
||||
|
||||
self.db.users.insert(user, (err, dbUser) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(dbUser._id);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async findCodeUserId(code)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
self.db.codes.findOne({ _id: code }, (err, doc) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(doc !== null ? doc.userId : null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async addCode(userId, expiration)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return await retry(async bail =>
|
||||
{
|
||||
var code = shortid.generate();
|
||||
|
||||
if ((await self.findCodeUserId(code)) !== null)
|
||||
throw new Error('Code ' + code + ' already exists');
|
||||
|
||||
self.db.codes.insert({
|
||||
_id: code,
|
||||
userId: userId,
|
||||
expiration: expiration
|
||||
})
|
||||
|
||||
return code;
|
||||
}, {
|
||||
retries: 100,
|
||||
minTimeout: 0,
|
||||
maxTimeout: 0
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async addUpload(userId, files)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
var upload = {
|
||||
files: _.map(_.filter(files,
|
||||
(file) => file.hasOwnProperty('id') && file.hasOwnProperty('name')),
|
||||
(file) => { return { id: file.id, name: file.name } })
|
||||
};
|
||||
console.log(upload);
|
||||
|
||||
if (upload.files.length)
|
||||
{
|
||||
self.db.uploads.insert(upload, (err, dbUpload) =>
|
||||
{
|
||||
console.log(dbUpload);
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(dbUpload._id);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = Repository;
|
82
lib/repository/codes.js
Normal file
82
lib/repository/codes.js
Normal file
@ -0,0 +1,82 @@
|
||||
class CodesRepository
|
||||
{
|
||||
constructor(store)
|
||||
{
|
||||
var self = this;
|
||||
self.store = store;
|
||||
}
|
||||
|
||||
|
||||
async init()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
// Initialize database if empty
|
||||
self.store.count({}, (err, count) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
self.addUser('admin', null, 'test', null);
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async findCodeUserId(code)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
self.store.findOne({ _id: code }, (err, doc) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(doc !== null ? doc.userId : null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async addCode(userId, expiration)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return await retry(async bail =>
|
||||
{
|
||||
var code = shortid.generate();
|
||||
|
||||
if ((await self.findCodeUserId(code)) !== null)
|
||||
throw new Error('Code ' + code + ' already exists');
|
||||
|
||||
self.store.insert({
|
||||
_id: code,
|
||||
userId: userId,
|
||||
created: new Date(),
|
||||
expiration: expiration
|
||||
})
|
||||
|
||||
return code;
|
||||
}, {
|
||||
retries: 100,
|
||||
minTimeout: 0,
|
||||
maxTimeout: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = CodesRepository;
|
61
lib/repository/index.js
Normal file
61
lib/repository/index.js
Normal file
@ -0,0 +1,61 @@
|
||||
//const debug = require('debug')('recv:users');
|
||||
const _ = require('lodash');
|
||||
const path = require('path');
|
||||
const mkdirp = require('mkdirp');
|
||||
const bcrypt = require('bcrypt');
|
||||
const Datastore = require('nedb');
|
||||
const shortid = require('shortid');
|
||||
const retry = require('async-retry');
|
||||
|
||||
const UsersRepository = require('./users');
|
||||
const CodesRepository = require('./codes');
|
||||
const UploadsRepository = require('./uploads');
|
||||
|
||||
|
||||
class Repository
|
||||
{
|
||||
constructor(config)
|
||||
{
|
||||
var self = this;
|
||||
self.config = config;
|
||||
}
|
||||
|
||||
|
||||
async load()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
const initStore = (filename) =>
|
||||
{
|
||||
var store = new Datastore({
|
||||
filename: path.join(self.config.path, filename),
|
||||
autoload: true
|
||||
});
|
||||
|
||||
store.persistence.setAutocompactionInterval(self.config.autocompactionInterval);
|
||||
return store;
|
||||
};
|
||||
|
||||
mkdirp(self.config.path, async (err) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
self.users = new UsersRepository(initStore('users.db'));
|
||||
self.codes = new CodesRepository(initStore('codes.db'));
|
||||
self.uploads = new UploadsRepository(initStore('uploads.db'));
|
||||
|
||||
await self.users.init();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = Repository;
|
70
lib/repository/uploads.js
Normal file
70
lib/repository/uploads.js
Normal file
@ -0,0 +1,70 @@
|
||||
class UploadsRepository
|
||||
{
|
||||
constructor(store)
|
||||
{
|
||||
var self = this;
|
||||
self.store = store;
|
||||
}
|
||||
|
||||
|
||||
async init()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
// Initialize database if empty
|
||||
self.store.count({}, (err, count) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
self.addUser('admin', null, 'test', null);
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async addUpload(userId, files, expiration)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
var upload = {
|
||||
created: new Date(),
|
||||
expiration: expiration,
|
||||
files: _.map(_.filter(files,
|
||||
(file) => file.hasOwnProperty('id') && file.hasOwnProperty('name')),
|
||||
(file) => { return { id: file.id, name: file.name } })
|
||||
};
|
||||
|
||||
if (upload.files.length)
|
||||
{
|
||||
self.store.insert(upload, (err, dbUpload) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(dbUpload._id);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = UploadsRepository;
|
104
lib/repository/users.js
Normal file
104
lib/repository/users.js
Normal file
@ -0,0 +1,104 @@
|
||||
class UsersRepository
|
||||
{
|
||||
constructor(store)
|
||||
{
|
||||
var self = this;
|
||||
self.store = store;
|
||||
}
|
||||
|
||||
|
||||
async init()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
// Initialize database if empty
|
||||
self.store.count({}, (err, count) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
self.addUser('admin', null, 'test', null);
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async isValidUser(username, password)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
self.store.findOne({ username: username }, (err, doc) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (doc == null)
|
||||
{
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
bcrypt.compare(password, doc.password, (err, res) =>
|
||||
{
|
||||
if (err)
|
||||
reject(err)
|
||||
else
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async addUser(username, email, password, createdByUserId)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
bcrypt.hash(password, 10, function(err, hash)
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
var user = {
|
||||
username: username,
|
||||
email: email,
|
||||
password: hash,
|
||||
created: new Date(),
|
||||
createdByUserId: createdByUserId
|
||||
};
|
||||
|
||||
self.store.insert(user, (err, dbUser) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(dbUser._id);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = UsersRepository;
|
@ -7,17 +7,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="logo">
|
||||
<img src="/images/logo.png">
|
||||
</div>
|
||||
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
|
||||
<div class="disclaimer">
|
||||
{{ $t('disclaimer') }}
|
||||
</div>
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -14,14 +14,27 @@ const i18n = new VueI18n({
|
||||
});
|
||||
|
||||
|
||||
const Landing = () => import('./route/Landing.vue');
|
||||
const Upload = () => import('./route/Upload.vue');
|
||||
const Code = () => import('./route/Code.vue');
|
||||
|
||||
|
||||
const router = new VueRouter({
|
||||
routes: [
|
||||
{ path: '/', component: Landing },
|
||||
{ path: '/c/:codeParam', component: Landing, props: true },
|
||||
{ path: '/u/:codeParam', component: Upload, props: true }
|
||||
{ path: '/', component: () => import('./route/Landing.vue'),
|
||||
children: [
|
||||
{ path: 'c/:codeParam', component: Code, props: true },
|
||||
{ path: 'u/:codeParam', component: () => import('./route/Upload.vue'), props: true },
|
||||
{ path: '', component: Code }
|
||||
]
|
||||
},
|
||||
{ path: '/admin', component: () => import('./route/admin/Landing.vue'),
|
||||
children: [
|
||||
{ path: 'codes', component: () => import('./route/admin/Codes.vue') },
|
||||
{ path: 'profile', component: () => import('./route/admin/Profile.vue') },
|
||||
{ path: 'users', component: () => import('./route/admin/Users.vue') },
|
||||
{ path: '', component: () => import('./route/admin/Login.vue') }
|
||||
]
|
||||
},
|
||||
{ path: '*', redirect: '/' }
|
||||
]
|
||||
});
|
||||
|
||||
|
92
public/src/route/Code.vue
Normal file
92
public/src/route/Code.vue
Normal file
@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<div id="landing">
|
||||
<form class="pure-form pure-form-stacked" @submit.prevent="checkCode">
|
||||
<fieldset class="pure-group">
|
||||
<input type="text" class="pure-input-1-2" v-model="code.value" :placeholder="$t('landing.invitePlaceholder')">
|
||||
</fieldset>
|
||||
|
||||
<button type="submit" class="pure-button pure-button-primary" :disabled="code.value.trim() == '' || code.checking">{{ $t(code.checking ? 'landing.inviteButtonChecking' : 'landing.inviteButton') }} <span v-if="code.checking"><i class="fas fa-spinner fa-pulse"></i></span></button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import shared from '../shared';
|
||||
|
||||
export default {
|
||||
props: [
|
||||
'codeParam'
|
||||
],
|
||||
|
||||
data () {
|
||||
return {
|
||||
code: {
|
||||
value: '',
|
||||
checking: false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created()
|
||||
{
|
||||
var self = this;
|
||||
if (self.codeParam)
|
||||
{
|
||||
self.code.value = self.codeParam;
|
||||
self.checkCode();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
checkCode()
|
||||
{
|
||||
var self = this;
|
||||
if (self.code.checking)
|
||||
return;
|
||||
|
||||
self.code.checking = true;
|
||||
|
||||
axios.post('/token/upload', {
|
||||
code: self.code.value
|
||||
})
|
||||
.then((response) =>
|
||||
{
|
||||
shared.token = response.data;
|
||||
self.$router.push({ path: '/u/' + self.code.value });
|
||||
})
|
||||
.catch((error) =>
|
||||
{
|
||||
if (error.response && error.response.status == 403)
|
||||
shared.$emit('showNotification', self.$i18n.t('notification.invalidCode'), false);
|
||||
else
|
||||
shared.$emit('showNotification', error.message);
|
||||
})
|
||||
.then(() =>
|
||||
{
|
||||
self.code.checking = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../../node_modules/uppy/src/scss/uppy.scss';
|
||||
|
||||
|
||||
#landing
|
||||
{
|
||||
text-align: center;
|
||||
|
||||
input
|
||||
{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.login
|
||||
{
|
||||
margin-top: 5em;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,94 +1,20 @@
|
||||
<template>
|
||||
<div id="landing">
|
||||
<form class="pure-form pure-form-stacked" @submit.prevent="checkCode">
|
||||
<fieldset class="pure-group">
|
||||
<input type="text" class="pure-input-1-2" v-model="code.value" :placeholder="$t('landing.invitePlaceholder')">
|
||||
</fieldset>
|
||||
|
||||
<button type="submit" class="pure-button pure-button-primary" :disabled="code.value.trim() == '' || code.checking">{{ $t(code.checking ? 'landing.inviteButtonChecking' : 'landing.inviteButton') }} <span v-if="code.checking"><i class="fas fa-spinner fa-pulse"></i></span></button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import shared from '../shared';
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
|
||||
props: [
|
||||
'codeParam'
|
||||
],
|
||||
|
||||
data () {
|
||||
return {
|
||||
code: {
|
||||
value: '',
|
||||
checking: false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created()
|
||||
{
|
||||
var self = this;
|
||||
if (self.codeParam)
|
||||
{
|
||||
self.code.value = self.codeParam;
|
||||
self.checkCode();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
checkCode()
|
||||
{
|
||||
var self = this;
|
||||
if (self.code.checking)
|
||||
return;
|
||||
|
||||
self.code.checking = true;
|
||||
|
||||
axios.post('/token/upload', {
|
||||
code: self.code.value
|
||||
})
|
||||
.then((response) =>
|
||||
{
|
||||
shared.token = response.data;
|
||||
self.$router.push({ path: '/u/' + self.code.value });
|
||||
})
|
||||
.catch((error) =>
|
||||
{
|
||||
if (error.response && error.response.status == 403)
|
||||
shared.$emit('showNotification', self.$i18n.t('notification.invalidCode'), false);
|
||||
else
|
||||
shared.$emit('showNotification', error.message);
|
||||
})
|
||||
.then(() =>
|
||||
{
|
||||
self.code.checking = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../../node_modules/uppy/src/scss/uppy.scss';
|
||||
|
||||
|
||||
#landing
|
||||
{
|
||||
text-align: center;
|
||||
|
||||
input
|
||||
{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.login
|
||||
{
|
||||
margin-top: 5em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div id="landing">
|
||||
<div class="content">
|
||||
<div class="logo">
|
||||
<img src="/images/logo.png">
|
||||
</div>
|
||||
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
|
||||
<div class="disclaimer">
|
||||
{{ $t('disclaimer') }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
4
public/src/route/admin/Codes.vue
Normal file
4
public/src/route/admin/Codes.vue
Normal file
@ -0,0 +1,4 @@
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
10
public/src/route/admin/Landing.vue
Normal file
10
public/src/route/admin/Landing.vue
Normal file
@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<div id="admin">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
10
public/src/route/admin/Login.vue
Normal file
10
public/src/route/admin/Login.vue
Normal file
@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<div id="login">
|
||||
Login.
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
4
public/src/route/admin/Profile.vue
Normal file
4
public/src/route/admin/Profile.vue
Normal file
@ -0,0 +1,4 @@
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
4
public/src/route/admin/Users.vue
Normal file
4
public/src/route/admin/Users.vue
Normal file
@ -0,0 +1,4 @@
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user