aboutsummaryrefslogtreecommitdiff
path: root/src/services
diff options
context:
space:
mode:
Diffstat (limited to 'src/services')
-rw-r--r--src/services/api/api.service.js328
-rw-r--r--src/services/backend_interactor_service/backend_interactor_service.js175
-rw-r--r--src/services/color_convert/color_convert.js2
-rw-r--r--src/services/completion/completion.js2
-rw-r--r--src/services/date_utils/date_utils.js45
-rw-r--r--src/services/entity_normalizer/entity_normalizer.service.js12
-rw-r--r--src/services/errors/errors.js35
-rw-r--r--src/services/file_size_format/file_size_format.js2
-rw-r--r--src/services/follow_manipulate/follow_manipulate.js30
-rw-r--r--src/services/follow_request_fetcher/follow_request_fetcher.service.js2
-rw-r--r--src/services/new_api/mfa.js4
-rw-r--r--src/services/new_api/oauth.js21
-rw-r--r--src/services/new_api/user_search.js19
-rw-r--r--src/services/new_api/utils.js36
-rw-r--r--src/services/notification_utils/notification_utils.js2
-rw-r--r--src/services/notifications_fetcher/notifications_fetcher.service.js6
-rw-r--r--src/services/status_poster/status_poster.service.js13
-rw-r--r--src/services/style_setter/style_setter.js13
-rw-r--r--src/services/timeline_fetcher/timeline_fetcher.service.js10
-rw-r--r--src/services/user_highlighter/user_highlighter.js2
-rw-r--r--src/services/version/version.service.js2
21 files changed, 479 insertions, 282 deletions
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index 05d968f7..083d4f4f 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -1,5 +1,9 @@
+import { each, map, concat, last } from 'lodash'
+import { parseStatus, parseUser, parseNotification, parseAttachment } from '../entity_normalizer/entity_normalizer.service.js'
+import 'whatwg-fetch'
+import { RegistrationError, StatusCodeError } from '../errors/errors'
+
/* eslint-env browser */
-const BG_UPDATE_URL = '/api/qvitter/update_background_image.json'
const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json'
const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json'
const BLOCKS_IMPORT_URL = '/api/pleroma/blocks_import'
@@ -25,7 +29,6 @@ const MFA_DISABLE_OTP_URL = '/api/pleroma/profile/mfa/totp'
const MASTODON_LOGIN_URL = '/api/v1/accounts/verify_credentials'
const MASTODON_REGISTRATION_URL = '/api/v1/accounts'
-const GET_BACKGROUND_HACK = '/api/account/verify_credentials.json'
const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites'
const MASTODON_USER_NOTIFICATIONS_URL = '/api/v1/notifications'
const MASTODON_FAVORITE_URL = id => `/api/v1/statuses/${id}/favourite`
@@ -52,19 +55,22 @@ const MASTODON_BLOCK_USER_URL = id => `/api/v1/accounts/${id}/block`
const MASTODON_UNBLOCK_USER_URL = id => `/api/v1/accounts/${id}/unblock`
const MASTODON_MUTE_USER_URL = id => `/api/v1/accounts/${id}/mute`
const MASTODON_UNMUTE_USER_URL = id => `/api/v1/accounts/${id}/unmute`
+const MASTODON_SUBSCRIBE_USER = id => `/api/v1/pleroma/accounts/${id}/subscribe`
+const MASTODON_UNSUBSCRIBE_USER = id => `/api/v1/pleroma/accounts/${id}/unsubscribe`
const MASTODON_POST_STATUS_URL = '/api/v1/statuses'
const MASTODON_MEDIA_UPLOAD_URL = '/api/v1/media'
+const MASTODON_VOTE_URL = id => `/api/v1/polls/${id}/votes`
+const MASTODON_POLL_URL = id => `/api/v1/polls/${id}`
const MASTODON_STATUS_FAVORITEDBY_URL = id => `/api/v1/statuses/${id}/favourited_by`
const MASTODON_STATUS_REBLOGGEDBY_URL = id => `/api/v1/statuses/${id}/reblogged_by`
const MASTODON_PROFILE_UPDATE_URL = '/api/v1/accounts/update_credentials'
const MASTODON_REPORT_USER_URL = '/api/v1/reports'
const MASTODON_PIN_OWN_STATUS = id => `/api/v1/statuses/${id}/pin`
const MASTODON_UNPIN_OWN_STATUS = id => `/api/v1/statuses/${id}/unpin`
-
-import { each, map, concat, last } from 'lodash'
-import { parseStatus, parseUser, parseNotification, parseAttachment } from '../entity_normalizer/entity_normalizer.service.js'
-import 'whatwg-fetch'
-import { StatusCodeError } from '../errors/errors'
+const MASTODON_MUTE_CONVERSATION = id => `/api/v1/statuses/${id}/mute`
+const MASTODON_UNMUTE_CONVERSATION = id => `/api/v1/statuses/${id}/unmute`
+const MASTODON_SEARCH_2 = `/api/v2/search`
+const MASTODON_USER_SEARCH_URL = '/api/v1/accounts/search'
const oldfetch = window.fetch
@@ -76,7 +82,7 @@ let fetch = (url, options) => {
return oldfetch(fullUrl, options)
}
-const promisedRequest = ({ method, url, payload, credentials, headers = {} }) => {
+const promisedRequest = ({ method, url, params, payload, credentials, headers = {} }) => {
const options = {
method,
headers: {
@@ -85,6 +91,11 @@ const promisedRequest = ({ method, url, payload, credentials, headers = {} }) =>
...headers
}
}
+ if (params) {
+ url += '?' + Object.entries(params)
+ .map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value))
+ .join('&')
+ }
if (payload) {
options.body = JSON.stringify(payload)
}
@@ -106,7 +117,7 @@ const promisedRequest = ({ method, url, payload, credentials, headers = {} }) =>
})
}
-const updateNotificationSettings = ({credentials, settings}) => {
+const updateNotificationSettings = ({ credentials, settings }) => {
const form = new FormData()
each(settings, (value, key) => {
@@ -117,60 +128,50 @@ const updateNotificationSettings = ({credentials, settings}) => {
headers: authHeaders(credentials),
method: 'PUT',
body: form
- })
- .then((data) => data.json())
+ }).then((data) => data.json())
}
-const updateAvatar = ({credentials, avatar}) => {
+const updateAvatar = ({ credentials, avatar }) => {
const form = new FormData()
form.append('avatar', avatar)
return fetch(MASTODON_PROFILE_UPDATE_URL, {
headers: authHeaders(credentials),
method: 'PATCH',
body: form
- })
- .then((data) => data.json())
- .then((data) => parseUser(data))
+ }).then((data) => data.json())
+ .then((data) => parseUser(data))
}
-const updateBg = ({credentials, params}) => {
- let url = BG_UPDATE_URL
-
+const updateBg = ({ credentials, background }) => {
const form = new FormData()
-
- each(params, (value, key) => {
- if (value) {
- form.append(key, value)
- }
- })
-
- return fetch(url, {
+ form.append('pleroma_background_image', background)
+ return fetch(MASTODON_PROFILE_UPDATE_URL, {
headers: authHeaders(credentials),
- method: 'POST',
+ method: 'PATCH',
body: form
- }).then((data) => data.json())
+ })
+ .then((data) => data.json())
+ .then((data) => parseUser(data))
}
-const updateBanner = ({credentials, banner}) => {
+const updateBanner = ({ credentials, banner }) => {
const form = new FormData()
form.append('header', banner)
return fetch(MASTODON_PROFILE_UPDATE_URL, {
headers: authHeaders(credentials),
method: 'PATCH',
body: form
- })
- .then((data) => data.json())
- .then((data) => parseUser(data))
+ }).then((data) => data.json())
+ .then((data) => parseUser(data))
}
-const updateProfile = ({credentials, params}) => {
+const updateProfile = ({ credentials, params }) => {
return promisedRequest({
url: MASTODON_PROFILE_UPDATE_URL,
method: 'PATCH',
payload: params,
credentials
- })
- .then((data) => parseUser(data))
+ }).then((data) => parseUser(data))
}
// Params needed:
@@ -200,12 +201,11 @@ const register = ({ params, credentials }) => {
...rest
})
})
- .then((response) => [response.ok, response])
- .then(([ok, response]) => {
- if (ok) {
+ .then((response) => {
+ if (response.ok) {
return response.json()
} else {
- return response.json().then((error) => { throw new Error(error) })
+ return response.json().then((error) => { throw new RegistrationError(error) })
}
})
}
@@ -220,7 +220,7 @@ const authHeaders = (accessToken) => {
}
}
-const externalProfile = ({profileUrl, credentials}) => {
+const externalProfile = ({ profileUrl, credentials }) => {
let url = `${EXTERNAL_PROFILE_URL}?profileurl=${profileUrl}`
return fetch(url, {
headers: authHeaders(credentials),
@@ -228,7 +228,7 @@ const externalProfile = ({profileUrl, credentials}) => {
}).then((data) => data.json())
}
-const followUser = ({id, credentials}) => {
+const followUser = ({ id, credentials }) => {
let url = MASTODON_FOLLOW_URL(id)
return fetch(url, {
headers: authHeaders(credentials),
@@ -236,7 +236,7 @@ const followUser = ({id, credentials}) => {
}).then((data) => data.json())
}
-const unfollowUser = ({id, credentials}) => {
+const unfollowUser = ({ id, credentials }) => {
let url = MASTODON_UNFOLLOW_URL(id)
return fetch(url, {
headers: authHeaders(credentials),
@@ -254,21 +254,31 @@ const unpinOwnStatus = ({ id, credentials }) => {
.then((data) => parseStatus(data))
}
-const blockUser = ({id, credentials}) => {
+const muteConversation = ({ id, credentials }) => {
+ return promisedRequest({ url: MASTODON_MUTE_CONVERSATION(id), credentials, method: 'POST' })
+ .then((data) => parseStatus(data))
+}
+
+const unmuteConversation = ({ id, credentials }) => {
+ return promisedRequest({ url: MASTODON_UNMUTE_CONVERSATION(id), credentials, method: 'POST' })
+ .then((data) => parseStatus(data))
+}
+
+const blockUser = ({ id, credentials }) => {
return fetch(MASTODON_BLOCK_USER_URL(id), {
headers: authHeaders(credentials),
method: 'POST'
}).then((data) => data.json())
}
-const unblockUser = ({id, credentials}) => {
+const unblockUser = ({ id, credentials }) => {
return fetch(MASTODON_UNBLOCK_USER_URL(id), {
headers: authHeaders(credentials),
method: 'POST'
}).then((data) => data.json())
}
-const approveUser = ({id, credentials}) => {
+const approveUser = ({ id, credentials }) => {
let url = `${APPROVE_USER_URL}?user_id=${id}`
return fetch(url, {
headers: authHeaders(credentials),
@@ -276,7 +286,7 @@ const approveUser = ({id, credentials}) => {
}).then((data) => data.json())
}
-const denyUser = ({id, credentials}) => {
+const denyUser = ({ id, credentials }) => {
let url = `${DENY_USER_URL}?user_id=${id}`
return fetch(url, {
headers: authHeaders(credentials),
@@ -284,13 +294,13 @@ const denyUser = ({id, credentials}) => {
}).then((data) => data.json())
}
-const fetchUser = ({id, credentials}) => {
+const fetchUser = ({ id, credentials }) => {
let url = `${MASTODON_USER_URL}/${id}`
return promisedRequest({ url, credentials })
.then((data) => parseUser(data))
}
-const fetchUserRelationship = ({id, credentials}) => {
+const fetchUserRelationship = ({ id, credentials }) => {
let url = `${MASTODON_USER_RELATIONSHIPS_URL}/?id=${id}`
return fetch(url, { headers: authHeaders(credentials) })
.then((response) => {
@@ -304,7 +314,7 @@ const fetchUserRelationship = ({id, credentials}) => {
})
}
-const fetchFriends = ({id, maxId, sinceId, limit = 20, credentials}) => {
+const fetchFriends = ({ id, maxId, sinceId, limit = 20, credentials }) => {
let url = MASTODON_FOLLOWING_URL(id)
const args = [
maxId && `max_id=${maxId}`,
@@ -318,14 +328,14 @@ const fetchFriends = ({id, maxId, sinceId, limit = 20, credentials}) => {
.then((data) => data.map(parseUser))
}
-const exportFriends = ({id, credentials}) => {
+const exportFriends = ({ id, credentials }) => {
return new Promise(async (resolve, reject) => {
try {
let friends = []
let more = true
while (more) {
const maxId = friends.length > 0 ? last(friends).id : undefined
- const users = await fetchFriends({id, maxId, credentials})
+ const users = await fetchFriends({ id, maxId, credentials })
friends = concat(friends, users)
if (users.length === 0) {
more = false
@@ -338,7 +348,7 @@ const exportFriends = ({id, credentials}) => {
})
}
-const fetchFollowers = ({id, maxId, sinceId, limit = 20, credentials}) => {
+const fetchFollowers = ({ id, maxId, sinceId, limit = 20, credentials }) => {
let url = MASTODON_FOLLOWERS_URL(id)
const args = [
maxId && `max_id=${maxId}`,
@@ -352,13 +362,13 @@ const fetchFollowers = ({id, maxId, sinceId, limit = 20, credentials}) => {
.then((data) => data.map(parseUser))
}
-const fetchFollowRequests = ({credentials}) => {
+const fetchFollowRequests = ({ credentials }) => {
const url = FOLLOW_REQUESTS_URL
return fetch(url, { headers: authHeaders(credentials) })
.then((data) => data.json())
}
-const fetchConversation = ({id, credentials}) => {
+const fetchConversation = ({ id, credentials }) => {
let urlContext = MASTODON_STATUS_CONTEXT_URL(id)
return fetch(urlContext, { headers: authHeaders(credentials) })
.then((data) => {
@@ -368,13 +378,13 @@ const fetchConversation = ({id, credentials}) => {
throw new Error('Error fetching timeline', data)
})
.then((data) => data.json())
- .then(({ancestors, descendants}) => ({
+ .then(({ ancestors, descendants }) => ({
ancestors: ancestors.map(parseStatus),
descendants: descendants.map(parseStatus)
}))
}
-const fetchStatus = ({id, credentials}) => {
+const fetchStatus = ({ id, credentials }) => {
let url = MASTODON_STATUS_URL(id)
return fetch(url, { headers: authHeaders(credentials) })
.then((data) => {
@@ -387,7 +397,7 @@ const fetchStatus = ({id, credentials}) => {
.then((data) => parseStatus(data))
}
-const tagUser = ({tag, credentials, ...options}) => {
+const tagUser = ({ tag, credentials, ...options }) => {
const screenName = options.screen_name
const form = {
nicknames: [screenName],
@@ -404,7 +414,7 @@ const tagUser = ({tag, credentials, ...options}) => {
})
}
-const untagUser = ({tag, credentials, ...options}) => {
+const untagUser = ({ tag, credentials, ...options }) => {
const screenName = options.screen_name
const body = {
nicknames: [screenName],
@@ -421,7 +431,7 @@ const untagUser = ({tag, credentials, ...options}) => {
})
}
-const addRight = ({right, credentials, ...user}) => {
+const addRight = ({ right, credentials, ...user }) => {
const screenName = user.screen_name
return fetch(PERMISSION_GROUP_URL(screenName, right), {
@@ -431,7 +441,7 @@ const addRight = ({right, credentials, ...user}) => {
})
}
-const deleteRight = ({right, credentials, ...user}) => {
+const deleteRight = ({ right, credentials, ...user }) => {
const screenName = user.screen_name
return fetch(PERMISSION_GROUP_URL(screenName, right), {
@@ -441,7 +451,7 @@ const deleteRight = ({right, credentials, ...user}) => {
})
}
-const setActivationStatus = ({status, credentials, ...user}) => {
+const setActivationStatus = ({ status, credentials, ...user }) => {
const screenName = user.screen_name
const body = {
status: status
@@ -457,7 +467,7 @@ const setActivationStatus = ({status, credentials, ...user}) => {
})
}
-const deleteUser = ({credentials, ...user}) => {
+const deleteUser = ({ credentials, ...user }) => {
const screenName = user.screen_name
const headers = authHeaders(credentials)
@@ -467,7 +477,15 @@ const deleteUser = ({credentials, ...user}) => {
})
}
-const fetchTimeline = ({timeline, credentials, since = false, until = false, userId = false, tag = false, withMuted = false}) => {
+const fetchTimeline = ({
+ timeline,
+ credentials,
+ since = false,
+ until = false,
+ userId = false,
+ tag = false,
+ withMuted = false
+}) => {
const timelineUrls = {
public: MASTODON_PUBLIC_TIMELINE,
friends: MASTODON_USER_HOME_TIMELINE_URL,
@@ -544,26 +562,6 @@ const verifyCredentials = (user) => {
}
})
.then((data) => data.error ? data : parseUser(data))
- .then((mastoUser) => {
- // REMOVE WHEN BE SUPPORTS background_image
- return fetch(GET_BACKGROUND_HACK, {
- method: 'POST',
- headers: authHeaders(user)
- })
- .then((response) => {
- if (response.ok) {
- return response.json()
- } else {
- return {}
- }
- })
- /* eslint-disable camelcase */
- .then(({ background_image }) => ({
- ...mastoUser,
- background_image
- }))
- /* eslint-enable camelcase */
- })
}
const favorite = ({ id, credentials }) => {
@@ -586,8 +584,19 @@ const unretweet = ({ id, credentials }) => {
.then((data) => parseStatus(data))
}
-const postStatus = ({credentials, status, spoilerText, visibility, sensitive, mediaIds = [], inReplyToStatusId, contentType}) => {
+const postStatus = ({
+ credentials,
+ status,
+ spoilerText,
+ visibility,
+ sensitive,
+ poll,
+ mediaIds = [],
+ inReplyToStatusId,
+ contentType
+}) => {
const form = new FormData()
+ const pollOptions = poll.options || []
form.append('status', status)
form.append('source', 'Pleroma FE')
@@ -598,6 +607,19 @@ const postStatus = ({credentials, status, spoilerText, visibility, sensitive, me
mediaIds.forEach(val => {
form.append('media_ids[]', val)
})
+ if (pollOptions.some(option => option !== '')) {
+ const normalizedPoll = {
+ expires_in: poll.expiresIn,
+ multiple: poll.multiple
+ }
+ Object.keys(normalizedPoll).forEach(key => {
+ form.append(`poll[${key}]`, normalizedPoll[key])
+ })
+
+ pollOptions.forEach(option => {
+ form.append('poll[options][]', option)
+ })
+ }
if (inReplyToStatusId) {
form.append('in_reply_to_id', inReplyToStatusId)
}
@@ -626,7 +648,7 @@ const deleteStatus = ({ id, credentials }) => {
})
}
-const uploadMedia = ({formData, credentials}) => {
+const uploadMedia = ({ formData, credentials }) => {
return fetch(MASTODON_MEDIA_UPLOAD_URL, {
body: formData,
method: 'POST',
@@ -636,7 +658,7 @@ const uploadMedia = ({formData, credentials}) => {
.then((data) => parseAttachment(data))
}
-const importBlocks = ({file, credentials}) => {
+const importBlocks = ({ file, credentials }) => {
const formData = new FormData()
formData.append('list', file)
return fetch(BLOCKS_IMPORT_URL, {
@@ -647,7 +669,7 @@ const importBlocks = ({file, credentials}) => {
.then((response) => response.ok)
}
-const importFollows = ({file, credentials}) => {
+const importFollows = ({ file, credentials }) => {
const formData = new FormData()
formData.append('list', file)
return fetch(FOLLOW_IMPORT_URL, {
@@ -658,7 +680,7 @@ const importFollows = ({file, credentials}) => {
.then((response) => response.ok)
}
-const deleteAccount = ({credentials, password}) => {
+const deleteAccount = ({ credentials, password }) => {
const form = new FormData()
form.append('password', password)
@@ -671,7 +693,7 @@ const deleteAccount = ({credentials, password}) => {
.then((response) => response.json())
}
-const changePassword = ({credentials, password, newPassword, newPasswordConfirmation}) => {
+const changePassword = ({ credentials, password, newPassword, newPasswordConfirmation }) => {
const form = new FormData()
form.append('password', password)
@@ -686,14 +708,14 @@ const changePassword = ({credentials, password, newPassword, newPasswordConfirma
.then((response) => response.json())
}
-const settingsMFA = ({credentials}) => {
+const settingsMFA = ({ credentials }) => {
return fetch(MFA_SETTINGS_URL, {
headers: authHeaders(credentials),
method: 'GET'
}).then((data) => data.json())
}
-const mfaDisableOTP = ({credentials, password}) => {
+const mfaDisableOTP = ({ credentials, password }) => {
const form = new FormData()
form.append('password', password)
@@ -706,7 +728,7 @@ const mfaDisableOTP = ({credentials, password}) => {
.then((response) => response.json())
}
-const mfaConfirmOTP = ({credentials, password, token}) => {
+const mfaConfirmOTP = ({ credentials, password, token }) => {
const form = new FormData()
form.append('password', password)
@@ -718,38 +740,46 @@ const mfaConfirmOTP = ({credentials, password, token}) => {
method: 'POST'
}).then((data) => data.json())
}
-const mfaSetupOTP = ({credentials}) => {
+const mfaSetupOTP = ({ credentials }) => {
return fetch(MFA_SETUP_OTP_URL, {
headers: authHeaders(credentials),
method: 'GET'
}).then((data) => data.json())
}
-const generateMfaBackupCodes = ({credentials}) => {
+const generateMfaBackupCodes = ({ credentials }) => {
return fetch(MFA_BACKUP_CODES_URL, {
headers: authHeaders(credentials),
method: 'GET'
}).then((data) => data.json())
}
-const fetchMutes = ({credentials}) => {
+const fetchMutes = ({ credentials }) => {
return promisedRequest({ url: MASTODON_USER_MUTES_URL, credentials })
.then((users) => users.map(parseUser))
}
-const muteUser = ({id, credentials}) => {
+const muteUser = ({ id, credentials }) => {
return promisedRequest({ url: MASTODON_MUTE_USER_URL(id), credentials, method: 'POST' })
}
-const unmuteUser = ({id, credentials}) => {
+const unmuteUser = ({ id, credentials }) => {
return promisedRequest({ url: MASTODON_UNMUTE_USER_URL(id), credentials, method: 'POST' })
}
-const fetchBlocks = ({credentials}) => {
+const subscribeUser = ({ id, credentials }) => {
+ return promisedRequest({ url: MASTODON_SUBSCRIBE_USER(id), credentials, method: 'POST' })
+}
+
+const unsubscribeUser = ({ id, credentials }) => {
+ return promisedRequest({ url: MASTODON_UNSUBSCRIBE_USER(id), credentials, method: 'POST' })
+}
+
+const fetchBlocks = ({ credentials }) => {
return promisedRequest({ url: MASTODON_USER_BLOCKS_URL, credentials })
.then((users) => users.map(parseUser))
}
-const fetchOAuthTokens = ({credentials}) => {
+const fetchOAuthTokens = ({ credentials }) => {
const url = '/api/oauth_tokens.json'
return fetch(url, {
@@ -762,7 +792,7 @@ const fetchOAuthTokens = ({credentials}) => {
})
}
-const revokeOAuthToken = ({id, credentials}) => {
+const revokeOAuthToken = ({ id, credentials }) => {
const url = `/api/oauth_tokens/${id}`
return fetch(url, {
@@ -771,13 +801,13 @@ const revokeOAuthToken = ({id, credentials}) => {
})
}
-const suggestions = ({credentials}) => {
+const suggestions = ({ credentials }) => {
return fetch(SUGGESTIONS_URL, {
headers: authHeaders(credentials)
}).then((data) => data.json())
}
-const markNotificationsAsSeen = ({id, credentials}) => {
+const markNotificationsAsSeen = ({ id, credentials }) => {
const body = new FormData()
body.append('latest_id', id)
@@ -789,15 +819,39 @@ const markNotificationsAsSeen = ({id, credentials}) => {
}).then((data) => data.json())
}
-const fetchFavoritedByUsers = ({id}) => {
+const vote = ({ pollId, choices, credentials }) => {
+ const form = new FormData()
+ form.append('choices', choices)
+
+ return promisedRequest({
+ url: MASTODON_VOTE_URL(encodeURIComponent(pollId)),
+ method: 'POST',
+ credentials,
+ payload: {
+ choices: choices
+ }
+ })
+}
+
+const fetchPoll = ({ pollId, credentials }) => {
+ return promisedRequest(
+ {
+ url: MASTODON_POLL_URL(encodeURIComponent(pollId)),
+ method: 'GET',
+ credentials
+ }
+ )
+}
+
+const fetchFavoritedByUsers = ({ id }) => {
return promisedRequest({ url: MASTODON_STATUS_FAVORITEDBY_URL(id) }).then((users) => users.map(parseUser))
}
-const fetchRebloggedByUsers = ({id}) => {
+const fetchRebloggedByUsers = ({ id }) => {
return promisedRequest({ url: MASTODON_STATUS_REBLOGGEDBY_URL(id) }).then((users) => users.map(parseUser))
}
-const reportUser = ({credentials, userId, statusIds, comment, forward}) => {
+const reportUser = ({ credentials, userId, statusIds, comment, forward }) => {
return promisedRequest({
url: MASTODON_REPORT_USER_URL,
method: 'POST',
@@ -811,6 +865,60 @@ const reportUser = ({credentials, userId, statusIds, comment, forward}) => {
})
}
+const searchUsers = ({ credentials, query }) => {
+ return promisedRequest({
+ url: MASTODON_USER_SEARCH_URL,
+ params: {
+ q: query,
+ resolve: true
+ },
+ credentials
+ })
+ .then((data) => data.map(parseUser))
+}
+
+const search2 = ({ credentials, q, resolve, limit, offset, following }) => {
+ let url = MASTODON_SEARCH_2
+ let params = []
+
+ if (q) {
+ params.push(['q', encodeURIComponent(q)])
+ }
+
+ if (resolve) {
+ params.push(['resolve', resolve])
+ }
+
+ if (limit) {
+ params.push(['limit', limit])
+ }
+
+ if (offset) {
+ params.push(['offset', offset])
+ }
+
+ if (following) {
+ params.push(['following', true])
+ }
+
+ let queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&')
+ url += `?${queryString}`
+
+ return fetch(url, { headers: authHeaders(credentials) })
+ .then((data) => {
+ if (data.ok) {
+ return data
+ }
+ throw new Error('Error fetching search result', data)
+ })
+ .then((data) => { return data.json() })
+ .then((data) => {
+ data.accounts = data.accounts.slice(0, limit).map(u => parseUser(u))
+ data.statuses = data.statuses.slice(0, limit).map(s => parseStatus(s))
+ return data
+ })
+}
+
const apiService = {
verifyCredentials,
fetchTimeline,
@@ -824,6 +932,8 @@ const apiService = {
unfollowUser,
pinOwnStatus,
unpinOwnStatus,
+ muteConversation,
+ unmuteConversation,
blockUser,
unblockUser,
fetchUser,
@@ -838,6 +948,8 @@ const apiService = {
fetchMutes,
muteUser,
unmuteUser,
+ subscribeUser,
+ unsubscribeUser,
fetchBlocks,
fetchOAuthTokens,
revokeOAuthToken,
@@ -868,10 +980,14 @@ const apiService = {
denyUser,
suggestions,
markNotificationsAsSeen,
+ vote,
+ fetchPoll,
fetchFavoritedByUsers,
fetchRebloggedByUsers,
reportUser,
- updateNotificationSettings
+ updateNotificationSettings,
+ search2,
+ searchUsers
}
export default apiService
diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js
index 07093b5c..846d9415 100644
--- a/src/services/backend_interactor_service/backend_interactor_service.js
+++ b/src/services/backend_interactor_service/backend_interactor_service.js
@@ -2,57 +2,57 @@ import apiService from '../api/api.service.js'
import timelineFetcherService from '../timeline_fetcher/timeline_fetcher.service.js'
import notificationsFetcher from '../notifications_fetcher/notifications_fetcher.service.js'
-const backendInteractorService = (credentials) => {
- const fetchStatus = ({id}) => {
- return apiService.fetchStatus({id, credentials})
+const backendInteractorService = credentials => {
+ const fetchStatus = ({ id }) => {
+ return apiService.fetchStatus({ id, credentials })
}
- const fetchConversation = ({id}) => {
- return apiService.fetchConversation({id, credentials})
+ const fetchConversation = ({ id }) => {
+ return apiService.fetchConversation({ id, credentials })
}
- const fetchFriends = ({id, maxId, sinceId, limit}) => {
- return apiService.fetchFriends({id, maxId, sinceId, limit, credentials})
+ const fetchFriends = ({ id, maxId, sinceId, limit }) => {
+ return apiService.fetchFriends({ id, maxId, sinceId, limit, credentials })
}
- const exportFriends = ({id}) => {
- return apiService.exportFriends({id, credentials})
+ const exportFriends = ({ id }) => {
+ return apiService.exportFriends({ id, credentials })
}
- const fetchFollowers = ({id, maxId, sinceId, limit}) => {
- return apiService.fetchFollowers({id, maxId, sinceId, limit, credentials})
+ const fetchFollowers = ({ id, maxId, sinceId, limit }) => {
+ return apiService.fetchFollowers({ id, maxId, sinceId, limit, credentials })
}
- const fetchUser = ({id}) => {
- return apiService.fetchUser({id, credentials})
+ const fetchUser = ({ id }) => {
+ return apiService.fetchUser({ id, credentials })
}
- const fetchUserRelationship = ({id}) => {
- return apiService.fetchUserRelationship({id, credentials})
+ const fetchUserRelationship = ({ id }) => {
+ return apiService.fetchUserRelationship({ id, credentials })
}
const followUser = (id) => {
- return apiService.followUser({credentials, id})
+ return apiService.followUser({ credentials, id })
}
const unfollowUser = (id) => {
- return apiService.unfollowUser({credentials, id})
+ return apiService.unfollowUser({ credentials, id })
}
const blockUser = (id) => {
- return apiService.blockUser({credentials, id})
+ return apiService.blockUser({ credentials, id })
}
const unblockUser = (id) => {
- return apiService.unblockUser({credentials, id})
+ return apiService.unblockUser({ credentials, id })
}
const approveUser = (id) => {
- return apiService.approveUser({credentials, id})
+ return apiService.approveUser({ credentials, id })
}
const denyUser = (id) => {
- return apiService.denyUser({credentials, id})
+ return apiService.denyUser({ credentials, id })
}
const startFetchingTimeline = ({ timeline, store, userId = false, tag }) => {
@@ -63,73 +63,96 @@ const backendInteractorService = (credentials) => {
return notificationsFetcher.startFetching({ store, credentials })
}
- const tagUser = ({screen_name}, tag) => {
- return apiService.tagUser({screen_name, tag, credentials})
+ // eslint-disable-next-line camelcase
+ const tagUser = ({ screen_name }, tag) => {
+ return apiService.tagUser({ screen_name, tag, credentials })
}
- const untagUser = ({screen_name}, tag) => {
- return apiService.untagUser({screen_name, tag, credentials})
+ // eslint-disable-next-line camelcase
+ const untagUser = ({ screen_name }, tag) => {
+ return apiService.untagUser({ screen_name, tag, credentials })
}
- const addRight = ({screen_name}, right) => {
- return apiService.addRight({screen_name, right, credentials})
+ // eslint-disable-next-line camelcase
+ const addRight = ({ screen_name }, right) => {
+ return apiService.addRight({ screen_name, right, credentials })
}
- const deleteRight = ({screen_name}, right) => {
- return apiService.deleteRight({screen_name, right, credentials})
+ // eslint-disable-next-line camelcase
+ const deleteRight = ({ screen_name }, right) => {
+ return apiService.deleteRight({ screen_name, right, credentials })
}
- const setActivationStatus = ({screen_name}, status) => {
- return apiService.setActivationStatus({screen_name, status, credentials})
+ // eslint-disable-next-line camelcase
+ const setActivationStatus = ({ screen_name }, status) => {
+ return apiService.setActivationStatus({ screen_name, status, credentials })
}
- const deleteUser = ({screen_name}) => {
- return apiService.deleteUser({screen_name, credentials})
+ // eslint-disable-next-line camelcase
+ const deleteUser = ({ screen_name }) => {
+ return apiService.deleteUser({ screen_name, credentials })
}
- const updateNotificationSettings = ({settings}) => {
- return apiService.updateNotificationSettings({credentials, settings})
+ const vote = (pollId, choices) => {
+ return apiService.vote({ credentials, pollId, choices })
}
- const fetchMutes = () => apiService.fetchMutes({credentials})
- const muteUser = (id) => apiService.muteUser({credentials, id})
- const unmuteUser = (id) => apiService.unmuteUser({credentials, id})
- const fetchBlocks = () => apiService.fetchBlocks({credentials})
- const fetchFollowRequests = () => apiService.fetchFollowRequests({credentials})
- const fetchOAuthTokens = () => apiService.fetchOAuthTokens({credentials})
- const revokeOAuthToken = (id) => apiService.revokeOAuthToken({id, credentials})
- const fetchPinnedStatuses = (id) => apiService.fetchPinnedStatuses({credentials, id})
- const pinOwnStatus = (id) => apiService.pinOwnStatus({credentials, id})
- const unpinOwnStatus = (id) => apiService.unpinOwnStatus({credentials, id})
-
- const getCaptcha = () => apiService.getCaptcha()
- const register = (params) => apiService.register({ credentials, params })
- const updateAvatar = ({avatar}) => apiService.updateAvatar({credentials, avatar})
- const updateBg = ({params}) => apiService.updateBg({credentials, params})
- const updateBanner = ({banner}) => apiService.updateBanner({credentials, banner})
- const updateProfile = ({params}) => apiService.updateProfile({credentials, params})
-
- const externalProfile = (profileUrl) => apiService.externalProfile({profileUrl, credentials})
- const importBlocks = (file) => apiService.importBlocks({file, credentials})
- const importFollows = (file) => apiService.importFollows({file, credentials})
-
- const deleteAccount = ({password}) => apiService.deleteAccount({credentials, password})
- const changePassword = ({password, newPassword, newPasswordConfirmation}) => apiService.changePassword({credentials, password, newPassword, newPasswordConfirmation})
+ const fetchPoll = (pollId) => {
+ return apiService.fetchPoll({ credentials, pollId })
+ }
- const fetchSettingsMFA = () => apiService.settingsMFA({credentials})
- const generateMfaBackupCodes = () => apiService.generateMfaBackupCodes({credentials})
- const mfaSetupOTP = () => apiService.mfaSetupOTP({credentials})
- const mfaConfirmOTP = ({password, token}) => apiService.mfaConfirmOTP({credentials, password, token})
- const mfaDisableOTP = ({password}) => apiService.mfaDisableOTP({credentials, password})
+ const updateNotificationSettings = ({ settings }) => {
+ return apiService.updateNotificationSettings({ credentials, settings })
+ }
- const fetchFavoritedByUsers = (id) => apiService.fetchFavoritedByUsers({id})
- const fetchRebloggedByUsers = (id) => apiService.fetchRebloggedByUsers({id})
- const reportUser = (params) => apiService.reportUser({credentials, ...params})
+ const fetchMutes = () => apiService.fetchMutes({ credentials })
+ const muteUser = (id) => apiService.muteUser({ credentials, id })
+ const unmuteUser = (id) => apiService.unmuteUser({ credentials, id })
+ const subscribeUser = (id) => apiService.subscribeUser({ credentials, id })
+ const unsubscribeUser = (id) => apiService.unsubscribeUser({ credentials, id })
+ const fetchBlocks = () => apiService.fetchBlocks({ credentials })
+ const fetchFollowRequests = () => apiService.fetchFollowRequests({ credentials })
+ const fetchOAuthTokens = () => apiService.fetchOAuthTokens({ credentials })
+ const revokeOAuthToken = (id) => apiService.revokeOAuthToken({ id, credentials })
+ const fetchPinnedStatuses = (id) => apiService.fetchPinnedStatuses({ credentials, id })
+ const pinOwnStatus = (id) => apiService.pinOwnStatus({ credentials, id })
+ const unpinOwnStatus = (id) => apiService.unpinOwnStatus({ credentials, id })
+ const muteConversation = (id) => apiService.muteConversation({ credentials, id })
+ const unmuteConversation = (id) => apiService.unmuteConversation({ credentials, id })
- const favorite = (id) => apiService.favorite({id, credentials})
- const unfavorite = (id) => apiService.unfavorite({id, credentials})
- const retweet = (id) => apiService.retweet({id, credentials})
- const unretweet = (id) => apiService.unretweet({id, credentials})
+ const getCaptcha = () => apiService.getCaptcha()
+ const register = (params) => apiService.register({ credentials, params })
+ const updateAvatar = ({ avatar }) => apiService.updateAvatar({ credentials, avatar })
+ const updateBg = ({ background }) => apiService.updateBg({ credentials, background })
+ const updateBanner = ({ banner }) => apiService.updateBanner({ credentials, banner })
+ const updateProfile = ({ params }) => apiService.updateProfile({ credentials, params })
+
+ const externalProfile = (profileUrl) => apiService.externalProfile({ profileUrl, credentials })
+
+ const importBlocks = (file) => apiService.importBlocks({ file, credentials })
+ const importFollows = (file) => apiService.importFollows({ file, credentials })
+
+ const deleteAccount = ({ password }) => apiService.deleteAccount({ credentials, password })
+ const changePassword = ({ password, newPassword, newPasswordConfirmation }) =>
+ apiService.changePassword({ credentials, password, newPassword, newPasswordConfirmation })
+
+ const fetchSettingsMFA = () => apiService.settingsMFA({ credentials })
+ const generateMfaBackupCodes = () => apiService.generateMfaBackupCodes({ credentials })
+ const mfaSetupOTP = () => apiService.mfaSetupOTP({ credentials })
+ const mfaConfirmOTP = ({ password, token }) => apiService.mfaConfirmOTP({ credentials, password, token })
+ const mfaDisableOTP = ({ password }) => apiService.mfaDisableOTP({ credentials, password })
+
+ const fetchFavoritedByUsers = (id) => apiService.fetchFavoritedByUsers({ id })
+ const fetchRebloggedByUsers = (id) => apiService.fetchRebloggedByUsers({ id })
+ const reportUser = (params) => apiService.reportUser({ credentials, ...params })
+
+ const favorite = (id) => apiService.favorite({ id, credentials })
+ const unfavorite = (id) => apiService.unfavorite({ id, credentials })
+ const retweet = (id) => apiService.retweet({ id, credentials })
+ const unretweet = (id) => apiService.unretweet({ id, credentials })
+ const search2 = ({ q, resolve, limit, offset, following }) =>
+ apiService.search2({ credentials, q, resolve, limit, offset, following })
+ const searchUsers = (query) => apiService.searchUsers({ query, credentials })
const backendInteractorServiceInstance = {
fetchStatus,
@@ -149,12 +172,16 @@ const backendInteractorService = (credentials) => {
fetchMutes,
muteUser,
unmuteUser,
+ subscribeUser,
+ unsubscribeUser,
fetchBlocks,
fetchOAuthTokens,
revokeOAuthToken,
fetchPinnedStatuses,
pinOwnStatus,
unpinOwnStatus,
+ muteConversation,
+ unmuteConversation,
tagUser,
untagUser,
addRight,
@@ -180,6 +207,8 @@ const backendInteractorService = (credentials) => {
fetchFollowRequests,
approveUser,
denyUser,
+ vote,
+ fetchPoll,
fetchFavoritedByUsers,
fetchRebloggedByUsers,
reportUser,
@@ -187,7 +216,9 @@ const backendInteractorService = (credentials) => {
unfavorite,
retweet,
unretweet,
- updateNotificationSettings
+ updateNotificationSettings,
+ search2,
+ searchUsers
}
return backendInteractorServiceInstance
diff --git a/src/services/color_convert/color_convert.js b/src/services/color_convert/color_convert.js
index 7576c518..d1b17c61 100644
--- a/src/services/color_convert/color_convert.js
+++ b/src/services/color_convert/color_convert.js
@@ -59,7 +59,7 @@ const srgbToLinear = (srgb) => {
* @returns {Number} relative luminance
*/
const relativeLuminance = (srgb) => {
- const {r, g, b} = srgbToLinear(srgb)
+ const { r, g, b } = srgbToLinear(srgb)
return 0.2126 * r + 0.7152 * g + 0.0722 * b
}
diff --git a/src/services/completion/completion.js b/src/services/completion/completion.js
index 11c45867..df83d03d 100644
--- a/src/services/completion/completion.js
+++ b/src/services/completion/completion.js
@@ -8,7 +8,7 @@ export const wordAtPosition = (str, pos) => {
const words = splitIntoWords(str)
const wordsWithPosition = addPositionToWords(words)
- return find(wordsWithPosition, ({start, end}) => start <= pos && end > pos)
+ return find(wordsWithPosition, ({ start, end }) => start <= pos && end > pos)
}
export const addPositionToWords = (words) => {
diff --git a/src/services/date_utils/date_utils.js b/src/services/date_utils/date_utils.js
new file mode 100644
index 00000000..32e13bca
--- /dev/null
+++ b/src/services/date_utils/date_utils.js
@@ -0,0 +1,45 @@
+export const SECOND = 1000
+export const MINUTE = 60 * SECOND
+export const HOUR = 60 * MINUTE
+export const DAY = 24 * HOUR
+export const WEEK = 7 * DAY
+export const MONTH = 30 * DAY
+export const YEAR = 365.25 * DAY
+
+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' }
+ if (d < nowThreshold * SECOND) {
+ r.num = 0
+ r.key = 'time.now'
+ } else if (d < MINUTE) {
+ r.num = round(d / SECOND)
+ r.key = 'time.seconds'
+ } else if (d < HOUR) {
+ r.num = round(d / MINUTE)
+ r.key = 'time.minutes'
+ } else if (d < DAY) {
+ r.num = round(d / HOUR)
+ r.key = 'time.hours'
+ } else if (d < WEEK) {
+ r.num = round(d / DAY)
+ r.key = 'time.days'
+ } else if (d < MONTH) {
+ r.num = round(d / WEEK)
+ r.key = 'time.weeks'
+ } else if (d < YEAR) {
+ r.num = round(d / MONTH)
+ r.key = 'time.months'
+ }
+ // Remove plural form when singular
+ if (r.num === 1) r.key = r.key.slice(0, -1)
+ return r
+}
+
+export const relativeTimeShort = (date, nowThreshold = 1) => {
+ const r = relativeTime(date, nowThreshold)
+ r.key += '_short'
+ return r
+}
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 0e55ed2a..6cc1851d 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -60,13 +60,21 @@ export const parseUser = (data) => {
if (data.pleroma) {
const relationship = data.pleroma.relationship
+ output.background_image = data.pleroma.background_image
+ output.token = data.pleroma.chat_token
+
if (relationship) {
output.follows_you = relationship.followed_by
+ output.requested = relationship.requested
output.following = relationship.following
output.statusnet_blocking = relationship.blocking
output.muted = relationship.muting
+ output.subscribed = relationship.subscribing
}
+ output.hide_follows = data.pleroma.hide_follows
+ output.hide_followers = data.pleroma.hide_followers
+
output.rights = {
moderator: data.pleroma.is_moderator,
admin: data.pleroma.is_admin
@@ -145,7 +153,7 @@ export const parseUser = (data) => {
output.statuses_count = data.statuses_count
output.friendIds = []
output.followerIds = []
- output.pinnedStatuseIds = []
+ output.pinnedStatusIds = []
if (data.pleroma) {
output.follow_request_count = data.pleroma.follow_request_count
@@ -231,7 +239,9 @@ export const parseStatus = (data) => {
output.summary_html = addEmojis(data.spoiler_text, data.emojis)
output.external_url = data.url
+ output.poll = data.poll
output.pinned = data.pinned
+ output.muted = data.muted
} else {
output.favorited = data.favorited
output.fave_num = data.fave_num
diff --git a/src/services/errors/errors.js b/src/services/errors/errors.js
index 548f3c68..590552da 100644
--- a/src/services/errors/errors.js
+++ b/src/services/errors/errors.js
@@ -1,3 +1,5 @@
+import { humanizeErrors } from '../../modules/errors'
+
export function StatusCodeError (statusCode, body, options, response) {
this.name = 'StatusCodeError'
this.statusCode = statusCode
@@ -12,3 +14,36 @@ export function StatusCodeError (statusCode, body, options, response) {
}
StatusCodeError.prototype = Object.create(Error.prototype)
StatusCodeError.prototype.constructor = StatusCodeError
+
+export class RegistrationError extends Error {
+ constructor (error) {
+ super()
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this)
+ }
+
+ try {
+ // the error is probably a JSON object with a single key, "errors", whose value is another JSON object containing the real errors
+ if (typeof error === 'string') {
+ error = JSON.parse(error)
+ if (error.hasOwnProperty('error')) {
+ error = JSON.parse(error.error)
+ }
+ }
+
+ if (typeof error === 'object') {
+ // replace ap_id with username
+ if (error.ap_id) {
+ error.username = error.ap_id
+ delete error.ap_id
+ }
+ this.message = humanizeErrors(error)
+ } else {
+ this.message = error
+ }
+ } catch (e) {
+ // can't parse it, so just treat it like a string
+ this.message = error
+ }
+ }
+}
diff --git a/src/services/file_size_format/file_size_format.js b/src/services/file_size_format/file_size_format.js
index add56ee0..7e6cd4d7 100644
--- a/src/services/file_size_format/file_size_format.js
+++ b/src/services/file_size_format/file_size_format.js
@@ -9,7 +9,7 @@ const fileSizeFormat = (num) => {
exponent = Math.min(Math.floor(Math.log(num) / Math.log(1024)), units.length - 1)
num = (num / Math.pow(1024, exponent)).toFixed(2) * 1
unit = units[exponent]
- return {num: num, unit: unit}
+ return { num: num, unit: unit }
}
const fileSizeFormatService = {
fileSizeFormat
diff --git a/src/services/follow_manipulate/follow_manipulate.js b/src/services/follow_manipulate/follow_manipulate.js
index b2486e7c..529fdb9b 100644
--- a/src/services/follow_manipulate/follow_manipulate.js
+++ b/src/services/follow_manipulate/follow_manipulate.js
@@ -2,17 +2,17 @@ const fetchUser = (attempt, user, store) => new Promise((resolve, reject) => {
setTimeout(() => {
store.state.api.backendInteractor.fetchUser({ id: user.id })
.then((user) => store.commit('addNewUsers', [user]))
- .then(() => resolve([user.following, attempt]))
+ .then(() => resolve([user.following, user.requested, user.locked, attempt]))
.catch((e) => reject(e))
}, 500)
-}).then(([following, attempt]) => {
- if (!following && attempt <= 3) {
+}).then(([following, sent, locked, attempt]) => {
+ if (!following && !(locked && sent) && attempt <= 3) {
// If we BE reports that we still not following that user - retry,
// increment attempts by one
return fetchUser(++attempt, user, store)
} else {
// If we run out of attempts, just return whatever status is.
- return following
+ return sent
}
})
@@ -21,14 +21,10 @@ export const requestFollow = (user, store) => new Promise((resolve, reject) => {
.then((updated) => {
store.commit('updateUserRelationship', [updated])
- // For locked users we just mark it that we sent the follow request
- if (updated.locked) {
- resolve({ sent: true })
- }
-
- if (updated.following) {
- // If we get result immediately, just stop.
- resolve({ sent: false })
+ if (updated.following || (user.locked && user.requested)) {
+ // If we get result immediately or the account is locked, just stop.
+ resolve({ sent: updated.requested })
+ return
}
// But usually we don't get result immediately, so we ask server
@@ -39,14 +35,8 @@ export const requestFollow = (user, store) => new Promise((resolve, reject) => {
// Recursive Promise, it will call itself up to 3 times.
return fetchUser(1, user, store)
- .then((following) => {
- if (following) {
- // We confirmed and everything's good.
- resolve({ sent: false })
- } else {
- // If after all the tries, just treat it as if user is locked
- resolve({ sent: false })
- }
+ .then((sent) => {
+ resolve({ sent })
})
})
})
diff --git a/src/services/follow_request_fetcher/follow_request_fetcher.service.js b/src/services/follow_request_fetcher/follow_request_fetcher.service.js
index 125ff3e1..786740b7 100644
--- a/src/services/follow_request_fetcher/follow_request_fetcher.service.js
+++ b/src/services/follow_request_fetcher/follow_request_fetcher.service.js
@@ -8,7 +8,7 @@ const fetchAndUpdate = ({ store, credentials }) => {
.catch(() => {})
}
-const startFetching = ({credentials, store}) => {
+const startFetching = ({ credentials, store }) => {
fetchAndUpdate({ credentials, store })
const boundFetchAndUpdate = () => fetchAndUpdate({ credentials, store })
return setInterval(boundFetchAndUpdate, 10000)
diff --git a/src/services/new_api/mfa.js b/src/services/new_api/mfa.js
index ddf90e6b..cbba06d5 100644
--- a/src/services/new_api/mfa.js
+++ b/src/services/new_api/mfa.js
@@ -1,4 +1,4 @@
-const verifyOTPCode = ({app, instance, mfaToken, code}) => {
+const verifyOTPCode = ({ app, instance, mfaToken, code }) => {
const url = `${instance}/oauth/mfa/challenge`
const form = new window.FormData()
@@ -14,7 +14,7 @@ const verifyOTPCode = ({app, instance, mfaToken, code}) => {
}).then((data) => data.json())
}
-const verifyRecoveryCode = ({app, instance, mfaToken, code}) => {
+const verifyRecoveryCode = ({ app, instance, mfaToken, code }) => {
const url = `${instance}/oauth/mfa/challenge`
const form = new window.FormData()
diff --git a/src/services/new_api/oauth.js b/src/services/new_api/oauth.js
index 030e9980..d0d18c03 100644
--- a/src/services/new_api/oauth.js
+++ b/src/services/new_api/oauth.js
@@ -93,7 +93,7 @@ export const getClientToken = ({ clientId, clientSecret, instance }) => {
body: form
}).then((data) => data.json())
}
-const verifyOTPCode = ({app, instance, mfaToken, code}) => {
+const verifyOTPCode = ({ app, instance, mfaToken, code }) => {
const url = `${instance}/oauth/mfa/challenge`
const form = new window.FormData()
@@ -109,7 +109,7 @@ const verifyOTPCode = ({app, instance, mfaToken, code}) => {
}).then((data) => data.json())
}
-const verifyRecoveryCode = ({app, instance, mfaToken, code}) => {
+const verifyRecoveryCode = ({ app, instance, mfaToken, code }) => {
const url = `${instance}/oauth/mfa/challenge`
const form = new window.FormData()
@@ -125,13 +125,28 @@ const verifyRecoveryCode = ({app, instance, mfaToken, code}) => {
}).then((data) => data.json())
}
+const revokeToken = ({ app, instance, token }) => {
+ const url = `${instance}/oauth/revoke`
+ const form = new window.FormData()
+
+ form.append('client_id', app.clientId)
+ form.append('client_secret', app.clientSecret)
+ form.append('token', token)
+
+ return window.fetch(url, {
+ method: 'POST',
+ body: form
+ }).then((data) => data.json())
+}
+
const oauth = {
login,
getToken,
getTokenWithCredentials,
getOrCreateApp,
verifyOTPCode,
- verifyRecoveryCode
+ verifyRecoveryCode,
+ revokeToken
}
export default oauth
diff --git a/src/services/new_api/user_search.js b/src/services/new_api/user_search.js
deleted file mode 100644
index 869afa9c..00000000
--- a/src/services/new_api/user_search.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import utils from './utils.js'
-import { parseUser } from '../entity_normalizer/entity_normalizer.service.js'
-
-const search = ({query, store}) => {
- return utils.request({
- store,
- url: '/api/v1/accounts/search',
- params: {
- q: query
- }
- })
- .then((data) => data.json())
- .then((data) => data.map(parseUser))
-}
-const UserSearch = {
- search
-}
-
-export default UserSearch
diff --git a/src/services/new_api/utils.js b/src/services/new_api/utils.js
deleted file mode 100644
index 6696573b..00000000
--- a/src/services/new_api/utils.js
+++ /dev/null
@@ -1,36 +0,0 @@
-const queryParams = (params) => {
- return Object.keys(params)
- .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
- .join('&')
-}
-
-const headers = (store) => {
- const accessToken = store.getters.getToken()
- if (accessToken) {
- return { 'Authorization': `Bearer ${accessToken}` }
- } else {
- return {}
- }
-}
-
-const request = ({method = 'GET', url, params, store}) => {
- const instance = store.state.instance.server
- let fullUrl = `${instance}${url}`
-
- if (method === 'GET' && params) {
- fullUrl = fullUrl + `?${queryParams(params)}`
- }
-
- return window.fetch(fullUrl, {
- method,
- headers: headers(store),
- credentials: 'same-origin'
- })
-}
-
-const utils = {
- queryParams,
- request
-}
-
-export default utils
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
index f9cbbade..7021adbd 100644
--- a/src/services/notification_utils/notification_utils.js
+++ b/src/services/notification_utils/notification_utils.js
@@ -35,4 +35,4 @@ export const visibleNotificationsFromStore = (store, types) => {
}
export const unseenNotificationsFromStore = store =>
- filter(visibleNotificationsFromStore(store), ({seen}) => !seen)
+ filter(visibleNotificationsFromStore(store), ({ seen }) => !seen)
diff --git a/src/services/notifications_fetcher/notifications_fetcher.service.js b/src/services/notifications_fetcher/notifications_fetcher.service.js
index 60c497ae..f9ec3f6e 100644
--- a/src/services/notifications_fetcher/notifications_fetcher.service.js
+++ b/src/services/notifications_fetcher/notifications_fetcher.service.js
@@ -1,12 +1,12 @@
import apiService from '../api/api.service.js'
-const update = ({store, notifications, older}) => {
+const update = ({ store, notifications, older }) => {
store.dispatch('setNotificationsError', { value: false })
store.dispatch('addNewNotifications', { notifications, older })
}
-const fetchAndUpdate = ({store, credentials, older = false}) => {
+const fetchAndUpdate = ({ store, credentials, older = false }) => {
const args = { credentials }
const rootState = store.rootState || store.state
const timelineData = rootState.statuses.notifications
@@ -45,7 +45,7 @@ const fetchNotifications = ({ store, args, older }) => {
.catch(() => store.dispatch('setNotificationsError', { value: true }))
}
-const startFetching = ({credentials, store}) => {
+const startFetching = ({ credentials, store }) => {
fetchAndUpdate({ credentials, store })
const boundFetchAndUpdate = () => fetchAndUpdate({ credentials, store })
// Initially there's set flag to silence all desktop notifications so
diff --git a/src/services/status_poster/status_poster.service.js b/src/services/status_poster/status_poster.service.js
index e70b0f26..9e904d3a 100644
--- a/src/services/status_poster/status_poster.service.js
+++ b/src/services/status_poster/status_poster.service.js
@@ -1,10 +1,19 @@
import { map } from 'lodash'
import apiService from '../api/api.service.js'
-const postStatus = ({ store, status, spoilerText, visibility, sensitive, media = [], inReplyToStatusId = undefined, contentType = 'text/plain' }) => {
+const postStatus = ({ store, status, spoilerText, visibility, sensitive, poll, media = [], inReplyToStatusId = undefined, contentType = 'text/plain' }) => {
const mediaIds = map(media, 'id')
- return apiService.postStatus({credentials: store.state.users.currentUser.credentials, status, spoilerText, visibility, sensitive, mediaIds, inReplyToStatusId, contentType})
+ return apiService.postStatus({
+ credentials: store.state.users.currentUser.credentials,
+ status,
+ spoilerText,
+ visibility,
+ sensitive,
+ mediaIds,
+ inReplyToStatusId,
+ contentType,
+ poll })
.then((data) => {
if (!data.error) {
store.dispatch('addNewStatuses', {
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index d0b6ccbf..f186d202 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -202,6 +202,7 @@ const generateColors = (input) => {
colors.topBarLink = col.topBarLink || getTextColor(colors.topBar, colors.fgLink)
colors.faintLink = col.faintLink || Object.assign({}, col.link)
+ colors.linkBg = alphaBlend(colors.link, 0.4, colors.bg)
colors.icon = mixrgb(colors.bg, colors.text)
@@ -238,12 +239,12 @@ const generateColors = (input) => {
})
const htmlColors = Object.entries(colors)
- .reduce((acc, [k, v]) => {
- if (!v) return acc
- acc.solid[k] = rgb2hex(v)
- acc.complete[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgb2rgba(v)
- return acc
- }, { complete: {}, solid: {} })
+ .reduce((acc, [k, v]) => {
+ if (!v) return acc
+ acc.solid[k] = rgb2hex(v)
+ acc.complete[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgb2rgba(v)
+ return acc
+ }, { complete: {}, solid: {} })
return {
rules: {
colors: Object.entries(htmlColors.complete)
diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js
index 8e954cdf..f72688f8 100644
--- a/src/services/timeline_fetcher/timeline_fetcher.service.js
+++ b/src/services/timeline_fetcher/timeline_fetcher.service.js
@@ -2,7 +2,7 @@ import { camelCase } from 'lodash'
import apiService from '../api/api.service.js'
-const update = ({store, statuses, timeline, showImmediately, userId}) => {
+const update = ({ store, statuses, timeline, showImmediately, userId }) => {
const ccTimeline = camelCase(timeline)
store.dispatch('setError', { value: false })
@@ -15,7 +15,7 @@ const update = ({store, statuses, timeline, showImmediately, userId}) => {
})
}
-const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false, showImmediately = false, userId = false, tag = false, until}) => {
+const fetchAndUpdate = ({ store, credentials, timeline = 'friends', older = false, showImmediately = false, userId = false, tag = false, until }) => {
const args = { timeline, credentials }
const rootState = store.rootState || store.state
const timelineData = rootState.statuses.timelines[camelCase(timeline)]
@@ -40,17 +40,17 @@ const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false
if (!older && statuses.length >= 20 && !timelineData.loading && numStatusesBeforeFetch > 0) {
store.dispatch('queueFlush', { timeline: timeline, id: timelineData.maxId })
}
- update({store, statuses, timeline, showImmediately, userId})
+ update({ store, statuses, timeline, showImmediately, userId })
return statuses
}, () => store.dispatch('setError', { value: true }))
}
-const startFetching = ({timeline = 'friends', credentials, store, userId = false, tag = false}) => {
+const startFetching = ({ timeline = 'friends', credentials, store, userId = false, tag = false }) => {
const rootState = store.rootState || store.state
const timelineData = rootState.statuses.timelines[camelCase(timeline)]
const showImmediately = timelineData.visibleStatuses.length === 0
timelineData.userId = userId
- fetchAndUpdate({timeline, credentials, store, showImmediately, userId, tag})
+ fetchAndUpdate({ timeline, credentials, store, showImmediately, userId, tag })
const boundFetchAndUpdate = () => fetchAndUpdate({ timeline, credentials, store, userId, tag })
return setInterval(boundFetchAndUpdate, 10000)
}
diff --git a/src/services/user_highlighter/user_highlighter.js b/src/services/user_highlighter/user_highlighter.js
index f6ddfb9c..b91c0f78 100644
--- a/src/services/user_highlighter/user_highlighter.js
+++ b/src/services/user_highlighter/user_highlighter.js
@@ -1,7 +1,7 @@
import { hex2rgb } from '../color_convert/color_convert.js'
const highlightStyle = (prefs) => {
if (prefs === undefined) return
- const {color, type} = prefs
+ const { color, type } = prefs
if (typeof color !== 'string') return
const rgb = hex2rgb(color)
if (rgb == null) return
diff --git a/src/services/version/version.service.js b/src/services/version/version.service.js
index a750b0dd..2e11bf3a 100644
--- a/src/services/version/version.service.js
+++ b/src/services/version/version.service.js
@@ -1,6 +1,6 @@
export const extractCommit = versionString => {
- const regex = /-g(\w+)$/i
+ const regex = /-g(\w+)/i
const matches = versionString.match(regex)
return matches ? matches[1] : ''
}