aboutsummaryrefslogtreecommitdiff
path: root/src/services
diff options
context:
space:
mode:
authorHenry Jameson <me@hjkos.com>2019-08-31 22:38:02 +0300
committerHenry Jameson <me@hjkos.com>2019-08-31 22:38:02 +0300
commit18ec13d796c0928d09fa93de4117822d2e35502c (patch)
tree1cfb4d68a246c604396bb64bbba3e69bdf4fe511 /src/services
parentb3e9a5a71819c7d3a4b35c5b6ad551785a7ba44f (diff)
parent018a650166a5dce0878b696359a999ab67634cfc (diff)
Merge remote-tracking branch 'upstream/develop' into docs
* upstream/develop: (193 commits) fix user avatar fallback logic remove dead code make bio textarea resizable vertically only remove dead code remove dead code fix crazy watch logic in conversation show three dot button only if needed hide mute conversation button to guests update keyBy generate idObj at timeline level fix pin showing logic in conversation Show a message when JS is disabled Initialize chat only if user is logged in and it wasn't initialized before i18n/Update Japanese i18n/Update pedantic Japanese sync profile tab state with location query refactor TabSwitcher use better name of controlled prop fix potential bug to render active tab in controlled way remove unused param ...
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.js165
-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, 474 insertions, 277 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 fetchPoll = (pollId) => {
+ return apiService.fetchPoll({ credentials, pollId })
+ }
+
+ const updateNotificationSettings = ({ settings }) => {
+ return apiService.updateNotificationSettings({ credentials, settings })
+ }
+
+ 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 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 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 externalProfile = (profileUrl) => apiService.externalProfile({profileUrl, credentials})
- const importBlocks = (file) => apiService.importBlocks({file, credentials})
- const importFollows = (file) => apiService.importFollows({file, 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 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 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 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 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] : ''
}