diff --git a/CHANGELOG.md b/CHANGELOG.md index ef27fb4b..ac8ad270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased +## [1.2.0] - 2019-09-27 + ### Added - Emoji pack configuration - Ability to require user's password reset +– Ability to track admin/moderator actions, a.k.a. "the moderation log" ## [1.1.0] - 2019-09-15 diff --git a/README.md b/README.md index 72c81829..059918a9 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,19 @@ To compile everything for production run `yarn build:prod`. #### Disabling features -You can disable certain AdminFE features, like reports or settings by modifying `config/prod.env.js` env variable `DISABLED_FEATURES`, e.g. if you want to compile AdminFE without "Settings" you'll need to set it to: `DISABLED_FEATURES: '["settings"]'`, -to disable emoji pack settings add `"emoji-packs"` to the list. +You can disable certain AdminFE features, like reports or settings by modifying `config/prod.env.js` env variable `DISABLED_FEATURES`, e.g. if you want to compile AdminFE without "Settings" you'll need to set it to: `DISABLED_FEATURES: '["settings"]'`. + +Features, that can be disabled: + +- reports: `DISABLED_FEATURES: '["reports"]'` +- invites: `DISABLED_FEATURES: '["invites"]'` +- moderation log: `DISABLED_FEATURES: '["moderationLog"]'` +- settings: `DISABLED_FEATURES: '["settings"]'` +- emoji packs: `DISABLED_FEATURES: '["emojiPacks"]'` + +Of course, you can disable multiple features just by adding to the array, e.g. `DISABLED_FEATURES: '["emojiPacks", "settings"]'` will have both emoji packs and settings disabled. + +Users administration cannot be disabled. ## Changelog diff --git a/src/api/moderationLog.js b/src/api/moderationLog.js new file mode 100644 index 00000000..b866df33 --- /dev/null +++ b/src/api/moderationLog.js @@ -0,0 +1,38 @@ +import _ from 'lodash' + +import request from '@/utils/request' +import { getToken } from '@/utils/auth' +import { baseName } from './utils' + +export async function fetchLog(authHost, token, params, page = 1) { + const normalizedParams = new URLSearchParams( + _.omitBy({ ...params, page }, _.isUndefined) + ).toString() + + return await request({ + baseURL: baseName(authHost), + url: `/api/pleroma/admin/moderation_log?${normalizedParams}`, + method: 'get', + headers: authHeaders(token) + }) +} + +export async function fetchAdmins(authHost, token) { + return await request({ + baseURL: baseName(authHost), + url: `/api/pleroma/admin/users?filters=is_admin`, + method: 'get', + headers: authHeaders(token) + }) +} + +export async function fetchModerators(authHost, token) { + return await request({ + baseURL: baseName(authHost), + url: `/api/pleroma/admin/users?filters=is_moderator`, + method: 'get', + headers: authHeaders(token) + }) +} + +const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {} diff --git a/src/lang/en.js b/src/lang/en.js index eed40f5f..5d705cdf 100644 --- a/src/lang/en.js +++ b/src/lang/en.js @@ -67,6 +67,7 @@ export default { users: 'Users', reports: 'Reports', settings: 'Settings', + moderationLog: 'Moderation Log', 'emoji-packs': 'Emoji packs' }, navbar: { @@ -284,6 +285,9 @@ export default { closed: 'Closed', resolved: 'Resolved' }, + moderationLog: { + moderationLog: 'Moderation Log' + }, settings: { settings: 'Settings', instance: 'Instance', diff --git a/src/router/index.js b/src/router/index.js index b0e0d750..a5c496cc 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -49,6 +49,20 @@ const invites = { ] } +const moderationLogDisabled = disabledFeatures.includes('moderation-log') +const moderationLog = { + path: '/moderation_log', + component: Layout, + children: [ + { + path: 'index', + component: () => import('@/views/moderation_log/index'), + name: 'Moderation Log', + meta: { title: 'moderationLog', icon: 'list', noCache: true } + } + ] +} + const emojiPacksDisabled = disabledFeatures.includes('emoji-packs') const emojiPacks = { path: '/emoji-packs', @@ -122,13 +136,14 @@ export const asyncRouterMap = [ path: 'index', component: () => import('@/views/users/index'), name: 'Users', - meta: { title: 'Users', icon: 'peoples', noCache: true } + meta: { title: 'users', icon: 'peoples', noCache: true } } ] }, - ...(settingsDisabled ? [] : [settings]), ...(reportsDisabled ? [] : [reports]), ...(invitesDisabled ? [] : [invites]), + ...(moderationLogDisabled ? [] : [moderationLog]), + ...(settingsDisabled ? [] : [settings]), ...(emojiPacksDisabled ? [] : [emojiPacks]), { path: '/users/:id', diff --git a/src/store/index.js b/src/store/index.js index 830c0788..985074a0 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2,6 +2,7 @@ import Vue from 'vue' import Vuex from 'vuex' import app from './modules/app' import errorLog from './modules/errorLog' +import moderationLog from './modules/moderationLog' import invites from './modules/invites' import permission from './modules/permission' import reports from './modules/reports' @@ -19,6 +20,7 @@ const store = new Vuex.Store({ modules: { app, errorLog, + moderationLog, invites, permission, reports, diff --git a/src/store/modules/moderationLog.js b/src/store/modules/moderationLog.js new file mode 100644 index 00000000..5e790f9e --- /dev/null +++ b/src/store/modules/moderationLog.js @@ -0,0 +1,51 @@ +import { fetchLog, fetchAdmins, fetchModerators } from '@/api/moderationLog' + +const moderationLog = { + state: { + fetchedLog: [], + logItemsCount: 0, + admins: [], + moderators: [], + logLoading: true, + adminsLoading: true + }, + mutations: { + SET_LOG_LOADING: (state, status) => { + state.logLoading = status + }, + SET_ADMINS_LOADING: (state, status) => { + state.adminsLoading = status + }, + SET_MODERATION_LOG: (state, log) => { + state.fetchedLog = log + }, + SET_MODERATION_LOG_COUNT: (state, count) => { + state.logItemsCount = count + }, + SET_ADMINS: (state, admins) => { + state.admins = admins + }, + SET_MODERATORS: (state, moderators) => { + state.moderators = moderators + } + }, + actions: { + async FetchModerationLog({ commit, getters }, opts = {}) { + const response = await fetchLog(getters.authHost, getters.token, opts) + + commit('SET_MODERATION_LOG', response.data.items) + commit('SET_MODERATION_LOG_COUNT', response.data.total) + commit('SET_LOG_LOADING', false) + }, + async FetchAdmins({ commit, getters }) { + const adminsResponse = await fetchAdmins(getters.authHost, getters.token) + const moderatorsResponse = await fetchModerators(getters.authHost, getters.token) + + commit('SET_ADMINS', adminsResponse.data) + commit('SET_MODERATORS', moderatorsResponse.data) + commit('SET_ADMINS_LOADING', false) + } + } +} + +export default moderationLog diff --git a/src/views/moderation_log/index.vue b/src/views/moderation_log/index.vue new file mode 100644 index 00000000..6dba06f6 --- /dev/null +++ b/src/views/moderation_log/index.vue @@ -0,0 +1,151 @@ + + + {{ $t('moderationLog.moderationLog') }} + + + + + + + + + + + + + + + + + + + + {{ logEntry.message }} + + + + + + + + + + +