From b0634b2943352a956f802dfbbd2c672a9c7c4f9d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 6 Jan 2025 14:59:11 -0500 Subject: [PATCH 01/64] Add helpers for ios/android app store links in welcome mailer (#33475) --- app/helpers/application_helper.rb | 8 ++++++++ app/views/application/mailer/_checklist.html.haml | 4 ++-- app/views/user_mailer/welcome.text.erb | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e1ca536c7d..5a5ee05532 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -238,6 +238,14 @@ module ApplicationHelper I18n.t 'user_mailer.welcome.hashtags_recent_count', people: number_with_delimiter(people), count: people end + def app_store_url_ios + 'https://apps.apple.com/app/mastodon-for-iphone-and-ipad/id1571998974' + end + + def app_store_url_android + 'https://play.google.com/store/apps/details?id=org.joinmastodon.android' + end + private def storage_host_var diff --git a/app/views/application/mailer/_checklist.html.haml b/app/views/application/mailer/_checklist.html.haml index 91c7c98f26..4b460fa26d 100644 --- a/app/views/application/mailer/_checklist.html.haml +++ b/app/views/application/mailer/_checklist.html.haml @@ -29,8 +29,8 @@ %div - if defined?(show_apps_buttons) && show_apps_buttons .email-welcome-apps-btns - = link_to image_tag(frontend_asset_url('images/mailer-new/store-icons/btn-app-store.png'), alt: t('user_mailer.welcome.apps_ios_action'), width: 120, height: 40), 'https://apps.apple.com/app/mastodon-for-iphone-and-ipad/id1571998974' - = link_to image_tag(frontend_asset_url('images/mailer-new/store-icons/btn-google-play.png'), alt: t('user_mailer.welcome.apps_android_action'), width: 120, height: 40), 'https://play.google.com/store/apps/details?id=org.joinmastodon.android' + = link_to image_tag(frontend_asset_url('images/mailer-new/store-icons/btn-app-store.png'), alt: t('user_mailer.welcome.apps_ios_action'), width: 120, height: 40), app_store_url_ios + = link_to image_tag(frontend_asset_url('images/mailer-new/store-icons/btn-google-play.png'), alt: t('user_mailer.welcome.apps_android_action'), width: 120, height: 40), app_store_url_android - elsif defined?(button_text) && defined?(button_url) && defined?(checked) && !checked = render 'application/mailer/button', text: button_text, url: button_url, has_arrow: false /[if mso] diff --git a/app/views/user_mailer/welcome.text.erb b/app/views/user_mailer/welcome.text.erb index 144d44b842..383f436f8e 100644 --- a/app/views/user_mailer/welcome.text.erb +++ b/app/views/user_mailer/welcome.text.erb @@ -30,8 +30,8 @@ 5. <%= t('user_mailer.welcome.apps_title') %> <%= t('user_mailer.welcome.apps_step') %> - * iOS: https://apps.apple.com/app/mastodon-for-iphone-and-ipad/id1571998974 - * Android: https://play.google.com/store/apps/details?id=org.joinmastodon.android + * iOS: <%= app_store_url_ios %> + * Android: <%= app_store_url_android %> --- From efcd4ea5de2a617069be546852f504195de0336d Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 6 Jan 2025 18:25:13 -0500 Subject: [PATCH 02/64] Reference value constants from specs (#33479) --- spec/lib/activitypub/activity/create_spec.rb | 8 ++++---- spec/models/account_spec.rb | 3 +-- spec/models/appeal_spec.rb | 2 +- spec/policies/backup_policy_spec.rb | 12 ++++++++++-- spec/requests/api/v1/accounts/credentials_spec.rb | 2 +- spec/requests/api/v1/accounts/notes_spec.rb | 2 +- spec/requests/api/v2/media_spec.rb | 2 +- 7 files changed, 19 insertions(+), 12 deletions(-) diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index 8be6766dad..d70456e458 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -624,7 +624,7 @@ RSpec.describe ActivityPub::Activity::Create do type: 'Document', mediaType: 'image/png', url: 'http://example.com/attachment.png', - name: '*' * 1500, + name: '*' * MediaAttachment::MAX_DESCRIPTION_LENGTH, }, ], } @@ -636,7 +636,7 @@ RSpec.describe ActivityPub::Activity::Create do status = sender.statuses.first expect(status).to_not be_nil - expect(status.media_attachments.map(&:description)).to include('*' * 1500) + expect(status.media_attachments.map(&:description)).to include('*' * MediaAttachment::MAX_DESCRIPTION_LENGTH) end end @@ -651,7 +651,7 @@ RSpec.describe ActivityPub::Activity::Create do type: 'Document', mediaType: 'image/png', url: 'http://example.com/attachment.png', - summary: '*' * 1500, + summary: '*' * MediaAttachment::MAX_DESCRIPTION_LENGTH, }, ], } @@ -663,7 +663,7 @@ RSpec.describe ActivityPub::Activity::Create do status = sender.statuses.first expect(status).to_not be_nil - expect(status.media_attachments.map(&:description)).to include('*' * 1500) + expect(status.media_attachments.map(&:description)).to include('*' * MediaAttachment::MAX_DESCRIPTION_LENGTH) end end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 967809b8e1..7755cf9611 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -824,8 +824,7 @@ RSpec.describe Account do it { is_expected.to_not allow_values(account_note_over_limit).for(:note) } it { is_expected.to allow_value(fields_empty_name_value).for(:fields) } - it { is_expected.to_not allow_value(fields_over_limit).for(:fields) } - it { is_expected.to_not allow_value(fields_empty_name).for(:fields) } + it { is_expected.to_not allow_values(fields_over_limit, fields_empty_name).for(:fields) } end context 'when account is remote' do diff --git a/spec/models/appeal_spec.rb b/spec/models/appeal_spec.rb index e974ff9254..06775f5dd6 100644 --- a/spec/models/appeal_spec.rb +++ b/spec/models/appeal_spec.rb @@ -9,7 +9,7 @@ RSpec.describe Appeal do it { is_expected.to validate_length_of(:text).is_at_most(described_class::TEXT_LENGTH_LIMIT) } context 'with a strike created too long ago' do - let(:strike) { Fabricate.build :account_warning, created_at: 100.days.ago } + let(:strike) { Fabricate.build :account_warning, created_at: (described_class::MAX_STRIKE_AGE * 2).ago } it { is_expected.to_not allow_values(strike).for(:strike).against(:base).on(:create) } end diff --git a/spec/policies/backup_policy_spec.rb b/spec/policies/backup_policy_spec.rb index 031021d91d..28995d195b 100644 --- a/spec/policies/backup_policy_spec.rb +++ b/spec/policies/backup_policy_spec.rb @@ -23,22 +23,30 @@ RSpec.describe BackupPolicy do context 'when backups are too old' do it 'permits' do - travel(-8.days) do + travel(-before_time) do Fabricate(:backup, user: john.user) end expect(subject).to permit(john, Backup) end + + def before_time + described_class::MIN_AGE + 2.days + end end context 'when backups are newer' do it 'denies' do - travel(-3.days) do + travel(-within_time) do Fabricate(:backup, user: john.user) end expect(subject).to_not permit(john, Backup) end + + def within_time + described_class::MIN_AGE - 2.days + end end end end diff --git a/spec/requests/api/v1/accounts/credentials_spec.rb b/spec/requests/api/v1/accounts/credentials_spec.rb index 0bd3ace132..0badc17e1b 100644 --- a/spec/requests/api/v1/accounts/credentials_spec.rb +++ b/spec/requests/api/v1/accounts/credentials_spec.rb @@ -85,7 +85,7 @@ RSpec.describe 'credentials API' do end describe 'with invalid data' do - let(:params) { { note: 'This is too long. ' * 30 } } + let(:params) { { note: 'a' * 2 * Account::NOTE_LENGTH_LIMIT } } it 'returns http unprocessable entity' do subject diff --git a/spec/requests/api/v1/accounts/notes_spec.rb b/spec/requests/api/v1/accounts/notes_spec.rb index 1677ec07e3..e616df1e6f 100644 --- a/spec/requests/api/v1/accounts/notes_spec.rb +++ b/spec/requests/api/v1/accounts/notes_spec.rb @@ -29,7 +29,7 @@ RSpec.describe 'Accounts Notes API' do end context 'when account note exceeds allowed length', :aggregate_failures do - let(:comment) { 'a' * 2_001 } + let(:comment) { 'a' * AccountNote::COMMENT_SIZE_LIMIT * 2 } it 'does not create account note' do subject diff --git a/spec/requests/api/v2/media_spec.rb b/spec/requests/api/v2/media_spec.rb index 807e427d3f..18ebb9cdda 100644 --- a/spec/requests/api/v2/media_spec.rb +++ b/spec/requests/api/v2/media_spec.rb @@ -33,7 +33,7 @@ RSpec.describe 'Media API', :attachment_processing do let(:params) do { file: fixture_file_upload('attachment-jpg.123456_abcd', 'image/jpeg'), - description: 'aa' * MediaAttachment::MAX_DESCRIPTION_LENGTH, + description: 'a' * MediaAttachment::MAX_DESCRIPTION_LENGTH * 2, } end From dd937e115a42b1029038578217bb105c56a0f4a4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 7 Jan 2025 02:47:58 -0500 Subject: [PATCH 03/64] Use `distributable?` method in admin/status_policy method (#33477) --- app/policies/admin/status_policy.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/policies/admin/status_policy.rb b/app/policies/admin/status_policy.rb index e9379c25ec..c4ba5c2606 100644 --- a/app/policies/admin/status_policy.rb +++ b/app/policies/admin/status_policy.rb @@ -12,7 +12,7 @@ class Admin::StatusPolicy < ApplicationPolicy end def show? - role.can?(:manage_reports, :manage_users) && (record.public_visibility? || record.unlisted_visibility? || record.reported? || viewable_through_normal_policy?) + role.can?(:manage_reports, :manage_users) && eligible_to_show? end def destroy? @@ -29,6 +29,10 @@ class Admin::StatusPolicy < ApplicationPolicy private + def eligible_to_show? + record.distributable? || record.reported? || viewable_through_normal_policy? + end + def viewable_through_normal_policy? StatusPolicy.new(current_account, record, @preloaded_relations).show? end From edf62d4fe376d91ce194907b13599305846d4e42 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 7 Jan 2025 02:50:19 -0500 Subject: [PATCH 04/64] Add `self_editing?` method to user role policy (#33476) --- app/policies/user_role_policy.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/policies/user_role_policy.rb b/app/policies/user_role_policy.rb index 6144a0ec4a..44b5589581 100644 --- a/app/policies/user_role_policy.rb +++ b/app/policies/user_role_policy.rb @@ -10,10 +10,16 @@ class UserRolePolicy < ApplicationPolicy end def update? - role.can?(:manage_roles) && (role.overrides?(record) || role.id == record.id) + role.can?(:manage_roles) && (role.overrides?(record) || self_editing?) end def destroy? - !record.everyone? && role.can?(:manage_roles) && role.overrides?(record) && role.id != record.id + !record.everyone? && role.can?(:manage_roles) && role.overrides?(record) && !self_editing? + end + + private + + def self_editing? + role.id == record.id end end From 9715bd796f06f933493ff9f9b3ea2f25a2a2a874 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 08:50:27 +0100 Subject: [PATCH 05/64] New Crowdin Translations (automated) (#33480) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/da.json | 1 + app/javascript/mastodon/locales/fo.json | 2 ++ app/javascript/mastodon/locales/ko.json | 1 + app/javascript/mastodon/locales/lv.json | 3 +- app/javascript/mastodon/locales/sv.json | 34 +++++++++++++++----- config/locales/fo.yml | 42 +++++++++++++++++++++++++ config/locales/simple_form.fo.yml | 22 +++++++++++++ 7 files changed, 96 insertions(+), 9 deletions(-) diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index 92cfb62f51..ad81e5f35a 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -482,6 +482,7 @@ "lists.exclusive": "Skjul medlemmer i Hjem", "lists.exclusive_hint": "Er nogen er på denne liste, skjul personen i hjemme-feeds for at undgå at se vedkommendes indlæg to gange.", "lists.find_users_to_add": "Find brugere at tilføje", + "lists.list_members": "Liste over medlemmer", "lists.list_members_count": "{count, plural, one {# medlem} other {# medlemmer}}", "lists.list_name": "Listetitel", "lists.new_list_name": "Ny listetitel", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index c4d5f7296a..91acfb0e15 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -362,6 +362,7 @@ "footer.privacy_policy": "Privatlívspolitikkur", "footer.source_code": "Vís keldukotuna", "footer.status": "Støða", + "footer.terms_of_service": "Tænastutreytir", "generic.saved": "Goymt", "getting_started.heading": "At byrja", "hashtag.admin_moderation": "Lat umsjónarmarkamót upp fyri #{name}", @@ -858,6 +859,7 @@ "subscribed_languages.target": "Broyt haldaramál fyri {target}", "tabs_bar.home": "Heim", "tabs_bar.notifications": "Fráboðanir", + "terms_of_service.title": "Tænastutreytir", "time_remaining.days": "{number, plural, one {# dagur} other {# dagar}} eftir", "time_remaining.hours": "{number, plural, one {# tími} other {# tímar}} eftir", "time_remaining.minutes": "{number, plural, one {# minuttur} other {# minuttir}} eftir", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 9593744e4b..abaf40931c 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -414,6 +414,7 @@ "interaction_modal.title.reblog": "{name} 님의 게시물을 부스트", "interaction_modal.title.reply": "{name} 님의 게시물에 답글", "interaction_modal.title.vote": "{name} 님의 투표에 참여", + "interaction_modal.username_prompt": "예시: {example}", "intervals.full.days": "{number} 일", "intervals.full.hours": "{number} 시간", "intervals.full.minutes": "{number} 분", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index 1bc3c68382..9244f3509c 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -52,7 +52,7 @@ "account.mute_notifications_short": "Izslēgt paziņojumu skaņu", "account.mute_short": "Apklusināt", "account.muted": "Apklusināts", - "account.mutual": "Savstarpējs", + "account.mutual": "Abpusēji", "account.no_bio": "Apraksts nav sniegts.", "account.open_original_page": "Atvērt oriģinālo lapu", "account.posts": "Ieraksti", @@ -85,6 +85,7 @@ "alert.rate_limited.title": "Biežums ierobežots", "alert.unexpected.message": "Radās negaidīta kļūda.", "alert.unexpected.title": "Ups!", + "alt_text_badge.title": "Alt teksts", "announcement.announcement": "Paziņojums", "annual_report.summary.archetype.oracle": "Orākuls", "annual_report.summary.archetype.replier": "Sabiedriskais tauriņš", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index d53825295f..a9b299c97f 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -141,7 +141,7 @@ "column.bookmarks": "Bokmärken", "column.community": "Lokal tidslinje", "column.create_list": "Skapa lista", - "column.direct": "Privata nämningar", + "column.direct": "Privata omnämnande", "column.directory": "Bläddra bland profiler", "column.domain_blocks": "Blockerade domäner", "column.edit_list": "Redigera lista", @@ -239,6 +239,10 @@ "disabled_account_banner.text": "Ditt konto {disabledAccount} är för närvarande inaktiverat.", "dismissable_banner.community_timeline": "Dessa är de senaste offentliga inläggen från personer vars konton tillhandahålls av {domain}.", "dismissable_banner.dismiss": "Avfärda", + "dismissable_banner.explore_links": "Dessa nyhetshistorier delas mest på fediversum idag. Nyare nyhetshistorier som publiceras av fler olika personer rankas högre.", + "dismissable_banner.explore_statuses": "Dessa inlägg från fediverse vinner dragkraft idag. Nyare inlägg som många boostar och favoritmarkerar rankas högre.", + "dismissable_banner.explore_tags": "De här hashtaggarna vinner dragkraft i fediversum idag. Hashtaggar som används av fler olika personer rankas högre.", + "dismissable_banner.public_timeline": "De här är de aktuella publika inlägg från personer i fediversum som personer i {domain} följer.", "domain_block_modal.block": "Blockera server", "domain_block_modal.block_account_instead": "Blockera @{name} istället", "domain_block_modal.they_can_interact_with_old_posts": "Personer från denna server kan interagera med dina gamla inlägg.", @@ -285,7 +289,7 @@ "empty_column.blocks": "Du har ännu ej blockerat några användare.", "empty_column.bookmarked_statuses": "Du har inte bokmärkt några inlägg än. När du bokmärker ett inlägg kommer det synas här.", "empty_column.community": "Den lokala tidslinjen är tom. Skriv något offentligt för att sätta bollen i rullning!", - "empty_column.direct": "Du har inga privata nämningar. När du skickar eller tar emot ett direktmeddelande kommer det att visas här.", + "empty_column.direct": "Du har inga privata omnämninande. När du skickar eller tar emot ett direktmeddelande kommer det att visas här.", "empty_column.domain_blocks": "Det finns ännu inga dolda domäner.", "empty_column.explore_statuses": "Ingenting är trendigt just nu. Kom tillbaka senare!", "empty_column.favourited_statuses": "Du har inga favoritmarkerade inlägg ännu. När du favoritmärker ett så kommer det att dyka upp här.", @@ -402,7 +406,14 @@ "ignore_notifications_modal.new_accounts_title": "Vill du ignorera aviseringar från nya konton?", "ignore_notifications_modal.not_followers_title": "Vill du ignorera aviseringar från personer som inte följer dig?", "ignore_notifications_modal.not_following_title": "Vill du blockera aviseringar från personer som du inte följer dig?", - "ignore_notifications_modal.private_mentions_title": "Vill du ignorera aviseringar från oönskade privata omnämningar?", + "ignore_notifications_modal.private_mentions_title": "Vill du ignorera aviseringar från oombedda privata omnämnanden?", + "interaction_modal.action.favourite": "För att fortsätta, måste du favoritmarkera från ditt konto.", + "interaction_modal.action.follow": "För att fortsätta, måste du följa från ditt konto.", + "interaction_modal.action.reblog": "För att fortsätta, måste du boosta från ditt konto.", + "interaction_modal.action.reply": "För att fortsätta, måste du svara från ditt konto.", + "interaction_modal.action.vote": "För att fortsätta, måste du rösta från ditt konto.", + "interaction_modal.go": "Vidare", + "interaction_modal.no_account_yet": "Har du inget konto än?", "interaction_modal.on_another_server": "På en annan server", "interaction_modal.on_this_server": "På denna server", "interaction_modal.title.favourite": "Favoritmarkera {name}s inlägg", @@ -410,6 +421,7 @@ "interaction_modal.title.reblog": "Boosta {name}s inlägg", "interaction_modal.title.reply": "Svara på {name}s inlägg", "interaction_modal.title.vote": "Rösta i {name}s enkät", + "interaction_modal.username_prompt": "T.ex. {example}", "intervals.full.days": "{number, plural, one {# dag} other {# dagar}}", "intervals.full.hours": "{number, plural, one {# timme} other {# timmar}}", "intervals.full.minutes": "{number, plural, one {# minut} other {# minuter}}", @@ -419,7 +431,7 @@ "keyboard_shortcuts.column": "Fokusera kolumn", "keyboard_shortcuts.compose": "Fokusera skrivfältet", "keyboard_shortcuts.description": "Beskrivning", - "keyboard_shortcuts.direct": "för att öppna privata nämningskolumnen", + "keyboard_shortcuts.direct": "för att öppna privata omnämnandekolumnen", "keyboard_shortcuts.down": "Flytta ner i listan", "keyboard_shortcuts.enter": "Öppna inlägg", "keyboard_shortcuts.favourite": "Favoritmarkera inlägg", @@ -445,6 +457,7 @@ "keyboard_shortcuts.toggle_hidden": "Visa/gömma text bakom CW", "keyboard_shortcuts.toggle_sensitivity": "Visa/gömma media", "keyboard_shortcuts.toot": "Starta nytt inlägg", + "keyboard_shortcuts.translate": "för att översätta ett inlägg", "keyboard_shortcuts.unfocus": "Avfokusera skrivfält/sökfält", "keyboard_shortcuts.up": "Flytta uppåt i listan", "lightbox.close": "Stäng", @@ -466,6 +479,7 @@ "lists.delete": "Radera lista", "lists.done": "Klar", "lists.edit": "Redigera lista", + "lists.exclusive": "Dölj medlemmar i Hem flödet", "lists.exclusive_hint": "Om någon är med på den här listan, göm dem i ditt Hemtidlinje för att undvika att se deras inlägg två gånger.", "lists.find_users_to_add": "Hitta användare att lägga till", "lists.list_members": "Lista medlemmar", @@ -474,12 +488,14 @@ "lists.new_list_name": "Nytt listnamn", "lists.no_lists_yet": "Ännu inga listor.", "lists.no_members_yet": "Inga medlemmar ännu.", + "lists.no_results_found": "Inga resultat hittades.", "lists.remove_member": "Ta bort", "lists.replies_policy.followed": "Alla användare som följs", "lists.replies_policy.list": "Medlemmar i listan", "lists.replies_policy.none": "Ingen", "lists.save": "Spara", "lists.search": "Sök", + "lists.show_replies_to": "Inkludera svar från listmedlemmar till", "load_pending": "{count, plural, one {# nytt objekt} other {# nya objekt}}", "loading_indicator.label": "Laddar…", "media_gallery.hide": "Dölj", @@ -500,7 +516,7 @@ "navigation_bar.bookmarks": "Bokmärken", "navigation_bar.community_timeline": "Lokal tidslinje", "navigation_bar.compose": "Författa nytt inlägg", - "navigation_bar.direct": "Privata nämningar", + "navigation_bar.direct": "Privata omnämnande", "navigation_bar.discover": "Upptäck", "navigation_bar.domain_blocks": "Dolda domäner", "navigation_bar.explore": "Utforska", @@ -532,12 +548,14 @@ "notification.annual_report.view": "Visa #Wrapstodon", "notification.favourite": "{name} favoritmarkerade ditt inlägg", "notification.favourite.name_and_others_with_link": "{name} och {count, plural, one {# annan} other {# andra}} har favoritmarkerat ditt inlägg", + "notification.favourite_pm": "{name} favoritmarkerade ditt privata omnämnande", + "notification.favourite_pm.name_and_others_with_link": "{name} och {count, plural, one {# annan} other {# andra}} favoritmarkerade ditt privata omnämnande", "notification.follow": "{name} följer dig", "notification.follow.name_and_others": "{name} och {count, plural, one {# annan} other {# andra}} följer dig", "notification.follow_request": "{name} har begärt att följa dig", "notification.follow_request.name_and_others": "{name} och {count, plural, one {# en annan} other {# andra}} har bett att följa dig", "notification.label.mention": "Nämn", - "notification.label.private_mention": "Privat nämning", + "notification.label.private_mention": "Privat omnämnande", "notification.label.private_reply": "Privata svar", "notification.label.reply": "Svar", "notification.mention": "Nämn", @@ -783,8 +801,8 @@ "status.copy": "Kopiera inläggslänk", "status.delete": "Radera", "status.detailed_status": "Detaljerad samtalsvy", - "status.direct": "Nämn @{name} privat", - "status.direct_indicator": "Privat nämning", + "status.direct": "Omnämn @{name} privat", + "status.direct_indicator": "Privat omnämnande", "status.edit": "Redigera", "status.edited": "Senast ändrad {date}", "status.edited_x_times": "Redigerad {count, plural, one {{count} gång} other {{count} gånger}}", diff --git a/config/locales/fo.yml b/config/locales/fo.yml index 00ffed90bb..441217ec0e 100644 --- a/config/locales/fo.yml +++ b/config/locales/fo.yml @@ -214,6 +214,7 @@ fo: enable_user: Ger brúkara virknan memorialize_account: Minnst til Konto promote_user: Vís fram Brúkara + publish_terms_of_service: Útgev tænastutreytir reject_appeal: Avvís mótmali reject_user: Avvís Brúkara remove_avatar_user: Sletta Avatar @@ -278,6 +279,7 @@ fo: enable_user_html: "%{name} gjørdi innritan virkna fyri brúkaran %{target}" memorialize_account_html: "%{name} broytti kontuna hjá %{target} til eina minnissíðu" promote_user_html: "%{name} flutti brúkaran %{target} fram" + publish_terms_of_service_html: "%{name} útgav dagføringar til tænastutreytirnar" reject_appeal_html: "%{name} avvísti umsjónaráheitan frá %{target}" reject_user_html: "%{name} avvísti skráseting hjá %{target}" remove_avatar_user_html: "%{name} strikaði eftirgjørda skapningin hjá %{target}" @@ -925,6 +927,32 @@ fo: search: Leita title: Frámerki updated_msg: Frámerkjastillingar dagførdar + terms_of_service: + back: Aftur til tænastutreytir + changelog: Hvat er broytt + create: Brúka tínar egnu + current: Núverandi + draft: Kladda + generate: Brúka leist + generates: + action: Framleið + chance_to_review_html: "Framleiddu tænastutreytirnar verða ikki útgivnar av sær sjálvum. Tú fær møguleika at eftirhyggja úrslitini. Vinarliga útfyll neyðugu smálutirnar fyri at halda fram." + explanation_html: Leisturin við tænastutreytum er einans til kunningar og skal ikki fatast sum løgfrøðislig ráðgeving yvirhøvur. Vinarliga spyr tín egna løgfrøðisliga ráðgeva um tína støðu og ítøkiligu løgfrøðisligu spurningarnar hjá tær. + title: Uppseting av tænastutreytum + history: Søga + live: Beinleiðis + no_history: Enn eru ongar skrásettar broytingar í tænastutreytunum. + no_terms_of_service_html: Í løtuni hevur tú ongar tænastutreytir uppsettar. Hugsanin við tænastutreytum er at veita greidleika og at verja teg ímóti møguligum ábyrgdum í ósemjum við tínar brúkarar. + notified_on_html: Fráboðan latin brúkarum %{date} + notify_users: Gev brúkarum fráboðan + preview: + explanation_html: 'Teldubrævið verður sent til %{display_count} brúkarar, sum hava stovna kontu áðrenn %{date}. Fylgjandi tekstur kemur við í teldubrævið:' + send_preview: Send undanvísing til %{email} + title: Undanvís fráboðan um tænastutreytir + publish: Útgev + published_on_html: Útgivið %{date} + save_draft: Goym kladdu + title: Tænastutreytir title: Umsiting trends: allow: Loyv @@ -1156,6 +1184,7 @@ fo: set_new_password: Áset nýtt loyniorð setup: email_below_hint_html: Kekka mappuna við ruskposti ella bið um ein annan. Tú kanst rætta teldupostadressuna, um hon er skeiv. + email_settings_hint_html: Trýst á leinkið, sum vit sendu til %{email} fyri at byrja at brúka Mastodon. Vit bíða beint her. link_not_received: Fekk tú einki leinki? new_confirmation_instructions_sent: Tú fer at móttaka eitt nýtt teldubræv við váttanarleinkinum um nakrar fáar minuttir! title: Kekka innbakkan hjá tær @@ -1164,6 +1193,7 @@ fo: title: Rita inn á %{domain} sign_up: manual_review: Tilmeldingar til %{domain} fara ígjøgnum eina manuella eftirkanning av okkara kjakleiðarum. Fyri at hjálpa okkum at skunda undir skrásetingina, skriva eitt sindur um teg sjálva/n og hví tú vil hava eina kontu á %{domain}. + preamble: Við eini kontu á hesum Mastodon ambætaranum ber til hjá tær at fylgja ein og hvønn annan persón á fediversinum, óansæð hvar teirra konta er hýst. title: Latum okkum fáa teg settan upp á %{domain}. status: account_status: Kontustøða @@ -1175,6 +1205,7 @@ fo: view_strikes: Vís eldri atsóknir móti tíni kontu too_fast: Oyðublaðið innsent ov skjótt, royn aftur. use_security_key: Brúka trygdarlykil + user_agreement_html: Eg havi lisið og taki undir við tænastutreytunum og privatlívspolitikkinum author_attribution: example_title: Tekstadømi hint_html: Skrivar tú tíðindi ella greinar til bloggin uttanfyri Mastodon? Her kanst tú stýra, hvussu tú verður tilsipað/ur, tá ið títt tilfar verður deilt á Mastodon. @@ -1836,6 +1867,8 @@ fo: too_late: Tað er ov seint at kæra hesa atsókn tags: does_not_match_previous_name: samsvarar ikki við undanfarna navnið + terms_of_service: + title: Tænastutreytir themes: contrast: Mastodon (høgur kontrastur) default: Mastodon (myrkt) @@ -1896,6 +1929,15 @@ fo: further_actions_html: Var hetta ikki tú, so mæla vit til, at tú %{action} beinan vegin og at tú ger váttan í tveimum stigum virkna fyri at konta tín kann vera trygg. subject: Atgongd er fingin til kontu tína frá eini nýggjari IP adressu title: Ein nýggj innritan + terms_of_service_changed: + agreement: Við framhaldandi at brúka %{domain} góðtekur tú hesar treytir. Tekur tú ikki undir við dagførdu treytunum, so kanst tú til einhvørja tíð uppsiga avtaluna við %{domain} við at strika kontu tína. + changelog: 'Í stuttum merkir henda dagføringin:' + description: 'Tú móttekur hetta teldubrævið, tí at vit gera nakrar broytingar í okkara tænastutreytum á %{domain}. Vit eggja tær til at eftirhyggja dagførdu treytirnar her:' + description_html: Tú móttekur hetta teldubrævið, tí at vit gera nakrar broytingar í okkara tænastutreytum á %{domain}. Vit eggja tær til at eftirhyggja dagførdu og samlaðu treytirnar her. + sign_off: "%{domain} toymið" + subject: Dagføringar til okkara tænastutreytir + subtitle: Tænastutreytirnar hjá %{domain} eru við at verða broyttar + title: Týdningarmikil dagføring warning: appeal: Innsend eina kæru appeal_description: Trýrt tú, at hetta er ein feilur, so kanst tú senda eina kæru til starvsfólkini á %{instance}. diff --git a/config/locales/simple_form.fo.yml b/config/locales/simple_form.fo.yml index 0c9ec51722..99bb1ccaa0 100644 --- a/config/locales/simple_form.fo.yml +++ b/config/locales/simple_form.fo.yml @@ -130,6 +130,17 @@ fo: show_application: Óansæð, so er altíð møguligt hjá tær at síggja, hvør app postaði tín post. tag: name: Tú kanst einans broyta millum stórar og smáar stavir, til dømis fyri at gera tað meira lesiligt + terms_of_service: + changelog: Kunnu vera uppbygdar við Markdown syntaksi. + text: Kunnu vera uppbygdar við Markdown syntaksi. + terms_of_service_generator: + admin_email: Løgfrøðisligar fráboðanir fata um rættarligar mótfráboðanir, úrskurðir, áheitanir um at taka niður og løgfrøðisligar áheitanir. + arbitration_address: Kann vera tann sami sum fysiski bústaðurin omanfyri ella "N/A", um teldupostur verður brúktur + arbitration_website: Kann vera ein vevformularur ella "N/A", um teldupostur verður brúktur + dmca_address: Fyristøðufólk og -feløg í USA brúka bústaðin, ið er skrásettur í DMCA Designated Agent Directory. Ein postsmoguskráseting er tøk, um biðið verður um hana beinleiðis. Brúka DMCA Designated Agent Post Office Box Waiver Request fyri at senda teldubræv til Copyright Office og greið frá, at tú er ein kjakleiðari, sum virkar heimanifrá, og at tú er bangin fyri hevnd ella afturløning fyri tí, tú ger, og at tú hevur tørv á at brúka eina postsmogu fyri at fjala heimabústaðin fyri almenninginum. + dmca_email: Kann vera sami teldupoststaður, sum er brúktur til "Teldupoststaður fyri løgfrøðisligar fráboðanir" omanfyri + domain: Makaleys eyðmerking av nettænastuni, sum tú veitir. + jurisdiction: Lista landið, har sum tann, ið rindar rokningarnar, livir. Er tað eitt felag ella ein onnur eind, lista landið, har tað er skrásett, umframt býin, økið, umveldið ella statin, alt eftir hvat er hóskandi. user: chosen_languages: Tá hetta er valt, verða einans postar í valdum málum vístir á almennum tíðarlinjum role: Leikluturin stýrir hvørji rættindi, brúkarin hevur. @@ -319,6 +330,17 @@ fo: name: Tvíkrossur trendable: Loyv hesum frámerki at síggjast undir rákum usable: Loyv postum at brúka hetta frámerki lokalt + terms_of_service: + changelog: Hvat er broytt? + text: Tænastutreytir + terms_of_service_generator: + admin_email: Teldupoststaður fyri løgfrøðisligar fráboðanir + arbitration_address: Fysisk adressa fyri gerðarrættarfráboðanir + arbitration_website: Heimasíða har gerðarrættarfráboðanir kunnu innlatast + dmca_address: Fysiskur bústaður fyri DMCA/copyright fráboðanir + dmca_email: Teldubústaður fyri DMCA/copyright fráboðanir + domain: Navnaøki + jurisdiction: Løgdømi user: role: Leiklutur time_zone: Tíðarsona From 8233293429baa8721f0193d3228df793f3c3f882 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 09:28:06 +0000 Subject: [PATCH 06/64] Update DefinitelyTyped types (non-major) (#33220) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Renaud Chaput --- package.json | 2 ++ yarn.lock | 44 ++++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 6eee16dc28..a4817816a2 100644 --- a/package.json +++ b/package.json @@ -198,6 +198,8 @@ "webpack-dev-server": "^3.11.3" }, "resolutions": { + "@types/react": "^18.2.7", + "@types/react-dom": "^18.2.4", "kind-of": "^6.0.3", "webpack/terser-webpack-plugin": "^4.2.3" }, diff --git a/yarn.lock b/yarn.lock index 8278a45d40..119c85c7af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3830,12 +3830,12 @@ __metadata: linkType: hard "@types/hoist-non-react-statics@npm:3, @types/hoist-non-react-statics@npm:^3.3.1": - version: 3.3.5 - resolution: "@types/hoist-non-react-statics@npm:3.3.5" + version: 3.3.6 + resolution: "@types/hoist-non-react-statics@npm:3.3.6" dependencies: "@types/react": "npm:*" hoist-non-react-statics: "npm:^3.3.0" - checksum: 10c0/2a3b64bf3d9817d7830afa60ee314493c475fb09570a64e7737084cd482d2177ebdddf888ce837350bac51741278b077683facc9541f052d4bbe8487b4e3e618 + checksum: 10c0/149a4c217d81f21f8a1e152160a59d5b99b6a9aa6d354385d5f5bc02760cbf1e170a8442ba92eb653befff44b0c5bc2234bb77ce33e0d11a65f779e8bab5c321 languageName: node linkType: hard @@ -4015,9 +4015,9 @@ __metadata: linkType: hard "@types/prop-types@npm:*, @types/prop-types@npm:^15.7.5": - version: 15.7.13 - resolution: "@types/prop-types@npm:15.7.13" - checksum: 10c0/1b20fc67281902c6743379960247bc161f3f0406ffc0df8e7058745a85ea1538612109db0406290512947f9632fe9e10e7337bf0ce6338a91d6c948df16a7c61 + version: 15.7.14 + resolution: "@types/prop-types@npm:15.7.14" + checksum: 10c0/1ec775160bfab90b67a782d735952158c7e702ca4502968aa82565bd8e452c2de8601c8dfe349733073c31179116cf7340710160d3836aa8a1ef76d1532893b1 languageName: node linkType: hard @@ -4057,11 +4057,11 @@ __metadata: linkType: hard "@types/react-dom@npm:^18.2.4": - version: 18.3.1 - resolution: "@types/react-dom@npm:18.3.1" - dependencies: - "@types/react": "npm:*" - checksum: 10c0/8b416551c60bb6bd8ec10e198c957910cfb271bc3922463040b0d57cf4739cdcd24b13224f8d68f10318926e1ec3cd69af0af79f0291b599a992f8c80d47f1eb + version: 18.3.5 + resolution: "@types/react-dom@npm:18.3.5" + peerDependencies: + "@types/react": ^18.0.0 + checksum: 10c0/b163d35a6b32a79f5782574a7aeb12a31a647e248792bf437e6d596e2676961c394c5e3c6e91d1ce44ae90441dbaf93158efb4f051c0d61e2612f1cb04ce4faa languageName: node linkType: hard @@ -4124,20 +4124,20 @@ __metadata: linkType: hard "@types/react-swipeable-views@npm:^0.13.1": - version: 0.13.5 - resolution: "@types/react-swipeable-views@npm:0.13.5" + version: 0.13.6 + resolution: "@types/react-swipeable-views@npm:0.13.6" dependencies: "@types/react": "npm:*" - checksum: 10c0/d1dcc78d862f37d30a43d79d915fdb388e05dce0b2ac07462ca4f1b00e0eef37cb41d75997f5685dec79bcce1ffee0dfbc744f20d5266dd3090658def5b4e193 + checksum: 10c0/a26879146748417234bb7f44c5a71e6bab2b76c0b34c72f0493c18403487a5d77021510e8665bd8bd22786904fbbd90d6db55c8dd2bf983c32421139de851c94 languageName: node linkType: hard "@types/react-test-renderer@npm:^18.0.0": - version: 18.3.0 - resolution: "@types/react-test-renderer@npm:18.3.0" + version: 18.3.1 + resolution: "@types/react-test-renderer@npm:18.3.1" dependencies: - "@types/react": "npm:*" - checksum: 10c0/3c9748be52e8e659e7adf91dea6939486463264e6f633bf21c4cb116de18af7bef0595568a1e588160420b2f65289473075dda1cb417c2875df8cf7a09f5d913 + "@types/react": "npm:^18" + checksum: 10c0/9fc8467ff1a3f14be6cc3498a75fc788d2c92c0fffa7bf21269ed5d9d82db9195bf2178ddc42ea16a0836995c1b77601c6be8abb27bd1864668c418c6d0e5a3b languageName: node linkType: hard @@ -4159,13 +4159,13 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7": - version: 18.3.12 - resolution: "@types/react@npm:18.3.12" +"@types/react@npm:^18.2.7": + version: 18.3.18 + resolution: "@types/react@npm:18.3.18" dependencies: "@types/prop-types": "npm:*" csstype: "npm:^3.0.2" - checksum: 10c0/8bae8d9a41619804561574792e29112b413044eb0d53746dde2b9720c1f9a59f71c895bbd7987cd8ce9500b00786e53bc032dced38cddf42910458e145675290 + checksum: 10c0/8fb2b00672072135d0858dc9db07873ea107cc238b6228aaa2a9afd1ef7a64a7074078250db38afbeb19064be8ea6af5eac32d404efdd5f45e093cc4829d87f8 languageName: node linkType: hard From c12b85e7a94a04cb391b13ba2f5ae6b69315cef7 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Tue, 7 Jan 2025 06:24:52 -0500 Subject: [PATCH 07/64] Fix Style/MultipleComparison (#33313) Co-authored-by: Matt Jankowski --- .rubocop/style.yml | 3 --- app/lib/activitypub/tag_manager.rb | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.rubocop/style.yml b/.rubocop/style.yml index 7dd4299c3e..df1da2ba36 100644 --- a/.rubocop/style.yml +++ b/.rubocop/style.yml @@ -29,9 +29,6 @@ Style/IfUnlessModifier: Style/KeywordArgumentsMerging: Enabled: false -Style/MultipleComparison: - Enabled: false - Style/NumericLiterals: AllowedPatterns: - \d{4}_\d{2}_\d{2}_\d{6} diff --git a/app/lib/activitypub/tag_manager.rb b/app/lib/activitypub/tag_manager.rb index 23b44be372..a489928407 100644 --- a/app/lib/activitypub/tag_manager.rb +++ b/app/lib/activitypub/tag_manager.rb @@ -13,7 +13,7 @@ class ActivityPub::TagManager }.freeze def public_collection?(uri) - uri == COLLECTIONS[:public] || uri == 'as:Public' || uri == 'Public' + uri == COLLECTIONS[:public] || %w(as:Public Public).include?(uri) end def url_for(target) From 82e046ea0661e23681304d0e3b95d59736256d21 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 7 Jan 2025 12:29:38 +0100 Subject: [PATCH 08/64] =?UTF-8?q?Fix=20preview=20card=20sizing=20in=20?= =?UTF-8?q?=E2=80=9CAuthor=20attribution=E2=80=9D=20in=20profile=20setting?= =?UTF-8?q?s=20(#33482)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/javascript/styles/mastodon/forms.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index d79ab2aa21..82c53de5f7 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -659,6 +659,10 @@ code { } } } + + .status-card { + contain: unset; + } } .block-icon { From 927c7bb6bb5ac1bd86bad776d6260e22f6aae4f5 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 7 Jan 2025 08:46:56 -0500 Subject: [PATCH 09/64] Use ruby version 3.4.1 (#33304) --- .github/ISSUE_TEMPLATE/2.server_bug_report.yml | 2 +- .github/ISSUE_TEMPLATE/3.troubleshooting.yml | 2 +- .github/renovate.json5 | 5 ----- .github/workflows/test-ruby.yml | 4 ++++ .ruby-version | 2 +- Dockerfile | 6 +++--- Gemfile | 2 +- Gemfile.lock | 8 ++++---- 8 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/2.server_bug_report.yml b/.github/ISSUE_TEMPLATE/2.server_bug_report.yml index a66f5c1076..b868c672f3 100644 --- a/.github/ISSUE_TEMPLATE/2.server_bug_report.yml +++ b/.github/ISSUE_TEMPLATE/2.server_bug_report.yml @@ -60,7 +60,7 @@ body: Any additional technical details you may have, like logs or error traces value: | If this is happening on your own Mastodon server, please fill out those: - - Ruby version: (from `ruby --version`, eg. v3.3.5) + - Ruby version: (from `ruby --version`, eg. v3.4.1) - Node.js version: (from `node --version`, eg. v20.18.0) validations: required: false diff --git a/.github/ISSUE_TEMPLATE/3.troubleshooting.yml b/.github/ISSUE_TEMPLATE/3.troubleshooting.yml index eeb74b160b..fa9bfc7c80 100644 --- a/.github/ISSUE_TEMPLATE/3.troubleshooting.yml +++ b/.github/ISSUE_TEMPLATE/3.troubleshooting.yml @@ -61,7 +61,7 @@ body: value: | Please at least include those informations: - Operating system: (eg. Ubuntu 22.04) - - Ruby version: (from `ruby --version`, eg. v3.3.5) + - Ruby version: (from `ruby --version`, eg. v3.4.1) - Node.js version: (from `node --version`, eg. v20.18.0) validations: required: false diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 3d3499922e..8a10676283 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -14,11 +14,6 @@ // If we do not want a package to be grouped with others, we need to set its groupName // to `null` after any other rule set it to something. dependencyDashboardHeader: 'This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more. Before approving any upgrade: read the description and comments in the [`renovate.json5` file](https://github.com/mastodon/mastodon/blob/main/.github/renovate.json5).', - constraints: { - // Mastodon should work on Ruby 3.4, but its test dependencies are currently uninstallable on Ruby 3.4. - // TODO: remove this once https://github.com/briandunn/flatware/issues/103 is fixed - ruby: '3.3', - }, postUpdateOptions: ['yarnDedupeHighest'], packageRules: [ { diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 900faad07f..4deb08d328 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -125,6 +125,7 @@ jobs: matrix: ruby-version: - '3.2' + - '3.3' - '.ruby-version' steps: - uses: actions/checkout@v4 @@ -226,6 +227,7 @@ jobs: matrix: ruby-version: - '3.2' + - '3.3' - '.ruby-version' steps: - uses: actions/checkout@v4 @@ -304,6 +306,7 @@ jobs: matrix: ruby-version: - '3.2' + - '3.3' - '.ruby-version' steps: @@ -420,6 +423,7 @@ jobs: matrix: ruby-version: - '3.2' + - '3.3' - '.ruby-version' search-image: - docker.elastic.co/elasticsearch/elasticsearch:7.17.13 diff --git a/.ruby-version b/.ruby-version index 9c25013dbb..47b322c971 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.3.6 +3.4.1 diff --git a/Dockerfile b/Dockerfile index d80a4e1555..97c7a91499 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,9 +10,9 @@ ARG TARGETPLATFORM=${TARGETPLATFORM} ARG BUILDPLATFORM=${BUILDPLATFORM} -# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"] +# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.4.x"] # renovate: datasource=docker depName=docker.io/ruby -ARG RUBY_VERSION="3.3.6" +ARG RUBY_VERSION="3.4.1" # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] # renovate: datasource=node-version depName=node ARG NODE_MAJOR_VERSION="22" @@ -20,7 +20,7 @@ ARG NODE_MAJOR_VERSION="22" ARG DEBIAN_VERSION="bookworm" # Node image to use for base image based on combined variables (ex: 20-bookworm-slim) FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim AS node -# Ruby image to use for base image based on combined variables (ex: 3.3.x-slim-bookworm) +# Ruby image to use for base image based on combined variables (ex: 3.4.x-slim-bookworm) FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} AS ruby # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA diff --git a/Gemfile b/Gemfile index ad174cfdc4..d2e6769ace 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ # frozen_string_literal: true source 'https://rubygems.org' -ruby '>= 3.2.0', '< 3.5' +ruby '>= 3.2.0', '< 3.5.0' gem 'propshaft' gem 'puma', '~> 6.3' diff --git a/Gemfile.lock b/Gemfile.lock index f49de6bf3b..afb06744ed 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -238,11 +238,11 @@ GEM ffi-compiler (1.3.2) ffi (>= 1.15.5) rake - flatware (2.3.3) + flatware (2.3.4) drb thor (< 2.0) - flatware-rspec (2.3.3) - flatware (= 2.3.3) + flatware-rspec (2.3.4) + flatware (= 2.3.4) rspec (>= 3.6) fog-core (2.5.0) builder @@ -1034,7 +1034,7 @@ DEPENDENCIES xorcist (~> 1.1) RUBY VERSION - ruby 3.3.6p108 + ruby 3.4.1p0 BUNDLED WITH 2.6.2 From fdfbf6e04ee398b3fe39bf2dbddb810c63cb395f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 7 Jan 2025 09:11:12 -0500 Subject: [PATCH 10/64] Set statement timeout to zero in maintenance CLI (#33484) --- lib/mastodon/cli/maintenance.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/mastodon/cli/maintenance.rb b/lib/mastodon/cli/maintenance.rb index 532fbc328a..32ee35c7c7 100644 --- a/lib/mastodon/cli/maintenance.rb +++ b/lib/mastodon/cli/maintenance.rb @@ -192,6 +192,7 @@ module Mastodon::CLI verify_schema_version! verify_sidekiq_not_active! verify_backup_warning! + disable_timeout! end def process_deduplications @@ -251,6 +252,13 @@ module Mastodon::CLI fail_with_message 'Maintenance process stopped.' unless yes?('Continue? (Yes/No)') end + def disable_timeout! + # Remove server-configured timeout if present + database_connection.execute(<<~SQL.squish) + SET statement_timeout = 0 + SQL + end + def deduplicate_accounts! remove_index_if_exists!(:accounts, 'index_accounts_on_username_and_domain_lower') From fd7bcfa7493b789cb420b9c3357d83196dd71b45 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:18:05 +0100 Subject: [PATCH 11/64] Update dependency rubocop-performance to v1.23.1 (#33486) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index afb06744ed..43959a9e77 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -723,7 +723,7 @@ GEM parser (>= 3.3.1.0) rubocop-capybara (2.21.0) rubocop (~> 1.41) - rubocop-performance (1.23.0) + rubocop-performance (1.23.1) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) rubocop-rails (2.28.0) From 7d6fd68efd92b40d3b432d80f5f59383f0a8c493 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:18:09 +0100 Subject: [PATCH 12/64] Update dependency test-prof to v1.4.4 (#33487) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 43959a9e77..4a71eccab5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -809,7 +809,7 @@ GEM unicode-display_width (>= 1.1.1, < 3) terrapin (1.0.1) climate_control - test-prof (1.4.3) + test-prof (1.4.4) thor (1.3.2) tilt (2.5.0) timeout (0.4.3) From 5c4e224b66c77d55f98be4db38758f1ba92c4171 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Tue, 7 Jan 2025 16:40:24 +0100 Subject: [PATCH 13/64] Comment sidekiq build in docker compose (#33483) --- docker-compose.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 6048129318..63f17bf495 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -100,7 +100,8 @@ services: - redis sidekiq: - build: . + # You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes + # build: . image: ghcr.io/mastodon/mastodon:v4.3.2 restart: always env_file: .env.production From e0863fd7660b3ac08e309d750df7d0c2cb46b5a1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:06:00 +0100 Subject: [PATCH 14/64] Update peter-evans/create-pull-request action to v7.0.6 (#33492) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/crowdin-download-stable.yml | 2 +- .github/workflows/crowdin-download.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/crowdin-download-stable.yml b/.github/workflows/crowdin-download-stable.yml index ef28258cca..6d9a058629 100644 --- a/.github/workflows/crowdin-download-stable.yml +++ b/.github/workflows/crowdin-download-stable.yml @@ -50,7 +50,7 @@ jobs: # Create or update the pull request - name: Create Pull Request - uses: peter-evans/create-pull-request@v7.0.5 + uses: peter-evans/create-pull-request@v7.0.6 with: commit-message: 'New Crowdin translations' title: 'New Crowdin Translations for ${{ github.base_ref || github.ref_name }} (automated)' diff --git a/.github/workflows/crowdin-download.yml b/.github/workflows/crowdin-download.yml index e9b909b9e0..a7e47bb2a1 100644 --- a/.github/workflows/crowdin-download.yml +++ b/.github/workflows/crowdin-download.yml @@ -52,7 +52,7 @@ jobs: # Create or update the pull request - name: Create Pull Request - uses: peter-evans/create-pull-request@v7.0.5 + uses: peter-evans/create-pull-request@v7.0.6 with: commit-message: 'New Crowdin translations' title: 'New Crowdin Translations (automated)' From 5bbcb1bb2ee5ce57b1a6a0d9168fa938e61b408a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:06:05 +0100 Subject: [PATCH 15/64] Update dependency fastimage to v2.4.0 (#33491) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4a71eccab5..9c81c57ce4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -233,7 +233,7 @@ GEM faraday-net_http (3.4.0) net-http (>= 0.5.0) fast_blank (1.0.1) - fastimage (2.3.1) + fastimage (2.4.0) ffi (1.17.1) ffi-compiler (1.3.2) ffi (>= 1.15.5) From bbe9dcfade3b9766721604fd3fb811e0303f5836 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:06:11 +0100 Subject: [PATCH 16/64] Update dependency aws-sdk-s3 to v1.177.0 (#33490) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9c81c57ce4..e2525b13e2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -94,7 +94,7 @@ GEM ast (2.4.2) attr_required (1.0.2) aws-eventstream (1.3.0) - aws-partitions (1.1029.0) + aws-partitions (1.1032.0) aws-sdk-core (3.214.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) @@ -103,7 +103,7 @@ GEM aws-sdk-kms (1.96.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.176.1) + aws-sdk-s3 (1.177.0) aws-sdk-core (~> 3, >= 3.210.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) From 7ad44e22edee9b07f5a1b2df1efb5b5c7a12afe5 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 7 Jan 2025 11:28:35 -0500 Subject: [PATCH 17/64] Remove role color highlighting from custom css (#33493) --- app/controllers/custom_css_controller.rb | 6 ----- app/models/user_role.rb | 3 --- app/views/admin/roles/_role.html.haml | 4 ++-- app/views/custom_css/show.css.erb | 6 ----- spec/requests/custom_css_spec.rb | 29 ------------------------ 5 files changed, 2 insertions(+), 46 deletions(-) diff --git a/app/controllers/custom_css_controller.rb b/app/controllers/custom_css_controller.rb index eb6417698a..9f33870bd2 100644 --- a/app/controllers/custom_css_controller.rb +++ b/app/controllers/custom_css_controller.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class CustomCssController < ActionController::Base # rubocop:disable Rails/ApplicationController - before_action :set_user_roles - def show expires_in 3.minutes, public: true render content_type: 'text/css' @@ -14,8 +12,4 @@ class CustomCssController < ActionController::Base # rubocop:disable Rails/Appli Setting.custom_css end helper_method :custom_css_styles - - def set_user_roles - @user_roles = UserRole.providing_styles - end end diff --git a/app/models/user_role.rb b/app/models/user_role.rb index f9c4c14c4b..24cd5983f3 100644 --- a/app/models/user_role.rb +++ b/app/models/user_role.rb @@ -101,9 +101,6 @@ class UserRole < ApplicationRecord before_validation :set_position scope :assignable, -> { where.not(id: EVERYONE_ROLE_ID).order(position: :asc) } - scope :highlighted, -> { where(highlighted: true) } - scope :with_color, -> { where.not(color: [nil, '']) } - scope :providing_styles, -> { highlighted.with_color } has_many :users, inverse_of: :role, foreign_key: 'role_id', dependent: :nullify diff --git a/app/views/admin/roles/_role.html.haml b/app/views/admin/roles/_role.html.haml index 636127354b..085bdbd156 100644 --- a/app/views/admin/roles/_role.html.haml +++ b/app/views/admin/roles/_role.html.haml @@ -1,7 +1,7 @@ .announcements-list__item - if can?(:update, role) = link_to edit_admin_role_path(role), class: 'announcements-list__item__title' do - %span.user-role{ class: "user-role-#{role.id}" } + %span.user-role = material_symbol 'group' - if role.everyone? @@ -10,7 +10,7 @@ = role.name - else %span.announcements-list__item__title - %span.user-role{ class: "user-role-#{role.id}" } + %span.user-role = material_symbol 'group' - if role.everyone? diff --git a/app/views/custom_css/show.css.erb b/app/views/custom_css/show.css.erb index 78da809ed6..d4b24b2106 100644 --- a/app/views/custom_css/show.css.erb +++ b/app/views/custom_css/show.css.erb @@ -2,9 +2,3 @@ <%= raw custom_css_styles %> <%- end %> -<%- @user_roles.each do |role| %> -.user-role-<%= role.id %> { - --user-role-accent: <%= role.color %>; -} - -<%- end %> diff --git a/spec/requests/custom_css_spec.rb b/spec/requests/custom_css_spec.rb index d97da00187..380c32908a 100644 --- a/spec/requests/custom_css_spec.rb +++ b/spec/requests/custom_css_spec.rb @@ -45,34 +45,5 @@ RSpec.describe 'Custom CSS' do CSS end end - - context 'with highlighted colored UserRole records' do - before do - _highlighted_colored = Fabricate :user_role, highlighted: true, color: '#336699', id: '123_123_123' - _highlighted_no_color = Fabricate :user_role, highlighted: true, color: '' - _no_highlight_with_color = Fabricate :user_role, highlighted: false, color: '' - end - - it 'returns stylesheet from settings' do - get '/custom.css' - - expect(response) - .to have_http_status(200) - .and have_cacheable_headers - .and have_attributes( - content_type: match('text/css') - ) - expect(response.body.strip) - .to eq(expected_css) - end - - def expected_css - <<~CSS.strip - .user-role-123123123 { - --user-role-accent: #336699; - } - CSS - end - end end end From b3243ef41c5d992afa87b60147b459c725931b55 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 7 Jan 2025 11:28:54 -0500 Subject: [PATCH 18/64] Refer to constant values from `api/v1/apps` request spec (#33488) --- app/lib/application_extension.rb | 10 +++++++--- spec/models/doorkeeper/application_spec.rb | 15 +++++++++++++++ spec/requests/api/v1/apps_spec.rb | 6 +++--- 3 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 spec/models/doorkeeper/application_spec.rb diff --git a/app/lib/application_extension.rb b/app/lib/application_extension.rb index d7aaeba5bd..d8090d15bc 100644 --- a/app/lib/application_extension.rb +++ b/app/lib/application_extension.rb @@ -3,14 +3,18 @@ module ApplicationExtension extend ActiveSupport::Concern + APP_NAME_LIMIT = 60 + APP_REDIRECT_URI_LIMIT = 2_000 + APP_WEBSITE_LIMIT = 2_000 + included do include Redisable has_many :created_users, class_name: 'User', foreign_key: 'created_by_application_id', inverse_of: :created_by_application - validates :name, length: { maximum: 60 } - validates :website, url: true, length: { maximum: 2_000 }, if: :website? - validates :redirect_uri, length: { maximum: 2_000 } + validates :name, length: { maximum: APP_NAME_LIMIT } + validates :redirect_uri, length: { maximum: APP_REDIRECT_URI_LIMIT } + validates :website, url: true, length: { maximum: APP_WEBSITE_LIMIT }, if: :website? # The relationship used between Applications and AccessTokens is using # dependent: delete_all, which means the ActiveRecord callback in diff --git a/spec/models/doorkeeper/application_spec.rb b/spec/models/doorkeeper/application_spec.rb new file mode 100644 index 0000000000..e026d90caa --- /dev/null +++ b/spec/models/doorkeeper/application_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Doorkeeper::Application do + describe 'Associations' do + it { is_expected.to have_many(:created_users).class_name('User').inverse_of(:created_by_application).with_foreign_key(:created_by_application_id) } + end + + describe 'Validations' do + it { is_expected.to validate_length_of(:name).is_at_most(described_class::APP_NAME_LIMIT) } + it { is_expected.to validate_length_of(:redirect_uri).is_at_most(described_class::APP_REDIRECT_URI_LIMIT) } + it { is_expected.to validate_length_of(:website).is_at_most(described_class::APP_WEBSITE_LIMIT) } + end +end diff --git a/spec/requests/api/v1/apps_spec.rb b/spec/requests/api/v1/apps_spec.rb index 4e9147ba32..3120ab9c64 100644 --- a/spec/requests/api/v1/apps_spec.rb +++ b/spec/requests/api/v1/apps_spec.rb @@ -122,7 +122,7 @@ RSpec.describe 'Apps' do end context 'with a too-long name' do - let(:client_name) { 'hoge' * 20 } + let(:client_name) { 'a' * Doorkeeper::Application::APP_NAME_LIMIT * 2 } it 'returns http unprocessable entity' do subject @@ -134,7 +134,7 @@ RSpec.describe 'Apps' do end context 'with a too-long website' do - let(:website) { "https://foo.bar/#{'hoge' * 2_000}" } + let(:website) { "https://foo.bar/#{'a' * Doorkeeper::Application::APP_WEBSITE_LIMIT * 2}" } it 'returns http unprocessable entity' do subject @@ -146,7 +146,7 @@ RSpec.describe 'Apps' do end context 'with a too-long redirect_uri' do - let(:redirect_uris) { "https://app.example/#{'hoge' * 2_000}" } + let(:redirect_uris) { "https://app.example/#{'a' * Doorkeeper::Application::APP_REDIRECT_URI_LIMIT * 2}" } it 'returns http unprocessable entity' do subject From c0264c8013615cb725f9fd2d69bea60ea4a13324 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 8 Jan 2025 03:48:45 -0500 Subject: [PATCH 19/64] Extend custom CSS cache time with digest paths (#33207) --- app/controllers/custom_css_controller.rb | 2 +- app/helpers/theme_helper.rb | 23 +++++++++++++++ app/models/form/admin_settings.rb | 18 ++++++++++++ app/views/layouts/application.html.haml | 2 +- config/initializers/settings_digests.rb | 18 ++++++++++++ config/routes.rb | 3 +- spec/helpers/theme_helper_spec.rb | 20 +++++++++++++ spec/models/form/admin_settings_spec.rb | 36 ++++++++++++++++++++++++ spec/requests/cache_spec.rb | 1 + spec/requests/custom_css_spec.rb | 6 ++-- spec/routing/custom_css_routing_spec.rb | 19 +++++++++++++ 11 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 config/initializers/settings_digests.rb create mode 100644 spec/routing/custom_css_routing_spec.rb diff --git a/app/controllers/custom_css_controller.rb b/app/controllers/custom_css_controller.rb index 9f33870bd2..5b98914114 100644 --- a/app/controllers/custom_css_controller.rb +++ b/app/controllers/custom_css_controller.rb @@ -2,7 +2,7 @@ class CustomCssController < ActionController::Base # rubocop:disable Rails/ApplicationController def show - expires_in 3.minutes, public: true + expires_in 1.month, public: true render content_type: 'text/css' end diff --git a/app/helpers/theme_helper.rb b/app/helpers/theme_helper.rb index fab899a533..5dfb4a5184 100644 --- a/app/helpers/theme_helper.rb +++ b/app/helpers/theme_helper.rb @@ -23,8 +23,31 @@ module ThemeHelper end end + def custom_stylesheet + if active_custom_stylesheet.present? + stylesheet_link_tag( + custom_css_path(active_custom_stylesheet), + host: root_url, + media: :all, + skip_pipeline: true + ) + end + end + private + def active_custom_stylesheet + if cached_custom_css_digest.present? + [:custom, cached_custom_css_digest.to_s.first(8)] + .compact_blank + .join('-') + end + end + + def cached_custom_css_digest + Rails.cache.read(:setting_digest_custom_css) + end + def theme_color_for(theme) theme == 'mastodon-light' ? Themes::THEME_COLORS[:light] : Themes::THEME_COLORS[:dark] end diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index 515909d5cf..ffd2d4049c 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -69,6 +69,10 @@ class Form::AdminSettings favicon ).freeze + DIGEST_KEYS = %i( + custom_css + ).freeze + OVERRIDEN_SETTINGS = { authorized_fetch: :authorized_fetch_mode?, }.freeze @@ -122,6 +126,8 @@ class Form::AdminSettings KEYS.each do |key| next unless instance_variable_defined?(:"@#{key}") + cache_digest_value(key) if DIGEST_KEYS.include?(key) + if UPLOAD_KEYS.include?(key) public_send(key).save else @@ -133,6 +139,18 @@ class Form::AdminSettings private + def cache_digest_value(key) + Rails.cache.delete(:"setting_digest_#{key}") + + key_value = instance_variable_get(:"@#{key}") + if key_value.present? + Rails.cache.write( + :"setting_digest_#{key}", + Digest::SHA256.hexdigest(key_value) + ) + end + end + def typecast_value(key, value) if BOOLEAN_KEYS.include?(key) value == '1' diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 99e89d45ce..6f016c6cf5 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -34,7 +34,7 @@ = csrf_meta_tags unless skip_csrf_meta_tags? %meta{ name: 'style-nonce', content: request.content_security_policy_nonce } - = stylesheet_link_tag custom_css_path, skip_pipeline: true, host: root_url, media: 'all' + = custom_stylesheet = yield :header_tags diff --git a/config/initializers/settings_digests.rb b/config/initializers/settings_digests.rb new file mode 100644 index 0000000000..2a5d925c70 --- /dev/null +++ b/config/initializers/settings_digests.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +Rails.application.config.to_prepare do + custom_css = begin + Setting.custom_css + rescue ActiveRecord::AdapterError # Running without a database, not migrated, no connection, etc + nil + end + + if custom_css.present? + Rails + .cache + .write( + :setting_digest_custom_css, + Digest::SHA256.hexdigest(custom_css) + ) + end +end diff --git a/config/routes.rb b/config/routes.rb index 3909dd1b77..5adec04c7d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -55,7 +55,8 @@ Rails.application.routes.draw do get 'manifest', to: 'manifests#show', defaults: { format: 'json' } get 'intent', to: 'intents#show' - get 'custom.css', to: 'custom_css#show', as: :custom_css + get 'custom.css', to: 'custom_css#show' + resources :custom_css, only: :show, path: :css get 'remote_interaction_helper', to: 'remote_interaction_helper#index' diff --git a/spec/helpers/theme_helper_spec.rb b/spec/helpers/theme_helper_spec.rb index 7663e59436..c811b7c981 100644 --- a/spec/helpers/theme_helper_spec.rb +++ b/spec/helpers/theme_helper_spec.rb @@ -79,6 +79,26 @@ RSpec.describe ThemeHelper do end end + describe '#custom_stylesheet' do + context 'when custom css setting value digest is present' do + before { Rails.cache.write(:setting_digest_custom_css, '1a2s3d4f1a2s3d4f') } + + it 'returns value from settings' do + expect(custom_stylesheet) + .to match('/css/custom-1a2s3d4f.css') + end + end + + context 'when custom css setting value digest is not present' do + before { Rails.cache.delete(:setting_digest_custom_css) } + + it 'returns default value' do + expect(custom_stylesheet) + .to be_blank + end + end + end + private def html_links diff --git a/spec/models/form/admin_settings_spec.rb b/spec/models/form/admin_settings_spec.rb index 73106f2b69..899d56703a 100644 --- a/spec/models/form/admin_settings_spec.rb +++ b/spec/models/form/admin_settings_spec.rb @@ -17,4 +17,40 @@ RSpec.describe Form::AdminSettings do end end end + + describe '#save' do + describe 'updating digest values' do + context 'when updating custom css to real value' do + subject { described_class.new(custom_css: css) } + + let(:css) { 'body { color: red; }' } + let(:digested) { Digest::SHA256.hexdigest(css) } + + it 'changes relevant digest value' do + expect { subject.save } + .to(change { Rails.cache.read(:setting_digest_custom_css) }.to(digested)) + end + end + + context 'when updating custom css to empty value' do + subject { described_class.new(custom_css: '') } + + before { Rails.cache.write(:setting_digest_custom_css, 'previous-value') } + + it 'changes relevant digest value' do + expect { subject.save } + .to(change { Rails.cache.read(:setting_digest_custom_css) }.to(be_blank)) + end + end + + context 'when updating other fields' do + subject { described_class.new(site_contact_email: 'test@example.host') } + + it 'does not update digests' do + expect { subject.save } + .to(not_change { Rails.cache.read(:setting_digest_custom_css) }) + end + end + end + end end diff --git a/spec/requests/cache_spec.rb b/spec/requests/cache_spec.rb index 2a52e4dea9..8ca2817263 100644 --- a/spec/requests/cache_spec.rb +++ b/spec/requests/cache_spec.rb @@ -10,6 +10,7 @@ module TestEndpoints /.well-known/nodeinfo /nodeinfo/2.0 /manifest + /css/custom-1a2s3d4f.css /custom.css /actor /api/v1/instance/extended_description diff --git a/spec/requests/custom_css_spec.rb b/spec/requests/custom_css_spec.rb index 380c32908a..66ff5c4b13 100644 --- a/spec/requests/custom_css_spec.rb +++ b/spec/requests/custom_css_spec.rb @@ -5,10 +5,10 @@ require 'rails_helper' RSpec.describe 'Custom CSS' do include RoutingHelper - describe 'GET /custom.css' do + describe 'GET /css/:id.css' do context 'without any CSS or User Roles' do it 'returns empty stylesheet' do - get '/custom.css' + get '/css/custom-123.css' expect(response) .to have_http_status(200) @@ -27,7 +27,7 @@ RSpec.describe 'Custom CSS' do end it 'returns stylesheet from settings' do - get '/custom.css' + get '/css/custom-456.css' expect(response) .to have_http_status(200) diff --git a/spec/routing/custom_css_routing_spec.rb b/spec/routing/custom_css_routing_spec.rb new file mode 100644 index 0000000000..26139b4744 --- /dev/null +++ b/spec/routing/custom_css_routing_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Custom CSS routes' do + describe 'the legacy route' do + it 'routes to correct place' do + expect(get('/custom.css')) + .to route_to('custom_css#show') + end + end + + describe 'the custom digest route' do + it 'routes to correct place' do + expect(get('/css/custom-1a2s3d4f.css')) + .to route_to('custom_css#show', id: 'custom-1a2s3d4f', format: 'css') + end + end +end From c3fc12c2b4920227b79c1cd394c6a20485f3b2e9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 09:48:51 +0100 Subject: [PATCH 20/64] Update dependency rubyzip to v2.4.1 (#33494) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index e2525b13e2..dfea405a3a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -744,7 +744,7 @@ GEM ruby-vips (2.2.2) ffi (~> 1.12) logger - rubyzip (2.3.2) + rubyzip (2.4.1) rufus-scheduler (3.9.2) fugit (~> 1.1, >= 1.11.1) safety_net_attestation (0.4.0) From b6c2923cf729c579c0963f23a0db7043a17eaece Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 8 Jan 2025 03:53:26 -0500 Subject: [PATCH 21/64] Convert `settings/migration` spec controller->system (#33496) --- .../settings/migrations_controller_spec.rb | 104 ------------------ spec/requests/settings/migrations_spec.rb | 21 ++++ spec/system/settings/migrations_spec.rb | 99 +++++++++++++++++ 3 files changed, 120 insertions(+), 104 deletions(-) delete mode 100644 spec/controllers/settings/migrations_controller_spec.rb create mode 100644 spec/requests/settings/migrations_spec.rb create mode 100644 spec/system/settings/migrations_spec.rb diff --git a/spec/controllers/settings/migrations_controller_spec.rb b/spec/controllers/settings/migrations_controller_spec.rb deleted file mode 100644 index dca4c925fd..0000000000 --- a/spec/controllers/settings/migrations_controller_spec.rb +++ /dev/null @@ -1,104 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Settings::MigrationsController do - render_views - - describe 'GET #show' do - context 'when user is not sign in' do - subject { get :show } - - it { is_expected.to redirect_to new_user_session_path } - end - - context 'when user is sign in' do - subject { get :show } - - let(:user) { Fabricate(:account, moved_to_account: moved_to_account).user } - - before { sign_in user, scope: :user } - - context 'when user does not have moved to account' do - let(:moved_to_account) { nil } - - it 'renders show page' do - expect(subject).to have_http_status 200 - expect(subject).to render_template :show - end - end - - context 'when user has a moved to account' do - let(:moved_to_account) { Fabricate(:account) } - - it 'renders show page' do - expect(subject).to have_http_status 200 - expect(subject).to render_template :show - end - end - end - end - - describe 'POST #create' do - context 'when user is not sign in' do - subject { post :create } - - it { is_expected.to redirect_to new_user_session_path } - end - - context 'when user is signed in' do - subject { post :create, params: { account_migration: { acct: acct, current_password: '12345678' } } } - - let(:user) { Fabricate(:user, password: '12345678') } - - before { sign_in user, scope: :user } - - context 'when migration account is changed' do - let(:acct) { Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)]) } - - it 'updates moved to account' do - expect(subject).to redirect_to settings_migration_path - expect(user.account.reload.moved_to_account_id).to eq acct.id - end - end - - context 'when acct is the current account' do - let(:acct) { user.account } - - it 'does not update the moved account', :aggregate_failures do - subject - - expect(user.account.reload.moved_to_account_id).to be_nil - expect(response).to render_template :show - end - end - - context 'when target account does not reference the account being moved from' do - let(:acct) { Fabricate(:account, also_known_as: []) } - - it 'does not update the moved account', :aggregate_failures do - subject - - expect(user.account.reload.moved_to_account_id).to be_nil - expect(response).to render_template :show - end - end - - context 'when a recent migration already exists' do - let(:acct) { Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)]) } - - before do - moved_to = Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)]) - user.account.migrations.create!(acct: moved_to.acct) - end - - it 'does not update the moved account', :aggregate_failures do - subject - - expect(user.account.reload.moved_to_account_id).to be_nil - expect(response).to render_template :show - end - end - end - end -end diff --git a/spec/requests/settings/migrations_spec.rb b/spec/requests/settings/migrations_spec.rb new file mode 100644 index 0000000000..4103d6b320 --- /dev/null +++ b/spec/requests/settings/migrations_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Settings Migrations' do + describe 'GET #show' do + context 'when user is not signed in' do + subject { get '/settings/migration' } + + it { is_expected.to redirect_to new_user_session_path } + end + end + + describe 'POST #create' do + context 'when user is not signed in' do + subject { post '/settings/migration' } + + it { is_expected.to redirect_to new_user_session_path } + end + end +end diff --git a/spec/system/settings/migrations_spec.rb b/spec/system/settings/migrations_spec.rb new file mode 100644 index 0000000000..fecde36f35 --- /dev/null +++ b/spec/system/settings/migrations_spec.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Settings Migrations' do + describe 'Viewing settings migrations' do + let(:user) { Fabricate(:account, moved_to_account: moved_to_account).user } + + before { sign_in(user) } + + context 'when user does not have moved to account' do + let(:moved_to_account) { nil } + + it 'renders show page' do + visit settings_migration_path + + expect(page) + .to have_content(I18n.t('settings.migrate')) + end + end + + context 'when user has a moved to account' do + let(:moved_to_account) { Fabricate(:account) } + + it 'renders show page and account details' do + visit settings_migration_path + + expect(page) + .to have_content(I18n.t('settings.migrate')) + .and have_content(moved_to_account.pretty_acct) + end + end + end + + describe 'Creating migrations' do + let(:user) { Fabricate(:user, password: '12345678') } + + before { sign_in(user) } + + context 'when migration account is changed' do + let(:acct) { Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)]) } + + it 'updates moved to account' do + visit settings_migration_path + + expect { fill_in_and_submit } + .to(change { user.account.reload.moved_to_account_id }.to(acct.id)) + expect(page) + .to have_content(I18n.t('settings.migrate')) + end + end + + context 'when acct is the current account' do + let(:acct) { user.account } + + it 'does not update the moved account', :aggregate_failures do + visit settings_migration_path + + expect { fill_in_and_submit } + .to_not(change { user.account.reload.moved_to_account_id }.from(nil)) + expect(page) + .to have_content(I18n.t('settings.migrate')) + end + end + + context 'when target account does not reference the account being moved from' do + let(:acct) { Fabricate(:account, also_known_as: []) } + + it 'does not update the moved account', :aggregate_failures do + visit settings_migration_path + + expect { fill_in_and_submit } + .to_not(change { user.account.reload.moved_to_account_id }.from(nil)) + expect(page) + .to have_content(I18n.t('settings.migrate')) + end + end + + context 'when a recent migration already exists' do + let(:acct) { Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)]) } + let(:moved_to) { Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)]) } + + before { user.account.migrations.create!(acct: moved_to.acct) } + + it 'can not update the moved account', :aggregate_failures do + visit settings_migration_path + + expect(find_by_id('account_migration_acct')) + .to be_disabled + end + end + + def fill_in_and_submit + fill_in 'account_migration_acct', with: acct.username + fill_in 'account_migration_current_password', with: '12345678' + click_on I18n.t('migrations.proceed_with_move') + end + end +end From 0c690511c220d2ee9de9fc41e0d1f94b3cdb0b88 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 8 Jan 2025 03:54:08 -0500 Subject: [PATCH 22/64] Convert `auth/challenges` spec controller->request (#33495) --- .../auth/challenges_spec.rb} | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) rename spec/{controllers/auth/challenges_controller_spec.rb => requests/auth/challenges_spec.rb} (64%) diff --git a/spec/controllers/auth/challenges_controller_spec.rb b/spec/requests/auth/challenges_spec.rb similarity index 64% rename from spec/controllers/auth/challenges_controller_spec.rb rename to spec/requests/auth/challenges_spec.rb index 3c9d2a5964..628bfe499b 100644 --- a/spec/controllers/auth/challenges_controller_spec.rb +++ b/spec/requests/auth/challenges_spec.rb @@ -2,9 +2,7 @@ require 'rails_helper' -RSpec.describe Auth::ChallengesController do - render_views - +RSpec.describe 'Auth Challenges' do let(:password) { 'foobar12345' } let(:user) { Fabricate(:user, password: password) } @@ -14,9 +12,9 @@ RSpec.describe Auth::ChallengesController do let(:return_to) { edit_user_registration_path } context 'with correct password' do - before { post :create, params: { form_challenge: { return_to: return_to, current_password: password } } } - it 'redirects back and sets challenge passed at in session' do + post '/auth/challenge', params: { form_challenge: { return_to: return_to, current_password: password } } + expect(response) .to redirect_to(return_to) expect(session[:challenge_passed_at]) @@ -25,13 +23,12 @@ RSpec.describe Auth::ChallengesController do end context 'with incorrect password' do - before { post :create, params: { form_challenge: { return_to: return_to, current_password: 'hhfggjjd562' } } } - it 'renders challenge, displays error, does not set session' do - expect(response) - .to render_template('auth/challenges/new') + post '/auth/challenge', params: { form_challenge: { return_to: return_to, current_password: 'hhfggjjd562' } } + expect(response.body) - .to include 'Invalid password' + .to include(I18n.t('challenge.prompt')) + .and include('Invalid password') expect(session[:challenge_passed_at]) .to be_nil end From 35e57138f1d330e5440c0f7a47f7e760e3b9367c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 09:01:28 +0000 Subject: [PATCH 23/64] New Crowdin Translations (automated) (#33500) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/cy.json | 2 ++ app/javascript/mastodon/locales/pt-PT.json | 2 ++ app/javascript/mastodon/locales/sv.json | 11 +++++++++-- config/locales/activerecord.cy.yml | 2 ++ config/locales/activerecord.gl.yml | 2 ++ config/locales/activerecord.pt-PT.yml | 2 ++ config/locales/activerecord.tr.yml | 2 +- config/locales/doorkeeper.sk.yml | 1 + config/locales/simple_form.fr.yml | 2 +- config/locales/simple_form.sv.yml | 12 ++++++++++++ 10 files changed, 34 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index ffe15f538f..d7585b4ac2 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -457,6 +457,7 @@ "keyboard_shortcuts.toggle_hidden": "Dangos/cuddio testun tu ôl i CW", "keyboard_shortcuts.toggle_sensitivity": "Dangos/cuddio cyfryngau", "keyboard_shortcuts.toot": "Dechrau post newydd", + "keyboard_shortcuts.translate": "i gyfieithu postiad", "keyboard_shortcuts.unfocus": "Dad-ffocysu ardal cyfansoddi testun/chwilio", "keyboard_shortcuts.up": "Symud yn uwch yn y rhestr", "lightbox.close": "Cau", @@ -835,6 +836,7 @@ "status.reblogs.empty": "Does neb wedi hybio'r post yma eto. Pan y bydd rhywun yn gwneud, byddent yn ymddangos yma.", "status.redraft": "Dileu ac ailddrafftio", "status.remove_bookmark": "Tynnu nod tudalen", + "status.remove_favourite": "Tynnu o'r ffefrynnau", "status.replied_in_thread": "Atebodd mewn edefyn", "status.replied_to": "Wedi ateb {name}", "status.reply": "Ateb", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index ade10fc478..fa4f715b6d 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -457,6 +457,7 @@ "keyboard_shortcuts.toggle_hidden": "mostrar / esconder texto atrás do aviso de conteúdo", "keyboard_shortcuts.toggle_sensitivity": "mostrar / ocultar multimédia", "keyboard_shortcuts.toot": "criar uma nova publicação", + "keyboard_shortcuts.translate": "traduzir uma publicação", "keyboard_shortcuts.unfocus": "remover o foco da área de texto / pesquisa", "keyboard_shortcuts.up": "mover para cima na lista", "lightbox.close": "Fechar", @@ -836,6 +837,7 @@ "status.reblogs.empty": "Ainda ninguém impulsionou esta publicação. Quando alguém o fizer, aparecerá aqui.", "status.redraft": "Eliminar e reescrever", "status.remove_bookmark": "Retirar dos marcadores", + "status.remove_favourite": "Remover dos favoritos", "status.replied_in_thread": "Responder na conversa", "status.replied_to": "Respondeu a {name}", "status.reply": "Responder", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index a9b299c97f..486c3ac19d 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -240,7 +240,7 @@ "dismissable_banner.community_timeline": "Dessa är de senaste offentliga inläggen från personer vars konton tillhandahålls av {domain}.", "dismissable_banner.dismiss": "Avfärda", "dismissable_banner.explore_links": "Dessa nyhetshistorier delas mest på fediversum idag. Nyare nyhetshistorier som publiceras av fler olika personer rankas högre.", - "dismissable_banner.explore_statuses": "Dessa inlägg från fediverse vinner dragkraft idag. Nyare inlägg som många boostar och favoritmarkerar rankas högre.", + "dismissable_banner.explore_statuses": "Dessa inlägg från fediversum vinner dragkraft idag. Nyare inlägg som många boostar och favoritmarkerar rankas högre.", "dismissable_banner.explore_tags": "De här hashtaggarna vinner dragkraft i fediversum idag. Hashtaggar som används av fler olika personer rankas högre.", "dismissable_banner.public_timeline": "De här är de aktuella publika inlägg från personer i fediversum som personer i {domain} följer.", "domain_block_modal.block": "Blockera server", @@ -658,6 +658,7 @@ "onboarding.follows.done": "Färdig", "onboarding.follows.empty": "Tyvärr kan inga resultat visas just nu. Du kan prova att använda sökfunktionen eller utforska sidan för att hitta personer att följa, eller försök igen senare.", "onboarding.follows.search": "Sök", + "onboarding.follows.title": "Följ människor för att komma igång", "onboarding.profile.discoverable": "Gör min profil upptäckbar", "onboarding.profile.discoverable_hint": "När du väljer att vara upptäckbar på Mastodon kan dina inlägg visas i sök- och trendresultat, och din profil kan föreslås för personer med liknande intressen som du.", "onboarding.profile.display_name": "Visningsnamn", @@ -695,6 +696,7 @@ "privacy_policy.title": "Integritetspolicy", "recommended": "Rekommenderas", "refresh": "Läs om", + "regeneration_indicator.please_stand_by": "Vänligen vänta.", "relative_time.days": "{number}d", "relative_time.full.days": "{number, plural, one {# dag} other {# dagar}} sedan", "relative_time.full.hours": "{number, plural, one {# timme} other {# timmar}} sedan", @@ -778,15 +780,18 @@ "search_results.accounts": "Profiler", "search_results.all": "Alla", "search_results.hashtags": "Hashtaggar", + "search_results.no_results": "Inga resultat.", + "search_results.no_search_yet": "Prova att söka efter inlägg, profiler eller hashtags.", "search_results.see_all": "Visa alla", "search_results.statuses": "Inlägg", + "search_results.title": "Sök efter \"{q}\"", "server_banner.about_active_users": "Personer som använt denna server de senaste 30 dagarna (månatligt aktiva användare)", "server_banner.active_users": "aktiva användare", "server_banner.administered_by": "Administrerad av:", "server_banner.is_one_of_many": "{domain} är en av de många oberoende Mastodon-servrar som du kan använda för att delta i Fediversen.", "server_banner.server_stats": "Serverstatistik:", "sign_in_banner.create_account": "Skapa konto", - "sign_in_banner.follow_anyone": "Följ vem som helst över Fediverse och se allt i kronologisk ordning. Inga algoritmer, inga annonser och inga klickbeten i sikte.", + "sign_in_banner.follow_anyone": "Följ vem som helst över Fediversum och se allt i kronologisk ordning. Inga algoritmer, annonser eller klickbeten i sikte.", "sign_in_banner.mastodon_is": "Mastodon är det bästa sättet att hänga med i vad som händer.", "sign_in_banner.sign_in": "Logga in", "sign_in_banner.sso_redirect": "Logga in eller registrera dig", @@ -831,6 +836,7 @@ "status.reblogs.empty": "Ingen har boostat detta inlägg än. När någon gör det kommer de synas här.", "status.redraft": "Radera & gör om", "status.remove_bookmark": "Ta bort bokmärke", + "status.remove_favourite": "Ta bort från Favoriter", "status.replied_in_thread": "Svarade i tråden", "status.replied_to": "Svarade på {name}", "status.reply": "Svara", @@ -852,6 +858,7 @@ "subscribed_languages.target": "Ändra språkprenumerationer för {target}", "tabs_bar.home": "Hem", "tabs_bar.notifications": "Aviseringar", + "terms_of_service.title": "Användarvillkor", "time_remaining.days": "{number, plural, one {# dag} other {# dagar}} kvar", "time_remaining.hours": "{number, plural, one {# timme} other {# timmar}} kvar", "time_remaining.minutes": "{number, plural, one {# minut} other {# minuter}} kvar", diff --git a/config/locales/activerecord.cy.yml b/config/locales/activerecord.cy.yml index 3620c1c2f6..9bc9b3b2bc 100644 --- a/config/locales/activerecord.cy.yml +++ b/config/locales/activerecord.cy.yml @@ -24,6 +24,8 @@ cy: models: account: attributes: + fields: + fields_with_values_missing_labels: yn cynnwys gwerthoedd gyda labeli coll username: invalid: rhaid iddo gynnwys dim ond llythrennau, rhifau a thanlinellau reserved: wedi ei neilltuo diff --git a/config/locales/activerecord.gl.yml b/config/locales/activerecord.gl.yml index 0c4941f048..8fdff40282 100644 --- a/config/locales/activerecord.gl.yml +++ b/config/locales/activerecord.gl.yml @@ -24,6 +24,8 @@ gl: models: account: attributes: + fields: + fields_with_values_missing_labels: contén valores aos que lle faltan etiquetas username: invalid: só letras, números e trazo baixo reserved: está reservado diff --git a/config/locales/activerecord.pt-PT.yml b/config/locales/activerecord.pt-PT.yml index 86581331db..8b17ade2eb 100644 --- a/config/locales/activerecord.pt-PT.yml +++ b/config/locales/activerecord.pt-PT.yml @@ -24,6 +24,8 @@ pt-PT: models: account: attributes: + fields: + fields_with_values_missing_labels: contém valores com etiquetas em falta username: invalid: deve conter apenas letras, números e traços inferiores reserved: está reservado diff --git a/config/locales/activerecord.tr.yml b/config/locales/activerecord.tr.yml index 095aa72e67..4795e629fb 100644 --- a/config/locales/activerecord.tr.yml +++ b/config/locales/activerecord.tr.yml @@ -25,7 +25,7 @@ tr: account: attributes: fields: - fields_with_values_missing_labels: değerleri eksik etiketler içeriyor + fields_with_values_missing_labels: etiketleri eksik değerler içeriyor username: invalid: sadece harfler, sayılar ve alt çizgiler reserved: kullanılamaz diff --git a/config/locales/doorkeeper.sk.yml b/config/locales/doorkeeper.sk.yml index 774a2648f9..ba9a440a11 100644 --- a/config/locales/doorkeeper.sk.yml +++ b/config/locales/doorkeeper.sk.yml @@ -134,6 +134,7 @@ sk: media: Mediálne prílohy mutes: Stíšenia notifications: Upozornenia + profile: Váš Mastodon profil push: Upozornenia push reports: Hlásenia search: Vyhľadávanie diff --git a/config/locales/simple_form.fr.yml b/config/locales/simple_form.fr.yml index 1b0469f7a3..62dd23f930 100644 --- a/config/locales/simple_form.fr.yml +++ b/config/locales/simple_form.fr.yml @@ -174,7 +174,7 @@ fr: admin_account_action: include_statuses: Inclure les messages signalés dans le courriel send_email_notification: Notifier l’utilisateur par courriel - text: Attention personnalisée + text: Avertissement personnalisé type: Action types: disable: Désactiver diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml index 0815170fcc..5fd258d7e0 100644 --- a/config/locales/simple_form.sv.yml +++ b/config/locales/simple_form.sv.yml @@ -130,6 +130,12 @@ sv: show_application: Du kommer alltid att kunna se vilken app som publicerat ditt inlägg oavsett. tag: name: Du kan bara ändra skriftläget av bokstäverna, till exempel, för att göra det mer läsbart + terms_of_service: + changelog: Kan struktureras med Markdown syntax. + text: Kan struktureras med Markdown syntax. + terms_of_service_generator: + arbitration_website: Kan vara ett webbformulär, eller ”N/A” om du använder e-post + jurisdiction: Lista det land där vem som än betalar räkningarna bor. Om det är ett företag eller annan enhet, lista landet där det är inkorporerat, och staden, regionen, territoriet eller staten på lämpligt sätt. user: chosen_languages: Vid aktivering visas bara inlägg på dina valda språk i offentliga tidslinjer role: Rollen styr vilka behörigheter användaren har. @@ -224,6 +230,7 @@ sv: setting_hide_network: Göm ditt nätverk setting_reduce_motion: Minska rörelser i animationer setting_system_font_ui: Använd systemets standardfont + setting_system_scrollbars_ui: Använd systemets standardrullningsfält setting_theme: Sidans tema setting_trends: Visa dagens trender setting_unfollow_modal: Visa bekräftelse innan du slutar följa någon @@ -318,6 +325,11 @@ sv: name: Hashtagg trendable: Tillåt denna hashtagg att visas under trender usable: Tillåt inlägg att använda denna fyrkantstagg + terms_of_service: + changelog: Vad har ändrats? + text: Användarvillkor + terms_of_service_generator: + admin_email: E-postadress för juridiska meddelanden user: role: Roll time_zone: Tidszon From ee1cbda2262cec267c5c774c559d5ea7388cc541 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 09:06:37 +0000 Subject: [PATCH 24/64] Update opentelemetry-ruby (non-major) (#33501) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index d2e6769ace..8df00d8c0a 100644 --- a/Gemfile +++ b/Gemfile @@ -108,7 +108,7 @@ group :opentelemetry do gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.21.0', require: false gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.21.2', require: false gem 'opentelemetry-instrumentation-excon', '~> 0.22.0', require: false - gem 'opentelemetry-instrumentation-faraday', '~> 0.24.1', require: false + gem 'opentelemetry-instrumentation-faraday', '~> 0.25.0', require: false gem 'opentelemetry-instrumentation-http', '~> 0.23.2', require: false gem 'opentelemetry-instrumentation-http_client', '~> 0.22.3', require: false gem 'opentelemetry-instrumentation-net_http', '~> 0.22.4', require: false diff --git a/Gemfile.lock b/Gemfile.lock index dfea405a3a..8330d7bb7d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -510,7 +510,7 @@ GEM opentelemetry-instrumentation-excon (0.22.5) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-faraday (0.24.8) + opentelemetry-instrumentation-faraday (0.25.0) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) opentelemetry-instrumentation-http (0.23.5) @@ -963,7 +963,7 @@ DEPENDENCIES opentelemetry-instrumentation-active_model_serializers (~> 0.21.0) opentelemetry-instrumentation-concurrent_ruby (~> 0.21.2) opentelemetry-instrumentation-excon (~> 0.22.0) - opentelemetry-instrumentation-faraday (~> 0.24.1) + opentelemetry-instrumentation-faraday (~> 0.25.0) opentelemetry-instrumentation-http (~> 0.23.2) opentelemetry-instrumentation-http_client (~> 0.22.3) opentelemetry-instrumentation-net_http (~> 0.22.4) From 242221c11f8da661737b61c16efa7fdd01853f63 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:21:58 +0100 Subject: [PATCH 25/64] Update dependency connection_pool to v2.5.0 (#33503) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8330d7bb7d..f3a4e11f5d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -160,7 +160,7 @@ GEM cocoon (1.2.15) color_diff (0.1) concurrent-ruby (1.3.4) - connection_pool (2.4.1) + connection_pool (2.5.0) cose (1.3.1) cbor (~> 0.5.9) openssl-signature_algorithm (~> 1.0) From 5a142060e117a3f4124fd99a72dc3b5d69d199d3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:47:39 +0100 Subject: [PATCH 26/64] Update opentelemetry-ruby (non-major) (#33506) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f3a4e11f5d..36373bd337 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -490,7 +490,7 @@ GEM opentelemetry-instrumentation-active_job (0.7.8) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-active_model_serializers (0.21.0) + opentelemetry-instrumentation-active_model_serializers (0.21.1) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-active_support (>= 0.7.0) opentelemetry-instrumentation-base (~> 0.22.1) @@ -522,7 +522,7 @@ GEM opentelemetry-instrumentation-net_http (0.22.8) opentelemetry-api (~> 1.0) opentelemetry-instrumentation-base (~> 0.22.1) - opentelemetry-instrumentation-pg (0.29.1) + opentelemetry-instrumentation-pg (0.29.2) opentelemetry-api (~> 1.0) opentelemetry-helpers-sql-obfuscation opentelemetry-instrumentation-base (~> 0.22.1) From 6a351e2247d01be1b6f04d5fb4d16272df35d260 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:57:40 +0100 Subject: [PATCH 27/64] Update dependency core-js to v3.40.0 (#33504) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 119c85c7af..7b9ecfe86f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6534,9 +6534,9 @@ __metadata: linkType: hard "core-js@npm:^3.30.2": - version: 3.39.0 - resolution: "core-js@npm:3.39.0" - checksum: 10c0/f7602069b6afb2e3298eec612a5c1e0c3e6a458930fbfc7a4c5f9ac03426507f49ce395eecdd2d9bae9024f820e44582b67ffe16f2272395af26964f174eeb6b + version: 3.40.0 + resolution: "core-js@npm:3.40.0" + checksum: 10c0/db7946ada881e845d8b157061945b1187618fa45cf162f392a151e8a497962aed2da688c982eaa1d444c864be97a70f8be4d73385294b515d224dd164d19f1d4 languageName: node linkType: hard From 67a8d4638c6e6a3ef178258504a6535746608c42 Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Wed, 8 Jan 2025 06:01:51 -0500 Subject: [PATCH 28/64] Unpin peter-evans/create-pull-request to v7 (#30817) --- .github/workflows/crowdin-download.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crowdin-download.yml b/.github/workflows/crowdin-download.yml index a7e47bb2a1..d247a514d9 100644 --- a/.github/workflows/crowdin-download.yml +++ b/.github/workflows/crowdin-download.yml @@ -52,7 +52,7 @@ jobs: # Create or update the pull request - name: Create Pull Request - uses: peter-evans/create-pull-request@v7.0.6 + uses: peter-evans/create-pull-request@v7 with: commit-message: 'New Crowdin translations' title: 'New Crowdin Translations (automated)' From a16d83ffef6693d750283b3af1f18ef5996222e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:22:44 +0100 Subject: [PATCH 29/64] Update Node.js to 22.13 (#33502) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index 35d2d08ea1..fb0a135541 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22.12 +22.13 From d34e9eaf17a56e97c9db84a4b8fc3399446cef3a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 15:02:07 +0100 Subject: [PATCH 30/64] Update dependency @reduxjs/toolkit to v2.5.0 (#33102) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7b9ecfe86f..0f8217566f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3291,22 +3291,22 @@ __metadata: linkType: hard "@reduxjs/toolkit@npm:^2.0.1": - version: 2.3.0 - resolution: "@reduxjs/toolkit@npm:2.3.0" + version: 2.5.0 + resolution: "@reduxjs/toolkit@npm:2.5.0" dependencies: immer: "npm:^10.0.3" redux: "npm:^5.0.1" redux-thunk: "npm:^3.1.0" reselect: "npm:^5.1.0" peerDependencies: - react: ^16.9.0 || ^17.0.0 || ^18 + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 peerDependenciesMeta: react: optional: true react-redux: optional: true - checksum: 10c0/414e90b706331385a2122fc79e33f90c59a9caf9a59419f1bfd7f5e594bc8e4987902fd1bccbc53eb96d22c65ec2981ff5581f3d2df3ecd381a630f391edfc3e + checksum: 10c0/81748a5a6d2f52a14769b6ed25aea1e77cda81b1db6599c7c3a1d1605696c65c4469f55146c2b2a7a2f8ebafa5ecd4996aa8deecb37aebb5307217ec2fe384ac languageName: node linkType: hard From 2c36283a89b8cd59f72e63aac03a674c4c96a326 Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:03:21 +0000 Subject: [PATCH 31/64] Refresh `README.md` (#32143) --- README.md | 75 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 17d9eefb57..60dfa11448 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,24 @@ -

- - - Mastodon -

+> [!NOTE] +> Want to learn more about Mastodon? +> Click below to find out more in a video. -[![GitHub release](https://img.shields.io/github/release/mastodon/mastodon.svg)][releases] -[![Ruby Testing](https://github.com/mastodon/mastodon/actions/workflows/test-ruby.yml/badge.svg)](https://github.com/mastodon/mastodon/actions/workflows/test-ruby.yml) -[![Crowdin](https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg)][crowdin] +

+ + Mastodon hero image + +

-[releases]: https://github.com/mastodon/mastodon/releases -[crowdin]: https://crowdin.com/project/mastodon +

+ + Release + + Ruby Testing + + Crowdin +

Mastodon is a **free, open-source social network server** based on ActivityPub where users can follow friends and discover new ones. On Mastodon, users can publish anything they want: links, pictures, text, and video. All Mastodon servers are interoperable as a federated network (users on one server can seamlessly communicate with users from another one, including non-Mastodon software that implements ActivityPub!) -Click below to **learn more** in a video: - -[![Screenshot](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/ezgif-2-60f1b00403.gif)][youtube_demo] - -[youtube_demo]: https://www.youtube.com/watch?v=IPSbNdBmWKE - ## Navigation - [Project homepage 🐘](https://joinmastodon.org) @@ -37,25 +37,15 @@ Click below to **learn more** in a video: -### No vendor lock-in: Fully interoperable with any conforming platform +**No vendor lock-in: Fully interoperable with any conforming platform** - It doesn't have to be Mastodon; whatever implements ActivityPub is part of the social network! [Learn more](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/) -It doesn't have to be Mastodon; whatever implements ActivityPub is part of the social network! [Learn more](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/) +**Real-time, chronological timeline updates** - updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well! -### Real-time, chronological timeline updates +**Media attachments like images and short videos** - upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos loop continuously! -Updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well! +**Safety and moderation tools** - Mastodon includes private posts, locked accounts, phrase filtering, muting, blocking, and all sorts of other features, along with a reporting and moderation system. [Learn more](https://blog.joinmastodon.org/2018/07/cage-the-mastodon/) -### Media attachments like images and short videos - -Upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos loop continuously! - -### Safety and moderation tools - -Mastodon includes private posts, locked accounts, phrase filtering, muting, blocking, and all sorts of other features, along with a reporting and moderation system. [Learn more](https://blog.joinmastodon.org/2018/07/cage-the-mastodon/) - -### OAuth2 and a straightforward REST API - -Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Streaming APIs. This results in a rich app ecosystem with a lot of choices! +**OAuth2 and a straightforward REST API** - Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Streaming APIs. This results in a rich app ecosystem with a lot of choices! ## Deployment @@ -138,17 +128,30 @@ Mastodon is **free, open-source software** licensed under **AGPLv3**. You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository or submit translations using Crowdin. To get started, take a look at [CONTRIBUTING.md](CONTRIBUTING.md). If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon). -**IRC channel**: #mastodon on irc.libera.chat +**IRC channel**: #mastodon on [`irc.libera.chat`](https://libera.chat) ## License -Copyright (C) 2016-2024 Eugen Rochko & other Mastodon contributors (see [AUTHORS.md](AUTHORS.md)) +Copyright (c) 2016-2024 Eugen Rochko (+ [`mastodon authors`](AUTHORS.md)) -This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +Licensed under GNU Affero General Public License as stated in the [LICENSE](LICENSE): -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +``` +Copyright (c) 2016-2024 Eugen Rochko & other Mastodon contributors -You should have received a copy of the GNU Affero General Public License along with this program. If not, see . +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU Affero General Public License as published by the Free +Software Foundation, either version 3 of the License, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +details. + +You should have received a copy of the GNU Affero General Public License along +with this program. If not, see https://www.gnu.org/licenses/ +``` [codespace]: https://codespaces.new/mastodon/mastodon?quickstart=1&devcontainer_path=.devcontainer%2Fcodespaces%2Fdevcontainer.json [Dev Container extension]: https://containers.dev/supporting#dev-containers From 15669fcf75e79b4f6a2fe0c09ee8ae56d1a25270 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Wed, 8 Jan 2025 15:26:08 +0100 Subject: [PATCH 32/64] Include time portion in formatted datetimes when provided (#33191) --- app/javascript/entrypoints/public.tsx | 6 +++++- app/views/admin/report_notes/_report_note.html.haml | 2 +- app/views/admin/reports/_comment.html.haml | 2 +- app/views/disputes/strikes/show.html.haml | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/javascript/entrypoints/public.tsx b/app/javascript/entrypoints/public.tsx index 9e8ff9caa1..0560e76628 100644 --- a/app/javascript/entrypoints/public.tsx +++ b/app/javascript/entrypoints/public.tsx @@ -119,7 +119,11 @@ function loaded() { formattedContent = dateFormat.format(datetime); } - content.title = formattedContent; + const timeGiven = content.dateTime.includes('T'); + content.title = timeGiven + ? dateTimeFormat.format(datetime) + : dateFormat.format(datetime); + content.textContent = formattedContent; }); diff --git a/app/views/admin/report_notes/_report_note.html.haml b/app/views/admin/report_notes/_report_note.html.haml index dd60f7eabd..9c8e267d62 100644 --- a/app/views/admin/report_notes/_report_note.html.haml +++ b/app/views/admin/report_notes/_report_note.html.haml @@ -4,7 +4,7 @@ .report-notes__item__header %span.username = link_to report_note.account.username, admin_account_path(report_note.account_id) - %time.relative-formatted{ datetime: report_note.created_at.iso8601 } + %time.relative-formatted{ datetime: report_note.created_at.iso8601, title: report_note.created_at } = l report_note.created_at.to_date .report-notes__item__content diff --git a/app/views/admin/reports/_comment.html.haml b/app/views/admin/reports/_comment.html.haml index 8c07210af9..2b3af15c49 100644 --- a/app/views/admin/reports/_comment.html.haml +++ b/app/views/admin/reports/_comment.html.haml @@ -18,7 +18,7 @@ = link_to report.account.username, admin_account_path(report.account_id) - else = link_to report.account.domain, admin_instance_path(report.account.domain) - %time.relative-formatted{ datetime: report.created_at.iso8601 } + %time.relative-formatted{ datetime: report.created_at.iso8601, title: report.created_at } = l report.created_at.to_date .report-notes__item__content = simple_format(h(report.comment)) diff --git a/app/views/disputes/strikes/show.html.haml b/app/views/disputes/strikes/show.html.haml index 150dc06759..322d820a2a 100644 --- a/app/views/disputes/strikes/show.html.haml +++ b/app/views/disputes/strikes/show.html.haml @@ -66,7 +66,7 @@ .report-notes__item__header %span.username = link_to @appeal.account.username, can?(:show, @appeal.account) ? admin_account_path(@appeal.account_id) : short_account_url(@appeal.account) - %time.relative-formatted{ datetime: @appeal.created_at.iso8601 } + %time.relative-formatted{ datetime: @appeal.created_at.iso8601, title: @appeal.created_at } = l @appeal.created_at.to_date .report-notes__item__content From f22a2aab40dab165b2c0872b016e3803c12db972 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 8 Jan 2025 09:28:08 -0500 Subject: [PATCH 33/64] Add `Account#remote?` query method (#33508) --- app/models/account.rb | 6 +++++- app/models/poll.rb | 6 +----- spec/models/account_spec.rb | 28 ++++++++++++++++++++++++---- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/app/models/account.rb b/app/models/account.rb index d42da2e9af..fefc40869f 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -107,7 +107,7 @@ class Account < ApplicationRecord validates_with UniqueUsernameValidator, if: -> { will_save_change_to_username? } # Remote user validations, also applies to internal actors - validates :username, format: { with: USERNAME_ONLY_RE }, if: -> { (!local? || actor_type == 'Application') && will_save_change_to_username? } + validates :username, format: { with: USERNAME_ONLY_RE }, if: -> { (remote? || actor_type == 'Application') && will_save_change_to_username? } # Remote user validations validates :uri, presence: true, unless: :local?, on: :create @@ -186,6 +186,10 @@ class Account < ApplicationRecord domain.nil? end + def remote? + domain.present? + end + def moved? moved_to_account_id.present? end diff --git a/app/models/poll.rb b/app/models/poll.rb index b4e0edcd0f..93ef0cc589 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -61,11 +61,7 @@ class Poll < ApplicationRecord votes.where(account: account).pluck(:choice) end - delegate :local?, to: :account - - def remote? - !local? - end + delegate :local?, :remote?, to: :account def emojis @emojis ||= CustomEmoji.from_text(options.join(' '), account.domain) diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 7755cf9611..809ec52cde 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -48,14 +48,34 @@ RSpec.describe Account do end describe '#local?' do - it 'returns true when the account is local' do + it 'returns true when domain is null' do account = Fabricate(:account, domain: nil) - expect(account.local?).to be true + expect(account).to be_local end - it 'returns false when the account is on a different domain' do + it 'returns false when domain is present' do account = Fabricate(:account, domain: 'foreign.tld') - expect(account.local?).to be false + expect(account).to_not be_local + end + end + + describe '#remote?' do + context 'when the domain is null' do + subject { Fabricate.build :account, domain: nil } + + it { is_expected.to_not be_remote } + end + + context 'when the domain is blank' do + subject { Fabricate.build :account, domain: '' } + + it { is_expected.to_not be_remote } + end + + context 'when the domain is present' do + subject { Fabricate.build :account, domain: 'host.example' } + + it { is_expected.to be_remote } end end From 78e0d6a11a3ef73904bbfc3269dd061d564cac54 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 8 Jan 2025 09:29:32 -0500 Subject: [PATCH 34/64] Extract development section from top-level readme into standalone doc (#33328) --- CONTRIBUTING.md | 4 ++- README.md | 72 +++++-------------------------------------- docs/DEVELOPMENT.md | 75 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 66 deletions(-) create mode 100644 docs/DEVELOPMENT.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8286fdd2f7..4a3825484e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ You can contribute in the following ways: If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon). Please review the org-level [contribution guidelines] for high-level acceptance -criteria guidance. +criteria guidance and the [DEVELOPMENT] guide for environment-specific details. [contribution guidelines]: https://github.com/mastodon/.github/blob/main/CONTRIBUTING.md @@ -53,3 +53,5 @@ It is not always possible to phrase every change in such a manner, but it is des ## Documentation The [Mastodon documentation](https://docs.joinmastodon.org) is a statically generated site. You can [submit merge requests to mastodon/documentation](https://github.com/mastodon/documentation). + +[DEVELOPMENT]: docs/DEVELOPMENT.md diff --git a/README.md b/README.md index 60dfa11448..8a34754576 100644 --- a/README.md +++ b/README.md @@ -64,69 +64,14 @@ Mastodon is a **free, open-source social network server** based on ActivityPub w The repository includes deployment configurations for **Docker and docker-compose** as well as specific platforms like **Heroku**, and **Scalingo**. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). The [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the documentation. -## Development - -### Vagrant - -A **Vagrant** configuration is included for development purposes. To use it, complete the following steps: - -- Install Vagrant and Virtualbox -- Install the `vagrant-hostsupdater` plugin: `vagrant plugin install vagrant-hostsupdater` -- Run `vagrant up` -- Run `vagrant ssh -c "cd /vagrant && bin/dev"` -- Open `http://mastodon.local` in your browser - -### macOS - -To set up **macOS** for native development, complete the following steps: - -- Install [Homebrew] and run `brew install postgresql@14 redis imagemagick -libidn nvm` to install the required project dependencies -- Use a Ruby version manager to activate the ruby in `.ruby-version` and run - `nvm use` to activate the node version from `.nvmrc` -- Run the `bin/setup` script, which will install the required ruby gems and node - packages and prepare the database for local development -- Finally, run the `bin/dev` script which will launch services via `overmind` - (if installed) or `foreman` - -### Docker - -For production hosting and deployment with **Docker**, use the `Dockerfile` and -`docker-compose.yml` in the project root directory. - -For local development, install and launch [Docker], and run: - -```shell -docker compose -f .devcontainer/compose.yaml up -d -docker compose -f .devcontainer/compose.yaml exec app bin/setup -docker compose -f .devcontainer/compose.yaml exec app bin/dev -``` - -### Dev Containers - -Within IDEs that support the [Development Containers] specification, start the -"Mastodon on local machine" container from the editor. The necessary `docker -compose` commands to build and setup the container should run automatically. For -**Visual Studio Code** this requires installing the [Dev Container extension]. - -### GitHub Codespaces - -[GitHub Codespaces] provides a web-based version of VS Code and a cloud hosted -development environment configured with the software needed for this project. - -[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)][codespace] - -- Click the button to create a new codespace, and confirm the options -- Wait for the environment to build (takes a few minutes) -- When the editor is ready, run `bin/dev` in the terminal -- Wait for an _Open in Browser_ prompt. This will open Mastodon -- On the _Ports_ tab "stream" setting change _Port visibility_ → _Public_ - ## Contributing Mastodon is **free, open-source software** licensed under **AGPLv3**. -You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository or submit translations using Crowdin. To get started, take a look at [CONTRIBUTING.md](CONTRIBUTING.md). If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon). +You can open issues for bugs you've found or features you think are missing. You +can also submit pull requests to this repository or translations via Crowdin. To +get started, look at the [CONTRIBUTING] and [DEVELOPMENT] guides. For changes +accepted into Mastodon, you can request to be paid through our [OpenCollective]. **IRC channel**: #mastodon on [`irc.libera.chat`](https://libera.chat) @@ -153,9 +98,6 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/ ``` -[codespace]: https://codespaces.new/mastodon/mastodon?quickstart=1&devcontainer_path=.devcontainer%2Fcodespaces%2Fdevcontainer.json -[Dev Container extension]: https://containers.dev/supporting#dev-containers -[Development Containers]: https://containers.dev/supporting -[Docker]: https://docs.docker.com -[GitHub Codespaces]: https://docs.github.com/en/codespaces -[Homebrew]: https://brew.sh +[CONTRIBUTING]: CONTRIBUTING.md +[DEVELOPMENT]: docs/DEVELOPMENT.md +[OpenCollective]: https://opencollective.com/mastodon diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md new file mode 100644 index 0000000000..39f57dd402 --- /dev/null +++ b/docs/DEVELOPMENT.md @@ -0,0 +1,75 @@ +# Development + +## Overview + +Before starting local development, read the [CONTRIBUTING] guide to understand +what changes are desirable and what general processes to use. + +## Environments + +### Vagrant + +A **Vagrant** configuration is included for development purposes. To use it, +complete the following steps: + +- Install Vagrant and Virtualbox +- Install the `vagrant-hostsupdater` plugin: + `vagrant plugin install vagrant-hostsupdater` +- Run `vagrant up` +- Run `vagrant ssh -c "cd /vagrant && bin/dev"` +- Open `http://mastodon.local` in your browser + +### macOS + +To set up **macOS** for native development, complete the following steps: + +- Install [Homebrew] and run: + `brew install postgresql@14 redis imagemagick libidn nvm` + to install the required project dependencies +- Use a Ruby version manager to activate the ruby in `.ruby-version` and run + `nvm use` to activate the node version from `.nvmrc` +- Run the `bin/setup` script, which will install the required ruby gems and node + packages and prepare the database for local development +- Finally, run the `bin/dev` script which will launch services via `overmind` + (if installed) or `foreman` + +### Docker + +For production hosting and deployment with **Docker**, use the `Dockerfile` and +`docker-compose.yml` in the project root directory. + +For local development, install and launch [Docker], and run: + +```shell +docker compose -f .devcontainer/compose.yaml up -d +docker compose -f .devcontainer/compose.yaml exec app bin/setup +docker compose -f .devcontainer/compose.yaml exec app bin/dev +``` + +### Dev Containers + +Within IDEs that support the [Development Containers] specification, start the +"Mastodon on local machine" container from the editor. The necessary `docker +compose` commands to build and setup the container should run automatically. For +**Visual Studio Code** this requires installing the [Dev Container extension]. + +### GitHub Codespaces + +[GitHub Codespaces] provides a web-based version of VS Code and a cloud hosted +development environment configured with the software needed for this project. + +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)][codespace] + +- Click the button to create a new codespace, and confirm the options +- Wait for the environment to build (takes a few minutes) +- When the editor is ready, run `bin/dev` in the terminal +- Wait for an _Open in Browser_ prompt. This will open Mastodon +- On the _Ports_ tab "stream" setting change _Port visibility_ → _Public_ + +[codespace]: https://codespaces.new/mastodon/mastodon?quickstart=1&devcontainer_path=.devcontainer%2Fcodespaces%2Fdevcontainer.json +[CONTRIBUTING]: CONTRIBUTING.md +[Dev Container extension]: https://containers.dev/supporting#dev-containers +[Development Containers]: https://containers.dev/supporting +[Docker]: https://docs.docker.com +[GitHub Codespaces]: https://docs.github.com/en/codespaces +[Homebrew]: https://brew.sh From 1bf61957632bff5c0a3e8d0af60eeefb41a4cc18 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 8 Jan 2025 17:25:41 +0100 Subject: [PATCH 35/64] Fix use of deprecated `Iterable.isIndexed` from immutable (#33510) --- app/javascript/mastodon/actions/store.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/actions/store.js b/app/javascript/mastodon/actions/store.js index 8ab75cdc44..e8fec13453 100644 --- a/app/javascript/mastodon/actions/store.js +++ b/app/javascript/mastodon/actions/store.js @@ -1,4 +1,4 @@ -import { Iterable, fromJS } from 'immutable'; +import { fromJS, isIndexed } from 'immutable'; import { hydrateCompose } from './compose'; import { importFetchedAccounts } from './importer'; @@ -9,8 +9,7 @@ export const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY'; const convertState = rawState => fromJS(rawState, (k, v) => - Iterable.isIndexed(v) ? v.toList() : v.toMap()); - + isIndexed(v) ? v.toList() : v.toMap()); export function hydrateStore(rawState) { return dispatch => { From 6b1ea8dd2c998a5b6fe5f37454e4c04df4863772 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 8 Jan 2025 17:26:54 +0100 Subject: [PATCH 36/64] Require specific subtype of `formatMessage` in `timeAgoString` (#33511) --- .../mastodon/components/relative_timestamp.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/components/relative_timestamp.tsx b/app/javascript/mastodon/components/relative_timestamp.tsx index ac385e88c6..6253525091 100644 --- a/app/javascript/mastodon/components/relative_timestamp.tsx +++ b/app/javascript/mastodon/components/relative_timestamp.tsx @@ -1,6 +1,6 @@ import { Component } from 'react'; -import type { IntlShape } from 'react-intl'; +import type { MessageDescriptor, PrimitiveType, IntlShape } from 'react-intl'; import { injectIntl, defineMessages } from 'react-intl'; const messages = defineMessages({ @@ -102,7 +102,13 @@ const getUnitDelay = (units: string) => { }; export const timeAgoString = ( - intl: Pick, + intl: { + formatDate: IntlShape['formatDate']; + formatMessage: ( + { id, defaultMessage }: MessageDescriptor, + values?: Record, + ) => string; + }, date: Date, now: number, year: number, From 3c7f3b190cbaf6b6db25b15c16c8dc0bff599c00 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 17:53:12 +0100 Subject: [PATCH 37/64] Update formatjs monorepo (#32774) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 208 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 136 insertions(+), 72 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0f8217566f..a51d49ca56 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2267,14 +2267,26 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:2.2.3": - version: 2.2.3 - resolution: "@formatjs/ecma402-abstract@npm:2.2.3" +"@formatjs/ecma402-abstract@npm:2.2.4": + version: 2.2.4 + resolution: "@formatjs/ecma402-abstract@npm:2.2.4" dependencies: "@formatjs/fast-memoize": "npm:2.2.3" - "@formatjs/intl-localematcher": "npm:0.5.7" + "@formatjs/intl-localematcher": "npm:0.5.8" tslib: "npm:2" - checksum: 10c0/611d12bf320fc5c5b85cb2b57e3dcebe8490a51c6a0459c857c7a3560656cd2bdba5b117e9dd7cf174f5aa120c11eaad7a65a6783637b816caa59a1bc5c727f6 + checksum: 10c0/3f262533fa704ea7a1a7a8107deee2609774a242c621f8cb5dd4bf4c97abf2fc12f5aeda3f4ce85be18147c484a0ca87303dca6abef53290717e685c55eabd2d + languageName: node + linkType: hard + +"@formatjs/ecma402-abstract@npm:2.3.2": + version: 2.3.2 + resolution: "@formatjs/ecma402-abstract@npm:2.3.2" + dependencies: + "@formatjs/fast-memoize": "npm:2.2.6" + "@formatjs/intl-localematcher": "npm:0.5.10" + decimal.js: "npm:10" + tslib: "npm:2" + checksum: 10c0/364e9e7de974fed976e0e8142a0f888ee0af4a11a61899115e5761ed933e7c1f16379b7b54a01524fd3c5d58bf08b71308237ea969cd54889eaf7bb2d30ec776 languageName: node linkType: hard @@ -2296,6 +2308,15 @@ __metadata: languageName: node linkType: hard +"@formatjs/fast-memoize@npm:2.2.6": + version: 2.2.6 + resolution: "@formatjs/fast-memoize@npm:2.2.6" + dependencies: + tslib: "npm:2" + checksum: 10c0/dccdc21105af673e58ec7b04eb17cd6fde1fb1a7e7a446273ca43f7ab97c26d5c0fcc2b9e80d5b54bf9b80354f9e1e681273c0ed26633ec72f0adc2d116dfd7f + languageName: node + linkType: hard + "@formatjs/icu-messageformat-parser@npm:2.7.10": version: 2.7.10 resolution: "@formatjs/icu-messageformat-parser@npm:2.7.10" @@ -2307,14 +2328,35 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-messageformat-parser@npm:2.9.3": - version: 2.9.3 - resolution: "@formatjs/icu-messageformat-parser@npm:2.9.3" +"@formatjs/icu-messageformat-parser@npm:2.9.4": + version: 2.9.4 + resolution: "@formatjs/icu-messageformat-parser@npm:2.9.4" dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.3" - "@formatjs/icu-skeleton-parser": "npm:1.8.7" + "@formatjs/ecma402-abstract": "npm:2.2.4" + "@formatjs/icu-skeleton-parser": "npm:1.8.8" tslib: "npm:2" - checksum: 10c0/519b59f7b4cf90681315c5382f7fcd105eb1974486f0d62d9227b6d0498895114ccc818792c208baae1ef79571d93b0edb9914c676e5ab76924dddb7fd6c28a0 + checksum: 10c0/f1ed14ece7ef0abc9fb62e323b78c994fc772d346801ad5aaa9555e1a7d5c0fda791345f4f2e53a3223f0b82c1a4eaf9a83544c1c20cb39349d1a39bedcf1648 + languageName: node + linkType: hard + +"@formatjs/icu-messageformat-parser@npm:2.9.8": + version: 2.9.8 + resolution: "@formatjs/icu-messageformat-parser@npm:2.9.8" + dependencies: + "@formatjs/ecma402-abstract": "npm:2.3.2" + "@formatjs/icu-skeleton-parser": "npm:1.8.12" + tslib: "npm:2" + checksum: 10c0/df97c7f24fbeb8ef49ae1371f9498ad90f231f88211bf1effb7b2e8ac3531bec67c5d9147ddcb1add0ba697e8d089729add44a9a9c5015e0e8d61e7a43f062d9 + languageName: node + linkType: hard + +"@formatjs/icu-skeleton-parser@npm:1.8.12": + version: 1.8.12 + resolution: "@formatjs/icu-skeleton-parser@npm:1.8.12" + dependencies: + "@formatjs/ecma402-abstract": "npm:2.3.2" + tslib: "npm:2" + checksum: 10c0/03e743aa09acb2137e37d03b98578fcbbc949d056b8c151763778e885d04d621e69c82f7656547f0532351d2a987bffac0a8c4c3d81186f47a28047ba64385e2 languageName: node linkType: hard @@ -2328,35 +2370,44 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-skeleton-parser@npm:1.8.7": - version: 1.8.7 - resolution: "@formatjs/icu-skeleton-parser@npm:1.8.7" +"@formatjs/icu-skeleton-parser@npm:1.8.8": + version: 1.8.8 + resolution: "@formatjs/icu-skeleton-parser@npm:1.8.8" dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.3" + "@formatjs/ecma402-abstract": "npm:2.2.4" tslib: "npm:2" - checksum: 10c0/e29eb4151580f2d324e6591509dc4543e2326266fc209a08580c94d502acab14acc3560d98b3aaf9ffbd5ff8e2683601ff08c65b32886f22da015c31ca35c5d0 + checksum: 10c0/5ad78a5682e83b973e6fed4fca68660b944c41d1e941f0c84d69ff3d10ae835330062dc0a2cf0d237d2675ad3463405061a3963c14c2b9d8d1c1911f892b1a8d languageName: node linkType: hard -"@formatjs/intl-displaynames@npm:6.8.3": - version: 6.8.3 - resolution: "@formatjs/intl-displaynames@npm:6.8.3" +"@formatjs/intl-displaynames@npm:6.8.5": + version: 6.8.5 + resolution: "@formatjs/intl-displaynames@npm:6.8.5" dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.3" - "@formatjs/intl-localematcher": "npm:0.5.7" + "@formatjs/ecma402-abstract": "npm:2.2.4" + "@formatjs/intl-localematcher": "npm:0.5.8" tslib: "npm:2" - checksum: 10c0/54d3ecaabc45dc8494be4cd9633bbf5eb0bc40c5f62ed5e5073aa5b214c4a9a9620d61d1c8a6f0074618474fd9c2ccc42904605078d2f6341c242bf43627bb3a + checksum: 10c0/1092d6bac9ba7ee22470b85c9af16802244aa8a54f07e6cd560d15b96e8a08fc359f20dee88a064fe4c9ca8860f439abb109cbb7977b9ccceb846e28aacdf29c languageName: node linkType: hard -"@formatjs/intl-listformat@npm:7.7.3": - version: 7.7.3 - resolution: "@formatjs/intl-listformat@npm:7.7.3" +"@formatjs/intl-listformat@npm:7.7.5": + version: 7.7.5 + resolution: "@formatjs/intl-listformat@npm:7.7.5" dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.3" - "@formatjs/intl-localematcher": "npm:0.5.7" + "@formatjs/ecma402-abstract": "npm:2.2.4" + "@formatjs/intl-localematcher": "npm:0.5.8" tslib: "npm:2" - checksum: 10c0/2683513e86cc7885528f23237079e3ab9e3a8bc7111aa10d4c685dcbe368ef07039573115df240112fb20f2ec0b70c8ea189ea3b79cbfed7e3dc46024a4667ff + checksum: 10c0/f514397f6b05ac29171fffbbd15636fbec086080058c79c159f24edd2038747c22579d46ebf339cbb672f8505ea408e5d960d6751064c16e02d18445cf4e7e61 + languageName: node + linkType: hard + +"@formatjs/intl-localematcher@npm:0.5.10": + version: 0.5.10 + resolution: "@formatjs/intl-localematcher@npm:0.5.10" + dependencies: + tslib: "npm:2" + checksum: 10c0/362ec83aca9382165be575f1cefa477478339e6fead8ca8866185ce6e58427ea1487a811b12c73d1bcfa99fd4db0c24543b35c823451839f585576bfccb8c9cc languageName: node linkType: hard @@ -2369,43 +2420,44 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-localematcher@npm:0.5.7": - version: 0.5.7 - resolution: "@formatjs/intl-localematcher@npm:0.5.7" +"@formatjs/intl-localematcher@npm:0.5.8": + version: 0.5.8 + resolution: "@formatjs/intl-localematcher@npm:0.5.8" dependencies: tslib: "npm:2" - checksum: 10c0/1ae374ca146a0d7457794926eed808c99971628e594f704a42ae2540b1f38928b26cbf942a7bbcc2796cc9fe8d9d7a603ac422bd9b89b714d2f91b506da40792 + checksum: 10c0/7a660263986326b662d4cb537e8386331c34fda61fb830b105e6c62d49be58ace40728dae614883b27a41cec7b1df8b44f72f79e16e6028bfca65d398dc04f3b languageName: node linkType: hard "@formatjs/intl-pluralrules@npm:^5.2.2": - version: 5.3.3 - resolution: "@formatjs/intl-pluralrules@npm:5.3.3" + version: 5.4.2 + resolution: "@formatjs/intl-pluralrules@npm:5.4.2" dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.3" - "@formatjs/intl-localematcher": "npm:0.5.7" + "@formatjs/ecma402-abstract": "npm:2.3.2" + "@formatjs/intl-localematcher": "npm:0.5.10" + decimal.js: "npm:10" tslib: "npm:2" - checksum: 10c0/003d33af6f5d902517f230b7038e39b8336da3a84500fe5f4278fa5cac0c9a1b746de484f1c2bb2315026fd771491eafdc0aa59a809bb25189b63093efb8400d + checksum: 10c0/0ecb9da19084d7a15e636362c206c7ee14297ad365e3e63ea53c82c8442d02cd4dcf8a0da65af9b0f835b32f0e8c3d43407d6ee0a0d7974c3044c92574b49686 languageName: node linkType: hard -"@formatjs/intl@npm:2.10.13": - version: 2.10.13 - resolution: "@formatjs/intl@npm:2.10.13" +"@formatjs/intl@npm:2.10.15": + version: 2.10.15 + resolution: "@formatjs/intl@npm:2.10.15" dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.3" + "@formatjs/ecma402-abstract": "npm:2.2.4" "@formatjs/fast-memoize": "npm:2.2.3" - "@formatjs/icu-messageformat-parser": "npm:2.9.3" - "@formatjs/intl-displaynames": "npm:6.8.3" - "@formatjs/intl-listformat": "npm:7.7.3" - intl-messageformat: "npm:10.7.5" + "@formatjs/icu-messageformat-parser": "npm:2.9.4" + "@formatjs/intl-displaynames": "npm:6.8.5" + "@formatjs/intl-listformat": "npm:7.7.5" + intl-messageformat: "npm:10.7.7" tslib: "npm:2" peerDependencies: typescript: ^4.7 || 5 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/14edcc45addc181c7a45845bc34cec5c73bb5544dcf8ed455eca916bbd3a5023c7204a8e8e289060545b85006933c6f297c33c4f04a8a4cb3890aa7baae5bfbf + checksum: 10c0/5d51fd0785d5547f375991d7df2d6303479b0083eeb35c42c30c9633aab77101895498f1eace419fd34fdb5c84aea19037c5280c3a9d85f9c3ffe6eef76b6f39 languageName: node linkType: hard @@ -2429,11 +2481,11 @@ __metadata: languageName: node linkType: hard -"@formatjs/ts-transformer@npm:3.13.22": - version: 3.13.22 - resolution: "@formatjs/ts-transformer@npm:3.13.22" +"@formatjs/ts-transformer@npm:3.13.27": + version: 3.13.27 + resolution: "@formatjs/ts-transformer@npm:3.13.27" dependencies: - "@formatjs/icu-messageformat-parser": "npm:2.9.3" + "@formatjs/icu-messageformat-parser": "npm:2.9.8" "@types/json-stable-stringify": "npm:1" "@types/node": "npm:14 || 16 || 17 || 18 || 20 || 22" chalk: "npm:4" @@ -2445,7 +2497,7 @@ __metadata: peerDependenciesMeta: ts-jest: optional: true - checksum: 10c0/42503292248bcae728181fdf68e79eac4169c18064953beb9245097d2c58e5434ae7a7978e6ce2829dfd6eb4b4155f78fecef70ac6820626a338f231c66f60cb + checksum: 10c0/ab26ce081835ce2a1384172a6e24db42d48bc9f8b9b941c646fba2f01ce8370123480623d1fbc1e75f6ec90a232f8ff67b5243c5e9ad18311dc03d7061a4892b languageName: node linkType: hard @@ -5341,21 +5393,21 @@ __metadata: linkType: hard "babel-plugin-formatjs@npm:^10.5.1": - version: 10.5.24 - resolution: "babel-plugin-formatjs@npm:10.5.24" + version: 10.5.30 + resolution: "babel-plugin-formatjs@npm:10.5.30" dependencies: "@babel/core": "npm:^7.25.0" "@babel/helper-plugin-utils": "npm:^7.25.0" "@babel/plugin-syntax-jsx": "npm:^7.25.0" "@babel/traverse": "npm:^7.25.0" "@babel/types": "npm:^7.25.0" - "@formatjs/icu-messageformat-parser": "npm:2.9.3" - "@formatjs/ts-transformer": "npm:3.13.22" + "@formatjs/icu-messageformat-parser": "npm:2.9.8" + "@formatjs/ts-transformer": "npm:3.13.27" "@types/babel__core": "npm:^7.20.5" "@types/babel__helper-plugin-utils": "npm:^7.10.3" "@types/babel__traverse": "npm:^7.20.6" tslib: "npm:2" - checksum: 10c0/a99c92e62edb30e0b6a5bf1115811eb18336b851109f8c096b5a9aa2be3eb72299eea3a8cb706e03705eb79edfa5a62d69bb52d80a375c1d5a1c963e3d00c40e + checksum: 10c0/cf9f17b71da9e95a402e0722cfbf4a549c984a8bb536f6b46dc187fa4b69dd2e248e6a825ea95d5ddfa2a9b09b3eb399cefa2dce1dcf52fd6e661adb99a9d3fa languageName: node linkType: hard @@ -7121,7 +7173,7 @@ __metadata: languageName: node linkType: hard -"decimal.js@npm:^10.4.2, decimal.js@npm:^10.4.3": +"decimal.js@npm:10, decimal.js@npm:^10.4.2, decimal.js@npm:^10.4.3": version: 10.4.3 resolution: "decimal.js@npm:10.4.3" checksum: 10c0/6d60206689ff0911f0ce968d40f163304a6c1bc739927758e6efc7921cfa630130388966f16bf6ef6b838cb33679fbe8e7a78a2f3c478afce841fd55ac8fb8ee @@ -9918,15 +9970,27 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:10.7.5, intl-messageformat@npm:^10.3.5": - version: 10.7.5 - resolution: "intl-messageformat@npm:10.7.5" +"intl-messageformat@npm:10.7.7": + version: 10.7.7 + resolution: "intl-messageformat@npm:10.7.7" dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.3" + "@formatjs/ecma402-abstract": "npm:2.2.4" "@formatjs/fast-memoize": "npm:2.2.3" - "@formatjs/icu-messageformat-parser": "npm:2.9.3" + "@formatjs/icu-messageformat-parser": "npm:2.9.4" tslib: "npm:2" - checksum: 10c0/1aa173a8c16ace50520af3de7d3f0ce9bafda90d47b6d674eb88cc47c12c3460d4d53c97ca412fae1141b00abb8ff2ba313250997a040837f01a25379165c949 + checksum: 10c0/691895fb6a73a2feb2569658706e0d452861441de184dd1c9201e458a39fb80fc80080dd40d3d370400a52663f87de7a6d5a263c94245492f7265dd760441a95 + languageName: node + linkType: hard + +"intl-messageformat@npm:^10.3.5": + version: 10.7.11 + resolution: "intl-messageformat@npm:10.7.11" + dependencies: + "@formatjs/ecma402-abstract": "npm:2.3.2" + "@formatjs/fast-memoize": "npm:2.2.6" + "@formatjs/icu-messageformat-parser": "npm:2.9.8" + tslib: "npm:2" + checksum: 10c0/7ccd972277cc6798038af876c830203084db6552becfa99c3706541fd67838552013f57f8ed0ed3aed03d4fba436591a83a25f913365d66ad04ee9332eee7b73 languageName: node linkType: hard @@ -14662,18 +14726,18 @@ __metadata: linkType: hard "react-intl@npm:^6.4.2": - version: 6.8.6 - resolution: "react-intl@npm:6.8.6" + version: 6.8.9 + resolution: "react-intl@npm:6.8.9" dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.3" - "@formatjs/icu-messageformat-parser": "npm:2.9.3" - "@formatjs/intl": "npm:2.10.13" - "@formatjs/intl-displaynames": "npm:6.8.3" - "@formatjs/intl-listformat": "npm:7.7.3" + "@formatjs/ecma402-abstract": "npm:2.2.4" + "@formatjs/icu-messageformat-parser": "npm:2.9.4" + "@formatjs/intl": "npm:2.10.15" + "@formatjs/intl-displaynames": "npm:6.8.5" + "@formatjs/intl-listformat": "npm:7.7.5" "@types/hoist-non-react-statics": "npm:3" "@types/react": "npm:16 || 17 || 18" hoist-non-react-statics: "npm:3" - intl-messageformat: "npm:10.7.5" + intl-messageformat: "npm:10.7.7" tslib: "npm:2" peerDependencies: react: ^16.6.0 || 17 || 18 @@ -14681,7 +14745,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/ec88cc2b1d0edf089f04c8061ffda730840fb3317177d0dc1a6df208245ec278f52b4ca8546ff9511b0b28ff2d89863c5837a274d33731d4c8f75a3b3baafbe2 + checksum: 10c0/d42a6252beac5448b4a248d84923b0f75dfbbee6208cd5c49ac2f525714ab94efe2a4933d464c64cb161ddccaa37b83dffb2dd0529428219b8a60ce548da3e57 languageName: node linkType: hard From 1ce2dc3d1309adaefdcdc9bd4f300d744b4361b8 Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Thu, 9 Jan 2025 09:09:13 +0100 Subject: [PATCH 38/64] Target same browsers in development and production (#33513) --- .browserslistrc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.browserslistrc b/.browserslistrc index 6367e4d358..0135379d6e 100644 --- a/.browserslistrc +++ b/.browserslistrc @@ -1,10 +1,6 @@ -[production] defaults > 0.2% firefox >= 78 ios >= 15.6 not dead not OperaMini all - -[development] -supports es6-module From ce1501c3a72991b750f7084a20bdf2668595db5e Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 9 Jan 2025 03:12:48 -0500 Subject: [PATCH 39/64] Add "Account::Search" shared example for use in `Account` spec (#33507) --- spec/models/account_spec.rb | 266 +---------------- .../models/concerns/account/search.rb | 268 ++++++++++++++++++ 2 files changed, 269 insertions(+), 265 deletions(-) create mode 100644 spec/support/examples/models/concerns/account/search.rb diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 809ec52cde..f70690ddb6 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -3,6 +3,7 @@ require 'rails_helper' RSpec.describe Account do + include_examples 'Account::Search' include_examples 'Reviewable' context 'with an account record' do @@ -344,271 +345,6 @@ RSpec.describe Account do end end - describe '.search_for' do - before do - _missing = Fabricate( - :account, - display_name: 'Missing', - username: 'missing', - domain: 'missing.com' - ) - end - - it 'does not return suspended users' do - Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com', - suspended: true - ) - - results = described_class.search_for('username') - expect(results).to eq [] - end - - it 'does not return unapproved users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(approved: false) - - results = described_class.search_for('username') - expect(results).to eq [] - end - - it 'does not return unconfirmed users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(confirmed_at: nil) - - results = described_class.search_for('username') - expect(results).to eq [] - end - - it 'accepts ?, \, : and space as delimiter' do - match = Fabricate( - :account, - display_name: 'A & l & i & c & e', - username: 'username', - domain: 'example.com' - ) - - results = described_class.search_for('A?l\i:c e') - expect(results).to eq [match] - end - - it 'finds accounts with matching display_name' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com' - ) - - results = described_class.search_for('display') - expect(results).to eq [match] - end - - it 'finds accounts with matching username' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com' - ) - - results = described_class.search_for('username') - expect(results).to eq [match] - end - - it 'finds accounts with matching domain' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com' - ) - - results = described_class.search_for('example') - expect(results).to eq [match] - end - - it 'limits via constant by default' do - stub_const('Account::Search::DEFAULT_LIMIT', 1) - 2.times.each { Fabricate(:account, display_name: 'Display Name') } - results = described_class.search_for('display') - expect(results.size).to eq 1 - end - - it 'accepts arbitrary limits' do - 2.times.each { Fabricate(:account, display_name: 'Display Name') } - results = described_class.search_for('display', limit: 1) - expect(results.size).to eq 1 - end - - it 'ranks multiple matches higher' do - matches = [ - { username: 'username', display_name: 'username' }, - { display_name: 'Display Name', username: 'username', domain: 'example.com' }, - ].map(&method(:Fabricate).curry(2).call(:account)) - - results = described_class.search_for('username') - expect(results).to eq matches - end - end - - describe '.advanced_search_for' do - let(:account) { Fabricate(:account) } - - context 'when limiting search to followed accounts' do - it 'accepts ?, \, : and space as delimiter' do - match = Fabricate( - :account, - display_name: 'A & l & i & c & e', - username: 'username', - domain: 'example.com' - ) - account.follow!(match) - - results = described_class.advanced_search_for('A?l\i:c e', account, limit: 10, following: true) - expect(results).to eq [match] - end - - it 'does not return non-followed accounts' do - Fabricate( - :account, - display_name: 'A & l & i & c & e', - username: 'username', - domain: 'example.com' - ) - - results = described_class.advanced_search_for('A?l\i:c e', account, limit: 10, following: true) - expect(results).to eq [] - end - - it 'does not return suspended users' do - Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com', - suspended: true - ) - - results = described_class.advanced_search_for('username', account, limit: 10, following: true) - expect(results).to eq [] - end - - it 'does not return unapproved users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(approved: false) - - results = described_class.advanced_search_for('username', account, limit: 10, following: true) - expect(results).to eq [] - end - - it 'does not return unconfirmed users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(confirmed_at: nil) - - results = described_class.advanced_search_for('username', account, limit: 10, following: true) - expect(results).to eq [] - end - end - - it 'does not return suspended users' do - Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com', - suspended: true - ) - - results = described_class.advanced_search_for('username', account) - expect(results).to eq [] - end - - it 'does not return unapproved users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(approved: false) - - results = described_class.advanced_search_for('username', account) - expect(results).to eq [] - end - - it 'does not return unconfirmed users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(confirmed_at: nil) - - results = described_class.advanced_search_for('username', account) - expect(results).to eq [] - end - - it 'accepts ?, \, : and space as delimiter' do - match = Fabricate( - :account, - display_name: 'A & l & i & c & e', - username: 'username', - domain: 'example.com' - ) - - results = described_class.advanced_search_for('A?l\i:c e', account) - expect(results).to eq [match] - end - - it 'limits result count by default value' do - stub_const('Account::Search::DEFAULT_LIMIT', 1) - 2.times { Fabricate(:account, display_name: 'Display Name') } - results = described_class.advanced_search_for('display', account) - expect(results.size).to eq 1 - end - - it 'accepts arbitrary limits' do - 2.times { Fabricate(:account, display_name: 'Display Name') } - results = described_class.advanced_search_for('display', account, limit: 1) - expect(results.size).to eq 1 - end - - it 'ranks followed accounts higher' do - match = Fabricate(:account, username: 'Matching') - followed_match = Fabricate(:account, username: 'Matcher') - Fabricate(:follow, account: account, target_account: followed_match) - - results = described_class.advanced_search_for('match', account) - expect(results).to eq [followed_match, match] - expect(results.first.rank).to be > results.last.rank - end - end - describe '#statuses_count' do subject { Fabricate(:account) } diff --git a/spec/support/examples/models/concerns/account/search.rb b/spec/support/examples/models/concerns/account/search.rb new file mode 100644 index 0000000000..9d9b499732 --- /dev/null +++ b/spec/support/examples/models/concerns/account/search.rb @@ -0,0 +1,268 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'Account::Search' do + describe '.search_for' do + before do + _missing = Fabricate( + :account, + display_name: 'Missing', + username: 'missing', + domain: 'missing.com' + ) + end + + it 'does not return suspended users' do + Fabricate( + :account, + display_name: 'Display Name', + username: 'username', + domain: 'example.com', + suspended: true + ) + + results = described_class.search_for('username') + expect(results).to eq [] + end + + it 'does not return unapproved users' do + match = Fabricate( + :account, + display_name: 'Display Name', + username: 'username' + ) + + match.user.update(approved: false) + + results = described_class.search_for('username') + expect(results).to eq [] + end + + it 'does not return unconfirmed users' do + match = Fabricate( + :account, + display_name: 'Display Name', + username: 'username' + ) + + match.user.update(confirmed_at: nil) + + results = described_class.search_for('username') + expect(results).to eq [] + end + + it 'accepts ?, \, : and space as delimiter' do + match = Fabricate( + :account, + display_name: 'A & l & i & c & e', + username: 'username', + domain: 'example.com' + ) + + results = described_class.search_for('A?l\i:c e') + expect(results).to eq [match] + end + + it 'finds accounts with matching display_name' do + match = Fabricate( + :account, + display_name: 'Display Name', + username: 'username', + domain: 'example.com' + ) + + results = described_class.search_for('display') + expect(results).to eq [match] + end + + it 'finds accounts with matching username' do + match = Fabricate( + :account, + display_name: 'Display Name', + username: 'username', + domain: 'example.com' + ) + + results = described_class.search_for('username') + expect(results).to eq [match] + end + + it 'finds accounts with matching domain' do + match = Fabricate( + :account, + display_name: 'Display Name', + username: 'username', + domain: 'example.com' + ) + + results = described_class.search_for('example') + expect(results).to eq [match] + end + + it 'limits via constant by default' do + stub_const('Account::Search::DEFAULT_LIMIT', 1) + 2.times.each { Fabricate(:account, display_name: 'Display Name') } + results = described_class.search_for('display') + expect(results.size).to eq 1 + end + + it 'accepts arbitrary limits' do + 2.times.each { Fabricate(:account, display_name: 'Display Name') } + results = described_class.search_for('display', limit: 1) + expect(results.size).to eq 1 + end + + it 'ranks multiple matches higher' do + matches = [ + { username: 'username', display_name: 'username' }, + { display_name: 'Display Name', username: 'username', domain: 'example.com' }, + ].map(&method(:Fabricate).curry(2).call(:account)) + + results = described_class.search_for('username') + expect(results).to eq matches + end + end + + describe '.advanced_search_for' do + let(:account) { Fabricate(:account) } + + context 'when limiting search to followed accounts' do + it 'accepts ?, \, : and space as delimiter' do + match = Fabricate( + :account, + display_name: 'A & l & i & c & e', + username: 'username', + domain: 'example.com' + ) + account.follow!(match) + + results = described_class.advanced_search_for('A?l\i:c e', account, limit: 10, following: true) + expect(results).to eq [match] + end + + it 'does not return non-followed accounts' do + Fabricate( + :account, + display_name: 'A & l & i & c & e', + username: 'username', + domain: 'example.com' + ) + + results = described_class.advanced_search_for('A?l\i:c e', account, limit: 10, following: true) + expect(results).to eq [] + end + + it 'does not return suspended users' do + Fabricate( + :account, + display_name: 'Display Name', + username: 'username', + domain: 'example.com', + suspended: true + ) + + results = described_class.advanced_search_for('username', account, limit: 10, following: true) + expect(results).to eq [] + end + + it 'does not return unapproved users' do + match = Fabricate( + :account, + display_name: 'Display Name', + username: 'username' + ) + + match.user.update(approved: false) + + results = described_class.advanced_search_for('username', account, limit: 10, following: true) + expect(results).to eq [] + end + + it 'does not return unconfirmed users' do + match = Fabricate( + :account, + display_name: 'Display Name', + username: 'username' + ) + + match.user.update(confirmed_at: nil) + + results = described_class.advanced_search_for('username', account, limit: 10, following: true) + expect(results).to eq [] + end + end + + it 'does not return suspended users' do + Fabricate( + :account, + display_name: 'Display Name', + username: 'username', + domain: 'example.com', + suspended: true + ) + + results = described_class.advanced_search_for('username', account) + expect(results).to eq [] + end + + it 'does not return unapproved users' do + match = Fabricate( + :account, + display_name: 'Display Name', + username: 'username' + ) + + match.user.update(approved: false) + + results = described_class.advanced_search_for('username', account) + expect(results).to eq [] + end + + it 'does not return unconfirmed users' do + match = Fabricate( + :account, + display_name: 'Display Name', + username: 'username' + ) + + match.user.update(confirmed_at: nil) + + results = described_class.advanced_search_for('username', account) + expect(results).to eq [] + end + + it 'accepts ?, \, : and space as delimiter' do + match = Fabricate( + :account, + display_name: 'A & l & i & c & e', + username: 'username', + domain: 'example.com' + ) + + results = described_class.advanced_search_for('A?l\i:c e', account) + expect(results).to eq [match] + end + + it 'limits result count by default value' do + stub_const('Account::Search::DEFAULT_LIMIT', 1) + 2.times { Fabricate(:account, display_name: 'Display Name') } + results = described_class.advanced_search_for('display', account) + expect(results.size).to eq 1 + end + + it 'accepts arbitrary limits' do + 2.times { Fabricate(:account, display_name: 'Display Name') } + results = described_class.advanced_search_for('display', account, limit: 1) + expect(results.size).to eq 1 + end + + it 'ranks followed accounts higher' do + match = Fabricate(:account, username: 'Matching') + followed_match = Fabricate(:account, username: 'Matcher') + Fabricate(:follow, account: account, target_account: followed_match) + + results = described_class.advanced_search_for('match', account) + expect(results).to eq [followed_match, match] + expect(results.first.rank).to be > results.last.rank + end + end +end From f4b463ecb1203beaafbca11b9a760729b9a66223 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 9 Jan 2025 03:17:00 -0500 Subject: [PATCH 40/64] Use `response.parsed_body` for error view application controller spec (#33515) --- .../application_controller_spec.rb | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 4ee951628e..2e7a59db05 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -3,6 +3,8 @@ require 'rails_helper' RSpec.describe ApplicationController do + render_views + controller do def success head 200 @@ -23,9 +25,22 @@ RSpec.describe ApplicationController do shared_examples 'respond_with_error' do |code| it "returns http #{code} for http and renders template" do - expect(subject).to render_template("errors/#{code}", layout: 'error') + subject - expect(response).to have_http_status(code) + expect(response) + .to have_http_status(code) + expect(response.parsed_body) + .to have_css('body[class=error]') + expect(response.parsed_body.css('h1').to_s) + .to include(error_content(code)) + end + + def error_content(code) + if code == 422 + I18n.t('errors.422.content') + else + I18n.t("errors.#{code}") + end end end From 4148b6843097295cb1d110c072946ea8f78fc238 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 9 Jan 2025 03:17:06 -0500 Subject: [PATCH 41/64] Remove `render_template` from remote interaction helper request spec (#33518) --- spec/requests/remote_interaction_helper_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/requests/remote_interaction_helper_spec.rb b/spec/requests/remote_interaction_helper_spec.rb index 942f70b9a4..b89060b5b2 100644 --- a/spec/requests/remote_interaction_helper_spec.rb +++ b/spec/requests/remote_interaction_helper_spec.rb @@ -9,7 +9,6 @@ RSpec.describe 'Remote Interaction Helper' do expect(response) .to have_http_status(200) - .and render_template(:index, layout: 'helper_frame') .and have_attributes( headers: include( 'X-Frame-Options' => 'SAMEORIGIN', @@ -17,6 +16,8 @@ RSpec.describe 'Remote Interaction Helper' do 'Content-Security-Policy' => expected_csp_headers ) ) + expect(response.body) + .to match(/remote_interaction_helper/) end end From cbae00ad235db71dc8963749a616b6b9561afdab Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 9 Jan 2025 03:17:11 -0500 Subject: [PATCH 42/64] Remove `render_template` from accounts request spec (#33519) --- spec/requests/accounts_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/requests/accounts_spec.rb b/spec/requests/accounts_spec.rb index afd9ac80e2..72913ebf22 100644 --- a/spec/requests/accounts_spec.rb +++ b/spec/requests/accounts_spec.rb @@ -53,8 +53,9 @@ RSpec.describe 'Accounts show response' do it 'returns a standard HTML response', :aggregate_failures do expect(response) .to have_http_status(200) - .and render_template(:show) .and have_http_link_header(ActivityPub::TagManager.instance.uri_for(account)).for(rel: 'alternate') + expect(response.parsed_body.at('title').content) + .to include(account.username) end end From 4e2c15b45dbe324d1f202f0260889364fd5f1702 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Jan 2025 08:21:47 +0000 Subject: [PATCH 43/64] New Crowdin Translations (automated) (#33522) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/hu.json | 1 + app/javascript/mastodon/locales/ia.json | 2 ++ app/javascript/mastodon/locales/nn.json | 1 + app/javascript/mastodon/locales/pt-PT.json | 6 ++--- app/javascript/mastodon/locales/sv.json | 1 + config/locales/activerecord.hu.yml | 2 ++ config/locales/activerecord.ia.yml | 2 ++ config/locales/activerecord.lv.yml | 7 +++++ config/locales/activerecord.sv.yml | 2 ++ config/locales/gl.yml | 4 +-- config/locales/lv.yml | 30 ++++++++++++++++++---- config/locales/pt-PT.yml | 2 +- config/locales/simple_form.lv.yml | 9 +++++-- config/locales/simple_form.pt-PT.yml | 4 +-- config/locales/simple_form.sv.yml | 5 ++++ 15 files changed, 63 insertions(+), 15 deletions(-) diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index d1ae388675..703abf242b 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -457,6 +457,7 @@ "keyboard_shortcuts.toggle_hidden": "Tartalmi figyelmeztetéssel ellátott szöveg megjelenítése/elrejtése", "keyboard_shortcuts.toggle_sensitivity": "Média megjelenítése/elrejtése", "keyboard_shortcuts.toot": "Új bejegyzés írása", + "keyboard_shortcuts.translate": "Bejegyzés lefordítása", "keyboard_shortcuts.unfocus": "Szerkesztés/keresés fókuszból való kivétele", "keyboard_shortcuts.up": "Mozgás felfelé a listában", "lightbox.close": "Bezárás", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 0b17e60710..e2f821022e 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -457,6 +457,7 @@ "keyboard_shortcuts.toggle_hidden": "Monstrar/celar texto detra advertimento de contento", "keyboard_shortcuts.toggle_sensitivity": "Monstrar/celar multimedia", "keyboard_shortcuts.toot": "Initiar un nove message", + "keyboard_shortcuts.translate": "a traducer un message", "keyboard_shortcuts.unfocus": "Disfocalisar le area de composition de texto/de recerca", "keyboard_shortcuts.up": "Displaciar in alto in le lista", "lightbox.close": "Clauder", @@ -836,6 +837,7 @@ "status.reblogs.empty": "Necuno ha ancora impulsate iste message. Quando alcuno lo face, le impulsos apparera hic.", "status.redraft": "Deler e reconciper", "status.remove_bookmark": "Remover marcapagina", + "status.remove_favourite": "Remover del favoritos", "status.replied_in_thread": "Respondite in le discussion", "status.replied_to": "Respondite a {name}", "status.reply": "Responder", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index 6091f1679f..1a7f92be18 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -837,6 +837,7 @@ "status.reblogs.empty": "Ingen har framheva dette tutet enno. Om nokon gjer, så dukkar det opp her.", "status.redraft": "Slett & skriv på nytt", "status.remove_bookmark": "Fjern bokmerke", + "status.remove_favourite": "Fjern frå favorittar", "status.replied_in_thread": "Svara i tråden", "status.replied_to": "Svarte {name}", "status.reply": "Svar", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index fa4f715b6d..b4b3c40dc5 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -85,7 +85,7 @@ "alert.rate_limited.title": "Limite de tentativas", "alert.unexpected.message": "Ocorreu um erro inesperado.", "alert.unexpected.title": "Bolas!", - "alt_text_badge.title": "Texto alternativo", + "alt_text_badge.title": "Texto descritivo", "announcement.announcement": "Mensagem de manutenção", "annual_report.summary.archetype.booster": "O caçador de frescura", "annual_report.summary.archetype.lurker": "O espreitador", @@ -642,10 +642,10 @@ "notifications.policy.filter_hint": "Enviar para a caixa de notificações filtradas", "notifications.policy.filter_limited_accounts_hint": "Limitado pelos moderadores do servidor", "notifications.policy.filter_limited_accounts_title": "Contas moderadas", - "notifications.policy.filter_new_accounts.hint": "Criada {days, plural, one {no último dia} other {nos últimos # dias}}", + "notifications.policy.filter_new_accounts.hint": "Criadas {days, plural, one {no último dia} other {nos últimos # dias}}", "notifications.policy.filter_new_accounts_title": "Novas contas", "notifications.policy.filter_not_followers_hint": "Incluindo pessoas que te seguem há menos de {days, plural, one {um dia} other {# dias}}", - "notifications.policy.filter_not_followers_title": "Pessoas não te seguem", + "notifications.policy.filter_not_followers_title": "Pessoas que não te seguem", "notifications.policy.filter_not_following_hint": "Até que os aproves manualmente", "notifications.policy.filter_not_following_title": "Pessoas que não segues", "notifications.policy.filter_private_mentions_hint": "Filtrado, a não ser que seja em resposta à tua própria menção ou se seguires o remetente", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 486c3ac19d..f451caf6f9 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -697,6 +697,7 @@ "recommended": "Rekommenderas", "refresh": "Läs om", "regeneration_indicator.please_stand_by": "Vänligen vänta.", + "regeneration_indicator.preparing_your_home_feed": "Förbereder ditt hemflöde…", "relative_time.days": "{number}d", "relative_time.full.days": "{number, plural, one {# dag} other {# dagar}} sedan", "relative_time.full.hours": "{number, plural, one {# timme} other {# timmar}} sedan", diff --git a/config/locales/activerecord.hu.yml b/config/locales/activerecord.hu.yml index 27ca9018d4..b26d1afbe3 100644 --- a/config/locales/activerecord.hu.yml +++ b/config/locales/activerecord.hu.yml @@ -24,6 +24,8 @@ hu: models: account: attributes: + fields: + fields_with_values_missing_labels: hiányzó címkékkel rendelkező értékeket tartalmaz username: invalid: csak betűket, számokat vagy alávonást tartalmazhat reserved: foglalt diff --git a/config/locales/activerecord.ia.yml b/config/locales/activerecord.ia.yml index fcb3f68278..35b28a19aa 100644 --- a/config/locales/activerecord.ia.yml +++ b/config/locales/activerecord.ia.yml @@ -24,6 +24,8 @@ ia: models: account: attributes: + fields: + fields_with_values_missing_labels: contine valores con etiquettas perdite username: invalid: debe continer solmente litteras, numeros e lineettas basse reserved: es reservate diff --git a/config/locales/activerecord.lv.yml b/config/locales/activerecord.lv.yml index b7e2db65e8..3fb928c89c 100644 --- a/config/locales/activerecord.lv.yml +++ b/config/locales/activerecord.lv.yml @@ -24,6 +24,8 @@ lv: models: account: attributes: + fields: + fields_with_values_missing_labels: satur vērtības ar trūkstošām iezīmēm username: invalid: drīkst saturēt tikai burtus, ciparus un pasvītras reserved: ir rezervēts @@ -39,6 +41,11 @@ lv: attributes: data: malformed: ir nepareizi veidots + list_account: + attributes: + account_id: + taken: jau ir sarakstā + must_be_following: jābūt kontam, kuram seko status: attributes: reblog: diff --git a/config/locales/activerecord.sv.yml b/config/locales/activerecord.sv.yml index f05161992c..bf1ef22f3d 100644 --- a/config/locales/activerecord.sv.yml +++ b/config/locales/activerecord.sv.yml @@ -24,6 +24,8 @@ sv: models: account: attributes: + fields: + fields_with_values_missing_labels: innehåller värden med saknade etiketter username: invalid: endast bokstäver, siffror och understrykning reserved: är reserverat diff --git a/config/locales/gl.yml b/config/locales/gl.yml index ac6581c8c9..63a2b9b340 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -1859,9 +1859,9 @@ gl: '63113904': 2 anos '7889238': 3 meses min_age_label: Límite temporal - min_favs: Manter as publicacións favorecidas polo menos + min_favs: Manter publicacións favorecidas polo menos min_favs_hint: Non elimina ningunha das túas publicacións que recibiron alomenos esta cantidade de favorecementos. Deixa en branco para eliminar publicacións independentemente do número de favorecementos - min_reblogs: Manter publicacións promovidas máis de + min_reblogs: Manter publicacións promovidas polo menos min_reblogs_hint: Non elimina ningunha das túas publicacións se foron promovidas máis deste número de veces. Deixa en branco para eliminar publicacións independentemente do seu número de promocións stream_entries: sensitive_content: Contido sensible diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 0f757c6370..09b629c4da 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -217,6 +217,7 @@ lv: enable_user: Ieslēgt Lietotāju memorialize_account: Saglabāt Kontu Piemiņai promote_user: Izceltt Lietotāju + publish_terms_of_service: Publicēt pakalpojuma izmantošanas nosacījumus reject_appeal: Noraidīt Apelāciju reject_user: Noraidīt lietotāju remove_avatar_user: Noņemt profila attēlu @@ -273,6 +274,7 @@ lv: enable_user_html: "%{name} iespējoja pieteikšanos lietotājam %{target}" memorialize_account_html: "%{name} pārvērta %{target} kontu par atmiņas lapu" promote_user_html: "%{name} paaugstināja lietotāju %{target}" + publish_terms_of_service_html: "%{name} padarīja pieejamus pakalpojuma izmantošanas nosacījumu atjauninājumus" reject_appeal_html: "%{name} noraidīja satura pārraudzības lēmuma iebildumu no %{target}" reject_user_html: "%{name} noraidīja reģistrēšanos no %{target}" remove_avatar_user_html: "%{name} noņēma %{target} profila attēlu" @@ -641,7 +643,7 @@ lv: create_and_resolve: Atrisināt ar piezīmi create_and_unresolve: Atvērt atkārtoti ar piezīmi delete: Dzēst - placeholder: Apraksti veiktās darbības vai citus saistītus atjauninājumus... + placeholder: Jāapraksta veiktās darbības vai jebkuri citi saistītie atjauninājumi... title: Piezīmes notes_description_html: Skati un atstāj piezīmes citiem moderatoriem un sev nākotnei processed_msg: 'Pārskats #%{id} veiksmīgi apstrādāts' @@ -746,13 +748,13 @@ lv: rules: add_new: Pievienot noteikumu delete: Dzēst - description_html: Lai gan lielākā daļa apgalvo, ka ir izlasījuši pakalpojumu sniegšanas noteikumus un piekrīt tiem, parasti cilvēki to izlasa tikai pēc problēmas rašanās. Padariet vienkāršāku sava servera noteikumu uztveršanu, veidojot tos vienkāršā sarakstā pa punktiem. Centieties, lai atsevišķi noteikumi būtu īsi un vienkārši, taču arī nesadaliet tos daudzos atsevišķos vienumos. + description_html: Kaut arī lielākā daļa apgalvo, ka ir lasījuši un piekrīt pakalpojuma izmantošanas nosacījumiem, parasti cilvēki tos neizlasa, līdz rodas sarežģījumi. Padari vienkāršāku sava servera noteikumu pārskatīšanu, sniedzot tos vienkāršā uzsvēruma punktu sarakstā! Jāmēģina atsevišķus noteikumus veidot īsus un vienkāršus, bet jāmēģina arī tos nesadalīt daudzos atsevišķos vienumos. edit: Labot nosacījumu empty: Servera noteikumi vēl nav definēti. title: Servera noteikumi settings: about: - manage_rules: Pārvaldīt servera nosacījumus + manage_rules: Pārvaldīt servera noteikumus preamble: Sniedz padziļinātu informāciju par to, kā serveris tiek darbināts, moderēts un finansēts. rules_hint: Noteikumiem, kas taviem lietotājiem ir jāievēro, ir īpaša sadaļa. title: Par @@ -821,6 +823,7 @@ lv: back_to_account: Atpakaļ uz konta lapu back_to_report: Atpakaļ uz paziņojumu lapu batch: + add_to_report: 'Pievienot atskaitei #%{id}' remove_from_report: Noņemt no ziņojuma report: Ziņojums contents: Saturs @@ -832,13 +835,17 @@ lv: media: title: Multivide metadata: Metadati + no_history: Šis ieraksts nav bijis labots no_status_selected: Neviena ziņa netika mainīta, jo neviena netika atlasīta open: Atvērt ziņu original_status: Oriģinālā ziņa reblogs: Reblogi + replied_to_html: Atbildēja %{acct_link} status_changed: Ziņa mainīta status_title: Publicēja @%{name} + title: Konta ieraksti - @%{name} trending: Aktuāli + view_publicly: Skatīt publiski visibility: Redzamība with_media: Ar multividi strikes: @@ -876,8 +883,8 @@ lv: message_html: 'Nesaderīga Elasticsearch versija: %{value}' version_comparison: Darbojas Elasticsearch %{running_version}, tomēr ir nepieciešama %{required_version} rules_check: - action: Pārvaldīt servera nosacījumus - message_html: Tu neesi definējis nevienu servera nosacījumu. + action: Pārvaldīt servera noteikumus + message_html: Nav pievienots neviens servera noteikums. sidekiq_process_check: message_html: Rindā(s) %{value} nedarbojas neviens Sidekiq process. Lūdzu, pārskati savu Sidekiq konfigurāciju software_version_check: @@ -907,13 +914,21 @@ lv: name: Nosaukums newest: Jaunākie oldest: Vecākie + open: Apskatīt publiski reset: Atiestatīt review: Pārskatīt stāvokli search: Meklēt title: Tēmturi updated_msg: Tēmtura iestatījumi ir veiksmīgi atjaunināti terms_of_service: + back: Atpakaļ uz pakalpojuma izmantošanas nosacījumiem changelog: Kas ir mainījies + create: Izmantot savus + current: Pašreizējie + draft: Melnraksts + generate: Izmantot sagatavi + generates: + action: Izveidot history: Vēsture publish: Publicēt published_on_html: Publicēts %{date} @@ -1826,6 +1841,11 @@ lv: further_actions_html: Ja tas nebiji tu, iesakām nekavējoties %{action} un iespējot divu faktoru autentifikāciju, lai tavs konts būtu drošībā. subject: Tavam kontam ir piekļūts no jaunas IP adreses title: Jauna pieteikšanās + terms_of_service_changed: + sign_off: "%{domain} komanda" + subject: Mūsu pakalpojuma izmantošanas nosacījumu atjauninājumi + subtitle: Mainās %{domain} pakalpojuma izmantošanas nosacījumi + title: Svarīgs atjauninājums warning: appeal: Iesniegt apelāciju appeal_description: Ja uzskatāt, ka tā ir kļūda, varat iesniegt apelāciju %{instance} darbiniekiem. diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index 41fc9fbecc..bba71f165d 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -10,7 +10,7 @@ pt-PT: followers: one: Seguidor other: Seguidores - following: A seguir + following: Seguindo instance_actor_flash: Esta conta é um ator virtual utilizado para representar o servidor em si e não um utilizador individual. É utilizada para efeitos de federação e não deve ser suspensa. last_active: última atividade link_verified_on: A posse desta hiperligação foi verificada em %{date} diff --git a/config/locales/simple_form.lv.yml b/config/locales/simple_form.lv.yml index 2f4a05dca4..53224966f1 100644 --- a/config/locales/simple_form.lv.yml +++ b/config/locales/simple_form.lv.yml @@ -119,8 +119,8 @@ lv: sign_up_requires_approval: Jaunām reģistrācijām būs nepieciešams tavs apstiprinājums severity: Izvēlies, kas notiks ar pieprasījumiem no šīs IP adreses rule: - hint: Izvēles. Sniedz vairāk informācijas par nosacījumu - text: Apraksti nosacījumus vai prasības šī servera lietotājiem. Centies, lai tas būtu īss un vienkāršs + hint: Izvēles. Sniedz vairāk informācijas par noteikumu + text: Jāapraksta nosacījums vai prasība šī servera lietotājiem. Jāmēģina to veidot īsu un vienkāršu sessions: otp: 'Ievadi divfaktoru kodu, ko ģenerējusi tava tālruņa lietotne, vai izmanto kādu no atkopšanas kodiem:' webauthn: Ja tā ir USB atslēga, noteikti ievieto to un, ja nepieciešams, pieskaries tai. @@ -317,6 +317,11 @@ lv: name: Tēmturis trendable: Atļaut šim tēmturim parādīties zem tendencēm usable: Ļaut ierakstos vietēji izmantot šo tēmturi + terms_of_service: + changelog: Kas ir mainījies? + text: Pakalpojuma izmantošanas nosacījumi + terms_of_service_generator: + domain: Domēna vārds user: role: Loma time_zone: Laika josla diff --git a/config/locales/simple_form.pt-PT.yml b/config/locales/simple_form.pt-PT.yml index efc64d6dc6..f5a7e3a27e 100644 --- a/config/locales/simple_form.pt-PT.yml +++ b/config/locales/simple_form.pt-PT.yml @@ -161,7 +161,7 @@ pt-PT: fields: name: Rótulo value: Conteúdo - indexable: Incluir mensagens públicas nos resultados da pesquisa + indexable: Incluir mensagens públicas nos resultados de pesquisas show_collections: Mostrar quem sigo e os meus seguidores no perfil unlocked: Aceitar automaticamente novos seguidores account_alias: @@ -205,7 +205,7 @@ pt-PT: email: Endereço de correio electrónico expires_in: Expira em fields: Metadados de perfil - header: Cabeçalho + header: Imagem de cabeçalho honeypot: "%{label} (não preencher)" inbox_url: URL da caixa de entrada do repetidor irreversible: Expandir em vez de esconder diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml index 5fd258d7e0..421d360fac 100644 --- a/config/locales/simple_form.sv.yml +++ b/config/locales/simple_form.sv.yml @@ -134,7 +134,9 @@ sv: changelog: Kan struktureras med Markdown syntax. text: Kan struktureras med Markdown syntax. terms_of_service_generator: + arbitration_address: Kan vara samma som fysisk adress ovan, eller “N/A” om du använder e-post arbitration_website: Kan vara ett webbformulär, eller ”N/A” om du använder e-post + dmca_email: Kan vara samma e-postadress som används för “E-postadress för juridiska meddelanden” ovan jurisdiction: Lista det land där vem som än betalar räkningarna bor. Om det är ett företag eller annan enhet, lista landet där det är inkorporerat, och staden, regionen, territoriet eller staten på lämpligt sätt. user: chosen_languages: Vid aktivering visas bara inlägg på dina valda språk i offentliga tidslinjer @@ -330,6 +332,9 @@ sv: text: Användarvillkor terms_of_service_generator: admin_email: E-postadress för juridiska meddelanden + dmca_address: Fysisk adress för meddelanden om DMCA/upphovsrätt + dmca_email: Fysisk adress för meddelanden om DMCA/upphovsrätt + domain: Domän user: role: Roll time_zone: Tidszon From 8e2c642d4436eb06bf3c49379efe93cce20e58ef Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Thu, 9 Jan 2025 09:35:35 +0100 Subject: [PATCH 44/64] Do now swallow response body on persistent connection (#32729) --- app/lib/request.rb | 10 ++------ spec/lib/request_spec.rb | 49 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/app/lib/request.rb b/app/lib/request.rb index 3d2a0c0e31..f984f0e63e 100644 --- a/app/lib/request.rb +++ b/app/lib/request.rb @@ -111,16 +111,10 @@ class Request end begin - # If we are using a persistent connection, we have to - # read every response to be able to move forward at all. - # However, simply calling #to_s or #flush may not be safe, - # as the response body, if malicious, could be too big - # for our memory. So we use the #body_with_limit method - response.body_with_limit if http_client.persistent? - yield response if block_given? ensure - http_client.close unless http_client.persistent? + response.truncated_body if http_client.persistent? && !response.connection.finished_request? + http_client.close unless http_client.persistent? && response.connection.finished_request? end end diff --git a/spec/lib/request_spec.rb b/spec/lib/request_spec.rb index c600a48ee2..f17cf637b9 100644 --- a/spec/lib/request_spec.rb +++ b/spec/lib/request_spec.rb @@ -4,7 +4,9 @@ require 'rails_helper' require 'securerandom' RSpec.describe Request do - subject { described_class.new(:get, 'http://example.com') } + subject { described_class.new(:get, 'http://example.com', **options) } + + let(:options) { {} } describe '#headers' do it 'returns user agent' do @@ -39,8 +41,8 @@ RSpec.describe Request do end describe '#perform' do - context 'with valid host' do - before { stub_request(:get, 'http://example.com') } + context 'with valid host and non-persistent connection' do + before { stub_request(:get, 'http://example.com').to_return(body: 'lorem ipsum') } it 'executes a HTTP request' do expect { |block| subject.perform(&block) }.to yield_control @@ -71,9 +73,9 @@ RSpec.describe Request do expect(subject.send(:http_client)).to have_received(:close) end - it 'returns response which implements body_with_limit' do + it 'yields response' do subject.perform do |response| - expect(response).to respond_to :body_with_limit + expect(response.body_with_limit).to eq 'lorem ipsum' end end end @@ -95,6 +97,43 @@ RSpec.describe Request do expect { subject.perform }.to raise_error Mastodon::ValidationError end end + + context 'with persistent connection' do + before { stub_request(:get, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes)) } + + let(:http_client) { described_class.http_client.persistent('http://example.com') } + let(:options) { { http_client: http_client } } + + it 'leaves connection open after completely consumed response' do + allow(http_client).to receive(:close) + + subject.perform { |response| response.truncated_body(3.megabytes) } + + expect(http_client).to_not have_received(:close) + end + + it 'leaves connection open after nearly consumed response' do + allow(http_client).to receive(:close) + + subject.perform { |response| response.truncated_body(1.8.megabytes) } + + expect(http_client).to_not have_received(:close) + end + + it 'closes connection after unconsumed response' do + allow(http_client).to receive(:close) + + subject.perform + + expect(http_client).to have_received(:close) + end + + it 'yields response' do + subject.perform do |response| + expect(response.body_with_limit(2.megabytes).size).to eq 2.megabytes + end + end + end end describe "response's body_with_limit method" do From b0fbb7175997c81cffee815fa34022142fcc8ef0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Jan 2025 10:55:34 +0100 Subject: [PATCH 45/64] Update dependency jsdom to v26 (#33521) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- streaming/package.json | 2 +- yarn.lock | 121 ++++++++++++++++++++++++----------------- 2 files changed, 71 insertions(+), 52 deletions(-) diff --git a/streaming/package.json b/streaming/package.json index 2419ffd273..b98608edd5 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -21,7 +21,7 @@ "dotenv": "^16.0.3", "express": "^4.18.2", "ioredis": "^5.3.2", - "jsdom": "^25.0.0", + "jsdom": "^26.0.0", "pg": "^8.5.0", "pg-connection-string": "^2.6.0", "pino": "^9.0.0", diff --git a/yarn.lock b/yarn.lock index a51d49ca56..3136b05aa5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,6 +42,19 @@ __metadata: languageName: node linkType: hard +"@asamuzakjp/css-color@npm:^2.8.2": + version: 2.8.2 + resolution: "@asamuzakjp/css-color@npm:2.8.2" + dependencies: + "@csstools/css-calc": "npm:^2.1.1" + "@csstools/css-color-parser": "npm:^3.0.7" + "@csstools/css-parser-algorithms": "npm:^3.0.4" + "@csstools/css-tokenizer": "npm:^3.0.3" + lru-cache: "npm:^11.0.2" + checksum: 10c0/352b91ca7741876e459cd3cb350a969e842da1e532577157d38365a6da89b7d6e6944249489366ee61b8a225ede1b521e7ab305b70ad4c688b01404061eecca8 + languageName: node + linkType: hard + "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0": version: 7.26.0 resolution: "@babel/code-frame@npm:7.26.0" @@ -3061,7 +3074,7 @@ __metadata: eslint-define-config: "npm:^2.0.0" express: "npm:^4.18.2" ioredis: "npm:^5.3.2" - jsdom: "npm:^25.0.0" + jsdom: "npm:^26.0.0" pg: "npm:^8.5.0" pg-connection-string: "npm:^2.6.0" pino: "npm:^9.0.0" @@ -4792,12 +4805,10 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0": - version: 7.1.0 - resolution: "agent-base@npm:7.1.0" - dependencies: - debug: "npm:^4.3.4" - checksum: 10c0/fc974ab57ffdd8421a2bc339644d312a9cca320c20c3393c9d8b1fd91731b9bbabdb985df5fc860f5b79d81c3e350daa3fcb31c5c07c0bb385aafc817df004ce +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": + version: 7.1.3 + resolution: "agent-base@npm:7.1.3" + checksum: 10c0/6192b580c5b1d8fb399b9c62bf8343d76654c2dd62afcb9a52b2cf44a8b6ace1e3b704d3fe3547d91555c857d3df02603341ff2cb961b9cfe2b12f9f3c38ee11 languageName: node linkType: hard @@ -7045,12 +7056,13 @@ __metadata: languageName: node linkType: hard -"cssstyle@npm:^4.1.0": - version: 4.1.0 - resolution: "cssstyle@npm:4.1.0" +"cssstyle@npm:^4.2.1": + version: 4.2.1 + resolution: "cssstyle@npm:4.2.1" dependencies: - rrweb-cssom: "npm:^0.7.1" - checksum: 10c0/05c6597e5d3e0ec6b15221f2c0ce9a0443a46cc50a6089a3ba9ee1ac27f83ff86a445a8f95435137dadd859f091fc61b6d342abaf396d3c910471b5b33cfcbfa + "@asamuzakjp/css-color": "npm:^2.8.2" + rrweb-cssom: "npm:^0.8.0" + checksum: 10c0/02ba8c47c0caaab57acadacb3eb6c0f5f009000f55d61f6563670e07d389b26edefeed497e6c1847fcd2e6bbe0b6974c2d4291f97fa0c6ec6add13a7fa926d84 languageName: node linkType: hard @@ -7761,7 +7773,7 @@ __metadata: languageName: node linkType: hard -"entities@npm:^4.2.0, entities@npm:^4.4.0": +"entities@npm:^4.2.0, entities@npm:^4.5.0": version: 4.5.0 resolution: "entities@npm:4.5.0" checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 @@ -8918,14 +8930,14 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^4.0.0": - version: 4.0.0 - resolution: "form-data@npm:4.0.0" +"form-data@npm:^4.0.0, form-data@npm:^4.0.1": + version: 4.0.1 + resolution: "form-data@npm:4.0.1" dependencies: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" mime-types: "npm:^2.1.12" - checksum: 10c0/cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e + checksum: 10c0/bb102d570be8592c23f4ea72d7df9daa50c7792eb0cf1c5d7e506c1706e7426a4e4ae48a35b109e91c85f1c0ec63774a21ae252b66f4eb981cb8efef7d0463c8 languageName: node linkType: hard @@ -9705,13 +9717,13 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.5": - version: 7.0.5 - resolution: "https-proxy-agent@npm:7.0.5" +"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.6": + version: 7.0.6 + resolution: "https-proxy-agent@npm:7.0.6" dependencies: - agent-base: "npm:^7.0.2" + agent-base: "npm:^7.1.2" debug: "npm:4" - checksum: 10c0/2490e3acec397abeb88807db52cac59102d5ed758feee6df6112ab3ccd8325e8a1ce8bce6f4b66e5470eca102d31e425ace904242e4fa28dbe0c59c4bafa7b2c + checksum: 10c0/f729219bc735edb621fa30e6e84e60ee5d00802b8247aac0d7b79b0bd6d4b3294737a337b93b86a0bd9e68099d031858a39260c976dc14cdbba238ba1f8779ac languageName: node linkType: hard @@ -11316,21 +11328,21 @@ __metadata: languageName: node linkType: hard -"jsdom@npm:^25.0.0": - version: 25.0.1 - resolution: "jsdom@npm:25.0.1" +"jsdom@npm:^26.0.0": + version: 26.0.0 + resolution: "jsdom@npm:26.0.0" dependencies: - cssstyle: "npm:^4.1.0" + cssstyle: "npm:^4.2.1" data-urls: "npm:^5.0.0" decimal.js: "npm:^10.4.3" - form-data: "npm:^4.0.0" + form-data: "npm:^4.0.1" html-encoding-sniffer: "npm:^4.0.0" http-proxy-agent: "npm:^7.0.2" - https-proxy-agent: "npm:^7.0.5" + https-proxy-agent: "npm:^7.0.6" is-potential-custom-element-name: "npm:^1.0.1" - nwsapi: "npm:^2.2.12" - parse5: "npm:^7.1.2" - rrweb-cssom: "npm:^0.7.1" + nwsapi: "npm:^2.2.16" + parse5: "npm:^7.2.1" + rrweb-cssom: "npm:^0.8.0" saxes: "npm:^6.0.0" symbol-tree: "npm:^3.2.4" tough-cookie: "npm:^5.0.0" @@ -11338,15 +11350,15 @@ __metadata: webidl-conversions: "npm:^7.0.0" whatwg-encoding: "npm:^3.1.1" whatwg-mimetype: "npm:^4.0.0" - whatwg-url: "npm:^14.0.0" + whatwg-url: "npm:^14.1.0" ws: "npm:^8.18.0" xml-name-validator: "npm:^5.0.0" peerDependencies: - canvas: ^2.11.2 + canvas: ^3.0.0 peerDependenciesMeta: canvas: optional: true - checksum: 10c0/6bda32a6dfe4e37a30568bf51136bdb3ba9c0b72aadd6356280404275a34c9e097c8c25b5eb3c742e602623741e172da977ff456684befd77c9042ed9bf8c2b4 + checksum: 10c0/e48725ba4027edcfc9bca5799eaec72c6561ecffe3675a8ff87fe9c3541ca4ff9f82b4eff5b3d9c527302da0d859b2f60e9364347a5d42b77f5c76c436c569dc languageName: node linkType: hard @@ -11813,6 +11825,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^11.0.2": + version: 11.0.2 + resolution: "lru-cache@npm:11.0.2" + checksum: 10c0/c993b8e06ead0b24b969c1dbb5b301716aed66e320e9014a80012f5febe280b438f28ff50046b2c55ff404e889351ccb332ff91f8dd175a21f5eae80e3fb155f + languageName: node + linkType: hard + "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -12640,10 +12659,10 @@ __metadata: languageName: node linkType: hard -"nwsapi@npm:^2.2.12, nwsapi@npm:^2.2.2": - version: 2.2.12 - resolution: "nwsapi@npm:2.2.12" - checksum: 10c0/95e9623d63df111405503df8c5d800e26f71675d319e2c9c70cddfa31e5ace1d3f8b6d98d354544fc156a1506d920ec291e303fab761e4f99296868e199a466e +"nwsapi@npm:^2.2.16, nwsapi@npm:^2.2.2": + version: 2.2.16 + resolution: "nwsapi@npm:2.2.16" + checksum: 10c0/0aa0637f4d51043d0183d994e08336bae996b03b42984381bf09ebdf3ff4909c018eda6b2a8aba0a08f3ea8303db8a0dad0608b38dc0bff15fd87017286ae21a languageName: node linkType: hard @@ -13040,12 +13059,12 @@ __metadata: languageName: node linkType: hard -"parse5@npm:^7.0.0, parse5@npm:^7.1.1, parse5@npm:^7.1.2": - version: 7.1.2 - resolution: "parse5@npm:7.1.2" +"parse5@npm:^7.0.0, parse5@npm:^7.1.1, parse5@npm:^7.2.1": + version: 7.2.1 + resolution: "parse5@npm:7.2.1" dependencies: - entities: "npm:^4.4.0" - checksum: 10c0/297d7af8224f4b5cb7f6617ecdae98eeaed7f8cbd78956c42785e230505d5a4f07cef352af10d3006fa5c1544b76b57784d3a22d861ae071bbc460c649482bf4 + entities: "npm:^4.5.0" + checksum: 10c0/829d37a0c709215a887e410a7118d754f8e1afd7edb529db95bc7bbf8045fb0266a7b67801331d8e8d9d073ea75793624ec27ce9ff3b96862c3b9008f4d68e80 languageName: node linkType: hard @@ -15590,10 +15609,10 @@ __metadata: languageName: node linkType: hard -"rrweb-cssom@npm:^0.7.1": - version: 0.7.1 - resolution: "rrweb-cssom@npm:0.7.1" - checksum: 10c0/127b8ca6c8aac45e2755abbae6138d4a813b1bedc2caabf79466ae83ab3cfc84b5bfab513b7033f0aa4561c7753edf787d0dd01163ceacdee2e8eb1b6bf7237e +"rrweb-cssom@npm:^0.8.0": + version: 0.8.0 + resolution: "rrweb-cssom@npm:0.8.0" + checksum: 10c0/56f2bfd56733adb92c0b56e274c43f864b8dd48784d6fe946ef5ff8d438234015e59ad837fc2ad54714b6421384141c1add4eb569e72054e350d1f8a50b8ac7b languageName: node linkType: hard @@ -18334,13 +18353,13 @@ __metadata: languageName: node linkType: hard -"whatwg-url@npm:^14.0.0": - version: 14.0.0 - resolution: "whatwg-url@npm:14.0.0" +"whatwg-url@npm:^14.0.0, whatwg-url@npm:^14.1.0": + version: 14.1.0 + resolution: "whatwg-url@npm:14.1.0" dependencies: tr46: "npm:^5.0.0" webidl-conversions: "npm:^7.0.0" - checksum: 10c0/ac32e9ba9d08744605519bbe9e1371174d36229689ecc099157b6ba102d4251a95e81d81f3d80271eb8da182eccfa65653f07f0ab43ea66a6934e643fd091ba9 + checksum: 10c0/f00104f1c67ce086ba8ffedab529cbbd9aefd8c0a6555320026de7aeff31f91c38680f95818b140a7c9cc657cde3781e567835dda552ddb1e2b8faaba0ac3cb6 languageName: node linkType: hard From 51a92427cea51064debe59abe70c48a39fac41e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:04:14 +0100 Subject: [PATCH 46/64] Update dependency react-intl to v7 (#32954) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 128 ++++++++------------------------------------------- 2 files changed, 21 insertions(+), 109 deletions(-) diff --git a/package.json b/package.json index a4817816a2..6cb314db34 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "react-hotkeys": "^1.1.4", "react-immutable-proptypes": "^2.2.0", "react-immutable-pure-component": "^2.2.2", - "react-intl": "^6.4.2", + "react-intl": "^7.0.0", "react-motion": "^0.5.2", "react-notification": "^6.8.5", "react-overlays": "^5.2.1", diff --git a/yarn.lock b/yarn.lock index 3136b05aa5..e708282d87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2280,17 +2280,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:2.2.4": - version: 2.2.4 - resolution: "@formatjs/ecma402-abstract@npm:2.2.4" - dependencies: - "@formatjs/fast-memoize": "npm:2.2.3" - "@formatjs/intl-localematcher": "npm:0.5.8" - tslib: "npm:2" - checksum: 10c0/3f262533fa704ea7a1a7a8107deee2609774a242c621f8cb5dd4bf4c97abf2fc12f5aeda3f4ce85be18147c484a0ca87303dca6abef53290717e685c55eabd2d - languageName: node - linkType: hard - "@formatjs/ecma402-abstract@npm:2.3.2": version: 2.3.2 resolution: "@formatjs/ecma402-abstract@npm:2.3.2" @@ -2312,15 +2301,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/fast-memoize@npm:2.2.3": - version: 2.2.3 - resolution: "@formatjs/fast-memoize@npm:2.2.3" - dependencies: - tslib: "npm:2" - checksum: 10c0/f1004c3b280de7e362bd37c5f48ff34c2ba1d6271d4a7b695fed561d1201a3379397824d8bffbf15fecee344d1e70398393bbb04297f242692310a305f12e75b - languageName: node - linkType: hard - "@formatjs/fast-memoize@npm:2.2.6": version: 2.2.6 resolution: "@formatjs/fast-memoize@npm:2.2.6" @@ -2341,17 +2321,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-messageformat-parser@npm:2.9.4": - version: 2.9.4 - resolution: "@formatjs/icu-messageformat-parser@npm:2.9.4" - dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.4" - "@formatjs/icu-skeleton-parser": "npm:1.8.8" - tslib: "npm:2" - checksum: 10c0/f1ed14ece7ef0abc9fb62e323b78c994fc772d346801ad5aaa9555e1a7d5c0fda791345f4f2e53a3223f0b82c1a4eaf9a83544c1c20cb39349d1a39bedcf1648 - languageName: node - linkType: hard - "@formatjs/icu-messageformat-parser@npm:2.9.8": version: 2.9.8 resolution: "@formatjs/icu-messageformat-parser@npm:2.9.8" @@ -2383,38 +2352,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-skeleton-parser@npm:1.8.8": - version: 1.8.8 - resolution: "@formatjs/icu-skeleton-parser@npm:1.8.8" - dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.4" - tslib: "npm:2" - checksum: 10c0/5ad78a5682e83b973e6fed4fca68660b944c41d1e941f0c84d69ff3d10ae835330062dc0a2cf0d237d2675ad3463405061a3963c14c2b9d8d1c1911f892b1a8d - languageName: node - linkType: hard - -"@formatjs/intl-displaynames@npm:6.8.5": - version: 6.8.5 - resolution: "@formatjs/intl-displaynames@npm:6.8.5" - dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.4" - "@formatjs/intl-localematcher": "npm:0.5.8" - tslib: "npm:2" - checksum: 10c0/1092d6bac9ba7ee22470b85c9af16802244aa8a54f07e6cd560d15b96e8a08fc359f20dee88a064fe4c9ca8860f439abb109cbb7977b9ccceb846e28aacdf29c - languageName: node - linkType: hard - -"@formatjs/intl-listformat@npm:7.7.5": - version: 7.7.5 - resolution: "@formatjs/intl-listformat@npm:7.7.5" - dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.4" - "@formatjs/intl-localematcher": "npm:0.5.8" - tslib: "npm:2" - checksum: 10c0/f514397f6b05ac29171fffbbd15636fbec086080058c79c159f24edd2038747c22579d46ebf339cbb672f8505ea408e5d960d6751064c16e02d18445cf4e7e61 - languageName: node - linkType: hard - "@formatjs/intl-localematcher@npm:0.5.10": version: 0.5.10 resolution: "@formatjs/intl-localematcher@npm:0.5.10" @@ -2433,15 +2370,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-localematcher@npm:0.5.8": - version: 0.5.8 - resolution: "@formatjs/intl-localematcher@npm:0.5.8" - dependencies: - tslib: "npm:2" - checksum: 10c0/7a660263986326b662d4cb537e8386331c34fda61fb830b105e6c62d49be58ace40728dae614883b27a41cec7b1df8b44f72f79e16e6028bfca65d398dc04f3b - languageName: node - linkType: hard - "@formatjs/intl-pluralrules@npm:^5.2.2": version: 5.4.2 resolution: "@formatjs/intl-pluralrules@npm:5.4.2" @@ -2454,23 +2382,21 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl@npm:2.10.15": - version: 2.10.15 - resolution: "@formatjs/intl@npm:2.10.15" +"@formatjs/intl@npm:3.1.0": + version: 3.1.0 + resolution: "@formatjs/intl@npm:3.1.0" dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.4" - "@formatjs/fast-memoize": "npm:2.2.3" - "@formatjs/icu-messageformat-parser": "npm:2.9.4" - "@formatjs/intl-displaynames": "npm:6.8.5" - "@formatjs/intl-listformat": "npm:7.7.5" - intl-messageformat: "npm:10.7.7" + "@formatjs/ecma402-abstract": "npm:2.3.2" + "@formatjs/fast-memoize": "npm:2.2.6" + "@formatjs/icu-messageformat-parser": "npm:2.9.8" + intl-messageformat: "npm:10.7.11" tslib: "npm:2" peerDependencies: - typescript: ^4.7 || 5 + typescript: 5 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/5d51fd0785d5547f375991d7df2d6303479b0083eeb35c42c30c9633aab77101895498f1eace419fd34fdb5c84aea19037c5280c3a9d85f9c3ffe6eef76b6f39 + checksum: 10c0/a073768fffc51696eb7bd25fe1f0afdda1a0e38db3e2dd9b2fc3138ea799f00ef522f3d3083626ad3acbf913593254cfd728a6c6b08ef4f167dd132626a7e9fc languageName: node linkType: hard @@ -3004,7 +2930,7 @@ __metadata: react-hotkeys: "npm:^1.1.4" react-immutable-proptypes: "npm:^2.2.0" react-immutable-pure-component: "npm:^2.2.2" - react-intl: "npm:^6.4.2" + react-intl: "npm:^7.0.0" react-motion: "npm:^0.5.2" react-notification: "npm:^6.8.5" react-overlays: "npm:^5.2.1" @@ -9982,19 +9908,7 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:10.7.7": - version: 10.7.7 - resolution: "intl-messageformat@npm:10.7.7" - dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.4" - "@formatjs/fast-memoize": "npm:2.2.3" - "@formatjs/icu-messageformat-parser": "npm:2.9.4" - tslib: "npm:2" - checksum: 10c0/691895fb6a73a2feb2569658706e0d452861441de184dd1c9201e458a39fb80fc80080dd40d3d370400a52663f87de7a6d5a263c94245492f7265dd760441a95 - languageName: node - linkType: hard - -"intl-messageformat@npm:^10.3.5": +"intl-messageformat@npm:10.7.11, intl-messageformat@npm:^10.3.5": version: 10.7.11 resolution: "intl-messageformat@npm:10.7.11" dependencies: @@ -14744,27 +14658,25 @@ __metadata: languageName: node linkType: hard -"react-intl@npm:^6.4.2": - version: 6.8.9 - resolution: "react-intl@npm:6.8.9" +"react-intl@npm:^7.0.0": + version: 7.1.0 + resolution: "react-intl@npm:7.1.0" dependencies: - "@formatjs/ecma402-abstract": "npm:2.2.4" - "@formatjs/icu-messageformat-parser": "npm:2.9.4" - "@formatjs/intl": "npm:2.10.15" - "@formatjs/intl-displaynames": "npm:6.8.5" - "@formatjs/intl-listformat": "npm:7.7.5" + "@formatjs/ecma402-abstract": "npm:2.3.2" + "@formatjs/icu-messageformat-parser": "npm:2.9.8" + "@formatjs/intl": "npm:3.1.0" "@types/hoist-non-react-statics": "npm:3" "@types/react": "npm:16 || 17 || 18" hoist-non-react-statics: "npm:3" - intl-messageformat: "npm:10.7.7" + intl-messageformat: "npm:10.7.11" tslib: "npm:2" peerDependencies: react: ^16.6.0 || 17 || 18 - typescript: ^4.7 || 5 + typescript: 5 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/d42a6252beac5448b4a248d84923b0f75dfbbee6208cd5c49ac2f525714ab94efe2a4933d464c64cb161ddccaa37b83dffb2dd0529428219b8a60ce548da3e57 + checksum: 10c0/9d69e316a5f5c6d31fa77f136b595079db2f75f63398cf8253d407878246dd5bcf0cc2eb4d7d4aa0646530ee58b16ce9a8c3876a5c2f0dc38fdda7e4f8c07615 languageName: node linkType: hard From 91c75a63616e8a8616cc09484e033bab2780a925 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 9 Jan 2025 14:38:23 +0100 Subject: [PATCH 47/64] Re-introduce `application_id` in `ScheduledStatusSerializer` (#33505) --- app/serializers/rest/scheduled_status_serializer.rb | 4 ---- spec/serializers/rest/scheduled_status_serializer_spec.rb | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/serializers/rest/scheduled_status_serializer.rb b/app/serializers/rest/scheduled_status_serializer.rb index 8aa0d89386..7c54f39c0d 100644 --- a/app/serializers/rest/scheduled_status_serializer.rb +++ b/app/serializers/rest/scheduled_status_serializer.rb @@ -8,8 +8,4 @@ class REST::ScheduledStatusSerializer < ActiveModel::Serializer def id object.id.to_s end - - def params - object.params.without('application_id') - end end diff --git a/spec/serializers/rest/scheduled_status_serializer_spec.rb b/spec/serializers/rest/scheduled_status_serializer_spec.rb index 08ad8a6f8a..2cf0098654 100644 --- a/spec/serializers/rest/scheduled_status_serializer_spec.rb +++ b/spec/serializers/rest/scheduled_status_serializer_spec.rb @@ -17,7 +17,7 @@ RSpec.describe REST::ScheduledStatusSerializer do expect(subject.deep_symbolize_keys) .to include( scheduled_at: be_a(String).and(match_api_datetime_format), - params: not_include(:application_id) + params: include(:application_id) ) end end From c6c8e7e6ab03754f6456eaf7bfc26a9a318140dc Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 9 Jan 2025 14:47:12 +0100 Subject: [PATCH 48/64] Fix last paginated notification group only including data on a single notification (#33271) --- .../api/v2/notifications_controller.rb | 23 ++++++++- app/models/notification_group.rb | 26 +++++++--- spec/requests/api/v2/notifications_spec.rb | 49 +++++++++++++++++++ 3 files changed, 89 insertions(+), 9 deletions(-) diff --git a/app/controllers/api/v2/notifications_controller.rb b/app/controllers/api/v2/notifications_controller.rb index c070c0e5e7..cc38b95114 100644 --- a/app/controllers/api/v2/notifications_controller.rb +++ b/app/controllers/api/v2/notifications_controller.rb @@ -80,10 +80,31 @@ class Api::V2::NotificationsController < Api::BaseController return [] if @notifications.empty? MastodonOTELTracer.in_span('Api::V2::NotificationsController#load_grouped_notifications') do - NotificationGroup.from_notifications(@notifications, pagination_range: (@notifications.last.id)..(@notifications.first.id), grouped_types: params[:grouped_types]) + pagination_range = (@notifications.last.id)..@notifications.first.id + + # If the page is incomplete, we know we are on the last page + if incomplete_page? + if paginating_up? + pagination_range = @notifications.last.id...(params[:max_id]&.to_i) + else + range_start = params[:since_id]&.to_i + range_start += 1 unless range_start.nil? + pagination_range = range_start..(@notifications.first.id) + end + end + + NotificationGroup.from_notifications(@notifications, pagination_range: pagination_range, grouped_types: params[:grouped_types]) end end + def incomplete_page? + @notifications.size < limit_param(DEFAULT_NOTIFICATIONS_LIMIT) + end + + def paginating_up? + params[:min_id].present? + end + def browserable_account_notifications current_account.notifications.without_suspended.browserable( types: Array(browserable_params[:types]), diff --git a/app/models/notification_group.rb b/app/models/notification_group.rb index 9331b9406f..bf790bf7cd 100644 --- a/app/models/notification_group.rb +++ b/app/models/notification_group.rb @@ -64,21 +64,31 @@ class NotificationGroup < ActiveModelSerializers::Model binds = [ account_id, SAMPLE_ACCOUNTS_SIZE, - pagination_range.begin, - pagination_range.end, ActiveRecord::Relation::QueryAttribute.new('group_keys', group_keys, ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.new(ActiveModel::Type::String.new)), + pagination_range.begin || 0, ] + binds << pagination_range.end unless pagination_range.end.nil? + + upper_bound_cond = begin + if pagination_range.end.nil? + '' + elsif pagination_range.exclude_end? + 'AND id < $5' + else + 'AND id <= $5' + end + end ActiveRecord::Base.connection.select_all(<<~SQL.squish, 'grouped_notifications', binds).cast_values.to_h { |k, *values| [k, values] } SELECT groups.group_key, - (SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4 ORDER BY id DESC LIMIT 1), - array(SELECT from_account_id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4 ORDER BY id DESC LIMIT $2), - (SELECT count(*) FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4) AS notifications_count, - (SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id >= $3 ORDER BY id ASC LIMIT 1) AS min_id, - (SELECT created_at FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4 ORDER BY id DESC LIMIT 1) + (SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond} ORDER BY id DESC LIMIT 1), + array(SELECT from_account_id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond} ORDER BY id DESC LIMIT $2), + (SELECT count(*) FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond}) AS notifications_count, + (SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id >= $4 ORDER BY id ASC LIMIT 1) AS min_id, + (SELECT created_at FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond} ORDER BY id DESC LIMIT 1) FROM - unnest($5::text[]) AS groups(group_key); + unnest($3::text[]) AS groups(group_key); SQL else binds = [ diff --git a/spec/requests/api/v2/notifications_spec.rb b/spec/requests/api/v2/notifications_spec.rb index ffa0a71c77..aa4a861557 100644 --- a/spec/requests/api/v2/notifications_spec.rb +++ b/spec/requests/api/v2/notifications_spec.rb @@ -143,6 +143,55 @@ RSpec.describe 'Notifications' do end end + context 'when there are numerous notifications for the same final group' do + before do + user.account.notifications.destroy_all + 5.times.each { FavouriteService.new.call(Fabricate(:account), user.account.statuses.first) } + end + + context 'with no options' do + it 'returns a notification group covering all notifications' do + subject + + notification_ids = user.account.notifications.reload.pluck(:id) + + expect(response).to have_http_status(200) + expect(response.content_type) + .to start_with('application/json') + expect(response.parsed_body[:notification_groups]).to contain_exactly( + a_hash_including( + type: 'favourite', + sample_account_ids: have_attributes(size: 5), + page_min_id: notification_ids.first.to_s, + page_max_id: notification_ids.last.to_s + ) + ) + end + end + + context 'with min_id param' do + let(:params) { { min_id: user.account.notifications.reload.first.id - 1 } } + + it 'returns a notification group covering all notifications' do + subject + + notification_ids = user.account.notifications.reload.pluck(:id) + + expect(response).to have_http_status(200) + expect(response.content_type) + .to start_with('application/json') + expect(response.parsed_body[:notification_groups]).to contain_exactly( + a_hash_including( + type: 'favourite', + sample_account_ids: have_attributes(size: 5), + page_min_id: notification_ids.first.to_s, + page_max_id: notification_ids.last.to_s + ) + ) + end + end + end + context 'with no options' do it 'returns expected notification types', :aggregate_failures do subject From a8b2b474d79b9621dfa6309b83a5678f25926cde Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 9 Jan 2025 15:22:33 +0100 Subject: [PATCH 49/64] Add timestamp to all announcements in Web UI (#18329) --- .../components/announcements.jsx | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/features/getting_started/components/announcements.jsx b/app/javascript/mastodon/features/getting_started/components/announcements.jsx index 713ad9f069..ad66d2e5fa 100644 --- a/app/javascript/mastodon/features/getting_started/components/announcements.jsx +++ b/app/javascript/mastodon/features/getting_started/components/announcements.jsx @@ -335,15 +335,29 @@ class Announcement extends ImmutablePureComponent { const endsAt = announcement.get('ends_at') && new Date(announcement.get('ends_at')); const now = new Date(); const hasTimeRange = startsAt && endsAt; - const skipYear = hasTimeRange && startsAt.getFullYear() === endsAt.getFullYear() && endsAt.getFullYear() === now.getFullYear(); - const skipEndDate = hasTimeRange && startsAt.getDate() === endsAt.getDate() && startsAt.getMonth() === endsAt.getMonth() && startsAt.getFullYear() === endsAt.getFullYear(); const skipTime = announcement.get('all_day'); + let timestamp = null; + if (hasTimeRange) { + const skipYear = startsAt.getFullYear() === endsAt.getFullYear() && endsAt.getFullYear() === now.getFullYear(); + const skipEndDate = startsAt.getDate() === endsAt.getDate() && startsAt.getMonth() === endsAt.getMonth() && startsAt.getFullYear() === endsAt.getFullYear(); + timestamp = ( + <> + - + + ); + } else { + const publishedAt = new Date(announcement.get('published_at')); + timestamp = ( + + ); + } + return (
- {hasTimeRange && · - } + · {timestamp} From 9b8d1fb6d171e13f043c05e9311a5de6fb9029b6 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 9 Jan 2025 09:32:48 -0500 Subject: [PATCH 50/64] Add `Account#actor_type_application?` query method (#33525) --- app/models/account.rb | 10 +++++++--- spec/models/account_spec.rb | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/app/models/account.rb b/app/models/account.rb index fefc40869f..7321cff3db 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -107,14 +107,14 @@ class Account < ApplicationRecord validates_with UniqueUsernameValidator, if: -> { will_save_change_to_username? } # Remote user validations, also applies to internal actors - validates :username, format: { with: USERNAME_ONLY_RE }, if: -> { (remote? || actor_type == 'Application') && will_save_change_to_username? } + validates :username, format: { with: USERNAME_ONLY_RE }, if: -> { (remote? || actor_type_application?) && will_save_change_to_username? } # Remote user validations validates :uri, presence: true, unless: :local?, on: :create # Local user validations - validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: USERNAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' } - validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' } + validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: USERNAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_username? && !actor_type_application? } + validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? && !actor_type_application? } validates :display_name, length: { maximum: DISPLAY_NAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_display_name? } validates :note, note_length: { maximum: NOTE_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_note? } validates :fields, length: { maximum: DEFAULT_FIELDS_SIZE }, if: -> { local? && will_save_change_to_fields? } @@ -208,6 +208,10 @@ class Account < ApplicationRecord self.actor_type = ActiveModel::Type::Boolean.new.cast(val) ? 'Service' : 'Person' end + def actor_type_application? + actor_type == 'Application' + end + def group? actor_type == 'Group' end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index f70690ddb6..3e9b36652f 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -80,6 +80,20 @@ RSpec.describe Account do end end + describe '#actor_type_application?' do + context 'when the actor is not of type application' do + subject { Fabricate.build :account, actor_type: 'Person' } + + it { is_expected.to_not be_actor_type_application } + end + + context 'when the actor is of type application' do + subject { Fabricate.build :account, actor_type: 'Application' } + + it { is_expected.to be_actor_type_application } + end + end + describe 'Local domain user methods' do subject { Fabricate(:account, domain: nil, username: 'alice') } From 3a4aed989021f0feeda491972bb73a3263c3255a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 9 Jan 2025 09:39:49 -0500 Subject: [PATCH 51/64] Rename `app/helpers/jsonld_helper.rb` to `app/helpers/json_ld_helper.rb` (#33489) --- .rubocop_todo.yml | 6 +++--- app/helpers/{jsonld_helper.rb => json_ld_helper.rb} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename app/helpers/{jsonld_helper.rb => json_ld_helper.rb} (100%) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 552054898e..12ef0ad620 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --auto-gen-only-exclude --no-offense-counts --no-auto-gen-timestamp` -# using RuboCop version 1.69.1. +# using RuboCop version 1.69.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -8,7 +8,7 @@ Lint/NonLocalExitFromIterator: Exclude: - - 'app/helpers/jsonld_helper.rb' + - 'app/helpers/json_ld_helper.rb' # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. Metrics/AbcSize: @@ -82,7 +82,7 @@ Style/MutableConstant: # AllowedMethods: respond_to_missing? Style/OptionalBooleanParameter: Exclude: - - 'app/helpers/jsonld_helper.rb' + - 'app/helpers/json_ld_helper.rb' - 'app/lib/admin/system_check/message.rb' - 'app/lib/request.rb' - 'app/lib/webfinger.rb' diff --git a/app/helpers/jsonld_helper.rb b/app/helpers/json_ld_helper.rb similarity index 100% rename from app/helpers/jsonld_helper.rb rename to app/helpers/json_ld_helper.rb From 54e20301462b381f27c50ed305abeedde1ace878 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 9 Jan 2025 10:08:39 -0500 Subject: [PATCH 52/64] Add `AccountWarning#appeal_eligible?` method (#33526) --- app/models/account_warning.rb | 5 +++++ app/models/appeal.rb | 4 +--- app/policies/account_warning_policy.rb | 2 +- spec/models/account_warning_spec.rb | 14 ++++++++++++++ spec/models/appeal_spec.rb | 2 +- spec/policies/account_warning_policy_spec.rb | 4 ++-- 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/app/models/account_warning.rb b/app/models/account_warning.rb index 7aa474887b..9058f73fb8 100644 --- a/app/models/account_warning.rb +++ b/app/models/account_warning.rb @@ -27,6 +27,7 @@ class AccountWarning < ApplicationRecord suspend: 4_000, }, suffix: :action + APPEAL_WINDOW = 20.days RECENT_PERIOD = 3.months.freeze normalizes :text, with: ->(text) { text.to_s }, apply_to_nil: true @@ -49,6 +50,10 @@ class AccountWarning < ApplicationRecord overruled_at.present? end + def appeal_eligible? + created_at >= APPEAL_WINDOW.ago + end + def to_log_human_identifier target_account.acct end diff --git a/app/models/appeal.rb b/app/models/appeal.rb index fafa75e69d..6a75fec661 100644 --- a/app/models/appeal.rb +++ b/app/models/appeal.rb @@ -16,8 +16,6 @@ # updated_at :datetime not null # class Appeal < ApplicationRecord - MAX_STRIKE_AGE = 20.days - TEXT_LENGTH_LIMIT = 2_000 belongs_to :account @@ -68,6 +66,6 @@ class Appeal < ApplicationRecord private def validate_time_frame - errors.add(:base, I18n.t('strikes.errors.too_late')) if strike.created_at < MAX_STRIKE_AGE.ago + errors.add(:base, I18n.t('strikes.errors.too_late')) unless strike.appeal_eligible? end end diff --git a/app/policies/account_warning_policy.rb b/app/policies/account_warning_policy.rb index 4f8df7420e..976cae6c9c 100644 --- a/app/policies/account_warning_policy.rb +++ b/app/policies/account_warning_policy.rb @@ -6,7 +6,7 @@ class AccountWarningPolicy < ApplicationPolicy end def appeal? - target? && record.created_at >= Appeal::MAX_STRIKE_AGE.ago + target? && record.appeal_eligible? end private diff --git a/spec/models/account_warning_spec.rb b/spec/models/account_warning_spec.rb index 37866ce3da..9fe2b331eb 100644 --- a/spec/models/account_warning_spec.rb +++ b/spec/models/account_warning_spec.rb @@ -8,4 +8,18 @@ RSpec.describe AccountWarning do it { is_expected.to normalize(:text).from(nil).to('') } end end + + describe '#appeal_eligible?' do + context 'when created too long ago' do + subject { Fabricate.build :account_warning, created_at: (described_class::APPEAL_WINDOW * 2).ago } + + it { is_expected.to_not be_appeal_eligible } + end + + context 'when created recently' do + subject { Fabricate.build :account_warning, created_at: (described_class::APPEAL_WINDOW - 2.days).ago } + + it { is_expected.to be_appeal_eligible } + end + end end diff --git a/spec/models/appeal_spec.rb b/spec/models/appeal_spec.rb index 06775f5dd6..d624e14949 100644 --- a/spec/models/appeal_spec.rb +++ b/spec/models/appeal_spec.rb @@ -9,7 +9,7 @@ RSpec.describe Appeal do it { is_expected.to validate_length_of(:text).is_at_most(described_class::TEXT_LENGTH_LIMIT) } context 'with a strike created too long ago' do - let(:strike) { Fabricate.build :account_warning, created_at: (described_class::MAX_STRIKE_AGE * 2).ago } + let(:strike) { Fabricate.build :account_warning, created_at: (AccountWarning::APPEAL_WINDOW * 2).ago } it { is_expected.to_not allow_values(strike).for(:strike).against(:base).on(:create) } end diff --git a/spec/policies/account_warning_policy_spec.rb b/spec/policies/account_warning_policy_spec.rb index 75142e2071..2603794886 100644 --- a/spec/policies/account_warning_policy_spec.rb +++ b/spec/policies/account_warning_policy_spec.rb @@ -31,11 +31,11 @@ RSpec.describe AccountWarningPolicy do context 'when account is target' do context 'when record is appealable' do - it { is_expected.to permit(account, AccountWarning.new(target_account_id: account.id, created_at: Appeal::MAX_STRIKE_AGE.ago + 1.hour)) } + it { is_expected.to permit(account, AccountWarning.new(target_account_id: account.id, created_at: AccountWarning::APPEAL_WINDOW.ago + 1.hour)) } end context 'when record is not appealable' do - it { is_expected.to_not permit(account, AccountWarning.new(target_account_id: account.id, created_at: Appeal::MAX_STRIKE_AGE.ago - 1.hour)) } + it { is_expected.to_not permit(account, AccountWarning.new(target_account_id: account.id, created_at: AccountWarning::APPEAL_WINDOW.ago - 1.hour)) } end end end From f98972e4ebbdaf586c3e267bcae35a8922849af3 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 Jan 2025 04:00:31 -0500 Subject: [PATCH 53/64] Use `with_options` for Account `if: :local?` validation group (#33529) --- app/models/account.rb | 10 +++++----- spec/models/account_spec.rb | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/models/account.rb b/app/models/account.rb index 7321cff3db..6258857b1b 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -119,11 +119,11 @@ class Account < ApplicationRecord validates :note, note_length: { maximum: NOTE_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_note? } validates :fields, length: { maximum: DEFAULT_FIELDS_SIZE }, if: -> { local? && will_save_change_to_fields? } validates_with EmptyProfileFieldNamesValidator, if: -> { local? && will_save_change_to_fields? } - with_options on: :create do - validates :uri, absence: true, if: :local? - validates :inbox_url, absence: true, if: :local? - validates :shared_inbox_url, absence: true, if: :local? - validates :followers_url, absence: true, if: :local? + with_options on: :create, if: :local? do + validates :followers_url, absence: true + validates :inbox_url, absence: true + validates :shared_inbox_url, absence: true + validates :uri, absence: true end normalizes :username, with: ->(username) { username.squish } diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 3e9b36652f..5b995b4af6 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -595,6 +595,11 @@ RSpec.describe Account do it { is_expected.to allow_value(fields_empty_name_value).for(:fields) } it { is_expected.to_not allow_values(fields_over_limit, fields_empty_name).for(:fields) } + + it { is_expected.to validate_absence_of(:followers_url).on(:create) } + it { is_expected.to validate_absence_of(:inbox_url).on(:create) } + it { is_expected.to validate_absence_of(:shared_inbox_url).on(:create) } + it { is_expected.to validate_absence_of(:uri).on(:create) } end context 'when account is remote' do From 846c89b66e6300e438df17f3a2d11645cd460851 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 09:00:41 +0000 Subject: [PATCH 54/64] New Crowdin Translations (automated) (#33541) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/hu.json | 2 +- app/javascript/mastodon/locales/pl.json | 3 ++ app/javascript/mastodon/locales/pt-BR.json | 6 ++-- app/javascript/mastodon/locales/pt-PT.json | 4 +-- config/locales/lv.yml | 41 +++++++++++++++++----- config/locales/simple_form.lv.yml | 2 +- config/locales/simple_form.sv.yml | 2 +- 7 files changed, 44 insertions(+), 16 deletions(-) diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 703abf242b..847f7871fa 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -453,7 +453,7 @@ "keyboard_shortcuts.requests": "Követési kérések listájának megnyitása", "keyboard_shortcuts.search": "Fókuszálás a keresősávra", "keyboard_shortcuts.spoilers": "Tartalmi figyelmeztetés mező megjelenítése/elrejtése", - "keyboard_shortcuts.start": "\"Első lépések\" oszlop megnyitása", + "keyboard_shortcuts.start": "„Első lépések” oszlop megnyitása", "keyboard_shortcuts.toggle_hidden": "Tartalmi figyelmeztetéssel ellátott szöveg megjelenítése/elrejtése", "keyboard_shortcuts.toggle_sensitivity": "Média megjelenítése/elrejtése", "keyboard_shortcuts.toot": "Új bejegyzés írása", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index fe56267ea1..f9cb9743ac 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -406,6 +406,9 @@ "ignore_notifications_modal.not_followers_title": "Ignoruj powiadomienia od użytkowników którzy cię nie obserwują?", "ignore_notifications_modal.not_following_title": "Ignoruj powiadomienia od użytkowników których nie obserwujesz?", "ignore_notifications_modal.private_mentions_title": "Ignoruj powiadomienia o nieproszonych wzmiankach prywatnych?", + "interaction_modal.action.favourite": "Aby kontynuować, musisz dodać do ulubionych na swoim koncie.", + "interaction_modal.action.follow": "Aby kontynuować, musisz obserwować ze swojego konta.", + "interaction_modal.no_account_yet": "Nie masz jeszcze konta?", "interaction_modal.on_another_server": "Na innym serwerze", "interaction_modal.on_this_server": "Na tym serwerze", "interaction_modal.title.favourite": "Polub wpis użytkownika {name}", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 1505d333ba..142ae33c58 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -243,12 +243,12 @@ "dismissable_banner.explore_statuses": "Estas publicações através do fediverse estão ganhando atenção hoje. Publicações mais recentes com mais boosts e favoritos são classificados mais altamente.", "dismissable_banner.explore_tags": "Estas hashtags estão ganhando atenção hoje no fediverse. Hashtags usadas por muitas pessoas diferentes são classificadas mais altamente.", "dismissable_banner.public_timeline": "Estas são as publicações mais recentes das pessoas no fediverse que as pessoas do {domain} seguem.", - "domain_block_modal.block": "Servidor de blocos.", - "domain_block_modal.block_account_instead": "Bloco @(nome)", + "domain_block_modal.block": "Bloquear servidor", + "domain_block_modal.block_account_instead": "Bloquear @{name}", "domain_block_modal.they_can_interact_with_old_posts": "Pessoas deste servidor podem interagir com suas publicações antigas.", "domain_block_modal.they_cant_follow": "Ninguém deste servidor pode lhe seguir.", "domain_block_modal.they_wont_know": "Eles não saberão que foram bloqueados.", - "domain_block_modal.title": "Dominio do bloco", + "domain_block_modal.title": "Bloquear domínio?", "domain_block_modal.you_will_lose_num_followers": "Você perderá {followersCount, plural, one {{followersCountDisplay} seguidor} other {{followersCountDisplay} seguidores}} e {followingCount, plural, one {{followingCountDisplay} pessoa que você segue} other {{followingCountDisplay} pessoas que você segue}}.", "domain_block_modal.you_will_lose_relationships": "Você irá perder todos os seguidores e pessoas que você segue neste servidor.", "domain_block_modal.you_wont_see_posts": "Você não verá postagens ou notificações de usuários neste servidor.", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index b4b3c40dc5..f7329ad97e 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -244,7 +244,7 @@ "dismissable_banner.explore_tags": "Estas etiquetas estão a ganhar força no fediverso atualmente. As etiquetas que são utilizadas por mais pessoas diferentes são classificadas numa posição mais elevada.", "dismissable_banner.public_timeline": "Estas são as publicações públicas mais recentes de pessoas no fediverso que as pessoas em {domain} seguem.", "domain_block_modal.block": "Bloquear servidor", - "domain_block_modal.block_account_instead": "Bloquear antes @{name}", + "domain_block_modal.block_account_instead": "Em vez disso, bloquear @{name}", "domain_block_modal.they_can_interact_with_old_posts": "As pessoas deste servidor podem interagir com as tuas publicações antigas.", "domain_block_modal.they_cant_follow": "Ninguém deste servidor pode seguir-te.", "domain_block_modal.they_wont_know": "Eles não saberão que foram bloqueados.", @@ -260,7 +260,7 @@ "domain_pill.their_username": "O identificador único dele no seu servidor. É possível encontrar utilizadores com o mesmo nome de utilizador em servidores diferentes.", "domain_pill.username": "Nome de utilizador", "domain_pill.whats_in_a_handle": "Em que consiste um identificador?", - "domain_pill.who_they_are": "Uma vez que os identificadores dizem quem é alguém e onde está, pode interagir com as pessoas através da rede social de .", + "domain_pill.who_they_are": "Uma vez que os identificadores dizem quem é alguém e onde está, podes interagir com as pessoas através da rede social de .", "domain_pill.who_you_are": "Uma vez que o teu identificador indica quem és e onde estás, as pessoas podem interagir contigo através da rede social de .", "domain_pill.your_handle": "O teu identificador:", "domain_pill.your_server": "A tua casa digital, onde se encontram todas as tuas publicações. Não gostas deste? Muda de servidor a qualquer momento e leva também os teus seguidores.", diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 09b629c4da..2d256b475e 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -217,7 +217,7 @@ lv: enable_user: Ieslēgt Lietotāju memorialize_account: Saglabāt Kontu Piemiņai promote_user: Izceltt Lietotāju - publish_terms_of_service: Publicēt pakalpojuma izmantošanas nosacījumus + publish_terms_of_service: Publicēt pakalpojuma izmantošanas noteikumus reject_appeal: Noraidīt Apelāciju reject_user: Noraidīt lietotāju remove_avatar_user: Noņemt profila attēlu @@ -274,7 +274,7 @@ lv: enable_user_html: "%{name} iespējoja pieteikšanos lietotājam %{target}" memorialize_account_html: "%{name} pārvērta %{target} kontu par atmiņas lapu" promote_user_html: "%{name} paaugstināja lietotāju %{target}" - publish_terms_of_service_html: "%{name} padarīja pieejamus pakalpojuma izmantošanas nosacījumu atjauninājumus" + publish_terms_of_service_html: "%{name} padarīja pieejamus pakalpojuma izmantošanas noteikumu atjauninājumus" reject_appeal_html: "%{name} noraidīja satura pārraudzības lēmuma iebildumu no %{target}" reject_user_html: "%{name} noraidīja reģistrēšanos no %{target}" remove_avatar_user_html: "%{name} noņēma %{target} profila attēlu" @@ -748,9 +748,9 @@ lv: rules: add_new: Pievienot noteikumu delete: Dzēst - description_html: Kaut arī lielākā daļa apgalvo, ka ir lasījuši un piekrīt pakalpojuma izmantošanas nosacījumiem, parasti cilvēki tos neizlasa, līdz rodas sarežģījumi. Padari vienkāršāku sava servera noteikumu pārskatīšanu, sniedzot tos vienkāršā uzsvēruma punktu sarakstā! Jāmēģina atsevišķus noteikumus veidot īsus un vienkāršus, bet jāmēģina arī tos nesadalīt daudzos atsevišķos vienumos. + description_html: Kaut arī lielākā daļa apgalvo, ka ir lasījuši un piekrīt pakalpojuma izmantošanas noteikumiem, parasti cilvēki tos neizlasa, līdz rodas sarežģījumi. Padari vienkāršāku sava servera noteikumu pārskatīšanu, sniedzot tos vienkāršā uzsvēruma punktu sarakstā! Jāmēģina atsevišķus noteikumus veidot īsus un vienkāršus, bet jāmēģina arī tos nesadalīt daudzos atsevišķos vienumos. edit: Labot nosacījumu - empty: Servera noteikumi vēl nav definēti. + empty: Vēl nav pievienots neviens servera noteikums. title: Servera noteikumi settings: about: @@ -921,7 +921,7 @@ lv: title: Tēmturi updated_msg: Tēmtura iestatījumi ir veiksmīgi atjaunināti terms_of_service: - back: Atpakaļ uz pakalpojuma izmantošanas nosacījumiem + back: Atpakaļ uz pakalpojuma izmantošanas noteikumiem changelog: Kas ir mainījies create: Izmantot savus current: Pašreizējie @@ -929,9 +929,27 @@ lv: generate: Izmantot sagatavi generates: action: Izveidot + chance_to_review_html: "Izveidotie pakalpojuma izmantošanas noteikumi netiks automātiski publicēti. Būs iespēja izskatīt iznākumu. Lūgums norādīt nepieciešamo informāciju, lai turpinātu." + explanation_html: Pakalpojuma izmantošanas noteikumu sagatave tiek piedāvāta tikai izzināšanas nolūkam, un to nevajadzētu izmantot kā juridisku padomu jebkurā jautājumā. Lūgums sazināties ar savu juridisko padomdevēju par saviem apstākļiem un noteiktiem juridiskiem jautājumiem. + title: Pakalpojuma izmantošānas noteikumu uzstādīšana history: Vēsture + live: Darbībā + no_history: Nav ierakstu par pakalpojuma izmantošanas noteikumu izmaiņām. + no_terms_of_service_html: Pašlaik nav uzstādīti pakalpojuma izmantošanas noteikumi. Tie ir paredzēti, lai sniegtu skaidrību un aizsargātu no iespējamas atbildības strīdos ar lietotājiem. + notified_on_html: Lietotājiem paziņots %{date} + notify_users: Paziņot lietotājiem + preview: + explanation_html: 'E-pasta ziņojums tiks nosūtīts %{display_count} lietotājiem, kuri ir reģistrējušies pirms %{date}. Šis teksts tiks iekļauts e-pasta ziņojumā:' + send_preview: Nosūtīt priekšskatījumu uz %{email} + send_to_all: + one: Nosūtīt %{display_count} e-pasta ziņojumu + other: Nosūtīt %{display_count} e-pasta ziņojumus + zero: Nosūtīt %{display_count} e-pasta ziņojumu + title: Priekškatīt pakalpojuma izmantošanas noteikumu paziņojumu publish: Publicēt - published_on_html: Publicēts %{date} + published_on_html: Publicēti %{date} + save_draft: Saglabāt melnrakstu + title: Pakalpojuma izmantošanas noteikumi title: Pārvaldība trends: allow: Atļaut @@ -1172,6 +1190,7 @@ lv: view_strikes: Skati iepriekšējos brīdinājumus par savu kontu too_fast: Veidlapa ir iesniegta pārāk ātri, mēģini vēlreiz. use_security_key: Lietot drošības atslēgu + user_agreement_html: Es esmu izlasījis un piekrītu pakalpojuma izmantošanas noteikumiem un privātuma nosacījumiem author_attribution: example_title: Parauga teksts more_from_html: Vairāk no %{name} @@ -1792,6 +1811,8 @@ lv: too_late: Brīdinājuma apstrīdēšanas laiks ir nokavēts tags: does_not_match_previous_name: nesakrīt ar iepriekšējo nosaukumu + terms_of_service: + title: Pakalpojuma izmantošanas noteikumi themes: contrast: Mastodon (Augsts kontrasts) default: Mastodon (Tumšs) @@ -1842,9 +1863,13 @@ lv: subject: Tavam kontam ir piekļūts no jaunas IP adreses title: Jauna pieteikšanās terms_of_service_changed: + agreement: Ar %{domain} izmantošanas tuprināšanu tiek piekrists šiem noteikumiem. Ja ir iebildumi pret atjauninātajiem noteikumiem, savu piekrišanu var atcelt jebkurā laikā ar sava konta izdzēšanu. + changelog: 'Šeit īsumā ir aprakstīts, ko šis atjauninājums nozīmē:' + description: 'Šis e-pasta ziņojums tika saņemts, jo mēs veicam dažas izmaiņas savos pakalpojuma izmantošanas noteikumos %{domain}. Mēs aicinām pārskatīt pilnus atjauninātos noteikumus šeit:' + description_html: Šis e-pasta ziņojums tika saņemts, jo mēs veicam dažas izmaiņas savos pakalpojuma izmantošanas noteikumos %{domain}. Mēs aicinām pārskatīt pilnus atjauninātos noteikumus šeit. sign_off: "%{domain} komanda" - subject: Mūsu pakalpojuma izmantošanas nosacījumu atjauninājumi - subtitle: Mainās %{domain} pakalpojuma izmantošanas nosacījumi + subject: Mūsu pakalpojuma izmantošanas noteikumu atjauninājumi + subtitle: Mainās %{domain} pakalpojuma izmantošanas noteikumi title: Svarīgs atjauninājums warning: appeal: Iesniegt apelāciju diff --git a/config/locales/simple_form.lv.yml b/config/locales/simple_form.lv.yml index 53224966f1..7c7b11c1b3 100644 --- a/config/locales/simple_form.lv.yml +++ b/config/locales/simple_form.lv.yml @@ -53,7 +53,7 @@ lv: locale: Lietotāja saskarnes, e-pasta ziņojumu un push paziņojumu valoda password: Izmanto vismaz 8 rakstzīmes phrase: Tiks saskaņots neatkarīgi no ziņas teksta reģistra vai satura brīdinājuma - scopes: Kuriem API lietojumprogrammai būs atļauta piekļuve. Ja izvēlies augstākā līmeņa tvērumu, tev nav jāatlasa atsevišķi vienumi. + scopes: Kuriem API lietotnei būs ļauts piekļūt. Ja atlasa augstākā līmeņa tvērumu, nav nepieciešamas atlasīt atsevišķus. setting_aggregate_reblogs: Nerādīt jaunus izcēlumus ziņām, kas nesen tika palielinātas (ietekmē tikai nesen saņemtos palielinājumus) setting_always_send_emails: Parasti e-pasta paziņojumi netiek sūtīti, kad aktīvi izmantojat Mastodon setting_default_sensitive: Sensitīva multivide pēc noklusējuma ir paslēpti, un tos var atklāt, noklikšķinot diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml index 421d360fac..2d2c1c0060 100644 --- a/config/locales/simple_form.sv.yml +++ b/config/locales/simple_form.sv.yml @@ -159,7 +159,7 @@ sv: name: Etikett value: Innehåll indexable: Inkludera offentliga inlägg i sökresultaten - show_collections: Göm följare och följeslagare på profilen + show_collections: Visa följare och följeslagare på profilen unlocked: Godkänn nya följare automatiskt account_alias: acct: Namnet på det gamla kontot From 4fb3dc0363956a1a61613e90e9a4e7e945a7f714 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 Jan 2025 04:02:48 -0500 Subject: [PATCH 55/64] Extract `CSS_COLORS` constant for `UserRole` regex validation (#33532) --- app/models/user_role.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/user_role.rb b/app/models/user_role.rb index 24cd5983f3..d567bf5eca 100644 --- a/app/models/user_role.rb +++ b/app/models/user_role.rb @@ -42,6 +42,7 @@ class UserRole < ApplicationRecord NOBODY_POSITION = -1 POSITION_LIMIT = (2**31) - 1 + CSS_COLORS = /\A#?(?:[A-F0-9]{3}){1,2}\z/i # CSS-style hex colors module Flags NONE = 0 @@ -90,7 +91,7 @@ class UserRole < ApplicationRecord attr_writer :current_account validates :name, presence: true, unless: :everyone? - validates :color, format: { with: /\A#?(?:[A-F0-9]{3}){1,2}\z/i }, unless: -> { color.blank? } + validates :color, format: { with: CSS_COLORS }, if: :color? validates :position, numericality: { in: (-POSITION_LIMIT..POSITION_LIMIT) } validate :validate_permissions_elevation From 2499cd01db57275d2adc43aba97302fca5cc754f Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 Jan 2025 04:04:23 -0500 Subject: [PATCH 56/64] Add `duplicate_record` helper to maintenance CLI spec (#33536) --- spec/lib/mastodon/cli/maintenance_spec.rb | 59 +++++++++-------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/spec/lib/mastodon/cli/maintenance_spec.rb b/spec/lib/mastodon/cli/maintenance_spec.rb index 6a15677f43..3e8eb9c360 100644 --- a/spec/lib/mastodon/cli/maintenance_spec.rb +++ b/spec/lib/mastodon/cli/maintenance_spec.rb @@ -89,10 +89,8 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :accounts, name: :index_accounts_on_username_and_domain_lower - _remote_account = Fabricate(:account, username: duplicate_account_username, domain: duplicate_account_domain) - _remote_account_dupe = Fabricate.build(:account, username: duplicate_account_username, domain: duplicate_account_domain).save(validate: false) - _local_account = Fabricate(:account, username: duplicate_account_username, domain: nil) - _local_account_dupe = Fabricate.build(:account, username: duplicate_account_username, domain: nil).save(validate: false) + duplicate_record(:account, username: duplicate_account_username, domain: duplicate_account_domain) + duplicate_record(:account, username: duplicate_account_username, domain: nil) end def choose_local_account_to_keep @@ -127,8 +125,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :users, :email - Fabricate(:user, email: duplicate_email) - Fabricate.build(:user, email: duplicate_email).save(validate: false) + duplicate_record(:user, email: duplicate_email) end end @@ -156,8 +153,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :users, :confirmation_token - Fabricate(:user, confirmation_token: duplicate_confirmation_token) - Fabricate.build(:user, confirmation_token: duplicate_confirmation_token).save(validate: false) + duplicate_record(:user, confirmation_token: duplicate_confirmation_token) end end @@ -185,8 +181,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :users, :reset_password_token - Fabricate(:user, reset_password_token: duplicate_reset_password_token) - Fabricate.build(:user, reset_password_token: duplicate_reset_password_token).save(validate: false) + duplicate_record(:user, reset_password_token: duplicate_reset_password_token) end end @@ -214,8 +209,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :account_domain_blocks, [:account_id, :domain] - Fabricate(:account_domain_block, account: account, domain: duplicate_domain) - Fabricate.build(:account_domain_block, account: account, domain: duplicate_domain).save(validate: false) + duplicate_record(:account_domain_block, account: account, domain: duplicate_domain) end end @@ -244,8 +238,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :announcement_reactions, [:account_id, :announcement_id, :name] - Fabricate(:announcement_reaction, account: account, announcement: announcement, name: name) - Fabricate.build(:announcement_reaction, account: account, announcement: announcement, name: name).save(validate: false) + duplicate_record(:announcement_reaction, account: account, announcement: announcement, name: name) end end @@ -272,8 +265,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :conversations, :uri - Fabricate(:conversation, uri: uri) - Fabricate.build(:conversation, uri: uri).save(validate: false) + duplicate_record(:conversation, uri: uri) end end @@ -301,8 +293,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :custom_emojis, [:shortcode, :domain] - Fabricate(:custom_emoji, shortcode: duplicate_shortcode, domain: duplicate_domain) - Fabricate.build(:custom_emoji, shortcode: duplicate_shortcode, domain: duplicate_domain).save(validate: false) + duplicate_record(:custom_emoji, shortcode: duplicate_shortcode, domain: duplicate_domain) end end @@ -329,8 +320,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :custom_emoji_categories, :name - Fabricate(:custom_emoji_category, name: duplicate_name) - Fabricate.build(:custom_emoji_category, name: duplicate_name).save(validate: false) + duplicate_record(:custom_emoji_category, name: duplicate_name) end end @@ -357,8 +347,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :domain_allows, :domain - Fabricate(:domain_allow, domain: domain) - Fabricate.build(:domain_allow, domain: domain).save(validate: false) + duplicate_record(:domain_allow, domain: domain) end end @@ -385,8 +374,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :domain_blocks, :domain - Fabricate(:domain_block, domain: domain) - Fabricate.build(:domain_block, domain: domain).save(validate: false) + duplicate_record(:domain_block, domain: domain) end end @@ -413,8 +401,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :email_domain_blocks, :domain - Fabricate(:email_domain_block, domain: domain) - Fabricate.build(:email_domain_block, domain: domain).save(validate: false) + duplicate_record(:email_domain_block, domain: domain) end end @@ -441,8 +428,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :media_attachments, :shortcode - Fabricate(:media_attachment, shortcode: shortcode) - Fabricate.build(:media_attachment, shortcode: shortcode).save(validate: false) + duplicate_record(:media_attachment, shortcode: shortcode) end end @@ -469,8 +455,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :preview_cards, :url - Fabricate(:preview_card, url: url) - Fabricate.build(:preview_card, url: url).save(validate: false) + duplicate_record(:preview_card, url: url) end end @@ -530,8 +515,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :tags, name: 'index_tags_on_name_lower_btree' - Fabricate(:tag, name: name) - Fabricate.build(:tag, name: name).save(validate: false) + duplicate_record(:tag, name: name) end end @@ -558,8 +542,7 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :webauthn_credentials, :external_id - Fabricate(:webauthn_credential, external_id: external_id) - Fabricate.build(:webauthn_credential, external_id: external_id).save(validate: false) + duplicate_record(:webauthn_credential, external_id: external_id) end end @@ -586,11 +569,15 @@ RSpec.describe Mastodon::CLI::Maintenance do def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :webhooks, :url - Fabricate(:webhook, url: url) - Fabricate.build(:webhook, url: url).save(validate: false) + duplicate_record(:webhook, url: url) end end + def duplicate_record(fabricator, options = {}) + Fabricate(fabricator, options) + Fabricate.build(fabricator, options).save(validate: false) + end + def agree_to_backup_warning allow(cli.shell) .to receive(:yes?) From 8d4ca95163588a32412507c3142db5c7f3fb934e Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 Jan 2025 04:10:21 -0500 Subject: [PATCH 57/64] Convert `admin/follow_recommendations` spec controller->system (#33533) --- .../follow_recommendations_controller_spec.rb | 21 ------------------- .../admin/follow_recommendations_spec.rb | 18 ++++++++++++++++ 2 files changed, 18 insertions(+), 21 deletions(-) delete mode 100644 spec/controllers/admin/follow_recommendations_controller_spec.rb create mode 100644 spec/system/admin/follow_recommendations_spec.rb diff --git a/spec/controllers/admin/follow_recommendations_controller_spec.rb b/spec/controllers/admin/follow_recommendations_controller_spec.rb deleted file mode 100644 index 82446cd467..0000000000 --- a/spec/controllers/admin/follow_recommendations_controller_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Admin::FollowRecommendationsController do - render_views - - let(:user) { Fabricate(:admin_user) } - - before do - sign_in user, scope: :user - end - - describe 'GET #show' do - it 'returns http success' do - get :show - - expect(response).to have_http_status(:success) - end - end -end diff --git a/spec/system/admin/follow_recommendations_spec.rb b/spec/system/admin/follow_recommendations_spec.rb new file mode 100644 index 0000000000..141a0f8152 --- /dev/null +++ b/spec/system/admin/follow_recommendations_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Admin Follow Recommendations' do + let(:user) { Fabricate(:admin_user) } + + before { sign_in(user) } + + describe 'Viewing follow recommendations details' do + it 'shows a list of accounts' do + visit admin_follow_recommendations_path + + expect(page) + .to have_content(I18n.t('admin.follow_recommendations.title')) + end + end +end From d155763014b0a78792f0b4b38b5a9783172056a7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 09:10:58 +0000 Subject: [PATCH 58/64] Update dependency react-textarea-autosize to v8.5.7 (#33542) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index e708282d87..1231647d7c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14942,15 +14942,15 @@ __metadata: linkType: hard "react-textarea-autosize@npm:^8.4.1": - version: 8.5.6 - resolution: "react-textarea-autosize@npm:8.5.6" + version: 8.5.7 + resolution: "react-textarea-autosize@npm:8.5.7" dependencies: "@babel/runtime": "npm:^7.20.13" use-composed-ref: "npm:^1.3.0" use-latest: "npm:^1.2.1" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10c0/652d290d316c55a253507ecf65ca27f2162801dace10c715f2241203e81d82e9de6d282095b758b26c6bc9e1af9ca552cab5c3a361b230e5fcf25bec31e1bd25 + checksum: 10c0/ff004797ea28faca442460c42b30042d4c34a140f324eeeddee74508688dbc0f98966d21282c945630655006ad28a87edbcb59e6da7f9e762f4f3042c72f9f24 languageName: node linkType: hard From 1d680f19411120c9cfdf43f5284c5676eb621185 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 09:11:17 +0000 Subject: [PATCH 59/64] Update dependency rubocop to v1.70.0 (#33543) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 36373bd337..cb5e2bbbae 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -709,7 +709,7 @@ GEM rspec-mocks (~> 3.0) sidekiq (>= 5, < 8) rspec-support (3.13.2) - rubocop (1.69.2) + rubocop (1.70.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) From a8b0152bc548b6ac45f55ad0f0670b774a0117a6 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 Jan 2025 04:11:57 -0500 Subject: [PATCH 60/64] Convert `admin/terms_of_service/histories` spec controller->system (#33534) --- .../histories_controller_spec.rb | 21 ------------------- .../admin/terms_of_service/histories_spec.rb | 21 +++++++++++++++++++ 2 files changed, 21 insertions(+), 21 deletions(-) delete mode 100644 spec/controllers/admin/terms_of_service/histories_controller_spec.rb create mode 100644 spec/system/admin/terms_of_service/histories_spec.rb diff --git a/spec/controllers/admin/terms_of_service/histories_controller_spec.rb b/spec/controllers/admin/terms_of_service/histories_controller_spec.rb deleted file mode 100644 index 8c2c3a3de3..0000000000 --- a/spec/controllers/admin/terms_of_service/histories_controller_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Admin::TermsOfService::HistoriesController do - render_views - - let(:user) { Fabricate(:admin_user) } - - before do - sign_in user, scope: :user - end - - describe 'GET #show' do - it 'returns http success' do - get :show - - expect(response).to have_http_status(:success) - end - end -end diff --git a/spec/system/admin/terms_of_service/histories_spec.rb b/spec/system/admin/terms_of_service/histories_spec.rb new file mode 100644 index 0000000000..aa59550d09 --- /dev/null +++ b/spec/system/admin/terms_of_service/histories_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Admin Terms of Service Histories' do + let(:current_user) { Fabricate(:admin_user) } + + before { sign_in(current_user) } + + describe 'Viewing TOS histories' do + before { Fabricate :terms_of_service, changelog: 'The changelog notes from v1 are here' } + + it 'shows previous terms versions' do + visit admin_terms_of_service_history_path + + expect(page) + .to have_content(I18n.t('admin.terms_of_service.history')) + .and have_content(/changelog notes from v1/) + end + end +end From e0f6292492c5fce0c9e48b2c003c733f3d2346d3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 09:12:45 +0000 Subject: [PATCH 61/64] Update dependency uuid to v11.0.5 (#33538) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1231647d7c..0e40cc7221 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17843,11 +17843,11 @@ __metadata: linkType: hard "uuid@npm:^11.0.0": - version: 11.0.4 - resolution: "uuid@npm:11.0.4" + version: 11.0.5 + resolution: "uuid@npm:11.0.5" bin: uuid: dist/esm/bin/uuid - checksum: 10c0/3c13591c4dedaa3741f925e284df5974e3d6e0b1cb0f6f75f98c36f9c01d2a414350364fd067613ef600a21c6973dab0506530d4f499ff878f32a06f84569ead + checksum: 10c0/6f59f0c605e02c14515401084ca124b9cb462b4dcac866916a49862bcf831874508a308588c23a7718269226ad11a92da29b39d761ad2b86e736623e3a33b6e7 languageName: node linkType: hard From 4f6edc75963f4ea4e65a3512f0626b37e83b7dd7 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 Jan 2025 04:33:07 -0500 Subject: [PATCH 62/64] Use `in_order_of` in `trends/*` classes (#33531) --- app/models/trends/links.rb | 4 ++-- app/models/trends/query.rb | 7 +++++++ app/models/trends/statuses.rb | 4 ++-- app/models/trends/tags.rb | 5 +++-- spec/models/trends/links_spec.rb | 30 +++++++++++++++++++++++++++++ spec/models/trends/statuses_spec.rb | 25 ++++++++++++++++++++++++ spec/models/trends/tags_spec.rb | 25 ++++++++++++++++++++++++ 7 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 spec/models/trends/links_spec.rb diff --git a/app/models/trends/links.rb b/app/models/trends/links.rb index 0f3ead43f8..57ad486631 100644 --- a/app/models/trends/links.rb +++ b/app/models/trends/links.rb @@ -16,7 +16,7 @@ class Trends::Links < Trends::Base class Query < Trends::Query def to_arel scope = PreviewCard.joins(:trend).reorder(score: :desc) - scope = scope.reorder(language_order_clause.desc, score: :desc) if preferred_languages.present? + scope = scope.merge(language_order_clause) if preferred_languages.present? scope = scope.merge(PreviewCardTrend.allowed) if @allowed scope = scope.offset(@offset) if @offset.present? scope = scope.limit(@limit) if @limit.present? @@ -26,7 +26,7 @@ class Trends::Links < Trends::Base private def language_order_clause - Arel::Nodes::Case.new.when(PreviewCardTrend.arel_table[:language].in(preferred_languages)).then(1).else(0) + language_order_for(PreviewCardTrend) end end diff --git a/app/models/trends/query.rb b/app/models/trends/query.rb index 590e81f4fd..abed64042e 100644 --- a/app/models/trends/query.rb +++ b/app/models/trends/query.rb @@ -94,6 +94,13 @@ class Trends::Query to_arel.to_a end + def language_order_for(trend_class) + trend_class + .reorder(nil) + .in_order_of(:language, [preferred_languages], filter: false) + .order(score: :desc) + end + def preferred_languages if @account&.chosen_languages.present? @account.chosen_languages diff --git a/app/models/trends/statuses.rb b/app/models/trends/statuses.rb index 1d2f02809b..9c47dd486b 100644 --- a/app/models/trends/statuses.rb +++ b/app/models/trends/statuses.rb @@ -15,7 +15,7 @@ class Trends::Statuses < Trends::Base class Query < Trends::Query def to_arel scope = Status.joins(:trend).reorder(score: :desc) - scope = scope.reorder(language_order_clause.desc, score: :desc) if preferred_languages.present? + scope = scope.merge(language_order_clause) if preferred_languages.present? scope = scope.merge(StatusTrend.allowed) if @allowed scope = scope.not_excluded_by_account(@account).not_domain_blocked_by_account(@account) if @account.present? scope = scope.offset(@offset) if @offset.present? @@ -26,7 +26,7 @@ class Trends::Statuses < Trends::Base private def language_order_clause - Arel::Nodes::Case.new.when(StatusTrend.arel_table[:language].in(preferred_languages)).then(1).else(0) + language_order_for(StatusTrend) end end diff --git a/app/models/trends/tags.rb b/app/models/trends/tags.rb index 18f2a9a949..84e8dde11a 100644 --- a/app/models/trends/tags.rb +++ b/app/models/trends/tags.rb @@ -15,7 +15,8 @@ class Trends::Tags < Trends::Base class Query < Trends::Query def to_arel - scope = Tag.joins(:trend).reorder(language_order_clause.desc, score: :desc) + scope = Tag.joins(:trend).reorder(score: :desc) + scope = scope.merge(language_order_clause) if preferred_languages.present? scope = scope.merge(TagTrend.allowed) if @allowed scope = scope.offset(@offset) if @offset.present? scope = scope.limit(@limit) if @limit.present? @@ -25,7 +26,7 @@ class Trends::Tags < Trends::Base private def language_order_clause - Arel::Nodes::Case.new.when(TagTrend.arel_table[:language].in(preferred_languages)).then(1).else(0) + language_order_for(TagTrend) end end diff --git a/spec/models/trends/links_spec.rb b/spec/models/trends/links_spec.rb new file mode 100644 index 0000000000..b0d41d4613 --- /dev/null +++ b/spec/models/trends/links_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Trends::Links do + describe 'Trends::Links::Query' do + subject { described_class.new.query } + + describe '#records' do + context 'with scored cards' do + let!(:higher_score) { Fabricate :preview_card_trend, score: 10, language: 'en' } + let!(:lower_score) { Fabricate :preview_card_trend, score: 1, language: 'es' } + + it 'returns higher score first' do + expect(subject.records) + .to eq([higher_score.preview_card, lower_score.preview_card]) + end + + context 'with preferred locale' do + before { subject.in_locale!('es') } + + it 'returns in language order' do + expect(subject.records) + .to eq([lower_score.preview_card, higher_score.preview_card]) + end + end + end + end + end +end diff --git a/spec/models/trends/statuses_spec.rb b/spec/models/trends/statuses_spec.rb index 7c30b5b997..abb1535d04 100644 --- a/spec/models/trends/statuses_spec.rb +++ b/spec/models/trends/statuses_spec.rb @@ -45,6 +45,31 @@ RSpec.describe Trends::Statuses do end end + describe 'Trends::Statuses::Query methods' do + subject { described_class.new.query } + + describe '#records' do + context 'with scored cards' do + let!(:higher_score) { Fabricate :status_trend, score: 10, language: 'en' } + let!(:lower_score) { Fabricate :status_trend, score: 1, language: 'es' } + + it 'returns higher score first' do + expect(subject.records) + .to eq([higher_score.status, lower_score.status]) + end + + context 'with preferred locale' do + before { subject.in_locale!('es') } + + it 'returns in language order' do + expect(subject.records) + .to eq([lower_score.status, higher_score.status]) + end + end + end + end + end + describe '#add' do let(:status) { Fabricate(:status) } diff --git a/spec/models/trends/tags_spec.rb b/spec/models/trends/tags_spec.rb index 936b441d92..8f36b4a50d 100644 --- a/spec/models/trends/tags_spec.rb +++ b/spec/models/trends/tags_spec.rb @@ -29,6 +29,31 @@ RSpec.describe Trends::Tags do end end + describe 'Trends::Tags::Query' do + subject { described_class.new.query } + + describe '#records' do + context 'with scored cards' do + let!(:higher_score) { Fabricate :tag_trend, score: 10, language: 'en' } + let!(:lower_score) { Fabricate :tag_trend, score: 1, language: 'es' } + + it 'returns higher score first' do + expect(subject.records) + .to eq([higher_score.tag, lower_score.tag]) + end + + context 'with preferred locale' do + before { subject.in_locale!('es') } + + it 'returns in language order' do + expect(subject.records) + .to eq([lower_score.tag, higher_score.tag]) + end + end + end + end + end + describe '#refresh' do let!(:today) { at_time } let!(:yesterday) { today - 1.day } From 2cfc2a777a01b26a9442fbf9a912790097990a0b Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 Jan 2025 06:59:19 -0500 Subject: [PATCH 63/64] Add `build_object` method for defaults in `AP::Activity::Create` spec (#33537) --- spec/lib/activitypub/activity/create_spec.rb | 375 +++++++------------ 1 file changed, 129 insertions(+), 246 deletions(-) diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index d70456e458..5273b9be15 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -162,12 +162,9 @@ RSpec.describe ActivityPub::Activity::Create do context 'when object publication date is below ISO8601 range' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - published: '-0977-11-03T08:31:22Z', - } + build_object( + published: '-0977-11-03T08:31:22Z' + ) end it 'creates status with a valid creation date', :aggregate_failures do @@ -184,12 +181,9 @@ RSpec.describe ActivityPub::Activity::Create do context 'when object publication date is above ISO8601 range' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - published: '10000-11-03T08:31:22Z', - } + build_object( + published: '10000-11-03T08:31:22Z' + ) end it 'creates status with a valid creation date', :aggregate_failures do @@ -206,13 +200,10 @@ RSpec.describe ActivityPub::Activity::Create do context 'when object has been edited' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( published: '2022-01-22T15:00:00Z', - updated: '2022-01-22T16:00:00Z', - } + updated: '2022-01-22T16:00:00Z' + ) end it 'creates status with appropriate creation and edition dates', :aggregate_failures do @@ -232,13 +223,10 @@ RSpec.describe ActivityPub::Activity::Create do context 'when object has update date equal to creation date' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( published: '2022-01-22T15:00:00Z', - updated: '2022-01-22T15:00:00Z', - } + updated: '2022-01-22T15:00:00Z' + ) end it 'creates status and does not mark it as edited' do @@ -254,11 +242,9 @@ RSpec.describe ActivityPub::Activity::Create do context 'with an unknown object type' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Banana', - content: 'Lorem ipsum', - } + build_object( + type: 'Banana' + ) end it 'does not create a status' do @@ -267,13 +253,7 @@ RSpec.describe ActivityPub::Activity::Create do end context 'with a standalone' do - let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - } - end + let(:object_json) { build_object } it 'creates status' do expect { subject.perform }.to change(sender.statuses, :count).by(1) @@ -296,12 +276,9 @@ RSpec.describe ActivityPub::Activity::Create do context 'when public with explicit public address' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - to: 'https://www.w3.org/ns/activitystreams#Public', - } + build_object( + to: 'https://www.w3.org/ns/activitystreams#Public' + ) end it 'creates status' do @@ -316,12 +293,9 @@ RSpec.describe ActivityPub::Activity::Create do context 'when public with as:Public' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - to: 'as:Public', - } + build_object( + to: 'as:Public' + ) end it 'creates status' do @@ -336,12 +310,9 @@ RSpec.describe ActivityPub::Activity::Create do context 'when public with Public' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - to: 'Public', - } + build_object( + to: 'Public' + ) end it 'creates status' do @@ -356,12 +327,9 @@ RSpec.describe ActivityPub::Activity::Create do context 'when unlisted with explicit public address' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - cc: 'https://www.w3.org/ns/activitystreams#Public', - } + build_object( + cc: 'https://www.w3.org/ns/activitystreams#Public' + ) end it 'creates status' do @@ -376,12 +344,9 @@ RSpec.describe ActivityPub::Activity::Create do context 'when unlisted with as:Public' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - cc: 'as:Public', - } + build_object( + cc: 'as:Public' + ) end it 'creates status' do @@ -396,12 +361,9 @@ RSpec.describe ActivityPub::Activity::Create do context 'when unlisted with Public' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - cc: 'Public', - } + build_object( + cc: 'Public' + ) end it 'creates status' do @@ -416,12 +378,9 @@ RSpec.describe ActivityPub::Activity::Create do context 'when private' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - to: 'http://example.com/followers', - } + build_object( + to: 'http://example.com/followers' + ) end it 'creates status' do @@ -436,16 +395,13 @@ RSpec.describe ActivityPub::Activity::Create do context 'when private with inlined Collection in audience' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( to: { type: 'OrderedCollection', id: 'http://example.com/followers', first: 'http://example.com/followers?page=true', - }, - } + } + ) end it 'creates status' do @@ -462,12 +418,9 @@ RSpec.describe ActivityPub::Activity::Create do let(:recipient) { Fabricate(:account) } let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - to: ActivityPub::TagManager.instance.uri_for(recipient), - } + build_object( + to: ActivityPub::TagManager.instance.uri_for(recipient) + ) end it 'creates status with a silent mention' do @@ -485,16 +438,13 @@ RSpec.describe ActivityPub::Activity::Create do let(:recipient) { Fabricate(:account) } let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( to: ActivityPub::TagManager.instance.uri_for(recipient), tag: { type: 'Mention', href: ActivityPub::TagManager.instance.uri_for(recipient), - }, - } + } + ) end it 'creates status' do @@ -511,12 +461,9 @@ RSpec.describe ActivityPub::Activity::Create do let(:original_status) { Fabricate(:status) } let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - inReplyTo: ActivityPub::TagManager.instance.uri_for(original_status), - } + build_object( + inReplyTo: ActivityPub::TagManager.instance.uri_for(original_status) + ) end it 'creates status' do @@ -536,17 +483,14 @@ RSpec.describe ActivityPub::Activity::Create do let(:recipient) { Fabricate(:account) } let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( tag: [ { type: 'Mention', href: ActivityPub::TagManager.instance.uri_for(recipient), }, - ], - } + ] + ) end it 'creates status' do @@ -561,16 +505,13 @@ RSpec.describe ActivityPub::Activity::Create do context 'with mentions missing href' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( tag: [ { type: 'Mention', }, - ], - } + ] + ) end it 'creates status' do @@ -583,10 +524,7 @@ RSpec.describe ActivityPub::Activity::Create do context 'with media attachments' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( attachment: [ { type: 'Document', @@ -598,8 +536,8 @@ RSpec.describe ActivityPub::Activity::Create do mediaType: 'image/png', url: 'http://example.com/emoji.png', }, - ], - } + ] + ) end it 'creates status with correctly-ordered media attachments' do @@ -615,10 +553,7 @@ RSpec.describe ActivityPub::Activity::Create do context 'with media attachments with long description' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( attachment: [ { type: 'Document', @@ -626,8 +561,8 @@ RSpec.describe ActivityPub::Activity::Create do url: 'http://example.com/attachment.png', name: '*' * MediaAttachment::MAX_DESCRIPTION_LENGTH, }, - ], - } + ] + ) end it 'creates status' do @@ -642,10 +577,7 @@ RSpec.describe ActivityPub::Activity::Create do context 'with media attachments with long description as summary' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( attachment: [ { type: 'Document', @@ -653,8 +585,8 @@ RSpec.describe ActivityPub::Activity::Create do url: 'http://example.com/attachment.png', summary: '*' * MediaAttachment::MAX_DESCRIPTION_LENGTH, }, - ], - } + ] + ) end it 'creates status' do @@ -669,10 +601,7 @@ RSpec.describe ActivityPub::Activity::Create do context 'with media attachments with focal points' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( attachment: [ { type: 'Document', @@ -680,8 +609,8 @@ RSpec.describe ActivityPub::Activity::Create do url: 'http://example.com/attachment.png', focalPoint: [0.5, -0.7], }, - ], - } + ] + ) end it 'creates status' do @@ -696,17 +625,14 @@ RSpec.describe ActivityPub::Activity::Create do context 'with media attachments missing url' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( attachment: [ { type: 'Document', mediaType: 'image/png', }, - ], - } + ] + ) end it 'creates status' do @@ -719,18 +645,15 @@ RSpec.describe ActivityPub::Activity::Create do context 'with hashtags' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( tag: [ { type: 'Hashtag', href: 'http://example.com/blah', name: '#test', }, - ], - } + ] + ) end it 'creates status' do @@ -745,10 +668,7 @@ RSpec.describe ActivityPub::Activity::Create do context 'with featured hashtags' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( to: 'https://www.w3.org/ns/activitystreams#Public', tag: [ { @@ -756,8 +676,8 @@ RSpec.describe ActivityPub::Activity::Create do href: 'http://example.com/blah', name: '#test', }, - ], - } + ] + ) end before do @@ -779,17 +699,14 @@ RSpec.describe ActivityPub::Activity::Create do context 'with hashtags missing name' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( tag: [ { type: 'Hashtag', href: 'http://example.com/blah', }, - ], - } + ] + ) end it 'creates status' do @@ -802,18 +719,15 @@ RSpec.describe ActivityPub::Activity::Create do context 'with hashtags invalid name' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( tag: [ { type: 'Hashtag', href: 'http://example.com/blah', name: 'foo, #eh !', }, - ], - } + ] + ) end it 'creates status' do @@ -826,9 +740,7 @@ RSpec.describe ActivityPub::Activity::Create do context 'with emojis' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', + build_object( content: 'Lorem ipsum :tinking:', tag: [ { @@ -838,8 +750,8 @@ RSpec.describe ActivityPub::Activity::Create do }, name: 'tinking', }, - ], - } + ] + ) end it 'creates status' do @@ -854,9 +766,7 @@ RSpec.describe ActivityPub::Activity::Create do context 'with emojis served with invalid content-type' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', + build_object( content: 'Lorem ipsum :tinkong:', tag: [ { @@ -866,8 +776,8 @@ RSpec.describe ActivityPub::Activity::Create do }, name: 'tinkong', }, - ], - } + ] + ) end it 'creates status' do @@ -882,9 +792,7 @@ RSpec.describe ActivityPub::Activity::Create do context 'with emojis missing name' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', + build_object( content: 'Lorem ipsum :tinking:', tag: [ { @@ -893,8 +801,8 @@ RSpec.describe ActivityPub::Activity::Create do url: 'http://example.com/emoji.png', }, }, - ], - } + ] + ) end it 'creates status' do @@ -907,17 +815,15 @@ RSpec.describe ActivityPub::Activity::Create do context 'with emojis missing icon' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', + build_object( content: 'Lorem ipsum :tinking:', tag: [ { type: 'Emoji', name: 'tinking', }, - ], - } + ] + ) end it 'creates status' do @@ -930,8 +836,7 @@ RSpec.describe ActivityPub::Activity::Create do context 'with poll' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, + build_object( type: 'Question', content: 'Which color was the submarine?', oneOf: [ @@ -949,8 +854,8 @@ RSpec.describe ActivityPub::Activity::Create do totalItems: 3, }, }, - ], - } + ] + ) end it 'creates status with a poll' do @@ -973,12 +878,10 @@ RSpec.describe ActivityPub::Activity::Create do let!(:local_status) { Fabricate(:status, poll: poll) } let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', + build_object( name: 'Yellow', - inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status), - } + inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status) + ).except(:content) end it 'adds a vote to the poll with correct uri' do @@ -1000,12 +903,10 @@ RSpec.describe ActivityPub::Activity::Create do let!(:local_status) { Fabricate(:status, poll: poll) } let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', + build_object( name: 'Yellow', - inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status), - } + inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status) + ).except(:content) end it 'does not add a vote to the poll' do @@ -1017,10 +918,7 @@ RSpec.describe ActivityPub::Activity::Create do context 'with counts' do let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', + build_object( likes: { id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar', '/likes'].join, type: 'Collection', @@ -1030,8 +928,8 @@ RSpec.describe ActivityPub::Activity::Create do id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar', '/shares'].join, type: 'Collection', totalItems: 100, - }, - } + } + ) end it 'uses the counts from the created object' do @@ -1060,12 +958,9 @@ RSpec.describe ActivityPub::Activity::Create do end let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - to: 'https://www.w3.org/ns/activitystreams#Public', - } + build_object( + to: 'https://www.w3.org/ns/activitystreams#Public' + ) end before do @@ -1095,13 +990,7 @@ RSpec.describe ActivityPub::Activity::Create do subject.perform end - let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - } - end + let(:object_json) { build_object } it 'creates status' do status = sender.statuses.first @@ -1116,12 +1005,9 @@ RSpec.describe ActivityPub::Activity::Create do let!(:local_status) { Fabricate(:status) } let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status), - } + build_object( + inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status) + ) end before do @@ -1140,13 +1026,11 @@ RSpec.describe ActivityPub::Activity::Create do subject { described_class.new(json, sender, delivery: true) } let!(:local_account) { Fabricate(:account) } + let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - to: ActivityPub::TagManager.instance.uri_for(local_account), - } + build_object( + to: ActivityPub::TagManager.instance.uri_for(local_account) + ) end before do @@ -1166,12 +1050,9 @@ RSpec.describe ActivityPub::Activity::Create do let!(:local_account) { Fabricate(:account) } let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - cc: ActivityPub::TagManager.instance.uri_for(local_account), - } + build_object( + cc: ActivityPub::TagManager.instance.uri_for(local_account) + ) end before do @@ -1193,17 +1074,19 @@ RSpec.describe ActivityPub::Activity::Create do subject.perform end - let(:object_json) do - { - id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, - type: 'Note', - content: 'Lorem ipsum', - } - end + let(:object_json) { build_object } it 'does not create anything' do expect(sender.statuses.count).to eq 0 end end + + def build_object(options = {}) + { + id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, + type: 'Note', + content: 'Lorem ipsum', + }.merge(options) + end end end From 34cd7d6585992c03298c175ab5d22ad059b58cdb Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 10 Jan 2025 10:52:43 -0500 Subject: [PATCH 64/64] Use `config_for` for `Mastodon::Version` metadata/prerelease values (#33548) --- config/mastodon.yml | 3 +++ lib/mastodon/version.rb | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/config/mastodon.yml b/config/mastodon.yml index 2c09c59e0a..e20ba0ab05 100644 --- a/config/mastodon.yml +++ b/config/mastodon.yml @@ -2,3 +2,6 @@ shared: self_destruct_value: <%= ENV.fetch('SELF_DESTRUCT', nil) %> software_update_url: <%= ENV.fetch('UPDATE_CHECK_URL', 'https://api.joinmastodon.org/update-check') %> + version: + metadata: <%= ENV.fetch('MASTODON_VERSION_METADATA', nil) %> + prerelease: <%= ENV.fetch('MASTODON_VERSION_PRERELEASE', nil) %> diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index f132c3a548..ddde4a993d 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -21,11 +21,11 @@ module Mastodon end def prerelease - ENV['MASTODON_VERSION_PRERELEASE'].presence || default_prerelease + version_configuration[:prerelease].presence || default_prerelease end def build_metadata - ENV.fetch('MASTODON_VERSION_METADATA', nil) + version_configuration[:metadata] end def to_a @@ -77,5 +77,9 @@ module Mastodon def user_agent @user_agent ||= "Mastodon/#{Version} (#{HTTP::Request::USER_AGENT}; +http#{Rails.configuration.x.use_https ? 's' : ''}://#{Rails.configuration.x.web_domain}/)" end + + def version_configuration + Rails.configuration.x.mastodon.version + end end end