diff --git a/src/client/app/admin/views/drive.vue b/src/client/app/admin/views/drive.vue
new file mode 100644
index 000000000..d543d0a07
--- /dev/null
+++ b/src/client/app/admin/views/drive.vue
@@ -0,0 +1,139 @@
+
+
+
+ {{ $t('@.drive') }}
+
+
+
+ {{ $t('sort.title') }}
+
+
+
+
+
+
+ {{ $t('origin.title') }}
+
+
+
+
+
+
+
+
+
+ {{ file.name }}
+ @{{ file.user | acct }}
+
+
+
+ {{ file.type }}
+ {{ file.datasize | bytes }}
+
+
+
+
+
+ {{ $t('@.load-more') }}
+
+
+
+
+
+
+
+
diff --git a/src/client/app/admin/views/index.vue b/src/client/app/admin/views/index.vue
index 3da13ad21..9524a9854 100644
--- a/src/client/app/admin/views/index.vue
+++ b/src/client/app/admin/views/index.vue
@@ -22,12 +22,11 @@
{{ $t('instance') }}
{{ $t('moderators') }}
{{ $t('users') }}
+ {{ $t('@.drive') }}
{{ $t('emoji') }}
{{ $t('announcements') }}
{{ $t('hashtags') }}
-
-
@@ -63,6 +62,7 @@ import XEmoji from "./emoji.vue";
import XAnnouncements from "./announcements.vue";
import XHashtags from "./hashtags.vue";
import XUsers from "./users.vue";
+import XDrive from "./drive.vue";
import { faHeadset, faArrowLeft, faShareAlt } from '@fortawesome/free-solid-svg-icons';
import { faGrin } from '@fortawesome/free-regular-svg-icons';
@@ -79,7 +79,8 @@ export default Vue.extend({
XEmoji,
XAnnouncements,
XHashtags,
- XUsers
+ XUsers,
+ XDrive,
},
provide: {
isMobile
diff --git a/src/models/drive-file.ts b/src/models/drive-file.ts
index e4c159804..24c7ac75c 100644
--- a/src/models/drive-file.ts
+++ b/src/models/drive-file.ts
@@ -1,6 +1,7 @@
import * as mongo from 'mongodb';
const deepcopy = require('deepcopy');
import { pack as packFolder } from './drive-folder';
+import { pack as packUser } from './user';
import monkDb, { nativeDbConn } from '../db/mongodb';
import isObjectId from '../misc/is-objectid';
import getDriveFileUrl, { getOriginalUrl } from '../misc/get-drive-file-url';
@@ -131,6 +132,7 @@ export const packMany = (
options?: {
detail?: boolean
self?: boolean,
+ withUser?: boolean,
}
) => {
return Promise.all(files.map(f => pack(f, options)));
@@ -144,6 +146,7 @@ export const pack = (
options?: {
detail?: boolean,
self?: boolean,
+ withUser?: boolean,
}
) => new Promise(async (resolve, reject) => {
const opts = Object.assign({
@@ -208,6 +211,11 @@ export const pack = (
*/
}
+ if (opts.withUser) {
+ // Populate user
+ _target.user = await packUser(_file.metadata.userId);
+ }
+
delete _target.withoutChunks;
delete _target.storage;
delete _target.storageProps;
diff --git a/src/server/api/endpoints/admin/drive/files.ts b/src/server/api/endpoints/admin/drive/files.ts
new file mode 100644
index 000000000..2e54270a0
--- /dev/null
+++ b/src/server/api/endpoints/admin/drive/files.ts
@@ -0,0 +1,79 @@
+import $ from 'cafy';
+import File, { packMany } from '../../../../../models/drive-file';
+import define from '../../../define';
+
+export const meta = {
+ requireCredential: false,
+ requireModerator: true,
+
+ params: {
+ limit: {
+ validator: $.num.optional.range(1, 100),
+ default: 10
+ },
+
+ offset: {
+ validator: $.num.optional.min(0),
+ default: 0
+ },
+
+ sort: {
+ validator: $.str.optional.or([
+ '+createdAt',
+ '-createdAt',
+ '+size',
+ '-size',
+ ]),
+ },
+
+ origin: {
+ validator: $.str.optional.or([
+ 'combined',
+ 'local',
+ 'remote',
+ ]),
+ default: 'local'
+ }
+ }
+};
+
+export default define(meta, (ps, me) => new Promise(async (res, rej) => {
+ let _sort;
+ if (ps.sort) {
+ if (ps.sort == '+createdAt') {
+ _sort = {
+ uploadDate: -1
+ };
+ } else if (ps.sort == '-createdAt') {
+ _sort = {
+ uploadDate: 1
+ };
+ } else if (ps.sort == '+size') {
+ _sort = {
+ length: -1
+ };
+ } else if (ps.sort == '+size') {
+ _sort = {
+ length: -1
+ };
+ }
+ } else {
+ _sort = {
+ _id: -1
+ };
+ }
+
+ const q =
+ ps.origin == 'local' ? { host: null } :
+ ps.origin == 'remote' ? { host: { $ne: null } } :
+ {};
+
+ const files = await File
+ .find(q, {
+ limit: ps.limit,
+ sort: _sort,
+ skip: ps.offset
+ });
+
+ res(await packMany(files, { detail: true, withUser: true }));
+}));