aboutsummaryrefslogtreecommitdiff
path: root/src/services
diff options
context:
space:
mode:
Diffstat (limited to 'src/services')
-rw-r--r--src/services/api/api.service.js82
-rw-r--r--src/services/date_utils/date_utils.js16
-rw-r--r--src/services/export_import/export_import.js4
-rw-r--r--src/services/locale/locale.service.js27
-rw-r--r--src/services/notification_utils/notification_utils.js8
-rw-r--r--src/services/offset_finder/offset_finder.service.js2
-rw-r--r--src/services/resettable_async_component.js22
-rw-r--r--src/services/style_setter/style_setter.js8
8 files changed, 136 insertions, 33 deletions
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index c17d0476..8f09545c 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -9,6 +9,8 @@ const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import'
const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account'
const CHANGE_EMAIL_URL = '/api/pleroma/change_email'
const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
+const MOVE_ACCOUNT_URL = '/api/pleroma/move_account'
+const ALIASES_URL = '/api/pleroma/aliases'
const TAG_USER_URL = '/api/pleroma/admin/users/tag'
const PERMISSION_GROUP_URL = (screenName, right) => `/api/pleroma/admin/users/${screenName}/permission_group/${right}`
const ACTIVATE_USER_URL = '/api/pleroma/admin/users/activate'
@@ -88,6 +90,7 @@ const PLEROMA_CHAT_MESSAGES_URL = id => `/api/v1/pleroma/chats/${id}/messages`
const PLEROMA_CHAT_READ_URL = id => `/api/v1/pleroma/chats/${id}/read`
const PLEROMA_DELETE_CHAT_MESSAGE_URL = (chatId, messageId) => `/api/v1/pleroma/chats/${chatId}/messages/${messageId}`
const PLEROMA_ADMIN_REPORTS = '/api/pleroma/admin/reports'
+const PLEROMA_BACKUP_URL = '/api/v1/pleroma/backups'
const oldfetch = window.fetch
@@ -152,9 +155,15 @@ const updateNotificationSettings = ({ credentials, settings }) => {
}).then((data) => data.json())
}
-const updateProfileImages = ({ credentials, avatar = null, banner = null, background = null }) => {
+const updateProfileImages = ({ credentials, avatar = null, avatarName = null, banner = null, background = null }) => {
const form = new FormData()
- if (avatar !== null) form.append('avatar', avatar)
+ if (avatar !== null) {
+ if (avatarName !== null) {
+ form.append('avatar', avatar, avatarName)
+ } else {
+ form.append('avatar', avatar)
+ }
+ }
if (banner !== null) form.append('header', banner)
if (background !== null) form.append('pleroma_background_image', background)
return fetch(MASTODON_PROFILE_UPDATE_URL, {
@@ -192,6 +201,7 @@ const updateProfile = ({ credentials, params }) => {
// homepage
// location
// token
+// language
const register = ({ params, credentials }) => {
const { nickname, ...rest } = params
return fetch(MASTODON_REGISTRATION_URL, {
@@ -789,6 +799,49 @@ const changeEmail = ({ credentials, email, password }) => {
.then((response) => response.json())
}
+const moveAccount = ({ credentials, password, targetAccount }) => {
+ const form = new FormData()
+
+ form.append('password', password)
+ form.append('target_account', targetAccount)
+
+ return fetch(MOVE_ACCOUNT_URL, {
+ body: form,
+ method: 'POST',
+ headers: authHeaders(credentials)
+ })
+ .then((response) => response.json())
+}
+
+const addAlias = ({ credentials, alias }) => {
+ return promisedRequest({
+ url: ALIASES_URL,
+ method: 'PUT',
+ credentials,
+ payload: { alias }
+ })
+}
+
+const deleteAlias = ({ credentials, alias }) => {
+ return promisedRequest({
+ url: ALIASES_URL,
+ method: 'DELETE',
+ credentials,
+ payload: { alias }
+ })
+}
+
+const listAliases = ({ credentials }) => {
+ return promisedRequest({
+ url: ALIASES_URL,
+ method: 'GET',
+ credentials,
+ params: {
+ _cacheBooster: (new Date()).getTime()
+ }
+ })
+}
+
const changePassword = ({ credentials, password, newPassword, newPasswordConfirmation }) => {
const form = new FormData()
@@ -875,6 +928,25 @@ const fetchBlocks = ({ credentials }) => {
.then((users) => users.map(parseUser))
}
+const addBackup = ({ credentials }) => {
+ return promisedRequest({
+ url: PLEROMA_BACKUP_URL,
+ method: 'POST',
+ credentials
+ })
+}
+
+const listBackups = ({ credentials }) => {
+ return promisedRequest({
+ url: PLEROMA_BACKUP_URL,
+ method: 'GET',
+ credentials,
+ params: {
+ _cacheBooster: (new Date()).getTime()
+ }
+ })
+}
+
const fetchOAuthTokens = ({ credentials }) => {
const url = '/api/oauth_tokens.json'
@@ -1358,12 +1430,18 @@ const apiService = {
importFollows,
deleteAccount,
changeEmail,
+ moveAccount,
+ addAlias,
+ deleteAlias,
+ listAliases,
changePassword,
settingsMFA,
mfaDisableOTP,
generateMfaBackupCodes,
mfaSetupOTP,
mfaConfirmOTP,
+ addBackup,
+ listBackups,
fetchFollowRequests,
approveUser,
denyUser,
diff --git a/src/services/date_utils/date_utils.js b/src/services/date_utils/date_utils.js
index 32e13bca..677c184c 100644
--- a/src/services/date_utils/date_utils.js
+++ b/src/services/date_utils/date_utils.js
@@ -10,31 +10,29 @@ export const relativeTime = (date, nowThreshold = 1) => {
if (typeof date === 'string') date = Date.parse(date)
const round = Date.now() > date ? Math.floor : Math.ceil
const d = Math.abs(Date.now() - date)
- let r = { num: round(d / YEAR), key: 'time.years' }
+ let r = { num: round(d / YEAR), key: 'time.unit.years' }
if (d < nowThreshold * SECOND) {
r.num = 0
r.key = 'time.now'
} else if (d < MINUTE) {
r.num = round(d / SECOND)
- r.key = 'time.seconds'
+ r.key = 'time.unit.seconds'
} else if (d < HOUR) {
r.num = round(d / MINUTE)
- r.key = 'time.minutes'
+ r.key = 'time.unit.minutes'
} else if (d < DAY) {
r.num = round(d / HOUR)
- r.key = 'time.hours'
+ r.key = 'time.unit.hours'
} else if (d < WEEK) {
r.num = round(d / DAY)
- r.key = 'time.days'
+ r.key = 'time.unit.days'
} else if (d < MONTH) {
r.num = round(d / WEEK)
- r.key = 'time.weeks'
+ r.key = 'time.unit.weeks'
} else if (d < YEAR) {
r.num = round(d / MONTH)
- r.key = 'time.months'
+ r.key = 'time.unit.months'
}
- // Remove plural form when singular
- if (r.num === 1) r.key = r.key.slice(0, -1)
return r
}
diff --git a/src/services/export_import/export_import.js b/src/services/export_import/export_import.js
index ac67cf9c..7fee0ad3 100644
--- a/src/services/export_import/export_import.js
+++ b/src/services/export_import/export_import.js
@@ -1,9 +1,11 @@
+import utf8 from 'utf8'
+
export const newExporter = ({
filename = 'data',
getExportedObject
}) => ({
exportData () {
- const stringified = JSON.stringify(getExportedObject(), null, 2) // Pretty-print and indent with 2 spaces
+ const stringified = utf8.encode(JSON.stringify(getExportedObject(), null, 2)) // Pretty-print and indent with 2 spaces
// Create an invisible link with a data url and simulate a click
const e = document.createElement('a')
diff --git a/src/services/locale/locale.service.js b/src/services/locale/locale.service.js
index 5be99d81..8cef2522 100644
--- a/src/services/locale/locale.service.js
+++ b/src/services/locale/locale.service.js
@@ -1,12 +1,35 @@
+import languagesObject from '../../i18n/messages'
+import ISO6391 from 'iso-639-1'
+import _ from 'lodash'
+
const specialLanguageCodes = {
'ja_easy': 'ja',
- 'zh_Hant': 'zh-HANT'
+ 'zh_Hant': 'zh-HANT',
+ 'zh': 'zh-Hans'
}
const internalToBrowserLocale = code => specialLanguageCodes[code] || code
+const internalToBackendLocale = code => internalToBrowserLocale(code).replace('_', '-')
+
+const getLanguageName = (code) => {
+ const specialLanguageNames = {
+ 'ja_easy': 'やさしいにほんご',
+ 'zh': '简体中文',
+ 'zh_Hant': '繁體中文'
+ }
+ const languageName = specialLanguageNames[code] || ISO6391.getNativeName(code)
+ const browserLocale = internalToBrowserLocale(code)
+ return languageName.charAt(0).toLocaleUpperCase(browserLocale) + languageName.slice(1)
+}
+
+const languages = _.map(languagesObject.languages, (code) => ({ code: code, name: getLanguageName(code) })).sort((a, b) => a.name.localeCompare(b.name))
+
const localeService = {
- internalToBrowserLocale
+ internalToBrowserLocale,
+ internalToBackendLocale,
+ languages,
+ getLanguageName
}
export default localeService
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
index 8c70ea53..0f8b9b02 100644
--- a/src/services/notification_utils/notification_utils.js
+++ b/src/services/notification_utils/notification_utils.js
@@ -15,11 +15,12 @@ export const visibleTypes = store => {
rootState.config.notificationVisibility.followRequest && 'follow_request',
rootState.config.notificationVisibility.moves && 'move',
rootState.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction',
- rootState.config.notificationVisibility.reports && 'pleroma:report'
+ rootState.config.notificationVisibility.reports && 'pleroma:report',
+ rootState.config.notificationVisibility.polls && 'poll'
].filter(_ => _))
}
-const statusNotifications = ['like', 'mention', 'repeat', 'pleroma:emoji_reaction']
+const statusNotifications = ['like', 'mention', 'repeat', 'pleroma:emoji_reaction', 'poll']
export const isStatusNotification = (type) => includes(statusNotifications, type)
@@ -102,6 +103,9 @@ export const prepareNotificationObject = (notification, i18n) => {
case 'pleroma:report':
i18nString = 'submitted_report'
break
+ case 'poll':
+ i18nString = 'poll_ended'
+ break
}
if (notification.type === 'pleroma:emoji_reaction') {
diff --git a/src/services/offset_finder/offset_finder.service.js b/src/services/offset_finder/offset_finder.service.js
index 9034f8c8..5a904f08 100644
--- a/src/services/offset_finder/offset_finder.service.js
+++ b/src/services/offset_finder/offset_finder.service.js
@@ -9,7 +9,7 @@ export const findOffset = (child, parent, { top = 0, left = 0 } = {}, ignorePadd
result.left += ignorePadding ? 0 : leftPadding
}
- if (child.offsetParent && (parent === window || parent.contains(child.offsetParent) || parent === child.offsetParent)) {
+ if (child.offsetParent && window.getComputedStyle(child.offsetParent).position !== 'sticky' && (parent === window || parent.contains(child.offsetParent) || parent === child.offsetParent)) {
return findOffset(child.offsetParent, parent, result, false)
} else {
if (parent !== window) {
diff --git a/src/services/resettable_async_component.js b/src/services/resettable_async_component.js
index 517bbd88..1c046ce7 100644
--- a/src/services/resettable_async_component.js
+++ b/src/services/resettable_async_component.js
@@ -1,4 +1,4 @@
-import Vue from 'vue'
+import { defineAsyncComponent, shallowReactive, h } from 'vue'
/* By default async components don't have any way to recover, if component is
* failed, it is failed forever. This helper tries to remedy that by recreating
@@ -8,23 +8,21 @@ import Vue from 'vue'
* actual target component itself if needs to be.
*/
function getResettableAsyncComponent (asyncComponent, options) {
- const asyncComponentFactory = () => () => ({
- component: asyncComponent(),
+ const asyncComponentFactory = () => () => defineAsyncComponent({
+ loader: asyncComponent,
...options
})
- const observe = Vue.observable({ c: asyncComponentFactory() })
+ const observe = shallowReactive({ c: asyncComponentFactory() })
return {
- functional: true,
- render (createElement, { data, children }) {
+ render () {
// emit event resetAsyncComponent to reloading
- data.on = {}
- data.on.resetAsyncComponent = () => {
- observe.c = asyncComponentFactory()
- // parent.$forceUpdate()
- }
- return createElement(observe.c, data, children)
+ return h(observe.c(), {
+ onResetAsyncComponent () {
+ observe.c = asyncComponentFactory()
+ }
+ })
}
}
}
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index f75e6916..543aa874 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -13,10 +13,10 @@ export const applyTheme = (input) => {
const styleSheet = styleEl.sheet
styleSheet.toString()
- styleSheet.insertRule(`body { ${rules.radii} }`, 'index-max')
- styleSheet.insertRule(`body { ${rules.colors} }`, 'index-max')
- styleSheet.insertRule(`body { ${rules.shadows} }`, 'index-max')
- styleSheet.insertRule(`body { ${rules.fonts} }`, 'index-max')
+ styleSheet.insertRule(`:root { ${rules.radii} }`, 'index-max')
+ styleSheet.insertRule(`:root { ${rules.colors} }`, 'index-max')
+ styleSheet.insertRule(`:root { ${rules.shadows} }`, 'index-max')
+ styleSheet.insertRule(`:root { ${rules.fonts} }`, 'index-max')
body.classList.remove('hidden')
}