From 3232eee358134ca468b40ec3b517a15fe69b7fe6 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 14 Oct 2025 16:04:18 +0200 Subject: [PATCH] Fix error in logged-out hashtag view when remote posts require log-in (#36467) --- .../features/hashtag_timeline/index.jsx | 32 +++++++++++-------- app/javascript/mastodon/initial_state.ts | 4 +++ app/serializers/initial_state_serializer.rb | 2 ++ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/app/javascript/mastodon/features/hashtag_timeline/index.jsx b/app/javascript/mastodon/features/hashtag_timeline/index.jsx index ab3c32e6a..1a7ffa6c2 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/index.jsx +++ b/app/javascript/mastodon/features/hashtag_timeline/index.jsx @@ -16,15 +16,21 @@ import { expandHashtagTimeline, clearTimeline } from 'mastodon/actions/timelines import Column from 'mastodon/components/column'; import ColumnHeader from 'mastodon/components/column_header'; import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; +import { remoteTopicFeedAccess, me } from 'mastodon/initial_state'; import StatusListContainer from '../ui/containers/status_list_container'; import { HashtagHeader } from './components/hashtag_header'; import ColumnSettingsContainer from './containers/column_settings_container'; -const mapStateToProps = (state, props) => ({ - hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}${props.params.local ? ':local' : ''}`, 'unread']) > 0, -}); +const mapStateToProps = (state, props) => { + const local = props.params.local || (!me && remoteTopicFeedAccess !== 'public'); + + return ({ + local, + hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}${local ? ':local' : ''}`, 'unread']) > 0, + }); +}; class HashtagTimeline extends PureComponent { disconnects = []; @@ -113,16 +119,16 @@ class HashtagTimeline extends PureComponent { } _unload () { - const { dispatch } = this.props; - const { id, local } = this.props.params; + const { dispatch, local } = this.props; + const { id } = this.props.params; this._unsubscribe(); dispatch(clearTimeline(`hashtag:${id}${local ? ':local' : ''}`)); } _load() { - const { dispatch } = this.props; - const { id, tags, local } = this.props.params; + const { dispatch, local } = this.props; + const { id, tags } = this.props.params; this._subscribe(dispatch, id, tags, local); dispatch(expandHashtagTimeline(id, { tags, local })); @@ -133,8 +139,8 @@ class HashtagTimeline extends PureComponent { } componentDidUpdate (prevProps) { - const { params } = this.props; - const { id, tags, local } = prevProps.params; + const { params, local } = this.props; + const { id, tags } = prevProps.params; if (id !== params.id || !isEqual(tags, params.tags) || !isEqual(local, params.local)) { this._unload(); @@ -151,15 +157,15 @@ class HashtagTimeline extends PureComponent { }; handleLoadMore = maxId => { - const { dispatch, params } = this.props; - const { id, tags, local } = params; + const { dispatch, params, local } = this.props; + const { id, tags } = params; dispatch(expandHashtagTimeline(id, { maxId, tags, local })); }; render () { - const { hasUnread, columnId, multiColumn } = this.props; - const { id, local } = this.props.params; + const { hasUnread, columnId, multiColumn, local } = this.props; + const { id } = this.props.params; const pinned = !!columnId; return ( diff --git a/app/javascript/mastodon/initial_state.ts b/app/javascript/mastodon/initial_state.ts index 2bef1209e..f28d81a10 100644 --- a/app/javascript/mastodon/initial_state.ts +++ b/app/javascript/mastodon/initial_state.ts @@ -34,6 +34,8 @@ interface InitialStateMeta { streaming_api_base_url: string; local_live_feed_access: 'public' | 'authenticated'; remote_live_feed_access: 'public' | 'authenticated'; + local_topic_feed_access: 'public' | 'authenticated'; + remote_topic_feed_access: 'public' | 'authenticated'; title: string; show_trends: boolean; trends_as_landing_page: boolean; @@ -113,6 +115,8 @@ export const singleUserMode = getMeta('single_user_mode'); export const source_url = getMeta('source_url'); export const localLiveFeedAccess = getMeta('local_live_feed_access'); export const remoteLiveFeedAccess = getMeta('remote_live_feed_access'); +export const localTopicFeedAccess = getMeta('local_topic_feed_access'); +export const remoteTopicFeedAccess = getMeta('remote_topic_feed_access'); export const title = getMeta('title'); export const trendsAsLanding = getMeta('trends_as_landing_page'); export const useBlurhash = getMeta('use_blurhash'); diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index b19051172..93c06b767 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -118,6 +118,8 @@ class InitialStateSerializer < ActiveModel::Serializer terms_of_service_enabled: TermsOfService.current.present?, local_live_feed_access: Setting.local_live_feed_access, remote_live_feed_access: Setting.remote_live_feed_access, + local_topic_feed_access: Setting.local_topic_feed_access, + remote_topic_feed_access: Setting.remote_topic_feed_access, } end