From 1222604703918be5dce6206e854012406aab3dc8 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Wed, 24 Jul 2019 20:50:45 +0000 Subject: [PATCH] Reporting enhancements - User moderate actions - Don't show closed reports on the main reports dashboard - User links should link to the user's local (or shadowed) profile *inside* Admin FE so a moderator can do a more "full spectrum" analysis of the situation --- .gitlab-ci.yml | 26 +++ package.json | 2 +- src/api/__mocks__/reports.js | 14 +- src/api/users.js | 18 ++ src/lang/en.js | 14 +- src/router/index.js | 12 ++ src/store/index.js | 2 + src/store/modules/userProfile.js | 36 ++++ src/store/modules/users.js | 3 + .../reports/components/ReportsFilter.vue | 30 ++- src/views/reports/components/TimelineItem.vue | 70 ++++++- src/views/users/index.vue | 2 +- src/views/users/show.vue | 179 ++++++++++++++++++ yarn.lock | 8 +- 14 files changed, 396 insertions(+), 20 deletions(-) create mode 100644 .gitlab-ci.yml create mode 100644 src/store/modules/userProfile.js create mode 100644 src/views/users/show.vue diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..cef4ec5c --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,26 @@ +image: node:10 + +stages: + - lint + - build + - test + +lint: + stage: lint + script: + - yarn + - yarn lint + +test: + stage: test + variables: + APT_CACHE_DIR: apt-cache + script: + - yarn + - yarn test + +build: + stage: build + script: + - yarn + - npm run build:prod diff --git a/package.json b/package.json index 60f8edb4..9adb8ba8 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "driver.js": "0.8.1", "dropzone": "5.2.0", "echarts": "4.1.0", - "element-ui": "^2.7.0", + "element-ui": "^2.10.0", "file-saver": "1.3.8", "fuse.js": "3.4.2", "js-cookie": "2.2.0", diff --git a/src/api/__mocks__/reports.js b/src/api/__mocks__/reports.js index 43df97e7..a337df9a 100644 --- a/src/api/__mocks__/reports.js +++ b/src/api/__mocks__/reports.js @@ -1,14 +1,14 @@ const reports = [ - { created_at: '2019-05-21T21:35:33.000Z', account: { acct: 'benj', display_name: 'Benjamin Fame' }, actor: { acct: 'admin' }, state: 'open', id: '2', content: 'This is a report', statuses: [] }, - { created_at: '2019-05-20T22:45:33.000Z', account: { acct: 'alice', display_name: 'Alice Pool' }, actor: { acct: 'admin2' }, state: 'resolved', id: '1', content: 'Please block this user', statuses: [] }, - { created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys' }, actor: { acct: 'admin' }, state: 'closed', id: '3', content: '', statuses: [] }, - { created_at: '2019-05-21T21:35:33.000Z', account: { acct: 'benj', display_name: 'Benjamin Fame' }, actor: { acct: 'admin' }, state: 'open', id: '5', content: 'This is a report', statuses: [] }, - { created_at: '2019-05-20T22:45:33.000Z', account: { acct: 'alice', display_name: 'Alice Pool' }, actor: { acct: 'admin2' }, state: 'resolved', id: '7', content: 'Please block this user', statuses: [ + { created_at: '2019-05-21T21:35:33.000Z', account: { acct: 'benj', display_name: 'Benjamin Fame', tags: [] }, actor: { acct: 'admin' }, state: 'open', id: '2', content: 'This is a report', statuses: [] }, + { created_at: '2019-05-20T22:45:33.000Z', account: { acct: 'alice', display_name: 'Alice Pool', tags: [] }, actor: { acct: 'admin2' }, state: 'resolved', id: '1', content: 'Please block this user', statuses: [] }, + { created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys', tags: [] }, actor: { acct: 'admin' }, state: 'closed', id: '3', content: '', statuses: [] }, + { created_at: '2019-05-21T21:35:33.000Z', account: { acct: 'benj', display_name: 'Benjamin Fame', tags: [] }, actor: { acct: 'admin' }, state: 'open', id: '5', content: 'This is a report', statuses: [] }, + { created_at: '2019-05-20T22:45:33.000Z', account: { acct: 'alice', display_name: 'Alice Pool', tags: [] }, actor: { acct: 'admin2' }, state: 'resolved', id: '7', content: 'Please block this user', statuses: [ { account: { display_name: 'Alice Pool', avatar: '' }, visibility: 'public', sensitive: false, id: '11', content: 'Hey!', url: '', created_at: '2019-05-10T21:35:33.000Z' }, { account: { display_name: 'Alice Pool', avatar: '' }, visibility: 'unlisted', sensitive: true, id: '10', content: 'Bye!', url: '', created_at: '2019-05-10T21:00:33.000Z' } ] }, - { created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys' }, actor: { acct: 'admin' }, state: 'closed', id: '6', content: '', statuses: [] }, - { created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys' }, actor: { acct: 'admin' }, state: 'closed', id: '4', content: '', statuses: [] } + { created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys', tags: [] }, actor: { acct: 'admin' }, state: 'closed', id: '6', content: '', statuses: [] }, + { created_at: '2019-05-18T13:01:33.000Z', account: { acct: 'nick', display_name: 'Nick Keys', tags: [] }, actor: { acct: 'admin' }, state: 'closed', id: '4', content: '', statuses: [] } ] export async function fetchReports(limit, max_id, authHost, token) { diff --git a/src/api/users.js b/src/api/users.js index a751302a..dd75045f 100644 --- a/src/api/users.js +++ b/src/api/users.js @@ -39,6 +39,15 @@ export async function deleteUser(nickname, authHost, token) { }) } +export async function fetchUser(id, authHost, token) { + return await request({ + baseURL: baseName(authHost), + url: `/api/pleroma/admin/users/${id}`, + method: 'get', + headers: authHeaders(token) + }) +} + export async function fetchUsers(filters, authHost, token, page = 1) { return await request({ baseURL: baseName(authHost), @@ -86,4 +95,13 @@ export async function untagUser(nicknames, tags, authHost, token) { }) } +export async function fetchUserStatuses(id, authHost, godmode, token) { + return await request({ + baseURL: baseName(authHost), + url: `/api/pleroma/admin/users/${id}/statuses?godmode=${godmode}`, + 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 0897740f..b8cfa4c6 100644 --- a/src/lang/en.js +++ b/src/lang/en.js @@ -221,7 +221,16 @@ export default { emptyPasswordError: 'Please input the password', emptyNicknameError: 'Please input the username', invalidNicknameError: 'Username can include "a-z", "A-Z" and "0-9" characters' - + }, + userProfile: { + tags: 'Tags', + moderator: 'Moderator', + admin: 'Admin', + local: 'Local', + nickname: 'Nickname', + deactivated: 'Deactivated', + recentStatuses: 'Recent Statues', + showPrivateStatuses: 'Show private statuses' }, usersFilter: { inputPlaceholder: 'Select filter', @@ -245,8 +254,9 @@ export default { deleteCompleted: 'Delete comleted', deleteCanceled: 'Delete canceled', noNotes: 'No notes to display', - changeState: 'Change state', + changeState: 'Change report state', changeScope: 'Change scope', + moderateUser: 'Moderate user', resolve: 'Resolve', reopen: 'Reopen', close: 'Close', diff --git a/src/router/index.js b/src/router/index.js index 98f9e414..77bb9758 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -76,5 +76,17 @@ export const asyncRouterMap = [ } ] }, + { + path: '/users/:id', + component: Layout, + children: [ + { + path: '', + name: 'UsersShow', + component: () => import('@/views/users/show') + } + ], + hidden: true + }, { path: '*', redirect: '/404', hidden: true } ] diff --git a/src/store/index.js b/src/store/index.js index 119c4c97..84e93f94 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -6,6 +6,7 @@ import permission from './modules/permission' import reports from './modules/reports' import tagsView from './modules/tagsView' import user from './modules/user' +import userProfile from './modules/userProfile' import users from './modules/users' import getters from './getters' @@ -19,6 +20,7 @@ const store = new Vuex.Store({ reports, tagsView, user, + userProfile, users }, getters diff --git a/src/store/modules/userProfile.js b/src/store/modules/userProfile.js new file mode 100644 index 00000000..2dd656e6 --- /dev/null +++ b/src/store/modules/userProfile.js @@ -0,0 +1,36 @@ +import { fetchUser, fetchUserStatuses } from '@/api/users' + +const userProfile = { + state: { + user: {}, + loading: true, + statuses: [] + }, + mutations: { + SET_USER: (state, user) => { + state.user = user + }, + SET_LOADING: (state, status) => { + state.loading = status + }, + SET_STATUSES: (state, statuses) => { + state.statuses = statuses + } + }, + actions: { + async FetchData({ commit, getters }, { id, godmode }) { + commit('SET_LOADING', true) + + const [userResponse, statusesResponse] = await Promise.all([ + fetchUser(id, getters.authHost, getters.token), + fetchUserStatuses(id, getters.authHost, godmode, getters.token) + ]) + + commit('SET_USER', userResponse.data) + commit('SET_STATUSES', statusesResponse.data) + commit('SET_LOADING', false) + } + } +} + +export default userProfile diff --git a/src/store/modules/users.js b/src/store/modules/users.js index 80fb0c22..94715954 100644 --- a/src/store/modules/users.js +++ b/src/store/modules/users.js @@ -48,6 +48,9 @@ const users = { }, SET_USERS_FILTERS: (state, filters) => { state.filters = filters + }, + SET_USER_PROFILE: (state, user) => { + state.userProfile = user } }, actions: { diff --git a/src/views/reports/components/ReportsFilter.vue b/src/views/reports/components/ReportsFilter.vue index 263d2eca..40c23216 100644 --- a/src/views/reports/components/ReportsFilter.vue +++ b/src/views/reports/components/ReportsFilter.vue @@ -4,20 +4,42 @@ :placeholder="$t('reportsFilter.inputPlaceholder')" clearable class="select-field" + value-key="value" @change="toggleFilters"> - {{ $t('reportsFilter.open') }} - {{ $t('reportsFilter.closed') }} - {{ $t('reportsFilter.resolved') }} + {{ item.label }} + + diff --git a/yarn.lock b/yarn.lock index fc08d937..c687a794 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3446,10 +3446,10 @@ elegant-spinner@^1.0.1: resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4= -element-ui@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/element-ui/-/element-ui-2.7.0.tgz#6bfcdfa5c75bfc4cda835186f2a1f98b93cd5d14" - integrity sha512-FalWzOmT/K4w4C/8tw2kGvzzQnRJ5MqEvSL5rEKNa081PFGIcUS9exyVpYrNPKF8ua/W6qaqrXPC6DQ8sNcmOQ== +element-ui@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/element-ui/-/element-ui-2.10.0.tgz#e6129f6b6d6ffe0dbad125a4a8d17d447a5f639c" + integrity sha512-uthsnJ1CIdQvLWphr67uwFSfSYoRBjxFcEhXhy+2/EwKNsqO7MRN+mYqroNLz5WJuLqVy1aOpJ8Lv4B32qKthQ== dependencies: async-validator "~1.8.1" babel-helper-vue-jsx-merge-props "^2.0.0"