diff --git a/app/javascript/mastodon/actions/importer/index.js b/app/javascript/mastodon/actions/importer/index.js index d906bdfb14..516a7a7973 100644 --- a/app/javascript/mastodon/actions/importer/index.js +++ b/app/javascript/mastodon/actions/importer/index.js @@ -76,8 +76,8 @@ export function importFetchedStatuses(statuses) { pushUnique(polls, normalizePoll(status.poll, getState().getIn(['polls', status.poll.id]))); } - if (status.card?.author_account) { - pushUnique(accounts, status.card.author_account); + if (status.card) { + status.card.authors.forEach(author => author.account && pushUnique(accounts, author.account)); } } diff --git a/app/javascript/mastodon/actions/importer/normalizer.js b/app/javascript/mastodon/actions/importer/normalizer.js index be76b0f391..c09a3f442c 100644 --- a/app/javascript/mastodon/actions/importer/normalizer.js +++ b/app/javascript/mastodon/actions/importer/normalizer.js @@ -36,8 +36,15 @@ export function normalizeStatus(status, normalOldStatus) { normalStatus.poll = status.poll.id; } - if (status.card?.author_account) { - normalStatus.card = { ...status.card, author_account: status.card.author_account.id }; + if (status.card) { + normalStatus.card = { + ...status.card, + authors: status.card.authors.map(author => ({ + ...author, + accountId: author.account?.id, + account: undefined, + })), + }; } if (status.filtered) { diff --git a/app/javascript/mastodon/actions/trends.js b/app/javascript/mastodon/actions/trends.js index 01089fccbb..0bdf17a5d2 100644 --- a/app/javascript/mastodon/actions/trends.js +++ b/app/javascript/mastodon/actions/trends.js @@ -51,7 +51,7 @@ export const fetchTrendingLinks = () => (dispatch) => { api() .get('/api/v1/trends/links', { params: { limit: 20 } }) .then(({ data }) => { - dispatch(importFetchedAccounts(data.map(link => link.author_account).filter(account => !!account))); + dispatch(importFetchedAccounts(data.flatMap(link => link.authors.map(author => author.account)).filter(account => !!account))); dispatch(fetchTrendingLinksSuccess(data)); }) .catch(err => dispatch(fetchTrendingLinksFail(err))); diff --git a/app/javascript/mastodon/api_types/statuses.ts b/app/javascript/mastodon/api_types/statuses.ts index c7dd33b5da..db4e20506f 100644 --- a/app/javascript/mastodon/api_types/statuses.ts +++ b/app/javascript/mastodon/api_types/statuses.ts @@ -30,6 +30,12 @@ export interface ApiMentionJSON { acct: string; } +export interface ApiPreviewCardAuthorJSON { + name: string; + url: string; + account?: ApiAccountJSON; +} + export interface ApiPreviewCardJSON { url: string; title: string; @@ -48,6 +54,7 @@ export interface ApiPreviewCardJSON { embed_url: string; blurhash: string; published_at: string; + authors: ApiPreviewCardAuthorJSON[]; } export interface ApiStatusJSON { diff --git a/app/javascript/mastodon/features/explore/components/author_link.jsx b/app/javascript/mastodon/features/explore/components/author_link.jsx index 8dd9b0dabd..764ae75341 100644 --- a/app/javascript/mastodon/features/explore/components/author_link.jsx +++ b/app/javascript/mastodon/features/explore/components/author_link.jsx @@ -8,6 +8,10 @@ import { useAppSelector } from 'mastodon/store'; export const AuthorLink = ({ accountId }) => { const account = useAppSelector(state => state.getIn(['accounts', accountId])); + if (!account) { + return null; + } + return ( diff --git a/app/javascript/mastodon/features/explore/links.jsx b/app/javascript/mastodon/features/explore/links.jsx index 93fd1fb6dd..035e5aaad8 100644 --- a/app/javascript/mastodon/features/explore/links.jsx +++ b/app/javascript/mastodon/features/explore/links.jsx @@ -75,7 +75,7 @@ class Links extends PureComponent { publisher={link.get('provider_name')} publishedAt={link.get('published_at')} author={link.get('author_name')} - authorAccount={link.getIn(['author_account', 'id'])} + authorAccount={link.getIn(['authors', 0, 'account', 'id'])} sharedTimes={link.getIn(['history', 0, 'accounts']) * 1 + link.getIn(['history', 1, 'accounts']) * 1} thumbnail={link.get('image')} thumbnailDescription={link.get('image_description')} diff --git a/app/javascript/mastodon/features/status/components/card.jsx b/app/javascript/mastodon/features/status/components/card.jsx index f562e53f0b..f0ae40cbc4 100644 --- a/app/javascript/mastodon/features/status/components/card.jsx +++ b/app/javascript/mastodon/features/status/components/card.jsx @@ -138,7 +138,7 @@ export default class Card extends PureComponent { const interactive = card.get('type') === 'video'; const language = card.get('language') || ''; const largeImage = (card.get('image')?.length > 0 && card.get('width') > card.get('height')) || interactive; - const showAuthor = !!card.get('author_account'); + const showAuthor = !!card.getIn(['authors', 0, 'accountId']); const description = (
@@ -244,7 +244,7 @@ export default class Card extends PureComponent { {description} - {showAuthor && } + {showAuthor && } ); } diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb index cbfc393786..eac02ac14f 100644 --- a/app/models/preview_card.rb +++ b/app/models/preview_card.rb @@ -128,6 +128,22 @@ class PreviewCard < ApplicationRecord @history ||= Trends::History.new('links', id) end + def authors + @authors ||= [PreviewCard::Author.new(self)] + end + + class Author < ActiveModelSerializers::Model + attributes :name, :url, :account + + def initialize(preview_card) + super( + name: preview_card.author_name, + url: preview_card.author_url, + account: preview_card.author_account, + ) + end + end + class << self private diff --git a/app/serializers/rest/preview_card_serializer.rb b/app/serializers/rest/preview_card_serializer.rb index 7d4c99c2d1..f73a051ac0 100644 --- a/app/serializers/rest/preview_card_serializer.rb +++ b/app/serializers/rest/preview_card_serializer.rb @@ -1,6 +1,11 @@ # frozen_string_literal: true class REST::PreviewCardSerializer < ActiveModel::Serializer + class AuthorSerializer < ActiveModel::Serializer + attributes :name, :url + has_one :account, serializer: REST::AccountSerializer + end + include RoutingHelper attributes :url, :title, :description, :language, :type, @@ -8,7 +13,7 @@ class REST::PreviewCardSerializer < ActiveModel::Serializer :provider_url, :html, :width, :height, :image, :image_description, :embed_url, :blurhash, :published_at - has_one :author_account, serializer: REST::AccountSerializer, if: -> { object.author_account.present? } + has_many :authors, serializer: AuthorSerializer def url object.original_url.presence || object.url