From cba7bf8586f59a049f79aba586db201ac6f3530b Mon Sep 17 00:00:00 2001 From: Pitu Date: Sun, 13 Oct 2019 02:53:45 +0900 Subject: This commit adds a bunch of features for admins: * banning IP * see files from other users if you are admin * be able to see details of an uploaded file and it's user * improved display of thumbnails for non-image files --- .../migrations/20190221225812_initialMigration.js | 24 ++ .../database/migrations/20190221225813_addTags.js | 21 -- src/api/routes/admin/banIP.js | 25 ++ src/api/routes/admin/unBanIP.js | 27 ++ src/api/routes/admin/userGET.js | 32 +++ src/api/routes/files/fileGET.js | 29 +++ src/api/structures/Route.js | 5 +- src/site/assets/images/blank.png | Bin 466 -> 1892 bytes src/site/components/grid/Grid.vue | 290 ++++++++++++++++----- src/site/components/sidebar/Sidebar.vue | 4 +- src/site/pages/a/_identifier.vue | 3 +- src/site/pages/dashboard/admin/file/_id.vue | 170 ++++++++++++ src/site/pages/dashboard/admin/settings.vue | 135 ++++++++++ src/site/pages/dashboard/admin/user/_id.vue | 102 ++++++++ src/site/pages/dashboard/admin/users.vue | 249 ++++++++++++++++++ src/site/pages/dashboard/settings.vue | 135 ---------- src/site/pages/dashboard/users.vue | 249 ------------------ 17 files changed, 1023 insertions(+), 477 deletions(-) delete mode 100644 src/api/database/migrations/20190221225813_addTags.js create mode 100644 src/api/routes/admin/banIP.js create mode 100644 src/api/routes/admin/unBanIP.js create mode 100644 src/api/routes/admin/userGET.js create mode 100644 src/api/routes/files/fileGET.js create mode 100644 src/site/pages/dashboard/admin/file/_id.vue create mode 100644 src/site/pages/dashboard/admin/settings.vue create mode 100644 src/site/pages/dashboard/admin/user/_id.vue create mode 100644 src/site/pages/dashboard/admin/users.vue delete mode 100644 src/site/pages/dashboard/settings.vue delete mode 100644 src/site/pages/dashboard/users.vue (limited to 'src') diff --git a/src/api/database/migrations/20190221225812_initialMigration.js b/src/api/database/migrations/20190221225812_initialMigration.js index a9ce2c7..84bda7e 100644 --- a/src/api/database/migrations/20190221225812_initialMigration.js +++ b/src/api/database/migrations/20190221225812_initialMigration.js @@ -62,6 +62,27 @@ exports.up = async knex => { table.integer('albumId'); table.integer('linkId'); }); + + await knex.schema.createTable('tags', table => { + table.increments(); + table.string('uuid'); + table.integer('userId'); + table.string('name'); + table.timestamp('createdAt'); + table.timestamp('editedAt'); + }); + + await knex.schema.createTable('fileTags', table => { + table.increments(); + table.integer('fileId'); + table.integer('tagId'); + }); + + await knex.schema.createTable('bans', table => { + table.increments(); + table.string('ip'); + table.timestamp('createdAt'); + }); }; exports.down = async knex => { await knex.schema.dropTableIfExists('users'); @@ -70,4 +91,7 @@ exports.down = async knex => { await knex.schema.dropTableIfExists('links'); await knex.schema.dropTableIfExists('albumsFiles'); await knex.schema.dropTableIfExists('albumsLinks'); + await knex.schema.dropTableIfExists('tags'); + await knex.schema.dropTableIfExists('fileTags'); + await knex.schema.dropTableIfExists('bans'); }; diff --git a/src/api/database/migrations/20190221225813_addTags.js b/src/api/database/migrations/20190221225813_addTags.js deleted file mode 100644 index ef71877..0000000 --- a/src/api/database/migrations/20190221225813_addTags.js +++ /dev/null @@ -1,21 +0,0 @@ -exports.up = async knex => { - await knex.schema.createTable('tags', table => { - table.increments(); - table.string('uuid'); - table.integer('userId'); - table.string('name'); - table.timestamp('createdAt'); - table.timestamp('editedAt'); - }); - - await knex.schema.createTable('fileTags', table => { - table.increments(); - table.integer('fileId'); - table.integer('tagId'); - }); -}; - -exports.down = async knex => { - await knex.schema.dropTableIfExists('tags'); - await knex.schema.dropTableIfExists('fileTags'); -}; diff --git a/src/api/routes/admin/banIP.js b/src/api/routes/admin/banIP.js new file mode 100644 index 0000000..692880d --- /dev/null +++ b/src/api/routes/admin/banIP.js @@ -0,0 +1,25 @@ +const Route = require('../../structures/Route'); + +class banIP extends Route { + constructor() { + super('/admin/ban/ip', 'post', { adminOnly: true }); + } + + async run(req, res, db) { + if (!req.body) return res.status(400).json({ message: 'No body provided' }); + const { ip } = req.body; + if (!ip) return res.status(400).json({ message: 'No ip provided' }); + + try { + await db.table('bans').insert({ ip }); + } catch (error) { + return super.error(res, error); + } + + return res.json({ + message: 'Successfully banned the ip' + }); + } +} + +module.exports = banIP; diff --git a/src/api/routes/admin/unBanIP.js b/src/api/routes/admin/unBanIP.js new file mode 100644 index 0000000..493834b --- /dev/null +++ b/src/api/routes/admin/unBanIP.js @@ -0,0 +1,27 @@ +const Route = require('../../structures/Route'); + +class unBanIP extends Route { + constructor() { + super('/admin/unban/ip', 'post', { adminOnly: true }); + } + + async run(req, res, db) { + if (!req.body) return res.status(400).json({ message: 'No body provided' }); + const { ip } = req.body; + if (!ip) return res.status(400).json({ message: 'No ip provided' }); + + try { + await db.table('bans') + .where({ ip }) + .delete(); + } catch (error) { + return super.error(res, error); + } + + return res.json({ + message: 'Successfully unbanned the ip' + }); + } +} + +module.exports = unBanIP; diff --git a/src/api/routes/admin/userGET.js b/src/api/routes/admin/userGET.js new file mode 100644 index 0000000..895a565 --- /dev/null +++ b/src/api/routes/admin/userGET.js @@ -0,0 +1,32 @@ +const Route = require('../../structures/Route'); +const Util = require('../../utils/Util'); + +class usersGET extends Route { + constructor() { + super('/admin/users/:id', 'get', { adminOnly: true }); + } + + async run(req, res, db) { + const { id } = req.params; + if (!id) return res.status(400).json({ message: 'Invalid user ID supplied' }); + + try { + const user = await db.table('users').where({ id }).first(); + const files = await db.table('files').where({ userId: user.id }); + + for (let file of files) { + file = Util.constructFilePublicLink(file); + } + + return res.json({ + message: 'Successfully retrieved user', + user, + files + }); + } catch (error) { + return super.error(res, error); + } + } +} + +module.exports = usersGET; diff --git a/src/api/routes/files/fileGET.js b/src/api/routes/files/fileGET.js new file mode 100644 index 0000000..3bb8da4 --- /dev/null +++ b/src/api/routes/files/fileGET.js @@ -0,0 +1,29 @@ +const Route = require('../../structures/Route'); +const Util = require('../../utils/Util'); + +class filesGET extends Route { + constructor() { + super('/file/:id', 'get', { adminOnly: true }); + } + + async run(req, res, db) { + const { id } = req.params; + 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').where({ id: file.userId }).first(); + file = Util.constructFilePublicLink(file); + + // Additional relevant data + const filesFromUser = await db.table('files').where({ userId: user.id }).select('id'); + user.fileCount = filesFromUser.length; + + return res.json({ + message: 'Successfully retrieved file', + file, + user + }); + } +} + +module.exports = filesGET; diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index c04c585..2db9bc6 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -52,7 +52,10 @@ class Route { this.options = options || {}; } - authorize(req, res) { + async authorize(req, res) { + const banned = await db.table('bans').where({ ip: req.ip }).first(); + if (banned) return res.status(401).json({ message: 'This IP has been banned from using the service.' }); + if (this.options.bypassAuth) return this.run(req, res, db); if (req.headers.apiKey) return this.authorizeApiKey(req, res, req.headers.apiKey); if (!req.headers.authorization) return res.status(401).json({ message: 'No authorization header provided' }); diff --git a/src/site/assets/images/blank.png b/src/site/assets/images/blank.png index 8615039..224a81c 100644 Binary files a/src/site/assets/images/blank.png and b/src/site/assets/images/blank.png differ diff --git a/src/site/components/grid/Grid.vue b/src/site/components/grid/Grid.vue index 19acde9..2e2f911 100644 --- a/src/site/components/grid/Grid.vue +++ b/src/site/components/grid/Grid.vue @@ -4,6 +4,30 @@ transition: all .25s cubic-bezier(.55,0,.1,1); -webkit-transition: all .25s cubic-bezier(.55,0,.1,1); } + + div.toolbar { + padding: 1rem; + + .block { + text-align: right; + } + } + + span.extension { + position: absolute; + width: 100%; + height: 100%; + z-index: 0; + top: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; + font-size: 2rem; + pointer-events: none; + opacity: .75; + } + div.actions { opacity: 0; -webkit-transition: opacity 0.1s linear; @@ -23,6 +47,11 @@ span { padding: 3px; + &.more { + position: absolute; + top: 0; + right: 0; + } &:nth-child(1), &:nth-child(2) { align-items: flex-end; @@ -38,7 +67,7 @@ justify-content: center; align-items: center; display: flex; - &:before { + &.btn:before { content: ''; width: 30px; height: 30px; @@ -76,64 +105,174 @@ diff --git a/src/site/pages/dashboard/admin/settings.vue b/src/site/pages/dashboard/admin/settings.vue new file mode 100644 index 0000000..052a641 --- /dev/null +++ b/src/site/pages/dashboard/admin/settings.vue @@ -0,0 +1,135 @@ + + + diff --git a/src/site/pages/dashboard/admin/user/_id.vue b/src/site/pages/dashboard/admin/user/_id.vue new file mode 100644 index 0000000..7703b1c --- /dev/null +++ b/src/site/pages/dashboard/admin/user/_id.vue @@ -0,0 +1,102 @@ + + + + diff --git a/src/site/pages/dashboard/admin/users.vue b/src/site/pages/dashboard/admin/users.vue new file mode 100644 index 0000000..1fefa1e --- /dev/null +++ b/src/site/pages/dashboard/admin/users.vue @@ -0,0 +1,249 @@ + + + + + + + diff --git a/src/site/pages/dashboard/settings.vue b/src/site/pages/dashboard/settings.vue deleted file mode 100644 index 35a23e8..0000000 --- a/src/site/pages/dashboard/settings.vue +++ /dev/null @@ -1,135 +0,0 @@ - - - diff --git a/src/site/pages/dashboard/users.vue b/src/site/pages/dashboard/users.vue deleted file mode 100644 index 66ccebe..0000000 --- a/src/site/pages/dashboard/users.vue +++ /dev/null @@ -1,249 +0,0 @@ - - - - - - - -- cgit v1.2.3