refactor: removed useless code, cleaned up, fixed permissions
This commit is contained in:
parent
5ca3c35381
commit
bca8fbcd83
|
@ -3,7 +3,7 @@ const moment = require('moment');
|
||||||
|
|
||||||
exports.seed = async db => {
|
exports.seed = async db => {
|
||||||
const now = moment.utc().toDate();
|
const now = moment.utc().toDate();
|
||||||
const user = await db.table('users').where({ username: 'root' }).first();
|
const user = await db.table('users').where({ username: process.env.ADMIN_ACCOUNT }).first();
|
||||||
if (user) return;
|
if (user) return;
|
||||||
try {
|
try {
|
||||||
const hash = await bcrypt.hash(process.env.ADMIN_PASSWORD, 10);
|
const hash = await bcrypt.hash(process.env.ADMIN_PASSWORD, 10);
|
||||||
|
|
|
@ -14,7 +14,7 @@ class albumDELETE extends Route {
|
||||||
Check if the album exists
|
Check if the album exists
|
||||||
*/
|
*/
|
||||||
const album = await db.table('albums').where({ id, userId: user.id }).first();
|
const album = await db.table('albums').where({ id, userId: user.id }).first();
|
||||||
if (!album) return res.status(400).json({ message: 'The file doesn\'t exist or doesn\'t belong to the user' });
|
if (!album) return res.status(400).json({ message: 'The album doesn\'t exist or doesn\'t belong to the user' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -14,7 +14,7 @@ class albumDELETE extends Route {
|
||||||
Check if the album exists
|
Check if the album exists
|
||||||
*/
|
*/
|
||||||
const album = await db.table('albums').where({ id, userId: user.id }).first();
|
const album = await db.table('albums').where({ id, userId: user.id }).first();
|
||||||
if (!album) return res.status(400).json({ message: 'The file doesn\'t exist or doesn\'t belong to the user' });
|
if (!album) return res.status(400).json({ message: 'The album doesn\'t exist or doesn\'t belong to the user' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await Util.deleteAllFilesFromAlbum(id);
|
await Util.deleteAllFilesFromAlbum(id);
|
||||||
|
|
|
@ -18,6 +18,8 @@ class albumsGET extends Route {
|
||||||
.select('id', 'name', 'createdAt', 'editedAt');
|
.select('id', 'name', 'createdAt', 'editedAt');
|
||||||
|
|
||||||
for (const album of albums) {
|
for (const album of albums) {
|
||||||
|
// TODO: Optimize the shit out of this.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fetch every public link the album has
|
Fetch every public link the album has
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -6,13 +6,13 @@ class linkDELETE extends Route {
|
||||||
super('/album/link/delete/:identifier', 'delete');
|
super('/album/link/delete/:identifier', 'delete');
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(req, res, db) {
|
async run(req, res, db, user) {
|
||||||
const { identifier } = req.params;
|
const { identifier } = req.params;
|
||||||
if (!identifier) return res.status(400).json({ message: 'Invalid identifier supplied' });
|
if (!identifier) return res.status(400).json({ message: 'Invalid identifier supplied' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const link = await db.table('links')
|
const link = await db.table('links')
|
||||||
.where({ identifier })
|
.where({ identifier, userId: user.id })
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
dump(link);
|
dump(link);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
const Route = require('../../../structures/Route');
|
const Route = require('../../../structures/Route');
|
||||||
const Util = require('../../../utils/Util');
|
const Util = require('../../../utils/Util');
|
||||||
const log = require('../../../utils/Log');
|
|
||||||
|
|
||||||
class linkPOST extends Route {
|
class linkPOST extends Route {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -15,7 +14,7 @@ class linkPOST extends Route {
|
||||||
/*
|
/*
|
||||||
Make sure the album exists
|
Make sure the album exists
|
||||||
*/
|
*/
|
||||||
const exists = await db.table('albums').where('id', albumId).first();
|
const exists = await db.table('albums').where({ id: albumId, userId: user.id }).first();
|
||||||
if (!exists) return res.status(400).json({ message: 'Album doesn\t exist' });
|
if (!exists) return res.status(400).json({ message: 'Album doesn\t exist' });
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
const Route = require('../structures/Route');
|
|
||||||
|
|
||||||
class verifyGET extends Route {
|
|
||||||
constructor() {
|
|
||||||
super('/', 'get', { bypassAuth: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
run(req, res) {
|
|
||||||
return res.json({ message: 'Hai hai api desu.' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = verifyGET;
|
|
|
@ -5,11 +5,17 @@ class albumAddPOST extends Route {
|
||||||
super('/file/album/add', 'post');
|
super('/file/album/add', 'post');
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(req, res, db) {
|
async run(req, res, db, user) {
|
||||||
if (!req.body) return res.status(400).json({ message: 'No body provided' });
|
if (!req.body) return res.status(400).json({ message: 'No body provided' });
|
||||||
const { fileId, albumId } = req.body;
|
const { fileId, albumId } = req.body;
|
||||||
if (!fileId || !albumId) return res.status(400).json({ message: 'No id provided' });
|
if (!fileId || !albumId) return res.status(400).json({ message: 'No id provided' });
|
||||||
|
|
||||||
|
// Make sure both file and album belong to the user
|
||||||
|
const file = await db.table('files').where({ id: fileId, userId: user.id }).first();
|
||||||
|
if (!file) return res.status(400).json({ message: 'File doesn\'t exist.' });
|
||||||
|
const album = await db.table('albums').where({ id: albumId, userId: user.id }).first();
|
||||||
|
if (!album) return res.status(400).json({ message: 'Album doesn\'t exist.' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db.table('albumsFiles')
|
await db.table('albumsFiles')
|
||||||
.insert({ fileId, albumId });
|
.insert({ fileId, albumId });
|
||||||
|
|
|
@ -5,11 +5,17 @@ class albumDelPOST extends Route {
|
||||||
super('/file/album/del', 'post');
|
super('/file/album/del', 'post');
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(req, res, db) {
|
async run(req, res, db, user) {
|
||||||
if (!req.body) return res.status(400).json({ message: 'No body provided' });
|
if (!req.body) return res.status(400).json({ message: 'No body provided' });
|
||||||
const { fileId, albumId } = req.body;
|
const { fileId, albumId } = req.body;
|
||||||
if (!fileId || !albumId) return res.status(400).json({ message: 'No id provided' });
|
if (!fileId || !albumId) return res.status(400).json({ message: 'No id provided' });
|
||||||
|
|
||||||
|
// Make sure both file and album belong to the user
|
||||||
|
const file = await db.table('files').where({ id: fileId, userId: user.id }).first();
|
||||||
|
if (!file) return res.status(400).json({ message: 'File doesn\'t exist.' });
|
||||||
|
const album = await db.table('albums').where({ id: albumId, userId: user.id }).first();
|
||||||
|
if (!album) return res.status(400).json({ message: 'Album doesn\'t exist.' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db.table('albumsFiles')
|
await db.table('albumsFiles')
|
||||||
.where({ fileId, albumId })
|
.where({ fileId, albumId })
|
||||||
|
|
|
@ -5,11 +5,15 @@ class tagAddPOST extends Route {
|
||||||
super('/file/tag/add', 'post');
|
super('/file/tag/add', 'post');
|
||||||
}
|
}
|
||||||
|
|
||||||
run(req, res, db) {
|
async run(req, res, db, user) {
|
||||||
if (!req.body) return res.status(400).json({ message: 'No body provided' });
|
if (!req.body) return res.status(400).json({ message: 'No body provided' });
|
||||||
const { fileId, tagNames } = req.body;
|
const { fileId, tagNames } = req.body;
|
||||||
if (!fileId || !tagNames.length) return res.status(400).json({ message: 'No tags provided' });
|
if (!fileId || !tagNames.length) return res.status(400).json({ message: 'No tags provided' });
|
||||||
|
|
||||||
|
// Make sure the file belongs to the user
|
||||||
|
const file = await db.table('files').where({ id: fileId, userId: user.id }).first();
|
||||||
|
if (!file) return res.status(400).json({ message: 'File doesn\'t exist.' });
|
||||||
|
|
||||||
tagNames.forEach(async tag => {
|
tagNames.forEach(async tag => {
|
||||||
try {
|
try {
|
||||||
await db.table('fileTags').insert({ fileId, tag });
|
await db.table('fileTags').insert({ fileId, tag });
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
const Route = require('../../structures/Route');
|
|
||||||
|
|
||||||
class albumDelPOST extends Route {
|
|
||||||
constructor() {
|
|
||||||
super('/file/album/del', 'post');
|
|
||||||
}
|
|
||||||
|
|
||||||
async run(req, res, db) {
|
|
||||||
if (!req.body) return res.status(400).json({ message: 'No body provided' });
|
|
||||||
const { fileId, albumId } = req.body;
|
|
||||||
if (!fileId || !albumId) return res.status(400).json({ message: 'No id provided' });
|
|
||||||
|
|
||||||
try {
|
|
||||||
await db.table('albumsFiles')
|
|
||||||
.where({ fileId, albumId })
|
|
||||||
.delete();
|
|
||||||
} catch (error) {
|
|
||||||
return super.error(res, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json({
|
|
||||||
message: 'Successfully removed file from album'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = albumDelPOST;
|
|
|
@ -19,10 +19,14 @@ class uploadPOST extends Route {
|
||||||
super('/upload.....', 'post', { bypassAuth: true });
|
super('/upload.....', 'post', { bypassAuth: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(req, res, db) {
|
run(req, res) {
|
||||||
|
return res.status(201).send();
|
||||||
|
|
||||||
|
/*
|
||||||
const user = await Util.isAuthorized(req);
|
const user = await Util.isAuthorized(req);
|
||||||
if (!user && process.env.PUBLIC_MODE == 'false') return res.status(401).json({ message: 'Not authorized to use this resource' });
|
if (!user && process.env.PUBLIC_MODE == 'false') return res.status(401).json({ message: 'Not authorized to use this resource' });
|
||||||
return this.uploadFile(req, res, db, user);
|
return this.uploadFile(req, res, db, user);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
async processFile(req, res, db, user, file) {
|
async processFile(req, res, db, user, file) {
|
||||||
|
|
|
@ -6,15 +6,13 @@ class verifyGET extends Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
run(req, res, db, user) {
|
run(req, res, db, user) {
|
||||||
const returnUser = {
|
|
||||||
id: user.id,
|
|
||||||
username: user.username,
|
|
||||||
isAdmin: user.isAdmin
|
|
||||||
};
|
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
message: 'Successfully verified token',
|
message: 'Successfully verified token',
|
||||||
user: returnUser
|
user: {
|
||||||
|
id: user.id,
|
||||||
|
username: user.username,
|
||||||
|
isAdmin: user.isAdmin
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,16 @@ div#drag-overlay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
section.hero {
|
||||||
|
&.dashboard {
|
||||||
|
// background-color: $backgroundLight1 !important;
|
||||||
|
div.hero-body {
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
section input, section a.button {
|
section input, section a.button {
|
||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,11 +172,6 @@ export default {
|
||||||
searchTerm: null
|
searchTerm: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
config() {
|
|
||||||
return this.$store.state.config;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$search.items(this.files);
|
this.$search.items(this.files);
|
||||||
},
|
},
|
||||||
|
|
|
@ -50,30 +50,6 @@
|
||||||
<i class="icon-ecommerce-safebox" /> {{ config.serviceName }}
|
<i class="icon-ecommerce-safebox" /> {{ config.serviceName }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<!--
|
|
||||||
<template v-if="loggedIn">
|
|
||||||
<router-link
|
|
||||||
to="/dashboard/uploads"
|
|
||||||
class="navbar-item no-active"
|
|
||||||
exact><i class="hidden"/>Uploads</router-link>
|
|
||||||
|
|
||||||
<router-link
|
|
||||||
to="/dashboard/albums"
|
|
||||||
class="navbar-item no-active"
|
|
||||||
exact><i class="hidden"/>Albums</router-link>
|
|
||||||
|
|
||||||
<router-link
|
|
||||||
to="/dashboard/tags"
|
|
||||||
class="navbar-item no-active"
|
|
||||||
exact><i class="hidden"/>Tags</router-link>
|
|
||||||
|
|
||||||
<router-link
|
|
||||||
to="/dashboard/settings"
|
|
||||||
class="navbar-item no-active"
|
|
||||||
exact><i class="hidden"/>Settings</router-link>
|
|
||||||
</template>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<div class="spacer" />
|
<div class="spacer" />
|
||||||
|
|
||||||
<template v-if="loggedIn">
|
<template v-if="loggedIn">
|
||||||
|
@ -126,9 +102,6 @@ export default {
|
||||||
loggedIn() {
|
loggedIn() {
|
||||||
return this.$store.state.loggedIn;
|
return this.$store.state.loggedIn;
|
||||||
},
|
},
|
||||||
user() {
|
|
||||||
return this.$store.state.user;
|
|
||||||
},
|
|
||||||
config() {
|
config() {
|
||||||
return this.$store.state.config;
|
return this.$store.state.config;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,5 @@
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '~/assets/styles/_colors.scss';
|
|
||||||
section { background-color: $backgroundLight1 !important; }
|
|
||||||
section.hero div.hero-body {
|
|
||||||
align-items: baseline;
|
|
||||||
}
|
|
||||||
div.search-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<style lang="scss">
|
|
||||||
@import '~/assets/styles/_colors.scss';
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="hero is-fullheight">
|
<section class="hero is-fullheight dashboard">
|
||||||
<div class="hero-body">
|
<div class="hero-body">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
|
@ -95,11 +79,6 @@ export default {
|
||||||
user: {}
|
user: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
config() {
|
|
||||||
return this.$store.state.config;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
metaInfo() {
|
metaInfo() {
|
||||||
return { title: 'Account' };
|
return { title: 'Account' };
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="hero is-fullheight">
|
<section class="hero is-fullheight dashboard">
|
||||||
<div class="hero-body">
|
<div class="hero-body">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
|
@ -71,11 +71,6 @@ export default {
|
||||||
showingModalForFile: null
|
showingModalForFile: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
config() {
|
|
||||||
return this.$store.state.config;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
metaInfo() {
|
metaInfo() {
|
||||||
return { title: 'Album' };
|
return { title: 'Album' };
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '~/assets/styles/_colors.scss';
|
@import '~/assets/styles/_colors.scss';
|
||||||
section { background-color: $backgroundLight1 !important; }
|
|
||||||
section.hero div.hero-body {
|
|
||||||
align-items: baseline;
|
|
||||||
}
|
|
||||||
div.search-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.view-container {
|
div.view-container {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
@ -130,7 +121,7 @@
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="hero is-fullheight">
|
<section class="hero is-fullheight dashboard">
|
||||||
<div class="hero-body">
|
<div class="hero-body">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '~/assets/styles/_colors.scss';
|
|
||||||
section { background-color: $backgroundLight1 !important; }
|
|
||||||
section.hero div.hero-body {
|
|
||||||
align-items: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.albumsModal .columns .column { padding: .25rem; }
|
.albumsModal .columns .column { padding: .25rem; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="hero is-fullheight">
|
<section class="hero is-fullheight dashboard">
|
||||||
<div class="hero-body">
|
<div class="hero-body">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
|
@ -71,11 +65,6 @@ export default {
|
||||||
showingModalForFile: null
|
showingModalForFile: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
config() {
|
|
||||||
return this.$store.state.config;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
metaInfo() {
|
metaInfo() {
|
||||||
return { title: 'Uploads' };
|
return { title: 'Uploads' };
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,21 +1,5 @@
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '~/assets/styles/_colors.scss';
|
|
||||||
section { background-color: $backgroundLight1 !important; }
|
|
||||||
section.hero div.hero-body {
|
|
||||||
align-items: baseline;
|
|
||||||
}
|
|
||||||
div.search-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<style lang="scss">
|
|
||||||
@import '~/assets/styles/_colors.scss';
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="hero is-fullheight">
|
<section class="hero is-fullheight dashboard">
|
||||||
<div class="hero-body">
|
<div class="hero-body">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
|
@ -25,11 +9,6 @@
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<h2 class="subtitle">Service settings</h2>
|
<h2 class="subtitle">Service settings</h2>
|
||||||
<hr>
|
<hr>
|
||||||
<!--
|
|
||||||
<h1 class="title">Uploads</h1>
|
|
||||||
<h2 class="subtitle">Keep track of all your uploads in here</h2>
|
|
||||||
<hr>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<b-field label="Service name"
|
<b-field label="Service name"
|
||||||
message="Please enter the name which this service is gonna be identified as"
|
message="Please enter the name which this service is gonna be identified as"
|
||||||
|
@ -130,11 +109,6 @@ export default {
|
||||||
options: {}
|
options: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
config() {
|
|
||||||
return this.$store.state.config;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
metaInfo() {
|
metaInfo() {
|
||||||
return { title: 'Settings' };
|
return { title: 'Settings' };
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '~/assets/styles/_colors.scss';
|
@import '~/assets/styles/_colors.scss';
|
||||||
section { background-color: $backgroundLight1 !important; }
|
|
||||||
section.hero div.hero-body {
|
|
||||||
align-items: baseline;
|
|
||||||
}
|
|
||||||
div.search-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.view-container {
|
div.view-container {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
@ -130,7 +121,7 @@
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="hero is-fullheight">
|
<section class="hero is-fullheight dashboard">
|
||||||
<div class="hero-body">
|
<div class="hero-body">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '~/assets/styles/_colors.scss';
|
@import '~/assets/styles/_colors.scss';
|
||||||
section { background-color: $backgroundLight1 !important; }
|
|
||||||
section.hero div.hero-body {
|
|
||||||
align-items: baseline;
|
|
||||||
}
|
|
||||||
div.search-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.view-container {
|
div.view-container {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
@ -130,7 +121,7 @@
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="hero is-fullheight">
|
<section class="hero is-fullheight dashboard">
|
||||||
<div class="hero-body">
|
<div class="hero-body">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
|
|
Loading…
Reference in New Issue