Merge f1683907b0
into 9367eb5eb8
This commit is contained in:
commit
c874dee383
|
@ -1,3 +1,4 @@
|
|||
const { response } = require('express');
|
||||
const Route = require('../../structures/Route');
|
||||
const Util = require('../../utils/Util');
|
||||
|
||||
|
@ -11,21 +12,26 @@ class filesGET extends Route {
|
|||
if (!id) return res.status(400).json({ message: 'Invalid file ID supplied' });
|
||||
|
||||
let file = await db.table('files').where({ id }).first();
|
||||
const user = await db.table('users')
|
||||
.select('id', 'username', 'enabled', 'createdAt', 'editedAt', 'apiKeyEditedAt', 'isAdmin')
|
||||
.where({ id: file.userId })
|
||||
.first();
|
||||
file = Util.constructFilePublicLink(req, file);
|
||||
|
||||
// Additional relevant data
|
||||
const filesFromUser = await db.table('files').where({ userId: user.id }).select('id');
|
||||
user.fileCount = filesFromUser.length;
|
||||
if (file.userId) {
|
||||
const user = await db.table('users')
|
||||
.select('id', 'username', 'enabled', 'createdAt', 'editedAt', 'apiKeyEditedAt', 'isAdmin')
|
||||
.where({ id: file.userId })
|
||||
.first();
|
||||
const filesFromUser = await db.table('files').where({ userId: user.id }).select('id');
|
||||
user.fileCount = filesFromUser.length;
|
||||
|
||||
return res.json({
|
||||
return res.json({
|
||||
message: 'Successfully retrieved file',
|
||||
file,
|
||||
user
|
||||
})
|
||||
}
|
||||
else return res.json({
|
||||
message: 'Successfully retrieved file',
|
||||
file,
|
||||
user
|
||||
});
|
||||
file
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
const Route = require('../../structures/Route');
|
||||
const Util = require('../../utils/Util');
|
||||
|
||||
class filesGET extends Route {
|
||||
constructor() {
|
||||
super('/admin/uploads', 'get', { adminOnly: true });
|
||||
}
|
||||
|
||||
async run(req, res, db) {
|
||||
try {
|
||||
let count = 0;
|
||||
let files = db.table('files')
|
||||
.where({ userId: null })
|
||||
.orderBy('id', 'desc');
|
||||
|
||||
const { page, limit = 100 } = req.query;
|
||||
if (page && page >= 0) {
|
||||
files = await files.offset((page - 1) * limit).limit(limit);
|
||||
|
||||
const dbRes = await db.table('files')
|
||||
.count('* as count')
|
||||
.where({ userId: null })
|
||||
.first();
|
||||
|
||||
count = dbRes.count;
|
||||
} else {
|
||||
files = await files; // execute the query
|
||||
count = files.length;
|
||||
}
|
||||
|
||||
for (let file of files) {
|
||||
file = Util.constructFilePublicLink(req, file);
|
||||
}
|
||||
|
||||
return res.json({
|
||||
message: 'Successfully retrieved uploads',
|
||||
files,
|
||||
count
|
||||
});
|
||||
} catch (error) {
|
||||
return super.error(res, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = filesGET;
|
|
@ -9,7 +9,7 @@ class userDemote extends Route {
|
|||
async run(req, res) {
|
||||
if (!req.body) return res.status(400).json({ message: 'No body provided' });
|
||||
const { id } = req.body;
|
||||
if (!id) return res.status(400).json({ message: 'No id provided' });
|
||||
// if (!id) return res.status(400).json({ message: 'No id provided' });
|
||||
|
||||
try {
|
||||
await Util.deleteAllFilesFromUser(id);
|
||||
|
@ -18,7 +18,7 @@ class userDemote extends Route {
|
|||
}
|
||||
|
||||
return res.json({
|
||||
message: 'Successfully deleted the user\'s files'
|
||||
message: 'Successfully deleted files'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
Administration
|
||||
<b-icon class="is-pulled-right" :icon="props.expanded ? 'menu-down' : 'menu-up'" />
|
||||
</template>
|
||||
<b-menu-item icon="file-cog" label="Public uploads" tag="nuxt-link" to="/dashboard/admin/uploads" exact />
|
||||
<b-menu-item icon="account" label="Users" tag="nuxt-link" to="/dashboard/admin/users" exact />
|
||||
<b-menu-item icon="cog-outline" label="Settings" tag="nuxt-link" to="/dashboard/admin/settings" exact />
|
||||
<b-menu-item icon="chart-line" label="Statistics" tag="nuxt-link" to="/dashboard/admin/statistics" exact />
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
<span><timeago :since="admin.file.createdAt" /></span>
|
||||
</b-field>
|
||||
</div>
|
||||
<div class="column is-6">
|
||||
<div class="column is-6" v-if="admin.file.userId">
|
||||
<b-field
|
||||
label="User Id"
|
||||
horizontal>
|
||||
|
@ -103,13 +103,13 @@
|
|||
|
||||
<div class="mb2 mt2 text-center">
|
||||
<b-button
|
||||
v-if="admin.user.id !== auth.user.id"
|
||||
v-if="admin.file.userId !== auth.user.id"
|
||||
type="is-danger"
|
||||
@click="promptBanIP">
|
||||
Ban IP
|
||||
</b-button>
|
||||
<b-button
|
||||
v-if="admin.user.id !== auth.user.id"
|
||||
v-if="admin.user.id !== auth.user.id && admin.file.userId"
|
||||
type="is-danger"
|
||||
@click="promptDisableUser">
|
||||
Disable user
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
<style lang="scss" scoped>
|
||||
.underline { text-decoration: underline; }
|
||||
</style>
|
||||
<template>
|
||||
<section class="section is-fullheight dashboard">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column is-narrow">
|
||||
<Sidebar />
|
||||
</div>
|
||||
<div class="column">
|
||||
<h2 class="subtitle">
|
||||
Manage public uploads
|
||||
</h2>
|
||||
<hr>
|
||||
|
||||
<div class="mb2 mt2 text-center">
|
||||
<b-button
|
||||
type="is-danger"
|
||||
@click="promptPurgeFiles()">
|
||||
Purge files
|
||||
</b-button>
|
||||
</div>
|
||||
|
||||
<Grid
|
||||
v-if="user.files.length"
|
||||
:files="user.files">
|
||||
<template v-slot:pagination>
|
||||
<b-pagination
|
||||
:total="user.totalFiles"
|
||||
:per-page="limit"
|
||||
:current.sync="current"
|
||||
range-before="2"
|
||||
range-after="2"
|
||||
class="pagination-slot"
|
||||
icon-prev="icon-interface-arrow-left"
|
||||
icon-next="icon-interface-arrow-right"
|
||||
icon-pack="icon"
|
||||
aria-next-label="Next page"
|
||||
aria-previous-label="Previous page"
|
||||
aria-page-label="Page"
|
||||
aria-current-label="Current page" />
|
||||
</template>
|
||||
</Grid>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters, mapActions } from 'vuex';
|
||||
import Sidebar from '~/components/sidebar/Sidebar.vue';
|
||||
import Grid from '~/components/grid/Grid.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sidebar,
|
||||
Grid
|
||||
},
|
||||
middleware: ['auth', 'admin'],
|
||||
data() {
|
||||
return {
|
||||
options: {},
|
||||
current: 1,
|
||||
isLoading: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
limit: 'images/getLimit'
|
||||
}),
|
||||
...mapState({
|
||||
user: state => state.admin.user
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
current: 'fetchPaginate'
|
||||
},
|
||||
async asyncData({ app, params }) {
|
||||
await app.store.dispatch('admin/fetchFiles');
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
fetch: 'admin/fetchFiles'
|
||||
}),
|
||||
async fetchPaginate() {
|
||||
this.isLoading = true;
|
||||
await this.fetch( this.current );
|
||||
this.isLoading = false;
|
||||
},
|
||||
promptPurgeFiles() {
|
||||
this.$buefy.dialog.confirm({
|
||||
message: 'Are you sure you want to delete public files?',
|
||||
onConfirm: () => this.purgeFiles()
|
||||
});
|
||||
},
|
||||
async purgeFiles() {
|
||||
this.$handler.executeAction('admin/purgeUserFiles', null);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -1,3 +1,5 @@
|
|||
import axios from "axios";
|
||||
|
||||
export const state = () => ({
|
||||
users: [],
|
||||
user: {
|
||||
|
@ -57,6 +59,13 @@ export const actions = {
|
|||
|
||||
return response;
|
||||
},
|
||||
async fetchFiles({ commit }, page) {
|
||||
page = page || 1;
|
||||
const response = await this.$axios.$get('admin/uploads', { params: {limit: 50, page} });
|
||||
commit('setUserInfo', { ...response, page });
|
||||
|
||||
return response;
|
||||
},
|
||||
async fetchFile({ commit }, id) {
|
||||
const response = await this.$axios.$get(`admin/file/${id}`);
|
||||
commit('setFile', response);
|
||||
|
|
Loading…
Reference in New Issue