From b490ade544d83339e84ee00c98c04f94791f03cc Mon Sep 17 00:00:00 2001 From: Sol Fisher Romanoff Date: Fri, 21 Oct 2022 17:56:32 +0300 Subject: [PATCH] Add API endpoints for reports --- src/modules/reports.js | 62 +++++++++++++++++- src/services/api/api.service.js | 64 ++++++++++++++++++- .../entity_normalizer.service.js | 18 ++++++ 3 files changed, 139 insertions(+), 5 deletions(-) diff --git a/src/modules/reports.js b/src/modules/reports.js index fea83e5f..6048d719 100644 --- a/src/modules/reports.js +++ b/src/modules/reports.js @@ -1,11 +1,17 @@ -import filter from 'lodash/filter' +import { filter, find, forEach, remove } from 'lodash' + +const getReport = (state, id) => find(state.reports, { id }) +const updateReport = (state, { report, param, value }) => { + getReport(state, report.id)[param] = value +} const reports = { state: { userId: null, statuses: [], preTickedIds: [], - modalActivated: false + modalActivated: false, + reports: [] }, mutations: { openUserReportingModal (state, { userId, statuses, preTickedIds }) { @@ -16,6 +22,38 @@ const reports = { }, closeUserReportingModal (state) { state.modalActivated = false + }, + setReport (state, { report }) { + let existing = getReport(state, report.id) + if (existing) { + existing = report + } else { + state.reports.push(report) + } + }, + updateReportStates (state, { reports }) { + forEach(reports, (report) => { + updateReport(state, { report, param: 'state', value: report.state }) + }) + }, + addNoteToReport (state, { id, note, user }) { + // akkoma doesn't return the note from this API endpoint, and there's no + // good way to get it. the note data is spoofed in the frontend until + // reload. + // definitely worth adding this to the backend at some point + const report = getReport(state, id) + const date = new Date() + + report.notes.push({ + content: note, + user, + created_at: date.toISOString(), + id: date.getTime() + }) + }, + deleteNoteFromReport (state, { id, note }) { + const report = getReport(state, id) + remove(report.notes, { id: note }) } }, actions: { @@ -31,6 +69,26 @@ const reports = { }, closeUserReportingModal ({ commit }) { commit('closeUserReportingModal') + }, + getReports ({ rootState, commit }, params) { + return rootState.api.backendInteractor.getReports(params) + .then(reports => forEach(reports, report => commit('setReport', { report }))) + }, + updateReportStates ({ rootState, commit }, { reports }) { + commit('updateReportStates', { reports }) + return rootState.api.backendInteractor.updateReportStates({ reports }) + }, + getReport ({ rootState, commit }, { id }) { + return rootState.api.backendInteractor.getReport({ id }) + .then(report => commit('setReport', { report })) + }, + addNoteToReport ({ rootState, commit }, { id, note }) { + commit('addNoteToReport', { id, note, user: rootState.users.currentUser }) + return rootState.api.backendInteractor.addNoteToReport({ id, note }) + }, + deleteNoteFromReport ({ rootState, commit }, { id, note }) { + commit('deleteNoteFromReport', { id, note }) + return rootState.api.backendInteractor.deleteNoteFromReport({ id, note }) } } } diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 0cacf251..4e3e1ced 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -1,5 +1,5 @@ import { each, map, concat, last, get } from 'lodash' -import { parseStatus, parseSource, parseUser, parseNotification, parseAttachment, parseLinkHeaderPagination } from '../entity_normalizer/entity_normalizer.service.js' +import { parseStatus, parseSource, parseUser, parseNotification, parseReport, parseAttachment, parseLinkHeaderPagination } from '../entity_normalizer/entity_normalizer.service.js' import { RegistrationError, StatusCodeError } from '../errors/errors' /* eslint-env browser */ @@ -19,6 +19,9 @@ const ADMIN_USERS_URL = '/api/pleroma/admin/users' const SUGGESTIONS_URL = '/api/v1/suggestions' const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings' const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read' +const ADMIN_REPORTS_URL = '/api/v1/pleroma/admin/reports' +const ADMIN_REPORT_NOTES_URL = id => `/api/v1/pleroma/admin/reports/${id}/notes` +const ADMIN_REPORT_NOTE_URL = (report, note) => `/api/v1/pleroma/admin/reports/${report}/notes/${note}` const MFA_SETTINGS_URL = '/api/pleroma/accounts/mfa' const MFA_BACKUP_CODES_URL = '/api/pleroma/accounts/mfa/backup_codes' @@ -342,7 +345,7 @@ const fetchUserRelationship = ({ id, credentials }) => { return new Promise((resolve, reject) => response.json() .then((json) => { if (!response.ok) { - return reject(new StatusCodeError(response.status, json, { url }, response)) + return reject(new StatusCodeError(400, json, { url }, response)) } return resolve(json) })) @@ -635,6 +638,57 @@ const deleteUser = ({ credentials, user }) => { }) } +const getReports = ({ state, limit, page, pageSize, credentials }) => { + let url = ADMIN_REPORTS_URL + const args = [ + state && `state=${state}`, + limit && `limit=${limit}`, + page && `page=${page}`, + pageSize && `page_size=${pageSize}` + ].filter(_ => _).join('&') + + url = url + (args ? '?' + args : '') + return fetch(url, { headers: authHeaders(credentials) }) + .then((data) => data.json()) + .then((data) => data.reports.map(parseReport)) +} + +const updateReportStates = ({ credentials, reports }) => { + // reports syntax: [{ id: int, state: string }...] + const updates = { + reports: reports.map(report => { + return { + id: report.id.toString(), + state: report.state + } + }) + } + + return promisedRequest({ + url: ADMIN_REPORTS_URL, + method: 'PATCH', + payload: updates, + credentials + }) +} + +const addNoteToReport = ({ id, note, credentials }) => { + return promisedRequest({ + url: ADMIN_REPORT_NOTES_URL(id), + method: 'POST', + payload: { content: note }, + credentials + }) +} + +const deleteNoteFromReport = ({ report, note, credentials }) => { + return promisedRequest({ + url: ADMIN_REPORT_NOTE_URL(report, note), + method: 'DELETE', + credentials + }) +} + const fetchTimeline = ({ timeline, credentials, @@ -1726,7 +1780,11 @@ const apiService = { getSettingsProfile, saveSettingsProfile, listSettingsProfiles, - deleteSettingsProfile + deleteSettingsProfile, + getReports, + updateReportStates, + addNoteToReport, + deleteNoteFromReport } export default apiService diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index b1aded33..a2fa741f 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -429,6 +429,24 @@ export const parseNotification = (data) => { return output } +export const parseReport = (data) => { + const report = {} + + report.account = parseUser(data.account) + report.actor = parseUser(data.actor) + report.statuses = data.statuses.map(parseStatus) + report.notes = data.notes.map(note => { + note.user = parseUser(note.user) + return note + }) + report.state = data.state + report.content = data.content + report.created_at = data.created_at + report.id = data.id + + return report +} + const isNsfw = (status) => { const nsfwRegex = /#nsfw/i return (status.tags || []).includes('nsfw') || !!(status.text || '').match(nsfwRegex)