diff --git a/app/soapbox/__fixtures__/alex.json b/app/soapbox/__fixtures__/alex.json
new file mode 100644
index 000000000..022978fde
--- /dev/null
+++ b/app/soapbox/__fixtures__/alex.json
@@ -0,0 +1,127 @@
+{
+ "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": "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": 2378,
+ "following_count": 1571,
+ "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-20T04:14:49",
+ "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": [
+ "https://mitra.social/users/alex"
+ ],
+ "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": "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": 23477,
+ "url": "https://gleasonator.com/users/alex",
+ "username": "alex"
+}
diff --git a/app/soapbox/normalizers/__tests__/status-test.js b/app/soapbox/normalizers/__tests__/status-test.js
index 580adc379..654354373 100644
--- a/app/soapbox/normalizers/__tests__/status-test.js
+++ b/app/soapbox/normalizers/__tests__/status-test.js
@@ -16,6 +16,21 @@ describe('normalizeStatus', () => {
expect(result).toEqual(expected);
});
+ it('adds mention to self in self-reply on Mastodon', () => {
+ const status = fromJS(require('soapbox/__fixtures__/mastodon-reply-to-self.json'));
+
+ const expected = fromJS([{
+ id: '106801667066418367',
+ username: 'benis911',
+ acct: 'benis911',
+ url: 'https://mastodon.social/@benis911',
+ }]);
+
+ const result = normalizeStatus(status).get('mentions');
+
+ expect(result).toEqual(expected);
+ });
+
it('normalizes Mitra attachments', () => {
const status = fromJS(require('soapbox/__fixtures__/mitra-status-with-attachments.json'));
diff --git a/app/soapbox/normalizers/status.js b/app/soapbox/normalizers/status.js
index 6b0018328..dc8886e35 100644
--- a/app/soapbox/normalizers/status.js
+++ b/app/soapbox/normalizers/status.js
@@ -1,5 +1,7 @@
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
+import { accountToMention } from 'soapbox/utils/accounts';
+
// Ensure attachments have required fields
// https://docs.joinmastodon.org/entities/attachment/
const normalizeAttachment = attachment => {
@@ -41,9 +43,27 @@ const fixMentions = status => {
return status.set('mentions', sorted);
};
+// Add self to mentions if it's a reply to self
+const addSelfMention = status => {
+ const accountId = status.getIn(['account', 'id']);
+
+ const isSelfReply = accountId === status.get('in_reply_to_account_id');
+ const hasSelfMention = accountId === status.getIn(['mentions', 0, 'id']);
+
+ if (isSelfReply && !hasSelfMention) {
+ const mention = accountToMention(status.get('account'));
+ return status.update('mentions', ImmutableList(), mentions => (
+ ImmutableList([mention]).concat(mentions)
+ ));
+ } else {
+ return status;
+ }
+};
+
export const normalizeStatus = status => {
return status.withMutations(status => {
fixMentions(status);
+ addSelfMention(status);
normalizeAttachments(status);
});
};
diff --git a/app/soapbox/utils/__tests__/accounts-test.js b/app/soapbox/utils/__tests__/accounts-test.js
index 15a42ec57..d3fd6f9ba 100644
--- a/app/soapbox/utils/__tests__/accounts-test.js
+++ b/app/soapbox/utils/__tests__/accounts-test.js
@@ -6,6 +6,7 @@ import {
isStaff,
isAdmin,
isModerator,
+ accountToMention,
} from '../accounts';
describe('getDomain', () => {
@@ -115,3 +116,19 @@ describe('isModerator', () => {
});
});
});
+
+describe('accountToMention', () => {
+ it('converts the account to a mention', () => {
+ const account = fromJS(require('soapbox/__fixtures__/alex.json'));
+
+ const expected = fromJS({
+ id: '9v5bmRalQvjOy0ECcC',
+ username: 'alex',
+ acct: 'alex',
+ url: 'https://gleasonator.com/users/alex',
+ });
+
+ const result = accountToMention(account);
+ expect(result).toEqual(expected);
+ });
+});
diff --git a/app/soapbox/utils/accounts.js b/app/soapbox/utils/accounts.js
index 6970f0050..3cf2c7cd5 100644
--- a/app/soapbox/utils/accounts.js
+++ b/app/soapbox/utils/accounts.js
@@ -67,3 +67,12 @@ export const isRemote = account => !isLocal(account);
export const isVerified = account => (
account.getIn(['pleroma', 'tags'], ImmutableList()).includes('verified')
);
+
+export const accountToMention = account => {
+ return ImmutableMap({
+ id: account.get('id'),
+ username: account.get('username'),
+ acct: account.get('acct'),
+ url: account.get('url'),
+ });
+};