From da7c9248c6fa95c5031522cc824300dbb62642d9 Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 22 Sep 2023 08:00:03 +0900 Subject: [PATCH 01/69] Remove forwarding http->https from conf file --- dist/nginx-before-certbot.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/dist/nginx-before-certbot.conf b/dist/nginx-before-certbot.conf index 221b949e70..bc8aedfe77 100644 --- a/dist/nginx-before-certbot.conf +++ b/dist/nginx-before-certbot.conf @@ -4,5 +4,4 @@ server { server_name example.com; root /home/mastodon/live/public; location /.well-known/acme-challenge/ { allow all; } - location / { return 301 https://$host$request_uri; } } From 8e1fc0e5eb9be08da78b06bfa1b8b9b23e579f49 Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 22 Sep 2023 08:10:24 +0900 Subject: [PATCH 02/69] Add some description to readme --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5620e7069c..657db86255 100644 --- a/README.md +++ b/README.md @@ -37,16 +37,34 @@ RAILS_ENV=test ES_ENABLED=true RUN_SEARCH_SPECS=true bundle exec rspec spec/sear ## kmyblueの強み +追加の詳細は下記記事もご覧ください。 + +https://note.com/kmycode/n/n5fd5e823ed40 + ### 本家Mastodonへの積極的追従 kmyblueは、いくつかのフォークと異なり、追加機能を控えめにする代わりに本家Mastodonに積極的に追従を行います。バージョン 4 には 4 のよさがありますが、技術的に可能である限り、バージョン 5 へのアップグレードもやぶさかではありません。 kmyblueの追加機能そのままに、Mastodonの新機能も利用できるよう調整を行います。 +### ゆるやかな内輪での運用 + +kmyblueは同人向けサーバーとして出発したため、同人作家に需要のある「内輪ノリを外部にできるだけもらさない」という部分に特化しています。 + +「ローカル公開」という機能によって、「ローカルタイムラインに流すが他のサーバーの連合タイムラインに流さない」投稿が可能です。ただしMisskeyのローカル限定とは異なり、他のサーバーのフォロワーのタイムラインにも投稿は流れます。自分のサーバーの中で内輪で盛り上がって、他のサーバーの連合タイムラインには外面だけの投稿を流すことも可能です。 + +また、通常のMastodonでは公開投稿を他のサーバーの人に自由に検索できるようにすることも可能ですが、kmyblueでは未収載投稿に対して同様の設定が可能です。つまり、ローカルタイムラインにも連合タイムラインにも流れない、誰かの目に自然に触れることはない、でも特定キーワードを使った検索では引っかかりたい、そのような需要に対応できます。 + ### 絵文字リアクション対応 kmyblueは絵文字リアクションに対応しているフォークの1つです。絵文字リアクションは Misskey 標準搭載の機能で、需要が高い機能である割には、サーバーに負荷がかかるため本家Mastodonには搭載されていません。絵文字リアクションによってユーザーは「お気に入り」以上「返信」以下のコミュニケーションを気軽に行うことができ、Mastodonの利用体験が向上します。 各ユーザーが自分の投稿に絵文字リアクションをつけることを拒否できるほか、サーバー全体として絵文字リアクションを無効にする設定も可能です(この場合、他サーバーから来た絵文字リアクションはお気に入りとして保存されます) +### プライバシーへの配慮 + +- **ローカル公開** - ローカルタイムラインにのみ投稿を流し、他サーバーの連合タイムラインに流しません。他のサーバーには未収載として配信されます +- **検索許可** - 投稿ごとに検索を許可する範囲を細かく制御できます。これは本家Mastodonにはない特徴です +- **Misskeyへの投稿配送制限** - Misskeyへ未収載投稿を配送する時、「フォロワーのみ」に変換する設定がユーザー個別に可能です。Misskeyの自由な検索からkmyblue上の投稿を保護します + ## kmyblueのブランチ - **main** - 管理者が本家MastodonにPRするときに使うことがあります @@ -58,7 +76,9 @@ kmyblueは絵文字リアクションに対応しているフォークの1つ ## 本家Mastodonからの追加機能 -kmyblueは、本家Mastodonにいくつかの改造を加えています。以下に示します。 +kmyblueは、本家Mastodonにいくつかの改造を加えています。以下に示します。ただし以下はあくまで一例です。ほぼ完全な一覧は、以下の記事を参照してください。 + +https://note.com/kmycode/n/n5fd5e823ed40 ### ローカル公開 From bb47ff05bc85ca46347ab89f8745ce0d95f72699 Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 22 Sep 2023 08:17:15 +0900 Subject: [PATCH 03/69] Add attention --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 657db86255..887231ea41 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ kmyblueは同人向けサーバーとして出発したため、同人作家に 「ローカル公開」という機能によって、「ローカルタイムラインに流すが他のサーバーの連合タイムラインに流さない」投稿が可能です。ただしMisskeyのローカル限定とは異なり、他のサーバーのフォロワーのタイムラインにも投稿は流れます。自分のサーバーの中で内輪で盛り上がって、他のサーバーの連合タイムラインには外面だけの投稿を流すことも可能です。 -また、通常のMastodonでは公開投稿を他のサーバーの人に自由に検索できるようにすることも可能ですが、kmyblueでは未収載投稿に対して同様の設定が可能です。つまり、ローカルタイムラインにも連合タイムラインにも流れない、誰かの目に自然に触れることはない、でも特定キーワードを使った検索では引っかかりたい、そのような需要に対応できます。 +また、通常のMastodonでは公開投稿を他のサーバーの人に自由に検索できるようにすることも可能ですが、kmyblueでは未収載投稿に対して同様の設定が可能です。つまり、ローカルタイムラインにも連合タイムラインにも流れない、誰かの目に自然に触れることはない、でも特定キーワードを使った検索では引っかかりたい、そのような需要に対応できます。ただしこの検索ができるのはMisskeyならびにkmyblueフォークだけです。 ### 絵文字リアクション対応 From a011d3a7c6f44e744c96f12600bd34435282be7d Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 22 Sep 2023 10:13:09 +0200 Subject: [PATCH 04/69] Ignore CVE-2023-26141 (Sidekiq) from bundler audit (#27037) --- .bundler-audit.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .bundler-audit.yml diff --git a/.bundler-audit.yml b/.bundler-audit.yml new file mode 100644 index 0000000000..a457fc41e8 --- /dev/null +++ b/.bundler-audit.yml @@ -0,0 +1,4 @@ +--- +ignore: + # Sidekiq security issue, fixes in the latest Sidekiq 7 but we can not upgrade. Will be fixed in Sidekiq 6.5.10 + - CVE-2023-26141 From 4aaaf0dde380e79004ad3868d69c4815eccc85f5 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 22 Sep 2023 10:13:53 +0200 Subject: [PATCH 05/69] Fix the search documentation URL in system checks (#27036) --- app/lib/admin/system_check/elasticsearch_check.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/admin/system_check/elasticsearch_check.rb b/app/lib/admin/system_check/elasticsearch_check.rb index c0a1a21e86..406bb5bcb9 100644 --- a/app/lib/admin/system_check/elasticsearch_check.rb +++ b/app/lib/admin/system_check/elasticsearch_check.rb @@ -41,13 +41,13 @@ class Admin::SystemCheck::ElasticsearchCheck < Admin::SystemCheck::BaseCheck elsif cluster_health['status'] == 'red' Admin::SystemCheck::Message.new(:elasticsearch_health_red) elsif cluster_health['number_of_nodes'] < 2 && es_preset != 'single_node_cluster' - Admin::SystemCheck::Message.new(:elasticsearch_preset_single_node, nil, 'https://docs.joinmastodon.org/admin/optional/elasticsearch/#scaling') + Admin::SystemCheck::Message.new(:elasticsearch_preset_single_node, nil, 'https://docs.joinmastodon.org/admin/elasticsearch/#scaling') elsif Chewy.client.indices.get_settings[Chewy::Stash::Specification.index_name]&.dig('settings', 'index', 'number_of_replicas')&.to_i&.positive? && es_preset == 'single_node_cluster' Admin::SystemCheck::Message.new(:elasticsearch_reset_chewy) elsif cluster_health['status'] == 'yellow' Admin::SystemCheck::Message.new(:elasticsearch_health_yellow) else - Admin::SystemCheck::Message.new(:elasticsearch_preset, nil, 'https://docs.joinmastodon.org/admin/optional/elasticsearch/#scaling') + Admin::SystemCheck::Message.new(:elasticsearch_preset, nil, 'https://docs.joinmastodon.org/admin/elasticsearch/#scaling') end rescue Faraday::ConnectionFailed, Elasticsearch::Transport::Transport::Error Admin::SystemCheck::Message.new(:elasticsearch_running_check) From e82458552308f55b7cbc817af2938b231a172c16 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:06:48 +0200 Subject: [PATCH 06/69] New Crowdin Translations (automated) (#27052) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/bg.json | 4 ++-- app/javascript/mastodon/locales/en-GB.json | 1 + app/javascript/mastodon/locales/es-AR.json | 4 ++-- app/javascript/mastodon/locales/ko.json | 10 +++++----- app/javascript/mastodon/locales/no.json | 2 ++ app/javascript/mastodon/locales/sr-Latn.json | 1 + app/javascript/mastodon/locales/sr.json | 1 + app/javascript/mastodon/locales/vi.json | 2 +- config/locales/ja.yml | 2 +- config/locales/ko.yml | 2 +- config/locales/sr-Latn.yml | 1 + config/locales/sr.yml | 1 + config/locales/vi.yml | 2 +- 13 files changed, 20 insertions(+), 13 deletions(-) diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index d17bfdde7d..83bffd946d 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -26,7 +26,7 @@ "account.domain_blocked": "Блокиран домейн", "account.edit_profile": "Редактиране на профила", "account.enable_notifications": "Известяване при публикуване от @{name}", - "account.endorse": "Характеристика на профила", + "account.endorse": "Представи в профила", "account.featured_tags.last_status_at": "Последна публикация на {date}", "account.featured_tags.last_status_never": "Няма публикации", "account.featured_tags.title": "Главни хаштагове на {name}", @@ -393,7 +393,7 @@ "media_gallery.toggle_visible": "Скриване на {number, plural, one {изображение} other {изображения}}", "moved_to_account_banner.text": "Вашият акаунт {disabledAccount} сега е изключен, защото се преместихте в {movedToAccount}.", "mute_modal.duration": "Времетраене", - "mute_modal.hide_notifications": "Скривате ли известията от потребителя?", + "mute_modal.hide_notifications": "Скриване на известия от този потребител?", "mute_modal.indefinite": "Неопределено", "navigation_bar.about": "Относно", "navigation_bar.advanced_interface": "Отваряне в разширен уебинтерфейс", diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index 8d3535e326..20ed8937bc 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -590,6 +590,7 @@ "search.quick_action.open_url": "Open URL in Mastodon", "search.quick_action.status_search": "Posts matching {x}", "search.search_or_paste": "Search or paste URL", + "search_popout.full_text_search_disabled_message": "Unavailable on {domain}.", "search_popout.language_code": "ISO language code", "search_popout.options": "Search options", "search_popout.quick_actions": "Quick actions", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 1277264a99..7aeb66b546 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -302,8 +302,8 @@ "hashtag.follow": "Seguir etiqueta", "hashtag.unfollow": "Dejar de seguir etiqueta", "hashtags.and_other": "…y {count, plural, other {# más}}", - "home.actions.go_to_explore": "Mirá qué está en tendencia", - "home.actions.go_to_suggestions": "Encontrá cuentas para seguir", + "home.actions.go_to_explore": "Ver qué está en tendencia", + "home.actions.go_to_suggestions": "Encontrar cuentas para seguir", "home.column_settings.basic": "Básico", "home.column_settings.show_reblogs": "Mostrar adhesiones", "home.column_settings.show_replies": "Mostrar respuestas", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index e1361f6537..37c3990e49 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -137,7 +137,7 @@ "compose.language.search": "언어 검색...", "compose.published.body": "게시하였습니다.", "compose.published.open": "열기", - "compose.saved.body": "게시물을 저장했어요.", + "compose.saved.body": "게시물이 저장되었습니다.", "compose_form.direct_message_warning_learn_more": "더 알아보기", "compose_form.encryption_warning": "마스토돈의 게시물들은 종단간 암호화가 되지 않습니다. 민감한 정보를 마스토돈을 통해 전달하지 마세요.", "compose_form.hashtag_warning": "이 게시물은 전체공개가 아니기 때문에 어떤 해시태그로도 검색 되지 않습니다. 전체공개로 게시 된 게시물만이 해시태그로 검색될 수 있습니다.", @@ -307,12 +307,12 @@ "home.column_settings.basic": "기본", "home.column_settings.show_reblogs": "부스트 표시", "home.column_settings.show_replies": "답글 표시", - "home.explore_prompt.body": "홈 피드에는 내가 팔로우한 해시태그 그리고 팔로우한 사람과 부스트가 함께 나타나요. 너무 고요하게 느껴진다면, 다음 것들을 살펴볼 수 있어요:", + "home.explore_prompt.body": "홈 피드에는 내가 팔로우한 해시태그 그리고 팔로우한 사람과 부스트가 함께 나타납니다. 너무 고요하게 느껴진다면, 다음 것들을 살펴볼 수 있습니다.", "home.explore_prompt.title": "이곳은 마스토돈의 내 본거지입니다.", "home.hide_announcements": "공지사항 숨기기", "home.pending_critical_update.body": "서둘러 마스토돈 서버를 업데이트 하세요!", "home.pending_critical_update.link": "업데이트 보기", - "home.pending_critical_update.title": "긴급 보안 업데이트가 있어요!", + "home.pending_critical_update.title": "긴급 보안 업데이트가 있습니다!", "home.show_announcements": "공지사항 보기", "interaction_modal.description.favourite": "마스토돈 계정을 통해, 게시물을 좋아하는 것으로 작성자에게 호의를 표하고 나중에 보기 위해 저장할 수 있습니다.", "interaction_modal.description.follow": "마스토돈 계정을 통해, {name} 님을 팔로우 하고 그의 게시물을 홈 피드에서 받아 볼 수 있습니다.", @@ -554,7 +554,7 @@ "report.mute_explanation": "당신은 해당 계정의 게시물을 보지 않게 됩니다. 해당 계정은 여전히 당신을 팔로우 하거나 당신의 게시물을 볼 수 있으며 해당 계정은 자신이 뮤트 되었는지 알지 못합니다.", "report.next": "다음", "report.placeholder": "코멘트", - "report.reasons.dislike": "마음에 안듭니다", + "report.reasons.dislike": "마음에 안 듭니다", "report.reasons.dislike_description": "내가 보기 싫은 종류에 속합니다", "report.reasons.legal": "불법입니다", "report.reasons.legal_description": "내 서버가 속한 국가의 법률을 위반한다고 생각합니다", @@ -695,7 +695,7 @@ "upload_area.title": "드래그 & 드롭으로 업로드", "upload_button.label": "이미지, 영상, 오디오 파일 추가", "upload_error.limit": "파일 업로드 제한에 도달했습니다.", - "upload_error.poll": "파일 업로드는 설문과 함께 쓸 수 없어요.", + "upload_error.poll": "파일 업로드는 투표와 함께 쓸 수 없습니다.", "upload_form.audio_description": "청각 장애인을 위한 설명", "upload_form.description": "시각장애인을 위한 설명", "upload_form.description_missing": "설명이 추가되지 않음", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index 08949e9f7c..a670fd2e4f 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -310,6 +310,8 @@ "home.explore_prompt.body": "Tidslinjen din inneholder en blanding av innlegg fra emneknagger du har valgt å følge, personene du har valgt å følge, og innleggene de fremhever. Hvis det føles for stille, kan det være lurt å:", "home.explore_prompt.title": "Dette er hjemmet ditt i Mastodon.", "home.hide_announcements": "Skjul kunngjøring", + "home.pending_critical_update.link": "Se oppdateringer", + "home.pending_critical_update.title": "Kritisk sikkerhetsoppdatering er tilgjengelig!", "home.show_announcements": "Vis kunngjøring", "interaction_modal.description.favourite": "Med en konto på Mastodon, kan du favorittmarkere dette innlegget for å la forfatteren vite at du satte pris på det, og lagre innlegget til senere.", "interaction_modal.description.follow": "Med en konto på Mastodon, kan du følge {name} for å få innleggene deres i tidslinjen din.", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 49755e90ed..6fe5603f40 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -590,6 +590,7 @@ "search.quick_action.open_url": "Otvori URL adresu u Mastodon-u", "search.quick_action.status_search": "Podudaranje objava {x}", "search.search_or_paste": "Pretražite ili unesite adresu", + "search_popout.full_text_search_disabled_message": "Nije dostupno na {domain}.", "search_popout.language_code": "ISO kod jezika", "search_popout.options": "Opcije pretrage", "search_popout.quick_actions": "Brze radnje", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index 0beabb5187..f3c077cf31 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -590,6 +590,7 @@ "search.quick_action.open_url": "Отвори URL адресу у Mastodon-у", "search.quick_action.status_search": "Подударање објава {x}", "search.search_or_paste": "Претражите или унесите адресу", + "search_popout.full_text_search_disabled_message": "Није доступно на {domain}.", "search_popout.language_code": "ISO код језика", "search_popout.options": "Опције претраге", "search_popout.quick_actions": "Брзе радње", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 01d301d5e8..5c2417274a 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -592,7 +592,7 @@ "search.search_or_paste": "Tìm kiếm hoặc nhập URL", "search_popout.full_text_search_disabled_message": "Không khả dụng trên {domain}.", "search_popout.language_code": "Mã ngôn ngữ ISO", - "search_popout.options": "Tuỳ chọn tìm kiếm", + "search_popout.options": "Tùy chọn tìm kiếm", "search_popout.quick_actions": "Thao tác nhanh", "search_popout.recent": "Tìm kiếm gần đây", "search_popout.specific_date": "ngày cụ thể", diff --git a/config/locales/ja.yml b/config/locales/ja.yml index abcb3ccf90..8da2695fdc 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -378,7 +378,7 @@ ja: add_new: ドメインブロックを追加 confirm_suspension: cancel: キャンセル - confirm: ブロック + confirm: 停止 permanent_action: 失われたデータやフォロー関係は、ブロックを解除しても元に戻せません。 preamble_html: "%{domain} と、そのサブドメインをブロックします。" remove_all_data: この操作により、対象のドメインにあるアカウントからのコンテンツやメディア、プロフィール情報はすべて削除されます。 diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 128667834d..a6a85464e6 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -833,7 +833,7 @@ ko: action: 문서 참조 message_html: Elasticsearch 클러스터가 한 대의 노드만 사용하고 있습니다. ES_PRESETsingle_node_cluster로 설정되어야 합니다. elasticsearch_reset_chewy: - message_html: 설정 변경으로 인해Elasticsearch 시스템 인덱스가 최신상태가 아닙니다. tootctl search deploy --reset-chewy 명령으로 업데이트 하세요. + message_html: 설정 변경으로 인해 Elasticsearch 시스템 인덱스가 최신상태가 아닙니다. tootctl search deploy --reset-chewy 명령으로 업데이트 하세요. elasticsearch_running_check: message_html: Elasticsearch에 연결할 수 없습니다. 실행중인지 확인하거나, 전문검색을 비활성화하세요 elasticsearch_version_check: diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index 84178ef041..5d6849091a 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -1770,6 +1770,7 @@ sr-Latn: default: "%d %b %Y, %H:%M" month: "%b %Y" time: "%H:%M" + with_time_zone: "%d. %b %Y, %H:%M %Z" translation: errors: quota_exceeded: Prekoračena je kvota korišćenja usluge prevođenja na celom serveru. diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 012afecb47..379b9cb9d6 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -1770,6 +1770,7 @@ sr: default: "%d %b %Y, %H:%M" month: "%b %Y" time: "%H:%M" + with_time_zone: "%d. %b %Y, %H:%M %Z" translation: errors: quota_exceeded: Прекорачена је квота коришћења услуге превођења на целом серверу. diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 093b0bca9e..73222a6047 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -1513,7 +1513,7 @@ vi: activity: Tương tác confirm_follow_selected_followers: Bạn có chắc muốn theo dõi những người đã chọn? confirm_remove_selected_followers: Bạn có chắc muốn bỏ theo dõi những người đã chọn? - confirm_remove_selected_follows: Bạn có chắc muốn xoá những người theo dõi bạn đã chọn không? + confirm_remove_selected_follows: Bạn có chắc muốn xóa những người theo dõi bạn đã chọn không? dormant: Chưa follow_failure: Không thể theo dõi một số tài khoản đã chọn. follow_selected_followers: Theo dõi những người đã chọn From f330e186e98888a6ca95527c3237b75f5916ff69 Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 22 Sep 2023 20:12:38 +0900 Subject: [PATCH 07/69] Fix circle select is not working --- .../mastodon/features/compose/components/circle_select.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/features/compose/components/circle_select.jsx b/app/javascript/mastodon/features/compose/components/circle_select.jsx index 251e095f55..722137d081 100644 --- a/app/javascript/mastodon/features/compose/components/circle_select.jsx +++ b/app/javascript/mastodon/features/compose/components/circle_select.jsx @@ -31,8 +31,8 @@ class CircleSelect extends PureComponent { return null; } - const listOptions = circles.toArray().filter((circle) => circle[1]).map((circle) => { - return { value: circle[1].get('id'), label: circle[1].get('title') }; + const listOptions = circles.toArray().filter((circle) => circle).map((circle) => { + return { value: circle.get('id'), label: circle.get('title') }; }); const listValue = listOptions.find((opt) => opt.value === circleId); From 454008e4326e2897258fcbb68a3bbf5a1946bc79 Mon Sep 17 00:00:00 2001 From: KMY Date: Fri, 22 Sep 2023 21:48:03 +0900 Subject: [PATCH 08/69] Change lts to nil --- lib/mastodon/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index 4e9032b40a..f9ca3f5b5f 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -13,7 +13,7 @@ module Mastodon end def kmyblue_flag - 'LTS' + nil # 'LTS' end def major From 39da3d86f827f1ec68560209c70f705dd0b62f0e Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 22 Sep 2023 16:01:59 +0200 Subject: [PATCH 09/69] Fix ActiveRecord using two connection pools when no replica is defined (#27061) --- app/helpers/database_helper.rb | 17 +++++++++++++++-- app/models/application_record.rb | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/helpers/database_helper.rb b/app/helpers/database_helper.rb index 79227bb109..62a26a0c2a 100644 --- a/app/helpers/database_helper.rb +++ b/app/helpers/database_helper.rb @@ -1,11 +1,24 @@ # frozen_string_literal: true module DatabaseHelper + def replica_enabled? + ENV['REPLICA_DB_NAME'] || ENV.fetch('REPLICA_DATABASE_URL', nil) + end + module_function :replica_enabled? + def with_read_replica(&block) - ApplicationRecord.connected_to(role: :reading, prevent_writes: true, &block) + if replica_enabled? + ApplicationRecord.connected_to(role: :reading, prevent_writes: true, &block) + else + yield + end end def with_primary(&block) - ApplicationRecord.connected_to(role: :writing, &block) + if replica_enabled? + ApplicationRecord.connected_to(role: :writing, &block) + else + yield + end end end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 567542f91d..014a73997d 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -5,7 +5,7 @@ class ApplicationRecord < ActiveRecord::Base include Remotable - connects_to database: { writing: :primary, reading: ENV['REPLICA_DB_NAME'] || ENV['REPLICA_DATABASE_URL'] ? :replica : :primary } + connects_to database: { writing: :primary, reading: :replica } if DatabaseHelper.replica_enabled? class << self def update_index(_type_name, *_args, &_block) From b93ffb74bbeb998abb94c1f944807c2f74af56c0 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 22 Sep 2023 16:41:50 +0200 Subject: [PATCH 10/69] Improve modals reducer types (#26610) --- app/javascript/mastodon/actions/modal.ts | 4 +- app/javascript/mastodon/reducers/modal.ts | 53 +++++++++-------------- 2 files changed, 24 insertions(+), 33 deletions(-) diff --git a/app/javascript/mastodon/actions/modal.ts b/app/javascript/mastodon/actions/modal.ts index af34f5d6af..ab03e46765 100644 --- a/app/javascript/mastodon/actions/modal.ts +++ b/app/javascript/mastodon/actions/modal.ts @@ -1,12 +1,14 @@ import { createAction } from '@reduxjs/toolkit'; +import type { ModalProps } from 'mastodon/reducers/modal'; + import type { MODAL_COMPONENTS } from '../features/ui/components/modal_root'; export type ModalType = keyof typeof MODAL_COMPONENTS; interface OpenModalPayload { modalType: ModalType; - modalProps: unknown; + modalProps: ModalProps; } export const openModal = createAction('MODAL_OPEN'); diff --git a/app/javascript/mastodon/reducers/modal.ts b/app/javascript/mastodon/reducers/modal.ts index dab1e8301c..73a2afb916 100644 --- a/app/javascript/mastodon/reducers/modal.ts +++ b/app/javascript/mastodon/reducers/modal.ts @@ -1,13 +1,13 @@ import { Record as ImmutableRecord, Stack } from 'immutable'; -import type { PayloadAction } from '@reduxjs/toolkit'; +import type { Reducer } from '@reduxjs/toolkit'; import { COMPOSE_UPLOAD_CHANGE_SUCCESS } from '../actions/compose'; import type { ModalType } from '../actions/modal'; import { openModal, closeModal } from '../actions/modal'; import { TIMELINE_DELETE } from '../actions/timelines'; -type ModalProps = Record; +export type ModalProps = Record; interface Modal { modalType: ModalType; modalProps: ModalProps; @@ -62,33 +62,22 @@ const pushModal = ( }); }; -export function modalReducer( - state: State = initialState, - action: PayloadAction<{ - modalType: ModalType; - ignoreFocus: boolean; - modalProps: Record; - }>, -) { - switch (action.type) { - case openModal.type: - return pushModal( - state, - action.payload.modalType, - action.payload.modalProps, - ); - case closeModal.type: - return popModal(state, action.payload); - case COMPOSE_UPLOAD_CHANGE_SUCCESS: - return popModal(state, { modalType: 'FOCAL_POINT', ignoreFocus: false }); - case TIMELINE_DELETE: - return state.update('stack', (stack) => - stack.filterNot( - // @ts-expect-error TIMELINE_DELETE action is not typed yet. - (modal) => modal.get('modalProps').statusId === action.id, - ), - ); - default: - return state; - } -} +export const modalReducer: Reducer = (state = initialState, action) => { + if (openModal.match(action)) + return pushModal( + state, + action.payload.modalType, + action.payload.modalProps, + ); + else if (closeModal.match(action)) return popModal(state, action.payload); + // TODO: type those actions + else if (action.type === COMPOSE_UPLOAD_CHANGE_SUCCESS) + return popModal(state, { modalType: 'FOCAL_POINT', ignoreFocus: false }); + else if (action.type === TIMELINE_DELETE) + return state.update('stack', (stack) => + stack.filterNot( + (modal) => modal.get('modalProps').statusId === action.id, + ), + ); + else return state; +}; From 4b7bc1f07c712cf2375882da4f12a8af29444590 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Fri, 22 Sep 2023 18:18:46 +0200 Subject: [PATCH 11/69] Convert `dropdown_menu` state to Typescript (#25585) --- .../mastodon/actions/dropdown_menu.js | 10 ------ .../mastodon/actions/dropdown_menu.ts | 11 +++++++ .../containers/dropdown_menu_container.js | 13 +++++--- .../mastodon/components/scrollable_list.jsx | 7 +++- .../containers/dropdown_menu_container.js | 11 ++++--- app/javascript/mastodon/features/ui/index.jsx | 2 +- .../mastodon/reducers/dropdown_menu.js | 19 ----------- .../mastodon/reducers/dropdown_menu.ts | 33 +++++++++++++++++++ app/javascript/mastodon/reducers/index.ts | 4 +-- 9 files changed, 69 insertions(+), 41 deletions(-) delete mode 100644 app/javascript/mastodon/actions/dropdown_menu.js create mode 100644 app/javascript/mastodon/actions/dropdown_menu.ts delete mode 100644 app/javascript/mastodon/reducers/dropdown_menu.js create mode 100644 app/javascript/mastodon/reducers/dropdown_menu.ts diff --git a/app/javascript/mastodon/actions/dropdown_menu.js b/app/javascript/mastodon/actions/dropdown_menu.js deleted file mode 100644 index 023151d4bf..0000000000 --- a/app/javascript/mastodon/actions/dropdown_menu.js +++ /dev/null @@ -1,10 +0,0 @@ -export const DROPDOWN_MENU_OPEN = 'DROPDOWN_MENU_OPEN'; -export const DROPDOWN_MENU_CLOSE = 'DROPDOWN_MENU_CLOSE'; - -export function openDropdownMenu(id, keyboard, scroll_key) { - return { type: DROPDOWN_MENU_OPEN, id, keyboard, scroll_key }; -} - -export function closeDropdownMenu(id) { - return { type: DROPDOWN_MENU_CLOSE, id }; -} diff --git a/app/javascript/mastodon/actions/dropdown_menu.ts b/app/javascript/mastodon/actions/dropdown_menu.ts new file mode 100644 index 0000000000..3694df1ae0 --- /dev/null +++ b/app/javascript/mastodon/actions/dropdown_menu.ts @@ -0,0 +1,11 @@ +import { createAction } from '@reduxjs/toolkit'; + +export const openDropdownMenu = createAction<{ + id: string; + keyboard: boolean; + scrollKey: string; +}>('dropdownMenu/open'); + +export const closeDropdownMenu = createAction<{ id: string }>( + 'dropdownMenu/close', +); diff --git a/app/javascript/mastodon/components/edited_timestamp/containers/dropdown_menu_container.js b/app/javascript/mastodon/components/edited_timestamp/containers/dropdown_menu_container.js index a0896d985e..726fee9076 100644 --- a/app/javascript/mastodon/components/edited_timestamp/containers/dropdown_menu_container.js +++ b/app/javascript/mastodon/components/edited_timestamp/containers/dropdown_menu_container.js @@ -4,9 +4,14 @@ import { openDropdownMenu, closeDropdownMenu } from 'mastodon/actions/dropdown_m import { fetchHistory } from 'mastodon/actions/history'; import DropdownMenu from 'mastodon/components/dropdown_menu'; +/** + * + * @param {import('mastodon/store').RootState} state + * @param {*} props + */ const mapStateToProps = (state, { statusId }) => ({ - openDropdownId: state.getIn(['dropdown_menu', 'openId']), - openedViaKeyboard: state.getIn(['dropdown_menu', 'keyboard']), + openDropdownId: state.dropdownMenu.openId, + openedViaKeyboard: state.dropdownMenu.keyboard, items: state.getIn(['history', statusId, 'items']), loading: state.getIn(['history', statusId, 'loading']), }); @@ -15,11 +20,11 @@ const mapDispatchToProps = (dispatch, { statusId }) => ({ onOpen (id, onItemClick, keyboard) { dispatch(fetchHistory(statusId)); - dispatch(openDropdownMenu(id, keyboard)); + dispatch(openDropdownMenu({ id, keyboard })); }, onClose (id) { - dispatch(closeDropdownMenu(id)); + dispatch(closeDropdownMenu({ id })); }, }); diff --git a/app/javascript/mastodon/components/scrollable_list.jsx b/app/javascript/mastodon/components/scrollable_list.jsx index ce0b579f50..7672a4e424 100644 --- a/app/javascript/mastodon/components/scrollable_list.jsx +++ b/app/javascript/mastodon/components/scrollable_list.jsx @@ -23,9 +23,14 @@ const MOUSE_IDLE_DELAY = 300; const listenerOptions = supportsPassiveEvents ? { passive: true } : false; +/** + * + * @param {import('mastodon/store').RootState} state + * @param {*} props + */ const mapStateToProps = (state, { scrollKey }) => { return { - preventScroll: scrollKey === state.getIn(['dropdown_menu', 'scroll_key']), + preventScroll: scrollKey === state.dropdownMenu.scrollKey, }; }; diff --git a/app/javascript/mastodon/containers/dropdown_menu_container.js b/app/javascript/mastodon/containers/dropdown_menu_container.js index 6cf180cd53..bc9124c041 100644 --- a/app/javascript/mastodon/containers/dropdown_menu_container.js +++ b/app/javascript/mastodon/containers/dropdown_menu_container.js @@ -7,9 +7,12 @@ import { openModal, closeModal } from '../actions/modal'; import DropdownMenu from '../components/dropdown_menu'; import { isUserTouching } from '../is_mobile'; +/** + * @param {import('mastodon/store').RootState} state + */ const mapStateToProps = state => ({ - openDropdownId: state.getIn(['dropdown_menu', 'openId']), - openedViaKeyboard: state.getIn(['dropdown_menu', 'keyboard']), + openDropdownId: state.dropdownMenu.openId, + openedViaKeyboard: state.dropdownMenu.keyboard, }); const mapDispatchToProps = (dispatch, { status, items, scrollKey }) => ({ @@ -25,7 +28,7 @@ const mapDispatchToProps = (dispatch, { status, items, scrollKey }) => ({ actions: items, onClick: onItemClick, }, - }) : openDropdownMenu(id, keyboard, scrollKey)); + }) : openDropdownMenu({ id, keyboard, scrollKey })); }, onClose(id) { @@ -33,7 +36,7 @@ const mapDispatchToProps = (dispatch, { status, items, scrollKey }) => ({ modalType: 'ACTIONS', ignoreFocus: false, })); - dispatch(closeDropdownMenu(id)); + dispatch(closeDropdownMenu({ id })); }, }); diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index 55ccde72f5..ac5e2d9361 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -79,7 +79,7 @@ const mapStateToProps = state => ({ hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0, hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0, canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) && state.getIn(['compose', 'media_attachments']).size < 4, - dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null, + dropdownMenuIsOpen: state.dropdownMenu.openId !== null, firstLaunch: state.getIn(['settings', 'introductionVersion'], 0) < INTRODUCTION_VERSION, username: state.getIn(['accounts', me, 'username']), }); diff --git a/app/javascript/mastodon/reducers/dropdown_menu.js b/app/javascript/mastodon/reducers/dropdown_menu.js deleted file mode 100644 index 6f92f1bbe8..0000000000 --- a/app/javascript/mastodon/reducers/dropdown_menu.js +++ /dev/null @@ -1,19 +0,0 @@ -import Immutable from 'immutable'; - -import { - DROPDOWN_MENU_OPEN, - DROPDOWN_MENU_CLOSE, -} from '../actions/dropdown_menu'; - -const initialState = Immutable.Map({ openId: null, keyboard: false, scroll_key: null }); - -export default function dropdownMenu(state = initialState, action) { - switch (action.type) { - case DROPDOWN_MENU_OPEN: - return state.merge({ openId: action.id, keyboard: action.keyboard, scroll_key: action.scroll_key }); - case DROPDOWN_MENU_CLOSE: - return state.get('openId') === action.id ? state.set('openId', null).set('scroll_key', null) : state; - default: - return state; - } -} diff --git a/app/javascript/mastodon/reducers/dropdown_menu.ts b/app/javascript/mastodon/reducers/dropdown_menu.ts new file mode 100644 index 0000000000..59e19bb16d --- /dev/null +++ b/app/javascript/mastodon/reducers/dropdown_menu.ts @@ -0,0 +1,33 @@ +import { createReducer } from '@reduxjs/toolkit'; + +import { closeDropdownMenu, openDropdownMenu } from '../actions/dropdown_menu'; + +interface DropdownMenuState { + openId: string | null; + keyboard: boolean; + scrollKey: string | null; +} + +const initialState: DropdownMenuState = { + openId: null, + keyboard: false, + scrollKey: null, +}; + +export const dropdownMenuReducer = createReducer(initialState, (builder) => { + builder + .addCase( + openDropdownMenu, + (state, { payload: { id, keyboard, scrollKey } }) => { + state.openId = id; + state.keyboard = keyboard; + state.scrollKey = scrollKey; + }, + ) + .addCase(closeDropdownMenu, (state, { payload: { id } }) => { + if (state.openId === id) { + state.openId = null; + state.scrollKey = null; + } + }); +}); diff --git a/app/javascript/mastodon/reducers/index.ts b/app/javascript/mastodon/reducers/index.ts index c61c862cfe..722f04f370 100644 --- a/app/javascript/mastodon/reducers/index.ts +++ b/app/javascript/mastodon/reducers/index.ts @@ -15,7 +15,7 @@ import contexts from './contexts'; import conversations from './conversations'; import custom_emojis from './custom_emojis'; import domain_lists from './domain_lists'; -import dropdown_menu from './dropdown_menu'; +import { dropdownMenuReducer } from './dropdown_menu'; import filters from './filters'; import followed_tags from './followed_tags'; import height_cache from './height_cache'; @@ -46,7 +46,7 @@ import user_lists from './user_lists'; const reducers = { announcements, - dropdown_menu, + dropdownMenu: dropdownMenuReducer, timelines, meta, alerts, From 8eae7e6179a540a4457d9eea323d5fcb64917464 Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 23 Sep 2023 09:18:50 +0900 Subject: [PATCH 12/69] Add enable local public visibility setting for admin --- .../features/compose/components/privacy_dropdown.jsx | 6 +++++- app/javascript/mastodon/initial_state.js | 2 ++ app/javascript/mastodon/reducers/compose.js | 5 ++++- app/models/form/admin_settings.rb | 2 ++ app/models/status.rb | 6 ++++-- app/serializers/initial_state_serializer.rb | 1 + app/serializers/rest/instance_serializer.rb | 2 +- app/serializers/rest/v1/instance_serializer.rb | 2 +- app/services/post_status_service.rb | 4 +++- app/views/admin/settings/discovery/show.html.haml | 5 +++++ config/locales/en.yml | 1 + config/locales/ja.yml | 1 + config/locales/simple_form.en.yml | 2 ++ config/locales/simple_form.ja.yml | 2 ++ config/settings.yml | 1 + 15 files changed, 35 insertions(+), 7 deletions(-) diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx b/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx index b01c0ede8b..b8acc4b4f2 100644 --- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx +++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx @@ -9,7 +9,7 @@ import { supportsPassiveEvents } from 'detect-passive-events'; import Overlay from 'react-overlays/Overlay'; import { Icon } from 'mastodon/components/icon'; -import { enableLoginPrivacy } from 'mastodon/initial_state'; +import { enableLoginPrivacy, enableLocalPrivacy } from 'mastodon/initial_state'; import { IconButton } from '../../../components/icon_button'; @@ -246,6 +246,10 @@ class PrivacyDropdown extends PureComponent { this.selectableOptions = this.selectableOptions.filter((opt) => opt.value !== 'login'); } + if (!enableLocalPrivacy) { + this.selectableOptions = this.selectableOptions.filter((opt) => opt.value !== 'public_unlisted'); + } + if (this.props.noDirect) { this.selectableOptions = this.selectableOptions.filter((opt) => opt.value !== 'direct'); } diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js index 902158bc77..9158271429 100644 --- a/app/javascript/mastodon/initial_state.js +++ b/app/javascript/mastodon/initial_state.js @@ -61,6 +61,7 @@ * @property {string} dtl_tag * @property {boolean} enable_emoji_reaction * @property {boolean} enable_login_privacy + * @property {boolean} enable_local_privacy * @property {boolean} enable_dtl_menu * @property {boolean=} expand_spoilers * @property {boolean} hide_recent_emojis @@ -130,6 +131,7 @@ export const displayMediaExpand = getMeta('display_media_expand'); export const domain = getMeta('domain'); export const dtlTag = getMeta('dtl_tag'); export const enableEmojiReaction = getMeta('enable_emoji_reaction'); +export const enableLocalPrivacy = getMeta('enable_local_privacy'); export const enableLoginPrivacy = getMeta('enable_login_privacy'); export const enableDtlMenu = getMeta('enable_dtl_menu'); export const expandSpoilers = getMeta('expand_spoilers'); diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 612ee01d9b..c57fa01761 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -58,7 +58,7 @@ import { import { REDRAFT } from '../actions/statuses'; import { STORE_HYDRATE } from '../actions/store'; import { TIMELINE_DELETE } from '../actions/timelines'; -import { me } from '../initial_state'; +import { enableLocalPrivacy, me } from '../initial_state'; import { unescapeHTML } from '../utils/html'; import { uuid } from '../uuid'; @@ -138,6 +138,9 @@ function clearAll(state) { if (state.get('stay_privacy') && !state.get('in_reply_to')) { map.set('default_privacy', state.get('privacy')); } + if (map.get('privacy') && !enableLocalPrivacy) { + map.set('privacy', 'public'); + } if (!state.get('in_reply_to')) { map.set('posted_on_this_session', true); } diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index 08b546561d..a2de73bd14 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -47,6 +47,7 @@ class Form::AdminSettings streaming_other_servers_emoji_reaction enable_emoji_reaction check_lts_version_only + enable_public_unlisted_visibility ).freeze INTEGER_KEYS = %i( @@ -74,6 +75,7 @@ class Form::AdminSettings streaming_other_servers_emoji_reaction enable_emoji_reaction check_lts_version_only + enable_public_unlisted_visibility ).freeze UPLOAD_KEYS = %i( diff --git a/app/models/status.rb b/app/models/status.rb index 9f0299a511..b532f58a30 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -449,11 +449,13 @@ class Status < ApplicationRecord class << self def selectable_visibilities - visibilities.keys - %w(direct limited) + vs = visibilities.keys - %w(direct limited) + vs -= %w(public_unlisted) unless Setting.enable_public_unlisted_visibility + vs end def selectable_reblog_visibilities - %w(unset) + visibilities.keys - %w(direct limited) + %w(unset) + selectable_visibilities end def selectable_searchabilities diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index 8f67f7e754..c4e9927c74 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -37,6 +37,7 @@ class InitialStateSerializer < ActiveModel::Serializer status_page_url: Setting.status_page_url, sso_redirect: sso_redirect, dtl_tag: DTL_ENABLED ? DTL_TAG : nil, + enable_local_privacy: Setting.enable_public_unlisted_visibility, } if object.current_account diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index c8b4740bff..9b52277bf0 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -108,7 +108,6 @@ class REST::InstanceSerializer < ActiveModel::Serializer # for third party apps def fedibird_capabilities capabilities = [ - :kmyblue_visibility_public_unlisted, :enable_wide_emoji, :enable_wide_emoji_reaction, :kmyblue_searchability, @@ -126,6 +125,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer capabilities << :profile_search unless Chewy.enabled? capabilities << :emoji_reaction if Setting.enable_emoji_reaction + capabilities << :kmyblue_visibility_public_unlisted if Setting.enable_public_unlisted_visibility capabilities end diff --git a/app/serializers/rest/v1/instance_serializer.rb b/app/serializers/rest/v1/instance_serializer.rb index 9e801a7898..64951b3db5 100644 --- a/app/serializers/rest/v1/instance_serializer.rb +++ b/app/serializers/rest/v1/instance_serializer.rb @@ -117,7 +117,6 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer # for third party apps def fedibird_capabilities capabilities = [ - :kmyblue_visibility_public_unlisted, :enable_wide_emoji, :enable_wide_emoji_reaction, :kmyblue_searchability, @@ -135,6 +134,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer capabilities << :profile_search unless Chewy.enabled? capabilities << :emoji_reaction if Setting.enable_emoji_reaction + capabilities << :kmyblue_visibility_public_unlisted if Setting.enable_public_unlisted_visibility capabilities end diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index a549ab1c78..b532b775bc 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -78,7 +78,7 @@ class PostStatusService < BaseService @visibility = :direct if @in_reply_to&.limited_visibility? @visibility = :limited if %w(mutual circle).include?(@options[:visibility]) @visibility = :unlisted if (@visibility&.to_sym == :public || @visibility&.to_sym == :public_unlisted || @visibility&.to_sym == :login) && @account.silenced? - @visibility = :public_unlisted if @visibility&.to_sym == :public && !@options[:force_visibility] && !@options[:application]&.superapp && @account.user&.setting_public_post_to_unlisted + @visibility = :public_unlisted if @visibility&.to_sym == :public && !@options[:force_visibility] && !@options[:application]&.superapp && @account.user&.setting_public_post_to_unlisted && Setting.enable_public_unlisted_visibility @limited_scope = @options[:visibility]&.to_sym if @visibility == :limited @searchability = searchability @searchability = :private if @account.silenced? && @searchability&.to_sym == :public @@ -86,6 +86,8 @@ class PostStatusService < BaseService @scheduled_at = @options[:scheduled_at]&.to_datetime @scheduled_at = nil if scheduled_in_the_past? @reference_ids = (@options[:status_reference_ids] || []).map(&:to_i).filter(&:positive?) + raise ArgumentError if !Setting.enable_public_unlisted_visibility && @visibility == :public_unlisted + load_circle overwrite_dtl_post process_sensitive_words diff --git a/app/views/admin/settings/discovery/show.html.haml b/app/views/admin/settings/discovery/show.html.haml index 6ea9e4fb4b..ee7d72ad32 100644 --- a/app/views/admin/settings/discovery/show.html.haml +++ b/app/views/admin/settings/discovery/show.html.haml @@ -40,6 +40,11 @@ .fields-group = f.input :streaming_other_servers_emoji_reaction, as: :boolean, wrapper: :with_label, kmyblue: true + %h4= t('admin.settings.discovery.visibilities') + + .fields-group + = f.input :enable_public_unlisted_visibility, as: :boolean, wrapper: :with_label, kmyblue: true, hint: false + %h4= t('admin.settings.discovery.publish_statistics') .fields-group diff --git a/config/locales/en.yml b/config/locales/en.yml index 18ed3cb8f5..cf45976a7c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -817,6 +817,7 @@ en: publish_statistics: Publish statistics title: Discovery trends: Trends + visibilities: Visibilities domain_blocks: all: To everyone disabled: To no one diff --git a/config/locales/ja.yml b/config/locales/ja.yml index fd93ff54ab..b033c48264 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -814,6 +814,7 @@ ja: publish_statistics: 統計情報を公開する title: 見つける trends: トレンド + visibilities: 公開範囲 domain_blocks: all: 誰にでも許可 disabled: 誰にも許可しない diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index aa17a42816..af5c64ef62 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -96,6 +96,7 @@ en: closed_registrations_message: Displayed when sign-ups are closed content_cache_retention_period: All posts and boosts from other servers will be deleted after the specified number of days. Some posts may not be recoverable. All related bookmarks, favourites and boosts will also be lost and impossible to undo. custom_css: You can apply custom styles on the web version of Mastodon. + enable_public_unlisted_visibility: If true, your community maybe closed-minded. If turn it false, strongly recommend that you disclose that you have disabled this setting! mascot: Overrides the illustration in the advanced web interface. media_cache_retention_period: Downloaded media files will be deleted after the specified number of days when set to a positive value, and re-downloaded on demand. peers_api_enabled: A list of domain names this server has encountered in the fediverse. No data is included here about whether you federate with a given server, just that your server knows about it. This is used by services that collect statistics on federation in a general sense. @@ -321,6 +322,7 @@ en: content_cache_retention_period: Content cache retention period custom_css: Custom CSS enable_emoji_reaction: Enable stamp function + enable_public_unlisted_visibility: Enable public-unlisted visibility mascot: Custom mascot (legacy) media_cache_retention_period: Media cache retention period peers_api_enabled: Publish list of discovered servers in the API diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index e255c43cd4..6ea9661d5a 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -109,6 +109,7 @@ ja: closed_registrations_message: アカウント作成を停止している時に表示されます content_cache_retention_period: 指定した日数が経過した他のサーバーの投稿とブーストを削除します。削除された投稿は再取得できない場合があります。削除された投稿についたブックマークやお気に入り、ブーストも失われ、元に戻せません。 custom_css: ウェブ版のMastodonでカスタムスタイルを適用できます。 + enable_public_unlisted_visibility: 有効にするとあなたのコミュニティは閉鎖的になるかもしれません。この設定はkmyblueの主要機能の1つであり、無効にする場合は概要などに記載することを強くおすすめします。 mascot: 上級者向けWebインターフェースのイラストを上書きします。 media_cache_retention_period: 正の値に設定されている場合、ダウンロードされたメディアファイルは指定された日数の後に削除され、リクエストに応じて再ダウンロードされます。 peers_api_enabled: このサーバーが Fediverse で遭遇したドメイン名のリストです。このサーバーが知っているだけで、特定のサーバーと連合しているかのデータは含まれません。これは一般的に Fediverse に関する統計情報を収集するサービスによって使用されます。 @@ -336,6 +337,7 @@ ja: content_cache_retention_period: コンテンツキャッシュの保持期間 custom_css: カスタムCSS enable_emoji_reaction: スタンプ機能を有効にする + enable_public_unlisted_visibility: 公開範囲「ローカル公開」を有効にする mascot: カスタムマスコット(レガシー) media_cache_retention_period: メディアキャッシュの保持期間 peers_api_enabled: 発見したサーバーのリストをAPIで公開する diff --git a/config/settings.yml b/config/settings.yml index 69b3ed1ee3..c0b5f4109b 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -42,6 +42,7 @@ defaults: &defaults streaming_other_servers_emoji_reaction: false enable_emoji_reaction: true check_lts_version_only: true + enable_public_unlisted_visibility: true development: <<: *defaults From 95b2c66a3e3205c2dbbb3edd349eae7bfb5a3d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?KMY=EF=BC=88=E9=9B=AA=E3=81=82=E3=81=99=E3=81=8B=EF=BC=89?= Date: Sat, 23 Sep 2023 09:20:46 +0900 Subject: [PATCH 13/69] Update FUNDING.yml --- .github/FUNDING.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index be750a5e41..fa7a0c5353 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1 @@ -patreon: mastodon -open_collective: mastodon -custom: https://sponsor.joinmastodon.org +custom: https://fantia.jp/fanclubs/484677 From 516ad990c070346526a2598d576c0b9635aaec00 Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 23 Sep 2023 09:40:25 +0900 Subject: [PATCH 14/69] Add issue attributes --- .github/ISSUE_TEMPLATE/1.bug_report.yml | 74 ++++++++++++++++++ .github/ISSUE_TEMPLATE/1.web_bug_report.yml | 76 ------------------- .github/ISSUE_TEMPLATE/2.feature_request.yml | 16 ++++ .../ISSUE_TEMPLATE/2.server_bug_report.yml | 65 ---------------- .github/ISSUE_TEMPLATE/3.feature_request.yml | 22 ------ .../ISSUE_TEMPLATE/3.spec_change_request.yml | 28 +++++++ .github/ISSUE_TEMPLATE/config.yml | 6 +- 7 files changed, 119 insertions(+), 168 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/1.bug_report.yml delete mode 100644 .github/ISSUE_TEMPLATE/1.web_bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/2.feature_request.yml delete mode 100644 .github/ISSUE_TEMPLATE/2.server_bug_report.yml delete mode 100644 .github/ISSUE_TEMPLATE/3.feature_request.yml create mode 100644 .github/ISSUE_TEMPLATE/3.spec_change_request.yml diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml new file mode 100644 index 0000000000..b8ca9cbd01 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml @@ -0,0 +1,74 @@ +name: バグ報告 +description: kmyblueのバグ報告 +labels: [bug] +body: + - type: textarea + attributes: + label: バグの再現手順 + description: どのように操作したらバグが発生したのか、バグが発生する直前までの手順を順番に詳しく教えてください + value: | + 1. + 2. + 3. + ... + validations: + required: true + - type: textarea + attributes: + label: 期待する動作 + description: どのように動いてほしかったですか? + validations: + required: true + - type: textarea + attributes: + label: 実際の動作 + description: どのようなバグが発生しましたか? + validations: + required: true + - type: textarea + attributes: + label: 詳しい情報 + validations: + required: false + - type: input + attributes: + label: バグが発生したkmyblueサーバーのドメイン + description: サーバー固有の問題の可能性もありますので、プライバシー上可能な範囲内で、できるだけ書いてください + placeholder: kmy.blue + validations: + required: false + - type: input + attributes: + label: バグが発生したkmyblueのバージョン + description: | + Mastodonではなくkmyblueのバージョンを記述してください。例えばバージョン表記が `v4.2.0+kmyblue.5.1-LTS` の場合、バージョンは `5.1`になります + + バージョンは、PCだと画面左下、スマホだと概要画面の一番下に書いてあります + placeholder: 5.1 + validations: + required: true + - type: input + attributes: + label: ブラウザの名前 + description: | + ブラウザの名前を書いてください。可能であればバージョンも併記してください + placeholder: Firefox 105.0.3 + validations: + required: false + - type: input + attributes: + label: OS + description: | + あなたのOSと、できればバージョンも教えてください。スマホの場合は、「Android」「iPhone」にバージョンをつけてください + placeholder: Windows11 + validations: + required: false + - type: textarea + attributes: + label: その他の詳細情報 + description: | + あなたの環境が特殊な場合、詳しいことを教えてください(例: VPS、tor、学内LANなど) + + サーバー管理者の場合は、Ruby、Node.jsのバージョン、Cloudflareの使用可否なども可能なら書いてください + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/1.web_bug_report.yml b/.github/ISSUE_TEMPLATE/1.web_bug_report.yml deleted file mode 100644 index 20e27d103c..0000000000 --- a/.github/ISSUE_TEMPLATE/1.web_bug_report.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Bug Report (Web Interface) -description: If you are using Mastodon's web interface and something is not working as expected -labels: [bug, 'status/to triage', 'area/web interface'] -body: - - type: markdown - attributes: - value: | - Make sure that you are submitting a new bug that was not previously reported or already fixed. - - Please use a concise and distinct title for the issue. - - type: textarea - attributes: - label: Steps to reproduce the problem - description: What were you trying to do? - value: | - 1. - 2. - 3. - ... - validations: - required: true - - type: input - attributes: - label: Expected behaviour - description: What should have happened? - validations: - required: true - - type: input - attributes: - label: Actual behaviour - description: What happened? - validations: - required: true - - type: textarea - attributes: - label: Detailed description - validations: - required: false - - type: input - attributes: - label: Mastodon instance - description: The address of the Mastodon instance where you experienced the issue - placeholder: mastodon.social - validations: - required: true - - type: input - attributes: - label: Mastodon version - description: | - This is displayed at the bottom of the About page, eg. `v4.1.2+nightly-20230627` - placeholder: v4.1.2 - validations: - required: true - - type: input - attributes: - label: Browser name and version - description: | - What browser are you using when getting this bug? Please specify the version as well. - placeholder: Firefox 105.0.3 - validations: - required: true - - type: input - attributes: - label: Operating system - description: | - What OS are you running? Please specify the version as well. - placeholder: macOS 13.4.1 - validations: - required: true - - type: textarea - attributes: - label: Technical details - description: | - Any additional technical details you may have. This can include the full error log, inspector's output… - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/2.feature_request.yml b/.github/ISSUE_TEMPLATE/2.feature_request.yml new file mode 100644 index 0000000000..10fb4bb23b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2.feature_request.yml @@ -0,0 +1,16 @@ +name: 機能要望 +description: 機能の提案 +labels: [enhancement] +body: + - type: textarea + attributes: + label: 欲しい機能 + description: 欲しい機能の詳細を書いてください + validations: + required: true + - type: textarea + attributes: + label: 必要性 + description: この機能はあなたにとってなぜ必要でしょうか?どういった状況で使われるものですか? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/2.server_bug_report.yml b/.github/ISSUE_TEMPLATE/2.server_bug_report.yml deleted file mode 100644 index 49d5f57209..0000000000 --- a/.github/ISSUE_TEMPLATE/2.server_bug_report.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Bug Report (server / API) -description: | - If something is not working as expected, but is not from using the web interface. -labels: [bug, 'status/to triage'] -body: - - type: markdown - attributes: - value: | - Make sure that you are submitting a new bug that was not previously reported or already fixed. - - Please use a concise and distinct title for the issue. - - type: textarea - attributes: - label: Steps to reproduce the problem - description: What were you trying to do? - value: | - 1. - 2. - 3. - ... - validations: - required: true - - type: input - attributes: - label: Expected behaviour - description: What should have happened? - validations: - required: true - - type: input - attributes: - label: Actual behaviour - description: What happened? - validations: - required: true - - type: textarea - attributes: - label: Detailed description - validations: - required: false - - type: input - attributes: - label: Mastodon instance - description: The address of the Mastodon instance where you experienced the issue - placeholder: mastodon.social - validations: - required: false - - type: input - attributes: - label: Mastodon version - description: | - This is displayed at the bottom of the About page, eg. `v4.1.2+nightly-20230627` - placeholder: v4.1.2 - validations: - required: false - - type: textarea - attributes: - label: Technical details - description: | - 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.1.2) - - Node.js version: (from `node --version`, eg. v18.16.0) - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/3.feature_request.yml b/.github/ISSUE_TEMPLATE/3.feature_request.yml deleted file mode 100644 index 2cabcf61e0..0000000000 --- a/.github/ISSUE_TEMPLATE/3.feature_request.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Feature Request -description: I have a suggestion -labels: [suggestion] -body: - - type: markdown - attributes: - value: | - Please use a concise and distinct title for the issue. - - Consider: Could it be implemented as a 3rd party app using the REST API instead? - - type: textarea - attributes: - label: Pitch - description: Describe your idea for a feature. Make sure it has not already been suggested/implemented/turned down before. - validations: - required: true - - type: textarea - attributes: - label: Motivation - description: Why do you think this feature is needed? Who would benefit from it? - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/3.spec_change_request.yml b/.github/ISSUE_TEMPLATE/3.spec_change_request.yml new file mode 100644 index 0000000000..da64cd2b78 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3.spec_change_request.yml @@ -0,0 +1,28 @@ +name: 仕様変更要望 +description: 既存の仕様変更の要望 +labels: [specchange] +body: + - type: markdown + attributes: + value: 意図したものとは明らかに異なる挙動をしているものはバグとして、もともと仕様として決められた動きをしているものを変更したいときはこちらでお願いします + - type: textarea + attributes: + label: 挙動を変更してほしい機能や動作 + validations: + required: true + - type: textarea + attributes: + label: 現在の挙動 + validations: + required: true + - type: textarea + attributes: + label: 変更してほしい新しい挙動 + validations: + required: true + - type: textarea + attributes: + label: 必要性 + description: この変更はあなたにとってなぜ必要でしょうか?どういった状況で使われるものですか? + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f5d3196528..0086358db1 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1 @@ -blank_issues_enabled: false -contact_links: - - name: GitHub Discussions - url: https://github.com/mastodon/mastodon/discussions - about: Please ask and answer questions here. +blank_issues_enabled: true From b87c4b509ee53c53fedb648a56086657ad93daf6 Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 23 Sep 2023 09:42:19 +0900 Subject: [PATCH 15/69] Set version as string --- .github/ISSUE_TEMPLATE/1.bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml index b8ca9cbd01..10e7e53458 100644 --- a/.github/ISSUE_TEMPLATE/1.bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml @@ -44,7 +44,7 @@ body: Mastodonではなくkmyblueのバージョンを記述してください。例えばバージョン表記が `v4.2.0+kmyblue.5.1-LTS` の場合、バージョンは `5.1`になります バージョンは、PCだと画面左下、スマホだと概要画面の一番下に書いてあります - placeholder: 5.1 + placeholder: '5.1' validations: required: true - type: input From 0513db12ab69d5643cf8d6c164ffc6e7dc83e7d2 Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 23 Sep 2023 12:34:47 +0900 Subject: [PATCH 16/69] Remove firefish but add meisskey as misskey fork --- app/lib/activitypub/activity/create.rb | 2 +- app/lib/status_reach_finder.rb | 2 +- .../activitypub/process_account_service.rb | 2 +- app/services/delivery_antenna_service.rb | 7 +--- .../services/delivery_antenna_service_spec.rb | 38 ------------------- 5 files changed, 4 insertions(+), 47 deletions(-) diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index f991faa6a6..691c57a5a9 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -559,7 +559,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity info = instance_info return false if info.nil? - %w(misskey calckey firefish).include?(info.software) + %w(misskey calckey meisskey).include?(info.software) end def misskey_searchability diff --git a/app/lib/status_reach_finder.rb b/app/lib/status_reach_finder.rb index 7bdc300e1c..d280773041 100644 --- a/app/lib/status_reach_finder.rb +++ b/app/lib/status_reach_finder.rb @@ -159,7 +159,7 @@ class StatusReachFinder def banned_domains_for_misskey_of_status(status) return [] unless (status.public_unlisted_visibility? && status.account.user&.setting_reject_public_unlisted_subscription) || (status.unlisted_visibility? && status.account.user&.setting_reject_unlisted_subscription) - from_info = InstanceInfo.where(software: %w(misskey calckey firefish)).pluck(:domain) + from_info = InstanceInfo.where(software: %w(misskey calckey meisskey)).pluck(:domain) from_domain_block = DomainBlock.where(detect_invalid_subscription: true).pluck(:domain) (from_info + from_domain_block).uniq end diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index d7859ba92d..f55d10f2c2 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -305,7 +305,7 @@ class ActivityPub::ProcessAccountService < BaseService info = instance_info return false if info.nil? - %w(misskey calckey firefish).include?(info.software) + %w(misskey calckey meisskey).include?(info.software) end def subscribable_by diff --git a/app/services/delivery_antenna_service.rb b/app/services/delivery_antenna_service.rb index 53bcc226e7..3d26321995 100644 --- a/app/services/delivery_antenna_service.rb +++ b/app/services/delivery_antenna_service.rb @@ -121,12 +121,7 @@ class DeliveryAntennaService when :public, :public_unlisted, :login, :limited false when :unlisted - if @status.local? - !@status.public_searchability? - else - info = InstanceInfo.find_by(domain: @status.account.domain) - info&.software == 'firefish' || !@status.public_searchability? - end + !@status.public_searchability? else true end diff --git a/spec/services/delivery_antenna_service_spec.rb b/spec/services/delivery_antenna_service_spec.rb index e9620dc083..224d448b1a 100644 --- a/spec/services/delivery_antenna_service_spec.rb +++ b/spec/services/delivery_antenna_service_spec.rb @@ -362,42 +362,4 @@ RSpec.describe DeliveryAntennaService, type: :service do expect(antenna_feed_of(antenna)).to include status.id end end - - context 'with federated unlisted post' do - let(:visibility) { :unlisted } - let(:searchability) { :public } - let(:domain) { 'fast.example.com' } - let!(:antenna) { antenna_with_keyword(bob, 'body') } - let!(:empty_antenna) { antenna_with_keyword(tom, 'body') } - - context 'when unknown domain' do - let(:software) { nil } - - it 'detecting antenna' do - expect(antenna_feed_of(antenna)).to include status.id - expect(antenna_feed_of(empty_antenna)).to include status.id - end - end - - context 'when misskey domain' do - let(:software) { 'misskey' } - - it 'detecting antenna' do - expect(antenna_feed_of(antenna)).to include status.id - expect(antenna_feed_of(empty_antenna)).to include status.id - end - end - - context 'when firefish domain' do - let(:software) { 'firefish' } - - it 'detecting antenna' do - expect(antenna_feed_of(antenna)).to include status.id - end - - it 'not detecting antenna' do - expect(antenna_feed_of(empty_antenna)).to_not include status.id - end - end - end end From 77297b43bd8493f8d0ea17d1698cabc787554d52 Mon Sep 17 00:00:00 2001 From: KMY Date: Sat, 23 Sep 2023 20:08:02 +0900 Subject: [PATCH 17/69] Fix circle max of account #23 --- app/models/circle.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/circle.rb b/app/models/circle.rb index cb58b97bce..dcb29a91ab 100644 --- a/app/models/circle.rb +++ b/app/models/circle.rb @@ -24,6 +24,6 @@ class Circle < ApplicationRecord validates :title, presence: true validates_each :account_id, on: :create do |record, _attr, value| - record.errors.add(:base, I18n.t('lists.errors.limit')) if List.where(account_id: value).count >= PER_ACCOUNT_LIMIT + record.errors.add(:base, I18n.t('lists.errors.limit')) if Circle.where(account_id: value).count >= PER_ACCOUNT_LIMIT end end From 60d36d79d539c872ede81ef2c18b4da0665a8aec Mon Sep 17 00:00:00 2001 From: KMY Date: Sun, 24 Sep 2023 10:27:42 +0900 Subject: [PATCH 18/69] Fix git issue type name --- .github/ISSUE_TEMPLATE/3.spec_change_request.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/3.spec_change_request.yml b/.github/ISSUE_TEMPLATE/3.spec_change_request.yml index da64cd2b78..e71befe859 100644 --- a/.github/ISSUE_TEMPLATE/3.spec_change_request.yml +++ b/.github/ISSUE_TEMPLATE/3.spec_change_request.yml @@ -1,5 +1,5 @@ -name: 仕様変更要望 -description: 既存の仕様変更の要望 +name: 仕様変更・改善要望 +description: 既存の仕様や挙動変更の要望 labels: [specchange] body: - type: markdown From 70258ea9108ee565fec3c7ff29accc997d48debc Mon Sep 17 00:00:00 2001 From: KMY Date: Sun, 24 Sep 2023 12:16:48 +0900 Subject: [PATCH 19/69] Fix status is added bookmark category statuses list on bottom when bookmark --- .../mastodon/reducers/bookmark_categories.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/reducers/bookmark_categories.js b/app/javascript/mastodon/reducers/bookmark_categories.js index ea9e4f4895..2d25e08b51 100644 --- a/app/javascript/mastodon/reducers/bookmark_categories.js +++ b/app/javascript/mastodon/reducers/bookmark_categories.js @@ -64,6 +64,15 @@ const appendToBookmarkCategoryStatusesById = (state, bookmarkCategoryId, statuse })); }; +const prependToBookmarkCategoryStatusesById = (state, bookmarkCategoryId, statuses) => { + return state.update(bookmarkCategoryId, listMap => listMap.withMutations(map => { + map.set('isLoading', false); + if (map.get('items')) { + map.update('items', list => ImmutableOrderedSet([statuses]).union(list)); + } + })); +}; + const removeStatusFromBookmarkCategoryById = (state, bookmarkCategoryId, status) => { if (state.getIn([bookmarkCategoryId, 'items'])) { return state.updateIn([bookmarkCategoryId, 'items'], items => items.delete(status)); @@ -107,7 +116,8 @@ export default function bookmarkCategories(state = initialState, action) { case BOOKMARK_CATEGORY_STATUSES_EXPAND_SUCCESS: return appendToBookmarkCategoryStatuses(state, action.id, action.statuses, action.next); case BOOKMARK_CATEGORY_EDITOR_ADD_SUCCESS: - return appendToBookmarkCategoryStatusesById(state, action.bookmarkCategoryId, action.statusId, undefined); + console.log('HERE') + return prependToBookmarkCategoryStatusesById(state, action.bookmarkCategoryId, action.statusId); case BOOKMARK_CATEGORY_EDITOR_REMOVE_SUCCESS: return removeStatusFromBookmarkCategoryById(state, action.bookmarkCategoryId, action.statusId); case UNBOOKMARK_SUCCESS: From df3b3f4185fbca2abe4a81fe762823e9fe554823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?KMY=EF=BC=88=E9=9B=AA=E3=81=82=E3=81=99=E3=81=8B=EF=BC=89?= Date: Sun, 24 Sep 2023 13:01:09 +0900 Subject: [PATCH 20/69] Add circle posts history support (#18) * Wip: make web backend * Wip: keep statuses if edit circle * Wip: Add circle history page and record circle posts * Add circle post to history in web ui when post * Add test --- .../api/v1/circles/statuses_controller.rb | 66 +++++++ app/javascript/mastodon/actions/circles.js | 98 +++++++++- app/javascript/mastodon/actions/compose.js | 15 ++ .../features/circle_statuses/index.jsx | 182 ++++++++++++++++++ .../mastodon/features/circles/index.jsx | 6 +- .../features/ui/components/columns_area.jsx | 2 + app/javascript/mastodon/features/ui/index.jsx | 2 + .../features/ui/util/async-components.js | 4 + app/javascript/mastodon/reducers/circles.js | 87 ++++++++- app/javascript/mastodon/selectors/index.js | 4 + app/models/circle.rb | 2 + app/models/circle_status.rb | 26 +++ app/models/status.rb | 1 + app/services/process_mentions_service.rb | 2 + config/routes.rb | 2 +- config/routes/api.rb | 1 + .../20230923103430_create_circle_statuses.rb | 22 +++ db/schema.rb | 14 +- .../services/process_mentions_service_spec.rb | 23 +++ 19 files changed, 544 insertions(+), 15 deletions(-) create mode 100644 app/controllers/api/v1/circles/statuses_controller.rb create mode 100644 app/javascript/mastodon/features/circle_statuses/index.jsx create mode 100644 app/models/circle_status.rb create mode 100644 db/migrate/20230923103430_create_circle_statuses.rb diff --git a/app/controllers/api/v1/circles/statuses_controller.rb b/app/controllers/api/v1/circles/statuses_controller.rb new file mode 100644 index 0000000000..84e9b05543 --- /dev/null +++ b/app/controllers/api/v1/circles/statuses_controller.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +class Api::V1::Circles::StatusesController < Api::BaseController + before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:show] + before_action -> { doorkeeper_authorize! :write, :'write:lists' }, except: [:show] + + before_action :require_user! + before_action :set_circle + + after_action :insert_pagination_headers, only: :show + + def show + @statuses = load_statuses + render json: @statuses, each_serializer: REST::StatusSerializer + end + + private + + def set_circle + @circle = current_account.circles.find(params[:circle_id]) + end + + def load_statuses + if unlimited? + @circle.statuses.includes(:status_stat).all + else + @circle.statuses.includes(:status_stat).paginate_by_max_id(limit_param(DEFAULT_STATUSES_LIMIT), params[:max_id], params[:since_id]) + end + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def next_path + return if unlimited? + + api_v1_circle_statuses_url pagination_params(max_id: pagination_max_id) if records_continue? + end + + def prev_path + return if unlimited? + + api_v1_circle_statuses_url pagination_params(since_id: pagination_since_id) unless @statuses.empty? + end + + def pagination_max_id + @statuses.last.id + end + + def pagination_since_id + @statuses.first.id + end + + def records_continue? + @statuses.size == limit_param(DEFAULT_STATUSES_LIMIT) + end + + def pagination_params(core_params) + params.slice(:limit).permit(:limit).merge(core_params) + end + + def unlimited? + params[:limit] == '0' + end +end diff --git a/app/javascript/mastodon/actions/circles.js b/app/javascript/mastodon/actions/circles.js index 6a52e541c9..a497b27d5d 100644 --- a/app/javascript/mastodon/actions/circles.js +++ b/app/javascript/mastodon/actions/circles.js @@ -1,7 +1,7 @@ -import api from '../api'; +import api, { getLinks } from '../api'; import { showAlertForError } from './alerts'; -import { importFetchedAccounts } from './importer'; +import { importFetchedAccounts, importFetchedStatuses } from './importer'; export const CIRCLE_FETCH_REQUEST = 'CIRCLE_FETCH_REQUEST'; export const CIRCLE_FETCH_SUCCESS = 'CIRCLE_FETCH_SUCCESS'; @@ -50,6 +50,14 @@ export const CIRCLE_ADDER_CIRCLES_FETCH_REQUEST = 'CIRCLE_ADDER_CIRCLES_FETCH_RE export const CIRCLE_ADDER_CIRCLES_FETCH_SUCCESS = 'CIRCLE_ADDER_CIRCLES_FETCH_SUCCESS'; export const CIRCLE_ADDER_CIRCLES_FETCH_FAIL = 'CIRCLE_ADDER_CIRCLES_FETCH_FAIL'; +export const CIRCLE_STATUSES_FETCH_REQUEST = 'CIRCLE_STATUSES_FETCH_REQUEST'; +export const CIRCLE_STATUSES_FETCH_SUCCESS = 'CIRCLE_STATUSES_FETCH_SUCCESS'; +export const CIRCLE_STATUSES_FETCH_FAIL = 'CIRCLE_STATUSES_FETCH_FAIL'; + +export const CIRCLE_STATUSES_EXPAND_REQUEST = 'CIRCLE_STATUSES_EXPAND_REQUEST'; +export const CIRCLE_STATUSES_EXPAND_SUCCESS = 'CIRCLE_STATUSES_EXPAND_SUCCESS'; +export const CIRCLE_STATUSES_EXPAND_FAIL = 'CIRCLE_STATUSES_EXPAND_FAIL'; + export const fetchCircle = id => (dispatch, getState) => { if (getState().getIn(['circles', id])) { return; @@ -370,3 +378,89 @@ export const removeFromCircleAdder = circleId => (dispatch, getState) => { dispatch(removeFromCircle(circleId, getState().getIn(['circleAdder', 'accountId']))); }; +export function fetchCircleStatuses(circleId) { + return (dispatch, getState) => { + if (getState().getIn(['circles', circleId, 'statuses', 'isLoading'])) { + return; + } + + dispatch(fetchCircleStatusesRequest(circleId)); + + api(getState).get(`/api/v1/circles/${circleId}/statuses`).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(importFetchedStatuses(response.data)); + dispatch(fetchCircleStatusesSuccess(circleId, response.data, next ? next.uri : null)); + }).catch(error => { + dispatch(fetchCircleStatusesFail(circleId, error)); + }); + }; +} + +export function fetchCircleStatusesRequest(id) { + return { + type: CIRCLE_STATUSES_FETCH_REQUEST, + id, + }; +} + +export function fetchCircleStatusesSuccess(id, statuses, next) { + return { + type: CIRCLE_STATUSES_FETCH_SUCCESS, + id, + statuses, + next, + }; +} + +export function fetchCircleStatusesFail(id, error) { + return { + type: CIRCLE_STATUSES_FETCH_FAIL, + id, + error, + }; +} + +export function expandCircleStatuses(circleId) { + return (dispatch, getState) => { + const url = getState().getIn(['circles', circleId, 'statuses', 'next'], null); + + if (url === null || getState().getIn(['circles', circleId, 'statuses', 'isLoading'])) { + return; + } + + dispatch(expandCircleStatusesRequest(circleId)); + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(importFetchedStatuses(response.data)); + dispatch(expandCircleStatusesSuccess(circleId, response.data, next ? next.uri : null)); + }).catch(error => { + dispatch(expandCircleStatusesFail(circleId, error)); + }); + }; +} + +export function expandCircleStatusesRequest(id) { + return { + type: CIRCLE_STATUSES_EXPAND_REQUEST, + id, + }; +} + +export function expandCircleStatusesSuccess(id, statuses, next) { + return { + type: CIRCLE_STATUSES_EXPAND_SUCCESS, + id, + statuses, + next, + }; +} + +export function expandCircleStatusesFail(id, error) { + return { + type: CIRCLE_STATUSES_EXPAND_FAIL, + id, + error, + }; +} + diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index 1f682d1321..efe4c56406 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -28,6 +28,8 @@ export const COMPOSE_DIRECT = 'COMPOSE_DIRECT'; export const COMPOSE_MENTION = 'COMPOSE_MENTION'; export const COMPOSE_RESET = 'COMPOSE_RESET'; +export const COMPOSE_WITH_CIRCLE_SUCCESS = 'COMPOSE_WITH_CIRCLE_SUCCESS'; + export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST'; export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS'; export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL'; @@ -174,6 +176,7 @@ export function submitCompose(routerHistory) { const status = getState().getIn(['compose', 'text'], ''); const media = getState().getIn(['compose', 'media_attachments']); const statusId = getState().getIn(['compose', 'id'], null); + const circleId = getState().getIn(['compose', 'circle_id'], null); if ((!status || !status.length) && media.size === 0) { return; @@ -253,6 +256,10 @@ export function submitCompose(routerHistory) { insertIfOnline(`account:${response.data.account.id}`); } + if (statusId === null && circleId !== null && circleId !== 0) { + dispatch(submitComposeWithCircleSuccess({ ...response.data }, circleId)); + } + dispatch(showAlert({ message: statusId === null ? messages.published : messages.saved, action: messages.open, @@ -278,6 +285,14 @@ export function submitComposeSuccess(status) { }; } +export function submitComposeWithCircleSuccess(status, circleId) { + return { + type: COMPOSE_WITH_CIRCLE_SUCCESS, + status, + circleId, + } +} + export function submitComposeFail(error) { return { type: COMPOSE_SUBMIT_FAIL, diff --git a/app/javascript/mastodon/features/circle_statuses/index.jsx b/app/javascript/mastodon/features/circle_statuses/index.jsx new file mode 100644 index 0000000000..2896455ab5 --- /dev/null +++ b/app/javascript/mastodon/features/circle_statuses/index.jsx @@ -0,0 +1,182 @@ +import PropTypes from 'prop-types'; + +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; + +import { Helmet } from 'react-helmet'; + +import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { connect } from 'react-redux'; + +import { debounce } from 'lodash'; + +import { deleteCircle, expandCircleStatuses, fetchCircle, fetchCircleStatuses } from 'mastodon/actions/circles'; +import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns'; +import { openModal } from 'mastodon/actions/modal'; +import ColumnHeader from 'mastodon/components/column_header'; +import { Icon } from 'mastodon/components/icon'; +import { LoadingIndicator } from 'mastodon/components/loading_indicator'; +import StatusList from 'mastodon/components/status_list'; +import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error'; +import Column from 'mastodon/features/ui/components/column'; +import { getCircleStatusList } from 'mastodon/selectors'; + + +const messages = defineMessages({ + deleteMessage: { id: 'confirmations.delete_circle.message', defaultMessage: 'Are you sure you want to permanently delete this circle?' }, + deleteConfirm: { id: 'confirmations.delete_circle.confirm', defaultMessage: 'Delete' }, + heading: { id: 'column.circles', defaultMessage: 'Circles' }, +}); + +const mapStateToProps = (state, { params }) => ({ + circle: state.getIn(['circles', params.id]), + statusIds: getCircleStatusList(state, params.id), + isLoading: state.getIn(['circles', params.id, 'isLoading'], true), + isEditing: state.getIn(['circleEditor', 'circleId']) === params.id, + hasMore: !!state.getIn(['circles', params.id, 'next']), +}); + +class CircleStatuses extends ImmutablePureComponent { + + static contextTypes = { + router: PropTypes.object, + }; + + static propTypes = { + params: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + statusIds: ImmutablePropTypes.list.isRequired, + circle: PropTypes.oneOfType([ImmutablePropTypes.map, PropTypes.bool]), + intl: PropTypes.object.isRequired, + columnId: PropTypes.string, + multiColumn: PropTypes.bool, + hasMore: PropTypes.bool, + isLoading: PropTypes.bool, + }; + + UNSAFE_componentWillMount () { + this.props.dispatch(fetchCircle(this.props.params.id)); + this.props.dispatch(fetchCircleStatuses(this.props.params.id)); + } + + handlePin = () => { + const { columnId, dispatch } = this.props; + + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('CIRCLE_STATUSES', { id: this.props.params.id })); + this.context.router.history.push('/'); + } + }; + + handleMove = (dir) => { + const { columnId, dispatch } = this.props; + dispatch(moveColumn(columnId, dir)); + }; + + handleHeaderClick = () => { + this.column.scrollTop(); + }; + + handleEditClick = () => { + this.props.dispatch(openModal({ + modalType: 'CIRCLE_EDITOR', + modalProps: { circleId: this.props.params.id }, + })); + }; + + handleDeleteClick = () => { + const { dispatch, columnId, intl } = this.props; + const { id } = this.props.params; + + dispatch(openModal({ + modalType: 'CONFIRM', + modalProps: { + message: intl.formatMessage(messages.deleteMessage), + confirm: intl.formatMessage(messages.deleteConfirm), + onConfirm: () => { + dispatch(deleteCircle(id)); + + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + this.context.router.history.push('/circles'); + } + }, + }, + })); + }; + + setRef = c => { + this.column = c; + }; + + handleLoadMore = debounce(() => { + this.props.dispatch(expandCircleStatuses()); + }, 300, { leading: true }); + + render () { + const { intl, circle, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props; + const pinned = !!columnId; + + if (typeof circle === 'undefined') { + return ( + +
+ +
+
+ ); + } else if (circle === false) { + return ( + + ); + } + + const emptyMessage = ; + + return ( + + +
+ + + +
+
+ + + + + {intl.formatMessage(messages.heading)} + + +
+ ); + } + +} + +export default connect(mapStateToProps)(injectIntl(CircleStatuses)); diff --git a/app/javascript/mastodon/features/circles/index.jsx b/app/javascript/mastodon/features/circles/index.jsx index 1b83876827..1cd3ae417f 100644 --- a/app/javascript/mastodon/features/circles/index.jsx +++ b/app/javascript/mastodon/features/circles/index.jsx @@ -13,7 +13,6 @@ import { fetchCircles, deleteCircle } from 'mastodon/actions/circles'; import { openModal } from 'mastodon/actions/modal'; import Column from 'mastodon/components/column'; import ColumnHeader from 'mastodon/components/column_header'; -import { IconButton } from 'mastodon/components/icon_button'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import ScrollableList from 'mastodon/components/scrollable_list'; import ColumnLink from 'mastodon/features/ui/components/column_link'; @@ -106,10 +105,7 @@ class Circles extends ImmutablePureComponent { bindToDocument={!multiColumn} > {circles.map(circle => - (
- - -
) + , )} diff --git a/app/javascript/mastodon/features/ui/components/columns_area.jsx b/app/javascript/mastodon/features/ui/components/columns_area.jsx index af549d21ed..280330f530 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.jsx +++ b/app/javascript/mastodon/features/ui/components/columns_area.jsx @@ -24,6 +24,7 @@ import { BookmarkCategoryStatuses, AntennaSetting, AntennaTimeline, + CircleStatuses, } from '../util/async-components'; import BundleColumnError from './bundle_column_error'; @@ -45,6 +46,7 @@ const componentMap = { 'EMOJI_REACTIONS': EmojiReactedStatuses, 'BOOKMARKS': BookmarkedStatuses, 'BOOKMARKS_EX': BookmarkCategoryStatuses, + 'CIRCLE_STATUSES': CircleStatuses, 'ANTENNA': AntennaSetting, 'ANTENNA_TIMELINE': AntennaTimeline, 'LIST': ListTimeline, diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index 64a1e302e5..feef2a7559 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -65,6 +65,7 @@ import { Lists, Antennas, Circles, + CircleStatuses, AntennaSetting, Directory, Explore, @@ -259,6 +260,7 @@ class SwitchingColumnsArea extends PureComponent { + diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js index 81d83ec818..10daf55357 100644 --- a/app/javascript/mastodon/features/ui/util/async-components.js +++ b/app/javascript/mastodon/features/ui/util/async-components.js @@ -54,6 +54,10 @@ export function Circles () { return import(/* webpackChunkName: "features/circles" */'../../circles'); } +export function CircleStatuses () { + return import(/* webpackChunkName: "features/circle_statuses" */'../../circle_statuses'); +} + export function Status () { return import(/* webpackChunkName: "features/status" */'../../status'); } diff --git a/app/javascript/mastodon/reducers/circles.js b/app/javascript/mastodon/reducers/circles.js index 805d7f186a..96237219d9 100644 --- a/app/javascript/mastodon/reducers/circles.js +++ b/app/javascript/mastodon/reducers/circles.js @@ -1,4 +1,4 @@ -import { List as ImmutableList, fromJS } from 'immutable'; +import { List as ImmutableList, Map as ImmutableMap, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable'; import { CIRCLE_FETCH_SUCCESS, @@ -7,31 +7,106 @@ import { CIRCLE_CREATE_SUCCESS, CIRCLE_UPDATE_SUCCESS, CIRCLE_DELETE_SUCCESS, + CIRCLE_STATUSES_FETCH_REQUEST, + CIRCLE_STATUSES_FETCH_SUCCESS, + CIRCLE_STATUSES_FETCH_FAIL, + CIRCLE_STATUSES_EXPAND_REQUEST, + CIRCLE_STATUSES_EXPAND_SUCCESS, + CIRCLE_STATUSES_EXPAND_FAIL, } from '../actions/circles'; +import { + COMPOSE_WITH_CIRCLE_SUCCESS, +} from '../actions/compose'; const initialState = ImmutableList(); -const normalizeList = (state, circle) => state.set(circle.id, fromJS(circle)); +const initialStatusesState = ImmutableMap({ + items: ImmutableList(), + isLoading: false, + next: null, +}); -const normalizeLists = (state, circles) => { +const normalizeCircle = (state, circle) => { + const old = state.get(circle.id); + if (old === false) { + return state; + } + + let s = state.set(circle.id, fromJS(circle)); + if (old) { + s = s.setIn([circle.id, 'statuses'], old.get('statuses')); + } else { + s = s.setIn([circle.id, 'statuses'], initialStatusesState); + } + return s; +}; + +const normalizeCircles = (state, circles) => { circles.forEach(circle => { - state = normalizeList(state, circle); + state = normalizeCircle(state, circle); }); return state; }; +const normalizeCircleStatuses = (state, circleId, statuses, next) => { + return state.updateIn([circleId, 'statuses'], listMap => listMap.withMutations(map => { + map.set('next', next); + map.set('loaded', true); + map.set('isLoading', false); + map.set('items', ImmutableOrderedSet(statuses.map(item => item.id))); + })); +}; + +const appendToCircleStatuses = (state, circleId, statuses, next) => { + return appendToCircleStatusesById(state, circleId, statuses.map(item => item.id), next); +}; + +const appendToCircleStatusesById = (state, circleId, statuses, next) => { + return state.updateIn([circleId, 'statuses'], listMap => listMap.withMutations(map => { + if (typeof next !== 'undefined') { + map.set('next', next); + } + map.set('isLoading', false); + if (map.get('items')) { + map.set('items', map.get('items').union(statuses)); + } + })); +}; + +const prependToCircleStatusById = (state, circleId, statusId) => { + if (!state.get(circleId)) return state; + + return state.updateIn([circleId], circle => circle.withMutations(map => { + if (map.getIn(['statuses', 'items'])) { + map.updateIn(['statuses', 'items'], list => ImmutableOrderedSet([statusId]).union(list)); + } + })); +} + export default function circles(state = initialState, action) { switch(action.type) { case CIRCLE_FETCH_SUCCESS: case CIRCLE_CREATE_SUCCESS: case CIRCLE_UPDATE_SUCCESS: - return normalizeList(state, action.circle); + return normalizeCircle(state, action.circle); case CIRCLES_FETCH_SUCCESS: - return normalizeLists(state, action.circles); + return normalizeCircles(state, action.circles); case CIRCLE_DELETE_SUCCESS: case CIRCLE_FETCH_FAIL: return state.set(action.id, false); + case CIRCLE_STATUSES_FETCH_REQUEST: + case CIRCLE_STATUSES_EXPAND_REQUEST: + return state.setIn([action.id, 'statuses', 'isLoading'], true); + case CIRCLE_STATUSES_FETCH_FAIL: + case CIRCLE_STATUSES_EXPAND_FAIL: + return state.setIn([action.id, 'statuses', 'isLoading'], false); + case CIRCLE_STATUSES_FETCH_SUCCESS: + return normalizeCircleStatuses(state, action.id, action.statuses, action.next); + case CIRCLE_STATUSES_EXPAND_SUCCESS: + return appendToCircleStatuses(state, action.id, action.statuses, action.next); + case COMPOSE_WITH_CIRCLE_SUCCESS: + return prependToCircleStatusById(state, action.circleId, action.status.id); default: return state; } diff --git a/app/javascript/mastodon/selectors/index.js b/app/javascript/mastodon/selectors/index.js index 6d5adbeb48..f6398e9324 100644 --- a/app/javascript/mastodon/selectors/index.js +++ b/app/javascript/mastodon/selectors/index.js @@ -135,3 +135,7 @@ export const getStatusList = createSelector([ export const getBookmarkCategoryStatusList = createSelector([ (state, bookmarkCategoryId) => state.getIn(['bookmark_categories', bookmarkCategoryId, 'items']), ], (items) => items ? items.toList() : ImmutableList()); + +export const getCircleStatusList = createSelector([ + (state, circleId) => state.getIn(['circles', circleId, 'statuses', 'items']), +], (items) => items ? items.toList() : ImmutableList()); diff --git a/app/models/circle.rb b/app/models/circle.rb index dcb29a91ab..7c11ab59ea 100644 --- a/app/models/circle.rb +++ b/app/models/circle.rb @@ -20,6 +20,8 @@ class Circle < ApplicationRecord has_many :circle_accounts, inverse_of: :circle, dependent: :destroy has_many :accounts, through: :circle_accounts + has_many :circle_statuses, inverse_of: :circle, dependent: :destroy + has_many :statuses, through: :circle_statuses validates :title, presence: true diff --git a/app/models/circle_status.rb b/app/models/circle_status.rb new file mode 100644 index 0000000000..b394a4f927 --- /dev/null +++ b/app/models/circle_status.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: circle_statuses +# +# id :bigint(8) not null, primary key +# circle_id :bigint(8) +# status_id :bigint(8) not null +# created_at :datetime not null +# updated_at :datetime not null +# + +class CircleStatus < ApplicationRecord + belongs_to :circle + belongs_to :status + + validates :status, uniqueness: { scope: :circle } + validate :account_own_status + + private + + def account_own_status + errors.add(:status_id, :invalid) unless status.account_id == circle.account_id + end +end diff --git a/app/models/status.rb b/app/models/status.rb index b532f58a30..98b274ce04 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -106,6 +106,7 @@ class Status < ApplicationRecord has_one :poll, inverse_of: :status, dependent: :destroy has_one :trend, class_name: 'StatusTrend', inverse_of: :status has_one :scheduled_expiration_status, inverse_of: :status, dependent: :destroy + has_one :circle_status, inverse_of: :status, dependent: :destroy validates :uri, uniqueness: true, presence: true, unless: :local? validates :text, presence: true, unless: -> { with_media? || reblog? } diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb index 493facbea7..0a5b48a9d9 100644 --- a/app/services/process_mentions_service.rb +++ b/app/services/process_mentions_service.rb @@ -112,5 +112,7 @@ class ProcessMentionsService < BaseService @circle.accounts.find_each do |target_account| @current_mentions << @status.mentions.new(silent: true, account: target_account) unless mentioned_account_ids.include?(target_account.id) end + + @circle.statuses << @status end end diff --git a/config/routes.rb b/config/routes.rb index 3db26c7f8c..ed5995b2f4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,7 +18,7 @@ Rails.application.routes.draw do /lists/(*any) /antennasw/(*any) /antennast/(*any) - /circles + /circles/(*any) /notifications /favourites /emoji_reactions diff --git a/config/routes/api.rb b/config/routes/api.rb index 9bf466ddab..961cd43ad3 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -226,6 +226,7 @@ namespace :api, format: false do resources :circles, only: [:index, :create, :show, :update, :destroy] do resource :accounts, only: [:show, :create, :destroy], controller: 'circles/accounts' + resource :statuses, only: [:show], controller: 'circles/statuses' end resources :bookmark_categories, only: [:index, :create, :show, :update, :destroy] do diff --git a/db/migrate/20230923103430_create_circle_statuses.rb b/db/migrate/20230923103430_create_circle_statuses.rb new file mode 100644 index 0000000000..9c14bb808a --- /dev/null +++ b/db/migrate/20230923103430_create_circle_statuses.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require Rails.root.join('lib', 'mastodon', 'migration_helpers') + +class CreateCircleStatuses < ActiveRecord::Migration[7.0] + include Mastodon::MigrationHelpers + + disable_ddl_transaction! + + def change + safety_assured do + create_table :circle_statuses do |t| + t.belongs_to :circle, null: true, foreign_key: { on_delete: :cascade } + t.belongs_to :status, null: false, foreign_key: { on_delete: :cascade } + t.datetime :created_at, null: false + t.datetime :updated_at, null: false + end + + add_index :circle_statuses, [:circle_id, :status_id], unique: true + end + end +end diff --git a/db/schema.rb b/db/schema.rb index c5dcfc6a33..e17320cdaa 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_09_19_232836) do +ActiveRecord::Schema[7.0].define(version: 2023_09_23_103430) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -447,6 +447,16 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_19_232836) do t.index ["follow_id"], name: "index_circle_accounts_on_follow_id" end + create_table "circle_statuses", force: :cascade do |t| + t.bigint "circle_id" + t.bigint "status_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["circle_id", "status_id"], name: "index_circle_statuses_on_circle_id_and_status_id", unique: true + t.index ["circle_id"], name: "index_circle_statuses_on_circle_id" + t.index ["status_id"], name: "index_circle_statuses_on_status_id" + end + create_table "circles", force: :cascade do |t| t.bigint "account_id", null: false t.string "title", default: "", null: false @@ -1414,6 +1424,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_19_232836) do add_foreign_key "circle_accounts", "accounts", on_delete: :cascade add_foreign_key "circle_accounts", "circles", on_delete: :cascade add_foreign_key "circle_accounts", "follows", on_delete: :cascade + add_foreign_key "circle_statuses", "circles", on_delete: :cascade + add_foreign_key "circle_statuses", "statuses", on_delete: :cascade add_foreign_key "circles", "accounts", on_delete: :cascade add_foreign_key "conversation_mutes", "accounts", name: "fk_225b4212bb", on_delete: :cascade add_foreign_key "conversation_mutes", "conversations", on_delete: :cascade diff --git a/spec/services/process_mentions_service_spec.rb b/spec/services/process_mentions_service_spec.rb index 0db73c41fa..39bb355577 100644 --- a/spec/services/process_mentions_service_spec.rb +++ b/spec/services/process_mentions_service_spec.rb @@ -103,4 +103,27 @@ RSpec.describe ProcessMentionsService, type: :service do end end end + + context 'with circle post' do + let(:status) { Fabricate(:status, account: account) } + let(:circle) { Fabricate(:circle, account: account) } + let(:follower) { Fabricate(:account) } + let(:other) { Fabricate(:account) } + + before do + follower.follow!(account) + other.follow!(account) + circle.accounts << follower + described_class.new.call(status, limited_type: :circle, circle: circle) + end + + it 'remains circle post on history' do + expect(CircleStatus.exists?(circle_id: circle.id, status_id: status.id)).to be true + end + + it 'post is delivered to circle members' do + expect(status.mentioned_accounts.count).to eq 1 + expect(status.mentioned_accounts.first.id).to eq follower.id + end + end end From 2c36bce71148180eb46a5b7b99a777c41fde798d Mon Sep 17 00:00:00 2001 From: KMY Date: Sun, 24 Sep 2023 18:05:35 +0900 Subject: [PATCH 21/69] Fix loading indicator when open empty circle --- app/javascript/mastodon/reducers/circles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/reducers/circles.js b/app/javascript/mastodon/reducers/circles.js index 96237219d9..b9a6e6c37a 100644 --- a/app/javascript/mastodon/reducers/circles.js +++ b/app/javascript/mastodon/reducers/circles.js @@ -38,7 +38,7 @@ const normalizeCircle = (state, circle) => { } else { s = s.setIn([circle.id, 'statuses'], initialStatusesState); } - return s; + return s.setIn([circle.id, 'isLoading'], false).setIn([circle.id, 'isLoaded'], true); }; const normalizeCircles = (state, circles) => { From e38eed8855890d339bc23f0990ecee786c10c60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?KMY=EF=BC=88=E9=9B=AA=E3=81=82=E3=81=99=E3=81=8B=EF=BC=89?= Date: Sun, 24 Sep 2023 19:29:43 +0900 Subject: [PATCH 22/69] Add mentioned users by status view (#28) * Wip * Add mentioned users menu to status * Add test code --- .../statuses/mentioned_accounts_controller.rb | 74 +++++++++++++++ .../mastodon/actions/interactions.js | 90 +++++++++++++++++++ .../mastodon/components/status_action_bar.jsx | 11 ++- .../features/mentioned_users/index.jsx | 90 +++++++++++++++++++ .../features/status/components/action_bar.jsx | 6 ++ app/javascript/mastodon/features/ui/index.jsx | 2 + .../features/ui/util/async-components.js | 4 + app/javascript/mastodon/reducers/circles.js | 1 + .../mastodon/reducers/user_lists.js | 17 ++++ app/models/mention.rb | 2 + app/policies/status_policy.rb | 4 + config/routes/api.rb | 1 + .../mentioned_accounts_controller_spec.rb | 78 ++++++++++++++++ 13 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 app/controllers/api/v1/statuses/mentioned_accounts_controller.rb create mode 100644 app/javascript/mastodon/features/mentioned_users/index.jsx create mode 100644 spec/controllers/api/v1/statuses/mentioned_accounts_controller_spec.rb diff --git a/app/controllers/api/v1/statuses/mentioned_accounts_controller.rb b/app/controllers/api/v1/statuses/mentioned_accounts_controller.rb new file mode 100644 index 0000000000..4d905ef1a6 --- /dev/null +++ b/app/controllers/api/v1/statuses/mentioned_accounts_controller.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +class Api::V1::Statuses::MentionedAccountsController < Api::BaseController + include Authorization + + before_action -> { authorize_if_got_token! :read, :'read:accounts' } + before_action :set_status + after_action :insert_pagination_headers + + def index + cache_if_unauthenticated! + @accounts = load_accounts + render json: @accounts, each_serializer: REST::AccountSerializer + end + + private + + def load_accounts + scope = default_accounts + scope = scope.where.not(id: current_account.excluded_from_timeline_account_ids) unless current_account.nil? + scope.merge(paginated_mentioned_users).to_a + end + + def default_accounts + Account + .without_suspended + .includes(:mentions, :account_stat) + .references(:mentions) + .where(mentions: { status_id: @status.id }) + end + + def paginated_mentioned_users + Mention.paginate_by_max_id( + limit_param(DEFAULT_ACCOUNTS_LIMIT), + params[:max_id], + params[:since_id] + ) + end + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def next_path + api_v1_status_mentioned_by_index_url pagination_params(max_id: pagination_max_id) if records_continue? + end + + def prev_path + api_v1_status_mentioned_by_index_url pagination_params(since_id: pagination_since_id) unless @accounts.empty? + end + + def pagination_max_id + @accounts.last.mentions.last.id + end + + def pagination_since_id + @accounts.first.mentions.first.id + end + + def records_continue? + @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) + end + + def set_status + @status = Status.find(params[:status_id]) + authorize @status, :show_mentioned_users? + rescue Mastodon::NotPermittedError + not_found + end + + def pagination_params(core_params) + params.slice(:limit).permit(:limit).merge(core_params) + end +end diff --git a/app/javascript/mastodon/actions/interactions.js b/app/javascript/mastodon/actions/interactions.js index b361809309..640c5c3128 100644 --- a/app/javascript/mastodon/actions/interactions.js +++ b/app/javascript/mastodon/actions/interactions.js @@ -71,6 +71,14 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARKED_REQUEST'; export const UNBOOKMARK_SUCCESS = 'UNBOOKMARKED_SUCCESS'; export const UNBOOKMARK_FAIL = 'UNBOOKMARKED_FAIL'; +export const MENTIONED_USERS_FETCH_REQUEST = 'MENTIONED_USERS_FETCH_REQUEST'; +export const MENTIONED_USERS_FETCH_SUCCESS = 'MENTIONED_USERS_FETCH_SUCCESS'; +export const MENTIONED_USERS_FETCH_FAIL = 'MENTIONED_USERS_FETCH_FAIL'; + +export const MENTIONED_USERS_EXPAND_REQUEST = 'MENTIONED_USERS_EXPAND_REQUEST'; +export const MENTIONED_USERS_EXPAND_SUCCESS = 'MENTIONED_USERS_EXPAND_SUCCESS'; +export const MENTIONED_USERS_EXPAND_FAIL = 'MENTIONED_USERS_EXPAND_FAIL'; + export function reblog(status, visibility) { return function (dispatch, getState) { dispatch(reblogRequest(status)); @@ -735,3 +743,85 @@ export function unpinFail(status, error) { skipLoading: true, }; } + +export function fetchMentionedUsers(id) { + return (dispatch, getState) => { + dispatch(fetchMentionedUsersRequest(id)); + + api(getState).get(`/api/v1/statuses/${id}/mentioned_by`).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(importFetchedAccounts(response.data)); + dispatch(fetchMentionedUsersSuccess(id, response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => { + dispatch(fetchMentionedUsersFail(id, error)); + }); + }; +} + +export function fetchMentionedUsersRequest(id) { + return { + type: MENTIONED_USERS_FETCH_REQUEST, + id, + }; +} + +export function fetchMentionedUsersSuccess(id, accounts, next) { + return { + type: MENTIONED_USERS_FETCH_SUCCESS, + id, + accounts, + next, + }; +} + +export function fetchMentionedUsersFail(id, error) { + return { + type: MENTIONED_USERS_FETCH_FAIL, + id, + error, + }; +} + +export function expandMentionedUsers(id) { + return (dispatch, getState) => { + const url = getState().getIn(['user_lists', 'mentioned_users', id, 'next']); + if (url === null) { + return; + } + + dispatch(expandMentionedUsersRequest(id)); + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + + dispatch(importFetchedAccounts(response.data)); + dispatch(expandMentionedUsersSuccess(id, response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => dispatch(expandMentionedUsersFail(id, error))); + }; +} + +export function expandMentionedUsersRequest(id) { + return { + type: MENTIONED_USERS_EXPAND_REQUEST, + id, + }; +} + +export function expandMentionedUsersSuccess(id, accounts, next) { + return { + type: MENTIONED_USERS_EXPAND_SUCCESS, + id, + accounts, + next, + }; +} + +export function expandMentionedUsersFail(id, error) { + return { + type: MENTIONED_USERS_EXPAND_FAIL, + id, + error, + }; +} diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index 02a42a92dd..a6f5e87037 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -24,6 +24,7 @@ const messages = defineMessages({ edit: { id: 'status.edit', defaultMessage: 'Edit' }, direct: { id: 'status.direct', defaultMessage: 'Privately mention @{name}' }, mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' }, + mentions: { id: 'status.mentions', defaultMessage: 'Mentioned users' }, mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' }, block: { id: 'account.block', defaultMessage: 'Block @{name}' }, reply: { id: 'status.reply', defaultMessage: 'Reply' }, @@ -249,6 +250,10 @@ class StatusActionBar extends ImmutablePureComponent { this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}`); }; + handleOpenMentions = () => { + this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}/mentioned_users`); + }; + handleEmbed = () => { this.props.onEmbed(this.props.status); }; @@ -315,7 +320,11 @@ class StatusActionBar extends ImmutablePureComponent { } if (signedIn) { - if (!simpleTimelineMenu) { + if (writtenByMe) { + menu.push({ text: intl.formatMessage(messages.mentions), action: this.handleOpenMentions }); + } + + if (!simpleTimelineMenu || writtenByMe) { menu.push(null); } diff --git a/app/javascript/mastodon/features/mentioned_users/index.jsx b/app/javascript/mastodon/features/mentioned_users/index.jsx new file mode 100644 index 0000000000..f32e38820e --- /dev/null +++ b/app/javascript/mastodon/features/mentioned_users/index.jsx @@ -0,0 +1,90 @@ +import PropTypes from 'prop-types'; + +import { injectIntl, FormattedMessage } from 'react-intl'; + +import { Helmet } from 'react-helmet'; + +import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { connect } from 'react-redux'; + +import { debounce } from 'lodash'; + +import { fetchMentionedUsers, expandMentionedUsers } from 'mastodon/actions/interactions'; +import ColumnHeader from 'mastodon/components/column_header'; +import { LoadingIndicator } from 'mastodon/components/loading_indicator'; +import ScrollableList from 'mastodon/components/scrollable_list'; +import AccountContainer from 'mastodon/containers/account_container'; +import Column from 'mastodon/features/ui/components/column'; + +const mapStateToProps = (state, props) => ({ + accountIds: state.getIn(['user_lists', 'mentioned_users', props.params.statusId, 'items']), + hasMore: !!state.getIn(['user_lists', 'mentioned_users', props.params.statusId, 'next']), + isLoading: state.getIn(['user_lists', 'mentioned_users', props.params.statusId, 'isLoading'], true), +}); + +class MentionedUsers extends ImmutablePureComponent { + + static propTypes = { + params: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + accountIds: ImmutablePropTypes.list, + hasMore: PropTypes.bool, + isLoading: PropTypes.bool, + multiColumn: PropTypes.bool, + intl: PropTypes.object.isRequired, + }; + + UNSAFE_componentWillMount () { + if (!this.props.accountIds) { + this.props.dispatch(fetchMentionedUsers(this.props.params.statusId)); + } + } + + handleLoadMore = debounce(() => { + this.props.dispatch(expandMentionedUsers(this.props.params.statusId)); + }, 300, { leading: true }); + + render () { + const { accountIds, hasMore, isLoading, multiColumn } = this.props; + + if (!accountIds) { + return ( + + + + ); + } + + const emptyMessage = ; + + return ( + + + + + {accountIds.map(id => + , + )} + + + + + + + ); + } + +} + +export default connect(mapStateToProps)(injectIntl(MentionedUsers)); diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx index 56086075fc..2e5df723de 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.jsx +++ b/app/javascript/mastodon/features/status/components/action_bar.jsx @@ -22,6 +22,7 @@ const messages = defineMessages({ edit: { id: 'status.edit', defaultMessage: 'Edit' }, direct: { id: 'status.direct', defaultMessage: 'Privately mention @{name}' }, mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' }, + mentions: { id: 'status.mentions', defaultMessage: 'Mentioned users' }, reply: { id: 'status.reply', defaultMessage: 'Reply' }, reblog: { id: 'status.reblog', defaultMessage: 'Boost' }, cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' }, @@ -95,6 +96,10 @@ class ActionBar extends PureComponent { intl: PropTypes.object.isRequired, }; + handleOpenMentions = () => { + this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}/mentioned_users`); + }; + handleReplyClick = () => { this.props.onReply(this.props.status); }; @@ -264,6 +269,7 @@ class ActionBar extends PureComponent { menu.push(null); } + menu.push({ text: intl.formatMessage(messages.mentions), action: this.handleOpenMentions }); menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick }); menu.push(null); menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick }); diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index feef2a7559..ee51220df6 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -46,6 +46,7 @@ import { Favourites, EmojiReactions, StatusReferences, + MentionedUsers, DirectTimeline, HashtagTimeline, AntennaTimeline, @@ -243,6 +244,7 @@ class SwitchingColumnsArea extends PureComponent { + {/* Legacy routes, cannot be easily factored with other routes because they share a param name */} diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js index 10daf55357..2857fcec38 100644 --- a/app/javascript/mastodon/features/ui/util/async-components.js +++ b/app/javascript/mastodon/features/ui/util/async-components.js @@ -106,6 +106,10 @@ export function StatusReferences () { return import(/* webpackChunkName: "features/status_references" */'../../status_references'); } +export function MentionedUsers () { + return import(/* webpackChunkName: "features/mentioned_users" */'../../mentioned_users'); +} + export function FollowRequests () { return import(/* webpackChunkName: "features/follow_requests" */'../../follow_requests'); } diff --git a/app/javascript/mastodon/reducers/circles.js b/app/javascript/mastodon/reducers/circles.js index b9a6e6c37a..cadbb000e0 100644 --- a/app/javascript/mastodon/reducers/circles.js +++ b/app/javascript/mastodon/reducers/circles.js @@ -23,6 +23,7 @@ const initialState = ImmutableList(); const initialStatusesState = ImmutableMap({ items: ImmutableList(), isLoading: false, + loaded: true, next: null, }); diff --git a/app/javascript/mastodon/reducers/user_lists.js b/app/javascript/mastodon/reducers/user_lists.js index 2cb41cd03d..ecf08dfbc3 100644 --- a/app/javascript/mastodon/reducers/user_lists.js +++ b/app/javascript/mastodon/reducers/user_lists.js @@ -64,6 +64,12 @@ import { EMOJI_REACTIONS_EXPAND_SUCCESS, EMOJI_REACTIONS_EXPAND_FAIL, STATUS_REFERENCES_FETCH_SUCCESS, + MENTIONED_USERS_FETCH_REQUEST, + MENTIONED_USERS_FETCH_SUCCESS, + MENTIONED_USERS_FETCH_FAIL, + MENTIONED_USERS_EXPAND_REQUEST, + MENTIONED_USERS_EXPAND_SUCCESS, + MENTIONED_USERS_EXPAND_FAIL, } from '../actions/interactions'; import { MUTES_FETCH_REQUEST, @@ -92,6 +98,7 @@ const initialState = ImmutableMap({ favourited_by: initialListState, emoji_reactioned_by: initialListState, referred_by: initialListState, + mentioned_users: initialListState, follow_requests: initialListState, blocks: initialListState, mutes: initialListState, @@ -205,6 +212,16 @@ export default function userLists(state = initialState, action) { return appendToEmojiReactionList(state, ['emoji_reactioned_by', action.id], action.accounts, action.next); case STATUS_REFERENCES_FETCH_SUCCESS: return state.setIn(['referred_by', action.id], ImmutableList(action.statuses.map(item => item.id))); + case MENTIONED_USERS_FETCH_SUCCESS: + return normalizeList(state, ['mentioned_users', action.id], action.accounts, action.next); + case MENTIONED_USERS_EXPAND_SUCCESS: + return appendToList(state, ['mentioned_users', action.id], action.accounts, action.next); + case MENTIONED_USERS_FETCH_REQUEST: + case MENTIONED_USERS_EXPAND_REQUEST: + return state.setIn(['mentioned_users', action.id, 'isLoading'], true); + case MENTIONED_USERS_FETCH_FAIL: + case MENTIONED_USERS_EXPAND_FAIL: + return state.setIn(['mentioned_users', action.id, 'isLoading'], false); case NOTIFICATIONS_UPDATE: return action.notification.type === 'follow_request' ? normalizeFollowRequest(state, action.notification) : state; case FOLLOW_REQUESTS_FETCH_SUCCESS: diff --git a/app/models/mention.rb b/app/models/mention.rb index 2348b2905c..5addfcc583 100644 --- a/app/models/mention.rb +++ b/app/models/mention.rb @@ -13,6 +13,8 @@ # class Mention < ApplicationRecord + include Paginable + belongs_to :account, inverse_of: :mentions belongs_to :status diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb index 335abe9e92..301ec4fdc4 100644 --- a/app/policies/status_policy.rb +++ b/app/policies/status_policy.rb @@ -24,6 +24,10 @@ class StatusPolicy < ApplicationPolicy end end + def show_mentioned_users? + owned? + end + def reblog? !requires_mention? && (!private? || owned?) && show? && !blocking_author? end diff --git a/config/routes/api.rb b/config/routes/api.rb index 961cd43ad3..005d8f6839 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -12,6 +12,7 @@ namespace :api, format: false do resources :favourited_by, controller: :favourited_by_accounts, only: :index resources :emoji_reactioned_by, controller: :emoji_reactioned_by_accounts, only: :index resources :referred_by, controller: :referred_by_statuses, only: :index + resources :mentioned_by, controller: :mentioned_accounts, only: :index resources :bookmark_categories, only: :index resource :reblog, only: :create post :unreblog, to: 'reblogs#destroy' diff --git a/spec/controllers/api/v1/statuses/mentioned_accounts_controller_spec.rb b/spec/controllers/api/v1/statuses/mentioned_accounts_controller_spec.rb new file mode 100644 index 0000000000..2299791344 --- /dev/null +++ b/spec/controllers/api/v1/statuses/mentioned_accounts_controller_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Api::V1::Statuses::MentionedAccountsController do + render_views + + let(:user) { Fabricate(:user) } + let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'read:accounts') } + let(:alice) { Fabricate(:account) } + let(:bob) { Fabricate(:account) } + let(:ohagi) { Fabricate(:account) } + + context 'with an oauth token' do + before do + allow(controller).to receive(:doorkeeper_token) { token } + end + + describe 'GET #index' do + let(:status) { Fabricate(:status, account: user.account) } + + before do + Mention.create!(account: bob, status: status) + Mention.create!(account: ohagi, status: status) + end + + it 'returns http success' do + get :index, params: { status_id: status.id, limit: 2 } + expect(response).to have_http_status(200) + expect(response.headers['Link'].links.size).to eq(2) + end + + it 'returns accounts who favorited the status' do + get :index, params: { status_id: status.id, limit: 2 } + expect(body_as_json.size).to eq 2 + expect([body_as_json[0][:id], body_as_json[1][:id]]).to contain_exactly(bob.id.to_s, ohagi.id.to_s) + end + + it 'does not return blocked users' do + user.account.block!(ohagi) + get :index, params: { status_id: status.id, limit: 2 } + expect(body_as_json.size).to eq 1 + expect(body_as_json[0][:id]).to eq bob.id.to_s + end + + context 'when other accounts status' do + let(:status) { Fabricate(:status, account: alice) } + + it 'returns http unauthorized' do + get :index, params: { status_id: status.id } + expect(response).to have_http_status(404) + end + end + end + end + + context 'without an oauth token' do + before do + allow(controller).to receive(:doorkeeper_token).and_return(nil) + end + + context 'with a public status' do + let(:status) { Fabricate(:status, account: user.account, visibility: :public) } + + describe 'GET #index' do + before do + Mention.create!(account: bob, status: status) + end + + it 'returns http unauthorized' do + get :index, params: { status_id: status.id } + expect(response).to have_http_status(404) + end + end + end + end +end From 8a3f2ee0fb2a974e4483a174805d54725b0a2775 Mon Sep 17 00:00:00 2001 From: KMY Date: Sun, 24 Sep 2023 20:29:36 +0900 Subject: [PATCH 23/69] Refactoring searchability to StatusParser --- app/lib/activitypub/activity/create.rb | 100 +------------------- app/lib/activitypub/parser/status_parser.rb | 72 ++++++++++++++ 2 files changed, 74 insertions(+), 98 deletions(-) diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 6b8a715330..1f81fcda6c 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -72,12 +72,6 @@ class ActivityPub::Activity::Create < ActivityPub::Activity as_array(@object['cc'] || @json['cc']).map { |x| value_or_id(x) } end - def audience_searchable_by - return nil if @object['searchableBy'].nil? - - @audience_searchable_by = as_array(@object['searchableBy']).map { |x| value_or_id(x) } - end - def process_status @tags = [] @mentions = [] @@ -120,7 +114,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity end def process_status_params - @status_parser = ActivityPub::Parser::StatusParser.new(@json, followers_collection: @account.followers_url, object: @object) + @status_parser = ActivityPub::Parser::StatusParser.new(@json, followers_collection: @account.followers_url, object: @object, account: @account) @params = { uri: @status_parser.uri, @@ -136,7 +130,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity sensitive: @account.sensitized? || @status_parser.sensitive || false, visibility: @status_parser.visibility, limited_scope: @status_parser.limited_scope, - searchability: searchability, + searchability: @status_parser.searchability, thread: replied_to_status, conversation: conversation_from_uri(@object['conversation']), media_attachment_ids: process_attachments.take(MediaAttachment::ACTIVITYPUB_STATUS_ATTACHMENT_MAX).map(&:id), @@ -500,94 +494,4 @@ class ActivityPub::Activity::Create < ActivityPub::Activity def join_group! GroupReblogService.new.call(@status) end - - def searchability_from_audience - if audience_searchable_by.nil? - nil - elsif audience_searchable_by.any? { |uri| ActivityPub::TagManager.instance.public_collection?(uri) } - :public - elsif audience_searchable_by.include?('as:Limited') - :limited - elsif audience_searchable_by.include?(@account.followers_url) - :private - else - :direct - end - end - - SCAN_SEARCHABILITY_RE = /\[searchability:(public|followers|reactors|private)\]/ - SCAN_SEARCHABILITY_FEDIBIRD_RE = /searchable_by_(all_users|followers_only|reacted_users_only|nobody)/ - - def searchability - from_audience = searchability_from_audience - return from_audience if from_audience - return nil if default_searchability_from_bio? - - searchability_from_bio || (misskey_software? ? misskey_searchability : nil) - end - - def default_searchability_from_bio? - note = @account.note - return false if note.blank? - - note.include?('searchable_by_default_range') - end - - def searchability_from_bio - note = @account.note - return nil if note.blank? - - searchability_bio = note.scan(SCAN_SEARCHABILITY_FEDIBIRD_RE).first || note.scan(SCAN_SEARCHABILITY_RE).first - return nil unless searchability_bio - - searchability = searchability_bio[0] - return nil if searchability.nil? - - searchability = :public if %w(public all_users).include?(searchability) - searchability = :private if %w(followers followers_only).include?(searchability) - searchability = :direct if %w(reactors reacted_users_only).include?(searchability) - searchability = :limited if %w(private nobody).include?(searchability) - - searchability - end - - def instance_info - @instance_info ||= InstanceInfo.find_by(domain: @account.domain) - end - - def misskey_software? - info = instance_info - return false if info.nil? - - %w(misskey calckey).include?(info.software) - end - - def misskey_searchability - visibility = visibility_from_audience - %i(public unlisted).include?(visibility) ? :public : :limited - end - - def visibility_from_audience - if audience_to.any? { |to| ActivityPub::TagManager.instance.public_collection?(to) } - :public - elsif audience_cc.any? { |cc| ActivityPub::TagManager.instance.public_collection?(cc) } - :unlisted - elsif audience_to.include?('as:LoginOnly') || audience_to.include?('LoginUser') - :login - elsif audience_to.include?(@account.followers_url) - :private - else - :direct - end - end - - def visibility_from_audience_with_silence - visibility = visibility_from_audience - - if @account.silenced? && %i(public).include?(visibility) - :unlisted - else - visibility - end - end end diff --git a/app/lib/activitypub/parser/status_parser.rb b/app/lib/activitypub/parser/status_parser.rb index 852578721c..4ffec58ae3 100644 --- a/app/lib/activitypub/parser/status_parser.rb +++ b/app/lib/activitypub/parser/status_parser.rb @@ -10,6 +10,7 @@ class ActivityPub::Parser::StatusParser @json = json @object = magic_values[:object] || json['object'] || json @magic_values = magic_values + @account = magic_values[:account] end def uri @@ -86,6 +87,14 @@ class ActivityPub::Parser::StatusParser end end + def searchability + from_audience = searchability_from_audience + return from_audience if from_audience + return nil if default_searchability_from_bio? + + searchability_from_bio || (misskey_software? ? misskey_searchability : nil) + end + def limited_scope case @object['limitedScope'] when 'Mutual' @@ -117,6 +126,12 @@ class ActivityPub::Parser::StatusParser as_array(@object['cc'] || @json['cc']).map { |x| value_or_id(x) } end + def audience_searchable_by + return nil if @object['searchableBy'].nil? + + @audience_searchable_by = as_array(@object['searchableBy']).map { |x| value_or_id(x) } + end + def summary_language_map? @object['summaryMap'].is_a?(Hash) && !@object['summaryMap'].empty? end @@ -128,4 +143,61 @@ class ActivityPub::Parser::StatusParser def name_language_map? @object['nameMap'].is_a?(Hash) && !@object['nameMap'].empty? end + + def instance_info + @instance_info ||= InstanceInfo.find_by(domain: @account.domain) + end + + def misskey_software? + info = instance_info + return false if info.nil? + + %w(misskey calckey).include?(info.software) + end + + def misskey_searchability + %i(public unlisted).include?(visibility) ? :public : :limited + end + + SCAN_SEARCHABILITY_RE = /\[searchability:(public|followers|reactors|private)\]/ + SCAN_SEARCHABILITY_FEDIBIRD_RE = /searchable_by_(all_users|followers_only|reacted_users_only|nobody)/ + + def default_searchability_from_bio? + note = @account.note + return false if note.blank? + + note.include?('searchable_by_default_range') + end + + def searchability_from_bio + note = @account.note + return nil if note.blank? + + searchability_bio = note.scan(SCAN_SEARCHABILITY_FEDIBIRD_RE).first || note.scan(SCAN_SEARCHABILITY_RE).first + return nil unless searchability_bio + + searchability = searchability_bio[0] + return nil if searchability.nil? + + searchability = :public if %w(public all_users).include?(searchability) + searchability = :private if %w(followers followers_only).include?(searchability) + searchability = :direct if %w(reactors reacted_users_only).include?(searchability) + searchability = :limited if %w(private nobody).include?(searchability) + + searchability + end + + def searchability_from_audience + if audience_searchable_by.nil? + nil + elsif audience_searchable_by.any? { |uri| ActivityPub::TagManager.instance.public_collection?(uri) } + :public + elsif audience_searchable_by.include?('as:Limited') + :limited + elsif audience_searchable_by.include?(@account.followers_url) + :private + else + :direct + end + end end From 3dded2809f22e78052c9d27d81e7ee1e544a344d Mon Sep 17 00:00:00 2001 From: KMY Date: Sun, 24 Sep 2023 21:39:09 +0900 Subject: [PATCH 24/69] #13 Turn searchability private if account is silenced --- app/models/status.rb | 1 + spec/models/status_spec.rb | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/models/status.rb b/app/models/status.rb index 98b274ce04..7916b95326 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -427,6 +427,7 @@ class Status < ApplicationRecord def compute_searchability local = account.local? + return 'private' if public_searchability? && account.silenced? return 'direct' if unsupported_searchability? return searchability if local && !searchability.nil? return 'direct' if local || [:public, :private, :direct, :limited].exclude?(account.searchability.to_sym) diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index 16210592f4..89f90fc751 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -120,7 +120,8 @@ RSpec.describe Status do let(:account_searchability) { :public } let(:status_searchability) { :public } let(:account_domain) { 'example.com' } - let(:account) { Fabricate(:account, domain: account_domain, searchability: account_searchability) } + let(:silenced_at) { nil } + let(:account) { Fabricate(:account, domain: account_domain, searchability: account_searchability, silenced_at: silenced_at) } context 'when public-public' do it 'returns public' do @@ -128,6 +129,14 @@ RSpec.describe Status do end end + context 'when public-public but silenced' do + let(:silenced_at) { Time.now.utc } + + it 'returns private' do + expect(subject.compute_searchability).to eq 'private' + end + end + context 'when public-private' do let(:status_searchability) { :private } From 1fa40cff704585ca62d56382df44e39d83981857 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:09:51 +0200 Subject: [PATCH 25/69] Update eslint (non-major) (#27113) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 59 +++++++++++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/yarn.lock b/yarn.lock index 70b791d8f8..de50d6fff9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1298,16 +1298,11 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.5.1": +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": version "4.8.1" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.1.tgz#8c4bb756cc2aa7eaf13cfa5e69c83afb3260c20c" integrity sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ== -"@eslint-community/regexpp@^4.6.1": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005" - integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg== - "@eslint/eslintrc@^2.1.2": version "2.1.2" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" @@ -1323,10 +1318,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.49.0": - version "8.49.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333" - integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== +"@eslint/js@8.50.0": + version "8.50.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.50.0.tgz#9e93b850f0f3fa35f5fa59adfd03adae8488e484" + integrity sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ== "@floating-ui/core@^1.3.1": version "1.3.1" @@ -5357,9 +5352,9 @@ eslint-import-resolver-node@^0.3.7: resolve "^1.22.4" eslint-import-resolver-typescript@^3.5.5: - version "3.6.0" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.0.tgz#36f93e1eb65a635e688e16cae4bead54552e3bbd" - integrity sha512-QTHR9ddNnn35RTxlaEnx2gCxqFlF2SEN0SE2d17SqwyM7YOSI2GHWRYp5BiRkObTUNYPupC/3Fq2a0PpT+EKpg== + version "3.6.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa" + integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg== dependencies: debug "^4.3.4" enhanced-resolve "^5.12.0" @@ -5417,9 +5412,9 @@ eslint-plugin-import@~2.28.0: tsconfig-paths "^3.14.2" eslint-plugin-jsdoc@^46.1.0: - version "46.8.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.8.1.tgz#cfc649c15d460903fe8e86eda582023bb97f283a" - integrity sha512-uTce7IBluPKXIQMWJkIwFsI1gv7sZRmLjctca2K5DIxPi8fSBj9f4iru42XmGwuiMyH2f3nfc60sFmnSGv4Z/A== + version "46.8.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.8.2.tgz#3e6b1c93e91e38fe01874d45da121b56393c54a5" + integrity sha512-5TSnD018f3tUJNne4s4gDWQflbsgOycIKEUBoCLn6XtBMgNHxQFmV8vVxUtiPxAQq8lrX85OaSG/2gnctxw9uQ== dependencies: "@es-joy/jsdoccomment" "~0.40.1" are-docs-informative "^0.0.2" @@ -5515,14 +5510,14 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.41.0: - version "8.49.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.49.0.tgz#09d80a89bdb4edee2efcf6964623af1054bf6d42" - integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ== + version "8.50.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.50.0.tgz#2ae6015fee0240fcd3f83e1e25df0287f487d6b2" + integrity sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.49.0" + "@eslint/js" "8.50.0" "@humanwhocodes/config-array" "^0.11.11" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -5997,9 +5992,9 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + version "3.2.9" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" + integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== follow-redirects@^1.0.0, follow-redirects@^1.15.0: version "1.15.2" @@ -6192,9 +6187,9 @@ get-symbol-description@^1.0.0: get-intrinsic "^1.1.1" get-tsconfig@^4.5.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.0.tgz#06ce112a1463e93196aa90320c35df5039147e34" - integrity sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw== + version "4.7.2" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" + integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== dependencies: resolve-pkg-maps "^1.0.0" @@ -6290,9 +6285,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.19.0: - version "13.21.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.21.0.tgz#163aae12f34ef502f5153cfbdd3600f36c63c571" - integrity sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg== + version "13.22.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.22.0.tgz#0c9fcb9c48a2494fbb5edbfee644285543eba9d8" + integrity sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw== dependencies: type-fest "^0.20.2" @@ -11206,9 +11201,9 @@ spdx-expression-parse@^3.0.0, spdx-expression-parse@^3.0.1: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.13" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" - integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== + version "3.0.15" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.15.tgz#142460aabaca062bc7cd4cc87b7d50725ed6a4ba" + integrity sha512-lpT8hSQp9jAKp9mhtBU4Xjon8LPGBvLIuBiSVhMEtmLecTh2mO0tlqrAMp47tBXzMr13NJMQ2lf7RpQGLJ3HsQ== spdy-transport@^3.0.0: version "3.0.0" From a4c29a4e516a1a0fda985b2d5143182a3c75a138 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:23:12 +0200 Subject: [PATCH 26/69] Update Node.js to v20.7 (#27112) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index f73bdcf786..4d397e3bdf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1.4 # This needs to be bookworm-slim because the Ruby image is built on bookworm-slim -ARG NODE_VERSION="20.6-bookworm-slim" +ARG NODE_VERSION="20.7-bookworm-slim" FROM ghcr.io/moritzheiber/ruby-jemalloc:3.2.2-slim as ruby FROM node:${NODE_VERSION} as build From c56d7d702f65fef013ed769ada571b44b64b0dc4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:36:46 +0200 Subject: [PATCH 27/69] Update dependency @reduxjs/toolkit to v1.9.6 (#27110) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index de50d6fff9..42d903c24b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1813,9 +1813,9 @@ integrity sha512-tOQQBVH8LsUpGXqDnk+kaOGVsgZ8maHAhEiw3Git3p88q+c0Slgu47HuDnL6sVxeCfz24zbq7dOjsVYDiTpDIA== "@reduxjs/toolkit@^1.9.5": - version "1.9.5" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.5.tgz#d3987849c24189ca483baa7aa59386c8e52077c4" - integrity sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ== + version "1.9.6" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.6.tgz#fc968b45fe5b17ff90932c4556960d9c1078365a" + integrity sha512-Gc4ikl90ORF4viIdAkY06JNUnODjKfGxZRwATM30EdHq8hLSVoSrwXne5dd739yenP5bJxAX7tLuOWK5RPGtrw== dependencies: immer "^9.0.21" redux "^4.2.1" @@ -11455,6 +11455,7 @@ stringz@^2.1.0: char-regex "^1.0.2" "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + name strip-ansi-cjs version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== From 736fe753467629b023a066e6436be8c7e5cf5c70 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:50:09 +0200 Subject: [PATCH 28/69] New Crowdin Translations (automated) (#27080) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ca.json | 28 ++++---- app/javascript/mastodon/locales/cs.json | 3 +- app/javascript/mastodon/locales/de.json | 6 +- app/javascript/mastodon/locales/eo.json | 4 ++ app/javascript/mastodon/locales/es.json | 2 +- app/javascript/mastodon/locales/fa.json | 74 ++++++++++++-------- app/javascript/mastodon/locales/fr.json | 10 +-- app/javascript/mastodon/locales/gd.json | 6 +- app/javascript/mastodon/locales/gl.json | 2 +- app/javascript/mastodon/locales/ko.json | 4 +- app/javascript/mastodon/locales/nl.json | 2 +- app/javascript/mastodon/locales/no.json | 4 ++ app/javascript/mastodon/locales/sk.json | 3 +- app/javascript/mastodon/locales/vi.json | 6 +- app/javascript/mastodon/locales/zh-CN.json | 12 ++-- app/javascript/mastodon/locales/zh-HK.json | 1 + config/locales/ca.yml | 4 +- config/locales/cs.yml | 80 ++++++++++++++++++++++ config/locales/cy.yml | 1 + config/locales/de.yml | 2 +- config/locales/doorkeeper.fa.yml | 8 ++- config/locales/fa.yml | 72 +++++++++++++++++-- config/locales/gd.yml | 2 +- config/locales/gl.yml | 2 +- config/locales/ja.yml | 8 +-- config/locales/ko.yml | 2 +- config/locales/no.yml | 26 +++++++ config/locales/simple_form.ca.yml | 2 +- config/locales/simple_form.cy.yml | 2 + config/locales/simple_form.fa.yml | 35 ++++++++++ config/locales/simple_form.no.yml | 8 ++- config/locales/simple_form.zh-CN.yml | 10 +-- config/locales/sk.yml | 9 +++ config/locales/sl.yml | 1 + config/locales/zh-CN.yml | 12 ++-- 35 files changed, 356 insertions(+), 97 deletions(-) diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 99640953af..433b9b47b7 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -321,7 +321,7 @@ "interaction_modal.login.action": "Torna a l'inici", "interaction_modal.login.prompt": "Domini del teu servidor domèstic, p.ex. mastodon.social", "interaction_modal.no_account_yet": "No a Mastodon?", - "interaction_modal.on_another_server": "En un servidor diferent", + "interaction_modal.on_another_server": "A un altre servidor", "interaction_modal.on_this_server": "En aquest servidor", "interaction_modal.sign_in": "No has iniciat sessió en aquest servidor. On tens el teu compte?", "interaction_modal.sign_in_hint": "Ajuda: Aquesta és la web on vas registrar-te. Si no ho recordes, mira el correu electrònic de benvinguda en la teva safata d'entrada. També pots introduïr el teu nom d'usuari complet! (per ex. @Mastodon@mastodon.social)", @@ -391,7 +391,7 @@ "load_pending": "{count, plural, one {# element nou} other {# elements nous}}", "loading_indicator.label": "Es carrega...", "media_gallery.toggle_visible": "{number, plural, one {Amaga la imatge} other {Amaga les imatges}}", - "moved_to_account_banner.text": "El teu compte {disabledAccount} està actualment desactivat perquè l'has traslladat a {movedToAccount}.", + "moved_to_account_banner.text": "El teu compte {disabledAccount} està desactivat perquè l'has mogut a {movedToAccount}.", "mute_modal.duration": "Durada", "mute_modal.hide_notifications": "Amagar les notificacions d'aquest usuari?", "mute_modal.indefinite": "Indefinit", @@ -426,8 +426,8 @@ "notification.admin.sign_up": "{name} s'ha registrat", "notification.favourite": "{name} ha afavorit el teu tut", "notification.follow": "{name} et segueix", - "notification.follow_request": "{name} ha sol·licitat seguir-te", - "notification.mention": "{name} t'ha mencionat", + "notification.follow_request": "{name} ha sol·licitat de seguir-te", + "notification.mention": "{name} t'ha esmentat", "notification.own_poll": "La teva enquesta ha finalitzat", "notification.poll": "Ha finalitzat una enquesta en què has votat", "notification.reblog": "{name} t'ha impulsat", @@ -451,7 +451,7 @@ "notifications.column_settings.show": "Mostra a la columna", "notifications.column_settings.sound": "Reprodueix so", "notifications.column_settings.status": "Nous tuts:", - "notifications.column_settings.unread_notifications.category": "Notificacions no llegides", + "notifications.column_settings.unread_notifications.category": "Notificacions pendents de llegir", "notifications.column_settings.unread_notifications.highlight": "Destaca les notificacions no llegides", "notifications.column_settings.update": "Edicions:", "notifications.filter.all": "Totes", @@ -473,25 +473,25 @@ "onboarding.action.back": "Porta'm enrere", "onboarding.actions.back": "Porta'm enrere", "onboarding.actions.go_to_explore": "Mira què és tendència", - "onboarding.actions.go_to_home": "Vés a la teva línia de temps inici", + "onboarding.actions.go_to_home": "Ves a la teva línia de temps", "onboarding.compose.template": "Hola Mastodon!", "onboarding.follows.empty": "Malauradament, cap resultat pot ser mostrat ara mateix. Pots provar de fer servir la cerca o visitar la pàgina Explora per a trobar gent a qui seguir o provar-ho de nou més tard.", - "onboarding.follows.lead": "Tu tens cura de la teva línia de temps inici. Com més gent segueixis, més activa i interessant serà. Aquests perfils poden ser un bon punt d'inici—sempre pots acabar deixant-los de seguir!", - "onboarding.follows.title": "Popular a Mastodon", + "onboarding.follows.lead": "La teva línia de temps inici només està a les teves mans. Com més gent segueixis, més activa i interessant serà. Aquests perfils poden ser un bon punt d'inici—sempre pots acabar deixant de seguir-los!:", + "onboarding.follows.title": "Personalitza la pantalla d'inci", "onboarding.share.lead": "Permet que la gent sàpiga com trobar-te a Mastodon!", "onboarding.share.message": "Sóc {username} a #Mastodon! Vine i segueix-me a {url}", "onboarding.share.next_steps": "Possibles passes següents:", "onboarding.share.title": "Comparteix el teu perfil", - "onboarding.start.lead": "El teu nou compte a Mastodon ja està preparat. Aquí tens com en pots treure tot el suc:", + "onboarding.start.lead": "El teu nou compte ja està preparat a Mastodon, la xarxa social on tu—no un algorisme—té tot el control. Aquí tens com en pots treure tot el suc:", "onboarding.start.skip": "Vols saltar-te tota la resta?", "onboarding.start.title": "Llestos!", - "onboarding.steps.follow_people.body": "Tu tens cura de la teva línia de temps. Omple-la de gent interessant.", - "onboarding.steps.follow_people.title": "{count, plural, zero {No segueixes cap persona} one {Segeueixes ona persona} other {Segueixes # persones}}", - "onboarding.steps.publish_status.body": "Saluda el món.", + "onboarding.steps.follow_people.body": "Mastodon va de seguir a gent interessant.", + "onboarding.steps.follow_people.title": "Personalitza la pantalla d'inci", + "onboarding.steps.publish_status.body": "Saluda al món amb text, fotos, vídeos o enquestes {emoji}", "onboarding.steps.publish_status.title": "Fes el teu primer tut", - "onboarding.steps.setup_profile.body": "És més fàcil que altres interaccionin amb tu si tens un perfil complet.", + "onboarding.steps.setup_profile.body": "És més fàcil que altres interactuïn amb tu si tens un perfil complet.", "onboarding.steps.setup_profile.title": "Personalitza el perfil", - "onboarding.steps.share_profile.body": "Permet als teus amics de saber com trobar-te a Mastodon!", + "onboarding.steps.share_profile.body": "Fer saber als teus amics com trobar-te a Mastodon", "onboarding.steps.share_profile.title": "Comparteix el teu perfil", "onboarding.tips.2fa": "Ho sabies? Pots securitzar el teu compte activant l'autenticació de doble factor en la configuració del teu perfil. Funciona amb qualsevol aplicació TOTP de la teva elecció, no cal número de telèfon!", "onboarding.tips.accounts_from_other_servers": "Ho sabies? Com Mastodon és descentralitzat, et pots trobar amb perfils que són a servidors diferents del teu. I, tanmateix, també hi pots interactuar sense cap problema! El servidor és la segona part del seu nom d'usuari!", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index 94fc3ed2d0..94d62a4889 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -114,7 +114,7 @@ "column.directory": "Prozkoumat profily", "column.domain_blocks": "Blokované domény", "column.favourites": "Oblíbené", - "column.firehose": "Živé kanály l", + "column.firehose": "Živé kanály", "column.follow_requests": "Žádosti o sledování", "column.home": "Domů", "column.lists": "Seznamy", @@ -585,6 +585,7 @@ "search.quick_action.open_url": "Otevřít URL v Mastodonu", "search.quick_action.status_search": "Příspěvky odpovídající {x}", "search.search_or_paste": "Hledat nebo vložit URL", + "search_popout.full_text_search_disabled_message": "Nedostupné na {domain}.", "search_popout.language_code": "Kód jazyka podle ISO", "search_popout.options": "Možnosti hledání", "search_popout.quick_actions": "Rychlé akce", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 7f8ffbb0db..acd53c28a7 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -143,7 +143,7 @@ "compose_form.hashtag_warning": "Dieser Beitrag wird unter keinem Hashtag sichtbar sein, weil er nicht öffentlich ist. Nur öffentliche Beiträge können nach Hashtags durchsucht werden.", "compose_form.lock_disclaimer": "Dein Profil ist nicht {locked}. Andere können dir folgen und deine Beiträge sehen, die nur für Follower bestimmt sind.", "compose_form.lock_disclaimer.lock": "geschützt", - "compose_form.placeholder": "Was gibt's Neues?", + "compose_form.placeholder": "Was gibt’s Neues?", "compose_form.poll.add_option": "Auswahl", "compose_form.poll.duration": "Umfragedauer", "compose_form.poll.option_placeholder": "{number}. Auswahl", @@ -286,7 +286,7 @@ "footer.source_code": "Quellcode anzeigen", "footer.status": "Status", "generic.saved": "Gespeichert", - "getting_started.heading": "Auf geht's!", + "getting_started.heading": "Auf geht’s!", "hashtag.column_header.tag_mode.all": "und {additional}", "hashtag.column_header.tag_mode.any": "oder {additional}", "hashtag.column_header.tag_mode.none": "ohne {additional}", @@ -360,7 +360,7 @@ "keyboard_shortcuts.requests": "Liste der Follower-Anfragen aufrufen", "keyboard_shortcuts.search": "Suchleiste fokussieren", "keyboard_shortcuts.spoilers": "Feld für Inhaltswarnung anzeigen/ausblenden", - "keyboard_shortcuts.start": "„Auf geht's!“ öffnen", + "keyboard_shortcuts.start": "„Auf geht’s!“ öffnen", "keyboard_shortcuts.toggle_hidden": "Beitragstext hinter der Inhaltswarnung anzeigen/ausblenden", "keyboard_shortcuts.toggle_sensitivity": "Medien anzeigen/ausblenden", "keyboard_shortcuts.toot": "Neuen Beitrag erstellen", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 2eace137c1..6b4258a6bc 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -113,6 +113,7 @@ "column.direct": "Privataj mencioj", "column.directory": "Foliumi la profilojn", "column.domain_blocks": "Blokitaj domajnoj", + "column.favourites": "Stelumoj", "column.firehose": "Vivantaj fluoj", "column.follow_requests": "Petoj de sekvado", "column.home": "Hejmo", @@ -136,6 +137,7 @@ "compose.language.search": "Serĉi lingvojn...", "compose.published.body": "Afiŝo publikigita.", "compose.published.open": "Malfermi", + "compose.saved.body": "Afiŝo konservita.", "compose_form.direct_message_warning_learn_more": "Lerni pli", "compose_form.encryption_warning": "La afiŝoj en Mastodon ne estas tutvoje ĉifritaj. Ne kunhavigu tiklajn informojn ĉe Mastodon.", "compose_form.hashtag_warning": "Ĉi tiu afiŝo ne estos listigita en neniu kradvorto ĉar ĝi ne estas publika. Nur publikaj afiŝoj povas esti serĉitaj per kradvortoj.", @@ -180,6 +182,7 @@ "confirmations.mute.explanation": "Tio kaŝos la mesaĝojn de la uzanto kaj la mesaĝojn kiuj mencias rin, sed ri ankoraŭ rajtos vidi viajn mesaĝojn kaj sekvi vin.", "confirmations.mute.message": "Ĉu vi certas, ke vi volas silentigi {name}?", "confirmations.redraft.confirm": "Forigi kaj reskribi", + "confirmations.redraft.message": "Ĉu vi certas ke vi volas forigi tiun afiŝon kaj reskribi ĝin? Ĉiuj diskonigoj kaj stelumoj estos perditaj, kaj respondoj al la originala mesaĝo estos senparentaj.", "confirmations.reply.confirm": "Respondi", "confirmations.reply.message": "Respondi nun anstataŭigos la skribatan afiŝon. Ĉu vi certas, ke vi volas daŭrigi?", "confirmations.unfollow.confirm": "Ne plu sekvi", @@ -548,6 +551,7 @@ "search.search_or_paste": "Serĉu aŭ algluu URL-on", "search_popout.quick_actions": "Rapidaj agoj", "search_popout.recent": "Lastaj serĉoj", + "search_popout.user": "uzanto", "search_results.accounts": "Profiloj", "search_results.all": "Ĉiuj", "search_results.hashtags": "Kradvortoj", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 5d32464ba1..5684ec4873 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -379,7 +379,7 @@ "lists.delete": "Borrar lista", "lists.edit": "Editar lista", "lists.edit.submit": "Cambiar título", - "lists.exclusive": "Ocultar estas publicaciones en inicio", + "lists.exclusive": "Ocultar estas publicaciones de inicio", "lists.new.create": "Añadir lista", "lists.new.title_placeholder": "Título de la nueva lista", "lists.replies_policy.followed": "Cualquier usuario seguido", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 4e8cd70938..c1b067cff8 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -15,13 +15,13 @@ "account.add_or_remove_from_list": "افزودن یا برداشتن از سیاهه‌ها", "account.badges.bot": "روبات", "account.badges.group": "گروه", - "account.block": "مسدود کردن ‎@{name}", - "account.block_domain": "مسدود کردن دامنهٔ {domain}", + "account.block": "انسداد ‎@{name}", + "account.block_domain": "انسداد دامنهٔ {domain}", "account.block_short": "انسداد", - "account.blocked": "مسدود شده", + "account.blocked": "مسدود", "account.browse_more_on_origin_server": "مرور بیش‌تر روی نمایهٔ اصلی", "account.cancel_follow_request": "رد کردن درخواست پی‌گیری", - "account.direct": "خصوصی از @{name} نام ببرید", + "account.direct": "اشارهٔ خصوصی به ‪@{name}‬", "account.disable_notifications": "آگاه کردن من هنگام فرسته‌های ‎@{name} را متوقّف کن", "account.domain_blocked": "دامنه مسدود شد", "account.edit_profile": "ویرایش نمایه", @@ -46,7 +46,7 @@ "account.link_verified_on": "مالکیت این پیوند در {date} بررسی شد", "account.locked_info": "این حساب خصوصی است. صاحبش تصمیم می‌گیرد که چه کسی پی‌گیرش باشد.", "account.media": "رسانه", - "account.mention": "نام‌بردن از ‎@{name}", + "account.mention": "اشاره به ‎@{name}", "account.moved_to": "{name} نشان داده که حساب جدیدش این است:", "account.mute": "خموشاندن ‎@{name}", "account.mute_notifications_short": "خموشی آگاهی‌ها", @@ -110,7 +110,7 @@ "column.blocks": "کاربران مسدود شده", "column.bookmarks": "نشانک‌ها", "column.community": "خط زمانی محلّی", - "column.direct": "خصوصی نام ببرید", + "column.direct": "اشاره‌های خصوصی", "column.directory": "مرور نمایه‌ها", "column.domain_blocks": "دامنه‌های مسدود شده", "column.favourites": "برگزیده‌ها", @@ -137,6 +137,7 @@ "compose.language.search": "جست‌وجوی زبان‌ها…", "compose.published.body": "فرسته منتشر شد.", "compose.published.open": "گشودن", + "compose.saved.body": "فرسته ذخیره شد.", "compose_form.direct_message_warning_learn_more": "بیشتر بدانید", "compose_form.encryption_warning": "فرسته‌های ماستودون رمزگذاری سرتاسری نشده‌اند. هیچ اطّلاعات حساسی را روی ماستودون هم‌رسانی نکنید.", "compose_form.hashtag_warning": "از آن‌جا که این فرسته عمومی نیست زیر هیچ برچسبی سیاهه نخواهد شد. تنها فرسته‌های عمومی می‌توانند با برچسب جست‌وجو شوند.", @@ -147,7 +148,7 @@ "compose_form.poll.duration": "مدت نظرسنجی", "compose_form.poll.option_placeholder": "گزینهٔ {number}", "compose_form.poll.remove_option": "برداشتن این گزینه", - "compose_form.poll.switch_to_multiple": "تبدیل به نظرسنجی چندگزینه‌ای", + "compose_form.poll.switch_to_multiple": "تغییر نظرسنجی برای اجازه به چندین گزینه", "compose_form.poll.switch_to_single": "تبدیل به نظرسنجی تک‌گزینه‌ای", "compose_form.publish": "انتشار", "compose_form.publish_form": "انتشار", @@ -160,8 +161,8 @@ "compose_form.spoiler.unmarked": "افزودن هشدار محتوا", "compose_form.spoiler_placeholder": "هشدارتان را این‌جا بنویسید", "confirmation_modal.cancel": "لغو", - "confirmations.block.block_and_report": "مسدود کردن و گزارش", - "confirmations.block.confirm": "مسدود کردن", + "confirmations.block.block_and_report": "انسداد و گزارش", + "confirmations.block.confirm": "انسداد", "confirmations.block.message": "مطمئنید که می‌خواهید {name} را مسدود کنید؟", "confirmations.cancel_follow_request.confirm": "رد کردن درخواست", "confirmations.cancel_follow_request.message": "مطمئنید که می خواهید درخواست پی‌گیری {name} را لغو کنید؟", @@ -171,7 +172,7 @@ "confirmations.delete_list.message": "مطمئنید می‌خواهید این سیاهه را برای همیشه حذف کنید؟", "confirmations.discard_edit_media.confirm": "دور انداختن", "confirmations.discard_edit_media.message": "تغییرات ذخیره نشده‌ای در توضیحات یا پیش‌نمایش رسانه دارید. همگی نادیده گرفته شوند؟", - "confirmations.domain_block.confirm": "مسدود کردن تمام دامنه", + "confirmations.domain_block.confirm": "انسداد تمام دامنه", "confirmations.domain_block.message": "آیا جدی جدی می‌خواهید تمام دامنهٔ {domain} را مسدود کنید؟ در بیشتر موارد مسدود کردن یا خموشاندن چند حساب خاص کافی است و توصیه می‌شود. پس از این کار شما هیچ محتوایی را از این دامنه در خط زمانی عمومی یا آگاهی‌هایتان نخواهید دید. پی‌گیرانتان از این دامنه هم برداشته خواهند شد.", "confirmations.edit.confirm": "ویرایش", "confirmations.edit.message": "در صورت ویرایش، پیامی که در حال نوشتنش بودید از بین خواهد رفت. می‌خواهید ادامه دهید؟", @@ -181,6 +182,7 @@ "confirmations.mute.explanation": "این کار فرسته‌های آن‌ها و فرسته‌هایی را که از آن‌ها نام برده پنهان می‌کند، ولی آن‌ها همچنان اجازه دارند فرسته‌های شما را ببینند و شما را پی‌گیری کنند.", "confirmations.mute.message": "مطمئنید می‌خواهید {name} را بخموشانید؟", "confirmations.redraft.confirm": "حذف و بازنویسی", + "confirmations.redraft.message": "مطمئنید که می‌خواهید این فرسته را حذف کنید و از نو بنویسید؟ با این کار تقویت‌ها و پسندهایش از دست رفته و پاسخ‌ها به آن بی‌مرجع می‌شود.", "confirmations.reply.confirm": "پاسخ", "confirmations.reply.message": "اگر الان پاسخ دهید، چیزی که در حال نوشتنش بودید پاک خواهد شد. می‌خواهید ادامه دهید؟", "confirmations.unfollow.confirm": "پی‌نگرفتن", @@ -294,16 +296,23 @@ "hashtag.column_settings.tag_mode.any": "هرکدام از این‌ها", "hashtag.column_settings.tag_mode.none": "هیچ‌کدام از این‌ها", "hashtag.column_settings.tag_toggle": "افزودن برچسب‌هایی بیشتر به این ستون", + "hashtag.counter_by_accounts": "{count, plural, one {{counter} مشارکت کننده} other {{counter} مشارکت کننده}}", + "hashtag.counter_by_uses": "{count, plural, one {{counter} فرسته} other {{counter} فرسته}}", "hashtag.counter_by_uses_today": "{count, plural, one {{counter} فرسته} other {{counter} فرسته}} امروز", "hashtag.follow": "پی‌گرفتن برچسب", "hashtag.unfollow": "پی‌نگرفتن برچسب", + "hashtags.and_other": "…و {count, plural, other {# بیش‌تر}}", "home.actions.go_to_explore": "ببینید چه داغ است", "home.actions.go_to_suggestions": "یافتن افراد برای پی‌گیری", "home.column_settings.basic": "پایه‌ای", "home.column_settings.show_reblogs": "نمایش تقویت‌ها", "home.column_settings.show_replies": "نمایش پاسخ‌ها", + "home.explore_prompt.body": "خوراک خانگیتان ترکیبی از فرسته‌ها از برچسب‌هایی که برای پی‌گیری گزیده‌اید، افرادی که پی می‌گیرید و فرسته‌هایی که تقویت می‌کنند را خواهد داشت. اگر خیلی خلوت به نظر می‌رسد،‌ شاید بخواهید:", "home.explore_prompt.title": "این پایگاه خانگیتان در ماستودون است.", "home.hide_announcements": "نهفتن اعلامیه‌ها", + "home.pending_critical_update.body": "لطفاً کارساز ماستودونتان را در نخستین فرصت به‌روز کنید!", + "home.pending_critical_update.link": "دیدن به‌روز رسانی‌ها", + "home.pending_critical_update.title": "به‌روز رسانی امنیتی بحرانی موجود است!", "home.show_announcements": "نمایش اعلامیه‌ها", "interaction_modal.description.favourite": "با حسابی روی ماستودون می‌توانید این فرسته را برگزیده تا نگارنده بداند قدردانش هستید و برای آینده ذخیره‌اش می‌کنید.", "interaction_modal.description.follow": "با حسابی روی ماستودون می‌توانید {name} را برای دریافت فرسته‌هایش در خوراک خانگیتان دنبال کنید.", @@ -314,6 +323,8 @@ "interaction_modal.no_account_yet": "در ماستودون نیست؟", "interaction_modal.on_another_server": "روی کارسازی دیگر", "interaction_modal.on_this_server": "روی این کارساز", + "interaction_modal.sign_in": "شما در این کارساز وارد نشده‌اید. حسابتان کجا میزبانی شده؟", + "interaction_modal.sign_in_hint": "نکته: میزبانتان، پایگاه وبیست که رویش ثبت‌نام کرده‌اید. اگر به خاطر نمی‌آورید، به رایانامهٔ خوش‌آمد در صندوق ورودیتان بنگرید. همچنین می‌توانید نام کاربری کاملتان (چون ‪@Mastodon@mastodon.social‬) را وارد کنید!", "interaction_modal.title.favourite": "فرسته‌های برگزیدهٔ {name}", "interaction_modal.title.follow": "پیگیری {name}", "interaction_modal.title.reblog": "تقویت فرستهٔ {name}", @@ -330,6 +341,7 @@ "keyboard_shortcuts.direct": "باز کردن ستون اشاره‌های خصوصی", "keyboard_shortcuts.down": "پایین بردن در سیاهه", "keyboard_shortcuts.enter": "گشودن فرسته", + "keyboard_shortcuts.favourite": "پسندیدن فرسته", "keyboard_shortcuts.favourites": "گشودن فهرست برگزیده‌ها", "keyboard_shortcuts.federated": "گشودن خط زمانی همگانی", "keyboard_shortcuts.heading": "میان‌برهای صفحه‌کلید", @@ -337,7 +349,7 @@ "keyboard_shortcuts.hotkey": "میان‌بر", "keyboard_shortcuts.legend": "نمایش این نشانه", "keyboard_shortcuts.local": "گشودن خط زمانی محلّی", - "keyboard_shortcuts.mention": "نام‌بردن نویسنده", + "keyboard_shortcuts.mention": "اشاره به نویسنده", "keyboard_shortcuts.muted": "گشودن فهرست کاربران خموش", "keyboard_shortcuts.my_profile": "گشودن نمایه‌تان", "keyboard_shortcuts.notifications": "گشودن ستون آگاهی‌ها", @@ -361,7 +373,7 @@ "lightbox.previous": "قبلی", "limited_account_hint.action": "به هر روی نمایه نشان داده شود", "limited_account_hint.title": "این نمایه از سوی ناظم‌های {domain} پنهان شده.", - "link_preview.author": "بر اساس {name}", + "link_preview.author": "از {name}", "lists.account.add": "افزودن به سیاهه", "lists.account.remove": "برداشتن از سیاهه", "lists.delete": "حذف سیاهه", @@ -402,6 +414,7 @@ "navigation_bar.lists": "سیاهه‌ها", "navigation_bar.logout": "خروج", "navigation_bar.mutes": "کاربران خموشانده", + "navigation_bar.opened_in_classic_interface": "فرسته‌ها، حساب‌ها و دیگر صفحه‌های خاص به طور پیش‌گزیده در میانای وب کلاسیک گشوده می‌شوند.", "navigation_bar.personal": "شخصی", "navigation_bar.pins": "فرسته‌های سنجاق شده", "navigation_bar.preferences": "ترجیحات", @@ -411,11 +424,11 @@ "not_signed_in_indicator.not_signed_in": "برای دسترسی به این منبع باید وارد شوید.", "notification.admin.report": "{name}، {target} را گزارش داد", "notification.admin.sign_up": "{name} ثبت نام کرد", - "notification.favourite": "{name} نوشتهٔ شما را پسندید", + "notification.favourite": "{name} فرسته‌تان را برگزید", "notification.follow": "‫{name}‬ پی‌گیرتان شد", - "notification.follow_request": "{name} می‌خواهد پی‌گیر شما باشد", - "notification.mention": "‫{name}‬ از شما نام برد", - "notification.own_poll": "نظرسنجی شما به پایان رسید", + "notification.follow_request": "{name} درخواست پی‌گیریتان را داد", + "notification.mention": "‫{name}‬ به شما اشاره کرد", + "notification.own_poll": "نظرسنجیتان پایان یافت", "notification.poll": "نظرسنجی‌ای که در آن رأی دادید به پایان رسیده است", "notification.reblog": "‫{name}‬ فرسته‌تان را تقویت کرد", "notification.status": "{name} چیزی فرستاد", @@ -431,7 +444,7 @@ "notifications.column_settings.filter_bar.show_bar": "نمایش نوار پالایه", "notifications.column_settings.follow": "پی‌گیرندگان جدید:", "notifications.column_settings.follow_request": "درخواست‌های جدید پی‌گیری:", - "notifications.column_settings.mention": "نام‌بردن‌ها:", + "notifications.column_settings.mention": "اشاره‌ها:", "notifications.column_settings.poll": "نتایج نظرسنجی:", "notifications.column_settings.push": "آگاهی‌های ارسالی", "notifications.column_settings.reblog": "تقویت‌ها:", @@ -445,7 +458,7 @@ "notifications.filter.boosts": "تقویت‌ها", "notifications.filter.favourites": "برگزیده‌ها", "notifications.filter.follows": "پی‌گرفتگان", - "notifications.filter.mentions": "نام‌بردن‌ها", + "notifications.filter.mentions": "اشاره‌ها", "notifications.filter.polls": "نتایج نظرسنجی", "notifications.filter.statuses": "به‌روز رسانی‌ها از کسانی که پی‌گیرشانید", "notifications.grant_permission": "اعطای مجوز.", @@ -480,10 +493,10 @@ "onboarding.steps.setup_profile.title": "Customize your profile", "onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!", "onboarding.steps.share_profile.title": "Share your profile", - "onboarding.tips.2fa": "آیا میدانستید؟ شما می‌توانید با رفتن به تنظیمات حساب و فعال کردن احراز هویت دوعاملی، حساب خود را ایمن کنید؟ این قابلیت با هر نرم‌افزار TOTP دلخواه شما کار مي‌کند و نیازی به شماره تلفن ندارد!", - "onboarding.tips.accounts_from_other_servers": "آیا می‌دانستید؟ چون ماستودون نامتمرکز است، بعضی از پروفایل‌هایی که با آنها برخورد می‌کنید درواقع روی کارساز هایی متفاوت از کارساز شما میزبانی می‌شوند. و شما همچنان می‌توانید با آنها به شکل راحت و روان تعامل کنید! کارساز آن‌ها در نیمه دوم نام کاربری‌شان است!", - "onboarding.tips.migration": "آیا می‌دانستید؟ اگر احساس می‌کنید {domain} انتخاب کارساز خوبی برای آینده‌تان نیست، می‌توانید بدون از دست دادن پیگیرهایتان به یک کارساز ماستودون دیگر مهاجرت کنید. شما حتی می‌توانید کارساز خودتان را میزبانی کنید!", - "onboarding.tips.verification": "آیا می‌دانستید؟ شما می‌توانید حساب خود را با قراردادن پیوندی به نمایه ماستودون‌تان روی وبسایت خود، و اضافه کردن وبسایت‌تان به نمایه خود تایید کنید. بدون نیاز به هیچ کارمزد یا سندی!", + "onboarding.tips.2fa": "آیا می‌دانستید؟ می‌توانید با پریایی هویت‌سنجی دو عاملی در تنظیمات حساب، حسابتان را ایمن کنید؟ این قابلیت با هر نرم‌افزار TOTP دلخواه کار کرده و نیازی به شماره تلفن ندارد!", + "onboarding.tips.accounts_from_other_servers": "آیا می‌دانستید؟ از آن‌جا که ماستودون نامتمرکز است، برخی نمایه‌ها که به آن‌ها برمی‌خورید روی کارسازهایی متفاوت از شما میزبانی می‌شوند و باز هم می‌توانید بدون مشکل با آن‌ها تعامل داشته باشید! کارسازشان در نیمه دوم نام کاربریشان است!", + "onboarding.tips.migration": "آیا می‌دانستید؟ اگر احساس می‌کنید {domain} انتخاب کارساز خوبی برای آینده‌تان نیست، می‌توانید بدون از دست دادن پیگیرهایتان به کارساز ماستودون دیگری مهاجرت کنید. حتا می‌توانید کارساز خودتان را میزبانی کنید!", + "onboarding.tips.verification": "آیا می‌دانستید؟ می‌توانید حسابتان را با گذاشتن پیوندی به نمایهٔ ماستودونتان روی پایگاه وب خود و افزودن پایگاه وبتان به نمایه‌تان تأیید کنید. بدون نیاز به هیچ کارمزد یا سندی!", "password_confirmation.exceeds_maxlength": "تأییدیه گذرواژه از حداکثر طول گذرواژه بیشتر است", "password_confirmation.mismatching": "تایید گذرواژه با گذرواژه مطابقت ندارد", "picture_in_picture.restore": "برگرداندن", @@ -523,8 +536,9 @@ "relative_time.seconds": "{number} ثانیه", "relative_time.today": "امروز", "reply_indicator.cancel": "لغو", - "report.block": "مسدود کردن", + "report.block": "انسداد", "report.block_explanation": "شما فرسته‌هایشان را نخواهید دید. آن‌ها نمی‌توانند فرسته‌هایتان را ببینند یا شما را پی‌بگیرند. آنها می‌توانند بگویند که مسدود شده‌اند.", + "report.categories.legal": "حقوقی", "report.categories.other": "غیره", "report.categories.spam": "هرزنامه", "report.categories.violation": "محتوا یک یا چند قانون کارساز را نقض می‌کند", @@ -576,12 +590,18 @@ "search.quick_action.open_url": "باز کردن پیوند در ماستودون", "search.quick_action.status_search": "فرسته‌های جور با {x}", "search.search_or_paste": "جست‌وجو یا جایگذاری نشانی", + "search_popout.full_text_search_disabled_message": "روی {domain} موجود نیست.", + "search_popout.language_code": "کد زبان ایزو", + "search_popout.options": "گزینه‌های جست‌وجو", "search_popout.quick_actions": "کنش‌های سریع", "search_popout.recent": "جست‌وجوهای اخیر", + "search_popout.specific_date": "تاریخ مشخص", + "search_popout.user": "کاربر", "search_results.accounts": "نمایه‌ها", "search_results.all": "همه", "search_results.hashtags": "برچسب‌ها", "search_results.nothing_found": "چیزی برای این عبارت جست‌وجو یافت نشد", + "search_results.see_all": "دیدن همه", "search_results.statuses": "فرسته‌ها", "search_results.title": "جست‌وجو برای {q}", "server_banner.about_active_users": "افرادی که در ۳۰ روز گذشته از این کارساز استفاده کرده‌اند (کاربران فعّال ماهانه)", @@ -597,15 +617,15 @@ "status.admin_account": "گشودن واسط مدیریت برای ‎@{name}", "status.admin_domain": "گشودن واسط مدیریت برای ‎{domain}", "status.admin_status": "گشودن این فرسته در واسط مدیریت", - "status.block": "مسدود کردن ‎@{name}", + "status.block": "انسداد ‎@{name}", "status.bookmark": "نشانک", "status.cancel_reblog_private": "ناتقویت", "status.cannot_reblog": "این فرسته قابل تقویت نیست", "status.copy": "رونوشت از پیوند فرسته", "status.delete": "حذف", "status.detailed_status": "نمایش کامل گفتگو", - "status.direct": "خصوصی به @{name} اشاره کنید", - "status.direct_indicator": "اشاره خصوصی", + "status.direct": "اشارهٔ خصوصی به ‪@{name}‬", + "status.direct_indicator": "اشارهٔ خصوصی", "status.edit": "ویرایش", "status.edited": "ویرایش شده در {date}", "status.edited_x_times": "{count, plural, one {{count} مرتبه} other {{count} مرتبه}} ویرایش شد", @@ -620,7 +640,7 @@ "status.media.open": "کلیک برای گشودن", "status.media.show": "کلیک برای نمایش", "status.media_hidden": "رسانهٔ نهفته", - "status.mention": "نام‌بردن از ‎@{name}", + "status.mention": "اشاره به ‎@{name}", "status.more": "بیشتر", "status.mute": "خموشاندن ‎@{name}", "status.mute_conversation": "خموشاندن گفت‌وگو", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 16fca0a288..9471918543 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -20,7 +20,7 @@ "account.block_short": "Bloquer", "account.blocked": "Bloqué·e", "account.browse_more_on_origin_server": "Parcourir davantage sur le profil original", - "account.cancel_follow_request": "Retirer la demande d’abonnement", + "account.cancel_follow_request": "Annuler le suivi", "account.direct": "Mention privée @{name}", "account.disable_notifications": "Ne plus me notifier quand @{name} publie quelque chose", "account.domain_blocked": "Domaine bloqué", @@ -50,7 +50,7 @@ "account.moved_to": "{name} a indiqué que son nouveau compte est maintenant :", "account.mute": "Masquer @{name}", "account.mute_notifications_short": "Désactiver les alertes", - "account.mute_short": "Masquer", + "account.mute_short": "Mettre en sourdine", "account.muted": "Masqué·e", "account.no_bio": "Aucune description fournie.", "account.open_original_page": "Ouvrir la page d'origine", @@ -108,7 +108,7 @@ "closed_registrations_modal.title": "Inscription sur Mastodon", "column.about": "À propos", "column.blocks": "Comptes bloqués", - "column.bookmarks": "Signets", + "column.bookmarks": "Marque-pages", "column.community": "Fil public local", "column.direct": "Mentions privées", "column.directory": "Parcourir les profils", @@ -149,9 +149,9 @@ "compose_form.poll.option_placeholder": "Choix {number}", "compose_form.poll.remove_option": "Supprimer ce choix", "compose_form.poll.switch_to_multiple": "Changer le sondage pour autoriser plusieurs choix", - "compose_form.poll.switch_to_single": "Changer le sondage pour autoriser qu'un seul choix", + "compose_form.poll.switch_to_single": "Modifier le sondage pour autoriser qu'un seul choix", "compose_form.publish": "Publier", - "compose_form.publish_form": "Publier", + "compose_form.publish_form": "Nouvelle publication", "compose_form.publish_loud": "{publish} !", "compose_form.save_changes": "Enregistrer les modifications", "compose_form.sensitive.hide": "{count, plural, one {Marquer le média comme sensible} other {Marquer les médias comme sensibles}}", diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json index fa202a5e86..ea1ce59e84 100644 --- a/app/javascript/mastodon/locales/gd.json +++ b/app/javascript/mastodon/locales/gd.json @@ -683,9 +683,9 @@ "time_remaining.moments": "Cha doir e ach greiseag", "time_remaining.seconds": "{number, plural, one {# diog} two {# dhiog} few {# diogan} other {# diog}} air fhàgail", "timeline_hint.remote_resource_not_displayed": "Cha dèid {resource} o fhrithealaichean eile a shealltainn.", - "timeline_hint.resources.followers": "Luchd-leantainn", - "timeline_hint.resources.follows": "A’ leantainn", - "timeline_hint.resources.statuses": "Postaichean nas sine", + "timeline_hint.resources.followers": "luchd-leantainn", + "timeline_hint.resources.follows": "an fheadhainn gan leantainn", + "timeline_hint.resources.statuses": "postaichean nas sine", "trends.counter_by_accounts": "{count, plural, one {{counter} neach} two {{counter} neach} few {{counter} daoine} other {{counter} duine}} {days, plural, one {san {days} latha} two {san {days} latha} few {sna {days} làithean} other {sna {days} latha}} seo chaidh", "trends.trending_now": "A’ treandadh an-dràsta", "ui.beforeunload": "Caillidh tu an dreachd agad ma dh’fhàgas tu Mastodon an-dràsta.", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 2919c74b48..b5d9e50f65 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -135,7 +135,7 @@ "community.column_settings.remote_only": "Só remoto", "compose.language.change": "Elixe o idioma", "compose.language.search": "Buscar idiomas...", - "compose.published.body": "Publicación publicada.", + "compose.published.body": "Mensaxe publicada.", "compose.published.open": "Abrir", "compose.saved.body": "Publicación gardada.", "compose_form.direct_message_warning_learn_more": "Saber máis", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 37c3990e49..5b37324f7d 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -487,7 +487,7 @@ "onboarding.start.title": "해내셨군요!", "onboarding.steps.follow_people.body": "흥미로운 사람들을 팔로우하는 것은 마스토돈의 전부입니다.", "onboarding.steps.follow_people.title": "내게 맞는 홈 피드 꾸미기", - "onboarding.steps.publish_status.body": "글, 사진, 영상, 투표 또는 {emoji}와 함께 세상에 인사해보세요.", + "onboarding.steps.publish_status.body": "글, 사진, 영상, 설문 또는 {emoji}와 함께 세상에 인사해보세요.", "onboarding.steps.publish_status.title": "첫번째 게시물 쓰기", "onboarding.steps.setup_profile.body": "의미있는 프로필을 작성해 상호작용을 늘려보세요.", "onboarding.steps.setup_profile.title": "프로필 꾸미기", @@ -695,7 +695,7 @@ "upload_area.title": "드래그 & 드롭으로 업로드", "upload_button.label": "이미지, 영상, 오디오 파일 추가", "upload_error.limit": "파일 업로드 제한에 도달했습니다.", - "upload_error.poll": "파일 업로드는 투표와 함께 쓸 수 없습니다.", + "upload_error.poll": "파일 업로드는 설문과 함께 쓸 수 없어요.", "upload_form.audio_description": "청각 장애인을 위한 설명", "upload_form.description": "시각장애인을 위한 설명", "upload_form.description_missing": "설명이 추가되지 않음", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 4bf1979b9d..87a2af4f20 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -379,7 +379,7 @@ "lists.delete": "Lijst verwijderen", "lists.edit": "Lijst bewerken", "lists.edit.submit": "Titel veranderen", - "lists.exclusive": "Verberg deze berichten op je startpagina", + "lists.exclusive": "Verberg deze berichten op je starttijdlijn", "lists.new.create": "Lijst toevoegen", "lists.new.title_placeholder": "Naam nieuwe lijst", "lists.replies_policy.followed": "Elke gevolgde gebruiker", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index a670fd2e4f..449fdfb1a1 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -310,6 +310,7 @@ "home.explore_prompt.body": "Tidslinjen din inneholder en blanding av innlegg fra emneknagger du har valgt å følge, personene du har valgt å følge, og innleggene de fremhever. Hvis det føles for stille, kan det være lurt å:", "home.explore_prompt.title": "Dette er hjemmet ditt i Mastodon.", "home.hide_announcements": "Skjul kunngjøring", + "home.pending_critical_update.body": "Vennligst oppdater Mastodon-serveren din så snart som mulig!", "home.pending_critical_update.link": "Se oppdateringer", "home.pending_critical_update.title": "Kritisk sikkerhetsoppdatering er tilgjengelig!", "home.show_announcements": "Vis kunngjøring", @@ -413,6 +414,7 @@ "navigation_bar.lists": "Lister", "navigation_bar.logout": "Logg ut", "navigation_bar.mutes": "Dempede brukere", + "navigation_bar.opened_in_classic_interface": "Innlegg, kontoer og andre spesifikke sider åpnes som standard i det klassiske webgrensesnittet.", "navigation_bar.personal": "Personlig", "navigation_bar.pins": "Festede innlegg", "navigation_bar.preferences": "Innstillinger", @@ -588,6 +590,7 @@ "search.quick_action.open_url": "Åpne URL i Mastodon", "search.quick_action.status_search": "Innlegg som samsvarer med {x}", "search.search_or_paste": "Søk eller lim inn URL", + "search_popout.full_text_search_disabled_message": "Ikke tilgjengelig på {domain}.", "search_popout.language_code": "ISO språkkode", "search_popout.options": "Alternativer for søk", "search_popout.quick_actions": "Hurtighandlinger", @@ -598,6 +601,7 @@ "search_results.all": "Alle", "search_results.hashtags": "Emneknagger", "search_results.nothing_found": "Fant ikke noe for disse søkeordene", + "search_results.see_all": "Se alle", "search_results.statuses": "Innlegg", "search_results.title": "Søk etter {q}", "server_banner.about_active_users": "Personer som har brukt denne serveren i løpet av de siste 30 dagene (aktive brukere månedlig)", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 6c08f899a4..bd1252b47f 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -47,7 +47,7 @@ "account.locked_info": "Stav súkromia pre tento účet je nastavený na zamknutý. Jeho vlastník sám prehodnocuje, kto ho môže sledovať.", "account.media": "Médiá", "account.mention": "Spomeň @{name}", - "account.moved_to": "{name} uvádza, že jeho/jej nový účet je:", + "account.moved_to": "{name} uvádza, že jeho/jej nový účet je teraz:", "account.mute": "Nevšímaj si @{name}", "account.mute_notifications_short": "Stíš oboznámenia", "account.mute_short": "Nevšímaj si", @@ -303,6 +303,7 @@ "home.column_settings.basic": "Základné", "home.column_settings.show_reblogs": "Ukáž vyzdvihnuté", "home.column_settings.show_replies": "Ukáž odpovede", + "home.explore_prompt.title": "Toto je tvoja domovina v rámci Mastodonu.", "home.hide_announcements": "Skry oboznámenia", "home.pending_critical_update.body": "Prosím aktualizuj si svoj Mastodon server, ako náhle to bude možné!", "home.pending_critical_update.link": "Pozri aktualizácie", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 5c2417274a..3a7e75b912 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -341,8 +341,8 @@ "keyboard_shortcuts.direct": "mở mục nhắn riêng", "keyboard_shortcuts.down": "di chuyển xuống dưới danh sách", "keyboard_shortcuts.enter": "viết tút mới", - "keyboard_shortcuts.favourite": "Thích tút", - "keyboard_shortcuts.favourites": "Mở lượt thích", + "keyboard_shortcuts.favourite": "thích tút", + "keyboard_shortcuts.favourites": "mở lượt thích", "keyboard_shortcuts.federated": "mở mạng liên hợp", "keyboard_shortcuts.heading": "Danh sách phím tắt", "keyboard_shortcuts.home": "mở trang chính", @@ -557,7 +557,7 @@ "report.reasons.dislike": "Tôi không thích nó", "report.reasons.dislike_description": "Đó không phải là thứ gì mà bạn muốn thấy", "report.reasons.legal": "Vi phạm pháp luật", - "report.reasons.legal_description": "Bạn tin rằng nó vi phạm pháp luật ở nơi đặt máy chủ hoặc nước bạn", + "report.reasons.legal_description": "Vi phạm pháp luật ở nơi đặt máy chủ hoặc nước bạn", "report.reasons.other": "Một lý do khác", "report.reasons.other_description": "Vấn đề không nằm trong những mục trên", "report.reasons.spam": "Đây là spam", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 51c8e3f374..c311b5ae33 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -137,7 +137,7 @@ "compose.language.search": "搜索语言...", "compose.published.body": "嘟文已发布。", "compose.published.open": "打开", - "compose.saved.body": "帖子已保存。", + "compose.saved.body": "嘟文已保存。", "compose_form.direct_message_warning_learn_more": "详细了解", "compose_form.encryption_warning": "Mastodon 上的嘟文未经端到端加密。请勿在 Mastodon 上分享敏感信息。", "compose_form.hashtag_warning": "这条嘟文被设置为“不公开”,因此它不会出现在任何话题标签的列表下。只有公开的嘟文才能通过话题标签进行搜索。", @@ -199,7 +199,7 @@ "directory.recently_active": "最近活跃", "disabled_account_banner.account_settings": "账号设置", "disabled_account_banner.text": "您的账号 {disabledAccount} 目前已被禁用。", - "dismissable_banner.community_timeline": "这些是来自 {domain} 用户的最新公共嘟文。", + "dismissable_banner.community_timeline": "这些是来自 {domain} 用户的最新公开嘟文。", "dismissable_banner.dismiss": "忽略", "dismissable_banner.explore_links": "这些新闻故事正被本站和分布式网络上其他站点的用户谈论。", "dismissable_banner.explore_statuses": "这些是目前在社交网络上引起关注的嘟文。嘟文的喜欢和转嘟次数越多,排名越高。", @@ -414,7 +414,7 @@ "navigation_bar.lists": "列表", "navigation_bar.logout": "退出登录", "navigation_bar.mutes": "已隐藏的用户", - "navigation_bar.opened_in_classic_interface": "帖子、账户和其他特定页面默认在经典网页界面中打开。", + "navigation_bar.opened_in_classic_interface": "嘟文、账户和其他特定页面默认在经典网页界面中打开。", "navigation_bar.personal": "个人", "navigation_bar.pins": "置顶嘟文", "navigation_bar.preferences": "首选项", @@ -473,7 +473,7 @@ "onboarding.action.back": "带我返回", "onboarding.actions.back": "带我返回", "onboarding.actions.go_to_explore": "看看有什么新鲜事", - "onboarding.actions.go_to_home": "转到主页订阅流", + "onboarding.actions.go_to_home": "转到主页动态", "onboarding.compose.template": "你好 #Mastodon!", "onboarding.follows.empty": "很抱歉,现在无法显示任何结果。您可以尝试使用搜索或浏览探索页面来查找要关注的人,或稍后再试。", "onboarding.follows.lead": "你管理你自己的家庭饲料。你关注的人越多,它将越活跃和有趣。 这些配置文件可能是一个很好的起点——你可以随时取消关注它们!", @@ -575,7 +575,7 @@ "report.thanks.title": "不想看到这个内容?", "report.thanks.title_actionable": "感谢提交举报,我们将会进行处理。", "report.unfollow": "取消关注 @{name}", - "report.unfollow_explanation": "你正在关注此账户。如果要想在你的主页上不再看到他们的帖子,取消对他们的关注即可。", + "report.unfollow_explanation": "你正在关注此账户。如果不想继续在主页看到他们的嘟文,取消对他们的关注即可。", "report_notification.attached_statuses": "附上 {count} 条嘟文", "report_notification.categories.legal": "法律义务", "report_notification.categories.other": "其他", @@ -588,7 +588,7 @@ "search.quick_action.go_to_account": "前往 {x} 个人资料", "search.quick_action.go_to_hashtag": "前往标签 {x}", "search.quick_action.open_url": "在 Mastodon 中打开网址", - "search.quick_action.status_search": "匹配 {x} 的帖子", + "search.quick_action.status_search": "匹配 {x} 的嘟文", "search.search_or_paste": "搜索或输入网址", "search_popout.full_text_search_disabled_message": "在 {domain} 不可用", "search_popout.language_code": "ISO语言代码", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index 8725c35e89..e5de8daa9d 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -600,6 +600,7 @@ "search_results.all": "全部", "search_results.hashtags": "標籤", "search_results.nothing_found": "找不到與搜尋字詞相關的內容", + "search_results.see_all": "顯示全部", "search_results.statuses": "文章", "search_results.title": "搜尋 {q}", "server_banner.about_active_users": "在最近 30 天內內使用此伺服器的人 (月活躍用戶)", diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 694bdcc9c5..2cdf87d8fd 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -14,7 +14,7 @@ ca: following: Seguint instance_actor_flash: Aquest compte és un actor virtual usat per a representar el mateix servidor i no cap usuari individual. Es fa servir per a federar i no s'hauria d'esborrar. last_active: última activitat - link_verified_on: La propietat d'aquest enllaç s'ha verificat el %{date} + link_verified_on: La propietat d'aquest enllaç va quedar verificada el %{date} nothing_here: No hi ha res aquí! pin_errors: following: Has d'estar seguint la persona que vulguis avalar @@ -1464,7 +1464,7 @@ ca: action: Respon body: "%{name} t'ha mencionat en:" subject: "%{name} t'ha mencionat" - title: Menció nova + title: Nova menció poll: subject: Ha finalitzat l'enquesta de %{name} reblog: diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 95c980a6d4..03ec9708d5 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -315,6 +315,7 @@ cs: unpublish: Skrýt unpublished_msg: Zveřejněné oznámení bylo úspěšně skryto! updated_msg: Oznámení bylo úspěšně aktualizováno! + critical_update_pending: Čeká se na kritickou aktualizaci custom_emojis: assign_category: Přiřadit kategorii by_domain: Doména @@ -396,6 +397,15 @@ cs: undo: Zakázat federaci s doménou domain_blocks: add_new: Přidat novou blokaci domény + confirm_suspension: + cancel: Zrušit + confirm: Pozastavit + permanent_action: Zrušení pozastavení neobnoví žádná data ani vztah. + preamble_html: Chystáte se pozastavit %{domain} a jeho poddomény. + remove_all_data: Tímto odstraníte z vašeho serveru všechen obsah, média a profilové údaje účtů této domény. + stop_communication: Váš server přestane komunikovat s těmito servery. + title: Potvrďte blokování domény %{domain} + undo_relationships: Toto vrátí jakýkoliv vztah sledování mezi účty na těchto serverech a vaším. created_msg: Blokace domény se právě vyřizuje destroyed_msg: Blokace domény byla odvolána domain: Doména @@ -759,6 +769,9 @@ cs: branding: preamble: Značka vašeho serveru jej odlišuje od ostatních serverů v síti. Tyto informace se mohou zobrazovat v různých prostředích, například ve webovém rozhraní Mastodonu, v nativních aplikacích, v náhledech odkazů na jiných webových stránkách a v aplikacích pro zasílání zpráv atd. Z tohoto důvodu je nejlepší, aby tyto informace byly jasné, krátké a stručné. title: Značka + captcha_enabled: + desc_html: Toto spoléhá na externí skripty z hCaptcha, což může být budit obavy o bezpečnost a soukromí. Navíc to může způsobit, že proces registrace bude pro některé osoby (zejména se zdravotním postižením) hůře přístupný. Z těchto důvodů zvažte alternativní přístup, jako je schvalování registrace nebo pozvánky. + title: Vyžadovat po nových uživatelích, aby vyřešili CAPTCHU pro potvrzení jejich účtu content_retention: preamble: Určuje, jak je obsah generovaný uživatelem uložen v Mastodonu. title: Uchovávání obsahu @@ -786,9 +799,24 @@ cs: approved: Pro registraci je vyžadováno schválení none: Nikdo se nemůže registrovat open: Kdokoliv se může registrovat + security: + authorized_fetch: Vyžadovat autentizaci od federovaných serverů + authorized_fetch_overridden_hint: Momentálně nemůžete změnit toto nastavení, protože je přepsáno proměnnou prostředí. + title: Nastavení serveru site_uploads: delete: Odstranit nahraný soubor destroyed_msg: Upload stránky byl úspěšně smazán! + software_updates: + critical_update: Kritické — aktualizujte, prosím, co nejdříve + documentation_link: Zjistit více + release_notes: Poznámky k vydání + title: Dostupné aktualizace + type: Typ + types: + major: Hlavní vydání + minor: Menší vydání + patch: Záplatové vydání — opravy chyb a rychle aplikovatelné změny + version: Verze statuses: account: Autor application: Aplikace @@ -829,6 +857,20 @@ cs: system_checks: database_schema_check: message_html: Na spuštění čekají databázové migrace. Nechte je prosím proběhnout pro zajištění očekávaného chování aplikace + elasticsearch_health_red: + message_html: Elasticsearch cluster je nezdravý (červený stav), vyhledávací funkce jsou nedostupné + elasticsearch_health_yellow: + message_html: Elasticsearch cluster je nezdravý (žlutý stav), možná budete chtít prozkoumat důvod + elasticsearch_index_mismatch: + message_html: Mapování indexu Elasticsearch jsou zastaralá. Prosím spusťte tootctl search deploy --only=%{value} + elasticsearch_preset: + action: Prohlédnout dokumentaci + message_html: Váš Elasticsearch cluster má více než jeden node, ale Mastodon není nakonfigurován pro jejich používání. + elasticsearch_preset_single_node: + action: Zobrazit dokumentaci + message_html: Váš Elasticsearch cluster má pouze jeden uzel, ES_PRESET by měl být nastaven na single_node_cluster. + elasticsearch_reset_chewy: + message_html: Váš system index v Elasticsearch je kvůli změně nastavení zastaralý. Pro aktualizaci prosím spusťte tootctl search deploy --reset-chewy. elasticsearch_running_check: message_html: Nelze se připojit k Elasticsearch. Prosím zkontrolujte, že běží, nebo vypněte fulltextové vyhledávání elasticsearch_version_check: @@ -839,6 +881,12 @@ cs: message_html: Nedefinovali jste žádná pravidla serveru. sidekiq_process_check: message_html: Pro %{value} frontu/fronty neběží žádný Sidekiq proces. Zkontrolujte prosím svou Sidekiq konfiguraci + software_version_critical_check: + action: Zobrazit dostupné aktualizace + message_html: K dispozici je kritická aktualizace Mastodonu, prosím aktualizujte co nejrychleji. + software_version_patch_check: + action: Zobrazit dostupné aktualizace + message_html: Je dostupná opravná aktualizace Mastodonu. upload_check_privacy_error: action: Pro více informací se podívejte zde message_html: "Váš webový server je špatně nakonfigurován. Soukromí vašich uživatelů je ohroženo." @@ -960,6 +1008,9 @@ cs: body: 'Uživatel %{target} se odvolává proti rozhodnutí moderátora %{action_taken_by} z %{date}, kterým bylo %{type}. Napsal:' next_steps: Můžete schválit odvolání pro vrácení rozhodnutí moderátora, nebo to ignorovat. subject: Uživatel %{username} se odvolává proti rozhodnutí moderátora na %{instance} + new_critical_software_updates: + body: Byly vydány nové kritické verze Mastodonu, možná budete chtít aktualizovat co nejdříve! + subject: Pro %{instance} jsou dostupné kritické aktualizace Mastodonu! new_pending_account: body: Detaily nového účtu jsou uvedeny níže. Tuto žádost můžete schválit nebo zamítnout. subject: Nový účet na serveru %{instance} čekající na posouzení (%{username}) @@ -967,6 +1018,9 @@ cs: body: Uživatel %{reporter} nahlásil uživatele %{target} body_remote: Někdo z domény %{domain} nahlásil uživatele %{target} subject: Nové hlášení pro %{instance} (#%{id}) + new_software_updates: + body: Byly vydány nové verze Mastodonu, možná budete chtít aktualizovat! + subject: Pro %{instance} jsou dostupné nové verze Mastodonu! new_trends: body: 'Následující položky vyžadují posouzení, než mohou být zobrazeny veřejně:' new_trending_links: @@ -1000,6 +1054,7 @@ cs: notification_preferences: Změnit předvolby e-mailů salutation: "%{name}," settings: 'Změnit předvolby e-mailů: %{link}' + unsubscribe: Přestat odebírat view: 'Zobrazit:' view_profile: Zobrazit profil view_status: Zobrazit příspěvek @@ -1013,6 +1068,10 @@ cs: your_token: Váš přístupový token auth: apply_for_account: Požádat o účet + captcha_confirmation: + help_html: Pokud máte problémy s řešením CAPTCHA, můžete se s námi spojit prostřednictvím %{email} a můžeme vám pomoci. + hint_html: Ještě jedna věc! Musíme potvrdit, že jste člověk (to proto, abychom drželi stranou spam!). Vyřešte CAPTCHA níže a klikněte na "Pokračovat". + title: Bezpečnostní kontrola confirmations: wrong_email_hint: Pokud není e-mail správný, můžete si ho změnit v nastavení účtu. delete_account: Odstranit účet @@ -1049,8 +1108,11 @@ cs: rules: accept: Přijmout back: Zpět + invited_by: 'Můžete se připojit k %{domain} díky pozvánce, kterou jste obdrželi od:' preamble: Tohle nastavují a prosazují moderátoři %{domain}. + preamble_invited: Než budete pokračovat, vezměte prosím v úvahu základní pravidla stanovená moderátory %{domain}. title: Některá základní pravidla. + title_invited: Byl/a jsi pozván/a. security: Zabezpečení set_new_password: Nastavit nové heslo setup: @@ -1151,6 +1213,10 @@ cs: your_appeal_rejected: Vaše odvolání bylo zamítnuto domain_validator: invalid_domain: není platné doménové jméno + edit_profile: + basic_information: Základní informace + hint_html: "Nastavte si, co lidé uvidí na vašem veřejném profilu a vedle vašich příspěvků. Ostatní lidé vás budou spíše sledovat a komunikovat s vámi, když budete mít vyplněný profil a profilový obrázek." + other: Další errors: '400': Žádost, kterou jste odeslali, byla neplatná nebo poškozená. '403': Nejste oprávněni tuto stránku zobrazit. @@ -1306,6 +1372,7 @@ cs: bookmarks: Záložky domain_blocking: Seznam blokovaných domén following: Seznam sledovaných + lists: Seznamy muting: Seznam ignorovaných upload: Nahrát invites: @@ -1461,12 +1528,22 @@ cs: expired: Anketa již skončila invalid_choice: Zvolená možnost hlasování neexistuje over_character_limit: nesmí být žádná delší než %{max} znaků + self_vote: Nemůžete hlasovat ve svých vlastních anketách too_few_options: musí mít více než jednu položku too_many_options: nesmí obsahovat více než %{max} položek preferences: other: Ostatní posting_defaults: Výchozí možnosti psaní public_timelines: Veřejné časové osy + privacy: + hint_html: "Nastavte si, jak chcete, aby šlo váš profil a vaše příspěvky nalézt. Řada funkcí v Mastodonu vám může po zapnutí pomoci získat širší publikum. Věnujte chvíli kontrole těchto nastavení, aby vyhovovala vašim potřebám." + privacy: Soukromí + privacy_hint_html: Nastavte si, kolik toho chcete zveřejnit ve prospěch ostatních. Lidé objevují zajímavé profily a skvělé aplikace procházením sledovaných ostatních lidí i tím, že vidí, z jakých aplikací ostatní posílají příspěvky, vy se však můžete rozhodnout tyto údaje skrýt. + reach: Dosah + reach_hint_html: Nastavte si, zda chcete být objeveni a sledováni novými lidmi. Chcete, aby se vaše příspěvky objevovaly na obrazovce Objevit? Chcete, aby vás další lidé viděli ve svých doporučeních ke sledování? Chcete přijímat všechny nové sledující automaticky nebo mít podrobnou kontrolu nad každým z nich? + search: Vyhledávání + search_hint_html: Mějte pod kontrolou, jak chcete být nalezeni. Chcete, aby vás lidé našli podle toho, o čem jste veřejně psali? Chcete, aby lidé mimo Mastodon mohli nalézt váš profil při prohledávání webu? Mějte na vědomí, že úplné vyřazení ze všech vyhledávačů nelze u veřejných informací garantovat. + title: Soukromí a dosah privacy_policy: title: Zásady ochrany osobních údajů reactions: @@ -1773,7 +1850,10 @@ cs: seamless_external_login: Jste přihlášeni přes externí službu, nastavení hesla a e-mailu proto nejsou dostupná. signed_in_as: 'Přihlášeni jako:' verification: + here_is_how: Jak na to + instructions_html: Zkopírujte a vložte níže uvedený kód do HTML vašeho webu. Poté přidejte adresu vašeho webu do jednoho z extra políček na vašem profilu na záložce "Upravit profil" a uložte změny. verification: Ověření + verified_links: Vaše ověřené odkazy webauthn_credentials: add: Přidat nový bezpečnostní klíč create: diff --git a/config/locales/cy.yml b/config/locales/cy.yml index ec6dc75396..a975457cf9 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -1866,6 +1866,7 @@ cy: default: "%b %d, %Y, %H:%M" month: "%b %Y" time: "%H:%M" + with_time_zone: "%b %d, %Y, %H:%M %Z" translation: errors: quota_exceeded: Aethpwyd y tu hwnt i gwota defnydd y gweinydd cyfan ar gyfer y gwasanaeth cyfieithu. diff --git a/config/locales/de.yml b/config/locales/de.yml index da92f8fa27..69151b2e70 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1829,7 +1829,7 @@ de: signed_in_as: 'Angemeldet als:' verification: extra_instructions_html: Hinweis: Der Link auf deiner Website kann unsichtbar sein. Der wichtige Teil ist rel="me", wodurch das Nachahmen von Personen auf Websites mit nutzergenerierten Inhalten verhindert wird. Du kannst auch ein link-Tag statt a im Header auf der Seite verwenden, jedoch muss der HTML-Code ohne das Ausführen von JavaScript zugänglich sein. - here_is_how: So funktioniert's + here_is_how: So funktioniert’s hint_html: "Alle können ihre Identität auf Mastodon verifizieren. Basierend auf offenen Standards – jetzt und für immer kostenlos. Alles, was du brauchst, ist eine eigene Website. Wenn du von deinem Profil auf diese Website verlinkst, überprüfen wir, ob die Website zu deinem Profil zurückverlinkt, und zeigen einen visuellen Hinweis an." instructions_html: Kopiere den unten stehenden Code und füge ihn in das HTML deiner Website ein. Trage anschließend die Adresse deiner Website in ein Zusatzfeld auf deinem Profil ein und speichere die Änderungen. Die Zusatzfelder befinden sich im Reiter „Profil bearbeiten“. verification: Verifizierung diff --git a/config/locales/doorkeeper.fa.yml b/config/locales/doorkeeper.fa.yml index 0eb1479aa1..085507f8bf 100644 --- a/config/locales/doorkeeper.fa.yml +++ b/config/locales/doorkeeper.fa.yml @@ -64,7 +64,7 @@ fa: review_permissions: بازبینی اجازه‌ها title: نیاز به اجازه دادن show: - title: این کد مجوز را کپی کرده و در برنامه وارد کنید. + title: این کد تأیید را رونوشت کرده و در برنامه بگذارید. authorized_applications: buttons: revoke: فسخ @@ -127,6 +127,7 @@ fa: bookmarks: نشانک‌ها conversations: گفت‌وگوها crypto: رمزگذاری سرتاسری + favourites: برگزیده‌ها filters: پالایه‌ها follow: پی‌گیری، خموشی و مسدودی‌ها follows: پی‌گرفتگان @@ -155,6 +156,9 @@ fa: admin:read:reports: خواندن اطّلاعات حساس از همهٔ گزارش‌ها و حساب‌های گزارش‌شده admin:write: تغییر تمام داده‌ها روی کارساز admin:write:accounts: انجام کنش مدیریتی روی حساب‌ها + admin:write:domain_allows: انجام کنش مدیریتی روی اجازه‌های دامنه + admin:write:domain_blocks: انجام کنش مدیریتی روی انسدادهای دامنه + admin:write:email_domain_blocks: انجام کنش مدیریتی روی انسدادهای دامنهٔ رایانامه admin:write:ip_blocks: انجام کنش مدیریتی روی مسدودسازی های IP admin:write:reports: انجام کنش مدیریتی روی گزارش‌ها crypto: از رمزگذاری سرتاسر استفاده کنید @@ -164,6 +168,7 @@ fa: read:accounts: دیدن اطّلاعات حساب read:blocks: دیدن مسدودهایتان read:bookmarks: دیدن نشانک‌هایتان + read:favourites: دیدن برگزیده‌هایتان read:filters: دیدن پالایه‌هایتان read:follows: دیدن پی‌گیری‌هایتان read:lists: دیدن سیاهه‌هایتان @@ -177,6 +182,7 @@ fa: write:blocks: انسداد حساب‌ها و دامنه‌ها write:bookmarks: نشانک‌گذاری وضعیت‌ها write:conversations: مکالمات را بی‌صدا و حذف کنید + write:favourites: فرسته‌های برگزیده write:filters: ایحاد پالایش‌ها write:follows: پی‌گیری افراد write:lists: ایجاد سیاهه‌ها diff --git a/config/locales/fa.yml b/config/locales/fa.yml index f5ba91e1f9..e2138e0aeb 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -31,7 +31,7 @@ fa: created_msg: یادداشت مدیر با موفقیت ساخته شد! destroyed_msg: یادداشت نظارتی با موفقیت نابود شد! accounts: - add_email_domain_block: مسدود کردن دامنهٔ رایانامه + add_email_domain_block: انسداد دامنهٔ رایانامه approve: پذیرفتن approved_msg: کارهٔ ثبت‌نام %{username} با موفقیت تأیید شد are_you_sure: مطمئنید؟ @@ -309,6 +309,7 @@ fa: unpublish: عدم انتشار unpublished_msg: انتشار اعلامیه با موفقیت لغو شد! updated_msg: اعلامیه با موفقیت به‌روز شد! + critical_update_pending: به‌روز رسانی‌های بحرانی منتظرند custom_emojis: assign_category: تعیین دسته by_domain: دامنه @@ -387,7 +388,7 @@ fa: confirm: تعلیق title: تأیید انسداد دامنه برای %{domain} created_msg: مسدودسازی دامنه در حال پردازش است - destroyed_msg: مسدودکردن دامنه واگردانده شد + destroyed_msg: انسداد دامنه واگردانده شد domain: دامنه edit: ویرایش مسدودسازی دامنه existing_domain_block_html: شما پیش‌تر محدودیت‌های سخت‌تری روی %{name} اعمال کرده‌اید، و باید نخست مسدودسازی را لغو کنید. @@ -432,8 +433,16 @@ fa: not_permitted: مجاز نیست title: دامنه‌های رایانامهٔ مسدود شده export_domain_allows: + new: + title: درون‌ریزی اجازه‌های دامنه no_file: هیچ پرونده‌ای گزیده نشده export_domain_blocks: + import: + existing_relationships_warning: رابطه‌های پی‌گیری موجود + private_comment_template: درون‌ریخته از %{source} در %{date} + title: درون‌ریزی انسدادهای دامنه + new: + title: درون‌ریزی انسدادهای دامنه no_file: هیچ پرونده‌ای گزیده نشده follow_recommendations: description_html: "پیشنهادات پیگیری به کاربران جدید کک می‌کند تا سریع‌تر محتوای جالب را پیدا کنند. زمانی که کاربری هنوز به اندازه کافی با دیگران تعامل نداشته است تا پیشنهادات پیگیری شخصی‌سازی‌شده دریافت کند، این حساب‌ها را به جای آن فهرست مشاهده خواهد کرد. این حساب‌ها به صورت روزانه و در ترکیب با بیشتری تعاملات و بالاترین دنبال‌کنندگان محلی برای یک زبان مشخص بازمحاسبه می‌شوند." @@ -445,6 +454,7 @@ fa: unsuppress: بازگردانی پیشنهادهای پی‌گیری instances: availability: + failure_threshold_reached: در %{date} به آستانهٔ شکست رسید. no_failures_recorded: هیچ شکستی در سابقه نیست. title: موجود بودن back_to_all: همه @@ -473,6 +483,7 @@ fa: delivery: all: همه clear: پاک کردن خطاهای تحول محتوا + failing: شکست خوردن restart: بازراه‌اندازی تحویل محتوا stop: متوقف‌کردن تحویل محتوا unavailable: ناموجود @@ -618,8 +629,10 @@ fa: delete_user_data: حذف داده‌های کاربر invite_users: دعوت کاربران manage_announcements: مدیریت اعلامیه‌ها + manage_appeals: مدیریت درخواست‌های بازنگری manage_blocks: مدیریت مسدودی‌ها manage_custom_emojis: مدیریت ایموجی‌های سفارشی + manage_federation: مدیریت خودگردانی manage_invites: مدیریت دعوت‌ها manage_reports: مدیریت گزارش‌ها manage_roles: مدیریت نقش‌ها @@ -648,6 +661,8 @@ fa: appearance: preamble: سفارشی‌سازی رابطس وب ماستودون. title: ظاهر + default_noindex: + title: درخواست خروج از اندیس‌گذاری پیش‌گزیدهٔ موتور جست‌وجو discovery: follow_recommendations: پیروی از پیشنهادها profile_directory: شاخهٔ نمایه @@ -667,9 +682,20 @@ fa: approved: ثبت نام نیازمند تأیید مدیران است none: کسی نمی‌تواند ثبت نام کند open: همه می‌توانند ثبت نام کنند + title: تنظیمات کارساز site_uploads: delete: پرونده بارگذاری شده را پاک کنید destroyed_msg: بارگذاری پایگاه با موفقیت حذف شد! + software_updates: + critical_update: بحرانی — لطفاً به سرعت به‌روز کنید + documentation_link: بیش‌تر بیاموزید + release_notes: یادداشت‌های انتشار + title: به‌روز رسانی‌های موجود + type: گونه + types: + major: ارائه بزرگ + minor: ارائه کوچک + version: نگارش statuses: account: نگارنده application: برنامه @@ -710,11 +736,24 @@ fa: system_checks: database_schema_check: message_html: تعداد مهاجرت پایگاه داده در انتظار انجام هستند. لطفا آن‌ها را اجرا کنید تا اطمینان یابید که برنامه مطابق انتظار رفتار خواهد کرد + elasticsearch_preset: + action: دیدن مستندات + elasticsearch_preset_single_node: + action: دیدن مستندات + elasticsearch_version_check: + message_html: 'نگارش الستیک‌سرچ ناسازگار: %{value}' + version_comparison: الستیک‌سرچ %{running_version} در حال اجراست، حال که %{required_version} لازم است rules_check: action: مدیریت قانون‌های کارساز message_html: هیچ قانون کارسازی تعریف نکرده‌اید. sidekiq_process_check: message_html: صف(های) %{value} فاقد هیچونه فرایند Sidekiq هستند. لطفا تنظیمات Sidekiq خود را بازبینی کنید + upload_check_privacy_error: + action: برای اطّلاعات بیش‌تر این‌جا را بررسی کنید + message_html: "کارساز وبتان بد پیکربندی شده. محرمانگی کاربرانتان در خطر است." + upload_check_privacy_error_object_storage: + action: برای اطّلاعات بیش‌تر این‌جا را بررسی کنید + message_html: "ذخیره‌سازتان بد پیکربندی شده. محرمانگی کاربرانتان در خطر است." tags: review: وضعیت بازبینی updated_msg: تنظیمات برچسب‌ها با موفقیت به‌روز شد @@ -858,6 +897,7 @@ fa: migrate_account: نقل مکان به یک حساب دیگر migrate_account_html: اگر می‌خواهید این حساب را به حساب دیگری منتقل کنید، این‌جا را کلیک کنید. or_log_in_with: یا ورود به وسیلهٔ + privacy_policy_agreement_html: سیاست محرمانگی را خوانده و پذیرفته‌ام progress: confirm: تأیید رایانامه details: جزئیات شما @@ -967,6 +1007,7 @@ fa: invalid_domain: نام دامین معتبر نیست edit_profile: basic_information: اطلاعات پایه + hint_html: "شخصی‌سازی آن چه مردم روی نمایهٔ عمومیتان و کنار فرسته‌هایتان می‌بینند. هنگامی که نمایه‌ای کامل و یک تصویر نمایه داشته باشید،‌ احتمال پی‌گیری متقابل و تعامل با شما بیش‌تر است." other: سایر errors: '400': درخواستی که فرستادید نامعتبر یا اشتباه بود. @@ -1019,6 +1060,7 @@ fa: statuses: فرسته‌های جدا title: ویرایش پالایه errors: + deprecated_api_multiple_keywords: این پارامترها نمی‌توانند از این برنامه تغییر یابند؛ چرا که به بیش از یک کلیدواژهٔ پالایه اعمال می‌شود. از برنامه‌ای جدیدتر یا میانای وب استفاده کنید. invalid_context: زمینه‌ای موجود نیست یا نامعتبر است index: delete: پاک‌کردن @@ -1045,6 +1087,9 @@ fa: title: فرسته‌های پالوده generic: all: همه + all_matching_items_selected_html: + one: "%{count} مورد مطابق با جست‌وجویتان گزیده شده." + other: "%{count} مورد مطابق با جست‌وجویتان گزیده شدند." cancel: لغو changes_saved_msg: تغییرات با موفقیت ذخیره شدند! confirm: تأیید @@ -1107,6 +1152,9 @@ fa: expires_at: تاریخ انقضا uses: استفاده‌ها title: دعوت دیگران + lists: + errors: + limit: به بیشینهٔ تعداد سیاهه‌ها رسیدید login_activities: authentication_methods: otp: کارهٔ تأیید هویت دوعاملی @@ -1121,6 +1169,9 @@ fa: mail_subscriptions: unsubscribe: complete: لغو اشتراک شد + emails: + notification_emails: + mention: رایانامه‌های آگاهی اشاره title: لغو اشتراک media_attachments: validations: @@ -1187,9 +1238,9 @@ fa: title: درخواست پیگیری تازه mention: action: پاسخ - body: "%{name} در این‌جا از شما نام برد:" - subject: "%{name} از شما نام برد" - title: نام‌برده‌شدن تازه + body: "%{name} در این‌جا به شما اشاره کرد:" + subject: "%{name} به شما اشاره کرد" + title: اشارهٔ جدید poll: subject: نظرسنجی‌ای از %{name} پایان یافت reblog: @@ -1244,6 +1295,14 @@ fa: other: سایر تنظیمات posting_defaults: تنظیمات پیش‌فرض انتشار public_timelines: خط زمانی‌های عمومی + privacy: + hint_html: "شخصی‌سازی چگونگی پیدا شدن فرسته‌ها و نمایه‌تان. ویژگی‌های متعدّدی در ماستودون می‌توانند هنگام به کار افتادن در رسیدن به مخاطبینی گسترده‌تر یاریتان کنند. کمی وقت برای بازبینی این تنظیمات گذاشته تا مطمئن شوید برایتان مناسبند." + privacy: محرمانگی + reach: دسترسی + reach_hint_html: واپایش این که می‌خواهید به دست افراد جدید قابل کشف و پی‌گیری باشید یا نه. می‌خواهید فرسته‌هایتان روی صفحهٔ کشف ظاهر شوند؟ می‌خواهید دیگر افراد در پیشنهادهای پی‌گیریشان ببینندتان؟ می‌خواهید پی‌گیران جدید را به طور خودکار بپذیرید یا روی هرکدامشان واپایش داشته باشید؟ + search: جست‌وجو + search_hint_html: واپایش این که چگونه می‌خواهید پیدا شوید. می‌خواهید افراد با آن‌چه به صورت عمومی درباره‌اش فرستاده‌اید پیدایتان کنند؟ می‌خواهید افراد خارج از ماستودون هنگام جست‌وجوی وب نمایه‌تان را بیابند؟ لطفاً‌به خاطر داشته باشید که خروج کامل از تمامی موتورهای جست‌وجو برای اطّلاعات عمومی قابل تضمین نیست. + title: محرمانگی و دسترسی privacy_policy: title: سیاست محرمانگی reactions: @@ -1519,7 +1578,10 @@ fa: seamless_external_login: شما با یک سرویس خارج از مجموعه وارد شده‌اید، به همین دلیل تنظیمات ایمیل و گذرواژه برای شما در دسترس نیست. signed_in_as: 'واردشده به نام:' verification: + extra_instructions_html: نکته: پیوند روی پایگاه وبتان می‌تواند نامرئی باشد. بخش مهم rel="me" است که از جعل هویت روی پایگاه‌هایی با محتوای تولید شده به دست کاربر جلوگیری می‌کند. حتا می‌توانید به جای برچسب a از برچسب link در سرایند صفحه استفاده کنید؛ ولی HTML باید بدون اجرای جاوااسکریپت در دسترس باشد. here_is_how: به اینصورت + hint_html: "تأیید هویتتان روی ماستودون برای همه است. برپایهٔ استانداردهای وب و رایگان برای همیشه. تمام آن چه نیاز دارید پایگاه وب شخصیست که افراد شما را با آن بشناسند. هنگام پیوند دادن به این پایگاه از نمایه‌تان، بررسی می‌کنیم که پیوندهای پایگاه وب نیز به نمایه‌تان پیوند داده باشد و نشانگری تصویری رویش نشان می‌دهیم." + instructions_html: کد زیر را رونوشت کرده و در HTML پایگاه وبتان جایگذاری کنید. سپس نشانی پایگاه وبتان را از زبانهٔ «ویرایش نمایه» در یکی از زمینه‌های اضافی روی نمایه‌تان افزوده و تغییرات را ذخیره کنید. verification: تأیید verified_links: "‏پیوندهای تأییدشده‌ شما" webauthn_credentials: diff --git a/config/locales/gd.yml b/config/locales/gd.yml index dbc962d250..e620db3a78 100644 --- a/config/locales/gd.yml +++ b/config/locales/gd.yml @@ -458,7 +458,7 @@ gd: not_permitted: Chan eil seo ceadaichte resolved_dns_records_hint_html: Thèid ainm na h-àrainne fhuasgladh nan àrainnean MX a leanas agus an urra riutha-san gun gabh iad ri post-d. Ma bhacas tu àrainn MX, bacaidh seo an clàradh o sheòladh puist-d sam bith a chleachdas an aon àrainn MX fiù ’s ma bhios ainm àrainne eadar-dhealaichte ’ga sealltainn. Thoir an aire nach bac thu solaraichean puist-d mòra. resolved_through_html: Chaidh fuasgladh slighe %{domain} - title: Àrainnean puist-d ’gam bacadh + title: Bacadh àrainnean puist-d export_domain_allows: new: title: Ion-phortaich àrainnean ceadaichte diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 1dfbaf03d2..14f78e4615 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -71,7 +71,7 @@ gl: enabled: Activado enabled_msg: Desbloqueada a conta de %{username} followers: Seguidoras - follows: Segue + follows: Seguimentos header: Cabeceira inbox_url: URL da caixa de entrada invite_request_text: Razóns para unirte diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 8da2695fdc..b18405fb65 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -379,11 +379,11 @@ ja: confirm_suspension: cancel: キャンセル confirm: 停止 - permanent_action: 失われたデータやフォロー関係は、ブロックを解除しても元に戻せません。 - preamble_html: "%{domain} と、そのサブドメインをブロックします。" + permanent_action: 失われたデータやフォロー関係は、停止を解除しても元に戻せません。 + preamble_html: "%{domain} と、そのサブドメインに「停止」の処置を行います。" remove_all_data: この操作により、対象のドメインにあるアカウントからのコンテンツやメディア、プロフィール情報はすべて削除されます。 - stop_communication: ブロックしたサーバーとは通信を行わなくなります。 - title: "%{domain} をブロック" + stop_communication: 対象のサーバーとは通信を行わなくなります。 + title: "「%{domain}」ドメインブロックの確認" undo_relationships: この操作により、このサーバーと対象サーバーのアカウント間のフォロー関係はすべて解除されます。 created_msg: ドメインブロック処理を完了しました destroyed_msg: ドメインブロックを外しました diff --git a/config/locales/ko.yml b/config/locales/ko.yml index a6a85464e6..da6d8596e0 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -1303,7 +1303,7 @@ ko: unconfirmed: 미확인 status: 상태 success: 파일이 정상적으로 업로드되었으며, 현재 처리 중입니다 - time_started: 시작 시간 + time_started: 시작 시각 titles: blocking: 차단한 계정 가져오는 중 bookmarks: 북마크 가져오는 중 diff --git a/config/locales/no.yml b/config/locales/no.yml index 8bb36e76f8..dc8151d552 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -309,6 +309,7 @@ unpublish: Avpubliser unpublished_msg: Kunngjøring upublisert! updated_msg: Kunngjøringen er oppdatert! + critical_update_pending: Kritisk oppdatering avventer custom_emojis: assign_category: Tilegn kategori by_domain: Domene @@ -774,6 +775,18 @@ site_uploads: delete: Slett den opplastede filen destroyed_msg: Vellykket sletting av sideopplasting! + software_updates: + critical_update: Kritisk — vennligst oppdater raskt + description: "Det anbefales å holde Mastodon-installasjonen oppdatert for å dra nytte av nye rettelser og funksjoner. Dessuten er det av og til viktig å oppdatere Mastodon raskt for å unngå sikkerhetsproblemer. Derfor sjekker Mastodon om det finnes oppdateringer \nhvert 30. minutt, og varsler deg i henhold til dine valg for e-postvarsling." + documentation_link: Finn ut mer + release_notes: Informasjon om utgivelsen + title: Tilgjengelige oppdateringer + type: Type + types: + major: Stor oppdatering + minor: Mindre oppdatering + patch: Liten oppdatering – feilrettinger og endringer som er lette å legge til + version: Versjon statuses: account: Forfatter application: Applikasjon @@ -838,6 +851,12 @@ message_html: Du har ikke definert noen serverregler. sidekiq_process_check: message_html: Ingen Sidekiq-prosess kjører for %{value} køen(e). Vennligst se gjennom Sidekiq-konfigurasjonen din + software_version_critical_check: + action: Se tilgjengelige oppdateringer + message_html: En kritisk oppdatering av Mastodon er tilgjengelig. Vennligst oppdater så raskt som mulig. + software_version_patch_check: + action: Se tilgjengelige oppdateringer + message_html: En oppdatering av Mastodon som inneholder feilrettinger er tilgjengelig. upload_check_privacy_error: action: Sjekk her for mer informasjon message_html: "Webserveren din er feilkonfigurert. Personvernet til brukerne dine er i fare." @@ -951,6 +970,9 @@ body: "%{target} klager på en moderasjonsbeslutning av %{action_taken_by} fra %{date}, noe som var %{type}. De skrev:" next_steps: Du kan godkjenne klagen for å angre på moderasjonsvedtaket eller ignorere det. subject: "%{username} klager på en moderasjonsbeslutning for %{instance}" + new_critical_software_updates: + body: Nye kritiske versjoner av Mastodon har blitt utgitt, det kan være fordelaktig å oppdatere så snart som mulig! + subject: Kritiske Mastodon-oppdateringer er tilgjengelige for %{instance}! new_pending_account: body: Detaljer om den nye kontoen er nedenfor. Du kan godkjenne eller avvise denne søknaden. subject: Ny konto opp til vurdering på %{instance} (%{username}) @@ -958,6 +980,9 @@ body: "%{reporter} har rapportert %{target}" body_remote: Noen fra %{domain} har rapportert %{target} subject: Ny rapport for %{instance} (#%{id}) + new_software_updates: + body: Nye versjoner av Mastodoner har blitt utgitt, du ønsker kanskje å oppdatere! + subject: Nye versjoner av Mastodon er tilgjengelige for %{instance}! new_trends: body: 'Følgende elementer trenger en gjennomgang før de kan vises offentlig:' new_trending_links: @@ -1708,6 +1733,7 @@ default: "%-d. %b %Y, %H:%M" month: "%b %Y" time: "%H:%M" + with_time_zone: "%-d. %b %Y, %H:%M %Z" two_factor_authentication: add: Legg til disable: Skru av diff --git a/config/locales/simple_form.ca.yml b/config/locales/simple_form.ca.yml index 15e1d0de24..12a6ac1fe8 100644 --- a/config/locales/simple_form.ca.yml +++ b/config/locales/simple_form.ca.yml @@ -15,7 +15,7 @@ ca: account_migration: acct: Especifica l'usuari@domini del compte al qual et vols traslladar account_warning_preset: - text: Pots usar totes les sintaxis, com ara URL, etiquetes i mencions + text: Pots usar tota mena de sintaxi, com ara URL, etiquetes i mencions title: Opcional. No és visible per al destinatari admin_account_action: include_statuses: L'usuari veurà quins tuts han causat l'acció de moderació o avís diff --git a/config/locales/simple_form.cy.yml b/config/locales/simple_form.cy.yml index 8079fd03c0..70194a1e0c 100644 --- a/config/locales/simple_form.cy.yml +++ b/config/locales/simple_form.cy.yml @@ -291,6 +291,8 @@ cy: pending_account: Mae cyfrif newydd angen adolygiad reblog: Mae rhywun wedi hybu eich postiad report: Cyflwynwyd adroddiad newydd + software_updates: + label: Mae fersiwn Mastodon newydd ar gael trending_tag: Mae pwnc llosg newydd angen adolygiad rule: text: Rheol diff --git a/config/locales/simple_form.fa.yml b/config/locales/simple_form.fa.yml index ca382f387e..676eb192ee 100644 --- a/config/locales/simple_form.fa.yml +++ b/config/locales/simple_form.fa.yml @@ -2,6 +2,14 @@ fa: simple_form: hints: + account: + discoverable: ممکن است نمایه و فرسته‌های عمومیتان در جاهای مختلف ماستودون نمایانده و توصیه شود و نمایه‌تان به دیگر کاربران پیشنهاد شود. + display_name: نام کامل یا باحالتان. + fields: صفحهٔ خانگی، تلفّظ، سن و هرچیزی که دوست دارید. + indexable: ممکن است فرسته‌های عمومیتان در نتیجه‌های جست‌وجوی ماستودون ظاهر شود. افرادی که با فرسته‌هایتان تعامل داشتند در هر صورت می‌توانند جست‌وجویشان کنند. + note: 'می‌توانید افراد دیگر را @نام برده یا #برچسب بزنید.' + show_collections: افراد خواهند توانست پی‌گیران و پی‌گرفته شده‌هایتان را مرور کنند. افرادی که پی‌می‌گیریدشان در هر صورت خواهند دید که پی‌می‌گیریدشان. + unlocked: افراد خواهند توانست بدون درخواست تأیید پی‌بگیرندتان. اگر می‌خواهید درخواست‌های پی‌گیری را بازبینی کرده و بگزینید که پی‌گیران جدید را بپذیرید یا رد کنید، علامت را بردارید. account_alias: acct: مشخّص کردن username@domain حسابی که می‌خواهید از آن منتقل شوید account_migration: @@ -72,7 +80,17 @@ fa: backups_retention_period: نگه داشتن بایگانی‌های کاربری برای روزهای مشخّص شده. bootstrap_timeline_accounts: سنجاق کردنThese accounts will be pinned to the top of new users' follow recommendations. closed_registrations_message: نمایش داده هنگام بسته بودن ثبت‌نام‌ها + content_cache_retention_period: همهٔ فرسته‌ها و تقویت‌ها از دیگر کارسازها پس از روزهای نشخّص حذف خواهند شد. ممکن است برخی فرسته‌ها قابل بازیابی نباشند. همهٔ نشانک‌ها، پسندها و تقویت‌ها نیز از دست خواهند رفت و قابل بازگشت نخواهند بود. + custom_css: می‌توانیدروی نگارش وب ماستودون سبک‌های سفارشی اعمال کنید. + mascot: نقش میانای وب پیش‌رفته را پایمال می‌کند. + media_cache_retention_period: اگر به مقدار مثبتی تنظیم شود، پرونده‌های رسانهٔ بارگرفته پس از روزهای مشخّص شده حذف خواهند شد و هنگام درخواست دوباره بارگرفته می‌شوند. + profile_directory: شاخهٔ نمایه، همهٔ کاربرانی که کشف‌پذیری را برگزیده‌اند سیاهه می‌کند. require_invite_text: زمانی که نام‌نویسی ها نیازمند تایید دستی است، متن «چرا می‌خواهید بپیوندید؟» بخش درخواست دعوت را به جای اختیاری، اجباری کنید + site_contact_email: چگونگی دسترسی افراد به شما برای مقاصد قانونی یا پشتیبانی. + site_contact_username: چکونگی رسیدن افراد به شما روی ماستودون. + site_extended_description: هر اطّلاعات بیش‌تری که ممکن است برای بازدیدکنندگان و کاربرانتان مفید باشد. می‌تواند به شکل مارک‌دون باشد. + site_short_description: شرحی کوتاه برای کمک به شناسایی یکتای کارسازتان. چه‌کسی می‌گرداندش و برای چه کسیست؟ + site_terms: از سیاست محرمانگی خوتان استفاده کرده یا برای استفاده از سیاست پیش‌گزیده خالی بگذارید. می‌تواند در قالب مارک‌دون باشد. form_challenge: current_password: شما در حال ورود به یک منطقهٔ‌ حفاظت‌شده هستید imports: @@ -93,6 +111,9 @@ fa: sessions: otp: 'کد تأیید دومرحله‌ای که کاره روی تلفن شما ساخته را وارد کنید یا یکی از کدهای بازیابی را به کار ببرید:' webauthn: اگر کلید USB باشد ، از اتصاڵ آن مطمئن شوید و، اگر لازم باشد، به آن ضربه‌ایی بزنید. + settings: + indexable: صفحهٔ نمایه‌تان ممکن است در نتیجه‌های جست‌وجو روی گوگل، بینگ و جاهای دیگر ظاهر شود. + show_application: خودتان همواره خواهید توانست ببینید که کدام کاره فرسته‌تان را منتشر کرده. tag: name: شما تنها می‌توانید بزرگی و کوچکی حروف را تغییر دهید تا مثلاً آن را خواناتر کنید user: @@ -102,9 +123,13 @@ fa: url: جایی که رویدادها فرستاده می‌شوند labels: account: + discoverable: معرّفی نمایه و فرسته‌ها در الگوریتم‌های کشف fields: name: برچسب value: محتوا + indexable: بودن فرسته‌های عمومی در نتیجه‌های جست‌وجو + show_collections: نمایش پی‌گیران و پی‌گرفته شده‌ها روی نمایه + unlocked: پذیرش خودکار پی‌گیران جدید account_alias: acct: نشانی حساب قدیمی account_migration: @@ -249,9 +274,18 @@ fa: pending_account: وقتی حساب تازه‌ای نیاز به بازبینی داشت ایمیل بفرست reblog: وقتی کسی فرستهٔ شما را تقویت کرد ایمیل بفرست report: گزارش جدیدی فرستاده شد + software_updates: + all: آگاهی برای همهٔ به‌روز رسانی‌ها + critical: آگاهی فقط برای به‌روز رسانی‌های بحرانی + label: نگارشی جدید از ماستادون موجود است + none: هرگز برای به‌روز رسانی‌ها آگاهی داده نشود (توصیه نمی‌شود) + patch: آگاهی برای به‌روز رسانی‌های رفع اشکال trending_tag: روند جدیدی نیازمند بازبینی است rule: text: قانون + settings: + indexable: بودن صفحهٔ نمایه در نتیجه‌های جست‌وجو + show_application: نمایش این که فرسته را از کدام کاره فرستاده‌اید tag: listable: اجازه به این برچسب برای ظاهر شدن در جست‌وجوها و پیشنهادها name: برچسب @@ -271,6 +305,7 @@ fa: url: نشانی نقطهٔ پایانی 'no': خیر not_recommended: پیشنهاد نشده + overridden: پایمال recommended: توصیه می‌شود required: mark: "*" diff --git a/config/locales/simple_form.no.yml b/config/locales/simple_form.no.yml index 1a32a5fadb..a9d5465f36 100644 --- a/config/locales/simple_form.no.yml +++ b/config/locales/simple_form.no.yml @@ -200,7 +200,7 @@ password: Passord phrase: Nøkkelord eller frase setting_advanced_layout: Skru på det avanserte nettgrensesnittet - setting_aggregate_reblogs: Gruppefremhevinger i tidslinjer + setting_aggregate_reblogs: Samle fremhevinger i tidslinjer setting_always_send_emails: Alltid send e-postvarslinger setting_auto_play_gif: Autoavspill animert GIF-filer setting_boost_modal: Vis bekreftelse før fremheving @@ -291,6 +291,12 @@ pending_account: Ny bruker avventer gjennomgang reblog: Send e-post når noen fremhever din status report: Ny rapport er sendt + software_updates: + all: Varsle om alle oppdateringer + critical: Varsle kun om kritiske oppdateringer + label: En ny versjon av Mastodon er tilgjengelig + none: Aldri varsle om oppdateringer (anbefales ikke) + patch: Varsle om oppdateringer med feilrettinger trending_tag: Ny trend krever gjennomgang rule: text: Regler diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml index 04266d2719..7a56fa2559 100644 --- a/config/locales/simple_form.zh-CN.yml +++ b/config/locales/simple_form.zh-CN.yml @@ -3,10 +3,10 @@ zh-CN: simple_form: hints: account: - discoverable: 您的公开帖子和个人资料可能会在Mastodon的各个领域中被推荐,您的个人资料可能会被推荐给其他用户。 + discoverable: 您的公开嘟文和个人资料可能会在 Mastodon 的多个位置展示,您的个人资料可能会被推荐给其他用户。 display_name: 您的全名或昵称。 fields: 你的主页、人称代词、年龄,以及任何你想要添加的内容。 - indexable: 您的公开嘟文可能会出现在Mastodon的搜索结果中。与您的嘟文互动过的人可能能够进行搜索并找到它们。 + indexable: 您的公开嘟文会出现在 Mastodon 的搜索结果中。无论是否勾选,与您的嘟文有过交互的人都可能通过搜索找到它们。 note: '您可以提及 @其他人 或 #标签 。' show_collections: 人们将能够浏览您的关注和追随者。您关注的人会看到您关注他们。 unlocked: 人们将能够在不请求批准的情况下关注您。如果您希望审核关注请求并选择接受或拒绝新的粉丝,请取消勾选此项。 @@ -71,12 +71,12 @@ zh-CN: featured_tag: name: 以下是你最近使用过的标签: filters: - action: 选择在帖子匹配过滤器时要执行的操作 + action: 选择在嘟文命中过滤器时要执行的操作 actions: hide: 彻底屏蔽过滤内容,犹如它不曾存在过一般 warn: 在警告中提及过滤器标题后,隐藏过滤内容 form_admin_settings: - activity_api_enabled: 本地发布的帖子、 活跃用户和每周的注册数 + activity_api_enabled: 本站每周的嘟文数、活跃用户数和新注册用户数 backups_retention_period: 将在指定天数内保留生成的用户存档。 bootstrap_timeline_accounts: 这些账号将在新用户关注推荐中置顶。 closed_registrations_message: 在关闭注册时显示 @@ -144,7 +144,7 @@ zh-CN: fields: name: 标签 value: 内容 - indexable: 在搜索结果中包含公共嘟文 + indexable: 将公开嘟文纳入搜索范围 show_collections: 在个人资料中显示关注和关注者 unlocked: 自动接受新关注者 account_alias: diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 11e8de056a..e08d1101ef 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -425,6 +425,7 @@ sk: failing: Zlyhávajúce unavailable: Nedostupné delivery_available: Je v dosahu doručovania + empty: Nenájdené žiadne domény. moderation: all: Všetky limited: Obmedzené @@ -482,6 +483,12 @@ sk: created_msg: Poznámka o nahlásení úspešne vytvorená! destroyed_msg: Poznámka o nahlásení úspešne vymazaná! reports: + account: + notes: + few: "%{count} poznámok" + many: "%{count} poznámok" + one: "%{count} poznámka" + other: "%{count} poznámky" action_taken_by: Zákrok vykonal/a actions: suspend_description_html: Tento účet a všetok jeho obsah bude nedostupný a nakoniec zmazaný, interaktovať s ním bude nemožné. Zvrátiteľné v rámci 30 dní. Uzatvára všetky hlásenia voči tomuto účtu. @@ -1015,6 +1022,8 @@ sk: other: Ostatné posting_defaults: Východiskové nastavenia príspevkov public_timelines: Verejné časové osi + privacy: + title: Súkromie a dosah reactions: errors: limit_reached: Maximálny počet rôznorodých reakcií bol dosiahnutý diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 576833b043..35230ceddb 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -869,6 +869,7 @@ sl: action: Glejte razpoložljive posodobitve software_version_patch_check: action: Glejte razpoložljive posodobitve + message_html: Na voljo je posodobitev Mastodona s popravki hroščev. upload_check_privacy_error: action: Preverite tukaj za več informacij message_html: "Vaš spletni strežnik je napačno nastavljen. Zasebnost vaših uporabnikov je izpostavljena tveganjem." diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index db3902b704..51baaf7a4e 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -626,13 +626,13 @@ zh-CN: statuses_description_html: 在与该账号的通信中将引用违规内容 summary: action_preambles: - delete_html: 您即将删除 @%{acct} 的一些帖子。 这将: + delete_html: 您即将删除 @%{acct} 的一些嘟文。 这将: mark_as_sensitive_html: 您即将 标记 @%{acct} 的帖一些子为 敏感。这将: silence_html: 您即将限制 @%{acct} 的帐户。 这将: suspend_html: 您即将暂停 @%{acct} 的帐户。 这将: actions: - delete_html: 删除违规帖子 - mark_as_sensitive_html: 将违规帖子的媒体标记为敏感 + delete_html: 删除违规嘟文 + mark_as_sensitive_html: 将违规嘟文的媒体标记为敏感 silence_html: 严格限制 @%{acct} 的影响力,方法是让他们的个人资料和内容仅对已经关注他们的人可见,或手动查找其个人资料时 suspend_html: 暂停 @%{acct},使他们的个人资料和内容无法访问,也无法与之互动 close_report: '将报告 #%{id} 标记为已解决' @@ -759,7 +759,7 @@ zh-CN: open: 开放注册 security: authorized_fetch: 需要跨站认证 - authorized_fetch_hint: 要求跨站验证可以更严格地执行用户级和服务器级的封锁。然而,这会产生性能上的代价,减少你的回复触达范围,并可能导致与一些联邦服务的兼容问题。此外,这并不能阻止专门的参与者获取你的公共帖子和账户。 + authorized_fetch_hint: 要求外站请求通过验证能够使用户级别与服务器级别的封锁更为严格。然而,这将带来额外的性能负担、减少回复触达范围、并可能导致与一些联邦宇宙服务的兼容性问题。此外,这并不能阻止他人针对性地获取公开嘟文与账户。 authorized_fetch_overridden_hint: 由于此设置被环境变量覆盖,目前无法更改。 federation_authentication: 强制跨站认证 title: 服务器设置 @@ -1164,7 +1164,7 @@ zh-CN: invalid_domain: 不是一个有效的域名 edit_profile: basic_information: 基本信息 - hint_html: "自定义公开资料和帖子旁边显示的内容。当您填写完整的个人资料并设置了头像时,其他人更有可能关注您并与您互动。" + hint_html: "自定义公开资料和嘟文旁边显示的内容。当您填写完整的个人资料并设置了头像时,其他人更有可能关注您并与您互动。" other: 其他 errors: '400': 你提交的请求无效或格式不正确。 @@ -1499,7 +1499,7 @@ zh-CN: privacy: 隐私 privacy_hint_html: 控制你愿意向他人透露多少信息。通过浏览他人的关注列表和查看他们发嘟所用的应用,人们可以发现有趣的用户和酷炫的应用,但你可能更喜欢将其隐藏起来。 reach: 范围 - reach_hint_html: 控制您是否希望被新人发现和关注。您是否希望您的帖子出现在“探索”屏幕上?您是否希望其他人在关注推荐中看到您?您是想自动接受所有新粉丝,还是对每个粉丝都进行仔细的筛选? + reach_hint_html: 控制您是否希望被新人发现和关注。您是否希望您的嘟文出现在“探索”页面上?您是否希望其他人在关注推荐中看到您?您是想自动接受所有新粉丝,还是对每个粉丝都进行仔细的筛选? search: 搜索 search_hint_html: 控制你希望被找到的方式。你想让人们通过你公开发布的内容来找到你吗?当在网络上搜索时,你是否希望Mastodon之外的人能够找到你的个人资料?请注意,我们无法保证完全排除所有搜索引擎对公开信息的索引。 title: 隐私与可达性 From 82c44f492d23aac19120879a7b83d22d18cdd37c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 11:03:19 +0200 Subject: [PATCH 29/69] Update dependency glob to v10.3.7 (#27078) 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 42d903c24b..100b1d924f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6221,9 +6221,9 @@ glob-parent@^6.0.2: is-glob "^4.0.3" glob@^10.2.5, glob@^10.2.6: - version "10.3.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.5.tgz#4c0e46b5bccd78ac42b06a7eaaeb9ee34062968e" - integrity sha512-bYUpUD7XDEHI4Q2O5a7PXGvyw4deKR70kHiDxzQbe925wbZknhOzUt2xBgTkYL6RBcVeXYuD9iNYeqoWbBZQnA== + version "10.3.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.7.tgz#d5bd30a529c8c9b262fb4b217941f64ad90e25ac" + integrity sha512-wCMbE1m9Nx5yD9LYtgsVWq5VhHlk5WzJirw594qZR6AIvQYuHrdDtIktUVjQItalD53y7dqoedu9xP0u0WaxIQ== dependencies: foreground-child "^3.1.0" jackspeak "^2.0.3" From aeeddb9d46e9b1521c0d715c392c0a26b425595f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 11:56:21 +0200 Subject: [PATCH 30/69] Update DefinitelyTyped types (non-major) (#27109) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 84 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/yarn.lock b/yarn.lock index 100b1d924f..41ac832d1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2109,24 +2109,24 @@ "@babel/types" "^7.20.7" "@types/body-parser@*": - version "1.19.2" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" - integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + version "1.19.3" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.3.tgz#fb558014374f7d9e56c8f34bab2042a3a07d25cd" + integrity sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ== dependencies: "@types/connect" "*" "@types/node" "*" "@types/connect@*": - version "3.4.35" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" - integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + version "3.4.36" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.36.tgz#e511558c15a39cb29bd5357eebb57bd1459cd1ab" + integrity sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w== dependencies: "@types/node" "*" "@types/emoji-mart@^3.0.9": - version "3.0.9" - resolved "https://registry.yarnpkg.com/@types/emoji-mart/-/emoji-mart-3.0.9.tgz#2f7ef5d9ec194f28029c46c81a5fc1e5b0efa73c" - integrity sha512-qdBo/2Y8MXaJ/2spKjDZocuq79GpnOhkwMHnK2GnVFa8WYFgfA+ei6sil3aeWQPCreOKIx9ogPpR5+7MaOqYAA== + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/emoji-mart/-/emoji-mart-3.0.10.tgz#d2248c08758094377bd8f438cf13b1364b8b6649" + integrity sha512-WP5Vw1CLsTQpPT/Hj+shIMC5TB4pyoJourYQe01ceYtJVEopTwuXbCTE6f7aHOKj26E/Y+oZaPtKBtnG1S4d2Q== dependencies: "@types/react" "*" @@ -2154,9 +2154,9 @@ integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== "@types/express-serve-static-core@^4.17.33": - version "4.17.35" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f" - integrity sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg== + version "4.17.37" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz#7e4b7b59da9142138a2aaa7621f5abedce8c7320" + integrity sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg== dependencies: "@types/node" "*" "@types/qs" "*" @@ -2164,9 +2164,9 @@ "@types/send" "*" "@types/express@^4.17.17": - version "4.17.17" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" - integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== + version "4.17.18" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.18.tgz#efabf5c4495c1880df1bdffee604b143b29c4a95" + integrity sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ== dependencies: "@types/body-parser" "*" "@types/express-serve-static-core" "^4.17.33" @@ -2201,6 +2201,11 @@ "@types/react" "*" hoist-non-react-statics "^3.3.0" +"@types/http-errors@*": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.2.tgz#a86e00bbde8950364f8e7846687259ffcd96e8c2" + integrity sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg== + "@types/http-link-header@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@types/http-link-header/-/http-link-header-1.0.3.tgz#899adf1d8d2036074514f3dbd148fb901ceff920" @@ -2275,9 +2280,9 @@ integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== "@types/lodash@^4.14.195": - version "4.14.198" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.198.tgz#4d27465257011aedc741a809f1269941fa2c5d4c" - integrity sha512-trNJ/vtMZYMLhfN45uLq4ShQSw0/S7xCTLLVM+WM1rmFpba/VS42jVUgaO3w/NOLiWR/09lnYk0yMaA/atdIsg== + version "4.14.199" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.199.tgz#c3edb5650149d847a277a8961a7ad360c474e9bf" + integrity sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg== "@types/mime@*": version "3.0.1" @@ -2300,9 +2305,9 @@ integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node@*": - version "20.6.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.2.tgz#a065925409f59657022e9063275cd0b9bd7e1b12" - integrity sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw== + version "20.6.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.5.tgz#4c6a79adf59a8e8193ac87a0e522605b16587258" + integrity sha512-2qGq5LAOTh9izcc0+F+dToFigBWiK1phKPt7rNhOqJSr35y8rlIBjDwGtFSgAI6MGIhjwOVNSQZVdJsZJ2uR1w== "@types/node@14 || 16 || 17": version "17.0.45" @@ -2310,9 +2315,9 @@ integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw== "@types/normalize-package-data@^2.4.0": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" - integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== + version "2.4.2" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.2.tgz#9b0e3e8533fe5024ad32d6637eb9589988b6fdca" + integrity sha512-lqa4UEhhv/2sjjIQgjX8B+RBjj47eo0mzGasklVJ78UKGQY1r0VpB9XHDaZZO9qzEFDdy4MrXLuEaSmPrPSe/A== "@types/npmlog@^4.1.4": version "4.1.4" @@ -2330,9 +2335,9 @@ integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/pg@^8.6.6": - version "8.10.2" - resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.10.2.tgz#7814d1ca02c8071f4d0864c1b17c589b061dba43" - integrity sha512-MKFs9P6nJ+LAeHLU3V0cODEOgyThJ3OAnmOlsZsxux6sfQs3HRXR5bBn7xG5DjckEFhTAxsXi7k7cd0pCMxpJw== + version "8.10.3" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.10.3.tgz#39b3acba4f313a65c8fbb4b241fcb21cc1ba4126" + integrity sha512-BACzsw64lCZesclRpZGu55tnqgFAYcrCBP92xLh1KLypZLCOsvJTSTgaoFVTy3lCys/aZTQzfeDxtjwrvdzL2g== dependencies: "@types/node" "*" pg-protocol "*" @@ -2344,9 +2349,9 @@ integrity sha512-O397rnSS9iQI4OirieAtsDqvCj4+3eY1J+EPdNTKuHuRWIfUoGyzX294o8C4KJYaLqgSrd2o60c5EqCU8Zv02g== "@types/prop-types@*", "@types/prop-types@^15.7.5": - version "15.7.6" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.6.tgz#bbf819813d6be21011b8f5801058498bec555572" - integrity sha512-RK/kBbYOQQHLYj9Z95eh7S6t7gq4Ojt/NT8HTk8bWVhA5DaF+5SMnxHKkP4gPNN3wAZkKP+VjAf0ebtYzf+fxg== + version "15.7.7" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.7.tgz#f9361f7b87fd5d8188b2c998db0a1f47e9fb391a" + integrity sha512-FbtmBWCcSa2J4zL781Zf1p5YUBXQomPEcep9QZCfRfQgTxz3pJWiDFLebohZ9fFntX5ibzOkSsrJ0TEew8cAog== "@types/punycode@^2.1.0": version "2.1.0" @@ -2518,10 +2523,11 @@ "@types/node" "*" "@types/serve-static@*": - version "1.15.1" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.1.tgz#86b1753f0be4f9a1bee68d459fcda5be4ea52b5d" - integrity sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ== + version "1.15.2" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.2.tgz#3e5419ecd1e40e7405d34093f10befb43f63381a" + integrity sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw== dependencies: + "@types/http-errors" "*" "@types/mime" "*" "@types/node" "*" @@ -2594,14 +2600,14 @@ source-map "^0.6.0" "@types/yargs-parser@*": - version "21.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" - integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + version "21.0.1" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.1.tgz#07773d7160494d56aa882d7531aac7319ea67c3b" + integrity sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ== "@types/yargs@^17.0.24", "@types/yargs@^17.0.8": - version "17.0.24" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" - integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== + version "17.0.25" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.25.tgz#3edd102803c97356fb4c805b2bbaf7dfc9ab6abc" + integrity sha512-gy7iPgwnzNvxgAEi2bXOHWCVOG6f7xsprVJH4MjlAWeBmJ7vh/Y1kwMtUrs64ztf24zVIRCpr3n/z6gm9QIkgg== dependencies: "@types/yargs-parser" "*" From 4b4315776546b21f96218eb68bb447acbeab03d7 Mon Sep 17 00:00:00 2001 From: KMY Date: Mon, 25 Sep 2023 19:58:12 +0900 Subject: [PATCH 31/69] #2 Add kmyblue capabilities on about page --- .../mastodon/features/about/index.jsx | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/app/javascript/mastodon/features/about/index.jsx b/app/javascript/mastodon/features/about/index.jsx index 03f32a7e88..ccd7920428 100644 --- a/app/javascript/mastodon/features/about/index.jsx +++ b/app/javascript/mastodon/features/about/index.jsx @@ -28,6 +28,11 @@ const messages = defineMessages({ silencedExplanation: { id: 'about.domain_blocks.silenced.explanation', defaultMessage: 'You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.' }, suspended: { id: 'about.domain_blocks.suspended.title', defaultMessage: 'Suspended' }, suspendedExplanation: { id: 'about.domain_blocks.suspended.explanation', defaultMessage: 'No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.' }, + publicUnlistedVisibility: { id: 'privacy.public_unlisted.short', defaultMessage: 'Public unlisted' }, + emojiReaction: { id: 'status.emoji_reaction', defaultMessage: 'Stamp' }, + enabled: { id: 'about.enabled', defaultMessage: 'Enabled' }, + disabled: { id: 'about.disabled', defaultMessage: 'Disabled' }, + capabilities: { id: 'about.kmyblue_capabilities', defaultMessage: 'kmyblue capabilities' }, }); const severityMessages = { @@ -122,6 +127,10 @@ class About extends PureComponent { const { multiColumn, intl, server, extendedDescription, domainBlocks } = this.props; const isLoading = server.get('isLoading'); + const fedibirdCapabilities = server.get('fedibird_capabilities'); + const isPublicUnlistedVisibility = fedibirdCapabilities.includes('kmyblue_visibility_public_unlisted'); + const isEmojiReaction = fedibirdCapabilities.includes('emoji_reaction'); + return (
@@ -182,6 +191,20 @@ class About extends PureComponent { ))} +
+

+ {!isLoading && ( +
    +
  1. + {intl.formatMessage(messages.emojiReaction)}: {intl.formatMessage(isEmojiReaction ? messages.enabled : messages.disabled)} +
  2. +
  3. + {intl.formatMessage(messages.publicUnlistedVisibility)}: {intl.formatMessage(isPublicUnlistedVisibility ? messages.enabled : messages.disabled)} +
  4. +
+ )} +
+
{domainBlocks.get('isLoading') ? ( <> From 88fa8e710adf103dee289b2a9cc691a410f97c21 Mon Sep 17 00:00:00 2001 From: gunchleoc Date: Mon, 25 Sep 2023 12:59:37 +0200 Subject: [PATCH 32/69] Fix line wrapping of language selection button with long locale codes (#27100) --- app/javascript/styles/mastodon/components.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 418a9cfeae..2f09f356dd 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -284,6 +284,7 @@ font-size: 11px; padding: 0 3px; line-height: 27px; + white-space: nowrap; &:hover, &:active, From b70576df15111888e0aea15756704fde4d281ea0 Mon Sep 17 00:00:00 2001 From: KMY Date: Mon, 25 Sep 2023 20:02:50 +0900 Subject: [PATCH 33/69] #9 Remove public unlisted visibility settings if disabled --- app/views/settings/preferences/reaching/show.html.haml | 5 +++-- app/views/settings/privacy_extra/show.html.haml | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/views/settings/preferences/reaching/show.html.haml b/app/views/settings/preferences/reaching/show.html.haml index cfeaeff68e..03077758aa 100644 --- a/app/views/settings/preferences/reaching/show.html.haml +++ b/app/views/settings/preferences/reaching/show.html.haml @@ -21,8 +21,9 @@ .fields-group = ff.input :stay_privacy, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_stay_privacy') - .fields-group - = ff.input :public_post_to_unlisted, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_public_post_to_unlisted'), hint: I18n.t('simple_form.hints.defaults.setting_public_post_to_unlisted') + - if Setting.enable_public_unlisted_visibility + .fields-group + = ff.input :public_post_to_unlisted, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_public_post_to_unlisted'), hint: I18n.t('simple_form.hints.defaults.setting_public_post_to_unlisted') .fields-group = ff.input :'web.enable_login_privacy', wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_enable_login_privacy'), hint: false diff --git a/app/views/settings/privacy_extra/show.html.haml b/app/views/settings/privacy_extra/show.html.haml index c9ccd03013..350841b7d5 100644 --- a/app/views/settings/privacy_extra/show.html.haml +++ b/app/views/settings/privacy_extra/show.html.haml @@ -26,8 +26,9 @@ %p.lead= t('privacy_extra.stop_deliver_hint_html') = f.simple_fields_for :settings, current_user.settings do |ff| - .fields-group - = ff.input :reject_public_unlisted_subscription, kmyblue: true, as: :boolean, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_reject_public_unlisted_subscription') + - if Setting.enable_public_unlisted_visibility + .fields-group + = ff.input :reject_public_unlisted_subscription, kmyblue: true, as: :boolean, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_reject_public_unlisted_subscription') .fields-group = ff.input :reject_unlisted_subscription, kmyblue: true, as: :boolean, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_reject_unlisted_subscription'), hint: I18n.t('simple_form.hints.defaults.setting_reject_unlisted_subscription') From 002c4bfe74e07d2b6f666ae5655caa66622e16be Mon Sep 17 00:00:00 2001 From: KMY Date: Mon, 25 Sep 2023 20:25:04 +0900 Subject: [PATCH 34/69] #29 Add personal limited_scope --- app/javascript/mastodon/components/status.jsx | 2 ++ .../report/components/status_check_box.jsx | 2 ++ .../status/components/detailed_status.jsx | 2 ++ .../features/ui/components/boost_modal.jsx | 2 ++ app/models/status.rb | 2 +- app/services/post_status_service.rb | 4 +++- app/services/process_mentions_service.rb | 4 ++++ spec/services/post_status_service_spec.rb | 23 +++++++++++++++++++ 8 files changed, 39 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index 2263fc542d..1a65aee51f 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -73,6 +73,7 @@ const messages = defineMessages({ limited_short: { id: 'privacy.limited.short', defaultMessage: 'Limited menbers only' }, mutual_short: { id: 'privacy.mutual.short', defaultMessage: 'Mutual followers only' }, circle_short: { id: 'privacy.circle.short', defaultMessage: 'Circle members only' }, + personal_short: { id: 'privacy.personal.short', defaultMessage: 'Yourself only' }, direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' }, edited: { id: 'status.edited', defaultMessage: 'Edited {date}' }, }); @@ -405,6 +406,7 @@ class Status extends ImmutablePureComponent { 'limited': { icon: 'get-pocket', text: intl.formatMessage(messages.limited_short) }, 'mutual': { icon: 'exchange', text: intl.formatMessage(messages.mutual_short) }, 'circle': { icon: 'user-circle', text: intl.formatMessage(messages.circle_short) }, + 'personal': { icon: 'sticky-note-o', text: intl.formatMessage(messages.personal_short) }, 'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) }, }; diff --git a/app/javascript/mastodon/features/report/components/status_check_box.jsx b/app/javascript/mastodon/features/report/components/status_check_box.jsx index a9610db75c..81b58296d5 100644 --- a/app/javascript/mastodon/features/report/components/status_check_box.jsx +++ b/app/javascript/mastodon/features/report/components/status_check_box.jsx @@ -23,6 +23,7 @@ const messages = defineMessages({ limited_short: { id: 'privacy.limited.short', defaultMessage: 'Limited menbers only' }, mutual_short: { id: 'privacy.mutual.short', defaultMessage: 'Mutual followers only' }, circle_short: { id: 'privacy.circle.short', defaultMessage: 'Circle members only' }, + personal_short: { id: 'privacy.personal.short', defaultMessage: 'Yourself only' }, direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' }, }); @@ -57,6 +58,7 @@ class StatusCheckBox extends PureComponent { 'limited': { icon: 'get-pocket', text: intl.formatMessage(messages.limited_short) }, 'mutual': { icon: 'exchange', text: intl.formatMessage(messages.mutual_short) }, 'circle': { icon: 'user-circle', text: intl.formatMessage(messages.circle_short) }, + 'personal': { icon: 'sticky-note-o', text: intl.formatMessage(messages.personal_short) }, 'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) }, }; diff --git a/app/javascript/mastodon/features/status/components/detailed_status.jsx b/app/javascript/mastodon/features/status/components/detailed_status.jsx index 63772a83d8..e9568bf9d0 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.jsx +++ b/app/javascript/mastodon/features/status/components/detailed_status.jsx @@ -35,6 +35,7 @@ const messages = defineMessages({ limited_short: { id: 'privacy.limited.short', defaultMessage: 'Limited menbers only' }, mutual_short: { id: 'privacy.mutual.short', defaultMessage: 'Mutual followers only' }, circle_short: { id: 'privacy.circle.short', defaultMessage: 'Circle members only' }, + personal_short: { id: 'privacy.personal.short', defaultMessage: 'Yourself only' }, direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' }, searchability_public_short: { id: 'searchability.public.short', defaultMessage: 'Public' }, searchability_private_short: { id: 'searchability.unlisted.short', defaultMessage: 'Followers' }, @@ -260,6 +261,7 @@ class DetailedStatus extends ImmutablePureComponent { 'limited': { icon: 'get-pocket', text: intl.formatMessage(messages.limited_short) }, 'mutual': { icon: 'exchange', text: intl.formatMessage(messages.mutual_short) }, 'circle': { icon: 'user-circle', text: intl.formatMessage(messages.circle_short) }, + 'personal': { icon: 'sticky-note-o', text: intl.formatMessage(messages.personal_short) }, 'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) }, }; diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.jsx b/app/javascript/mastodon/features/ui/components/boost_modal.jsx index fed1ef69df..f1a026b2b3 100644 --- a/app/javascript/mastodon/features/ui/components/boost_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/boost_modal.jsx @@ -30,6 +30,7 @@ const messages = defineMessages({ limited_short: { id: 'privacy.limited.short', defaultMessage: 'Limited menbers only' }, mutual_short: { id: 'privacy.mutual.short', defaultMessage: 'Mutual followers only' }, circle_short: { id: 'privacy.circle.short', defaultMessage: 'Circle members only' }, + personal_short: { id: 'privacy.personal.short', defaultMessage: 'Yourself only' }, direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' }, }); @@ -100,6 +101,7 @@ class BoostModal extends ImmutablePureComponent { 'limited': { icon: 'get-pocket', text: intl.formatMessage(messages.limited_short) }, 'mutual': { icon: 'exchange', text: intl.formatMessage(messages.mutual_short) }, 'circle': { icon: 'user-circle', text: intl.formatMessage(messages.circle_short) }, + 'personal': { icon: 'sticky-note-o', text: intl.formatMessage(messages.personal_short) }, 'direct': { icon: 'at', text: intl.formatMessage(messages.direct_short) }, }; diff --git a/app/models/status.rb b/app/models/status.rb index 7916b95326..c16c1a7c4f 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -58,7 +58,7 @@ class Status < ApplicationRecord enum visibility: { public: 0, unlisted: 1, private: 2, direct: 3, limited: 4, public_unlisted: 10, login: 11 }, _suffix: :visibility enum searchability: { public: 0, private: 1, direct: 2, limited: 3, unsupported: 4, public_unlisted: 10 }, _suffix: :searchability - enum limited_scope: { none: 0, mutual: 1, circle: 2 }, _suffix: :limited + enum limited_scope: { none: 0, mutual: 1, circle: 2, personal: 3 }, _suffix: :limited belongs_to :application, class_name: 'Doorkeeper::Application', optional: true diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index 981fad7d75..bdc1bbb576 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -145,6 +145,8 @@ class PostStatusService < BaseService process_mentions_service.call(@status, limited_type: @status.limited_visibility? ? @limited_scope : '', circle: @circle, save_records: false) safeguard_mentions!(@status) + @status.limited_scope = :personal if @status.limited_visibility? && !process_mentions_service.mentions? + UpdateStatusExpirationService.new.call(@status) # The following transaction block is needed to wrap the UPDATEs to @@ -221,7 +223,7 @@ class PostStatusService < BaseService end def process_mentions_service - ProcessMentionsService.new + @process_mentions_service ||= ProcessMentionsService.new end def process_hashtags_service diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb index 0a5b48a9d9..5053cf4ce3 100644 --- a/app/services/process_mentions_service.rb +++ b/app/services/process_mentions_service.rb @@ -24,6 +24,10 @@ class ProcessMentionsService < BaseService end end + def mentions? + @current_mentions.present? + end + private def scan_text! diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index a2cf6fbfb0..a719b37e3d 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -188,6 +188,17 @@ RSpec.describe PostStatusService, type: :service do expect(status.mentioned_accounts.first.id).to eq mutual_account.id end + it 'personal visibility with mutual' do + account = Fabricate(:account) + text = 'This is an English text.' + + status = subject.call(account, text: text, visibility: 'mutual') + + expect(status.visibility).to eq 'limited' + expect(status.limited_scope).to eq 'personal' + expect(status.mentioned_accounts.count).to eq 0 + end + it 'circle visibility' do account = Fabricate(:account) circle_account = Fabricate(:account) @@ -227,6 +238,18 @@ RSpec.describe PostStatusService, type: :service do expect { subject.call(account, text: text, visibility: 'limited') }.to raise_exception ActiveRecord::RecordInvalid end + it 'personal visibility with circle' do + account = Fabricate(:account) + circle = Fabricate(:circle, account: account) + text = 'This is an English text.' + + status = subject.call(account, text: text, visibility: 'circle', circle_id: circle.id) + + expect(status.visibility).to eq 'limited' + expect(status.limited_scope).to eq 'personal' + expect(status.mentioned_accounts.count).to eq 0 + end + it 'safeguards mentions' do account = Fabricate(:account) mentioned_account = Fabricate(:account, username: 'alice') From 1bd7455d81ea7146efb90413c4a89ea21c65310d Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 25 Sep 2023 15:06:43 +0200 Subject: [PATCH 35/69] =?UTF-8?q?Fix=20inefficient=20queries=20in=20?= =?UTF-8?q?=E2=80=9CFollows=20and=20followers=E2=80=9D=20as=20well=20as=20?= =?UTF-8?q?several=20admin=20pages=20(#27116)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/relationship_filter.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/relationship_filter.rb b/app/models/relationship_filter.rb index 3d75dce05e..955d7d188a 100644 --- a/app/models/relationship_filter.rb +++ b/app/models/relationship_filter.rb @@ -62,13 +62,13 @@ class RelationshipFilter def relationship_scope(value) case value when 'following' - account.following.eager_load(:account_stat).reorder(nil) + account.following.includes(:account_stat).reorder(nil) when 'followed_by' - account.followers.eager_load(:account_stat).reorder(nil) + account.followers.includes(:account_stat).reorder(nil) when 'mutual' - account.followers.eager_load(:account_stat).reorder(nil).merge(Account.where(id: account.following)) + account.followers.includes(:account_stat).reorder(nil).merge(Account.where(id: account.following)) when 'invited' - Account.joins(user: :invite).merge(Invite.where(user: account.user)).eager_load(:account_stat).reorder(nil) + Account.joins(user: :invite).merge(Invite.where(user: account.user)).includes(:account_stat).reorder(nil) else raise Mastodon::InvalidParameterError, "Unknown relationship: #{value}" end From 38753acaa562d6d69dcb0688a57a37655cb094ea Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 25 Sep 2023 15:06:57 +0200 Subject: [PATCH 36/69] Fix width of large text icon buttons (#27127) --- .../mastodon/features/compose/components/text_icon_button.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/compose/components/text_icon_button.jsx b/app/javascript/mastodon/features/compose/components/text_icon_button.jsx index 46b5d7fada..166d022b88 100644 --- a/app/javascript/mastodon/features/compose/components/text_icon_button.jsx +++ b/app/javascript/mastodon/features/compose/components/text_icon_button.jsx @@ -4,7 +4,7 @@ import { PureComponent } from 'react'; const iconStyle = { height: null, lineHeight: '27px', - width: `${18 * 1.28571429}px`, + minWidth: `${18 * 1.28571429}px`, }; export default class TextIconButton extends PureComponent { From 3de6dcf6343d68d695ff8087419217530019b05c Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 25 Sep 2023 15:07:10 +0200 Subject: [PATCH 37/69] Add redirection on `/deck` URLs for logged-out users (#27128) --- app/lib/permalink_redirector.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/lib/permalink_redirector.rb b/app/lib/permalink_redirector.rb index 0fcec683d9..0dd37483e2 100644 --- a/app/lib/permalink_redirector.rb +++ b/app/lib/permalink_redirector.rb @@ -14,6 +14,8 @@ class PermalinkRedirector find_account_url_by_name(first_segment) elsif accounts_request? && record_integer_id_request? find_account_url_by_id(second_segment) + elsif @path.start_with?('/deck') + @path.delete_prefix('/deck') end end @@ -52,7 +54,7 @@ class PermalinkRedirector end def path_segments - @path_segments ||= @path.delete_prefix('/').split('/') + @path_segments ||= @path.delete_prefix('/deck').delete_prefix('/').split('/') end def find_status_url_by_id(id) From a001ae2f3943d8ac111c6437ee6ff890e94544ac Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 25 Sep 2023 17:07:01 +0200 Subject: [PATCH 38/69] Fix explore prompt sometimes showing up when the home TL is loading (#27062) --- app/javascript/mastodon/features/home_timeline/index.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/features/home_timeline/index.jsx b/app/javascript/mastodon/features/home_timeline/index.jsx index 8ff0377946..63d373b9a9 100644 --- a/app/javascript/mastodon/features/home_timeline/index.jsx +++ b/app/javascript/mastodon/features/home_timeline/index.jsx @@ -55,8 +55,10 @@ const homeTooSlow = createSelector([ getHomeFeedSpeed, ], (isLoading, isPartial, speed) => !isLoading && !isPartial // Only if the home feed has finished loading - && (speed.gap > (30 * 60) // If the average gap between posts is more than 20 minutes - || (Date.now() - speed.newest) > (1000 * 3600)) // If the most recent post is from over an hour ago + && ( + (speed.gap > (30 * 60) // If the average gap between posts is more than 30 minutes + || (Date.now() - speed.newest) > (1000 * 3600)) // If the most recent post is from over an hour ago + ) ); const mapStateToProps = state => ({ From 06444c86c7a2a362cd0027adb4ed01721a2036af Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 25 Sep 2023 17:07:52 +0200 Subject: [PATCH 39/69] Fix division by zero in video in bitrate computation code (#27129) --- lib/paperclip/transcoder.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/paperclip/transcoder.rb b/lib/paperclip/transcoder.rb index ed5425a3b8..d2d946d3ad 100644 --- a/lib/paperclip/transcoder.rb +++ b/lib/paperclip/transcoder.rb @@ -43,7 +43,8 @@ module Paperclip unless eligible_to_passthrough?(metadata) size_limit_in_bits = MediaAttachment::VIDEO_LIMIT * 8 desired_bitrate = (metadata.width * metadata.height * 30 * BITS_PER_PIXEL).floor - maximum_bitrate = (size_limit_in_bits / metadata.duration).floor - 192_000 # Leave some space for the audio stream + duration = [metadata.duration, 1].max + maximum_bitrate = (size_limit_in_bits / duration).floor - 192_000 # Leave some space for the audio stream bitrate = [desired_bitrate, maximum_bitrate].min @output_options['b:v'] = bitrate From cf9230fa1ca1e2222c5e411f2f6b2415f2def541 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:38:55 +0200 Subject: [PATCH 40/69] Update docker/build-push-action action to v5 (#27120) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build-container-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-container-image.yml b/.github/workflows/build-container-image.yml index aa9e74e7e9..2abcc9a358 100644 --- a/.github/workflows/build-container-image.yml +++ b/.github/workflows/build-container-image.yml @@ -83,7 +83,7 @@ jobs: tags: ${{ inputs.tags }} labels: ${{ inputs.labels }} - - uses: docker/build-push-action@v4 + - uses: docker/build-push-action@v5 with: context: . build-args: | From 19bc73b736bf26d5126148f6d0b9fbc5e737b34c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:39:14 +0200 Subject: [PATCH 41/69] Update docker/login-action action to v3 (#27121) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build-container-image.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-container-image.yml b/.github/workflows/build-container-image.yml index 2abcc9a358..7aa30ead5c 100644 --- a/.github/workflows/build-container-image.yml +++ b/.github/workflows/build-container-image.yml @@ -61,14 +61,14 @@ jobs: - name: Log in to Docker Hub if: contains(inputs.push_to_images, 'tootsuite') - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Log in to the Github Container registry if: contains(inputs.push_to_images, 'ghcr.io') - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} From 8ea98aa3843203a8937e494e682bf4974789fdd9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:40:03 +0200 Subject: [PATCH 42/69] Update docker/metadata-action action to v5 (#27122) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build-container-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-container-image.yml b/.github/workflows/build-container-image.yml index 7aa30ead5c..b35138030c 100644 --- a/.github/workflows/build-container-image.yml +++ b/.github/workflows/build-container-image.yml @@ -74,7 +74,7 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - uses: docker/metadata-action@v4 + - uses: docker/metadata-action@v5 id: meta if: ${{ inputs.push_to_images != '' }} with: From cdd8c4eb2ac6439779637b018e1f1fa8904cc025 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:40:41 +0200 Subject: [PATCH 43/69] Update docker/setup-buildx-action action to v3 (#27123) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build-container-image.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-container-image.yml b/.github/workflows/build-container-image.yml index b35138030c..fe981fb013 100644 --- a/.github/workflows/build-container-image.yml +++ b/.github/workflows/build-container-image.yml @@ -32,7 +32,7 @@ jobs: - uses: docker/setup-qemu-action@v2 if: contains(inputs.platforms, 'linux/arm64') && !inputs.use_native_arm64_builder - - uses: docker/setup-buildx-action@v2 + - uses: docker/setup-buildx-action@v3 id: buildx if: ${{ !(inputs.use_native_arm64_builder && contains(inputs.platforms, 'linux/arm64')) }} @@ -41,7 +41,7 @@ jobs: run: | docker run --rm -d --name buildkitd -p 1234:1234 --privileged moby/buildkit:latest --addr tcp://0.0.0.0:1234 - - uses: docker/setup-buildx-action@v2 + - uses: docker/setup-buildx-action@v3 id: buildx-native if: inputs.use_native_arm64_builder && contains(inputs.platforms, 'linux/arm64') with: From 530f48610d2f7590c333ee7fd5897c815bfe4769 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:41:20 +0200 Subject: [PATCH 44/69] Update docker/setup-qemu-action action to v3 (#27124) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build-container-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-container-image.yml b/.github/workflows/build-container-image.yml index fe981fb013..29868c72f8 100644 --- a/.github/workflows/build-container-image.yml +++ b/.github/workflows/build-container-image.yml @@ -29,7 +29,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: docker/setup-qemu-action@v2 + - uses: docker/setup-qemu-action@v3 if: contains(inputs.platforms, 'linux/arm64') && !inputs.use_native_arm64_builder - uses: docker/setup-buildx-action@v3 From bd810391d609de5296c229797e5770ad50680a41 Mon Sep 17 00:00:00 2001 From: Essem Date: Mon, 25 Sep 2023 12:21:07 -0500 Subject: [PATCH 45/69] Properly remove tIME chunk from PNG uploads (#27111) --- app/models/concerns/account_avatar.rb | 2 +- app/models/concerns/account_header.rb | 2 +- app/models/custom_emoji.rb | 2 +- app/models/media_attachment.rb | 2 +- app/models/preview_card.rb | 2 +- app/models/preview_card_provider.rb | 2 +- app/models/site_upload.rb | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/models/concerns/account_avatar.rb b/app/models/concerns/account_avatar.rb index e9b8b4adba..b5919a9a23 100644 --- a/app/models/concerns/account_avatar.rb +++ b/app/models/concerns/account_avatar.rb @@ -18,7 +18,7 @@ module AccountAvatar included do # Avatar upload - has_attached_file :avatar, styles: ->(f) { avatar_styles(f) }, convert_options: { all: '+profile "!icc,*" +set modify-date +set create-date' }, processors: [:lazy_thumbnail] + has_attached_file :avatar, styles: ->(f) { avatar_styles(f) }, convert_options: { all: '+profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, processors: [:lazy_thumbnail] validates_attachment_content_type :avatar, content_type: IMAGE_MIME_TYPES validates_attachment_size :avatar, less_than: LIMIT remotable_attachment :avatar, LIMIT, suppress_errors: false diff --git a/app/models/concerns/account_header.rb b/app/models/concerns/account_header.rb index 0d197abfcd..e184880f93 100644 --- a/app/models/concerns/account_header.rb +++ b/app/models/concerns/account_header.rb @@ -19,7 +19,7 @@ module AccountHeader included do # Header upload - has_attached_file :header, styles: ->(f) { header_styles(f) }, convert_options: { all: '+profile "!icc,*" +set modify-date +set create-date' }, processors: [:lazy_thumbnail] + has_attached_file :header, styles: ->(f) { header_styles(f) }, convert_options: { all: '+profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, processors: [:lazy_thumbnail] validates_attachment_content_type :header, content_type: IMAGE_MIME_TYPES validates_attachment_size :header, less_than: LIMIT remotable_attachment :header, LIMIT, suppress_errors: false diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index f66353fadd..717de27723 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -39,7 +39,7 @@ class CustomEmoji < ApplicationRecord has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode, inverse_of: false - has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set modify-date +set create-date' } }, validate_media_type: false + has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' } }, validate_media_type: false before_validation :downcase_domain diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 2d1b70661b..b567003fb9 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -171,7 +171,7 @@ class MediaAttachment < ApplicationRecord DEFAULT_STYLES = [:original].freeze GLOBAL_CONVERT_OPTIONS = { - all: '-quality 90 +profile "!icc,*" +set modify-date -define jpeg:dct-method=float +set create-date', + all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp -define jpeg:dct-method=float', }.freeze belongs_to :account, inverse_of: :media_attachments, optional: true diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb index 3e2b5bf992..4e24fab240 100644 --- a/app/models/preview_card.rb +++ b/app/models/preview_card.rb @@ -53,7 +53,7 @@ class PreviewCard < ApplicationRecord has_and_belongs_to_many :statuses has_one :trend, class_name: 'PreviewCardTrend', inverse_of: :preview_card, dependent: :destroy - has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set modify-date +set create-date' }, validate_media_type: false + has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, validate_media_type: false validates :url, presence: true, uniqueness: true validates_attachment_content_type :image, content_type: IMAGE_MIME_TYPES diff --git a/app/models/preview_card_provider.rb b/app/models/preview_card_provider.rb index f3e4b49013..8ba24331bb 100644 --- a/app/models/preview_card_provider.rb +++ b/app/models/preview_card_provider.rb @@ -27,7 +27,7 @@ class PreviewCardProvider < ApplicationRecord validates :domain, presence: true, uniqueness: true, domain: true - has_attached_file :icon, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set modify-date +set create-date' } }, validate_media_type: false + has_attached_file :icon, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' } }, validate_media_type: false validates_attachment :icon, content_type: { content_type: ICON_MIME_TYPES }, size: { less_than: LIMIT } remotable_attachment :icon, LIMIT diff --git a/app/models/site_upload.rb b/app/models/site_upload.rb index 2335ffac53..03d472cdb2 100644 --- a/app/models/site_upload.rb +++ b/app/models/site_upload.rb @@ -41,7 +41,7 @@ class SiteUpload < ApplicationRecord mascot: {}.freeze, }.freeze - has_attached_file :file, styles: ->(file) { STYLES[file.instance.var.to_sym] }, convert_options: { all: '-coalesce +profile "!icc,*" +set modify-date +set create-date' }, processors: [:lazy_thumbnail, :blurhash_transcoder, :type_corrector] + has_attached_file :file, styles: ->(file) { STYLES[file.instance.var.to_sym] }, convert_options: { all: '-coalesce +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, processors: [:lazy_thumbnail, :blurhash_transcoder, :type_corrector] validates_attachment_content_type :file, content_type: %r{\Aimage/.*\z} validates :file, presence: true From 33a066a952fbd0689facc61ae9eacce1ea401553 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 10:47:04 +0200 Subject: [PATCH 46/69] Update dependency glob to v10.3.8 (#27145) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index 41ac832d1a..b9571d4248 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6227,12 +6227,12 @@ glob-parent@^6.0.2: is-glob "^4.0.3" glob@^10.2.5, glob@^10.2.6: - version "10.3.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.7.tgz#d5bd30a529c8c9b262fb4b217941f64ad90e25ac" - integrity sha512-wCMbE1m9Nx5yD9LYtgsVWq5VhHlk5WzJirw594qZR6AIvQYuHrdDtIktUVjQItalD53y7dqoedu9xP0u0WaxIQ== + version "10.3.8" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.8.tgz#186499f88ba2e7342ed7f4c1e60acdfe477d94f4" + integrity sha512-0z5t5h4Pxtqi+8ozm+j7yMI/bQ1sBeg4oAUGkDPUguaY2YZB76gtlllWoxWEHo02E5qAjsELwVX8g8Wk6RvQog== dependencies: foreground-child "^3.1.0" - jackspeak "^2.0.3" + jackspeak "^2.3.5" minimatch "^9.0.1" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-scurry "^1.10.1" @@ -7346,10 +7346,10 @@ iterator.prototype@^1.1.0: has-tostringtag "^1.0.0" reflect.getprototypeof "^1.0.3" -jackspeak@^2.0.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.3.tgz#95e4cbcc03b3eb357bf6bcce14a903fb3d1151e1" - integrity sha512-R2bUw+kVZFS/h1AZqBKrSgDmdmjApzgY0AlCPumopFiAlbUxE2gf+SCuBzQ0cP5hHmUmFYF5yw55T97Th5Kstg== +jackspeak@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.5.tgz#443f237f9eeeb0d7c6ec34835ef5289bb4acb068" + integrity sha512-Ratx+B8WeXLAtRJn26hrhY8S1+Jz6pxPMrkrdkgb/NstTNiqMhX0/oFVu5wX+g5n6JlEu2LPsDJmY8nRP4+alw== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -11461,7 +11461,6 @@ stringz@^2.1.0: char-regex "^1.0.2" "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: - name strip-ansi-cjs version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== From 5ea3e8e765e0a0ae8e60c3e4e0b03cd3604ffdf1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 10:47:16 +0200 Subject: [PATCH 47/69] New Crowdin Translations (automated) (#27144) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/sr-Latn.json | 4 ++-- app/javascript/mastodon/locales/sr.json | 4 ++-- config/locales/devise.sr-Latn.yml | 8 ++++---- config/locales/devise.sr.yml | 8 ++++---- config/locales/simple_form.lv.yml | 2 +- config/locales/sk.yml | 3 +++ config/locales/sr-Latn.yml | 10 +++++----- config/locales/sr.yml | 10 +++++----- 8 files changed, 26 insertions(+), 23 deletions(-) diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 6fe5603f40..9750784bbc 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -302,8 +302,8 @@ "hashtag.follow": "Zaprati heš oznaku", "hashtag.unfollow": "Otprati heš oznaku", "hashtags.and_other": "…i {count, plural, one {još #} few {još #}other {još #}}", - "home.actions.go_to_explore": "Pogledaj šta je u trendu", - "home.actions.go_to_suggestions": "Pronađite ljude za praćenje", + "home.actions.go_to_explore": "Pogledate šta je u trendu", + "home.actions.go_to_suggestions": "Pronađete ljude koje biste pratili", "home.column_settings.basic": "Osnovna", "home.column_settings.show_reblogs": "Prikaži podržavanja", "home.column_settings.show_replies": "Prikaži odgovore", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index f3c077cf31..bb4739cbcc 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -302,8 +302,8 @@ "hashtag.follow": "Запрати хеш ознаку", "hashtag.unfollow": "Отпрати хеш ознаку", "hashtags.and_other": "…и {count, plural, one {још #} few {још #}other {још #}}", - "home.actions.go_to_explore": "Погледај шта је у тренду", - "home.actions.go_to_suggestions": "Пронађите људе за праћење", + "home.actions.go_to_explore": "Погледате шта је у тренду", + "home.actions.go_to_suggestions": "Пронађeте људе које бисте пратили", "home.column_settings.basic": "Основна", "home.column_settings.show_reblogs": "Прикажи подржавања", "home.column_settings.show_replies": "Прикажи одговоре", diff --git a/config/locales/devise.sr-Latn.yml b/config/locales/devise.sr-Latn.yml index 836f83a9a5..6b4a5801c6 100644 --- a/config/locales/devise.sr-Latn.yml +++ b/config/locales/devise.sr-Latn.yml @@ -18,13 +18,13 @@ sr-Latn: unconfirmed: Pre nastavka morate potvrditi svoj nalog. mailer: confirmation_instructions: - action: Potvrdite adresu e-pošte + action: Verifikujte adresu e-pošte action_with_app: Potvrdi i vrati se na %{app} explanation: Napravili ste nalog na %{host} sa adresom ove e-pošte. Na jedan klik ste udaljeni od aktiviranja. Ako ovo niste vi, molimo ignorišite ovu e-poštu. explanation_when_pending: Prijavili ste se za poziv %{host} sa ovim imejlom. Kada potvrdite svoj imejl, pregledaćemo vašu prijavu. Možete se prijaviti da biste promenili detalje ili izbrisali nalog, ali ne možete pristupiti većini funkcija dok vam nalog ne bude odobren. Ako vaša prijava bude odbijena, vaši podaci će biti uklonjeni, tako da od vas neće biti potrebne dalje radnje. Ako ovo niste bili vi, zanemarite ovaj imejl. extra_html: Molimo da takođe proverite pravila ove instance i naše uslove korišćenja. subject: 'Mastodont: Uputstvo za potvrdu korisničkog naloga na instanci %{instance}' - title: Potvrdite adresu e-pošte + title: Verifikujte adresu e-pošte email_changed: explanation: 'Adresa ove e-pošte za vaš nalog će biti promenjena u:' extra: Ako niste promenili vašu e-poštu, sasvim je moguće da je neko drugi dobio pristup vašem nalogu. Molimo promenite lozinku odmah ili kontaktirajte administratora instance ako ste zaključani izvan vašeg naloga. @@ -39,7 +39,7 @@ sr-Latn: explanation: Potvrdite novu adresu da biste promenili e-poštu. extra: Ako ova promena nije inicirana sa vaše strane, molimo ignorišite ovu e-poštu. Adresa e-pošta za ovaj Mastodon nalog neće biti promenjena dok ne pristupite poveznici/linku iznad. subject: 'Mastodon: Potvrdite e-poštu za %{instance}' - title: Potvrdite adresu e-pošte + title: Verifikujte adresu e-pošte reset_password_instructions: action: Lozinka promenjena explanation: Zatražili ste novu lozinku za vaš nalog. @@ -93,7 +93,7 @@ sr-Latn: signed_up_but_locked: Uspešno ste se registrovali. Nažalost ne možete se prijaviti zato što je Vaš nalog zaključan. signed_up_but_pending: Na vaš imejl poslata je poruka sa vezom za potvrdu. Nakon što kliknete na vezu, pregledaćemo vašu prijavu. Bićete obavešteni ako bude odobreno. signed_up_but_unconfirmed: Poruka za potvrdu Vašeg naloga je poslata na Vašu imejl adresu. Kliknite na vezu u imejlu da potvrdite svoj nalog. Molimo proverite i spam fasciklu ako niste primili poruku. - update_needs_confirmation: Uspešno ste ažurirali svoj nalog, ali treba da potvrdimo novu adresu Vaše e-pošte. Molimo Vas da proverite e-poštu i pratite link za potvrdu nove adrese Vaše e-pošte. + update_needs_confirmation: Uspešno ste ažurirali svoj nalog, ali moramo da verifikujemo vašu novu adresu e-pošte. Proverite svoju e-poštu i pratite vezu za potvrdu da biste potvrdili novu adresu e-pošte. Proverite svoju fasciklu neželjene pošte ako niste primili ovu e-poštu. updated: Vaš nalog je uspešno ažuriran. sessions: already_signed_out: Uspešno ste se odjavili. diff --git a/config/locales/devise.sr.yml b/config/locales/devise.sr.yml index b1be1eebfa..d55cf7a268 100644 --- a/config/locales/devise.sr.yml +++ b/config/locales/devise.sr.yml @@ -18,13 +18,13 @@ sr: unconfirmed: Пре наставка морате потврдити свој налог. mailer: confirmation_instructions: - action: Потврдите адресу е-поште + action: Верификујте адресу е-поште action_with_app: Потврди и врати се на %{app} explanation: Направили сте налог на %{host} са адресом ове е-поште. На један клик сте удаљени од активирања. Ако ово нисте ви, молимо игноришите ову е-пошту. explanation_when_pending: Пријавили сте се за позив %{host} са овим имејлом. Када потврдите свој имејл, прегледаћемо вашу пријаву. Можете се пријавити да бисте променили детаље или избрисали налог, али не можете приступити већини функција док вам налог не буде одобрен. Ако ваша пријава буде одбијена, ваши подаци ће бити уклоњени, тако да од вас неће бити потребне даље радње. Ако ово нисте били ви, занемарите овај имејл. extra_html: Молимо да такође проверите правила ове инстанце и наше услове коришћења. subject: 'Mastodon: Упутство за потврду корисничког налога на инстанци %{instance}' - title: Потврдите адресу е-поште + title: Верификујте адресу е-поште email_changed: explanation: 'Адреса ове е-поште за ваш налог ће бити промењена у:' extra: Ако нисте променили вашу е-пошту, сасвим је могуће да је неко други добио приступ вашем налогу. Молимо промените лозинку одмах или контактирајте администратора инстанце ако сте закључани изван вашег налога. @@ -39,7 +39,7 @@ sr: explanation: Потврдите нову адресу да бисте променили е-пошту. extra: Ако ова промена није иницирана са ваше стране, молимо игноришите ову е-пошту. Адреса е-поште за овај Mastodon налог неће бити промењена док не приступите вези изнад. subject: 'Mastodon: Потврдите е-пошту за %{instance}' - title: Потврдите адресу е-поште + title: Верификујте адресу е-поште reset_password_instructions: action: Лозинка промењена explanation: Затражили сте нову лозинку за ваш налог. @@ -93,7 +93,7 @@ sr: signed_up_but_locked: Успешно сте се регистровали. Нажалост не можете се пријавити зато што је Ваш налог закључан. signed_up_but_pending: На ваш имејл послата је порука са везом за потврду. Након што кликнете на везу, прегледаћемо вашу пријаву. Бићете обавештени ако буде одобрено. signed_up_but_unconfirmed: Порука за потврду Вашег налога је послата на Вашу имејл адресу. Кликните на везу у имејлу да потврдите свој налог. Молимо проверите и спам фасциклу ако нисте примили поруку. - update_needs_confirmation: Uспешно сте ажурирали свој налог, али треба да потврдимо нову адресу Ваше е-поште. Молимо Вас да проверите е-пошту и пратите линк за потврду нове адресе Ваше е-поште. + update_needs_confirmation: Успешно сте ажурирали свој налог, али морамо да верификујемо вашу нову адресу е-поште. Проверите своју е-пошту и пратите везу за потврду да бисте потврдили нову адресу е-поште. Проверите своју фасциклу нежељене поште ако нисте примили ову е-пошту. updated: Ваш налог је успешно ажуриран. sessions: already_signed_out: Успешно сте се одјавили. diff --git a/config/locales/simple_form.lv.yml b/config/locales/simple_form.lv.yml index beff4ee64a..bf831c946f 100644 --- a/config/locales/simple_form.lv.yml +++ b/config/locales/simple_form.lv.yml @@ -301,7 +301,7 @@ lv: rule: text: Noteikumi settings: - indexable: Ietvert profila lapu muklēšanas dzinējos + indexable: Ietvert profila lapu meklēšanas dzinējos show_application: Parādi, no kuras lietotnes nosūtīji ziņu tag: listable: Atļaut šim tēmturim parādīties meklējumos un ieteikumos diff --git a/config/locales/sk.yml b/config/locales/sk.yml index e08d1101ef..78b9b87db3 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -273,6 +273,7 @@ sk: title: Oboznámenia unpublish: Zruš zverejnenie updated_msg: Oboznámenie úspešne aktualizované! + critical_update_pending: Čaká kritická aktualizácia custom_emojis: assign_category: Priraď kategóriu by_domain: Doména @@ -418,6 +419,8 @@ sk: instance_accounts_dimension: Najsledovanejšie účty instance_accounts_measure: uložené účty instance_follows_measure: ich sledovatelia tu + instance_languages_dimension: Najpopulárnejšie jazyky + instance_media_attachments_measure: uložené mediálne prílohy instance_reports_measure: hlásenia o nich instance_statuses_measure: uložené príspevky delivery: diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index 5d6849091a..82fbbff49e 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -1151,7 +1151,7 @@ sr-Latn: x_seconds: "%{count} sek." deletes: challenge_not_passed: Lozinka koju ste uneli nije bila ispravna - confirm_password: Unesite trenutnu lozinku da bismo proverili Vaš identitet + confirm_password: Unesite trenutnu lozinku za verifikaciju vašeg identiteta confirm_username: Unesite svoje korisničko ime da biste potvrdili proceduru proceed: Obriši nalog success_msg: Vaš nalog je uspešno obrisan @@ -1209,8 +1209,8 @@ sr-Latn: '406': Ova stranica nije dostupna u izabranom formatu. '410': Strana koju ste tražili više ne postoji. '422': - content: Bezbedonosna provera nije uspela. Da ne blokirate kolačiće? - title: Bezbedonosna provera nije uspela + content: Bezbedonosna verifikacija nije uspela. Da li blokirate kolačiće? + title: Bezbedonosna verifikacija nije uspela '429': Uspored '500': content: Izvinjavamo se, nešto je pošlo po zlu sa ove strane. @@ -1296,7 +1296,7 @@ sr-Latn: one: "%{count} stavka koja se poklapa sa Vašom pretragom je izabrana." other: Svih %{count} stavki koje se poklapaju sa Vašom pretragom su izabrane. cancel: Otkaži - changes_saved_msg: Izmene uspešno sačuvane! + changes_saved_msg: Promene su uspešno sačuvane! confirm: Potvrdi copy: Kopiraj delete: Izbriši @@ -1864,7 +1864,7 @@ sr-Latn: here_is_how: Evo kako hint_html: "Verifikacija vašeg identiteta na Mastodon-u je za svakoga. Zasnovano na otvorenim veb standardima, sada i zauvek besplatno. Sve što vam treba je lični veb sajt po kome vas ljudi prepoznaju. Kada se povežete sa ovim veb sajtom sa svog profila, proverićemo da li je veb sajt povezan sa vašim profilom i na njemu ćemo prikazati vizuelni indikator." instructions_html: Kopirajte i nalepite kod ispod u HTML svog veb sajta. Zatim dodajte adresu svog veb sajta u jedno od dodatnih polja na svom profilu sa kartice „Uredi profil” i sačuvajte promene. - verification: Provera + verification: Verifikacija verified_links: Vaše verifikovane veze webauthn_credentials: add: Dodajte novi sigurnosni ključ diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 379b9cb9d6..ffddab8697 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -1151,7 +1151,7 @@ sr: x_seconds: "%{count} сек." deletes: challenge_not_passed: Лозинка коју сте унели није била исправна - confirm_password: Унесите тренутну лозинку да бисмо проверили Ваш идентитет + confirm_password: Унесите тренутну лозинку за верификацију вашег идентитета confirm_username: Унесите своје корисничко име да бисте потврдили процедуру proceed: Обриши налог success_msg: Ваш налог је успешно обрисан @@ -1209,8 +1209,8 @@ sr: '406': Ова страница није доступна у изабраном формату. '410': Страна коју сте тражили више не постоји. '422': - content: Безбедоносна провера није успела. Да не блокирате колачиће? - title: Безбедоносна провера није успела + content: Безбедоносна верификација није успела. Да ли блокирате колачиће? + title: Безбедоносна верификација није успела '429': Успоред '500': content: Извињавамо се, нешто је пошло по злу са ове стране. @@ -1296,7 +1296,7 @@ sr: one: "%{count} ставка која се поклапа са Вашом претрагом је изабрана." other: Свих %{count} ставки које се поклапају са Вашом претрагом су изабране. cancel: Откажи - changes_saved_msg: Измене успешно сачуване! + changes_saved_msg: Промене су успешно сачуване! confirm: Потврди copy: Копирај delete: Избриши @@ -1864,7 +1864,7 @@ sr: here_is_how: Ево како hint_html: "Верификација вашег идентитета на Mastodon-у је за свакога. Засновано на отвореним веб стандардима, сада и заувек бесплатно. Све што вам треба је лични веб сајт по коме вас људи препознају. Када се повежете са овим веб сајтом са свог профила, проверићемо да ли је веб сајт повезан са вашим профилом и на њему ћемо приказати визуелни индикатор." instructions_html: Копирајте и налепите код испод у HTML свог веб сајта. Затим додајте адресу свог веб сајта у једно од додатних поља на свом профилу са картице „Уреди профил” и сачувајте промене. - verification: Провера + verification: Верификација verified_links: Ваше верификоване везе webauthn_credentials: add: Додајте нови сигурносни кључ From fdc9f971f7a4320e08c92f6a6e1522e6062ae8c5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 10:47:34 +0200 Subject: [PATCH 48/69] Update dependency selenium-webdriver to v4.13.1 (#27141) 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 13bca58a5c..7842fb69d2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -686,7 +686,7 @@ GEM scenic (1.7.0) activerecord (>= 4.0.0) railties (>= 4.0.0) - selenium-webdriver (4.11.0) + selenium-webdriver (4.13.1) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) @@ -804,7 +804,7 @@ GEM rack-proxy (>= 0.6.1) railties (>= 5.2) semantic_range (>= 2.3.0) - websocket (1.2.9) + websocket (1.2.10) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) From 13c51133d34be32457de4dd35c275aca216b2452 Mon Sep 17 00:00:00 2001 From: KMY Date: Tue, 26 Sep 2023 17:53:36 +0900 Subject: [PATCH 49/69] Fix always set public visibility when login visibility is locked --- app/javascript/mastodon/reducers/compose.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index c57fa01761..2947012fd4 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -58,7 +58,7 @@ import { import { REDRAFT } from '../actions/statuses'; import { STORE_HYDRATE } from '../actions/store'; import { TIMELINE_DELETE } from '../actions/timelines'; -import { enableLocalPrivacy, me } from '../initial_state'; +import { enableLocalPrivacy, enableLoginPrivacy, me } from '../initial_state'; import { unescapeHTML } from '../utils/html'; import { uuid } from '../uuid'; @@ -138,7 +138,7 @@ function clearAll(state) { if (state.get('stay_privacy') && !state.get('in_reply_to')) { map.set('default_privacy', state.get('privacy')); } - if (map.get('privacy') && !enableLocalPrivacy) { + if ((map.get('privacy') === 'login' && !enableLoginPrivacy) || (map.get('privacy') === 'public_unlisted' && !enableLocalPrivacy)) { map.set('privacy', 'public'); } if (!state.get('in_reply_to')) { From 28ab1ca973ec8aaa6525d9ca2d2b69546e1c363d Mon Sep 17 00:00:00 2001 From: KMY Date: Tue, 26 Sep 2023 18:05:58 +0900 Subject: [PATCH 50/69] #24 Fix editing circle post icon --- .../mastodon/features/compose/components/compose_form.jsx | 4 ++-- .../features/compose/containers/circle_select_container.js | 2 +- app/javascript/mastodon/reducers/compose.js | 6 +++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/features/compose/components/compose_form.jsx b/app/javascript/mastodon/features/compose/components/compose_form.jsx index 9782aa17bc..ef98aae479 100644 --- a/app/javascript/mastodon/features/compose/components/compose_form.jsx +++ b/app/javascript/mastodon/features/compose/components/compose_form.jsx @@ -103,11 +103,11 @@ class ComposeForm extends ImmutablePureComponent { }; canSubmit = () => { - const { isSubmitting, isChangingUpload, isUploading, anyMedia, privacy, circleId } = this.props; + const { isSubmitting, isChangingUpload, isUploading, anyMedia, privacy, circleId, isEditing } = this.props; const fulltext = this.getFulltextForCharacterCounting(); const isOnlyWhitespace = fulltext.length !== 0 && fulltext.trim().length === 0; - return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia) || (privacy === 'circle' && !circleId)); + return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia) || (privacy === 'circle' && !isEditing && !circleId)); }; handleSubmit = (e) => { diff --git a/app/javascript/mastodon/features/compose/containers/circle_select_container.js b/app/javascript/mastodon/features/compose/containers/circle_select_container.js index c3a81140bd..141288c803 100644 --- a/app/javascript/mastodon/features/compose/containers/circle_select_container.js +++ b/app/javascript/mastodon/features/compose/containers/circle_select_container.js @@ -4,7 +4,7 @@ import { changeCircle } from '../../../actions/compose'; import CircleSelect from '../components/circle_select'; const mapStateToProps = state => ({ - unavailable: state.getIn(['compose', 'privacy']) !== 'circle', + unavailable: state.getIn(['compose', 'privacy']) !== 'circle' || !!state.getIn(['compose', 'id']), circles: state.get('circles'), circleId: state.getIn(['compose', 'circle_id']), }); diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 2947012fd4..44665f23af 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -577,7 +577,11 @@ export default function compose(state = initialState, action) { map.set('id', action.status.get('id')); map.set('text', action.text); map.set('in_reply_to', action.status.get('in_reply_to_id')); - map.set('privacy', action.status.get('visibility_ex')); + if (action.status.get('visibility_ex') !== 'limited') { + map.set('privacy', action.status.get('visibility_ex')); + } else { + map.set('privacy', action.status.get('limited_scope') === 'mutual' ? 'mutual' : 'circle'); + } map.set('media_attachments', action.status.get('media_attachments')); map.set('focusDate', new Date()); map.set('caretPosition', null); From af62d7f96ac4a50041d877242baf309c9b272170 Mon Sep 17 00:00:00 2001 From: KMY Date: Tue, 26 Sep 2023 18:10:21 +0900 Subject: [PATCH 51/69] Dont distribute personal limited post --- app/services/post_status_service.rb | 4 ++-- spec/services/post_status_service_spec.rb | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index bdc1bbb576..bf2ba2cdbf 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -196,9 +196,9 @@ class PostStatusService < BaseService ProcessReferencesService.call_service(@status, @reference_ids, []) LinkCrawlWorker.perform_async(@status.id) DistributionWorker.perform_async(@status.id) - ActivityPub::DistributionWorker.perform_async(@status.id) + ActivityPub::DistributionWorker.perform_async(@status.id) unless @status.personal_limited? PollExpirationNotifyWorker.perform_at(@status.poll.expires_at, @status.poll.id) if @status.poll - GroupReblogService.new.call(@status) + GroupReblogService.new.call(@status) unless @status.personal_limited? end def validate_status! diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index a719b37e3d..2e513b9ca4 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -293,6 +293,19 @@ RSpec.describe PostStatusService, type: :service do expect(ActivityPub::DistributionWorker).to have_received(:perform_async).with(status.id) end + it 'gets distributed when personal post' do + allow(DistributionWorker).to receive(:perform_async) + allow(ActivityPub::DistributionWorker).to receive(:perform_async) + + account = Fabricate(:account) + + empty_circle = Fabricate(:circle, account: account) + status = subject.call(account, text: 'test status update', visibility: 'circle', circle_id: empty_circle.id) + + expect(DistributionWorker).to have_received(:perform_async).with(status.id) + expect(ActivityPub::DistributionWorker).to_not have_received(:perform_async).with(status.id) + end + it 'crawls links' do allow(LinkCrawlWorker).to receive(:perform_async) account = Fabricate(:account) From 82eaa26d87ccba69ba36c31c952f5c18d03460a9 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 26 Sep 2023 11:11:52 +0200 Subject: [PATCH 52/69] Update `tootctl maintenance fix-duplicates` to Mastodon v4.2.0 (#27147) --- lib/mastodon/cli/maintenance.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/mastodon/cli/maintenance.rb b/lib/mastodon/cli/maintenance.rb index e9badfb8d1..e73bcbf86a 100644 --- a/lib/mastodon/cli/maintenance.rb +++ b/lib/mastodon/cli/maintenance.rb @@ -5,7 +5,7 @@ require_relative 'base' module Mastodon::CLI class Maintenance < Base MIN_SUPPORTED_VERSION = 2019_10_01_213028 - MAX_SUPPORTED_VERSION = 2022_11_04_133904 + MAX_SUPPORTED_VERSION = 2023_09_07_150100 # Stubs to enjoy ActiveRecord queries while not depending on a particular # version of the code/database @@ -37,6 +37,8 @@ module Mastodon::CLI class CanonicalEmailBlock < ApplicationRecord; end class Appeal < ApplicationRecord; end class Webhook < ApplicationRecord; end + class BulkImport < ApplicationRecord; end + class SoftwareUpdate < ApplicationRecord; end class PreviewCard < ApplicationRecord self.inheritance_column = false @@ -86,6 +88,7 @@ module Mastodon::CLI owned_classes << FollowRecommendationSuppression if ActiveRecord::Base.connection.table_exists?(:follow_recommendation_suppressions) owned_classes << AccountIdentityProof if ActiveRecord::Base.connection.table_exists?(:account_identity_proofs) owned_classes << Appeal if ActiveRecord::Base.connection.table_exists?(:appeals) + owned_classes << BulkImport if ActiveRecord::Base.connection.table_exists?(:bulk_imports) owned_classes.each do |klass| klass.where(account_id: other_account.id).find_each do |record| @@ -169,6 +172,7 @@ module Mastodon::CLI deduplicate_tags! deduplicate_webauthn_credentials! deduplicate_webhooks! + deduplicate_software_updates! Scenic.database.refresh_materialized_view('instances', concurrently: true, cascade: false) if ActiveRecord::Migrator.current_version >= 2020_12_06_004238 Rails.cache.clear @@ -204,6 +208,7 @@ module Mastodon::CLI ActiveRecord::Base.connection.execute('REINDEX INDEX search_index;') ActiveRecord::Base.connection.execute('REINDEX INDEX index_accounts_on_uri;') ActiveRecord::Base.connection.execute('REINDEX INDEX index_accounts_on_url;') + ActiveRecord::Base.connection.execute('REINDEX INDEX index_accounts_on_domain_and_id;') if ActiveRecord::Migrator.current_version >= 2023_05_24_190515 end def deduplicate_users! @@ -241,6 +246,8 @@ module Mastodon::CLI else ActiveRecord::Base.connection.add_index :users, ['reset_password_token'], name: 'index_users_on_reset_password_token', unique: true, where: 'reset_password_token IS NOT NULL', opclass: :text_pattern_ops end + + ActiveRecord::Base.connection.execute('REINDEX INDEX index_users_on_unconfirmed_email;') if ActiveRecord::Migrator.current_version >= 2023_07_02_151753 end def deduplicate_users_process_confirmation_token @@ -541,6 +548,11 @@ module Mastodon::CLI ActiveRecord::Base.connection.add_index :webhooks, ['url'], name: 'index_webhooks_on_url', unique: true end + def deduplicate_software_updates! + # Not bothering with this, it's data that will be recovered with the scheduler + SoftwareUpdate.delete_all + end + def deduplicate_local_accounts!(accounts) accounts = accounts.sort_by(&:id).reverse From 2054ee7cd5f088d31c727c8e2603918b83aba188 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 11:12:21 +0200 Subject: [PATCH 53/69] Update dependency glob to v10.3.9 (#27148) 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 b9571d4248..ca1ac07d63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6227,9 +6227,9 @@ glob-parent@^6.0.2: is-glob "^4.0.3" glob@^10.2.5, glob@^10.2.6: - version "10.3.8" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.8.tgz#186499f88ba2e7342ed7f4c1e60acdfe477d94f4" - integrity sha512-0z5t5h4Pxtqi+8ozm+j7yMI/bQ1sBeg4oAUGkDPUguaY2YZB76gtlllWoxWEHo02E5qAjsELwVX8g8Wk6RvQog== + version "10.3.9" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.9.tgz#181ae87640ecce9b2fc5b96e4e2d70b7c3629ab8" + integrity sha512-2tU/LKevAQvDVuVJ9pg9Yv9xcbSh+TqHuTaXTNbQwf+0kDl9Fm6bMovi4Nm5c8TVvfxo2LLcqCGtmO9KoJaGWg== dependencies: foreground-child "^3.1.0" jackspeak "^2.3.5" From 60241d9b7267f9fdce3de6046965c2081ca65496 Mon Sep 17 00:00:00 2001 From: KMY Date: Tue, 26 Sep 2023 18:22:49 +0900 Subject: [PATCH 54/69] #32 Add get circle statuses test --- .../api/v1/circles/statuses_controller.rb | 1 - .../v1/circles/statuses_controller_spec.rb | 43 +++++++++++++++++++ spec/fabricators/circle_status_fabricator.rb | 6 +++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 spec/controllers/api/v1/circles/statuses_controller_spec.rb create mode 100644 spec/fabricators/circle_status_fabricator.rb diff --git a/app/controllers/api/v1/circles/statuses_controller.rb b/app/controllers/api/v1/circles/statuses_controller.rb index 84e9b05543..705731936b 100644 --- a/app/controllers/api/v1/circles/statuses_controller.rb +++ b/app/controllers/api/v1/circles/statuses_controller.rb @@ -2,7 +2,6 @@ class Api::V1::Circles::StatusesController < Api::BaseController before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:show] - before_action -> { doorkeeper_authorize! :write, :'write:lists' }, except: [:show] before_action :require_user! before_action :set_circle diff --git a/spec/controllers/api/v1/circles/statuses_controller_spec.rb b/spec/controllers/api/v1/circles/statuses_controller_spec.rb new file mode 100644 index 0000000000..d56ea1a6f6 --- /dev/null +++ b/spec/controllers/api/v1/circles/statuses_controller_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::Circles::StatusesController do + render_views + + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:lists') } + let(:circle) { Fabricate(:circle, account: user.account) } + let(:status) { Fabricate(:status, account: user.account, visibility: 'limited', limited_scope: 'circle') } + + before do + allow(controller).to receive(:doorkeeper_token) { token } + Fabricate(:circle_status, status: status, circle: circle) + other_circle = Fabricate(:circle) + Fabricate(:circle_status, status: Fabricate(:status, visibility: 'limited', limited_scope: 'circle', account: other_circle.account), circle: other_circle) + end + + describe 'GET #index' do + it 'returns http success' do + get :show, params: { circle_id: circle.id, limit: 1 } + + expect(response).to have_http_status(200) + json = body_as_json + expect(json.map { |item| item[:id].to_i }).to eq [status.id] + end + + context "with someone else's statuses" do + let(:other_account) { Fabricate(:account) } + let(:other_circle) { Fabricate(:circle, account: other_account) } + + before do + Fabricate(:circle_status, circle: other_circle, status: Fabricate(:status, account: other_account, visibility: 'limited', limited_scope: 'circle')) + end + + it 'returns http failed' do + get :show, params: { circle_id: other_circle.id } + expect(response).to have_http_status(404) + end + end + end +end diff --git a/spec/fabricators/circle_status_fabricator.rb b/spec/fabricators/circle_status_fabricator.rb new file mode 100644 index 0000000000..f190331a36 --- /dev/null +++ b/spec/fabricators/circle_status_fabricator.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +Fabricator(:circle_status) do + circle { Fabricate.build(:circle) } + status { Fabricate.build(:status) } +end From 8b8d49545f08498c788abdf5f678d69a7854ffca Mon Sep 17 00:00:00 2001 From: KMY Date: Tue, 26 Sep 2023 18:23:38 +0900 Subject: [PATCH 55/69] Fix test of statuses limit --- spec/controllers/api/v1/circles/statuses_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/controllers/api/v1/circles/statuses_controller_spec.rb b/spec/controllers/api/v1/circles/statuses_controller_spec.rb index d56ea1a6f6..2a323aa0f8 100644 --- a/spec/controllers/api/v1/circles/statuses_controller_spec.rb +++ b/spec/controllers/api/v1/circles/statuses_controller_spec.rb @@ -19,7 +19,7 @@ describe Api::V1::Circles::StatusesController do describe 'GET #index' do it 'returns http success' do - get :show, params: { circle_id: circle.id, limit: 1 } + get :show, params: { circle_id: circle.id, limit: 5 } expect(response).to have_http_status(200) json = body_as_json From 57f592fed50747f3c97718a2761e17bafe6c8698 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Tue, 26 Sep 2023 11:25:01 +0200 Subject: [PATCH 56/69] Add Typescript types for some API objects (#26602) --- app/javascript/mastodon/api_types/accounts.ts | 45 +++++++++++++++++++ .../mastodon/api_types/custom_emoji.ts | 8 ++++ .../mastodon/api_types/relationships.ts | 18 ++++++++ app/serializers/rest/account_serializer.rb | 2 + .../rest/custom_emoji_serializer.rb | 2 + .../rest/relationship_serializer.rb | 2 + 6 files changed, 77 insertions(+) create mode 100644 app/javascript/mastodon/api_types/accounts.ts create mode 100644 app/javascript/mastodon/api_types/custom_emoji.ts create mode 100644 app/javascript/mastodon/api_types/relationships.ts diff --git a/app/javascript/mastodon/api_types/accounts.ts b/app/javascript/mastodon/api_types/accounts.ts new file mode 100644 index 0000000000..9d740c96de --- /dev/null +++ b/app/javascript/mastodon/api_types/accounts.ts @@ -0,0 +1,45 @@ +import type { ApiCustomEmojiJSON } from './custom_emoji'; + +export interface ApiAccountFieldJSON { + name: string; + value: string; + verified_at: string | null; +} + +export interface ApiAccountRoleJSON { + color: string; + id: string; + name: string; +} + +// See app/serializers/rest/account_serializer.rb +export interface ApiAccountJSON { + acct: string; + avatar: string; + avatar_static: string; + bot: boolean; + created_at: string; + discoverable: boolean; + display_name: string; + emojis: ApiCustomEmojiJSON[]; + fields: ApiAccountFieldJSON[]; + followers_count: number; + following_count: number; + group: boolean; + header: string; + header_static: string; + id: string; + last_status_at: string; + locked: boolean; + noindex: boolean; + note: string; + roles: ApiAccountJSON[]; + statuses_count: number; + uri: string; + url: string; + username: string; + moved?: ApiAccountJSON; + suspended?: boolean; + limited?: boolean; + memorial?: boolean; +} diff --git a/app/javascript/mastodon/api_types/custom_emoji.ts b/app/javascript/mastodon/api_types/custom_emoji.ts new file mode 100644 index 0000000000..05144d6f68 --- /dev/null +++ b/app/javascript/mastodon/api_types/custom_emoji.ts @@ -0,0 +1,8 @@ +// See app/serializers/rest/account_serializer.rb +export interface ApiCustomEmojiJSON { + shortcode: string; + static_url: string; + url: string; + category?: string; + visible_in_picker: boolean; +} diff --git a/app/javascript/mastodon/api_types/relationships.ts b/app/javascript/mastodon/api_types/relationships.ts new file mode 100644 index 0000000000..9f26a0ce9b --- /dev/null +++ b/app/javascript/mastodon/api_types/relationships.ts @@ -0,0 +1,18 @@ +// See app/serializers/rest/relationship_serializer.rb +export interface ApiRelationshipJSON { + blocked_by: boolean; + blocking: boolean; + domain_blocking: boolean; + endorsed: boolean; + followed_by: boolean; + following: boolean; + id: string; + languages: string[] | null; + muting_notifications: boolean; + muting: boolean; + note: string; + notifying: boolean; + requested_by: boolean; + requested: boolean; + showing_reblogs: boolean; +} diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb index 310cf1b1e4..435ae36b74 100644 --- a/app/serializers/rest/account_serializer.rb +++ b/app/serializers/rest/account_serializer.rb @@ -4,6 +4,8 @@ class REST::AccountSerializer < ActiveModel::Serializer include RoutingHelper include FormattingHelper + # Please update `app/javascript/mastodon/api_types/accounts.ts` when making changes to the attributes + attributes :id, :username, :acct, :display_name, :locked, :bot, :discoverable, :group, :created_at, :note, :url, :uri, :avatar, :avatar_static, :header, :header_static, :followers_count, :following_count, :statuses_count, :last_status_at diff --git a/app/serializers/rest/custom_emoji_serializer.rb b/app/serializers/rest/custom_emoji_serializer.rb index aff58e4d94..33da69da53 100644 --- a/app/serializers/rest/custom_emoji_serializer.rb +++ b/app/serializers/rest/custom_emoji_serializer.rb @@ -3,6 +3,8 @@ class REST::CustomEmojiSerializer < ActiveModel::Serializer include RoutingHelper + # Please update `app/javascript/mastodon/api_types/custom_emoji.ts` when making changes to the attributes + attributes :shortcode, :url, :static_url, :visible_in_picker attribute :category, if: :category_loaded? diff --git a/app/serializers/rest/relationship_serializer.rb b/app/serializers/rest/relationship_serializer.rb index b533874012..4d7ed75935 100644 --- a/app/serializers/rest/relationship_serializer.rb +++ b/app/serializers/rest/relationship_serializer.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class REST::RelationshipSerializer < ActiveModel::Serializer + # Please update `app/javascript/mastodon/api_types/relationships.ts` when making changes to the attributes + attributes :id, :following, :showing_reblogs, :notifying, :languages, :followed_by, :blocking, :blocked_by, :muting, :muting_notifications, :requested, :requested_by, :domain_blocking, :endorsed, :note From fe5e45689512a300c5bfb8a606fcf498f4a08485 Mon Sep 17 00:00:00 2001 From: KMY Date: Tue, 26 Sep 2023 19:22:33 +0900 Subject: [PATCH 57/69] Fix test --- spec/fabricators/circle_status_fabricator.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/fabricators/circle_status_fabricator.rb b/spec/fabricators/circle_status_fabricator.rb index f190331a36..649d4f4438 100644 --- a/spec/fabricators/circle_status_fabricator.rb +++ b/spec/fabricators/circle_status_fabricator.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true Fabricator(:circle_status) do - circle { Fabricate.build(:circle) } - status { Fabricate.build(:status) } + circle + status + before_create { |circle_status, _| circle_status.status.account = circle.account } end From bce99f848f9046e728ad23929d025e9b631f6db7 Mon Sep 17 00:00:00 2001 From: KMY Date: Wed, 27 Sep 2023 10:56:08 +0900 Subject: [PATCH 58/69] Fix ProcessReferencesWorker error for tasks before update --- app/services/process_references_service.rb | 4 ++-- app/workers/process_references_worker.rb | 4 ++-- spec/workers/process_references_worker_spec.rb | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 spec/workers/process_references_worker_spec.rb diff --git a/app/services/process_references_service.rb b/app/services/process_references_service.rb index faf5965a7a..0be4bc9160 100644 --- a/app/services/process_references_service.rb +++ b/app/services/process_references_service.rb @@ -46,7 +46,7 @@ class ProcessReferencesService < BaseService return unless need_process?(status, reference_parameters, urls) Rails.cache.write("status_reference:#{status.id}", true, expires_in: 10.minutes) - ProcessReferencesWorker.perform_async(status.id, reference_parameters, urls, []) + ProcessReferencesWorker.perform_async(status.id, reference_parameters, urls, no_fetch_urls: []) end def self.call_service(status, reference_parameters, urls) @@ -133,6 +133,6 @@ class ProcessReferencesService < BaseService end def launch_worker - ProcessReferencesWorker.perform_async(@status.id, @reference_parameters, @urls, @no_fetch_urls) + ProcessReferencesWorker.perform_async(@status.id, @reference_parameters, @urls, no_fetch_urls: @no_fetch_urls) end end diff --git a/app/workers/process_references_worker.rb b/app/workers/process_references_worker.rb index a3815e1ece..8b6d0d7b34 100644 --- a/app/workers/process_references_worker.rb +++ b/app/workers/process_references_worker.rb @@ -3,8 +3,8 @@ class ProcessReferencesWorker include Sidekiq::Worker - def perform(status_id, ids, urls, no_fetch_urls) - ProcessReferencesService.new.call(Status.find(status_id), ids || [], urls: urls || [], no_fetch_urls: no_fetch_urls) + def perform(status_id, ids, urls, no_fetch_urls: nil) + ProcessReferencesService.new.call(Status.find(status_id), ids || [], urls: urls || [], no_fetch_urls: no_fetch_urls || []) rescue ActiveRecord::RecordNotFound true end diff --git a/spec/workers/process_references_worker_spec.rb b/spec/workers/process_references_worker_spec.rb new file mode 100644 index 0000000000..10a2bc68f9 --- /dev/null +++ b/spec/workers/process_references_worker_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ProcessReferencesWorker do + let(:worker) { described_class.new } + + describe 'perform' do + it 'runs without error for simple call' do + expect { worker.perform(1000, [], []) }.to_not raise_error + end + + it 'runs without error with no_fetch_urls' do + expect { worker.perform(1000, [], [], no_fetch_urls: []) }.to_not raise_error + end + end +end From 41f4175e665c3d373bf9ba8b1cffd82359aaf53b Mon Sep 17 00:00:00 2001 From: KMY Date: Wed, 27 Sep 2023 11:00:35 +0900 Subject: [PATCH 59/69] Bump version to 5.2 LTS --- lib/mastodon/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index 4e9032b40a..611f439135 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -9,7 +9,7 @@ module Mastodon end def kmyblue_minor - 1 + 2 end def kmyblue_flag From 097e7ac5d1c5e05c37ab593659eb286cb08cb0af Mon Sep 17 00:00:00 2001 From: KMY Date: Wed, 27 Sep 2023 11:23:18 +0900 Subject: [PATCH 60/69] Revert "Fix ProcessReferencesWorker error for tasks before update" This reverts commit 75c0e512f4b477a035a24f972aadc7a51a22742d. --- app/services/process_references_service.rb | 4 ++-- app/workers/process_references_worker.rb | 4 ++-- spec/workers/process_references_worker_spec.rb | 17 ----------------- 3 files changed, 4 insertions(+), 21 deletions(-) delete mode 100644 spec/workers/process_references_worker_spec.rb diff --git a/app/services/process_references_service.rb b/app/services/process_references_service.rb index 0be4bc9160..faf5965a7a 100644 --- a/app/services/process_references_service.rb +++ b/app/services/process_references_service.rb @@ -46,7 +46,7 @@ class ProcessReferencesService < BaseService return unless need_process?(status, reference_parameters, urls) Rails.cache.write("status_reference:#{status.id}", true, expires_in: 10.minutes) - ProcessReferencesWorker.perform_async(status.id, reference_parameters, urls, no_fetch_urls: []) + ProcessReferencesWorker.perform_async(status.id, reference_parameters, urls, []) end def self.call_service(status, reference_parameters, urls) @@ -133,6 +133,6 @@ class ProcessReferencesService < BaseService end def launch_worker - ProcessReferencesWorker.perform_async(@status.id, @reference_parameters, @urls, no_fetch_urls: @no_fetch_urls) + ProcessReferencesWorker.perform_async(@status.id, @reference_parameters, @urls, @no_fetch_urls) end end diff --git a/app/workers/process_references_worker.rb b/app/workers/process_references_worker.rb index 8b6d0d7b34..a3815e1ece 100644 --- a/app/workers/process_references_worker.rb +++ b/app/workers/process_references_worker.rb @@ -3,8 +3,8 @@ class ProcessReferencesWorker include Sidekiq::Worker - def perform(status_id, ids, urls, no_fetch_urls: nil) - ProcessReferencesService.new.call(Status.find(status_id), ids || [], urls: urls || [], no_fetch_urls: no_fetch_urls || []) + def perform(status_id, ids, urls, no_fetch_urls) + ProcessReferencesService.new.call(Status.find(status_id), ids || [], urls: urls || [], no_fetch_urls: no_fetch_urls) rescue ActiveRecord::RecordNotFound true end diff --git a/spec/workers/process_references_worker_spec.rb b/spec/workers/process_references_worker_spec.rb deleted file mode 100644 index 10a2bc68f9..0000000000 --- a/spec/workers/process_references_worker_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ProcessReferencesWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error for simple call' do - expect { worker.perform(1000, [], []) }.to_not raise_error - end - - it 'runs without error with no_fetch_urls' do - expect { worker.perform(1000, [], [], no_fetch_urls: []) }.to_not raise_error - end - end -end From f9ccc886573134193855c3f70d827fe403f484e1 Mon Sep 17 00:00:00 2001 From: KMY Date: Wed, 27 Sep 2023 11:27:52 +0900 Subject: [PATCH 61/69] Fix test --- app/workers/process_references_worker.rb | 2 +- spec/workers/process_references_worker_spec.rb | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 spec/workers/process_references_worker_spec.rb diff --git a/app/workers/process_references_worker.rb b/app/workers/process_references_worker.rb index a3815e1ece..78465b8008 100644 --- a/app/workers/process_references_worker.rb +++ b/app/workers/process_references_worker.rb @@ -3,7 +3,7 @@ class ProcessReferencesWorker include Sidekiq::Worker - def perform(status_id, ids, urls, no_fetch_urls) + def perform(status_id, ids, urls, no_fetch_urls = nil) ProcessReferencesService.new.call(Status.find(status_id), ids || [], urls: urls || [], no_fetch_urls: no_fetch_urls) rescue ActiveRecord::RecordNotFound true diff --git a/spec/workers/process_references_worker_spec.rb b/spec/workers/process_references_worker_spec.rb new file mode 100644 index 0000000000..10a2bc68f9 --- /dev/null +++ b/spec/workers/process_references_worker_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ProcessReferencesWorker do + let(:worker) { described_class.new } + + describe 'perform' do + it 'runs without error for simple call' do + expect { worker.perform(1000, [], []) }.to_not raise_error + end + + it 'runs without error with no_fetch_urls' do + expect { worker.perform(1000, [], [], no_fetch_urls: []) }.to_not raise_error + end + end +end From 93ffe2cff2bb41a25195be46996d407380a4d1d2 Mon Sep 17 00:00:00 2001 From: KMY Date: Wed, 27 Sep 2023 13:40:36 +0900 Subject: [PATCH 62/69] Add sidekiq option to process references worker --- app/workers/process_references_worker.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/workers/process_references_worker.rb b/app/workers/process_references_worker.rb index 78465b8008..f082744857 100644 --- a/app/workers/process_references_worker.rb +++ b/app/workers/process_references_worker.rb @@ -3,6 +3,8 @@ class ProcessReferencesWorker include Sidekiq::Worker + sidekiq_options queue: 'pull', retry: 3 + def perform(status_id, ids, urls, no_fetch_urls = nil) ProcessReferencesService.new.call(Status.find(status_id), ids || [], urls: urls || [], no_fetch_urls: no_fetch_urls) rescue ActiveRecord::RecordNotFound From 8d77643bd3da5d14b47785dae5506708cac67c0a Mon Sep 17 00:00:00 2001 From: KMY Date: Wed, 27 Sep 2023 14:41:16 +0900 Subject: [PATCH 63/69] Fix web warning --- app/services/process_references_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/process_references_service.rb b/app/services/process_references_service.rb index 0be4bc9160..faf5965a7a 100644 --- a/app/services/process_references_service.rb +++ b/app/services/process_references_service.rb @@ -46,7 +46,7 @@ class ProcessReferencesService < BaseService return unless need_process?(status, reference_parameters, urls) Rails.cache.write("status_reference:#{status.id}", true, expires_in: 10.minutes) - ProcessReferencesWorker.perform_async(status.id, reference_parameters, urls, no_fetch_urls: []) + ProcessReferencesWorker.perform_async(status.id, reference_parameters, urls, []) end def self.call_service(status, reference_parameters, urls) @@ -133,6 +133,6 @@ class ProcessReferencesService < BaseService end def launch_worker - ProcessReferencesWorker.perform_async(@status.id, @reference_parameters, @urls, no_fetch_urls: @no_fetch_urls) + ProcessReferencesWorker.perform_async(@status.id, @reference_parameters, @urls, @no_fetch_urls) end end From 297db76188b8aa50decccf9f7fa52ebcc637943f Mon Sep 17 00:00:00 2001 From: KMY Date: Wed, 27 Sep 2023 18:03:13 +0900 Subject: [PATCH 64/69] #41 Add Japanese language flag to posts from misskey --- app/lib/activitypub/parser/status_parser.rb | 4 + spec/lib/activitypub/activity/create_spec.rb | 80 ++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/app/lib/activitypub/parser/status_parser.rb b/app/lib/activitypub/parser/status_parser.rb index 4ffec58ae3..e0a234e110 100644 --- a/app/lib/activitypub/parser/status_parser.rb +++ b/app/lib/activitypub/parser/status_parser.rb @@ -107,6 +107,10 @@ class ActivityPub::Parser::StatusParser end def language + @language ||= original_language || (misskey_software? ? 'ja' : nil) + end + + def original_language if content_language_map? @object['contentMap'].keys.first elsif name_language_map? diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index 9c4bba3e62..c199fcd038 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -1088,6 +1088,86 @@ RSpec.describe ActivityPub::Activity::Create do expect(poll.votes.first).to be_nil end end + + context 'with language' do + let(:to) { 'https://www.w3.org/ns/activitystreams#Public' } + let(:object_json) do + { + id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, + type: 'Note', + content: 'Lorem ipsum', + to: to, + contentMap: { ja: 'Lorem ipsum' }, + } + end + + it 'create status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.language).to eq 'ja' + end + end + + context 'without language' do + let(:to) { 'https://www.w3.org/ns/activitystreams#Public' } + let(:object_json) do + { + id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, + type: 'Note', + content: 'Lorem ipsum', + to: to, + } + end + + it 'create status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.language).to be_nil + end + end + + context 'without language when misskey server' do + let(:sender_software) { 'misskey' } + let(:to) { 'https://www.w3.org/ns/activitystreams#Public' } + let(:object_json) do + { + id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, + type: 'Note', + content: 'Lorem ipsum', + to: to, + } + end + + it 'create status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.language).to eq 'ja' + end + end + + context 'with language when misskey server' do + let(:sender_software) { 'misskey' } + let(:to) { 'https://www.w3.org/ns/activitystreams#Public' } + let(:object_json) do + { + id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, + type: 'Note', + content: 'Lorem ipsum', + to: to, + contentMap: { 'en-US': 'Lorem ipsum' }, + } + end + + it 'create status' do + status = sender.statuses.first + + expect(status).to_not be_nil + expect(status.language).to eq 'en-US' + end + end end context 'with an encrypted message' do From f2047e5b5ad13d39405035d8b16b63c4dcc33c38 Mon Sep 17 00:00:00 2001 From: KMY Date: Wed, 27 Sep 2023 18:20:48 +0900 Subject: [PATCH 65/69] Fix test --- app/services/activitypub/process_status_update_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index dd6c8bc8a1..da82af8dff 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -10,7 +10,7 @@ class ActivityPub::ProcessStatusUpdateService < BaseService @activity_json = activity_json @json = object_json - @status_parser = ActivityPub::Parser::StatusParser.new(@json) + @status_parser = ActivityPub::Parser::StatusParser.new(@json, account: status.account) @uri = @status_parser.uri @status = status @account = status.account From b1759f2c10c9c0c10d62fac3068259f6cc3b37c3 Mon Sep 17 00:00:00 2001 From: KMY Date: Thu, 28 Sep 2023 15:40:27 +0900 Subject: [PATCH 66/69] #25 Exclude public_searchability posts from restriction for misskey --- app/lib/status_reach_finder.rb | 1 + config/locales/simple_form.en.yml | 4 ++-- config/locales/simple_form.ja.yml | 6 +++--- spec/lib/status_reach_finder_spec.rb | 16 ++++++++++++++-- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/app/lib/status_reach_finder.rb b/app/lib/status_reach_finder.rb index 8639a30a9f..fde6e36fce 100644 --- a/app/lib/status_reach_finder.rb +++ b/app/lib/status_reach_finder.rb @@ -157,6 +157,7 @@ class StatusReachFinder end def banned_domains_for_misskey_of_status(status) + return [] if status.public_searchability? return [] unless (status.public_unlisted_visibility? && status.account.user&.setting_reject_public_unlisted_subscription) || (status.unlisted_visibility? && status.account.user&.setting_reject_unlisted_subscription) from_info = InstanceInfo.where(software: %w(misskey calckey)).pluck(:domain) diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index af5c64ef62..2012e1a7f7 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -269,8 +269,8 @@ en: setting_noai: Set noai meta tags setting_public_post_to_unlisted: Convert public post to public unlisted if not using Web app setting_reduce_motion: Reduce motion in animations - setting_reject_public_unlisted_subscription: Reject sending public unlisted posts to Misskey, Calckey - setting_reject_unlisted_subscription: Reject sending unlisted posts to Misskey, Calckey + setting_reject_public_unlisted_subscription: Reject sending public unlisted visibility/non-public searchability posts to Misskey, Calckey + setting_reject_unlisted_subscription: Reject sending unlisted visibility/non-public searchability posts to Misskey, Calckey setting_send_without_domain_blocks: Send your post to all server with administrator set as rejecting-post-server for protect you [DEPRECATED] setting_show_application: Disclose application used to send posts setting_show_emoji_reaction_on_timeline: Show all stamps on timeline diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index 6ea9661d5a..2a03f00fdb 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -81,7 +81,7 @@ ja: setting_link_preview: プレビュー生成を停止することは、センシティブなサイトへのリンクを頻繁に投稿する人にも有効かもしれません setting_noai: AI学習への利用を禁止するメタタグをプロフィールページに追加します。ただし実効性があるとは限りません setting_public_post_to_unlisted: 未対応のサードパーティアプリからもローカル公開で投稿できますが、公開投稿はWeb以外できなくなります - setting_reject_unlisted_subscription: Misskeyやそのフォーク(Calckeyなど)は、フォローしていないアカウントの「未収載」投稿を **購読・検索** することができます。これはkmyblueの挙動と異なります。そのようなサーバーに、指定した公開範囲の投稿を「フォロワーのみ」として配送します。ただし構造上、完璧な対応は困難でたまに未収載として配信されること、ご理解ください + setting_reject_unlisted_subscription: Misskeyやそのフォークは、フォローしていないアカウントの「未収載」投稿を **購読・検索** することができます。これはkmyblueの挙動と異なります。そのようなサーバーに、指定した公開範囲の投稿を「フォロワーのみ」として配送します。ただし構造上、完璧な対応は困難でたまに未収載として配信されること、ご理解ください setting_show_application: 投稿するのに使用したアプリが投稿の詳細ビューに表示されるようになります setting_single_ref_to_quote: 当サーバーがまだ対象投稿を取り込んでいない場合、引用が相手に正常に認識されない場合があります setting_stop_emoji_reaction_streaming: 通信容量の節約に役立ちます @@ -284,8 +284,8 @@ ja: setting_noai: 自分のコンテンツのAI学習利用に対して不快感を表明する setting_public_post_to_unlisted: サードパーティから公開範囲「公開」で投稿した場合、「ローカル公開」に変更する setting_reduce_motion: アニメーションの動きを減らす - setting_reject_public_unlisted_subscription: Misskey系サーバーに「ローカル公開」投稿を「フォロワーのみ」に変換して配送する - setting_reject_unlisted_subscription: Misskey系サーバーに「未収載」投稿を「フォロワーのみ」に変換して配送する + setting_reject_public_unlisted_subscription: Misskey系サーバーに「ローカル公開」かつ検索許可「誰でも以外」の投稿を「フォロワーのみ」に変換して配送する + setting_reject_unlisted_subscription: Misskey系サーバーに「未収載」かつ検索許可「誰でも以外」の投稿を「フォロワーのみ」に変換して配送する setting_send_without_domain_blocks: 管理人の設定した配送停止設定を拒否する (非推奨) setting_show_application: 送信したアプリを開示する setting_show_emoji_reaction_on_timeline: タイムライン上に他の人のつけたスタンプを表示する diff --git a/spec/lib/status_reach_finder_spec.rb b/spec/lib/status_reach_finder_spec.rb index 57946d3a70..4292f12bc6 100644 --- a/spec/lib/status_reach_finder_spec.rb +++ b/spec/lib/status_reach_finder_spec.rb @@ -9,8 +9,9 @@ describe StatusReachFinder do let(:parent_status) { nil } let(:visibility) { :public } + let(:searchability) { :public } let(:alice) { Fabricate(:account, username: 'alice') } - let(:status) { Fabricate(:status, account: alice, thread: parent_status, visibility: visibility) } + let(:status) { Fabricate(:status, account: alice, thread: parent_status, visibility: visibility, searchability: searchability) } context 'with a simple case' do let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox') } @@ -49,8 +50,9 @@ describe StatusReachFinder do end end - context 'when misskey' do + context 'when misskey with private searchability' do let(:sender_software) { 'misskey' } + let(:searchability) { :private } it 'send status without setting' do expect(subject.inboxes).to include 'https://foo.bar/inbox' @@ -63,6 +65,16 @@ describe StatusReachFinder do expect(subject.inboxes_for_misskey).to include 'https://foo.bar/inbox' end end + + context 'when misskey with public searchability' do + let(:sender_software) { 'misskey' } + + it 'send status with setting' do + alice.user.settings.update(reject_unlisted_subscription: 'true') + expect(subject.inboxes).to include 'https://foo.bar/inbox' + expect(subject.inboxes_for_misskey).to_not include 'https://foo.bar/inbox' + end + end end context 'when it contains mentions of remote accounts' do From 62b7b7a9b98a6deef3bc8b3db50c779f8362d2bc Mon Sep 17 00:00:00 2001 From: KMY Date: Thu, 28 Sep 2023 16:16:24 +0900 Subject: [PATCH 67/69] #38 Change limited_scope to circle when personal post is added mentions --- app/services/update_status_service.rb | 8 ++++- spec/services/post_status_service_spec.rb | 13 ++++++++ spec/services/update_status_service_spec.rb | 33 +++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb index 6e63fa9742..0a5de6b907 100644 --- a/app/services/update_status_service.rb +++ b/app/services/update_status_service.rb @@ -167,7 +167,13 @@ class UpdateStatusService < BaseService def update_metadata! ProcessHashtagsService.new.call(@status) - ProcessMentionsService.new.call(@status) + process_mentions_service.call(@status) + + @status.update(limited_scope: :circle) if process_mentions_service.mentions? + end + + def process_mentions_service + @process_mentions_service ||= ProcessMentionsService.new end def broadcast_updates! diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index 2e513b9ca4..5e2a54c264 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -250,6 +250,19 @@ RSpec.describe PostStatusService, type: :service do expect(status.mentioned_accounts.count).to eq 0 end + it 'using empty circle but with mention' do + account = Fabricate(:account) + Fabricate(:account, username: 'bob', domain: nil) + circle = Fabricate(:circle, account: account) + text = 'This is an English text. @bob' + + status = subject.call(account, text: text, visibility: 'circle', circle_id: circle.id) + + expect(status.visibility).to eq 'limited' + expect(status.limited_scope).to eq 'circle' + expect(status.mentioned_accounts.count).to eq 1 + end + it 'safeguards mentions' do account = Fabricate(:account) mentioned_account = Fabricate(:account, username: 'alice') diff --git a/spec/services/update_status_service_spec.rb b/spec/services/update_status_service_spec.rb index 9c53ebb2fd..288466bdeb 100644 --- a/spec/services/update_status_service_spec.rb +++ b/spec/services/update_status_service_spec.rb @@ -166,6 +166,39 @@ RSpec.describe UpdateStatusService, type: :service do end end + context 'when personal_limited mentions in text change' do + let!(:account) { Fabricate(:account) } + let!(:bob) { Fabricate(:account, username: 'bob') } + let!(:status) { PostStatusService.new.call(account, text: 'Hello', visibility: 'circle', circle_id: Fabricate(:circle, account: account).id) } + + before do + subject.call(status, status.account_id, text: 'Hello @bob') + end + + it 'changes mentions' do + expect(status.active_mentions.pluck(:account_id)).to eq [bob.id] + end + + it 'changes visibilities' do + expect(status.visibility).to eq 'limited' + expect(status.limited_scope).to eq 'circle' + end + end + + context 'when personal_limited in text change' do + let!(:account) { Fabricate(:account) } + let!(:status) { PostStatusService.new.call(account, text: 'Hello', visibility: 'circle', circle_id: Fabricate(:circle, account: account).id) } + + before do + subject.call(status, status.account_id, text: 'AAA') + end + + it 'not changing visibilities' do + expect(status.visibility).to eq 'limited' + expect(status.limited_scope).to eq 'personal' + end + end + context 'when hashtags in text change' do let!(:account) { Fabricate(:account) } let!(:status) { PostStatusService.new.call(account, text: 'Hello #foo') } From d75c8506ce820d19d85a65f8fa32bcdb50a7fb23 Mon Sep 17 00:00:00 2001 From: KMY Date: Thu, 28 Sep 2023 16:17:58 +0900 Subject: [PATCH 68/69] #38 Show alert when mention is added to limited post --- .../compose/containers/warning_container.jsx | 11 +++++-- app/javascript/mastodon/reducers/compose.js | 4 +++ app/javascript/mastodon/utils/mentions.ts | 29 +++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 app/javascript/mastodon/utils/mentions.ts diff --git a/app/javascript/mastodon/features/compose/containers/warning_container.jsx b/app/javascript/mastodon/features/compose/containers/warning_container.jsx index cfa8e8ab7d..4daeeecb99 100644 --- a/app/javascript/mastodon/features/compose/containers/warning_container.jsx +++ b/app/javascript/mastodon/features/compose/containers/warning_container.jsx @@ -6,6 +6,7 @@ import { connect } from 'react-redux'; import { me } from 'mastodon/initial_state'; import { HASHTAG_PATTERN_REGEX } from 'mastodon/utils/hashtags'; +import { MENTION_PATTERN_REGEX } from 'mastodon/utils/mentions'; import Warning from '../components/warning'; @@ -14,10 +15,11 @@ const mapStateToProps = state => ({ hashtagWarning: !['public', 'public_unlisted', 'login'].includes(state.getIn(['compose', 'privacy'])) && state.getIn(['compose', 'searchability']) !== 'public' && HASHTAG_PATTERN_REGEX.test(state.getIn(['compose', 'text'])), directMessageWarning: state.getIn(['compose', 'privacy']) === 'direct', searchabilityWarning: state.getIn(['compose', 'searchability']) === 'limited', - limitedPostWarning: ['mutual', 'circle'].includes(state.getIn(['compose', 'privacy'])), + mentionWarning: ['mutual', 'circle', 'limited'].includes(state.getIn(['compose', 'privacy'])) && MENTION_PATTERN_REGEX.test(state.getIn(['compose', 'text'])), + limitedPostWarning: ['mutual', 'circle'].includes(state.getIn(['compose', 'privacy'])) && !state.getIn(['compose', 'limited_scope']), }); -const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning, searchabilityWarning, limitedPostWarning }) => { +const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning, searchabilityWarning, mentionWarning, limitedPostWarning }) => { if (needsLockWarning) { return }} />} />; } @@ -40,6 +42,10 @@ const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning return } />; } + if (mentionWarning) { + return } />; + } + if (limitedPostWarning) { return } />; } @@ -52,6 +58,7 @@ WarningWrapper.propTypes = { hashtagWarning: PropTypes.bool, directMessageWarning: PropTypes.bool, searchabilityWarning: PropTypes.bool, + mentionWarning: PropTypes.bool, limitedPostWarning: PropTypes.bool, }; diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 44665f23af..dc34e7f1af 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -144,6 +144,7 @@ function clearAll(state) { if (!state.get('in_reply_to')) { map.set('posted_on_this_session', true); } + map.set('limited_scope', null); map.set('id', null); map.set('in_reply_to', null); map.set('searchability', state.get('default_searchability')); @@ -411,6 +412,7 @@ export default function compose(state = initialState, action) { map.set('in_reply_to', action.status.get('id')); map.set('text', statusToTextMentions(state, action.status)); map.set('privacy', privacyPreference(action.status.get('visibility_ex'), state.get('default_privacy'))); + map.set('limited_scope', null); map.set('searchability', privacyPreference(action.status.get('searchability'), state.get('default_searchability'))); map.set('focusDate', new Date()); map.set('caretPosition', null); @@ -547,6 +549,7 @@ export default function compose(state = initialState, action) { map.set('text', action.raw_text || unescapeHTML(expandMentions(action.status))); map.set('in_reply_to', action.status.get('in_reply_to_id')); map.set('privacy', action.status.get('visibility_ex')); + map.set('limited_scope', null); map.set('media_attachments', action.status.get('media_attachments').map((media) => media.set('unattached', true))); map.set('focusDate', new Date()); map.set('caretPosition', null); @@ -582,6 +585,7 @@ export default function compose(state = initialState, action) { } else { map.set('privacy', action.status.get('limited_scope') === 'mutual' ? 'mutual' : 'circle'); } + map.set('limited_scope', action.status.get('limited_scope')); map.set('media_attachments', action.status.get('media_attachments')); map.set('focusDate', new Date()); map.set('caretPosition', null); diff --git a/app/javascript/mastodon/utils/mentions.ts b/app/javascript/mastodon/utils/mentions.ts new file mode 100644 index 0000000000..0fbf28a3cf --- /dev/null +++ b/app/javascript/mastodon/utils/mentions.ts @@ -0,0 +1,29 @@ +const MENTION_SEPARATORS = '_\\u00b7\\u200c'; +const ALPHA = '\\p{L}\\p{M}'; +const WORD = '\\p{L}\\p{M}\\p{N}\\p{Pc}'; + +const buildMentionPatternRegex = () => { + try { + return new RegExp( + `(?:^|[^\\/\\)\\w])@(([${WORD}_][${WORD}${MENTION_SEPARATORS}]*[${ALPHA}${MENTION_SEPARATORS}][${WORD}${MENTION_SEPARATORS}]*[${WORD}_])|([${WORD}_]*[${ALPHA}][${WORD}_]*))`, + 'iu', + ); + } catch { + return /(?:^|[^/)\w])#(\w*[a-zA-Z·]\w*)/i; + } +}; + +const buildMentionRegex = () => { + try { + return new RegExp( + `^(([${WORD}_][${WORD}${MENTION_SEPARATORS}]*[${ALPHA}${MENTION_SEPARATORS}][${WORD}${MENTION_SEPARATORS}]*[${WORD}_])|([${WORD}_]*[${ALPHA}][${WORD}_]*))$`, + 'iu', + ); + } catch { + return /^(\w*[a-zA-Z·]\w*)$/i; + } +}; + +export const MENTION_PATTERN_REGEX = buildMentionPatternRegex(); + +export const MENTION_REGEX = buildMentionRegex(); From 322ce1fc27a44b1ba6a96919ffcd7150472c3b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?KMY=EF=BC=88=E9=9B=AA=E3=81=82=E3=81=99=E3=81=8B=EF=BC=89?= Date: Thu, 28 Sep 2023 17:56:21 +0900 Subject: [PATCH 69/69] Bump version to 6.0 (#46) * Bump version to 6.0 * Add cherrypick to banned target * Fix translations --- .../compose/containers/warning_container.jsx | 2 +- app/javascript/mastodon/locales/en.json | 8 ++++++++ app/javascript/mastodon/locales/ja.json | 12 ++++++++++-- app/lib/status_reach_finder.rb | 2 +- lib/mastodon/version.rb | 4 ++-- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/app/javascript/mastodon/features/compose/containers/warning_container.jsx b/app/javascript/mastodon/features/compose/containers/warning_container.jsx index 4daeeecb99..bc74d1209b 100644 --- a/app/javascript/mastodon/features/compose/containers/warning_container.jsx +++ b/app/javascript/mastodon/features/compose/containers/warning_container.jsx @@ -43,7 +43,7 @@ const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning } if (mentionWarning) { - return } />; + return } />; } if (limitedPostWarning) { diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 6cbb18c9b8..e553549508 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -1,6 +1,7 @@ { "about.blocks": "Moderated servers", "about.contact": "Contact:", + "about.disabled": "Disabled", "about.disclaimer": "Mastodon is free, open-source software, and a trademark of Mastodon gGmbH.", "about.domain_blocks.no_reason_available": "Reason not available", "about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.", @@ -10,6 +11,8 @@ "about.domain_blocks.silenced.title": "Limited", "about.domain_blocks.suspended.explanation": "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.", "about.domain_blocks.suspended.title": "Suspended", + "about.enabled": "Enabled", + "about.kmyblue_capability": "This server is using kmyblue, a fork of Mastodon. On this server, kmyblues unique features are configured as follows.", "about.not_available": "This information has not been made available on this server.", "about.powered_by": "Decentralized social media powered by {mastodon}", "about.rules": "Server rules", @@ -104,6 +107,8 @@ "bundle_modal_error.close": "Close", "bundle_modal_error.message": "Something went wrong while loading this component.", "bundle_modal_error.retry": "Try again", + "circles.delete": "Delete circle", + "circles.edit": "Edit circle", "closed_registrations.other_server_instructions": "Since Mastodon is decentralized, you can create an account on another server and still interact with this one.", "closed_registrations_modal.description": "Creating an account on {domain} is currently not possible, but please keep in mind that you do not need an account specifically on {domain} to use Mastodon.", "closed_registrations_modal.find_another_server": "Find another server", @@ -151,6 +156,7 @@ "compose_form.lock_disclaimer.lock": "locked", "compose_form.markdown.marked": "Markdown is available", "compose_form.markdown.unmarked": "Markdown is NOT available", + "compose_form.mention_warning": "When you add a mention to a limited post, the person you are mentioning can also see this post.", "compose_form.placeholder": "What's on your mind?", "compose_form.searchability_warning": "Self only searchability is not available other mastodon servers. Others can search your post.", "compose_form.poll.add_option": "Add a choice", @@ -236,6 +242,7 @@ "empty_column.account_unavailable": "Profile unavailable", "empty_column.blocks": "You haven't blocked any users yet.", "empty_column.bookmarked_statuses": "You don't have any bookmarked posts yet. When you bookmark one, it will show up here.", + "empty_column.circle_statuses": "You don't have any circle posts yet. When you post one as circle, it will show up here.", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.direct": "You don't have any private mentions yet. When you send or receive one, it will show up here.", "empty_column.domain_blocks": "There are no blocked domains yet.", @@ -533,6 +540,7 @@ "privacy.login.short": "Login only", "privacy.mutual.long": "Mutual followers only", "privacy.mutual.short": "Mutual", + "privacy.personal.short": "Yourself only", "privacy.private.long": "Visible for followers only", "privacy.private.short": "Followers only", "privacy.public.long": "Visible for all", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 8fecf184be..efe5842199 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -1,6 +1,7 @@ { "about.blocks": "制限中のサーバー", "about.contact": "連絡先", + "about.disabled": "無効", "about.disclaimer": "Mastodonは自由なオープンソースソフトウェアでMastodon gGmbHの商標です。", "about.domain_blocks.no_reason_available": "制限理由", "about.domain_blocks.preamble": "Mastodonでは連合先のどのようなサーバーのユーザーとも交流できます。ただし次のサーバーには例外が設定されています。", @@ -10,6 +11,8 @@ "about.domain_blocks.silenced.title": "制限", "about.domain_blocks.suspended.explanation": "これらのサーバーからのデータは処理されず、保存や変換もされません。該当するユーザーとの交流もできません。", "about.domain_blocks.suspended.title": "停止済み", + "about.enabled": "有効", + "about.kmyblue_capability": "このサーバーは、kmyblueというMastodonフォークを利用しています。kmyblue独自機能の一部は、サーバー管理者によって有効・無効を切り替えることができます。", "about.not_available": "この情報はこのサーバーでは利用できません。", "about.powered_by": "{mastodon}による分散型ソーシャルメディア", "about.rules": "サーバーのルール", @@ -154,8 +157,10 @@ "bundle_modal_error.close": "閉じる", "bundle_modal_error.message": "コンポーネントの読み込み中に問題が発生しました。", "bundle_modal_error.retry": "再試行", - "circles.account.add": "おはぎに追加", - "circles.account.remove": "おはぎから外す", + "circles.account.add": "サークルに追加", + "circles.account.remove": "サークルから外す", + "circles.delete": "サークルを削除", + "circles.edit": "サークルを編集", "circles.edit.submit": "タイトルを変更", "circles.new.create": "サークルを作成", "circles.new.title_placeholder": "新規サークル名", @@ -213,6 +218,7 @@ "compose_form.lock_disclaimer.lock": "承認制", "compose_form.markdown.marked": "Markdown有効", "compose_form.markdown.unmarked": "Markdownは有効になっていません", + "compose_form.mention_warning": "限定投稿にメンションを追加すると、そのアカウントはサークルメンバー・相互などに関係なくこの投稿を読むことができます", "compose_form.placeholder": "今なにしてる?", "compose_form.searchability_warning": "検索許可「自分のみ」はkmyblue内の検索でのみ有効です。他のサーバーでは「リアクションした人のみ」と同等に扱われます", "compose_form.poll.add_option": "追加", @@ -308,6 +314,7 @@ "empty_column.bookmark_categories": "まだ分類がありません。分類を作るとここに表示されます。", "empty_column.bookmarked_statuses": "まだ何もブックマーク登録していません。ブックマーク登録するとここに表示されます。", "empty_column.circles": "まだサークルがありません。サークルを作るとここに表示されます。", + "empty_column.circle_statuses": "まだサークル投稿がありません。このサークルでなにか投稿するとここに表示されます。", "empty_column.community": "ローカルタイムラインはまだ使われていません。何か書いてみましょう!", "empty_column.direct": "非公開の返信はまだありません。非公開でやりとりをするとここに表示されます。", "empty_column.domain_blocks": "ブロックしているドメインはありません。", @@ -618,6 +625,7 @@ "privacy.login.short": "ログインユーザーのみ", "privacy.mutual.long": "相互フォローさんのみ閲覧可、限定投稿", "privacy.mutual.short": "相互のみ", + "privacy.personal.short": "自分限定", "privacy.private.long": "フォロワーのみ閲覧可", "privacy.private.short": "フォロワーのみ", "privacy.public.long": "誰でも閲覧可、ホーム+ローカル+連合TL", diff --git a/app/lib/status_reach_finder.rb b/app/lib/status_reach_finder.rb index fde6e36fce..93f52bc7ec 100644 --- a/app/lib/status_reach_finder.rb +++ b/app/lib/status_reach_finder.rb @@ -160,7 +160,7 @@ class StatusReachFinder return [] if status.public_searchability? return [] unless (status.public_unlisted_visibility? && status.account.user&.setting_reject_public_unlisted_subscription) || (status.unlisted_visibility? && status.account.user&.setting_reject_unlisted_subscription) - from_info = InstanceInfo.where(software: %w(misskey calckey)).pluck(:domain) + from_info = InstanceInfo.where(software: %w(misskey calckey cherrypick)).pluck(:domain) from_domain_block = DomainBlock.where(detect_invalid_subscription: true).pluck(:domain) (from_info + from_domain_block).uniq end diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index e86356948f..0d68960eb4 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -5,11 +5,11 @@ module Mastodon module_function def kmyblue_major - 5 + 6 end def kmyblue_minor - 2 + 0 end def kmyblue_flag