diff options
Diffstat (limited to 'app')
38 files changed, 261 insertions, 206 deletions
diff --git a/app/controllers/admin/custom_emojis_controller.rb b/app/controllers/admin/custom_emojis_controller.rb index ca81f3255..5cce5bce4 100644 --- a/app/controllers/admin/custom_emojis_controller.rb +++ b/app/controllers/admin/custom_emojis_controller.rb @@ -31,10 +31,12 @@ module Admin emoji = CustomEmoji.new(domain: nil, shortcode: @custom_emoji.shortcode, image: @custom_emoji.image) if emoji.save - redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.copied_msg') + flash[:notice] = I18n.t('admin.custom_emojis.copied_msg') else - redirect_to admin_custom_emojis_path, alert: I18n.t('admin.custom_emojis.copy_failed_msg') + flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg') end + + redirect_to admin_custom_emojis_path(params[:page]) end def enable diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index aac3c31ff..223db96ff 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -6,7 +6,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController before_action :check_enabled_registrations, only: [:new, :create] before_action :configure_sign_up_params, only: [:create] before_action :set_sessions, only: [:edit, :update] - before_action :set_instance_presenter, only: [:new, :update] + before_action :set_instance_presenter, only: [:new, :create, :update] def destroy not_found diff --git a/app/controllers/concerns/user_tracking_concern.rb b/app/controllers/concerns/user_tracking_concern.rb index 8a63af95d..8663c3086 100644 --- a/app/controllers/concerns/user_tracking_concern.rb +++ b/app/controllers/concerns/user_tracking_concern.rb @@ -7,12 +7,14 @@ module UserTrackingConcern UPDATE_SIGN_IN_HOURS = 24 included do - before_action :set_user_activity, if: %i(user_signed_in? user_needs_sign_in_update?) + before_action :set_user_activity end private def set_user_activity + return unless user_needs_sign_in_update? + # Mark as signed-in today current_user.update_tracked_fields!(request) @@ -21,7 +23,7 @@ module UserTrackingConcern end def user_needs_sign_in_update? - current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_HOURS.hours.ago + user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_HOURS.hours.ago) end def user_needs_feed_update? diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js index fc47110e3..fbaebf786 100644 --- a/app/javascript/mastodon/actions/accounts.js +++ b/app/javascript/mastodon/actions/accounts.js @@ -122,7 +122,7 @@ export function unfollowAccount(id) { dispatch(unfollowAccountRequest(id)); api(getState).post(`/api/v1/accounts/${id}/unfollow`).then(response => { - dispatch(unfollowAccountSuccess(response.data)); + dispatch(unfollowAccountSuccess(response.data, getState().get('statuses'))); }).catch(error => { dispatch(unfollowAccountFail(error)); }); @@ -157,10 +157,11 @@ export function unfollowAccountRequest(id) { }; }; -export function unfollowAccountSuccess(relationship) { +export function unfollowAccountSuccess(relationship, statuses) { return { type: ACCOUNT_UNFOLLOW_SUCCESS, relationship, + statuses, }; }; diff --git a/app/javascript/mastodon/components/relative_timestamp.js b/app/javascript/mastodon/components/relative_timestamp.js index 534d83fac..51588e78c 100644 --- a/app/javascript/mastodon/components/relative_timestamp.js +++ b/app/javascript/mastodon/components/relative_timestamp.js @@ -94,6 +94,10 @@ export default class RelativeTimestamp extends React.Component { this._scheduleNextUpdate(nextProps, nextState); } + componentWillUnmount () { + clearTimeout(this._timer); + } + _scheduleNextUpdate (props, state) { clearTimeout(this._timer); diff --git a/app/javascript/mastodon/features/compose/util/counter.js b/app/javascript/mastodon/features/compose/util/counter.js index 588a372c6..e6d2487c5 100644 --- a/app/javascript/mastodon/features/compose/util/counter.js +++ b/app/javascript/mastodon/features/compose/util/counter.js @@ -5,5 +5,5 @@ const urlPlaceholder = 'xxxxxxxxxxxxxxxxxxxxxxx'; export function countableText(inputText) { return inputText .replace(urlRegex, urlPlaceholder) - .replace(/(?:^|[^\/\w])@(([a-z0-9_]+)@[a-z0-9\.\-]+)/ig, '@$2'); + .replace(/(?:^|[^\/\w])@(([a-z0-9_]+)@[a-z0-9\.\-]+[a-z0-9]+)/ig, '@$2'); }; diff --git a/app/javascript/mastodon/features/home_timeline/index.js b/app/javascript/mastodon/features/home_timeline/index.js index 8d74783a3..b35347ba6 100644 --- a/app/javascript/mastodon/features/home_timeline/index.js +++ b/app/javascript/mastodon/features/home_timeline/index.js @@ -16,7 +16,6 @@ const messages = defineMessages({ const mapStateToProps = state => ({ hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0, - hasFollows: state.getIn(['accounts_counters', state.getIn(['meta', 'me']), 'following_count']) > 0, }); @connect(mapStateToProps) @@ -27,7 +26,6 @@ export default class HomeTimeline extends React.PureComponent { dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, hasUnread: PropTypes.bool, - hasFollows: PropTypes.bool, columnId: PropTypes.string, multiColumn: PropTypes.bool, }; @@ -60,17 +58,9 @@ export default class HomeTimeline extends React.PureComponent { } render () { - const { intl, hasUnread, hasFollows, columnId, multiColumn } = this.props; + const { intl, hasUnread, columnId, multiColumn } = this.props; const pinned = !!columnId; - let emptyMessage; - - if (hasFollows) { - emptyMessage = <FormattedMessage id='empty_column.home.inactivity' defaultMessage='Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.' />; - } else { - emptyMessage = <FormattedMessage id='empty_column.home' defaultMessage="You aren't following anyone yet. Visit {public} or use search to get started and meet other users." values={{ public: <Link to='/timelines/public'><FormattedMessage id='empty_column.home.public_timeline' defaultMessage='the public timeline' /></Link> }} />; - } - return ( <Column ref={this.setRef} name='home'> <ColumnHeader @@ -91,7 +81,7 @@ export default class HomeTimeline extends React.PureComponent { scrollKey={`home_timeline-${columnId}`} loadMore={this.handleLoadMore} timelineId='home' - emptyMessage={emptyMessage} + emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage='Your home timeline is empty! Visit {public} or use search to get started and meet other users.' values={{ public: <Link to='/timelines/public'><FormattedMessage id='empty_column.home.public_timeline' defaultMessage='the public timeline' /></Link> }} />} /> </Column> ); diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 240e3725e..eeded31b7 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -81,7 +81,7 @@ "emoji_button.travel": "Travel & Places", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", - "empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.", + "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index b5051a32d..fe2433591 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -1,7 +1,7 @@ { "account.block": "Bloquejar @{name}", "account.block_domain": "Amagar tot de {domain}", - "account.disclaimer_full": "Information below may reflect the user's profile incompletely.", + "account.disclaimer_full": "La informació següent pot reflectir incompleta el perfil de l'usuari.", "account.edit_profile": "Editar perfil", "account.follow": "Seguir", "account.followers": "Seguidors", @@ -13,19 +13,19 @@ "account.posts": "Publicacions", "account.report": "Informe @{name}", "account.requested": "Esperant aprovació", - "account.share": "Share @{name}'s profile", + "account.share": "Compartir el perfil de @{name}", "account.unblock": "Desbloquejar @{name}", "account.unblock_domain": "Mostra {domain}", "account.unfollow": "Deixar de seguir", "account.unmute": "Treure silenci de @{name}", - "account.view_full_profile": "View full profile", + "account.view_full_profile": "Veure el perfil complet", "boost_modal.combo": "Pots premer {combo} per saltar-te això el proper cop", - "bundle_column_error.body": "Something went wrong while loading this component.", - "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Network error", - "bundle_modal_error.close": "Close", - "bundle_modal_error.message": "Something went wrong while loading this component.", - "bundle_modal_error.retry": "Try again", + "bundle_column_error.body": "S'ha produït un error en carregar aquest component.", + "bundle_column_error.retry": "Torna-ho a provar", + "bundle_column_error.title": "Error de connexió", + "bundle_modal_error.close": "Tanca", + "bundle_modal_error.message": "S'ha produït un error en carregar aquest component.", + "bundle_modal_error.retry": "Torna-ho a provar", "column.blocks": "Usuaris bloquejats", "column.community": "Línia de temps local", "column.favourites": "Favorits", @@ -33,15 +33,15 @@ "column.home": "Inici", "column.mutes": "Usuaris silenciats", "column.notifications": "Notificacions", - "column.pins": "Pinned toot", + "column.pins": "Toot fixat", "column.public": "Línia de temps federada", "column_back_button.label": "Enrere", - "column_header.hide_settings": "Hide settings", - "column_header.moveLeft_settings": "Move column to the left", - "column_header.moveRight_settings": "Move column to the right", - "column_header.pin": "Pin", - "column_header.show_settings": "Show settings", - "column_header.unpin": "Unpin", + "column_header.hide_settings": "Amaga la configuració", + "column_header.moveLeft_settings": "Mou la columna cap a l'esquerra", + "column_header.moveRight_settings": "Mou la columna cap a la dreta", + "column_header.pin": "Fixar", + "column_header.show_settings": "Mostra la configuració", + "column_header.unpin": "Deslligar", "column_subheading.navigation": "Navegació", "column_subheading.settings": "Configuració", "compose_form.lock_disclaimer": "El teu compte no està bloquejat {locked}. Tothom pot seguir-te i veure els teus missatges a seguidors.", @@ -61,22 +61,22 @@ "confirmations.domain_block.message": "Estàs realment, realment segur que vols bloquejar totalment {domain}? En la majoria dels casos bloquejar o silenciar és suficient i preferible.", "confirmations.mute.confirm": "Silenciar", "confirmations.mute.message": "Estàs segur que vols silenciar {name}?", - "confirmations.unfollow.confirm": "Unfollow", - "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?", - "embed.instructions": "Embed this status on your website by copying the code below.", - "embed.preview": "Here is what it will look like:", + "confirmations.unfollow.confirm": "Deixar de seguir", + "confirmations.unfollow.message": "Estàs segur que vols deixar de seguir {name}?", + "embed.instructions": "Incrusta aquest estat al lloc web copiant el codi a continuació.", + "embed.preview": "A continuació s'explica com:", "emoji_button.activity": "Activitat", - "emoji_button.custom": "Custom", + "emoji_button.custom": "Personalitzat", "emoji_button.flags": "Flags", "emoji_button.food": "Menjar i Beure", "emoji_button.label": "Inserir emoji", "emoji_button.nature": "Natura", - "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "Emojos no!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "Objectes", "emoji_button.people": "Gent", - "emoji_button.recent": "Frequently used", + "emoji_button.recent": "Freqüentment utilitzat", "emoji_button.search": "Cercar...", - "emoji_button.search_results": "Search results", + "emoji_button.search_results": "Resultats de la cerca", "emoji_button.symbols": "Símbols", "emoji_button.travel": "Viatges i Llocs", "empty_column.community": "La línia de temps local és buida. Escriu alguna cosa públicament per fer rodar la pilota!", @@ -88,7 +88,7 @@ "empty_column.public": "No hi ha res aquí! Escriu alguna cosa públicament o segueix manualment usuaris d'altres instàncies per omplir-ho", "follow_request.authorize": "Autoritzar", "follow_request.reject": "Rebutjar", - "getting_started.appsshort": "Apps", + "getting_started.appsshort": "Aplicacions", "getting_started.faq": "PMF", "getting_started.heading": "Començant", "getting_started.open_source_notice": "Mastodon és un programari de codi obert. Pots contribuir o informar de problemes a GitHub de {github}.", @@ -100,8 +100,8 @@ "home.column_settings.show_replies": "Mostrar respostes", "home.settings": "Ajustos de columna", "lightbox.close": "Tancar", - "lightbox.next": "Next", - "lightbox.previous": "Previous", + "lightbox.next": "Següent", + "lightbox.previous": "Anterior", "loading_indicator.label": "Carregant...", "media_gallery.toggle_visible": "Alternar visibilitat", "missing_indicator.label": "No trobat", @@ -113,7 +113,7 @@ "navigation_bar.info": "Informació addicional", "navigation_bar.logout": "Tancar sessió", "navigation_bar.mutes": "Usuaris silenciats", - "navigation_bar.pins": "Pinned toots", + "navigation_bar.pins": "Toots fixats", "navigation_bar.preferences": "Preferències", "navigation_bar.public_timeline": "Línia de temps federada", "notification.favourite": "{name} ha afavorit el teu estat", @@ -126,8 +126,8 @@ "notifications.column_settings.favourite": "Favorits:", "notifications.column_settings.follow": "Nous seguidors:", "notifications.column_settings.mention": "Mencions:", - "notifications.column_settings.push": "Push notifications", - "notifications.column_settings.push_meta": "This device", + "notifications.column_settings.push": "Push notificacions", + "notifications.column_settings.push_meta": "Aquest dispositiu", "notifications.column_settings.reblog": "Boosts:", "notifications.column_settings.show": "Mostrar en la columna", "notifications.column_settings.sound": "Reproduïr so", @@ -160,28 +160,33 @@ "privacy.public.short": "Públic", "privacy.unlisted.long": "No publicar en línies de temps públiques", "privacy.unlisted.short": "No llistat", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Cancel·lar", "report.placeholder": "Comentaris addicionals", "report.submit": "Enviar", "report.target": "Informes", "search.placeholder": "Cercar", - "search_popout.search_format": "Advanced search format", + "search_popout.search_format": "Format de cerca avançada", "search_popout.tips.hashtag": "hashtag", "search_popout.tips.status": "status", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", - "search_popout.tips.user": "user", - "search_results.total": "{count, number} {count, plural, one {result} other {results}}", - "standalone.public_title": "A look inside...", + "search_popout.tips.text": "El text simple retorna coincidències amb els noms de visualització, els noms d'usuari i els hashtags", + "search_popout.tips.user": "usuari", + "search_results.total": "{count, number} {count, plural, un {result} altres {results}}", + "standalone.public_title": "Una mirada a l'interior ...", "status.cannot_reblog": "Aquesta publicació no pot ser retootejada", "status.delete": "Esborrar", - "status.embed": "Embed", + "status.embed": "Incrustar", "status.favourite": "Favorit", "status.load_more": "Carrega més", "status.media_hidden": "Multimèdia amagat", "status.mention": "Esmentar @{name}", "status.mute_conversation": "Silenciar conversació", "status.open": "Ampliar aquest estat", - "status.pin": "Pin on profile", + "status.pin": "Fixat en el perfil", "status.reblog": "Boost", "status.reblogged_by": "{name} ha retootejat", "status.reply": "Respondre", @@ -189,11 +194,11 @@ "status.report": "Informar sobre @{name}", "status.sensitive_toggle": "Clic per veure", "status.sensitive_warning": "Contingut sensible", - "status.share": "Share", + "status.share": "Compartir", "status.show_less": "Mostra menys", "status.show_more": "Mostra més", "status.unmute_conversation": "Activar conversació", - "status.unpin": "Unpin from profile", + "status.unpin": "Deslliga del perfil", "tabs_bar.compose": "Compondre", "tabs_bar.federated_timeline": "Federada", "tabs_bar.home": "Inici", @@ -201,16 +206,16 @@ "tabs_bar.notifications": "Notificacions", "upload_area.title": "Arrossega i deixa anar per carregar", "upload_button.label": "Afegir multimèdia", - "upload_form.description": "Describe for the visually impaired", + "upload_form.description": "Descriure els problemes visuals", "upload_form.undo": "Desfer", "upload_progress.label": "Pujant...", - "video.close": "Close video", - "video.exit_fullscreen": "Exit full screen", - "video.expand": "Expand video", - "video.fullscreen": "Full screen", - "video.hide": "Hide video", - "video.mute": "Mute sound", - "video.pause": "Pause", - "video.play": "Play", - "video.unmute": "Unmute sound" + "video.close": "Tancar el vídeo", + "video.exit_fullscreen": "Surt de pantalla completa", + "video.expand": "Ampliar el vídeo", + "video.fullscreen": "Pantalla completa", + "video.hide": "Amaga vídeo", + "video.mute": "Silenciar el so", + "video.pause": "Pausa", + "video.play": "Reproduir", + "video.unmute": "Activar so" } diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index b79b1b2f0..9d9853236 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -81,7 +81,7 @@ "emoji_button.travel": "Reisen und Orte", "empty_column.community": "Die lokale Zeitleiste ist leer. Schreibe einen öffentlichen Beitrag, um den Ball ins Rollen zu bringen!", "empty_column.hashtag": "Unter diesem Hashtag gibt es noch nichts.", - "empty_column.home": "Du folgst noch niemandem. Besuche {public} oder nutze die Suche, um loszulegen und andere Leute zu finden.", + "empty_column.home": "Deine Startseite ist leer! Besuche {public} oder nutze die Suche, um loszulegen und andere Leute zu finden.", "empty_column.home.inactivity": "Deine Zeitleiste ist leer. Falls du eine längere Zeit inaktiv warst, wird sie für dich so schnell wie möglich neu erstellt.", "empty_column.home.public_timeline": "die öffentliche Zeitleiste", "empty_column.notifications": "Du hast noch keine Mitteilungen. Interagiere mit anderen, um ins Gespräch zu kommen.", @@ -143,7 +143,7 @@ "onboarding.page_six.almost_done": "Fast fertig …", "onboarding.page_six.appetoot": "Guten Appetröt!", "onboarding.page_six.apps_available": "Es gibt verschiedene {apps} für iOS, Android und weitere Plattformen.", - "onboarding.page_six.github": "Mastodon ist freie, quelloffene Software. Du kannst auf GitHub unter {github} dazu beitragen, Probleme melden und Wünsche äußern.", + "onboarding.page_six.github": "Mastodon ist freie, quelloffene Software. Du kannst auf {github} dazu beitragen, Probleme melden und Wünsche äußern.", "onboarding.page_six.guidelines": "Richtlinien", "onboarding.page_six.read_guidelines": "Bitte mach dich mit den {guidelines} von {domain} vertraut.", "onboarding.page_six.various_app": "Apps", diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index 8fdb8c44c..99ff3b35b 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -912,7 +912,7 @@ "id": "empty_column.home.inactivity" }, { - "defaultMessage": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.", + "defaultMessage": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", "id": "empty_column.home" }, { diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index b0dbc46bd..12efe0e0c 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -81,7 +81,7 @@ "emoji_button.travel": "Travel & Places", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", - "empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.", + "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 1ccd2b817..8f90bdf78 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -81,7 +81,7 @@ "emoji_button.travel": "Travel & Places", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", - "empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.", + "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 13fb91278..9df0dec42 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -66,17 +66,17 @@ "embed.instructions": "برای جاگذاری این نوشته در سایت خودتان، کد زیر را کپی کنید.", "embed.preview": "نوشتهٔ جاگذاریشده این گونه به نظر خواهد رسید:", "emoji_button.activity": "فعالیت", - "emoji_button.custom": "Custom", + "emoji_button.custom": "سفارشی", "emoji_button.flags": "پرچمها", "emoji_button.food": "غذا و نوشیدنی", "emoji_button.label": "افزودن شکلک", "emoji_button.nature": "طبیعت", - "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "اینجا شکلکی نیست!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "اشیا", "emoji_button.people": "مردم", - "emoji_button.recent": "Frequently used", + "emoji_button.recent": "زیاد بهکاررفته", "emoji_button.search": "جستجو...", - "emoji_button.search_results": "Search results", + "emoji_button.search_results": "نتایج جستجو", "emoji_button.symbols": "نمادها", "emoji_button.travel": "سفر و مکان", "empty_column.community": "فهرست نوشتههای محلی خالی است. چیزی بنویسید تا چرخش بچرخد!", @@ -165,11 +165,11 @@ "report.submit": "بفرست", "report.target": "گزارشدادن", "search.placeholder": "جستجو", - "search_popout.search_format": "Advanced search format", - "search_popout.tips.hashtag": "hashtag", - "search_popout.tips.status": "status", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", - "search_popout.tips.user": "user", + "search_popout.search_format": "راهنمای جستجوی پیشرفته", + "search_popout.tips.hashtag": "هشتگ", + "search_popout.tips.status": "نوشته", + "search_popout.tips.text": "جستجوی متنی ساده برای نامها، نامهای کاربری، و هشتگها", + "search_popout.tips.user": "کاربر", "search_results.total": "{count, number} {count, plural, one {نتیجه} other {نتیجه}}", "standalone.public_title": "نگاهی به کاربران این سرور...", "status.cannot_reblog": "این نوشته را نمیشود بازبوقید", @@ -201,7 +201,7 @@ "tabs_bar.notifications": "اعلانها", "upload_area.title": "برای بارگذاری به اینجا بکشید", "upload_button.label": "افزودن تصویر", - "upload_form.description": "Describe for the visually impaired", + "upload_form.description": "نوشتهٔ توضیحی برای کمبینایان و نابینایان", "upload_form.undo": "واگردانی", "upload_progress.label": "بارگذاری...", "video.close": "بستن ویدیو", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 425b3d82a..0f6554595 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -81,7 +81,7 @@ "emoji_button.travel": "Travel & Places", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", - "empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.", + "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 4eca47b60..145b683f3 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -54,13 +54,13 @@ "compose_form.spoiler_placeholder": "Écrivez ici votre avertissement", "confirmation_modal.cancel": "Annuler", "confirmations.block.confirm": "Bloquer", - "confirmations.block.message": "Confirmez vous le blocage de {name} ?", + "confirmations.block.message": "Confirmez-vous le blocage de {name} ?", "confirmations.delete.confirm": "Supprimer", - "confirmations.delete.message": "Confirmez vous la suppression de ce pouet ?", + "confirmations.delete.message": "Confirmez-vous la suppression de ce pouet ?", "confirmations.domain_block.confirm": "Masquer le domaine entier", "confirmations.domain_block.message": "Êtes-vous vraiment, vraiment sûr⋅e de vouloir bloquer {domain} en entier ? Dans la plupart des cas, quelques blocages ou masquages ciblés sont suffisants et préférables.", "confirmations.mute.confirm": "Masquer", - "confirmations.mute.message": "Confirmez vous le masquage de {name} ?", + "confirmations.mute.message": "Confirmez-vous le masquage de {name} ?", "confirmations.unfollow.confirm": "Ne plus suivre", "confirmations.unfollow.message": "Voulez-vous arrêter de suivre {name} ?", "embed.instructions": "Intégrez ce statut à votre site en copiant ce code ci-dessous.", @@ -69,7 +69,7 @@ "emoji_button.custom": "Personnalisés", "emoji_button.flags": "Drapeaux", "emoji_button.food": "Boire et manger", - "emoji_button.label": "Insérer un emoji", + "emoji_button.label": "Insérer un émoji", "emoji_button.nature": "Nature", "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "Objets", @@ -79,7 +79,7 @@ "emoji_button.search_results": "Résultats de la recherche", "emoji_button.symbols": "Symboles", "emoji_button.travel": "Lieux et voyages", - "empty_column.community": "Le fil public local est vide. Écrivez-donc quelque chose pour le remplir !", + "empty_column.community": "Le fil public local est vide. Écrivez donc quelque chose pour le remplir !", "empty_column.hashtag": "Il n’y a encore aucun contenu associé à ce hashtag", "empty_column.home": "Vous ne suivez encore personne. Visitez {public} ou bien utilisez la recherche pour vous connecter à d’autres utilisateur⋅ice⋅s.", "empty_column.home.inactivity": "Votre accueil est vide. Si vous ne vous êtes pas connecté⋅e depuis un moment, il se remplira automatiquement très bientôt.", @@ -124,7 +124,7 @@ "notifications.clear_confirmation": "Voulez-vous vraiment supprimer toutes vos notifications ?", "notifications.column_settings.alert": "Notifications locales", "notifications.column_settings.favourite": "Favoris :", - "notifications.column_settings.follow": "Nouveaux⋅elles abonn⋅é⋅s :", + "notifications.column_settings.follow": "Nouveaux⋅elles abonné⋅e⋅s :", "notifications.column_settings.mention": "Mentions :", "notifications.column_settings.push": "Notifications push", "notifications.column_settings.push_meta": "Cet appareil", @@ -139,7 +139,7 @@ "onboarding.page_one.federation": "Mastodon est un réseau social qui appartient à tou⋅te⋅s.", "onboarding.page_one.handle": "Vous êtes sur {domain}, une des nombreuses instances indépendantes de Mastodon. Votre nom d’utilisateur⋅ice complet est {handle}", "onboarding.page_one.welcome": "Bienvenue sur Mastodon !", - "onboarding.page_six.admin": "L’administrateur⋅trice de votre instance est {admin}", + "onboarding.page_six.admin": "L’administrateur⋅ice de votre instance est {admin}", "onboarding.page_six.almost_done": "Nous y sommes presque…", "onboarding.page_six.appetoot": "Bon appouétit !", "onboarding.page_six.apps_available": "De nombreuses {apps} sont disponibles pour iOS, Android et autres. Et maintenant… Bon appouétit !", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 7b9c1b293..2296ea71e 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -81,7 +81,7 @@ "emoji_button.travel": "Travel & Places", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", - "empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.", + "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index a3e237f6b..04b88da34 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -151,8 +151,8 @@ "onboarding.page_three.search": "Gebruik de zoekbalk linksboven om andere mensen op Mastodon te vinden en om te zoeken op hashtags, zoals {illustration} en {introductions}. Om iemand te vinden die niet op deze Mastodon-server zit, moet je het volledige Mastodon-adres van deze persoon invoeren.", "onboarding.page_two.compose": "Schrijf berichten (wij noemen dit toots) in het tekstvak in de linkerkolom. Je kan met de pictogrammen daaronder afbeeldingen uploaden, privacy-instellingen veranderen en je tekst een waarschuwing meegeven.", "onboarding.skip": "Overslaan", - "privacy.change": "Privacy toot aanpassen", - "privacy.direct.long": "Toot alleen naar vermelde gebruikers", + "privacy.change": "Zichtbaarheid toot aanpassen", + "privacy.direct.long": "Alleen aan vermelde gebruikers tonen", "privacy.direct.short": "Direct", "privacy.private.long": "Alleen aan volgers tonen", "privacy.private.short": "Alleen volgers", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index d730b47f4..4715f60ef 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -81,7 +81,7 @@ "emoji_button.travel": "Viatges & lòcs", "empty_column.community": "Lo flux public local es void. Escrivètz quicòm per lo garnir !", "empty_column.hashtag": "I a pas encara de contengut ligat a aqueste hashtag", - "empty_column.home": "Pel moment seguètz pas degun. Visitatz {public} o utilizatz la recèrca per vos connectar a d’autras personas.", + "empty_column.home": "Vòstre flux d’acuèlh es void. Visitatz {public} o utilizatz la recèrca per vos connectar a d’autras personas.", "empty_column.home.inactivity": "Vòstra pagina d’acuèlh es voida. Se sètz estat inactiu per un moment, serà tornada generar per vos dins una estona.", "empty_column.home.public_timeline": "lo flux public", "empty_column.notifications": "Avètz pas encara de notificacions. Respondètz a qualqu’un per començar una conversacion.", @@ -201,7 +201,7 @@ "tabs_bar.notifications": "Notificacions", "upload_area.title": "Lisatz e depausatz per mandar", "upload_button.label": "Ajustar un mèdia", - "upload_form.description": "Descripcion se per cas i aja un problèma", + "upload_form.description": "Descripcion pels mal vesents", "upload_form.undo": "Anullar", "upload_progress.label": "Mandadís…", "video.close": "Tampar la vidèo", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 61674b37e..2c79a7509 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -45,7 +45,7 @@ "column_subheading.navigation": "Navegação", "column_subheading.settings": "Configurações", "compose_form.lock_disclaimer": "A sua conta não está {locked}. Qualquer pessoa pode te seguir e visualizar postagens direcionadas a apenas seguidores.", - "compose_form.lock_disclaimer.lock": "trancado", + "compose_form.lock_disclaimer.lock": "trancada", "compose_form.placeholder": "No que você está pensando?", "compose_form.publish": "Publicar", "compose_form.publish_loud": "{publish}!", @@ -66,17 +66,17 @@ "embed.instructions": "Incorpore esta postagem em seu site copiando o código abaixo:", "embed.preview": "Aqui está uma previsão de como ficará:", "emoji_button.activity": "Atividades", - "emoji_button.custom": "Custom", + "emoji_button.custom": "Customizados", "emoji_button.flags": "Bandeiras", "emoji_button.food": "Comidas & Bebidas", "emoji_button.label": "Inserir Emoji", "emoji_button.nature": "Natureza", - "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "Não tem emojos! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "Objetos", "emoji_button.people": "Pessoas", - "emoji_button.recent": "Frequently used", + "emoji_button.recent": "Usados frequentemente", "emoji_button.search": "Buscar...", - "emoji_button.search_results": "Search results", + "emoji_button.search_results": "Resultados da busca", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viagens & Lugares", "empty_column.community": "A timeline local está vazia. Escreva algo publicamente para começar!", @@ -148,7 +148,7 @@ "onboarding.page_six.read_guidelines": "Por favor, leia as {guidelines} do {domain}!", "onboarding.page_six.various_app": "aplicativos móveis", "onboarding.page_three.profile": "Edite o seu perfil para mudar o seu o seu avatar, bio e nome de exibição. No menu de configurações, você também encontrará outras preferências.", - "onboarding.page_three.search": "Use a barra de buscas para encontrar pessoas e consultar hashtahs, como #illustrations e #introductions. Para procurar por uma pessoa que não estiver nesta instância, use o nome de usuário completo dela.", + "onboarding.page_three.search": "Use a barra de buscas para encontrar pessoas e consultar hashtags, como #illustrations e #introductions. Para procurar por uma pessoa que não estiver nesta instância, use o nome de usuário completo dela.", "onboarding.page_two.compose": "Escreva postagens na coluna de escrita. Você pode hospedar imagens, mudar as configurações de privacidade e adicionar alertas de conteúdo através dos ícones abaixo.", "onboarding.skip": "Pular", "privacy.change": "Ajustar a privacidade da mensagem", @@ -165,15 +165,15 @@ "report.submit": "Enviar", "report.target": "Denunciar", "search.placeholder": "Pesquisar", - "search_popout.search_format": "Advanced search format", - "search_popout.tips.hashtag": "hashtag", - "search_popout.tips.status": "status", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", +"search_popout.search_format": "Advanced search format", +"search_popout.tips.hashtag": "hashtag", +"search_popout.tips.status": "status", + "search_popout.tips.text": "Texto simples retorna nomes de exibição, usuários e hashtags correspondentes", "search_popout.tips.user": "user", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", "standalone.public_title": "Dê uma espiada...", "status.cannot_reblog": "Esta postagem não pode ser compartilhada", - "status.delete": "Eliminar", + "status.delete": "Excluir", "status.embed": "Incorporar", "status.favourite": "Adicionar aos favoritos", "status.load_more": "Carregar mais", @@ -201,15 +201,15 @@ "tabs_bar.notifications": "Notificações", "upload_area.title": "Arraste e solte para enviar", "upload_button.label": "Adicionar mídia", - "upload_form.description": "Describe for the visually impaired", - "upload_form.undo": "Anular", + "upload_form.description": "Descreva a imagem para deficientes visuais", + "upload_form.undo": "Desfazer", "upload_progress.label": "Salvando...", "video.close": "Fechar vídeo", "video.exit_fullscreen": "Sair da tela cheia", "video.expand": "Expandir vídeo", "video.fullscreen": "Tela cheia", "video.hide": "Esconder vídeo", - "video.mute": "Silenciar vídeo", + "video.mute": "Silenciar", "video.pause": "Parar", "video.play": "Reproduzir", "video.unmute": "Retirar silêncio" diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index f3ec9c532..4339d1497 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -81,7 +81,7 @@ "emoji_button.travel": "Travel & Places", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", - "empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.", + "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", diff --git a/app/javascript/mastodon/reducers/timelines.js b/app/javascript/mastodon/reducers/timelines.js index 065e89f96..b17d74ef3 100644 --- a/app/javascript/mastodon/reducers/timelines.js +++ b/app/javascript/mastodon/reducers/timelines.js @@ -14,6 +14,7 @@ import { import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS, + ACCOUNT_UNFOLLOW_SUCCESS, } from '../actions/accounts'; import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; @@ -108,6 +109,12 @@ const filterTimelines = (state, relationship, statuses) => { return state; }; +const filterTimeline = (timeline, state, relationship, statuses) => + state.updateIn([timeline, 'items'], ImmutableList(), list => + list.filterNot(statusId => + statuses.getIn([statusId, 'account']) === relationship.id + )); + const updateTop = (state, timeline, top) => { return state.update(timeline, initialTimeline, map => map.withMutations(mMap => { if (top) mMap.set('unread', 0); @@ -134,6 +141,8 @@ export default function timelines(state = initialState, action) { case ACCOUNT_BLOCK_SUCCESS: case ACCOUNT_MUTE_SUCCESS: return filterTimelines(state, action.relationship, action.statuses); + case ACCOUNT_UNFOLLOW_SUCCESS: + return filterTimeline('home', state, action.relationship, action.statuses); case TIMELINE_SCROLL_TOP: return updateTop(state, action.timeline, action.top); case TIMELINE_CONNECT: diff --git a/app/javascript/styles/about.scss b/app/javascript/styles/about.scss index 8c37310e8..4ec689427 100644 --- a/app/javascript/styles/about.scss +++ b/app/javascript/styles/about.scss @@ -702,7 +702,6 @@ .features #mastodon-timeline { height: 70vh; width: 100%; - min-width: 330px; margin-bottom: 50px; .column { @@ -716,85 +715,96 @@ } &.tag-page { - .brand { - padding-top: 20px; - margin-bottom: 20px; + .features { + padding: 30px 0; - img { - height: 48px; - width: auto; - } - } + .container { + max-width: 820px; - .container { - max-width: 690px; - } + #mastodon-timeline { + margin-right: 0; + border-top-right-radius: 0; + } - .cta { - margin: 40px 0; - margin-bottom: 80px; + .about-mastodon { + .about-hashtag { + background: darken($ui-base-color, 4%); + padding: 0 20px 20px 30px; + border-radius: 0 5px 5px 0; - .button { - margin-right: 4px; - } - } + .brand { + padding-top: 20px; + margin-bottom: 20px; - .about-mastodon { - max-width: 330px; + img { + height: 48px; + width: auto; + } + } - p { - strong { - color: $ui-secondary-color; - font-weight: 700; + p { + strong { + color: $ui-secondary-color; + font-weight: 700; + } + } + + .cta { + margin: 0; + + .button { + margin-right: 4px; + } + } + } + + .features-list { + margin-left: 30px; + margin-right: 10px; + } } } } @media screen and (max-width: 675px) { - .container { - display: flex; - flex-direction: column; - } - .features { - padding: 20px 0; - } + padding: 10px 0; - .about-mastodon { - order: 1; - flex: 0 0 auto; - max-width: 100%; - } + .container { + display: flex; + flex-direction: column; - #mastodon-timeline { - order: 2; - flex: 0 0 auto; - height: 60vh; - } + #mastodon-timeline { + order: 2; + flex: 0 0 auto; + height: 60vh; + margin-bottom: 20px; + border-top-right-radius: 4px; + } - .cta { - margin: 20px 0; - margin-bottom: 30px; - } + .about-mastodon { + order: 1; + flex: 0 0 auto; + max-width: 100%; - .features-list { - display: none; - } + .about-hashtag { + background: unset; + padding: 0; + border-radius: 0; + + .cta { + margin: 20px 0; + } + } - .stripe { - display: none; + .features-list { + display: none; + } + } + } } } } - - .stripe { - width: 100%; - height: 360px; - overflow: hidden; - background: darken($ui-base-color, 4%); - position: absolute; - z-index: -1; - } } @keyframes floating { diff --git a/app/lib/activitypub/activity/undo.rb b/app/lib/activitypub/activity/undo.rb index 4b0905de2..cbed417c4 100644 --- a/app/lib/activitypub/activity/undo.rb +++ b/app/lib/activitypub/activity/undo.rb @@ -17,7 +17,8 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity private def undo_announce - status = Status.find_by(uri: object_uri, account: @account) + status = Status.find_by(uri: object_uri, account: @account) + status ||= Status.find_by(uri: @object['atomUri'], account: @account) if @object.is_a?(Hash) && @object['atomUri'].present? if status.nil? delete_later!(object_uri) diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index f6a694135..5a3af7206 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -85,7 +85,7 @@ class FeedManager oldest_home_score = redis.zrange(timeline_key, 0, 0, with_scores: true)&.first&.last&.to_i || 0 from_account.statuses.select('id, reblog_of_id').where('id > ?', oldest_home_score).reorder(nil).find_each do |status| - unpush(:home, into_account, status) + remove_from_feed(:home, into_account, status) end end @@ -121,7 +121,8 @@ class FeedManager #return true if reggie === status.content || reggie === status.spoiler_text # extremely violent filtering code END - return true if status.reply? && (status.in_reply_to_id.nil? || status.in_reply_to_account_id.nil?) + return false if receiver_id == status.account_id + return true if status.reply? && (status.in_reply_to_id.nil? || status.in_reply_to_account_id.nil?) check_for_mutes = [status.account_id] check_for_mutes.concat([status.reblog.account_id]) if status.reblog? diff --git a/app/lib/ostatus/atom_serializer.rb b/app/lib/ostatus/atom_serializer.rb index a1ac11a51..3ca6c5943 100644 --- a/app/lib/ostatus/atom_serializer.rb +++ b/app/lib/ostatus/atom_serializer.rb @@ -23,7 +23,7 @@ class OStatus::AtomSerializer append_element(author, 'name', account.username) append_element(author, 'email', account.local? ? account.local_username_and_domain : account.acct) append_element(author, 'summary', Formatter.instance.simplified_format(account).to_str, type: :html) if account.note? - append_element(author, 'link', nil, rel: :alternate, type: 'text/html', href: TagManager.instance.url_for(account)) + append_element(author, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(account)) append_element(author, 'link', nil, rel: :avatar, type: account.avatar_content_type, 'media:width': 120, 'media:height': 120, href: full_asset_url(account.avatar.url(:original))) if account.avatar? append_element(author, 'link', nil, rel: :header, type: account.header_content_type, 'media:width': 700, 'media:height': 335, href: full_asset_url(account.header.url(:original))) if account.header? append_element(author, 'poco:preferredUsername', account.username) @@ -47,7 +47,7 @@ class OStatus::AtomSerializer feed << author(account) - append_element(feed, 'link', nil, rel: :alternate, type: 'text/html', href: TagManager.instance.url_for(account)) + append_element(feed, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(account)) append_element(feed, 'link', nil, rel: :self, type: 'application/atom+xml', href: account_url(account, format: 'atom')) append_element(feed, 'link', nil, rel: :next, type: 'application/atom+xml', href: account_url(account, format: 'atom', max_id: stream_entries.last.id)) if stream_entries.size == 20 append_element(feed, 'link', nil, rel: :hub, href: api_push_url) @@ -86,9 +86,9 @@ class OStatus::AtomSerializer serialize_status_attributes(entry, stream_entry.status) end - append_element(entry, 'link', nil, rel: :alternate, type: 'text/html', href: TagManager.instance.url_for(stream_entry.status)) + append_element(entry, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(stream_entry.status)) append_element(entry, 'link', nil, rel: :self, type: 'application/atom+xml', href: account_stream_entry_url(stream_entry.account, stream_entry, format: 'atom')) - append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(stream_entry.thread), href: TagManager.instance.url_for(stream_entry.thread)) if stream_entry.threaded? + append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(stream_entry.thread), href: ::TagManager.instance.url_for(stream_entry.thread)) if stream_entry.threaded? append_element(entry, 'ostatus:conversation', nil, ref: conversation_uri(stream_entry.status.conversation)) unless stream_entry&.status&.conversation_id.nil? entry @@ -109,8 +109,8 @@ class OStatus::AtomSerializer serialize_status_attributes(object, status) - append_element(object, 'link', nil, rel: :alternate, type: 'text/html', href: TagManager.instance.url_for(status)) - append_element(object, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(status.thread), href: TagManager.instance.url_for(status.thread)) unless status.thread.nil? + append_element(object, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(status)) + append_element(object, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(status.thread), href: ::TagManager.instance.url_for(status.thread)) unless status.thread.nil? append_element(object, 'ostatus:conversation', nil, ref: conversation_uri(status.conversation)) unless status.conversation_id.nil? object @@ -290,7 +290,7 @@ class OStatus::AtomSerializer entry << object(favourite.status) - append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: TagManager.instance.url_for(favourite.status)) + append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: ::TagManager.instance.url_for(favourite.status)) entry end @@ -312,7 +312,7 @@ class OStatus::AtomSerializer entry << object(favourite.status) - append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: TagManager.instance.url_for(favourite.status)) + append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: ::TagManager.instance.url_for(favourite.status)) entry end diff --git a/app/models/notification.rb b/app/models/notification.rb index 1e64d1ae9..0a5d987cf 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -68,7 +68,10 @@ class Notification < ApplicationRecord class << self def reload_stale_associations!(cached_items) account_ids = cached_items.map(&:from_account_id).uniq - accounts = Account.where(id: account_ids).map { |a| [a.id, a] }.to_h + + return if account_ids.empty? + + accounts = Account.where(id: account_ids).map { |a| [a.id, a] }.to_h cached_items.each do |item| item.from_account = accounts[item.from_account_id] diff --git a/app/models/status.rb b/app/models/status.rb index 107ccface..30d53f298 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -134,7 +134,7 @@ class Status < ApplicationRecord CustomEmoji.from_text([spoiler_text, text].join(' '), account.domain) end - after_create :store_uri, if: :local? + after_create_commit :store_uri, if: :local? around_create Mastodon::Snowflake::Callbacks @@ -194,7 +194,11 @@ class Status < ApplicationRecord account_ids << item.reblog.account_id if item.reblog? end - accounts = Account.where(id: account_ids.uniq).map { |a| [a.id, a] }.to_h + account_ids.uniq! + + return if account_ids.empty? + + accounts = Account.where(id: account_ids).map { |a| [a.id, a] }.to_h cached_items.each do |item| item.account = accounts[item.account_id] @@ -216,9 +220,7 @@ class Status < ApplicationRecord # non-followers can see everything that isn't private/direct, but can see stuff they are mentioned in. visibility.push(:private) if account.following?(target_account) - joins("LEFT OUTER JOIN mentions ON statuses.id = mentions.status_id AND mentions.account_id = #{account.id}") - .where(arel_table[:visibility].in(visibility).or(Mention.arel_table[:id].not_eq(nil))) - .order(visibility: :desc) + where(visibility: visibility).or(where(id: account.mentions.select(:status_id))) end end diff --git a/app/serializers/activitypub/activity_serializer.rb b/app/serializers/activitypub/activity_serializer.rb index df399211c..50c4f6a04 100644 --- a/app/serializers/activitypub/activity_serializer.rb +++ b/app/serializers/activitypub/activity_serializer.rb @@ -5,6 +5,7 @@ class ActivityPub::ActivitySerializer < ActiveModel::Serializer has_one :proper, key: :object, serializer: ActivityPub::NoteSerializer, unless: :announce? attribute :proper_uri, key: :object, if: :announce? + attribute :atom_uri, if: :announce? def id ActivityPub::TagManager.instance.activity_uri_for(object) @@ -34,6 +35,10 @@ class ActivityPub::ActivitySerializer < ActiveModel::Serializer ActivityPub::TagManager.instance.uri_for(object.proper) end + def atom_uri + OStatus::TagManager.instance.uri_for(object) + end + def announce? object.reblog? end diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index cf3d78683..7029c4d75 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -72,6 +72,8 @@ class FetchLinkCardService < BaseService def attempt_oembed response = OEmbed::Providers.get(@url) + return false unless response.respond_to?(:type) + @card.type = response.type @card.title = response.respond_to?(:title) ? response.title : '' @card.author_name = response.respond_to?(:author_name) ? response.author_name : '' @@ -113,7 +115,7 @@ class FetchLinkCardService < BaseService detector.strip_tags = true guess = detector.detect(html, response.charset) - page = Nokogiri::HTML(html, nil, guess&.fetch(:encoding)) + page = Nokogiri::HTML(html, nil, guess&.fetch(:encoding, nil)) if meta_property(page, 'twitter:player') @card.type = :video diff --git a/app/services/fetch_remote_status_service.rb b/app/services/fetch_remote_status_service.rb index cacf6ba51..9c009335b 100644 --- a/app/services/fetch_remote_status_service.rb +++ b/app/services/fetch_remote_status_service.rb @@ -40,6 +40,6 @@ class FetchRemoteStatusService < BaseService end def confirmed_domain?(domain, account) - account.domain.nil? || domain.casecmp(account.domain).zero? || domain.casecmp(Addressable::URI.parse(account.remote_url).normalized_host).zero? + account.domain.nil? || domain.casecmp(account.domain).zero? || domain.casecmp(Addressable::URI.parse(account.remote_url || account.uri).normalized_host).zero? end end diff --git a/app/services/send_interaction_service.rb b/app/services/send_interaction_service.rb index af205c9c9..fabba8a3e 100644 --- a/app/services/send_interaction_service.rb +++ b/app/services/send_interaction_service.rb @@ -12,9 +12,11 @@ class SendInteractionService < BaseService return if !target_account.ostatus? || block_notification? - delivery = build_request.perform.flush + delivery = build_request.perform raise Mastodon::UnexpectedResponseError, delivery unless delivery.code > 199 && delivery.code < 300 + + delivery.connection&.close end private diff --git a/app/services/subscribe_service.rb b/app/services/subscribe_service.rb index 2d8af0203..2f725e2ec 100644 --- a/app/services/subscribe_service.rb +++ b/app/services/subscribe_service.rb @@ -6,7 +6,7 @@ class SubscribeService < BaseService @account = account @account.secret = SecureRandom.hex - @response = build_request.perform.flush + @response = build_request.perform if response_failed_permanently? # We're not allowed to subscribe. Fail and move on. @@ -20,6 +20,7 @@ class SubscribeService < BaseService # We need to retry at a later time. Fail loudly! raise Mastodon::UnexpectedResponseError, @response end + @response.connection&.close end private diff --git a/app/services/unsubscribe_service.rb b/app/services/unsubscribe_service.rb index d84a5a530..01f5c6b7a 100644 --- a/app/services/unsubscribe_service.rb +++ b/app/services/unsubscribe_service.rb @@ -7,9 +7,10 @@ class UnsubscribeService < BaseService @account = account begin - @response = build_request.perform.flush + @response = build_request.perform Rails.logger.debug "PuSH unsubscribe for #{@account.acct} failed: #{@response.status}" unless @response.status.success? + @response.connection&.close rescue HTTP::Error, OpenSSL::SSL::SSLError => e Rails.logger.debug "PuSH unsubscribe for #{@account.acct} failed: #{e}" end diff --git a/app/views/admin/custom_emojis/_custom_emoji.html.haml b/app/views/admin/custom_emojis/_custom_emoji.html.haml index 53263c43f..1fa64908c 100644 --- a/app/views/admin/custom_emojis/_custom_emoji.html.haml +++ b/app/views/admin/custom_emojis/_custom_emoji.html.haml @@ -10,7 +10,7 @@ = custom_emoji.domain %td - unless custom_emoji.local? - = table_link_to 'copy', t('admin.custom_emojis.copy'), copy_admin_custom_emoji_path(custom_emoji), method: :post + = table_link_to 'copy', t('admin.custom_emojis.copy'), copy_admin_custom_emoji_path(custom_emoji, page: params[:page]), method: :post %td - if custom_emoji.disabled? = table_link_to 'power-off', t('admin.custom_emojis.enable'), enable_admin_custom_emoji_path(custom_emoji), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } diff --git a/app/views/tags/show.html.haml b/app/views/tags/show.html.haml index 6266d3c0c..ea8b0faa3 100644 --- a/app/views/tags/show.html.haml +++ b/app/views/tags/show.html.haml @@ -7,31 +7,43 @@ = render 'og' .landing-page.tag-page - .stripe .features .container #mastodon-timeline{ data: { props: Oj.dump(default_props.merge(hashtag: @tag.name)) } } .about-mastodon - .brand - = link_to root_url do - = image_tag asset_pack_path('logo_full.svg'), alt: 'Mastodon' + .about-hashtag + .brand + = link_to root_url do + = image_tag asset_pack_path('logo_full.svg'), alt: 'Mastodon' - %p= t 'about.about_hashtag_html', hashtag: @tag.name + %p= t 'about.about_hashtag_html', hashtag: @tag.name - .cta - = link_to t('auth.login'), new_user_session_path, class: 'button button-secondary' - = link_to t('about.learn_more'), root_url, class: 'button button-alternative' + .cta + = link_to t('auth.login'), new_user_session_path, class: 'button button-secondary' + = link_to t('about.learn_more'), root_url, class: 'button button-alternative' .features-list .features-list__row .text + %h6= t 'about.features.real_conversation_title' + = t 'about.features.real_conversation_body' + .visual + = fa_icon 'fw comments' + .features-list__row + .text %h6= t 'about.features.not_a_product_title' = t 'about.features.not_a_product_body' .visual = fa_icon 'fw users' .features-list__row .text + %h6= t 'about.features.within_reach_title' + = t 'about.features.within_reach_body' + .visual + = fa_icon 'fw mobile' + .features-list__row + .text %h6= t 'about.features.humane_approach_title' = t 'about.features.humane_approach_body' .visual diff --git a/app/workers/activitypub/delivery_worker.rb b/app/workers/activitypub/delivery_worker.rb index 7b1e06a70..ae86e3dd2 100644 --- a/app/workers/activitypub/delivery_worker.rb +++ b/app/workers/activitypub/delivery_worker.rb @@ -16,6 +16,7 @@ class ActivityPub::DeliveryWorker raise Mastodon::UnexpectedResponseError, @response unless response_successful? + @response.connection&.close failure_tracker.track_success! rescue => e failure_tracker.track_failure! @@ -31,7 +32,7 @@ class ActivityPub::DeliveryWorker end def perform_request - @response = build_request.perform.flush + @response = build_request.perform end def response_successful? diff --git a/app/workers/pubsubhubbub/delivery_worker.rb b/app/workers/pubsubhubbub/delivery_worker.rb index c3506727b..a9174edd2 100644 --- a/app/workers/pubsubhubbub/delivery_worker.rb +++ b/app/workers/pubsubhubbub/delivery_worker.rb @@ -27,6 +27,7 @@ class Pubsubhubbub::DeliveryWorker raise Mastodon::UnexpectedResponseError, payload_delivery unless response_successful? + payload_delivery.connection&.close subscription.touch(:last_successful_delivery_at) end @@ -37,7 +38,7 @@ class Pubsubhubbub::DeliveryWorker def callback_post_payload request = Request.new(:post, subscription.callback_url, body: payload) request.add_headers(headers) - request.perform.flush + request.perform end def blocked_domain? |