diff --git a/app/images/avatar-missing.png b/app/images/avatar-missing.png new file mode 100644 index 000000000..b3e6b5709 Binary files /dev/null and b/app/images/avatar-missing.png differ diff --git a/app/images/avatar-missing.svg b/app/images/avatar-missing.svg new file mode 100644 index 000000000..7eb156089 --- /dev/null +++ b/app/images/avatar-missing.svg @@ -0,0 +1,116 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/app/soapbox/__fixtures__/mitra-context.json b/app/soapbox/__fixtures__/mitra-context.json new file mode 100644 index 000000000..91b48420c --- /dev/null +++ b/app/soapbox/__fixtures__/mitra-context.json @@ -0,0 +1,107 @@ +[ + { + "id": "017ed503-bc96-301a-e871-2c23b30ddd05", + "uri": "https://mitra.social/objects/017ed503-bc96-301a-e871-2c23b30ddd05", + "created_at": "2022-02-07T16:28:18.966874Z", + "account": { + "id": "017ed4f9-c121-2ae6-0805-15516cce02c3", + "username": "alex", + "acct": "alex", + "url": "https://mitra.social/users/alex", + "display_name": null, + "created_at": "2022-02-07T16:17:24.769229Z", + "note": null, + "avatar": null, + "header": null, + "fields": [], + "followers_count": 1, + "following_count": 1, + "statuses_count": 3, + "source": null, + "wallet_address": null + }, + "content": "@silverpill sup!", + "in_reply_to_id": null, + "reblog": null, + "visibility": "public", + "replies_count": 1, + "favourites_count": 0, + "reblogs_count": 0, + "media_attachments": [], + "mentions": [ + { + "id": "dd4ebc18-269d-4c7b-a310-03d29c6ab551", + "username": "silverpill", + "acct": "silverpill", + "url": "https://mitra.social/users/silverpill" + } + ], + "tags": [], + "favourited": false, + "reblogged": false, + "ipfs_cid": null, + "token_id": null, + "token_tx_id": null + }, + { + "id": "017ed505-5926-392f-256a-f86d5075df70", + "uri": "https://mitra.social/objects/017ed505-5926-392f-256a-f86d5075df70", + "created_at": "2022-02-07T16:30:04.582771Z", + "account": { + "id": "dd4ebc18-269d-4c7b-a310-03d29c6ab551", + "username": "silverpill", + "acct": "silverpill", + "url": "https://mitra.social/users/silverpill", + "display_name": "silverpill", + "created_at": "2021-11-06T21:08:57.441927Z", + "note": "Admin of mitra.social instance. It is running experimental ActivityPub server Mitra.", + "avatar": "https://mitra.social/media/6a785bf7dd05f61c3590e8935aa49156a499ac30fd1e402f79e7e164adb36e2c.png", + "header": null, + "fields": [ + { + "name": "Matrix", + "value": "@silverpill:poa.st" + }, + { + "name": "Alt", + "value": "@silverpill@poa.st" + }, + { + "name": "Code", + "value": "https://codeberg.org/silverpill/" + }, + { + "name": "$XMR", + "value": "884y9LmsWY7PQNsyR7bJy1dvj91tuF5spVabyCnPk4KfQtSuzFbQobTFC7xSemJgVW1FWAwnJbjTZX5zZWbBrfkv62DB62d" + } + ], + "followers_count": 27, + "following_count": 15, + "statuses_count": 110, + "source": null, + "wallet_address": null + }, + "content": "@alex welcome", + "in_reply_to_id": "017ed503-bc96-301a-e871-2c23b30ddd05", + "reblog": null, + "visibility": "public", + "replies_count": 0, + "favourites_count": 1, + "reblogs_count": 0, + "media_attachments": [], + "mentions": [ + { + "id": "017ed4f9-c121-2ae6-0805-15516cce02c3", + "username": "alex", + "acct": "alex", + "url": "https://mitra.social/users/alex" + } + ], + "tags": [], + "favourited": true, + "reblogged": false, + "ipfs_cid": null, + "token_id": null, + "token_tx_id": null + } +] diff --git a/app/soapbox/__fixtures__/mitra-status-with-attachments.json b/app/soapbox/__fixtures__/mitra-status-with-attachments.json new file mode 100644 index 000000000..689e4d3bb --- /dev/null +++ b/app/soapbox/__fixtures__/mitra-status-with-attachments.json @@ -0,0 +1,95 @@ +{ + "id": "017eeb0e-e5e7-98fe-6b2b-ad02349251fb", + "uri": "https://gleasonator.com/objects/aa5e66c9-0a10-4167-9c80-f40d9574aaec", + "created_at": "2022-02-11T23:11:59.891770Z", + "account": { + "id": "8fe4d6ed-3a99-43e1-a7d4-66b4e635f756", + "username": "alex", + "acct": "alex@gleasonator.com", + "url": "https://gleasonator.com/users/alex", + "display_name": "Alex Gleason", + "created_at": "2021-11-14T17:01:17.446307Z", + "note": "I create Fediverse software that empowers people online.

I'm vegan btw

Note: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.", + "avatar": "https://mitra.social/media/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png", + "header": "https://mitra.social/media/bdfb009adac0e31257e9fe527d3844a7234cc71f6e06dff2bec94354639555dd.png", + "fields": [ + { + "name": "Website", + "value": "https://alexgleason.me" + }, + { + "name": "Pleroma+Soapbox", + "value": "https://soapbox.pub" + }, + { + "name": "Email", + "value": "alex@alexgleason.me" + }, + { + "name": "Gender identity", + "value": "Soyboy" + }, + { + "name": "Donate (PayPal)", + "value": "https://paypal.me/gleasonator" + }, + { + "name": "$BTC", + "value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n" + }, + { + "name": "$ETH", + "value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717" + }, + { + "name": "$DOGE", + "value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D" + }, + { + "name": "$XMR", + "value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK" + } + ], + "followers_count": 2, + "following_count": 2, + "statuses_count": 970, + "source": null, + "wallet_address": null + }, + "content": "

Test

", + "in_reply_to_id": null, + "reblog": null, + "visibility": "public", + "replies_count": 0, + "favourites_count": 0, + "reblogs_count": 0, + "media_attachments": [ + { + "id": "017eeb0e-e5df-30a4-77a7-a929145cb836", + "type": "image", + "url": "https://mitra.social/media/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png" + }, + { + "id": "017eeb0e-e5e4-2a48-2889-afdebf368a54", + "type": "unknown", + "url": "https://mitra.social/media/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac" + }, + { + "id": "017eeb0e-e5e5-79fd-6054-8b6869b1db49", + "type": "unknown", + "url": "https://mitra.social/media/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.oga" + }, + { + "id": "017eeb0e-e5e6-c416-a444-21e560c47839", + "type": "unknown", + "url": "https://mitra.social/media/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0" + } + ], + "mentions": [], + "tags": [], + "favourited": false, + "reblogged": false, + "ipfs_cid": null, + "token_id": null, + "token_tx_id": null +} diff --git a/app/soapbox/__fixtures__/pleroma-status-with-attachments.json b/app/soapbox/__fixtures__/pleroma-status-with-attachments.json new file mode 100644 index 000000000..75db8292f --- /dev/null +++ b/app/soapbox/__fixtures__/pleroma-status-with-attachments.json @@ -0,0 +1,238 @@ +{ + "account": { + "acct": "alex", + "avatar": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png", + "avatar_static": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png", + "bot": false, + "created_at": "2020-01-08T01:25:43.000Z", + "display_name": "Alex Gleason", + "emojis": [], + "fields": [ + { + "name": "Website", + "value": "https://alexgleason.me" + }, + { + "name": "Pleroma+Soapbox", + "value": "https://soapbox.pub" + }, + { + "name": "Email", + "value": "alex@alexgleason.me" + }, + { + "name": "Gender identity", + "value": "Soyboy" + }, + { + "name": "Donate (PayPal)", + "value": "https://paypal.me/gleasonator" + }, + { + "name": "$BTC", + "value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n" + }, + { + "name": "$ETH", + "value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717" + }, + { + "name": "$DOGE", + "value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D" + }, + { + "name": "$XMR", + "value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK" + } + ], + "followers_count": 2344, + "following_count": 1564, + "fqn": "alex@gleasonator.com", + "header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png", + "header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png", + "id": "9v5bmRalQvjOy0ECcC", + "last_status_at": "2022-02-11T23:12:00", + "locked": false, + "note": "I create Fediverse software that empowers people online.

I'm vegan btw

Note: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.", + "pleroma": { + "accepts_chat_messages": true, + "also_known_as": [], + "ap_id": "https://gleasonator.com/users/alex", + "background_image": null, + "birthday": "1993-07-03", + "favicon": "https://gleasonator.com/favicon.png", + "hide_favorites": true, + "hide_followers": false, + "hide_followers_count": false, + "hide_follows": false, + "hide_follows_count": false, + "is_admin": true, + "is_confirmed": true, + "is_moderator": false, + "is_suggested": true, + "relationship": {}, + "skip_thread_containment": false, + "tags": [] + }, + "source": { + "fields": [ + { + "name": "Website", + "value": "https://alexgleason.me" + }, + { + "name": "Pleroma+Soapbox", + "value": "https://soapbox.pub" + }, + { + "name": "Email", + "value": "alex@alexgleason.me" + }, + { + "name": "Gender identity", + "value": "Soyboy" + }, + { + "name": "Donate (PayPal)", + "value": "https://paypal.me/gleasonator" + }, + { + "name": "$BTC", + "value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n" + }, + { + "name": "$ETH", + "value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717" + }, + { + "name": "$DOGE", + "value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D" + }, + { + "name": "$XMR", + "value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK" + } + ], + "note": "I create Fediverse software that empowers people online.\r\n\r\nI'm vegan btw\r\n\r\nNote: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.", + "pleroma": { + "actor_type": "Person", + "discoverable": false + }, + "sensitive": false + }, + "statuses_count": 23357, + "url": "https://gleasonator.com/users/alex", + "username": "alex" + }, + "application": { + "name": "Soapbox FE", + "website": "https://soapbox.pub/" + }, + "bookmarked": false, + "card": null, + "content": "

Test

", + "created_at": "2022-02-11T23:11:59.000Z", + "emojis": [], + "favourited": false, + "favourites_count": 1, + "id": "AGNkA21auFR5lnEAHw", + "in_reply_to_account_id": null, + "in_reply_to_id": null, + "language": null, + "media_attachments": [ + { + "blurhash": "emLqe9t7~q%M%M-;WBt7ofRj%Moft7ofoft7ayWBj[of-;j[ayofM{", + "description": "", + "id": "974611173", + "meta": { + "original": { + "aspect": 0.9944598337950139, + "height": 1444, + "width": 1436 + } + }, + "pleroma": { + "mime_type": "image/png" + }, + "preview_url": "https://media.gleasonator.com/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png", + "remote_url": "https://media.gleasonator.com/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png", + "text_url": "https://media.gleasonator.com/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png", + "type": "image", + "url": "https://media.gleasonator.com/8e04e6091bbbac79641b5812508683ce72c38693661c18d16040553f2371e18d.png" + }, + { + "blurhash": null, + "description": "", + "id": "-1764036199", + "pleroma": { + "mime_type": "application/x-nes-rom" + }, + "preview_url": "https://media.gleasonator.com/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac.nes", + "remote_url": "https://media.gleasonator.com/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac.nes", + "text_url": "https://media.gleasonator.com/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac.nes", + "type": "unknown", + "url": "https://media.gleasonator.com/8f72dc2e98572eb4ba7c3a902bca5f69c448fc4391837e5f8f0d4556280440ac.nes" + }, + { + "blurhash": null, + "description": "", + "id": "-636167741", + "pleroma": { + "mime_type": "audio/ogg" + }, + "preview_url": "https://media.gleasonator.com/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.ogg", + "remote_url": "https://media.gleasonator.com/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.ogg", + "text_url": "https://media.gleasonator.com/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.ogg", + "type": "audio", + "url": "https://media.gleasonator.com/55a81a090247cc4fc127e5716bcf7964f6e0df9b584f85f4696c0b994747a4d0.ogg" + }, + { + "blurhash": null, + "description": "", + "id": "517941208", + "pleroma": { + "mime_type": "text/plain" + }, + "preview_url": "https://media.gleasonator.com/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0.LICENSE", + "remote_url": "https://media.gleasonator.com/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0.LICENSE", + "text_url": "https://media.gleasonator.com/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0.LICENSE", + "type": "unknown", + "url": "https://media.gleasonator.com/0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0.LICENSE" + } + ], + "mentions": [], + "muted": false, + "pinned": false, + "pleroma": { + "content": { + "text/plain": "Test" + }, + "conversation_id": "AGNkA1yP66srbtjcJc", + "direct_conversation_id": null, + "emoji_reactions": [], + "expires_at": null, + "in_reply_to_account_acct": null, + "local": true, + "parent_visible": false, + "pinned_at": null, + "quote": null, + "quote_url": null, + "quote_visible": false, + "spoiler_text": { + "text/plain": "" + }, + "thread_muted": false + }, + "poll": null, + "reblog": null, + "reblogged": false, + "reblogs_count": 0, + "replies_count": 0, + "sensitive": false, + "spoiler_text": "", + "tags": [], + "text": null, + "uri": "https://gleasonator.com/objects/aa5e66c9-0a10-4167-9c80-f40d9574aaec", + "url": "https://gleasonator.com/notice/AGNkA21auFR5lnEAHw", + "visibility": "public" +} diff --git a/app/soapbox/actions/__tests__/statuses-test.js b/app/soapbox/actions/__tests__/statuses-test.js new file mode 100644 index 000000000..71a0596a4 --- /dev/null +++ b/app/soapbox/actions/__tests__/statuses-test.js @@ -0,0 +1,29 @@ +import { Map as ImmutableMap } from 'immutable'; + +import { STATUSES_IMPORT } from 'soapbox/actions/importer'; +import { __stub } from 'soapbox/api'; +import { mockStore } from 'soapbox/test_helpers'; + +import { fetchContext } from '../statuses'; + +describe('fetchContext()', () => { + it('handles Mitra context', done => { + const statuses = require('soapbox/__fixtures__/mitra-context.json'); + + __stub(mock => { + mock.onGet('/api/v1/statuses/017ed505-5926-392f-256a-f86d5075df70/context') + .reply(200, statuses); + }); + + const store = mockStore(ImmutableMap()); + + store.dispatch(fetchContext('017ed505-5926-392f-256a-f86d5075df70')).then(context => { + const actions = store.getActions(); + + expect(actions[3].type).toEqual(STATUSES_IMPORT); + expect(actions[3].statuses[0].id).toEqual('017ed503-bc96-301a-e871-2c23b30ddd05'); + + done(); + }).catch(console.error); + }); +}); diff --git a/app/soapbox/actions/external_auth.js b/app/soapbox/actions/external_auth.js index b3258ab70..c6fc5d340 100644 --- a/app/soapbox/actions/external_auth.js +++ b/app/soapbox/actions/external_auth.js @@ -13,7 +13,9 @@ import { authLoggedIn, verifyCredentials, switchAccount } from 'soapbox/actions/ import { obtainOAuthToken } from 'soapbox/actions/oauth'; import { parseBaseURL } from 'soapbox/utils/auth'; import sourceCode from 'soapbox/utils/code'; +import { getWalletAndSign } from 'soapbox/utils/ethereum'; import { getFeatures } from 'soapbox/utils/features'; +import { getQuirks } from 'soapbox/utils/quirks'; import { baseClient } from '../api'; @@ -32,36 +34,86 @@ const fetchExternalInstance = baseURL => { }); }; -export function createAppAndRedirect(host) { +function createExternalApp(instance, baseURL) { + return (dispatch, getState) => { + // Mitra: skip creating the auth app + if (getQuirks(instance).noApps) return new Promise(f => f({})); + + const { scopes } = getFeatures(instance); + + const params = { + client_name: sourceCode.displayName, + redirect_uris: `${window.location.origin}/auth/external`, + website: sourceCode.homepage, + scopes, + }; + + return dispatch(createApp(params, baseURL)); + }; +} + +function externalAuthorize(instance, baseURL) { + return (dispatch, getState) => { + const { scopes } = getFeatures(instance); + + return dispatch(createExternalApp(instance, baseURL)).then(app => { + const { client_id, redirect_uri } = app; + + const query = new URLSearchParams({ + client_id, + redirect_uri, + response_type: 'code', + scope: scopes, + }); + + localStorage.setItem('soapbox:external:app', JSON.stringify(app)); + localStorage.setItem('soapbox:external:baseurl', baseURL); + localStorage.setItem('soapbox:external:scopes', scopes); + + window.location.href = `${baseURL}/oauth/authorize?${query.toString()}`; + }); + }; +} + +export function externalEthereumLogin(instance, baseURL) { + return (dispatch, getState) => { + const loginMessage = instance.get('login_message'); + + return getWalletAndSign(loginMessage).then(({ wallet, signature }) => { + return dispatch(createExternalApp(instance, baseURL)).then(app => { + const params = { + grant_type: 'ethereum', + wallet_address: wallet.toLowerCase(), + client_id: app.client_id, + client_secret: app.client_secret, + password: signature, + redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', + scope: getFeatures(instance).scopes, + }; + + return dispatch(obtainOAuthToken(params, baseURL)) + .then(token => dispatch(authLoggedIn(token))) + .then(({ access_token }) => dispatch(verifyCredentials(access_token, baseURL))) + .then(account => dispatch(switchAccount(account.id))) + .then(() => window.location.href = '/'); + }); + }); + }; +} + +export function externalLogin(host) { return (dispatch, getState) => { const baseURL = parseBaseURL(host) || parseBaseURL(`https://${host}`); return fetchExternalInstance(baseURL).then(instance => { - const { scopes } = getFeatures(instance); - - const params = { - client_name: sourceCode.displayName, - redirect_uris: `${window.location.origin}/auth/external`, - website: sourceCode.homepage, - scopes, - }; - - return dispatch(createApp(params, baseURL)).then(app => { - const { client_id, redirect_uri } = app; - - const query = new URLSearchParams({ - client_id, - redirect_uri, - response_type: 'code', - scope: scopes, - }); - - localStorage.setItem('soapbox:external:app', JSON.stringify(app)); - localStorage.setItem('soapbox:external:baseurl', baseURL); - localStorage.setItem('soapbox:external:scopes', scopes); - - window.location.href = `${baseURL}/oauth/authorize?${query.toString()}`; - }); + const features = getFeatures(instance); + const quirks = getQuirks(instance); + + if (features.ethereumLogin && quirks.noOAuthForm) { + return dispatch(externalEthereumLogin(instance, baseURL)); + } else { + return dispatch(externalAuthorize(instance, baseURL)); + } }); }; } diff --git a/app/soapbox/actions/importer/normalizer.js b/app/soapbox/actions/importer/normalizer.js index 66524b556..7c5aa8bd3 100644 --- a/app/soapbox/actions/importer/normalizer.js +++ b/app/soapbox/actions/importer/normalizer.js @@ -15,6 +15,13 @@ const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => { export function normalizeAccount(account) { account = { ...account }; + // Some backends can return null, or omit these required fields + if (!account.emojis) account.emojis = []; + if (!account.display_name) account.display_name = ''; + if (!account.note) account.note = ''; + if (!account.avatar) account.avatar = account.avatar_static || require('images/avatar-missing.png'); + if (!account.avatar_static) account.avatar_static = account.avatar; + const emojiMap = makeEmojiMap(account); const displayName = account.display_name.trim().length === 0 ? account.username : account.display_name; @@ -41,6 +48,10 @@ export function normalizeAccount(account) { export function normalizeStatus(status, normalOldStatus, expandSpoilers) { const normalStatus = { ...status }; + // Some backends can return null, or omit these required fields + if (!normalStatus.emojis) normalStatus.emojis = []; + if (!normalStatus.spoiler_text) normalStatus.spoiler_text = ''; + // Copy the pleroma object too, so we can modify our copy if (status.pleroma) { normalStatus.pleroma = { ...status.pleroma }; diff --git a/app/soapbox/actions/instance.js b/app/soapbox/actions/instance.js index 85d8b2a3f..b1df09d64 100644 --- a/app/soapbox/actions/instance.js +++ b/app/soapbox/actions/instance.js @@ -61,6 +61,7 @@ export function fetchInstance() { dispatch(fetchNodeinfo()); // Pleroma < 2.1 backwards compatibility } }).catch(error => { + console.error(error); dispatch({ type: INSTANCE_FETCH_FAIL, error, skipAlert: true }); }); }; diff --git a/app/soapbox/actions/statuses.js b/app/soapbox/actions/statuses.js index f3b2e02a6..ba53994b5 100644 --- a/app/soapbox/actions/statuses.js +++ b/app/soapbox/actions/statuses.js @@ -143,10 +143,18 @@ export function fetchContext(id) { dispatch({ type: CONTEXT_FETCH_REQUEST, id }); return api(getState).get(`/api/v1/statuses/${id}/context`).then(({ data: context }) => { - const { ancestors, descendants } = context; - const statuses = ancestors.concat(descendants); - dispatch(importFetchedStatuses(statuses)); - dispatch({ type: CONTEXT_FETCH_SUCCESS, id, ancestors, descendants }); + if (Array.isArray(context)) { + // Mitra: returns a list of statuses + dispatch(importFetchedStatuses(context)); + } else if (typeof context === 'object') { + // Standard Mastodon API returns a map with `ancestors` and `descendants` + const { ancestors, descendants } = context; + const statuses = ancestors.concat(descendants); + dispatch(importFetchedStatuses(statuses)); + dispatch({ type: CONTEXT_FETCH_SUCCESS, id, ancestors, descendants }); + } else { + throw context; + } return context; }).catch(error => { if (error.response && error.response.status === 404) { diff --git a/app/soapbox/components/status_action_bar.js b/app/soapbox/components/status_action_bar.js index 5ef06ed65..1780f6575 100644 --- a/app/soapbox/components/status_action_bar.js +++ b/app/soapbox/components/status_action_bar.js @@ -342,6 +342,10 @@ class StatusActionBar extends ImmutablePureComponent { // }); } + if (!me) { + return menu; + } + if (features.bookmarks) { menu.push({ text: intl.formatMessage(status.get('bookmarked') ? messages.unbookmark : messages.bookmark), @@ -350,10 +354,6 @@ class StatusActionBar extends ImmutablePureComponent { }); } - if (!me) { - return menu; - } - menu.push(null); if (ownAccount || withDismiss) { diff --git a/app/soapbox/components/svg_icon.js b/app/soapbox/components/svg_icon.js index 5e5cd3ce0..ded55c50d 100644 --- a/app/soapbox/components/svg_icon.js +++ b/app/soapbox/components/svg_icon.js @@ -17,10 +17,13 @@ export default class SvgIcon extends React.PureComponent { }; render() { - const { src, className } = this.props; + const { src, className, ...other } = this.props; return ( -
+
); diff --git a/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_form-test.js.snap b/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_form-test.js.snap index 67b68261f..ed6a494b2 100644 --- a/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_form-test.js.snap +++ b/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_form-test.js.snap @@ -56,7 +56,9 @@ exports[` renders for Mastodon 1`] = ` style={Object {}} >