This commit is contained in:
Troplo 2020-10-08 03:37:31 +11:00
parent fe9427bbf2
commit 951fe5b493
4 changed files with 318 additions and 0 deletions

View File

@ -63,6 +63,11 @@
title: 'Audit Logs',
route: 'logs',
icon: 'edit'
},
{
title: 'Staff Applications',
route: 'applications',
icon: 'paper-plane'
}
]
}

View File

@ -0,0 +1,298 @@
<template>
<div class='admin_moderation'>
<h1>Staff Applications (Definitely not mobile friendly, not tested)F</h1>
<confirm-modal v-model='removePostObj.showConfirmModal' @confirm='removePost' text='Remove' color='red'>
Are you sure you want to remove this post?
</confirm-modal>
<confirm-modal v-model='removePostObj.showThreadDeleteModal' @confirm='deleteThread' text='Delete' color='red'>
Are you sure you want to delete the thread containing this post?
</confirm-modal>
<transition name='fade' mode='out-in'>
<loading-message v-if='!reports' key='loading'></loading-message>
<div
class='admin_moderation__reports'
v-else-if='filteredReports.length'
key='reports'
>
<div class='admin_moderation__report admin_moderation__report--header'>
<div class='admin_moderation__report__post admin_moderation__report--cell_border admin_moderation__report--cell_border-hidden'>
User
</div>
<div class='admin_moderation__report__reason admin_moderation__report--cell_border admin_moderation__report--cell_border-hidden'>Report reason</div>
<div class='admin_moderation__report__flagged_by admin_moderation__report--cell_border admin_moderation__report--cell_border-hidden'>
Reported by user
</div>
<div class='admin_moderation__report__actions'>
Actions
</div>
</div>
<div class='admin_moderation__report' :key='"report-" + $index' v-for='(report, $index) in filteredReports'>
<div class='admin_moderation__report__post admin_moderation__report--cell_border'>
<div class=''>
<div class='admin_moderation__report__post__user'>{{report.username}}</div>
</div>
<div class='admin_moderation__report__post__content'>{{report.Post.content | stripTags | truncate(150)}}</div>
</div>
<div class='admin_moderation__report__reason admin_moderation__report--cell_border'>{{report.reason}}</div>
<div class='admin_moderation__report__flagged_by admin_moderation__report--cell_border'>
<avatar-icon class='admin_moderation__report__flagged_by__avatar' size='small' :user='report.FlaggedByUser'></avatar-icon>
<div class='admin_moderation__report__flagged_by__text_info'>
<div class='admin_moderation__report__flagged_by__user'>{{report.FlaggedByUserUsername}}</div>
<div class='admin_moderation__report__flagged_by__date'>{{report.createdAt| formatDate}}</div>
</div>
</div>
<div class='admin_moderation__report__actions'>
<button class='button button--red' @click='removePost(report, $index)'>Remove post</button>
<menu-button
@delete='deleteReport(report.id, $index)'
@ban='banUser(report, $index)'
@deleteThread='deleteThread(report, $index)'
:options='reportMenuOptions'
>
<button class='button'>More options&hellip;</button>
</menu-button>
</div>
</div>
</div>
<div class='overlay_message' v-else key='no reports'>
<font-awesome-icon :icon='["fa", "thumbs-up"]' />
No user reports
</div>
</transition>
</div>
</template>
<script>
import MenuButton from '../MenuButton'
import LoadingMessage from '../LoadingMessage'
import AvatarIcon from '../AvatarIcon'
import ConfirmModal from '../ConfirmModal'
import AjaxErrorHandler from '../../assets/js/errorHandler'
export default {
name: 'AdminDashboard',
components: {
MenuButton,
LoadingMessage,
AvatarIcon,
ConfirmModal
},
data () {
return {
reportMenuOptions: [
{ value: "Delete report", event: 'delete' },
{ value: "Ban a user", event: 'ban' },
{ value: "Delete thread", event: 'deleteThread' }
],
reports: null,
removePostObj: {
showConfirmModal: false,
showThreadDeleteModal: false,
report: null,
index: null
}
}
},
computed: {
filteredReports () {
if (!this.reports) return null;
return this.reports
//Only show reports not already deleted
.filter(report => report.Post)
.map(report => {
let clone = Object.create(report);
//Provide username text if user deleted for post
//or flaggedByUser
if(!report.Post.User) {
clone.PostUserUsername = '[deleted]';
} else {
clone.PostUserUsername = report.Post.User.username;
}
if(!report.FlaggedByUser) {
clone.FlaggedByUserUsername = '[deleted]';
} else {
clone.FlaggedByUserUsername = report.FlaggedByUser.username;
}
return clone;
});
}
},
methods: {
deleteReport (id, index) {
return this.axios
.delete('/api/v1/users/report/' + id)
.then(() => {
this.reports.splice(index, 1)
})
.catch(AjaxErrorHandler(this.$store))
},
deleteThread (report, index) {
if(report) {
this.removePostObj.report = report
this.removePostObj.index = index
this.removePostObj.showThreadDeleteModal = true
} else {
let threadId = this.removePostObj.report.Post.Thread.id
this.axios
.delete('/api/v1/forums/thread/' + threadId)
.then(() => {
//Get reports with id of deleted thread
//and remove them locally
this.reports = this.reports.filter(report => {
return report.Post.Thread.id !== threadId
})
})
.catch(AjaxErrorHandler(this.$store))
}
},
removePost (report, index) {
if(report) {
this.removePostObj.report = report
this.removePostObj.index = index
this.removePostObj.showConfirmModal = true
} else {
this.axios
.delete('/api/v1/forums/post/' + this.removePostObj.report.Post.id)
.then(() => {
return this.axios.delete('/api/v1/users/report/post/' + this.removePostObj.report.id)
})
.then(() => {
this.reports.splice(this.removePostObj.index, 1)
})
.catch(AjaxErrorHandler(this.$store))
}
},
banUser (report) {
this.$router.push('bans')
setTimeout(() => {
this.$store.commit('moderation/setModal', true)
this.$store.commit('moderation/setUsername', report.Post.User.username)
}, 0)
}
},
mounted () {
this.$store.dispatch('setTitle', 'Moderation - Admin')
this.axios
.get('/api/v1/users/report')
.then(res => {
this.reports = res.data
})
.catch(AjaxErrorHandler(this.$store))
}
}
</script>
<style lang='scss' scoped>
@import '../../assets/scss/variables.scss';
.admin_moderation {
padding: 2rem;
padding-top: 1rem;
@at-root #{&}__reports {
margin-top: 1rem;
border: thin solid $color__gray--darker;
border-radius: 0.25rem;
&> :first-child {
border-radius: 0.25rem 0.25rem 0 0;
}
&> :last-child {
border-radius: 0 0 0.25rem 0.25rem;
}
}
@at-root #{&}__report {
display: flex;
background-color: #fff;
border-bottom: thin solid $color__lightgray--darkest;
padding: 0.5rem;
@at-root #{&}--header {
font-weight: bold;
}
@at-root #{&}--cell_border {
padding-right: 0.5rem;
margin-right: 0.5rem;
border-right: thin solid $color__lightgray--darkest;
@at-root #{&}-hidden {
border-right-color: transparent;
}
}
@at-root #{&}__post {
width: 35%;
display: flex;
@at-root #{&}__header {
display: flex;
justify-content: space-between;
border-right: thin solid $color__lightgray--darker;
padding-right: 0.25rem;
}
@at-root #{&}__thread {
font-size: 1rem;
text-decoration: underline;
}
@at-root #{&}__content {
padding-left: 0.25rem;
}
}
@at-root #{&}__reason {
width: 15%;
}
@at-root #{&}__flagged_by {
width: 20%;
display: flex;
@at-root #{&}__text_info {
margin-left: 0.5rem;
display: flex;
flex-direction: column;
}
@at-root #{&}__date {
color: $color__darkgray--primary;
}
}
@at-root #{&}__actions {
width: 30%;
display: flex;
align-items: center;
.button--red {
margin-right: 0.5rem;
}
}
}
@at-root #{&}__header {
display: flex;
justify-content: space-between;
align-items: center;
}
}
</style>

View File

@ -107,6 +107,7 @@ const AdminGeneral = () => import('./components/routes/AdminGeneral')
const AdminUsers = () => import('./components/routes/AdminUsers')
const AdminOther = () => import('./components/routes/AdminOther')
const AdminBadges = () => import('./components/routes/AdminAudit')
const AdminApplications = () => import('./components/routes/AdminApplications')
const Licenses = () => import('./components/routes/LICENSES')
const ConnectionProblems = () => import('./components/routes/ConnectionProblems')
@ -221,6 +222,7 @@ const router = new VueRouter({
{ path: 'moderation/bans', component: AdminModerationBannedUsers },
{ path: 'other', component: AdminOther },
{ path: 'logs', component: AdminBadges },
{ path: 'applications', component: AdminApplications },
] },
{ path: '*', component: NotFound }
],

View File

@ -99,4 +99,17 @@ router.get('/logs', async (req, res, next) => {
throw Errors.featureDisabled
} catch (e) { next(e) }
})
router.get('/', async (req, res, next) => {
try {
let reports = await Report.findAll({
include: [
{ model: User, as: 'User', attributes: { exclude: ['hash', 'email', 'emailVerified', 'koins', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode'] } },
{ model: Post, include: Post.includeOptions(), attributes: { exclude: ['hash', 'email', 'emailVerified', 'koins', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode'] } }
]
})
res.json(reports)
} catch (e) { next(e) }
})
module.exports = router;