some initial API refactoring

This commit is contained in:
Henry Jameson 2026-06-13 03:10:00 +03:00
commit 4a59c42395
20 changed files with 1368 additions and 1567 deletions

View file

@ -1,9 +1,11 @@
import EmojiPicker from 'src/components/emoji_picker/emoji_picker.vue' import EmojiPicker from 'src/components/emoji_picker/emoji_picker.vue'
import apiService from '../../services/api/api.service'
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js' import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js'
import { useCredentialsStore } from 'src/stores/credentials.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { fetchBookmarkFolders } from 'src/services/api/api.service.js'
const BookmarkFolderEdit = { const BookmarkFolderEdit = {
data() { data() {
return { return {
@ -22,8 +24,10 @@ const BookmarkFolderEdit = {
}, },
created() { created() {
if (!this.id) return if (!this.id) return
const credentials = this.$store.state.users.currentUser.credentials
apiService.fetchBookmarkFolders({ credentials }).then((folders) => { fetchBookmarkFolders({
credentials: useCredentialsStore().current,
}).then((folders) => {
const folder = folders.find((folder) => folder.id === this.id) const folder = folders.find((folder) => folder.id === this.id)
if (!folder) return if (!folder) return

View file

@ -1,4 +1,4 @@
import apiService from '../services/api/api.service.js' import { markNotificationsAsSeen } from '../services/api/api.service.js'
import { import {
closeAllDesktopNotifications, closeAllDesktopNotifications,
closeDesktopNotification, closeDesktopNotification,
@ -154,26 +154,22 @@ export const notifications = {
}, },
markNotificationsAsSeen({ rootState, state, commit }) { markNotificationsAsSeen({ rootState, state, commit }) {
commit('markNotificationsAsSeen') commit('markNotificationsAsSeen')
apiService markNotificationsAsSeen({
.markNotificationsAsSeen({ id: state.maxId,
id: state.maxId, credentials: rootState.users.currentUser.credentials,
credentials: rootState.users.currentUser.credentials, }).then(() => {
}) closeAllDesktopNotifications(rootState)
.then(() => { })
closeAllDesktopNotifications(rootState)
})
}, },
markSingleNotificationAsSeen({ rootState, commit }, { id }) { markSingleNotificationAsSeen({ rootState, commit }, { id }) {
commit('markSingleNotificationAsSeen', { id }) commit('markSingleNotificationAsSeen', { id })
apiService markNotificationsAsSeen({
.markNotificationsAsSeen({ single: true,
single: true, id,
id, credentials: rootState.users.currentUser.credentials,
credentials: rootState.users.currentUser.credentials, }).then(() => {
}) closeDesktopNotification(rootState, { id })
.then(() => { })
closeDesktopNotification(rootState, { id })
})
}, },
dismissNotificationLocal({ commit }, { id }) { dismissNotificationLocal({ commit }, { id }) {
commit('dismissNotification', { id }) commit('dismissNotification', { id })

View file

@ -13,7 +13,12 @@ import {
slice, slice,
} from 'lodash' } from 'lodash'
import apiService from '../services/api/api.service.js' import {
deleteStatus,
fetchScrobbles,
fetchStatusHistory,
fetchStatusSource,
} from '../services/api/api.service.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
@ -131,8 +136,7 @@ const getLatestScrobble = (state, user) => {
state.scrobblesNextFetch[user.id] = Date.now() + 24 * 60 * 60 * 1000 state.scrobblesNextFetch[user.id] = Date.now() + 24 * 60 * 60 * 1000
if (!scrobblesSupport) return if (!scrobblesSupport) return
apiService fetchScrobbles({ accountId: user.id })
.fetchScrobbles({ accountId: user.id })
.then((scrobbles) => { .then((scrobbles) => {
if (scrobbles?.error) { if (scrobbles?.error) {
useInstanceCapabilitiesStore().set('pleromaScrobblesAvailable', false) useInstanceCapabilitiesStore().set('pleromaScrobblesAvailable', false)
@ -607,20 +611,19 @@ const statuses = {
.then((status) => dispatch('addNewStatuses', { statuses: [status] })) .then((status) => dispatch('addNewStatuses', { statuses: [status] }))
}, },
fetchStatusSource({ rootState }, status) { fetchStatusSource({ rootState }, status) {
return apiService.fetchStatusSource({ return fetchStatusSource({
id: status.id, id: status.id,
credentials: rootState.users.currentUser.credentials, credentials: rootState.users.currentUser.credentials,
}) })
}, },
fetchStatusHistory(_, status) { fetchStatusHistory(_, status) {
return apiService.fetchStatusHistory({ status }) return fetchStatusHistory({ status })
}, },
deleteStatus({ rootState, commit }, status) { deleteStatus({ rootState, commit }, status) {
apiService deleteStatus({
.deleteStatus({ id: status.id,
id: status.id, credentials: rootState.users.currentUser.credentials,
credentials: rootState.users.currentUser.credentials, })
})
.then(() => { .then(() => {
commit('setDeleted', { status }) commit('setDeleted', { status })
}) })

View file

@ -9,7 +9,7 @@ import {
uniq, uniq,
} from 'lodash' } from 'lodash'
import apiService from '../services/api/api.service.js' import { register } from '../services/api/api.service.js'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import oauthApi from '../services/new_api/oauth.js' import oauthApi from '../services/new_api/oauth.js'
import { import {
@ -624,7 +624,7 @@ const users = {
try { try {
const token = await oauthStore.ensureAppToken() const token = await oauthStore.ensureAppToken()
const data = await apiService.register({ const data = await register({
credentials: token, credentials: token,
params: { ...userInfo }, params: { ...userInfo },
}) })

515
src/services/api/admin.js Normal file
View file

@ -0,0 +1,515 @@
import { promisedRequest } from './helpers.js'
import { RegistrationError, StatusCodeError } from 'src/services/errors/errors'
const REPORTS = '/api/v1/pleroma/admin/reports'
const CONFIG_URL = '/api/v1/pleroma/admin/config'
const DESCRIPTIONS_URL = '/api/v1/pleroma/admin/config/descriptions'
const ANNOUNCEMENTS_URL = (id) => '/api/v1/pleroma/admin/announcements/${id}'
const FRONTENDS_URL = '/api/v1/pleroma/admin/frontends'
const FRONTENDS_INSTALL_URL = '/api/v1/pleroma/admin/frontends/install'
const USERS_URL = (nickname) => `/api/v1/pleroma/admin/users/${nickname}`
const USERS_URL_LIST = ({
page,
pageSize,
filters = {},
query = '',
name = '',
email = '',
}) => {
const {
local = false,
external = false,
active = false,
needApproval = false,
unconfirmed = false,
deactivated = false,
isAdmin = true,
isModerator = true,
} = filters
const filters_str = [
local && 'local',
external && 'external',
active && 'active',
needApproval && 'need_approval',
unconfirmed && 'unconfirmed',
deactivated && 'deactivated',
isAdmin && 'is_admin',
isModerator && 'is_moderator',
]
.filter((x) => x)
.join(',')
return `/api/v1/pleroma/admin/users?page=${page}&page_size=${pageSize}&filters=${filters_str}&query=${query}&name=${name}&email=${email}`
}
const TAG_USER_URL = '/api/pleroma/admin/users/tag'
const PERMISSION_GROUP_URL = (right) =>
`/api/pleroma/admin/users/permission_group/${right}`
const ACTIVATE_USERS_URL = '/api/pleroma/admin/users/activate'
const DEACTIVATE_USERS_URL = '/api/pleroma/admin/users/deactivate'
const SUGGEST_USERS_URL = '/api/pleroma/admin/users/suggest'
const UNSUGGEST_USERS_URL = '/api/pleroma/admin/users/unsuggest'
const APPROVE_USERS_URL = '/api/v1/pleroma/admin/users/approve'
const CONFIRM_USERS_URL = '/api/v1/pleroma/admin/users/confirm_email'
const RESEND_CONFIRMATION_EMAIL_URL =
'/api/v1/pleroma/admin/users/resend_confirmation_email'
const LIST_STATUSES_URL = ({ id, page, pageSize, godmode, withReblogs }) =>
`/api/v1/pleroma/admin/users/${id}/statuses?page_size=${pageSize}&page=${page}&godmode=${godmode}&with_reblogs=${withReblogs}`
const CHANGE_STATUS_SCOPE_URL = (id) => `/api/v1/pleroma/admin/statuses/${id}`
const REQUIRE_PASSWORD_CHANGE_URL =
'/api/v1/pleroma/admin/users/force_password_reset'
const DISABLE_MFA_URL = '/api/v1/pleroma/admin/users/disable_mfa'
const EMOJI_RELOAD_URL = '/api/pleroma/admin/reload_emoji'
const EMOJI_IMPORT_FS_URL = '/api/pleroma/emoji/packs/import'
const EMOJI_PACKS_URL = (page, pageSize) =>
`/api/v1/pleroma/emoji/packs?page=${page}&page_size=${pageSize}`
const EMOJI_PACK_URL = (name) => `/api/v1/pleroma/emoji/pack?name=${name}`
const EMOJI_PACKS_DL_REMOTE_URL = '/api/v1/pleroma/emoji/packs/download'
const EMOJI_PACKS_DL_REMOTE_ZIP_URL = '/api/v1/pleroma/emoji/packs/download_zip'
const EMOJI_PACKS_LS_REMOTE_URL = (url, page, pageSize) =>
`/api/v1/pleroma/emoji/packs/remote?url=${url}&page=${page}&page_size=${pageSize}`
const EMOJI_UPDATE_FILE_URL = (name) =>
`/api/v1/pleroma/emoji/packs/files?name=${name}`
//
export const setUsersTags = ({
tags,
credentials,
value,
screen_names: nicknames,
}) =>
promisedRequest({
url: TAG_USER_URL,
method: value ? 'PUT' : 'DELETE',
credentials,
payload: {
nicknames,
tags,
},
})
export const setUsersRight = ({
right,
credentials,
value,
screen_names: nicknames,
}) =>
promisedRequest({
url: PERMISSION_GROUP_URL(right),
method: value ? 'POST' : 'DELETE',
credentials,
payload: {
nicknames,
},
})
export const setUsersActivationStatus = ({
credentials,
screen_names: nicknames,
value,
}) =>
promisedRequest({
url: value ? ACTIVATE_USERS_URL : DEACTIVATE_USERS_URL,
method: 'PATCH',
credentials,
payload: {
nicknames,
},
}).then((response) => response.users)
export const setUsersApprovalStatus = ({
credentials,
screen_names: nicknames,
}) =>
promisedRequest({
url: APPROVE_USERS_URL,
method: 'PATCH',
credentials,
payload: {
nicknames,
},
}).then((response) => response.users)
export const setUsersConfirmationStatus = ({
credentials,
screen_names: nicknames,
}) =>
promisedRequest({
url: CONFIRM_USERS_URL,
method: 'PATCH',
credentials,
payload: {
nicknames,
},
}).then((response) => response.users)
export const setUsersSuggestionStatus = ({
credentials,
screen_names: nicknames,
value,
}) =>
promisedRequest({
url: value ? SUGGEST_USERS_URL : UNSUGGEST_USERS_URL,
method: 'PATCH',
credentials,
payload: {
nicknames,
},
}).then((response) => response.users)
export const getUserData = ({ credentials, screen_name: nickname }) =>
promisedRequest({
url: USERS_URL(nickname),
method: 'GET',
credentials,
})
export const deleteAccounts = ({ credentials, screen_names: nicknames }) =>
promisedRequest({
url: USERS_URL(),
method: 'DELETE',
credentials,
payload: {
nicknames,
},
})
export const getAnnouncements = ({ credentials }) =>
promisedRequest({ url: ANNOUNCEMENTS_URL(), credentials })
// the reported list is hardly useful because standards are for dating i guess,
// so make sure to fetchIfMissing right afterward using this call
export const listUsers = ({ opts, credentials }) =>
promisedRequest({
url: USERS_URL_LIST(opts),
credentials,
method: 'GET',
})
export const resendConfirmationEmail = ({
screen_names: nicknames,
credentials,
}) =>
promisedRequest({
url: RESEND_CONFIRMATION_EMAIL_URL,
credentials,
method: 'PATCH',
payload: {
nicknames,
},
})
export const requirePasswordChange = ({
screen_names: nicknames,
credentials,
}) =>
promisedRequest({
url: REQUIRE_PASSWORD_CHANGE_URL,
credentials,
method: 'PATCH',
payload: {
nicknames,
},
})
export const disableMFA = ({ screen_name: nickname, credentials }) =>
promisedRequest({
url: DISABLE_MFA_URL,
credentials,
method: 'PUT',
payload: {
nickname,
},
})
export const listStatuses = ({ opts, credentials }) =>
promisedRequest({
url: LIST_STATUSES_URL(opts),
credentials,
method: 'GET',
})
export const changeStatusScope = ({
opts: { id, sensitive, visibility },
credentials,
}) => {
var payload = {}
if (typeof sensitive !== 'undefined') {
payload['sensitive'] = sensitive
}
if (typeof visibility !== 'undefined') {
payload['visibility'] = visibility
}
return promisedRequest({
url: CHANGE_STATUS_SCOPE_URL(id),
credentials,
method: 'PUT',
payload,
})
}
export const announcementToPayload = ({
content,
startsAt,
endsAt,
allDay,
}) => {
const payload = { content }
if (typeof startsAt !== 'undefined') {
payload.starts_at = startsAt ? new Date(startsAt).toISOString() : null
}
if (typeof endsAt !== 'undefined') {
payload.ends_at = endsAt ? new Date(endsAt).toISOString() : null
}
if (typeof allDay !== 'undefined') {
payload.all_day = allDay
}
return payload
}
export const postAnnouncement = ({
credentials,
content,
startsAt,
endsAt,
allDay,
}) =>
promisedRequest({
url: ANNOUNCEMENTS_URL(),
credentials,
method: 'POST',
payload: announcementToPayload({ content, startsAt, endsAt, allDay }),
})
export const editAnnouncement = ({
id,
credentials,
content,
startsAt,
endsAt,
allDay,
}) =>
promisedRequest({
url: ANNOUNCEMENTS_URL(id),
credentials,
method: 'PATCH',
payload: announcementToPayload({ content, startsAt, endsAt, allDay }),
})
export const deleteAnnouncement = ({ id, credentials }) =>
promisedRequest({
url: ANNOUNCEMENTS_URL(id),
credentials,
method: 'DELETE',
})
export const setReportState = ({ id, state, credentials }) => {
// TODO: Can't use promisedRequest because on OK this does not return json
// See https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1322
return promisedRequest({
url: REPORTS,
credentials,
method: 'PATCH',
payload: {
reports: [
{
id,
state,
},
],
},
})
.then((data) => {
if (data.status >= 500) {
throw Error(data.statusText)
} else if (data.status >= 400) {
return data.json()
}
return data
})
.then((data) => {
if (data.errors) {
throw Error(data.errors[0].message)
}
})
}
export const getInstanceDBConfig = ({ credentials }) =>
get({
url: CONFIG_URL,
credentials,
})
export const getInstanceConfigDescriptions = ({ credentials }) =>
get({
url: DESCRIPTIONS_URL,
credentials,
})
export const getAvailableFrontends = ({ credentials }) =>
promisedRequest({
url: FRONTENDS_URL,
credentials,
})
export const pushInstanceDBConfig = ({ credentials, payload }) =>
promisedRequest({
url: CONFIG_URL,
method: 'POST',
credentials,
payload,
})
export const installFrontend = ({ credentials, payload }) =>
promisedRequest({
url: FRONTENDS_INSTALL_URL,
credentials,
method: 'POST',
payload,
})
// Emoji packs
export const deleteEmojiPack = ({ name }) =>
promisedRequest({
url: EMOJI_PACK_URL(name),
method: 'DELETE',
})
export const reloadEmoji = ({ credentials }) =>
promisedRequest({
url: EMOJI_RELOAD_URL,
method: 'POST',
credentials,
})
export const importEmojiFromFS = ({ credentials }) =>
promisedRequest({
url: EMOJI_IMPORT_FS_URL,
credentials,
})
export const createEmojiPack = ({ name, credentials }) =>
promisedRequest({
url: EMOJI_PACK_URL(name),
method: 'POST',
credentials,
})
export const listEmojiPacks = ({ page, pageSize, credentials }) =>
promisedRequest({
url: EMOJI_PACKS_URL(page, pageSize),
})
export const listRemoteEmojiPacks = ({
instance,
page,
pageSize,
credentials,
}) => {
if (!instance.startsWith('http')) {
instance = 'https://' + instance
}
return promisedRequest({
url: EMOJI_PACKS_LS_REMOTE_URL(instance, page, pageSize),
credentials,
})
}
export const downloadRemoteEmojiPack = ({
instance,
packName,
as,
credentials,
}) =>
promisedRequest({
url: EMOJI_PACKS_DL_REMOTE_URL,
credentials,
method: 'POST',
payload: {
url: instance,
name: packName,
as,
},
})
export const downloadRemoteEmojiPackZIP = ({
url,
packName,
file,
credentials,
}) => {
const data = new FormData()
if (file) data.set('file', file)
if (url) data.set('url', url)
data.set('name', packName)
return promisedRequest({
url: EMOJI_PACKS_DL_REMOTE_ZIP_URL,
method: 'POST',
payload: data,
})
}
export const saveEmojiPackMetadata = ({ name, newData, credentials }) =>
promisedRequest({
url: EMOJI_PACK_URL(name),
credentials,
method: 'PATCH',
payload: { metadata: newData },
})
export const addNewEmojiFile = ({ packName, file, shortcode, filename }) => {
const data = new FormData()
if (filename.trim() !== '') {
data.set('filename', filename)
}
if (shortcode.trim() !== '') {
data.set('shortcode', shortcode)
}
data.set('file', file)
return promisedRequest({
url: EMOJI_UPDATE_FILE_URL(packName),
method: 'POST',
payload: data,
})
}
export const updateEmojiFile = ({
packName,
shortcode,
newShortcode,
newFilename,
credentials,
force,
}) =>
promisedRequest({
url: EMOJI_UPDATE_FILE_URL(packName),
credentials,
method: 'PATCH',
payload: {
shortcode,
new_shortcode: newShortcode,
new_filename: newFilename,
force,
},
})
export const deleteEmojiFile = ({ packName, shortcode }) =>
promisedRequest({
url: `${EMOJI_UPDATE_FILE_URL(packName)}&shortcode=${shortcode}`,
method: 'DELETE',
})

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,87 @@
import { RegistrationError, StatusCodeError } from 'src/services/errors/errors'
export const promisedRequest = ({
method,
url,
params,
payload,
formData,
credentials,
headers = {},
}) => {
const options = {
method,
credentials: 'same-origin',
headers: {
Accept: 'application/json',
...headers,
},
}
if (!formData) {
options.headers['Content-Type'] = 'application/json'
}
if (params) {
url +=
'?' +
Object.entries(params)
.map(
([key, value]) =>
encodeURIComponent(key) + '=' + encodeURIComponent(value),
)
.join('&')
}
if (formData || payload) {
options.body = formData || JSON.stringify(payload)
}
if (credentials) {
options.headers = {
...options.headers,
...authHeaders(credentials),
}
}
return fetch(url, options).then((response) => {
return new Promise((resolve, reject) => {
// 204 is "No content", which fails to parse json (as you'd might think)
if (response.ok && response.status === 204) resolve()
return response
.json()
.then((json) => {
if (!response.ok) {
return reject(
new StatusCodeError(
response.status,
json,
{ url, options },
response,
),
)
}
json._response = response
return resolve(json)
})
.catch((error) => {
return reject(
new StatusCodeError(
response.status,
error,
{ url, options },
response,
),
)
})
})
})
}
const authHeaders = (accessToken) => {
if (accessToken) {
return { Authorization: `Bearer ${accessToken}` }
} else {
return {}
}
}

View file

@ -1,10 +1,7 @@
import bookmarkFoldersFetcher from '../../services/bookmark_folders_fetcher/bookmark_folders_fetcher.service.js' import bookmarkFoldersFetcher from '../../services/bookmark_folders_fetcher/bookmark_folders_fetcher.service.js'
import followRequestFetcher from '../../services/follow_request_fetcher/follow_request_fetcher.service' import followRequestFetcher from '../../services/follow_request_fetcher/follow_request_fetcher.service'
import listsFetcher from '../../services/lists_fetcher/lists_fetcher.service.js' import listsFetcher from '../../services/lists_fetcher/lists_fetcher.service.js'
import apiService, { import * as apiService from '../api/api.service.js'
getMastodonSocketURI,
ProcessedWS,
} from '../api/api.service.js'
import notificationsFetcher from '../notifications_fetcher/notifications_fetcher.service.js' import notificationsFetcher from '../notifications_fetcher/notifications_fetcher.service.js'
import timelineFetcher from '../timeline_fetcher/timeline_fetcher.service.js' import timelineFetcher from '../timeline_fetcher/timeline_fetcher.service.js'
@ -58,8 +55,8 @@ const backendInteractorService = (credentials) => ({
startUserSocket({ store }) { startUserSocket({ store }) {
const serv = useInstanceStore().server.replace('http', 'ws') const serv = useInstanceStore().server.replace('http', 'ws')
const url = getMastodonSocketURI({}, serv) const url = apiService.getMastodonSocketURI({}, serv)
return ProcessedWS({ url, id: 'Unified', credentials }) return apiService.ProcessedWS({ url, id: 'Unified', credentials })
}, },
...Object.entries(apiService).reduce((acc, [key, func]) => { ...Object.entries(apiService).reduce((acc, [key, func]) => {

View file

@ -1,11 +1,10 @@
import apiService from '../api/api.service.js' import { fetchBookmarkFolders } from '../api/api.service.js'
import { promiseInterval } from '../promise_interval/promise_interval.js' import { promiseInterval } from '../promise_interval/promise_interval.js'
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js' import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js'
const fetchAndUpdate = ({ credentials }) => { const fetchAndUpdate = ({ credentials }) => {
return apiService return fetchBookmarkFolders({ credentials })
.fetchBookmarkFolders({ credentials })
.then( .then(
(bookmarkFolders) => { (bookmarkFolders) => {
useBookmarkFoldersStore().setBookmarkFolders(bookmarkFolders) useBookmarkFoldersStore().setBookmarkFolders(bookmarkFolders)

View file

@ -1,9 +1,8 @@
import apiService from '../api/api.service.js' import { fetchFollowRequests } from '../api/api.service.js'
import { promiseInterval } from '../promise_interval/promise_interval.js' import { promiseInterval } from '../promise_interval/promise_interval.js'
const fetchAndUpdate = ({ store, credentials }) => { const fetchAndUpdate = ({ store, credentials }) => {
return apiService return fetchFollowRequests({ credentials })
.fetchFollowRequests({ credentials })
.then( .then(
(requests) => { (requests) => {
store.commit('setFollowRequests', requests) store.commit('setFollowRequests', requests)

View file

@ -1,11 +1,10 @@
import apiService from '../api/api.service.js' import { fetchLists } from '../api/api.service.js'
import { promiseInterval } from '../promise_interval/promise_interval.js' import { promiseInterval } from '../promise_interval/promise_interval.js'
import { useListsStore } from 'src/stores/lists.js' import { useListsStore } from 'src/stores/lists.js'
const fetchAndUpdate = ({ credentials }) => { const fetchAndUpdate = ({ credentials }) => {
return apiService return fetchLists({ credentials })
.fetchLists({ credentials })
.then( .then(
(lists) => { (lists) => {
useListsStore().setLists(lists) useListsStore().setLists(lists)

View file

@ -1,4 +1,4 @@
import apiService from '../api/api.service.js' import { fetchTimeline } from '../api/api.service.js'
import { promiseInterval } from '../promise_interval/promise_interval.js' import { promiseInterval } from '../promise_interval/promise_interval.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
@ -80,8 +80,7 @@ const fetchAndUpdate = ({ store, credentials, older = false, since }) => {
} }
const fetchNotifications = ({ store, args, older }) => { const fetchNotifications = ({ store, args, older }) => {
return apiService return fetchTimeline(args)
.fetchTimeline(args)
.then((response) => { .then((response) => {
if (response.errors) { if (response.errors) {
if ( if (

View file

@ -1,6 +1,11 @@
import { map } from 'lodash' import { map } from 'lodash'
import apiService from '../api/api.service.js' import {
editStatus as apiEditStatus,
postStatus as apiPostStatus,
setMediaDescription as apiSetMediaDescription,
uploadMedia as apiUploadMedia,
} from '../api/api.service.js'
const postStatus = ({ const postStatus = ({
store, store,
@ -18,21 +23,20 @@ const postStatus = ({
}) => { }) => {
const mediaIds = map(media, 'id') const mediaIds = map(media, 'id')
return apiService return apiPostStatus({
.postStatus({ credentials: store.state.users.currentUser.credentials,
credentials: store.state.users.currentUser.credentials, status,
status, spoilerText,
spoilerText, visibility,
visibility, sensitive,
sensitive, mediaIds,
mediaIds, inReplyToStatusId,
inReplyToStatusId, quoteId,
quoteId, contentType,
contentType, poll,
poll, preview,
preview, idempotencyKey,
idempotencyKey, })
})
.then((data) => { .then((data) => {
if (!data.error && !preview) { if (!data.error && !preview) {
store.dispatch('addNewStatuses', { store.dispatch('addNewStatuses', {
@ -63,17 +67,16 @@ const editStatus = ({
}) => { }) => {
const mediaIds = map(media, 'id') const mediaIds = map(media, 'id')
return apiService return editStatus({
.editStatus({ id: statusId,
id: statusId, credentials: store.state.users.currentUser.credentials,
credentials: store.state.users.currentUser.credentials, status,
status, spoilerText,
spoilerText, sensitive,
sensitive, poll,
poll, mediaIds,
mediaIds, contentType,
contentType, })
})
.then((data) => { .then((data) => {
if (!data.error) { if (!data.error) {
store.dispatch('addNewStatuses', { store.dispatch('addNewStatuses', {
@ -95,12 +98,12 @@ const editStatus = ({
const uploadMedia = ({ store, formData }) => { const uploadMedia = ({ store, formData }) => {
const credentials = store.state.users.currentUser.credentials const credentials = store.state.users.currentUser.credentials
return apiService.uploadMedia({ credentials, formData }) return apiUploadMedia({ credentials, formData })
} }
const setMediaDescription = ({ store, id, description }) => { const setMediaDescription = ({ store, id, description }) => {
const credentials = store.state.users.currentUser.credentials const credentials = store.state.users.currentUser.credentials
return apiService.setMediaDescription({ credentials, id, description }) return apiSetMediaDescription({ credentials, id, description })
} }
const statusPosterService = { const statusPosterService = {

View file

@ -1,6 +1,6 @@
import { camelCase } from 'lodash' import { camelCase } from 'lodash'
import apiService from '../api/api.service.js' import { fetchTimeline } from '../api/api.service.js'
import { promiseInterval } from '../promise_interval/promise_interval.js' import { promiseInterval } from '../promise_interval/promise_interval.js'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
@ -75,8 +75,7 @@ const fetchAndUpdate = ({
const numStatusesBeforeFetch = timelineData.statuses.length const numStatusesBeforeFetch = timelineData.statuses.length
return apiService return fetchTimeline(args)
.fetchTimeline(args)
.then((response) => { .then((response) => {
if (response.errors) { if (response.errors) {
if (timeline === 'favorites') { if (timeline === 'favorites') {

View file

@ -1,6 +1,26 @@
import { cloneDeep, differenceWith, flatten, get, isEqual, set } from 'lodash' import { cloneDeep, differenceWith, flatten, get, isEqual, set } from 'lodash'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { useCredentialsStore } from 'src/stores/credentials.js'
import {
changeStatusScope,
deleteAccounts,
disableMFA,
getAvailableFrontends,
getInstanceDBConfig,
getUserData,
listStatuses,
listUsers,
requirePasswordChange,
resendConfirmationEmail,
setUsersActivationStatus,
setUsersApprovalStatus,
setUsersConfirmationStatus,
setUsersRight,
setUsersSuggestionStatus,
setUsersTags,
} from 'src/services/api/admin.js'
import { parseStatus } from 'src/services/entity_normalizer/entity_normalizer.service.js' import { parseStatus } from 'src/services/entity_normalizer/entity_normalizer.service.js'
export const defaultState = { export const defaultState = {
@ -21,7 +41,6 @@ export const newUserFlags = {
export const useAdminSettingsStore = defineStore('adminSettings', { export const useAdminSettingsStore = defineStore('adminSettings', {
state: () => ({ state: () => ({
...cloneDeep(defaultState), ...cloneDeep(defaultState),
backendInteractor: window.vuex.state.api.backendInteractor,
}), }),
actions: { actions: {
// Configuration Stuff // Configuration Stuff
@ -54,7 +73,9 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
}, },
loadAdminStuff() { loadAdminStuff() {
this.backendInteractor.fetchInstanceDBConfig().then((backendDbConfig) => { getInstanceDBConfig({
credentials: useCredentialsStore().current,
}).then((backendDbConfig) => {
if (backendDbConfig.error) { if (backendDbConfig.error) {
if (backendDbConfig.error.status === 400) { if (backendDbConfig.error.status === 400) {
backendDbConfig.error.json().then((errorJson) => { backendDbConfig.error.json().then((errorJson) => {
@ -68,11 +89,9 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
} }
}) })
if (this.descriptions === null) { if (this.descriptions === null) {
this.backendInteractor fetchInstanceConfigDescriptions().then((backendDescriptions) =>
.fetchInstanceConfigDescriptions() this.setInstanceAdminDescriptions({ backendDescriptions }),
.then((backendDescriptions) => )
this.setInstanceAdminDescriptions({ backendDescriptions }),
)
} }
}, },
setInstanceAdminSettings({ backendDbConfig }) { setInstanceAdminSettings({ backendDbConfig }) {
@ -203,15 +222,12 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
} }
}) })
window.vuex.state.api.backendInteractor pushInstanceDBConfig({
.pushInstanceDBConfig({ payload: {
payload: { configs: changed,
configs: changed, },
}, })
}) .then(() => fetchInstanceDBConfig())
.then(() =>
window.vuex.state.api.backendInteractor.fetchInstanceDBConfig(),
)
.then((backendDbConfig) => .then((backendDbConfig) =>
this.setInstanceAdminSettings({ backendDbConfig }), this.setInstanceAdminSettings({ backendDbConfig }),
) )
@ -234,21 +250,18 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
} }
} }
window.vuex.state.api.backendInteractor pushInstanceDBConfig({
.pushInstanceDBConfig({ payload: {
payload: { configs: [
configs: [ {
{ group,
group, key,
key, value: convert(clone),
value: convert(clone), },
}, ],
], },
}, })
}) .then(() => fetchInstanceDBConfig())
.then(() =>
window.vuex.state.api.backendInteractor.fetchInstanceDBConfig(),
)
.then((backendDbConfig) => .then((backendDbConfig) =>
this.setInstanceAdminSettings({ backendDbConfig }), this.setInstanceAdminSettings({ backendDbConfig }),
) )
@ -260,22 +273,19 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
this.modifiedPaths.delete(path) this.modifiedPaths.delete(path)
return window.vuex.state.api.backendInteractor return pushInstanceDBConfig({
.pushInstanceDBConfig({ payload: {
payload: { configs: [
configs: [ {
{ group,
group, key,
key, delete: true,
delete: true, subkeys: [subkey],
subkeys: [subkey], },
}, ],
], },
}, })
}) .then(() => fetchInstanceDBConfig())
.then(() =>
window.vuex.state.api.backendInteractor.fetchInstanceDBConfig(),
)
.then((backendDbConfig) => .then((backendDbConfig) =>
this.setInstanceAdminSettings({ backendDbConfig }), this.setInstanceAdminSettings({ backendDbConfig }),
) )
@ -283,9 +293,9 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
// Frontends Stuff // Frontends Stuff
loadFrontendsStuff() { loadFrontendsStuff() {
this.backendInteractor getAvailableFrontends({
.fetchAvailableFrontends() credentials: useCredentialsStore().current,
.then((frontends) => this.setAvailableFrontends({ frontends })) }).then((frontends) => this.setAvailableFrontends({ frontends }))
}, },
setAvailableFrontends({ frontends }) { setAvailableFrontends({ frontends }) {
@ -302,10 +312,10 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
// Statuses stuff // Statuses stuff
async fetchStatuses(opts) { async fetchStatuses(opts) {
const { total, activities } = const { total, activities } = await listStatuses({
await this.backendInteractor.adminListStatuses({ credentials: useCredentialsStore().current,
opts, opts,
}) })
const statuses = activities.map(parseStatus) const statuses = activities.map(parseStatus)
@ -317,7 +327,8 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
} }
}, },
async changeStatusScope(opts) { async changeStatusScope(opts) {
const raw = await this.backendInteractor.adminChangeStatusScope({ const raw = await changeStatusScope({
credentials: useCredentialsStore().current,
opts, opts,
}) })
const status = parseStatus(raw) const status = parseStatus(raw)
@ -327,7 +338,9 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
// Users stuff // Users stuff
async fetchUsers(opts) { async fetchUsers(opts) {
const { users, count } = await this.backendInteractor.adminListUsers({ const { users, count } = await listUsers({
credentials: useCredentialsStore().current,
opts, opts,
}) })
@ -344,17 +357,23 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
} }
}, },
async getUserData({ user }) { async getUserData({ user }) {
const api = this.backendInteractor.adminGetUserData const api = getUserData
const { screen_name } = user const { screen_name } = user
const result = await api({ screen_name }) const result = await api({
credentials: useCredentialsStore().current,
screen_name,
})
window.vuex.commit('updateUserAdminData', { user: result }) window.vuex.commit('updateUserAdminData', { user: result })
}, },
async deleteUsers({ users }) { async deleteUsers({ users }) {
const screen_names = users.map((u) => u.screen_name) const screen_names = users.map((u) => u.screen_name)
const api = this.backendInteractor.adminDeleteAccounts const api = deleteAccounts
const resultUserIds = await api({ screen_names }) const resultUserIds = await api({
credentials: useCredentialsStore().current,
screen_names,
})
resultUserIds.forEach((userId) => { resultUserIds.forEach((userId) => {
window.vuex.dispatch( window.vuex.dispatch(
@ -369,28 +388,34 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
resendConfirmationEmail({ users }) { resendConfirmationEmail({ users }) {
const screen_names = users.map((u) => u.screen_name) const screen_names = users.map((u) => u.screen_name)
return this.backendInteractor.adminResendConfirmationEmail({ return resendConfirmationEmail({
screen_names, credentials: useCredentialsStore().current,
screen_names,
}) })
}, },
requirePasswordChange({ users }) { requirePasswordChange({ users }) {
const screen_names = users.map((u) => u.screen_name) const screen_names = users.map((u) => u.screen_name)
return this.backendInteractor.adminRequirePasswordChange({ return requirePasswordChange({
screen_names, credentials: useCredentialsStore().current,
screen_names,
}) })
}, },
// Singular only! // Singular only!
disableMFA({ user }) { disableMFA({ user }) {
const { screen_name } = user const { screen_name } = user
return this.backendInteractor.adminDisableMFA({ screen_name }) return disableMFA({
credentials: useCredentialsStore().current,
screen_name,
})
}, },
async setUsersTags({ users, tags, value }) { async setUsersTags({ users, tags, value }) {
const screen_names = users.map((u) => u.screen_name) const screen_names = users.map((u) => u.screen_name)
const api = this.backendInteractor.adminSetUsersTags const api = setUsersTags
await api({ await api({
credentials: useCredentialsStore().current,
screen_names, screen_names,
tags, tags,
value, value,
@ -402,9 +427,10 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
}, },
async setUsersRight({ users, right, value }) { async setUsersRight({ users, right, value }) {
const screen_names = users.map((u) => u.screen_name) const screen_names = users.map((u) => u.screen_name)
const api = this.backendInteractor.adminSetUsersRight const api = setUsersRight
await api({ await api({
credentials: useCredentialsStore().current,
screen_names, screen_names,
right, right,
value, value,
@ -416,9 +442,10 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
}, },
async setUsersActivationStatus({ users, value }) { async setUsersActivationStatus({ users, value }) {
const screen_names = users.map((u) => u.screen_name) const screen_names = users.map((u) => u.screen_name)
const api = this.backendInteractor.adminSetUsersActivationStatus const api = setUsersActivationStatus
const resultUsers = await api({ const resultUsers = await api({
credentials: useCredentialsStore().current,
screen_names, screen_names,
value, value,
}) })
@ -429,9 +456,10 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
}, },
async setUsersSuggestionStatus({ users, value }) { async setUsersSuggestionStatus({ users, value }) {
const screen_names = users.map((u) => u.screen_name) const screen_names = users.map((u) => u.screen_name)
const api = this.backendInteractor.adminSetUsersSuggestionStatus const api = setUsersSuggestionStatus
const resultUsers = await api({ const resultUsers = await api({
credentials: useCredentialsStore().current,
screen_names, screen_names,
value, value,
}) })
@ -442,9 +470,12 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
}, },
async setUsersConfirmationStatus({ users }) { async setUsersConfirmationStatus({ users }) {
const screen_names = users.map((u) => u.screen_name) const screen_names = users.map((u) => u.screen_name)
const api = this.backendInteractor.adminSetUsersConfirmationStatus const api = setUsersConfirmationStatus
await api({ screen_names }) await api({
credentials: useCredentialsStore().current,
screen_names,
})
users.forEach((user) => { users.forEach((user) => {
this.getUserData({ user }) this.getUserData({ user })
@ -452,9 +483,10 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
}, },
async setUsersApprovalStatus({ users }) { async setUsersApprovalStatus({ users }) {
const screen_names = users.map((u) => u.screen_name) const screen_names = users.map((u) => u.screen_name)
const api = this.backendInteractor.adminSetUsersApprovalStatus const api = setUsersApprovalStatus
const resultUsers = await api({ const resultUsers = await api({
credentials: useCredentialsStore().current,
screen_names, screen_names,
}) })

View file

@ -1,5 +1,18 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { useCredentialsStore } from 'src/stores/credentials.js'
import {
getAnnouncements as adminGetAnnouncements,
deleteAnnouncement,
editAnnouncement,
postAnnouncement,
} from 'src/services/api/admin.js'
import {
dismissAnnouncement,
getAnnouncements,
} from 'src/services/api/api.service.js'
const FETCH_ANNOUNCEMENT_INTERVAL_MS = 1000 * 60 * 5 const FETCH_ANNOUNCEMENT_INTERVAL_MS = 1000 * 60 * 5
export const useAnnouncementsStore = defineStore('announcements', { export const useAnnouncementsStore = defineStore('announcements', {
@ -31,15 +44,19 @@ export const useAnnouncementsStore = defineStore('announcements', {
currentUser && currentUser &&
currentUser.privileges.has('announcements_manage_announcements') currentUser.privileges.has('announcements_manage_announcements')
const getAnnouncements = async () => { const fetchAnnouncements = async () => {
if (!isAdmin) { if (!isAdmin) {
return window.vuex.state.api.backendInteractor.fetchAnnouncements() return fetchAnnouncements({
credentials: useCredentialsStore().current,
})
} }
const all = const all = await adminGetAnnouncements({
await window.vuex.state.api.backendInteractor.adminFetchAnnouncements() credentials: useCredentialsStore().current,
const visible = })
await window.vuex.state.api.backendInteractor.fetchAnnouncements() const visible = await getAnnouncements({
credentials: useCredentialsStore().current,
})
const visibleObject = visible.reduce((a, c) => { const visibleObject = visible.reduce((a, c) => {
a[c.id] = c a[c.id] = c
return a return a
@ -59,7 +76,7 @@ export const useAnnouncementsStore = defineStore('announcements', {
return all return all
} }
return getAnnouncements() return fetchAnnouncements()
.then((announcements) => { .then((announcements) => {
this.announcements = announcements this.announcements = announcements
}) })
@ -74,17 +91,18 @@ export const useAnnouncementsStore = defineStore('announcements', {
}) })
}, },
markAnnouncementAsRead(id) { markAnnouncementAsRead(id) {
return window.vuex.state.api.backendInteractor return dismissAnnouncement({
.dismissAnnouncement({ id }) id,
.then(() => { credentials: useCredentialsStore().current,
const index = this.announcements.findIndex((a) => a.id === id) }).then(() => {
const index = this.announcements.findIndex((a) => a.id === id)
if (index < 0) { if (index < 0) {
return return
} }
this.announcements[index].read = true this.announcements[index].read = true
}) })
}, },
startFetchingAnnouncements() { startFetchingAnnouncements() {
if (this.fetchAnnouncementsTimer) { if (this.fetchAnnouncementsTimer) {
@ -105,25 +123,35 @@ export const useAnnouncementsStore = defineStore('announcements', {
clearInterval(interval) clearInterval(interval)
}, },
postAnnouncement({ content, startsAt, endsAt, allDay }) { postAnnouncement({ content, startsAt, endsAt, allDay }) {
return window.vuex.state.api.backendInteractor return postAnnouncement({
.postAnnouncement({ content, startsAt, endsAt, allDay }) credentials: useCredentialsStore().current,
.then(() => { content,
return this.fetchAnnouncements() startsAt,
}) endsAt,
allDay,
}).then(() => {
return this.fetchAnnouncements()
})
}, },
editAnnouncement({ id, content, startsAt, endsAt, allDay }) { editAnnouncement({ id, content, startsAt, endsAt, allDay }) {
return window.vuex.state.api.backendInteractor return editAnnouncement({
.editAnnouncement({ id, content, startsAt, endsAt, allDay }) id,
.then(() => { content,
return this.fetchAnnouncements() startsAt,
}) endsAt,
allDay,
credentials: useCredentialsStore().current,
}).then(() => {
return this.fetchAnnouncements()
})
}, },
deleteAnnouncement(id) { deleteAnnouncement(id) {
return window.vuex.state.api.backendInteractor return deleteAnnouncement({
.deleteAnnouncement({ id }) id,
.then(() => { credentials: useCredentialsStore().current,
return this.fetchAnnouncements() }).then(() => {
}) return this.fetchAnnouncements()
})
}, },
}, },
}) })

View file

@ -1,6 +1,14 @@
import { find, remove } from 'lodash' import { find, remove } from 'lodash'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { useCredentialsStore } from 'src/stores/credentials.js'
import {
createBookmarkFolder,
deleteBookmarkFolder,
updateBookmarkFolder,
} from 'src/services/api/api.service.js'
export const useBookmarkFoldersStore = defineStore('bookmarkFolders', { export const useBookmarkFoldersStore = defineStore('bookmarkFolders', {
state: () => ({ state: () => ({
allFolders: [], allFolders: [],
@ -30,23 +38,31 @@ export const useBookmarkFoldersStore = defineStore('bookmarkFolders', {
} }
}, },
createBookmarkFolder({ name, emoji }) { createBookmarkFolder({ name, emoji }) {
return window.vuex.state.api.backendInteractor return createBookmarkFolder({
.createBookmarkFolder({ name, emoji }) name,
.then((folder) => { emoji,
this.setBookmarkFolder(folder) credentials: useCredentialsStore().current,
return folder }).then((folder) => {
}) this.setBookmarkFolder(folder)
return folder
})
}, },
updateBookmarkFolder({ folderId, name, emoji }) { updateBookmarkFolder({ folderId, name, emoji }) {
return window.vuex.state.api.backendInteractor return updateBookmarkFolder({
.updateBookmarkFolder({ folderId, name, emoji }) credentials: useCredentialsStore().current,
.then((folder) => { folderId,
this.setBookmarkFolder(folder) name,
return folder emoji,
}) }).then((folder) => {
this.setBookmarkFolder(folder)
return folder
})
}, },
deleteBookmarkFolder({ folderId }) { deleteBookmarkFolder({ folderId }) {
window.vuex.state.api.backendInteractor.deleteBookmarkFolder({ folderId }) deleteBookmarkFolder({
folderId,
credentials: useCredentialsStore().current,
})
remove(this.allFolders, (folder) => folder.id === folderId) remove(this.allFolders, (folder) => folder.id === folderId)
}, },
}, },

19
src/stores/credentials.js Normal file
View file

@ -0,0 +1,19 @@
import { defineStore } from 'pinia'
const defaultState = {
credentials: null,
}
export const useCredentialsStore = defineStore('credentials', {
state: () => ({ ...defaultState }),
actions: {
setCredentials(credentials) {
this.credentials = credentials
},
},
getters: {
current() {
return window.vuex.state.users.currentUser.credentials
},
},
})

View file

@ -11,7 +11,7 @@ import {
LOCAL_DEFAULT_CONFIG_DEFINITIONS, LOCAL_DEFAULT_CONFIG_DEFINITIONS,
validateSetting, validateSetting,
} from '../modules/default_config_state.js' } from '../modules/default_config_state.js'
import apiService from '../services/api/api.service.js' import { fetchKnownDomains } from '../services/api/api.service.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
@ -210,7 +210,7 @@ export const useInstanceStore = defineStore('instance', {
}, },
async getKnownDomains() { async getKnownDomains() {
try { try {
this.knownDomains = await apiService.fetchKnownDomains({ this.knownDomains = await fetchKnownDomains({
credentials: window.vuex.state.users.currentUser.credentials, credentials: window.vuex.state.users.currentUser.credentials,
}) })
} catch (e) { } catch (e) {

View file

@ -1,8 +1,11 @@
import { filter } from 'lodash' import { filter } from 'lodash'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { useCredentialsStore } from 'src/stores/credentials.js'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { setReportState } from 'src/services/api/admin.js'
export const useReportsStore = defineStore('reports', { export const useReportsStore = defineStore('reports', {
state: () => ({ state: () => ({
reportModal: { reportModal: {
@ -40,18 +43,21 @@ export const useReportsStore = defineStore('reports', {
setReportState({ id, state }) { setReportState({ id, state }) {
const oldState = this.reports[id].state const oldState = this.reports[id].state
this.reports[id].state = state this.reports[id].state = state
window.vuex.state.api.backendInteractor
.setReportState({ id, state }) setReportState({
.catch((e) => { id,
console.error('Failed to set report state', e) state,
useInterfaceStore().pushGlobalNotice({ credentials: useCredentialsStore().current,
level: 'error', }).catch((e) => {
messageKey: 'general.generic_error_message', console.error('Failed to set report state', e)
messageArgs: [e.message], useInterfaceStore().pushGlobalNotice({
timeout: 5000, level: 'error',
}) messageKey: 'general.generic_error_message',
this.reports[id].state = oldState messageArgs: [e.message],
timeout: 5000,
}) })
this.reports[id].state = oldState
})
}, },
addReport(report) { addReport(report) {
this.reports[report.id] = report this.reports[report.id] = report