Merge remote-tracking branch 'parent/main' into upstream-20231214

This commit is contained in:
KMY 2023-12-14 09:21:21 +09:00
commit 08a2f557fe
61 changed files with 980 additions and 838 deletions

View file

@ -118,7 +118,7 @@ GEM
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
addressable (2.8.5)
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
aes_key_wrap (1.1.0)
android_key_attestation (0.3.0)
@ -220,9 +220,9 @@ GEM
database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1)
date (3.3.4)
debug (1.8.0)
irb (>= 1.5.0)
reline (>= 0.3.1)
debug (1.9.0)
irb (~> 1.10)
reline (>= 0.3.8)
debug_inspector (1.1.0)
devise (4.9.3)
bcrypt (~> 3.0)
@ -326,7 +326,7 @@ GEM
ruby-progressbar (~> 1.4)
globalid (1.2.1)
activesupport (>= 6.1)
haml (6.2.0)
haml (6.3.0)
temple (>= 0.8.2)
thor
tilt
@ -335,7 +335,7 @@ GEM
activesupport (>= 5.1)
haml (>= 4.0.6)
railties (>= 5.1)
haml_lint (0.51.0)
haml_lint (0.52.0)
haml (>= 4.0)
parallel (~> 1.10)
rainbow
@ -381,7 +381,7 @@ GEM
rdoc
reline (>= 0.3.8)
jmespath (1.6.2)
json (2.7.0)
json (2.7.1)
json-canonicalization (1.0.0)
json-jwt (1.15.3)
activesupport (>= 4.2)
@ -484,8 +484,8 @@ GEM
nokogiri (1.15.5)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
oj (3.16.2)
bigdecimal (~> 3.1)
oj (3.16.3)
bigdecimal (>= 3.0)
omniauth (2.1.1)
hashie (>= 3.4.6)
rack (>= 2.2.3)
@ -622,7 +622,7 @@ GEM
redis (>= 4)
redlock (1.3.2)
redis (>= 3.0.0, < 6.0)
regexp_parser (2.8.2)
regexp_parser (2.8.3)
reline (0.4.1)
io-console (~> 0.5)
request_store (1.5.1)
@ -664,7 +664,7 @@ GEM
rspec-mocks (~> 3.0)
sidekiq (>= 5, < 8)
rspec-support (3.12.1)
rubocop (1.58.0)
rubocop (1.59.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
@ -761,7 +761,7 @@ GEM
unicode-display_width (>= 1.1.1, < 3)
terrapin (0.6.0)
climate_control (>= 0.0.3, < 1.0)
test-prof (1.3.0)
test-prof (1.3.1)
thor (1.3.0)
tilt (2.3.0)
timeout (0.4.1)

View file

@ -114,7 +114,7 @@ module ApplicationHelper
end
def fa_icon(icon, attributes = {})
class_names = attributes[:class]&.split(' ') || []
class_names = attributes[:class]&.split || []
class_names << 'fa'
class_names += icon.split.map { |cl| "fa-#{cl}" }

View file

@ -18,6 +18,6 @@ export const notificationsUpdate = createAction(
playSound: boolean;
}) => ({
payload: args,
meta: { playSound: playSound ? { sound: 'boop' } : undefined },
meta: { sound: playSound ? 'boop' : undefined },
}),
);

View file

@ -21,6 +21,7 @@
"account.blocked": "Blocked",
"account.browse_more_on_origin_server": "Browse more on the original profile",
"account.cancel_follow_request": "Cancel follow",
"account.copy": "Copy link to profile",
"account.direct": "Privately mention @{name}",
"account.disable_notifications": "Stop notifying me when @{name} posts",
"account.domain_blocked": "Domain blocked",
@ -191,6 +192,7 @@
"conversation.mark_as_read": "Mark as read",
"conversation.open": "View conversation",
"conversation.with": "With {names}",
"copy_icon_button.copied": "Copied to clipboard",
"copypaste.copied": "Copied",
"copypaste.copy_to_clipboard": "Copy to clipboard",
"directory.federated": "From known fediverse",
@ -222,6 +224,7 @@
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"empty_column.account_hides_collections": "This user has chosen to not make this information available",
"empty_column.account_suspended": "Account suspended",
"empty_column.account_timeline": "No posts here!",
"empty_column.account_unavailable": "Profile unavailable",
@ -478,6 +481,8 @@
"onboarding.follows.empty": "Unfortunately, no results can be shown right now. You can try using search or browsing the explore page to find people to follow, or try again later.",
"onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!",
"onboarding.follows.title": "Personalize your home feed",
"onboarding.profile.discoverable": "Make my profile discoverable",
"onboarding.profile.discoverable_hint": "When you opt in to discoverability on Mastodon, your posts may appear in search results and trending, and your profile may be suggested to people with similar interests to you.",
"onboarding.profile.display_name": "Display name",
"onboarding.profile.display_name_hint": "Your full name or your fun name…",
"onboarding.profile.lead": "You can always complete this later in the settings, where even more customisation options are available.",
@ -530,6 +535,7 @@
"privacy.unlisted.short": "Unlisted",
"privacy_policy.last_updated": "Last updated {date}",
"privacy_policy.title": "Privacy Policy",
"recommended": "Recommended",
"refresh": "Refresh",
"regeneration_indicator.label": "Loading…",
"regeneration_indicator.sublabel": "Your home feed is being prepared!",
@ -600,6 +606,7 @@
"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.full_text_search_logged_out_message": "Only available when logged in.",
"search_popout.language_code": "ISO language code",
"search_popout.options": "Search options",
"search_popout.quick_actions": "Quick actions",

View file

@ -21,6 +21,7 @@
"account.blocked": "Blokita",
"account.browse_more_on_origin_server": "Foliumi pli ĉe la originala profilo",
"account.cancel_follow_request": "Nuligi peton por sekvado",
"account.copy": "Kopii ligilon al profilo",
"account.direct": "Private mencii @{name}",
"account.disable_notifications": "Ne plu sciigi min, kiam @{name} mesaĝas",
"account.domain_blocked": "Domajno blokita",
@ -191,6 +192,7 @@
"conversation.mark_as_read": "Marki legita",
"conversation.open": "Vidi konversacion",
"conversation.with": "Kun {names}",
"copy_icon_button.copied": "Kopiis al kliptabulo",
"copypaste.copied": "Kopiita",
"copypaste.copy_to_clipboard": "Kopii al dosierujo",
"directory.federated": "El konata fediverso",
@ -202,7 +204,9 @@
"dismissable_banner.community_timeline": "Jen la plej novaj publikaj afiŝoj de uzantoj, kies kontojn gastigas {domain}.",
"dismissable_banner.dismiss": "Eksigi",
"dismissable_banner.explore_links": "Tiuj novaĵoj estas aktuale priparolataj de uzantoj en tiu ĉi kaj aliaj serviloj, sur la malcentrigita reto.",
"dismissable_banner.explore_statuses": "Ĉi tioj estas afiŝoj de socia reto kiu populariĝas hodiau.",
"dismissable_banner.explore_tags": "Ĉi tiuj kradvostoj populariĝas en ĉi tiu kaj aliaj serviloj en la malcentraliza reto nun.",
"dismissable_banner.public_timeline": "Ĉi tioj estas plej lastaj publikaj afiŝoj de personoj ĉe socia reto kiu personoj ĉe {domain} sekvas.",
"embed.instructions": "Enkorpigu ĉi tiun afiŝon en vian retejon per kopio de la suba kodo.",
"embed.preview": "Ĝi aperos tiel:",
"emoji_button.activity": "Agadoj",
@ -220,6 +224,7 @@
"emoji_button.search_results": "Serĉaj rezultoj",
"emoji_button.symbols": "Simboloj",
"emoji_button.travel": "Vojaĝoj kaj lokoj",
"empty_column.account_hides_collections": "Ĉi tiu uzanto elektis ne disponebligi ĉi tiu informon",
"empty_column.account_suspended": "Konto suspendita",
"empty_column.account_timeline": "Neniu afiŝo ĉi tie!",
"empty_column.account_unavailable": "Profilo ne disponebla",
@ -229,6 +234,8 @@
"empty_column.direct": "Vi ankoraŭ ne havas privatan mencion. Kiam vi sendos aŭ ricevos iun, tiu aperos ĉi tie.",
"empty_column.domain_blocks": "Ankoraŭ neniu domajno estas blokita.",
"empty_column.explore_statuses": "Nenio tendencas nun. Rekontrolu poste!",
"empty_column.favourited_statuses": "Vi ankoraŭ ne havas stelumitan afiŝon.",
"empty_column.favourites": "Ankoraŭ neniu stelumis tiun afiŝon.",
"empty_column.follow_requests": "Vi ne ankoraŭ havas iun peton de sekvado. Kiam vi ricevos unu, ĝi aperos ĉi tie.",
"empty_column.followed_tags": "Vi ankoraŭ ne sekvas iujn kradvortojn. Kiam vi faras, ili aperos ĉi tie.",
"empty_column.hashtag": "Ankoraŭ estas nenio per ĉi tiu kradvorto.",
@ -292,19 +299,36 @@
"hashtag.column_settings.tag_mode.any": "Iu ajn",
"hashtag.column_settings.tag_mode.none": "Neniu",
"hashtag.column_settings.tag_toggle": "Aldoni pliajn etikedojn por ĉi tiu kolumno",
"hashtag.counter_by_accounts": "{count, plural,one {{counter} partoprenanto} other {{counter} partoprenantoj}}",
"hashtag.counter_by_uses": "{count, plural,one {{counter} afiŝo} other {{counter} afiŝoj}}",
"hashtag.counter_by_uses_today": "{count, plural,one {{counter} afiŝo} other {{counter} afiŝoj}} hodiau",
"hashtag.follow": "Sekvi la kradvorton",
"hashtag.unfollow": "Ne plu sekvi la kradvorton",
"hashtags.and_other": "…kaj {count, plural,other {# pli}}",
"home.actions.go_to_explore": "Vidi kio populariĝas",
"home.actions.go_to_suggestions": "Trovi homojn por sekvi",
"home.column_settings.basic": "Bazaj agordoj",
"home.column_settings.show_reblogs": "Montri diskonigojn",
"home.column_settings.show_replies": "Montri respondojn",
"home.explore_prompt.body": "Via hejmafiŝaro havos miksitajn afiŝojn de kradvortoj kiujn vi elektis sekvi, personoj kiujn vi elektis sekvi, kaj afiŝoj kiujn ili suprenigis.",
"home.explore_prompt.title": "Ĉi tio estas via hejma paĝo en Mastodon.",
"home.hide_announcements": "Kaŝi la anoncojn",
"home.pending_critical_update.body": "Ĝisdatigu vian servilon de Mastodon kiel eble plej baldau!",
"home.pending_critical_update.link": "Vidi ĝisdatigojn",
"home.pending_critical_update.title": "Kritika sekurĝisdatigo estas disponebla!",
"home.show_announcements": "Montri anoncojn",
"interaction_modal.description.favourite": "Per konto ĉe Mastodon, vi povas stelumiti ĉi tiun afiŝon por sciigi la afiŝanton ke vi aprezigas ŝin kaj konservas por la estonteco.",
"interaction_modal.description.follow": "Kun konto ĉe Mastodon, vi povos sekvi {name} por vidi ties mesaĝojn en via hejmo.",
"interaction_modal.description.reblog": "Kun konto ĉe Mastodon, vi povas diskonigi ĉi tiun afiŝon, por ke viaj propraj sekvantoj vidu ĝin.",
"interaction_modal.description.reply": "Kun konto ĉe Mastodon, vi povos respondi al ĉi tiu mesaĝo.",
"interaction_modal.login.action": "Prenu min hejmen",
"interaction_modal.login.prompt": "Domajno de via hejma servilo, ekz. mastodon.social",
"interaction_modal.no_account_yet": "Ĉu ne estas ĉe Mastodon?",
"interaction_modal.on_another_server": "En alia servilo",
"interaction_modal.on_this_server": "En ĉi tiu servilo",
"interaction_modal.sign_in": "Vi ne estas ensalutita al ĉi tiu servilo.",
"interaction_modal.sign_in_hint": "Gvideto: Tio estas la retejo kie vi registris. Vi ankau povas tajpi vian plenan uzantonomon!",
"interaction_modal.title.favourite": "Stelumi la afiŝon de {name}",
"interaction_modal.title.follow": "Sekvi {name}",
"interaction_modal.title.reblog": "Akceli la afiŝon de {name}",
"interaction_modal.title.reply": "Respondi al la afiŝo de {name}",
@ -320,6 +344,8 @@
"keyboard_shortcuts.direct": "por malfermi la kolumnon pri privataj mencioj",
"keyboard_shortcuts.down": "iri suben en la listo",
"keyboard_shortcuts.enter": "malfermi mesaĝon",
"keyboard_shortcuts.favourite": "Stelumi afiŝon",
"keyboard_shortcuts.favourites": "Malfermi la liston de la stelumoj",
"keyboard_shortcuts.federated": "Malfermi la frataran templinion",
"keyboard_shortcuts.heading": "Klavaraj mallongigoj",
"keyboard_shortcuts.home": "Malfermi la hejman templinion",
@ -366,6 +392,7 @@
"lists.search": "Serĉi inter la homoj, kiujn vi sekvas",
"lists.subheading": "Viaj listoj",
"load_pending": "{count,plural, one {# nova elemento} other {# novaj elementoj}}",
"loading_indicator.label": "Ŝargado…",
"media_gallery.toggle_visible": "{number, plural, one {Kaŝi la bildon} other {Kaŝi la bildojn}}",
"moved_to_account_banner.text": "Via konto {disabledAccount} estas malvalidigita ĉar vi movis ĝin al {movedToAccount}.",
"mute_modal.duration": "Daŭro",
@ -382,6 +409,7 @@
"navigation_bar.domain_blocks": "Blokitaj domajnoj",
"navigation_bar.edit_profile": "Redakti profilon",
"navigation_bar.explore": "Esplori",
"navigation_bar.favourites": "Stelumoj",
"navigation_bar.filters": "Silentigitaj vortoj",
"navigation_bar.follow_requests": "Petoj de sekvado",
"navigation_bar.followed_tags": "Sekvataj kradvortoj",
@ -389,6 +417,7 @@
"navigation_bar.lists": "Listoj",
"navigation_bar.logout": "Adiaŭi",
"navigation_bar.mutes": "Silentigitaj uzantoj",
"navigation_bar.opened_in_classic_interface": "Afiŝoj, kontoj, kaj aliaj specifaj paĝoj kiuj estas malfermititaj defaulta en la klasika reta interfaco.",
"navigation_bar.personal": "Persone",
"navigation_bar.pins": "Alpinglitaj mesaĝoj",
"navigation_bar.preferences": "Preferoj",
@ -398,6 +427,7 @@
"not_signed_in_indicator.not_signed_in": "Necesas saluti por aliri tiun rimedon.",
"notification.admin.report": "{name} raportis {target}",
"notification.admin.sign_up": "{name} kreis konton",
"notification.favourite": "{name} stelumis vian afiŝon",
"notification.follow": "{name} eksekvis vin",
"notification.follow_request": "{name} petis sekvi vin",
"notification.mention": "{name} menciis vin",
@ -411,6 +441,7 @@
"notifications.column_settings.admin.report": "Novaj raportoj:",
"notifications.column_settings.admin.sign_up": "Novaj registriĝoj:",
"notifications.column_settings.alert": "Sciigoj de la retumilo",
"notifications.column_settings.favourite": "Stelumoj:",
"notifications.column_settings.filter_bar.advanced": "Montri ĉiujn kategoriojn",
"notifications.column_settings.filter_bar.category": "Rapida filtra breto",
"notifications.column_settings.filter_bar.show_bar": "Montri la breton de filtrilo",
@ -428,6 +459,7 @@
"notifications.column_settings.update": "Redaktoj:",
"notifications.filter.all": "Ĉiuj",
"notifications.filter.boosts": "Diskonigoj",
"notifications.filter.favourites": "Stelumoj",
"notifications.filter.follows": "Sekvoj",
"notifications.filter.mentions": "Mencioj",
"notifications.filter.polls": "Balotenketaj rezultoj",
@ -441,14 +473,29 @@
"notifications_permission_banner.enable": "Ŝalti retumilajn sciigojn",
"notifications_permission_banner.how_to_control": "Por ricevi sciigojn kiam Mastodon ne estas malfermita, ebligu labortablajn sciigojn. Vi povas regi precize kiuj specoj de interagoj generas labortablajn sciigojn per la supra butono {icon} post kiam ili estas ebligitaj.",
"notifications_permission_banner.title": "Neniam preterlasas iun ajn",
"onboarding.action.back": "Prenu min reen",
"onboarding.actions.back": "Prenu min reen",
"onboarding.actions.go_to_explore": "See what's trending",
"onboarding.actions.go_to_home": "Go to your home feed",
"onboarding.compose.template": "Saluton #Mastodon!",
"onboarding.follows.empty": "Bedaŭrinde, neniu rezulto estas montrebla nuntempe. Vi povas provi serĉi aŭ foliumi la esploran paĝon por trovi kontojn por sekvi, aŭ retrovi baldaŭ.",
"onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!",
"onboarding.follows.title": "Popular on Mastodon",
"onboarding.profile.discoverable": "Trovebligi mian profilon",
"onboarding.profile.discoverable_hint": "Kiam vi aliĝi al trovebleco ĉe Mastodon, viaj afiŝoj eble aperos en serĉaj rezultoj kaj populariĝoj, kaj via profilo eble estas sugestota al personoj kun similaj intereseoj al vi.",
"onboarding.profile.display_name": "Publika nomo",
"onboarding.profile.display_name_hint": "Via plena nomo aŭ via kromnomo…",
"onboarding.profile.lead": "Vi ĉiam povas plenigi ĉi tion poste en la agordoj, kie eĉ pli da personecigagordoj estas disponeblaj.",
"onboarding.profile.note": "Sinprezento",
"onboarding.profile.note_hint": "Vi povas @mencii aliajn homojn aŭ #kradvortojn…",
"onboarding.profile.save_and_continue": "Konservi kaj daŭrigi",
"onboarding.profile.title": "Profila fikso",
"onboarding.profile.upload_avatar": "Alŝuti profilbildon",
"onboarding.profile.upload_header": "Alŝuti profilkapbildon",
"onboarding.share.lead": "Sciigi personojn pri kiel ili povas trovi vin ĉe Mastodon!",
"onboarding.share.message": "Mi estas {username} en #Mastodon! Sekvu min ĉe {url}",
"onboarding.share.next_steps": "Eblaj malantauaj paŝoj:",
"onboarding.share.title": "Disvastigi vian profilon",
"onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:",
"onboarding.start.skip": "Want to skip right ahead?",
"onboarding.start.title": "Vi atingas ĝin!",
@ -460,6 +507,9 @@
"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": "<strong>Ĉu vi scias?</strong> Vi povas sekurigi vian konton per efektivigi dufaktora autentigo en via kontoagordoj.",
"onboarding.tips.accounts_from_other_servers": "<strong>Ĉu vi scias?</strong> Ĉar Mastodon estas sencentra, kelkaj profiloj kiujn vi trovi estas gastigitaj ĉe aliaj serviloj kiuj ne estas via.",
"onboarding.tips.migration": "<strong>Ĉu vi scias?</strong> Se vi sentas ke {domain} ne estas bona servilelekto por vi en la estonteco, vi povas translokiĝi al alia servilo de Mastodon sen malgajni viajn sekvantojn.",
"password_confirmation.mismatching": "Pasvorto konfirmo ne kongruas",
"picture_in_picture.restore": "Remetu ĝin",
"poll.closed": "Finita",

View file

@ -606,6 +606,7 @@
"search.quick_action.status_search": "Sobivad postitused {x}",
"search.search_or_paste": "Otsi või kleebi URL",
"search_popout.full_text_search_disabled_message": "Pole saadaval kohas {domain}.",
"search_popout.full_text_search_logged_out_message": "Saadaval vaid kui sisse logitud.",
"search_popout.language_code": "Keele ISO-kood",
"search_popout.options": "Otsimisvalikud",
"search_popout.quick_actions": "Kiirtegevused",

View file

@ -30,7 +30,7 @@
"account.blocked": "ブロック済み",
"account.browse_more_on_origin_server": "リモートで表示",
"account.cancel_follow_request": "フォローリクエストの取り消し",
"account.copy": "プロフィールのリンクをコピーして下さい",
"account.copy": "プロフィールのリンクをコピー",
"account.direct": "@{name}さんに非公開でメンション",
"account.disable_notifications": "@{name}さんの投稿時の通知を停止",
"account.domain_blocked": "ドメインブロック中",
@ -276,7 +276,7 @@
"conversation.mark_as_read": "既読にする",
"conversation.open": "会話を表示",
"conversation.with": "{names}",
"copy_icon_button.copied": "クリップボードにコピーされた",
"copy_icon_button.copied": "コピーしました",
"copypaste.copied": "コピーしました",
"copypaste.copy_to_clipboard": "クリップボードにコピー",
"directory.federated": "既知の連合より",
@ -486,7 +486,7 @@
"lists.search": "フォローしている人の中から検索",
"lists.subheading": "あなたのリスト",
"load_pending": "{count}件の新着",
"loading_indicator.label": "",
"loading_indicator.label": "読み込み中…",
"media_gallery.toggle_visible": "{number, plural, one {画像を閉じる} other {画像を閉じる}}",
"moved_to_account_banner.text": "あなたのアカウント『{disabledAccount}』は『{movedToAccount}』に移動したため現在無効になっています。",
"mute_modal.duration": "ミュートする期間",
@ -589,17 +589,17 @@
"onboarding.follows.empty": "表示できる結果はありません。検索やエクスプローラーを使ったり、ほかのアカウントをフォローしたり、後でもう一度試しください。",
"onboarding.follows.lead": "ホームタイムラインはMastodonの軸足となる場所です。たくさんのユーザーをフォローすることで、ホームタイムラインはよりにぎやかでおもしろいものになります。手はじめに、おすすめのアカウントから何人かフォローしてみましょう:",
"onboarding.follows.title": "ホームタイムラインを埋める",
"onboarding.profile.discoverable": "自分のプロフィールが発見できないようにする",
"onboarding.profile.discoverable_hint": "マストドンの見つけやすくする機能が個人情報を利用することに承諾すると、あなたの投稿が検索結果やトレンドに表示されることがあります。また、あなたのプロフィールがあなたと似た興味関心を持つ人に提案されることがあります。",
"onboarding.profile.discoverable": "自分のプロフィールが見つけられるようにする",
"onboarding.profile.discoverable_hint": "Mastodonの「見つける」機能にオプトインすると、あなたの投稿が検索結果やトレンドに表示されることがあります。また、あなたに似た関心を持つ人にプロフィールがおすすめされることがあります。",
"onboarding.profile.display_name": "表示名",
"onboarding.profile.display_name_hint": "あなたのフルネーム、または楽しい名前…",
"onboarding.profile.lead": "このことは後でいつでも設定から完了させることが出来ますし、設定では更に多くのカスタマイズが利用可能になっています。",
"onboarding.profile.display_name_hint": "フルネーム、あるいは面白い名前など",
"onboarding.profile.lead": "あとでいつでも修正できますし、設定画面にはこれ以外のカスタマイズ項目もあります。",
"onboarding.profile.note": "自己紹介",
"onboarding.profile.note_hint": "@を使用して他の人々にメンションをすることができます。また#でハッシュタグが使用できます",
"onboarding.profile.save_and_continue": "保存してから続行して下さい",
"onboarding.profile.note_hint": "ほかの人に @言及 したり、#ハッシュタグ を付けたりできます",
"onboarding.profile.save_and_continue": "保存して続ける",
"onboarding.profile.title": "プロフィールの設定",
"onboarding.profile.upload_avatar": "プロフィール画像をアップロードしてください",
"onboarding.profile.upload_header": "プロフィールのヘッダー画像をアップロードして下さい",
"onboarding.profile.upload_avatar": "プロフィール画像をアップロード",
"onboarding.profile.upload_header": "プロフィールのヘッダー画像をアップロード",
"onboarding.share.lead": "新しいMastodonのアカウントをみんなに紹介しましょう。",
"onboarding.share.message": "「{username}」で #Mastodon はじめました! {url}",
"onboarding.share.next_steps": "次のステップに進む:",
@ -738,6 +738,7 @@
"searchability.unlisted.short": "フォロワーと反応者",
"search_popout.domain": "ドメイン",
"search_popout.full_text_search_disabled_message": "{domain}では利用できません。",
"search_popout.full_text_search_logged_out_message": "ログイン時のみ利用できます。",
"search_popout.language_code": "ISO言語コード",
"search_popout.options": "検索オプション",
"search_popout.quick_actions": "クイック操作",

View file

@ -239,7 +239,7 @@
"empty_column.follow_requests": "아직 팔로우 요청이 없습니다. 요청을 받았을 때 여기에 나타납니다.",
"empty_column.followed_tags": "아직 아무 해시태그도 팔로우하고 있지 않습니다. 해시태그를 팔로우하면, 여기에 표시됩니다.",
"empty_column.hashtag": "이 해시태그는 아직 사용되지 않았습니다.",
"empty_column.home": "당신의 홈 타임라인은 비어있습니다! 더 많은 사람을 팔로우 하여 채워보세요. {suggestions}",
"empty_column.home": "당신의 홈 타임라인은 비어있습니다! 더 많은 사람을 팔로우하여 채워보세요. {suggestions}",
"empty_column.list": "리스트에 아직 아무것도 없습니다. 리스트의 누군가가 게시물을 올리면 여기에 나타납니다.",
"empty_column.lists": "아직 리스트가 없습니다. 리스트를 만들면 여기에 나타납니다.",
"empty_column.mutes": "아직 아무도 뮤트하지 않았습니다.",

View file

@ -1,6 +1,6 @@
{
"about.contact": "Ratio:",
"about.domain_blocks.no_reason_available": "ratio abdere est",
"about.domain_blocks.no_reason_available": "Ratio abdere est",
"account.account_note_header": "Annotatio",
"account.badges.bot": "Robotum",
"account.badges.group": "Congregatio",
@ -49,7 +49,7 @@
"dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.",
"dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.",
"embed.instructions": "Embed this status on your website by copying the code below.",
"emoji_button.food": "cibus et potus",
"emoji_button.food": "Cibus et potus",
"emoji_button.people": "Homines",
"emoji_button.search": "Quaerere...",
"empty_column.account_timeline": "Hic nulla contributa!",
@ -57,13 +57,13 @@
"empty_column.home": "Your home timeline is empty! Follow more people to fill it up. {suggestions}",
"empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.",
"explore.trending_statuses": "Contributa",
"generic.saved": "servavit",
"generic.saved": "Servavit",
"hashtag.column_settings.tag_toggle": "Include additional tags in this column",
"keyboard_shortcuts.back": "to navigate back",
"keyboard_shortcuts.blocked": "to open blocked users list",
"keyboard_shortcuts.boost": "to boost",
"keyboard_shortcuts.column": "to focus a status in one of the columns",
"keyboard_shortcuts.compose": "to focus the compose textarea",
"keyboard_shortcuts.back": "Re navigare",
"keyboard_shortcuts.blocked": "Aperire listam usorum obstructorum",
"keyboard_shortcuts.boost": "Inlustrare publicatio",
"keyboard_shortcuts.column": "Columnam dirigere",
"keyboard_shortcuts.compose": "TextArea Compositi Attendere",
"keyboard_shortcuts.description": "Descriptio",
"keyboard_shortcuts.direct": "to open direct messages column",
"keyboard_shortcuts.down": "to move down in the list",

View file

@ -1 +1,80 @@
{}
{
"about.contact": "सम्पर्क:",
"about.disclaimer": "Mastodon नि:शुल्क, खुला स्रोत सफ्टवेयर, र Mastodon gGmbH को ट्रेडमार्क हो।",
"about.domain_blocks.no_reason_available": "कारण उपलब्ध छैन",
"about.domain_blocks.preamble": "Mastodon ले तपाइँलाई सामान्यतया फेडिभर्समा कुनै पनि अन्य सर्भरका सामग्री हेर्न र प्रयोगकर्ताहरूसँग अन्तरक्रिया गर्न दिन्छ। यी अपवादहरू हुन् जुन यस विशेष सर्भरमा बनाइएका छन्।",
"about.domain_blocks.silenced.title": "सीमित",
"about.domain_blocks.suspended.explanation": "यस सर्भरबाट कुनै पनि डेटा प्रशोधन, भण्डारण वा आदानप्रदान गरिने छैन, जसले यस सर्भरका प्रयोगकर्ताहरूसँग कुनै पनि अन्तरक्रिया वा सञ्चारलाई असम्भव बनाउँछ।",
"about.domain_blocks.suspended.title": "निलम्बित",
"about.not_available": "यो जानकारी यस सर्भरमा उपलब्ध गराइएको छैन।",
"about.powered_by": "{mastodon} द्वारा संचालित विकेन्द्रीकृत सामाजिक मिडिया",
"about.rules": "सर्भर नियमहरू",
"account.add_or_remove_from_list": "सूचीबाट थप्नुहोस् वा हटाउनुहोस्",
"account.badges.group": "समूह",
"account.block": "@{name} लाई ब्लक गर्नुहोस्",
"account.block_domain": "{domain} डोमेनलाई ब्लक गर्नुहोस्",
"account.block_short": "ब्लक",
"account.blocked": "ब्लक गरिएको",
"account.browse_more_on_origin_server": "मूल प्रोफाइलमा थप ब्राउज गर्नुहोस्",
"account.cancel_follow_request": "फलो अनुरोध रद्द गर्नुहोस",
"account.copy": "प्रोफाइलको लिङ्क प्रतिलिपि गर्नुहोस्",
"account.direct": "@{name} लाई निजी रूपमा उल्लेख गर्नुहोस्",
"account.disable_notifications": "@{name} ले पोस्ट गर्दा मलाई सूचित नगर्नुहोस्",
"account.domain_blocked": "डोमेन ब्लक गरिएको छ",
"account.edit_profile": "प्रोफाइल सम्पादन गर्नुहोस्",
"account.enable_notifications": "@{name} ले पोस्ट गर्दा मलाई सूचित गर्नुहोस्",
"account.endorse": "प्रोफाइलमा फिचर गर्नुहोस्",
"account.featured_tags.last_status_never": "कुनै पोस्ट छैन",
"account.follow": "फलो गर्नुहोस",
"account.followers.empty": "यस प्रयोगकर्तालाई अहिलेसम्म कसैले फलो गर्दैन।",
"account.follows.empty": "यो प्रयोगकर्ताले अहिलेसम्म कसैलाई फलो गरेको छैन।",
"account.go_to_profile": "प्रोफाइलमा जानुहोस्",
"account.hide_reblogs": "@{name} को बूस्टहरू लुकाउनुहोस्",
"account.link_verified_on": "यस लिङ्कको स्वामित्व {date} मा जाँच गरिएको थियो",
"account.media": "मिडिया",
"account.mention": "@{name} लाई उल्लेख गर्नुहोस्",
"account.no_bio": "कुनै विवरण प्रदान गरिएको छैन।",
"account.posts": "पोस्टहरू",
"account.requested": "स्वीकृतिको पर्खाइमा। फलो अनुरोध रद्द गर्न क्लिक गर्नुहोस्",
"account.requested_follow": "{name} ले तपाईंलाई फलो गर्न अनुरोध गर्नुभएको छ",
"account.share": "@{name} को प्रोफाइल सेयर गर्नुहोस्",
"account.show_reblogs": "@{name} को बूस्टहरू देखाउनुहोस्",
"account.statuses_counter": "{count, plural, one {{counter} पोस्ट} other {{counter} पोस्टहरू}}",
"account.unblock": "@{name} लाई अनब्लक गर्नुहोस्",
"account.unblock_domain": "{domain} डोमेनलाई अनब्लक गर्नुहोस्",
"account.unblock_short": "अनब्लक गर्नुहोस्",
"account.unendorse": "प्रोफाइलमा फिचर नगर्नुहोस्",
"account.unfollow": "अनफलो गर्नुहोस्",
"account_note.placeholder": "नोट लेख्न क्लिक गर्नुहोस्",
"admin.dashboard.retention.average": "औसत",
"admin.dashboard.retention.cohort_size": "नयाँ प्रयोगकर्ताहरू",
"alert.rate_limited.message": "कृपया {retry_time, time, medium} पछि पुन: प्रयास गर्नुहोस्।",
"alert.unexpected.message": "एउटा अनपेक्षित त्रुटि भयो।",
"bundle_column_error.retry": "पुन: प्रयास गर्नुहोस्",
"bundle_modal_error.close": "बन्द गर्नुहोस्",
"bundle_modal_error.message": "यो कम्पोनेन्ट लोड गर्दा केही गडबड भयो।",
"bundle_modal_error.retry": "Try again",
"closed_registrations.other_server_instructions": "Mastodon विकेन्द्रीकृत भएकोले, तपाइँ अर्को सर्भरमा खाता खोल्न सक्नुहुन्छ र पनि यो सर्भरसँग अन्तरक्रिया गर्न सक्नुहुन्छ।",
"closed_registrations_modal.description": "हाल {domain} मा खाता सिर्जना गर्न सम्भव छैन, तर कृपया ध्यान राख्नुहोस् कि तपाईंले Mastodon प्रयोग गर्नको लागि {domain} मा नै खाता खोल्न आवश्यक छैन।",
"closed_registrations_modal.find_another_server": "अर्को सर्भर खोज्नुहोस्",
"closed_registrations_modal.title": "Mastodon मा साइन अप गर्दै",
"column.blocks": "ब्लक गरिएको प्रयोगकर्ताहरु",
"column.directory": "प्रोफाइल ब्राउज गर्नुहोस्",
"column.domain_blocks": "ब्लक गरिएको डोमेन",
"column.follow_requests": "फलो अनुरोधहरू",
"column.lists": "सूचीहरू",
"column.notifications": "सूचनाहरू",
"column_header.hide_settings": "सेटिङ्हरू लुकाउनुहोस्",
"column_subheading.settings": "सेटिङहरू",
"compose.language.change": "भाषा परिवर्तन गर्नुहोस्",
"compose.language.search": "भाषाहरू खोज्नुहोस्...",
"compose_form.direct_message_warning_learn_more": "थप जान्नुहोस्",
"compose_form.poll.add_option": "विकल्प थप्नुहोस्",
"compose_form.poll.remove_option": "यो विकल्प हटाउनुहोस्",
"compose_form.publish_form": "नयाँ पोस्ट",
"compose_form.save_changes": "परिवर्तनहरू सेभ गर्नुहोस",
"compose_form.sensitive.hide": "{count, plural, one {संवेदनशील मिडियाको रूपमा चिन्ह लगाउनुहोस्} other {संवेदनशील मिडियाहरूको रूपमा चिन्ह लगाउनुहोस्}}",
"compose_form.sensitive.marked": "{count, plural, one {मिडियालाई संवेदनशील रूपमा चिन्ह लगाइएको छ} other {मिडियाहरूलाई संवेदनशील रूपमा चिन्ह लगाइएको छ}}",
"compose_form.sensitive.unmarked": "{count, plural, one {मिडियालाई संवेदनशील रूपमा चिन्ह लगाइएको छैन} other {मिडियाहरूलाई संवेदनशील रूपमा चिन्ह लगाइएको छैन}}",
"compose_form.spoiler_placeholder": "यहाँ आफ्नो चेतावनी लेख्नुहोस्"
}

View file

@ -224,6 +224,7 @@
"emoji_button.search_results": "Výsledky hľadania",
"emoji_button.symbols": "Symboly",
"emoji_button.travel": "Cestovanie a miesta",
"empty_column.account_hides_collections": "Tento užívateľ si zvolil nesprístupniť túto informáciu",
"empty_column.account_suspended": "Účet bol pozastavený",
"empty_column.account_timeline": "Nie sú tu žiadne príspevky!",
"empty_column.account_unavailable": "Profil nedostupný",

View file

@ -8,7 +8,7 @@
"about.domain_blocks.silenced.title": "已受限",
"about.domain_blocks.suspended.explanation": "來自此伺服器的資料都不會被處理、儲存或交換,也無法與此伺服器上的使用者互動或交流。",
"about.domain_blocks.suspended.title": "已停權",
"about.not_available": "無法於伺服器上使用此資訊。",
"about.not_available": "無法於伺服器上使用此資訊。",
"about.powered_by": "由 {mastodon} 提供的去中心化社群媒體",
"about.rules": "伺服器規則",
"account.account_note_header": "備註",
@ -34,9 +34,9 @@
"account.follow": "跟隨",
"account.followers": "跟隨者",
"account.followers.empty": "尚未有人跟隨這位使用者。",
"account.followers_counter": "被 {count, plural,one {{counter} 人}other {{counter} 人}}跟隨",
"account.followers_counter": "被 {count, plural, other {{counter} 人}}跟隨",
"account.following": "跟隨中",
"account.following_counter": "正在跟隨 {count, plural, one {{counter} 人} other {{counter} 人}}",
"account.following_counter": "正在跟隨 {count,plural,other {{counter} 人}}",
"account.follows.empty": "這位使用者尚未跟隨任何人。",
"account.follows_you": "跟隨了您",
"account.go_to_profile": "前往個人檔案",
@ -72,8 +72,8 @@
"account.unmute_notifications_short": "取消靜音推播通知",
"account.unmute_short": "解除靜音",
"account_note.placeholder": "按此新增備註",
"admin.dashboard.daily_retention": "註冊後使用者存留率(日)",
"admin.dashboard.monthly_retention": "註冊後使用者存留率(月)",
"admin.dashboard.daily_retention": "註冊後使用者存留率(日)",
"admin.dashboard.monthly_retention": "註冊後使用者存留率(月)",
"admin.dashboard.retention.average": "平均",
"admin.dashboard.retention.cohort": "註冊月份",
"admin.dashboard.retention.cohort_size": "新使用者",
@ -105,7 +105,7 @@
"closed_registrations.other_server_instructions": "因為 Mastodon 是去中心化的,所以您也能於其他伺服器上建立帳號,並仍然與這個伺服器互動。",
"closed_registrations_modal.description": "目前無法於 {domain} 建立新帳號,但也請別忘了,您並不一定需要有 {domain} 伺服器的帳號,也能使用 Mastodon。",
"closed_registrations_modal.find_another_server": "尋找另一個伺服器",
"closed_registrations_modal.preamble": "Mastodon 是去中心化的,所以無論您於哪個伺服器新增帳號,都可以與此伺服器上的任何人跟隨及互動。您甚至能自行架一個自己的伺服器!",
"closed_registrations_modal.preamble": "Mastodon 是去中心化的,所以無論您於哪個伺服器新增帳號,都可以與此伺服器上的任何人跟隨及互動。您甚至能自行架一個自己的伺服器!",
"closed_registrations_modal.title": "註冊 Mastodon",
"column.about": "關於",
"column.blocks": "已封鎖的使用者",
@ -155,7 +155,7 @@
"compose_form.publish_form": "嘟出去",
"compose_form.publish_loud": "{publish}",
"compose_form.save_changes": "儲存變更",
"compose_form.sensitive.hide": "標記媒體為敏感內容",
"compose_form.sensitive.hide": "{count, plural, other {將媒體標記為敏感內容}}",
"compose_form.sensitive.marked": "此媒體被標記為敏感內容",
"compose_form.sensitive.unmarked": "此媒體未被標記為敏感內容",
"compose_form.spoiler.marked": "移除內容警告",
@ -207,14 +207,14 @@
"dismissable_banner.explore_statuses": "這些於此伺服器以及去中心化網路中其他伺服器發出的嘟文正在被此伺服器上的人們熱烈討論著。越多不同人轉嘟及最愛排名更高。",
"dismissable_banner.explore_tags": "這些主題標籤正在被此伺服器以及去中心化網路上的人們熱烈討論著。越多不同人所嘟出的主題標籤排名更高。",
"dismissable_banner.public_timeline": "這些是來自 {domain} 使用者們跟隨中帳號所發表之最新公開嘟文。",
"embed.instructions": "若您欲於您的網站嵌入此嘟文,請複製以下程式碼。",
"embed.instructions": "如要將此嘟文嵌入您的網站,請複製以下程式碼。",
"embed.preview": "它將顯示成這樣:",
"emoji_button.activity": "活動",
"emoji_button.clear": "清除",
"emoji_button.custom": "自訂",
"emoji_button.flags": "旗幟",
"emoji_button.food": "食物 & 飲料",
"emoji_button.label": "插入表情符號",
"emoji_button.label": "插入表情圖案",
"emoji_button.nature": "自然",
"emoji_button.not_found": "啊就沒這表情符號吼!! (╯°□°)╯︵ ┻━┻",
"emoji_button.objects": "物件",
@ -353,11 +353,11 @@
"keyboard_shortcuts.legend": "顯示此說明選單",
"keyboard_shortcuts.local": "開啟本站時間軸",
"keyboard_shortcuts.mention": "提及作者",
"keyboard_shortcuts.muted": "開啟靜音使用者列表",
"keyboard_shortcuts.muted": "開啟靜音使用者清單",
"keyboard_shortcuts.my_profile": "開啟個人檔案頁面",
"keyboard_shortcuts.notifications": "開啟通知欄",
"keyboard_shortcuts.open_media": "開啟媒體",
"keyboard_shortcuts.pinned": "開啟釘選的嘟文列表",
"keyboard_shortcuts.pinned": "開啟釘選的嘟文清單",
"keyboard_shortcuts.profile": "開啟作者的個人檔案頁面",
"keyboard_shortcuts.reply": "回應嘟文",
"keyboard_shortcuts.requests": "開啟跟隨請求列表",
@ -386,7 +386,7 @@
"lists.new.create": "新增列表",
"lists.new.title_placeholder": "新列表標題",
"lists.replies_policy.followed": "任何跟隨的使用者",
"lists.replies_policy.list": "列表成員",
"lists.replies_policy.list": "成員清單",
"lists.replies_policy.none": "沒有人",
"lists.replies_policy.title": "顯示回覆:",
"lists.search": "搜尋您跟隨的使用者",
@ -452,7 +452,7 @@
"notifications.column_settings.push": "推播通知",
"notifications.column_settings.reblog": "轉嘟:",
"notifications.column_settings.show": "於欄位中顯示",
"notifications.column_settings.sound": "播放音",
"notifications.column_settings.sound": "播放",
"notifications.column_settings.status": "新嘟文:",
"notifications.column_settings.unread_notifications.category": "未讀通知",
"notifications.column_settings.unread_notifications.highlight": "突顯未讀通知",
@ -477,7 +477,7 @@
"onboarding.actions.back": "返回",
"onboarding.actions.go_to_explore": "看看發生什麼新鮮事",
"onboarding.actions.go_to_home": "前往您的首頁時間軸",
"onboarding.compose.template": "哈囉 #Mastodon",
"onboarding.compose.template": "你好 #Mastodon",
"onboarding.follows.empty": "很遺憾,目前未能顯示任何結果。您可以嘗試使用搜尋、瀏覽探索頁面以找尋人們跟隨、或稍候再試。",
"onboarding.follows.lead": "您的首頁時間軸是 Mastodon 的核心體驗。若您跟隨更多人的話,它將會變得更活躍有趣。這些個人檔案也許是個好起點,您可以隨時取消跟隨他們!",
"onboarding.follows.title": "客製化您的首頁時間軸",
@ -540,7 +540,7 @@
"regeneration_indicator.label": "載入中…",
"regeneration_indicator.sublabel": "您的首頁時間軸正在準備中!",
"relative_time.days": "{number} 天",
"relative_time.full.days": "{number, plural, one {# 天} other {# 天}}前",
"relative_time.full.days": "{number, plural, other {# 天}}前",
"relative_time.full.hours": "{number, plural, one {# 小時} other {# 小時}}前",
"relative_time.full.just_now": "剛剛",
"relative_time.full.minutes": "{number, plural, one {# 分鐘} other {# 分鐘}}前",
@ -620,7 +620,7 @@
"search_results.see_all": "檢視全部",
"search_results.statuses": "嘟文",
"search_results.title": "搜尋:{q}",
"server_banner.about_active_users": "最近三十日內使用此伺服器的人 (月活躍使用者)",
"server_banner.about_active_users": "最近三十日內使用此伺服器的人(月活躍使用者)",
"server_banner.active_users": "活躍使用者",
"server_banner.administered_by": "管理者:",
"server_banner.introduction": "{domain} 是由 {mastodon} 提供之去中心化社群網路一部分。",
@ -687,7 +687,7 @@
"status.translated_from_with": "透過 {provider} 翻譯 {lang}",
"status.uncached_media_warning": "無法預覽",
"status.unmute_conversation": "解除此對話的靜音",
"status.unpin": "個人檔案頁面取消釘選",
"status.unpin": "個人檔案頁面取消釘選",
"subscribed_languages.lead": "僅選定語言的嘟文才會出現於您的首頁上,並於變更後列出時間軸。選取「無」以接收所有語言的嘟文。",
"subscribed_languages.save": "儲存變更",
"subscribed_languages.target": "變更 {target} 的訂閱語言",

View file

@ -4642,11 +4642,6 @@ a.status-card {
align-items: center;
justify-content: center;
@supports (display: grid) {
// hack to fix Chrome <57
contain: strict;
}
& > span {
max-width: 500px;
}

View file

@ -42,13 +42,13 @@ class InlineRenderer
private
def preload_associations_for_status
ActiveRecord::Associations::Preloader.new(records: @object, associations: {
ActiveRecord::Associations::Preloader.new(records: [@object], associations: {
active_mentions: :account,
reblog: {
active_mentions: :account,
},
})
}).call
end
def current_user

View file

@ -14,9 +14,8 @@ class Vacuum::PreviewCardsVacuum
private
def vacuum_cached_images!
preview_cards_past_retention_period.find_each do |preview_card|
preview_card.image.destroy
preview_card.save
preview_cards_past_retention_period.find_in_batches do |preview_card|
AttachmentBatch.new(PreviewCard, preview_card).clear
end
end

View file

@ -78,9 +78,9 @@ class Announcement < ApplicationRecord
else
scope.select("name, custom_emoji_id, count(*) as count, exists(select 1 from announcement_reactions r where r.account_id = #{account.id} and r.announcement_id = announcement_reactions.announcement_id and r.name = announcement_reactions.name) as me")
end
end
end.to_a
ActiveRecord::Associations::Preloader.new(records: records, associations: :custom_emoji)
ActiveRecord::Associations::Preloader.new(records: records, associations: :custom_emoji).call
records
end

View file

@ -147,7 +147,7 @@ module Account::Search
tsquery = generate_query_for_search(terms)
find_by_sql([BASIC_SEARCH_SQL, { limit: limit, offset: offset, tsquery: tsquery }]).tap do |records|
ActiveRecord::Associations::Preloader.new(records: records, associations: :account_stat)
ActiveRecord::Associations::Preloader.new(records: records, associations: [:account_stat, { user: :role }]).call
end
end
@ -160,7 +160,7 @@ module Account::Search
end
find_by_sql([sql_template, { id: account.id, limit: limit, offset: offset, tsquery: tsquery }]).tap do |records|
ActiveRecord::Associations::Preloader.new(records: records, associations: :account_stat)
ActiveRecord::Associations::Preloader.new(records: records, associations: [:account_stat, { user: :role }]).call
end
end

View file

@ -134,7 +134,7 @@ class Notification < ApplicationRecord
# Instead of using the usual `includes`, manually preload each type.
# If polymorphic associations are loaded with the usual `includes`, other types of associations will be loaded more.
ActiveRecord::Associations::Preloader.new(records: grouped_notifications, associations: associations)
ActiveRecord::Associations::Preloader.new(records: grouped_notifications, associations: associations).call
end
unique_target_statuses = notifications.filter_map(&:target_status).uniq

View file

@ -111,8 +111,8 @@ class InitialStateSerializer < ActiveModel::Serializer
ActiveRecord::Associations::Preloader.new(
records: [object.current_account, object.admin, object.owner, object.disabled_account, object.moved_to_account].compact,
associations: [:account_stat, :user, { moved_to_account: [:account_stat, :user] }]
)
associations: [:account_stat, { user: :role, moved_to_account: [:account_stat, { user: :role }] }]
).call
store[object.current_account.id.to_s] = serialized_account(object.current_account) if object.current_account
store[object.admin.id.to_s] = serialized_account(object.admin) if object.admin

View file

@ -242,7 +242,7 @@ class AccountSearchService < BaseService
records = query_builder.build.limit(limit_for_non_exact_results).offset(offset).objects.compact
ActiveRecord::Associations::Preloader.new(records: records, associations: :account_stat)
ActiveRecord::Associations::Preloader.new(records: records, associations: [:account_stat, { user: :role }]).call
records
rescue Faraday::ConnectionFailed, Parslet::ParseFailed

View file

@ -11,7 +11,7 @@ class BatchedRemoveStatusService < BaseService
ActiveRecord::Associations::Preloader.new(
records: statuses,
associations: options[:skip_side_effects] ? :reblogs : [:account, :tags, reblogs: :account]
)
).call
statuses_and_reblogs = statuses.flat_map { |status| [status] + status.reblogs }
@ -23,7 +23,7 @@ class BatchedRemoveStatusService < BaseService
ActiveRecord::Associations::Preloader.new(
records: statuses_with_account_conversations,
associations: [mentions: :account]
)
).call
statuses_with_account_conversations.each(&:unlink_from_conversations!)

View file

@ -91,6 +91,15 @@ class FanOutOnWriteService < BaseService
LocalNotificationWorker.push_bulk(mentions) do |mention|
[mention.account_id, mention.id, 'Mention', 'mention']
end
next unless update?
# This may result in duplicate update payloads, but this ensures clients
# are aware of edits to posts only appearing in mention notifications
# (e.g. private mentions or mentions by people they do not follow)
PushUpdateWorker.push_bulk(mentions.filter { |mention| subscribed_to_streaming_api?(mention.account_id) }) do |mention|
[mention.account_id, @status.id, "timeline:#{mention.account_id}:notifications", { 'update' => true }]
end
end
end
@ -217,4 +226,8 @@ class FanOutOnWriteService < BaseService
def broadcastable_unlisted_public?
@status.unlisted_visibility? && @status.compute_searchability == 'public' && !@status.reblog? && !@account.silenced?
end
def subscribed_to_streaming_api?(account_id)
redis.exists?("subscribed:timeline:#{account_id}") || redis.exists?("subscribed:timeline:#{account_id}:notifications")
end
end

View file

@ -100,7 +100,7 @@ class FetchOEmbedService
end
def validate(oembed)
oembed if oembed[:version].to_s == '1.0' && oembed[:type].present?
oembed if oembed.present? && oembed[:version].to_s == '1.0' && oembed[:type].present?
end
def html

View file

@ -63,13 +63,6 @@ module Mastodon
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
# TODO: Release a version which uses the 7.0 defaults as specified above,
# but preserves the 6.1 cache format as set below. In a subsequent change,
# remove this line setting to 6.1 cache format, and then release another version.
# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format
# https://github.com/mastodon/mastodon/pull/24241#discussion_r1162890242
config.active_support.cache_format_version = 6.1
# Please, add to the `ignore` list any other `lib` subdirectories that do
# not contain `.rb` files, or that should not be reloaded or eager loaded.
# Common ones are `templates`, `generators`, or `middleware`, for example.

View file

@ -1,9 +1,6 @@
# frozen_string_literal: true
# TODO: Remove after 4.2.0
Rails.application.configure do
config.active_support.key_generator_hash_digest_class = OpenSSL::Digest::SHA1
end
# TODO: remove this file some time after 4.3.0
Rails.application.config.after_initialize do
Rails.application.config.action_dispatch.cookies_rotations.tap do |cookies|
@ -12,9 +9,8 @@ Rails.application.config.after_initialize do
secret_key_base = Rails.application.secret_key_base
# TODO: Switch to SHA1 after 4.2.0
key_generator = ActiveSupport::KeyGenerator.new(
secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA256
secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA1
)
key_len = ActiveSupport::MessageEncryptor.key_len

View file

@ -6,7 +6,9 @@ hr:
expires_at: Krajnji rok
options: Opcije
user:
agreement: Ugovor o uslugama
email: E-mail adresa
locale: Lokalitet
password: Lozinka
user/account:
username: Korisničko ime
@ -18,3 +20,16 @@ hr:
attributes:
username:
invalid: mora sadržavati samo slova, brojeve i _
reserved: je rezervisano
admin/webhook:
attributes:
url:
invalid: nije validan URL
doorkeeper/application:
attributes:
website:
invalid: nije validan URL
import:
attributes:
data:
malformed: je neispravan

View file

@ -36,7 +36,7 @@ ru:
status:
attributes:
reblog:
taken: поста уже существует
taken: пост уже существует
user:
attributes:
email:

View file

@ -28,7 +28,7 @@ zh-TW:
doorkeeper/application:
attributes:
website:
invalid: 不是有效的 URL
invalid: 不是有效的網址
import:
attributes:
data:

View file

@ -29,7 +29,7 @@ zh-TW:
edit:
title: 編輯應用程式
form:
error: 唉呦!請看看表單以排查錯誤
error: 糟糕!請檢查表單以排查錯誤
help:
native_redirect_uri: 請使用 %{native_redirect_uri} 作本站測試
redirect_uri: 每行輸入一個 URI

View file

@ -534,6 +534,7 @@ en-GB:
total_reported: Reports about them
total_storage: Media attachments
totals_time_period_hint_html: The totals displayed below include data for all time.
unknown_instance: There is currently no record of this domain on this server.
invites:
deactivate_all: Deactivate all
filter:
@ -610,6 +611,7 @@ en-GB:
created_at: Reported
delete_and_resolve: Delete posts
forwarded: Forwarded
forwarded_replies_explanation: This report is from a remote user and about remote content. It has been forwarded to you because the reported content is in reply to one of your users.
forwarded_to: Forwarded to %{domain}
mark_as_resolved: Mark as resolved
mark_as_sensitive: Mark as sensitive
@ -1038,6 +1040,14 @@ en-GB:
hint_html: Just one more thing! We need to confirm you're a human (this is so we can keep the spam out!). Solve the CAPTCHA below and click "Continue".
title: Security check
confirmations:
awaiting_review: Your e-mail address is confirmed! The %{domain} staff is now reviewing your registration. You will receive an e-mail if they approve your account!
awaiting_review_title: Your registration is being reviewed
clicking_this_link: clicking this link
login_link: log in
proceed_to_login_html: You can now proceed to %{login_link}.
redirect_to_app_html: You should have been redirected to the <strong>%{app_name}</strong> app. If that did not happen, try %{clicking_this_link} or manually return to the app.
registration_complete: Your registration on %{domain} is now complete!
welcome_title: Welcome, %{name}!
wrong_email_hint: If that e-mail address is not correct, you can change it in account settings.
delete_account: Delete account
delete_account_html: If you wish to delete your account, you can <a href="%{path}">proceed here</a>. You will be asked for confirmation.
@ -1099,6 +1109,7 @@ en-GB:
functional: Your account is fully operational.
pending: Your application is pending review by our staff. This may take some time. You will receive an e-mail if your application is approved.
redirecting_to: Your account is inactive because it is currently redirecting to %{acct}.
self_destruct: As %{domain} is closing down, you will only get limited access to your account.
view_strikes: View past strikes against your account
too_fast: Form submitted too fast, try again.
use_security_key: Use security key
@ -1356,6 +1367,7 @@ en-GB:
'86400': 1 day
expires_in_prompt: Never
generate: Generate invite link
invalid: This invite is not valid
invited_by: 'You were invited by:'
max_uses:
one: 1 use
@ -1568,6 +1580,9 @@ en-GB:
over_daily_limit: You have exceeded the limit of %{limit} scheduled posts for today
over_total_limit: You have exceeded the limit of %{limit} scheduled posts
too_soon: The scheduled date must be in the future
self_destruct:
lead_html: Unfortunately, <strong>%{domain}</strong> is permanently closing down. If you had an account there, you will not be able to continue using it, but you can still request a backup of your data.
title: This server is closing down
sessions:
activity: Last activity
browser: Browser
@ -1736,6 +1751,7 @@ en-GB:
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: The server-wide usage quota for the translation service has been exceeded.

View file

@ -534,6 +534,7 @@ et:
total_reported: Nende kohta teateid
total_storage: Lisatud meedia
totals_time_period_hint_html: Allpool kuvatud summad sisaldavad andmed kogu aja kohta.
unknown_instance: Hetkel pole selle domeeni jaoks siin serveris kirjet.
invites:
deactivate_all: Peata kõik
filter:
@ -610,6 +611,7 @@ et:
created_at: Teavitatud
delete_and_resolve: Kustuta postitused
forwarded: Edastatud
forwarded_replies_explanation: See aruanne pärineb kaugkasutajalt ja käsitleb kaugsisu. See on edastatud sulle, sest raporteeritud sisu on vastus ühele sinu kasutajale.
forwarded_to: Edastatud %{domain} domeeni
mark_as_resolved: Märgi lahendatuks
mark_as_sensitive: Märgi kui tundlik sisu
@ -832,6 +834,20 @@ et:
system_checks:
database_schema_check:
message_html: On ootel andmebaasi migreerimisi. Rakenduse ootuspäraseks toimimiseks palun käivita need
elasticsearch_health_red:
message_html: Elasticsearch klaster on ebaterve (punane staatus), otsingufunktsioonid ei ole saadaval
elasticsearch_health_yellow:
message_html: Elasticsearch klaster on ebaterve (kollane staatus), võiksid uurida põhjust
elasticsearch_index_mismatch:
message_html: Elasticsearchi indeksite kaardistused on vananenud. Palun käivita <code>tootctl search deploy --only=%{value}</code>
elasticsearch_preset:
action: Vaata dokumentatsiooni
message_html: Elasticsearchi klastris on rohkem kui üks sõlme, kuid Mastodon ei ole nende kasutamiseks konfigureeritud.
elasticsearch_preset_single_node:
action: Vaata dokumentatsiooni
message_html: Elasticsearchi klastris on ainult üks sõlm <code>ES_PRESET</code> peaks olema seatud väärtusele <code>single_node_cluster</code>.
elasticsearch_reset_chewy:
message_html: Elasticsearchi süsteemiindeks on seadistuse muutumise tõttu vananenud. Palun käivita <code>tootctl search deploy --reset-chewy</code> selle uuendamiseks.
elasticsearch_running_check:
message_html: Elasticsearch ei vasta. Kontrolli, kas see töötab või keela täistekstiotsing
elasticsearch_version_check:
@ -1024,6 +1040,14 @@ et:
hint_html: Üks asi veel! Me peame veenduma, et oled inimene (et me saaksime spämmi väljaspoole jätta!). Lahenda allpool olev CAPTCHA ja klõpsa "Jätka".
title: Turvalisuse kontroll
confirmations:
awaiting_review: E-posti aadress on kinnitatud! %{domain} töötajad vaatavad praegu registreeringut läbi. Saad e-kirja, kui nad kiidavad konto heaks!
awaiting_review_title: Su registreeringut vaadatakse läbi
clicking_this_link: klõpsates seda linki
login_link: logi sisse
proceed_to_login_html: Saad nüüd jätkata valikuga %{login_link}.
redirect_to_app_html: Sind oleks pidanud suunatama rakendusse <strong>%{app_name}</strong>. Kui seda ei juhtunud, proovi %{clicking_this_link} või naase käsitsi rakendusse.
registration_complete: Sinu registreering domeenil %{domain} on nüüd valmis!
welcome_title: Tere tulemast, %{name}!
wrong_email_hint: Kui see e-postiaadress pole korrektne, saad seda kontosätetes muuta.
delete_account: Konto kustutamine
delete_account_html: Kui soovid oma konto kustutada, siis <a href="%{path}">jätka siit</a>. Pead kustutamise eraldi kinnitama.
@ -1085,6 +1109,7 @@ et:
functional: Konto on täies mahus kasutatav.
pending: Taotlus ootab ülevaatamist meie personali poolt. See võib võtta mõne aja. Kui taotlus on vastu võetud, saadetakse sulle e-kiri.
redirecting_to: See konto pole aktiivne, sest on suunatud aadressile %{acct}.
self_destruct: Kuna %{domain} on sulgemisel, saad oma kontole vaid piiratud ligipääsu.
view_strikes: Vaata enda eelnevaid juhtumeid
too_fast: Vorm esitatud liiga kiirelt, proovi uuesti.
use_security_key: Kasuta turvavõtit
@ -1342,6 +1367,7 @@ et:
'86400': 1 päev
expires_in_prompt: Mitte kunagi
generate: Loo
invalid: See kutse pole kehtiv
invited_by: 'Sind kutsus:'
max_uses:
one: 1 kasutus
@ -1554,6 +1580,9 @@ et:
over_daily_limit: Lubatud ajastatud postituste arv %{limit} päevas on tänaseks ületatud
over_total_limit: Oled jõudnud ajastatud postituste lubatud maksimumarvuni %{limit}
too_soon: Ajastatud kuupäev peab olema tukevikus
self_destruct:
lead_html: Kahjuks suletakse <strong>%{domain}</strong> lõplikult. Kui sul oli seal konto, ei saa sa seda enam kasutada, kuid siiski võid taotleda oma andmete varukoopiat.
title: See server suletakse
sessions:
activity: Viimane aktiivsus
browser: Veebilehitseja

View file

@ -711,7 +711,7 @@ ja:
delete_and_resolve: 投稿を削除
force_cw: 強制的にCWにする
forwarded: 転送済み
forwarded_replies_explanation: の報告はリモートユーザーからのものであり、またリモートコンテンツに関するものです。報告されたコンテンツがあなたのユーザーの内の一人に対するリプライの中にあるため、あなたに転送されました。
forwarded_replies_explanation: れはリモートユーザーによる、リモートコンテンツについての報告です。問題のコンテンツはあなたのサーバー利用者への返信なので、こちらにも転送されて来ました。
forwarded_to: "%{domain}に転送されました"
mark_as_resolved: 解決済みとしてマーク
mark_as_sensitive: 閲覧注意にする

View file

@ -16,7 +16,7 @@ zh-TW:
acct: 指定要移動至的帳號的「使用者名稱@網域名稱」
account_warning_preset:
text: 您可使用嘟文語法,例如網址、「#」標籤與提及功能
title: 可選。不會向收件者顯示
title: 可選。不會向收件者顯示
admin_account_action:
include_statuses: 使用者可看到導致檢舉或警告的嘟文
send_email_notification: 使用者將收到帳號發生之事情的解釋

View file

@ -656,6 +656,10 @@ sk:
rules_check:
action: Spravuj serverové pravidlá
message_html: Neurčil/a si žiadne serverové pravidlá.
software_version_critical_check:
action: Pozri dostupné aktualizácie
software_version_patch_check:
action: Pozri dostupné aktualizácie
upload_check_privacy_error:
action: Pozri tu pre viac informácií
upload_check_privacy_error_object_storage:

View file

@ -467,7 +467,7 @@ zh-TW:
other: 錯誤嘗試於 %{count} 天。
no_failures_recorded: 報告中沒有錯誤。
title: 可用狀態
warning: 上一次嘗試連線至伺服器失敗
warning: 上一次嘗試連線至伺服器失敗
back_to_all: 所有
back_to_limited: 受限制的
back_to_warning: 警告
@ -876,7 +876,7 @@ zh-TW:
publishers:
no_publisher_selected: 因未選取任何發行者,所以什麼事都沒發生
shared_by_over_week:
other: 上週被 %{count} 使用者分享
other: 上週被 %{count} 使用者分享
title: 熱門連結
usage_comparison: 於今日被 %{today} 人分享,相較於昨日 %{yesterday} 人
not_allowed_to_trend: 不允許登上熱門
@ -1273,7 +1273,7 @@ zh-TW:
other: 選取 %{count} 個符合您搜尋的項目。
today: 今天
validation_errors:
other: 恩...似乎不太對勁耶?請檢查以下 %{count} 項錯誤
other: 恩...似乎發生了點錯誤?請檢查以下 %{count} 項錯誤
imports:
errors:
empty: 空的 CSV 檔案
@ -1796,7 +1796,7 @@ zh-TW:
welcome:
edit_profile_action: 設定個人檔案
edit_profile_step: 您可以設定您的個人檔案,包括上傳大頭貼、變更顯示名稱等等。您也可以選擇於新的跟隨者跟隨前,先對他們進行審核。
explanation: 下面是幾個小幫助,希望它們能幫到您
explanation: 以下是幾個小技巧,希望它們能幫到您
final_action: 開始嘟嘟
final_step: '開始嘟嘟吧!即使您現在沒有跟隨者,其他人仍然能於本站時間軸、主題標籤等地方,看到您的公開嘟文。試著用 #introductions 這個主題標籤介紹一下自己吧。'
full_handle: 您的完整帳號名稱
@ -1805,7 +1805,7 @@ zh-TW:
title: "%{name} 誠摯歡迎您的加入!"
users:
follow_limit_reached: 您無法跟隨多於 %{limit} 個人
go_to_sso_account_settings: 前往您的身分提供商 (identity provider) 之帳號設定
go_to_sso_account_settings: 前往您的身分識別提供者IdP之帳號設定
invalid_otp_token: 兩階段認證碼不正確
otp_lost_help_html: 如果您無法存取這兩者,您可以透過 %{email} 與我們聯繫
seamless_external_login: 由於您是由外部系統登入,所以不能設定密碼與電子郵件。

View file

@ -185,15 +185,15 @@ module Mastodon::CLI
end
def schema_has_instances_view?
ActiveRecord::Migrator.current_version >= 2020_12_06_004238
migrator_version >= 2020_12_06_004238
end
def verify_schema_version!
if ActiveRecord::Migrator.current_version < MIN_SUPPORTED_VERSION
if migrator_version < MIN_SUPPORTED_VERSION
say 'Your version of the database schema is too old and is not supported by this script.', :red
say 'Please update to at least Mastodon 3.0.0 before running this script.', :red
exit(1)
elsif ActiveRecord::Migrator.current_version > MAX_SUPPORTED_VERSION
elsif migrator_version > MAX_SUPPORTED_VERSION
say 'Your version of the database schema is more recent than this script, this may cause unexpected errors.', :yellow
exit(1) unless yes?('Continue anyway? (Yes/No)')
end
@ -228,7 +228,7 @@ module Mastodon::CLI
end
say 'Restoring index_accounts_on_username_and_domain_lower…'
if ActiveRecord::Migrator.current_version < 2020_06_20_164023
if migrator_version < 2020_06_20_164023
ActiveRecord::Base.connection.add_index :accounts, 'lower (username), lower(domain)', name: 'index_accounts_on_username_and_domain_lower', unique: true
else
ActiveRecord::Base.connection.add_index :accounts, "lower (username), COALESCE(lower(domain), '')", name: 'index_accounts_on_username_and_domain_lower', unique: true
@ -238,7 +238,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
ActiveRecord::Base.connection.execute('REINDEX INDEX index_accounts_on_domain_and_id;') if migrator_version >= 2023_05_24_190515
end
def deduplicate_users!
@ -269,15 +269,15 @@ module Mastodon::CLI
say 'Restoring users indexes…'
ActiveRecord::Base.connection.add_index :users, ['confirmation_token'], name: 'index_users_on_confirmation_token', unique: true
ActiveRecord::Base.connection.add_index :users, ['email'], name: 'index_users_on_email', unique: true
ActiveRecord::Base.connection.add_index :users, ['remember_token'], name: 'index_users_on_remember_token', unique: true if ActiveRecord::Migrator.current_version < 2022_01_18_183010
ActiveRecord::Base.connection.add_index :users, ['remember_token'], name: 'index_users_on_remember_token', unique: true if migrator_version < 2022_01_18_183010
if ActiveRecord::Migrator.current_version < 2022_03_10_060641
if migrator_version < 2022_03_10_060641
ActiveRecord::Base.connection.add_index :users, ['reset_password_token'], name: 'index_users_on_reset_password_token', unique: true
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
ActiveRecord::Base.connection.execute('REINDEX INDEX index_users_on_unconfirmed_email;') if migrator_version >= 2023_07_02_151753
end
def deduplicate_users_process_confirmation_token
@ -292,7 +292,7 @@ module Mastodon::CLI
end
def deduplicate_users_process_remember_token
if ActiveRecord::Migrator.current_version < 2022_01_18_183010
if migrator_version < 2022_01_18_183010
ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users WHERE remember_token IS NOT NULL GROUP BY remember_token HAVING count(*) > 1").each do |row|
users = User.where(id: row['ids'].split(',')).sort_by(&:updated_at).reverse.drop(1)
say "Unsetting remember token for those accounts: #{users.map { |user| user.account.acct }.join(', ')}", :yellow
@ -371,7 +371,7 @@ module Mastodon::CLI
end
say 'Restoring conversations indexes…'
if ActiveRecord::Migrator.current_version < 2022_03_07_083603
if migrator_version < 2022_03_07_083603
ActiveRecord::Base.connection.add_index :conversations, ['uri'], name: 'index_conversations_on_uri', unique: true
else
ActiveRecord::Base.connection.add_index :conversations, ['uri'], name: 'index_conversations_on_uri', unique: true, where: 'uri IS NOT NULL', opclass: :text_pattern_ops
@ -488,7 +488,7 @@ module Mastodon::CLI
end
say 'Restoring media_attachments indexes…'
if ActiveRecord::Migrator.current_version < 2022_03_10_060626
if migrator_version < 2022_03_10_060626
ActiveRecord::Base.connection.add_index :media_attachments, ['shortcode'], name: 'index_media_attachments_on_shortcode', unique: true
else
ActiveRecord::Base.connection.add_index :media_attachments, ['shortcode'], name: 'index_media_attachments_on_shortcode', unique: true, where: 'shortcode IS NOT NULL', opclass: :text_pattern_ops
@ -521,7 +521,7 @@ module Mastodon::CLI
end
say 'Restoring statuses indexes…'
if ActiveRecord::Migrator.current_version < 2022_03_10_060706
if migrator_version < 2022_03_10_060706
ActiveRecord::Base.connection.add_index :statuses, ['uri'], name: 'index_statuses_on_uri', unique: true
else
ActiveRecord::Base.connection.add_index :statuses, ['uri'], name: 'index_statuses_on_uri', unique: true, where: 'uri IS NOT NULL', opclass: :text_pattern_ops
@ -543,7 +543,7 @@ module Mastodon::CLI
end
say 'Restoring tags indexes…'
if ActiveRecord::Migrator.current_version < 2021_04_21_121431
if migrator_version < 2021_04_21_121431
ActiveRecord::Base.connection.add_index :tags, 'lower((name)::text)', name: 'index_tags_on_name_lower', unique: true
else
ActiveRecord::Base.connection.execute 'CREATE UNIQUE INDEX CONCURRENTLY index_tags_on_name_lower_btree ON tags (lower(name) text_pattern_ops)'
@ -707,12 +707,16 @@ module Mastodon::CLI
end
end
def migrator_version
ActiveRecord::Migrator.current_version
end
def find_duplicate_accounts
ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM accounts GROUP BY lower(username), COALESCE(lower(domain), '') HAVING count(*) > 1")
end
def remove_index_if_exists!(table, name)
ActiveRecord::Base.connection.remove_index(table, name: name)
ActiveRecord::Base.connection.remove_index(table, name: name) if ActiveRecord::Base.connection.index_name_exists?(table, name)
rescue ArgumentError, ActiveRecord::StatementInvalid
nil
end

View file

@ -45,7 +45,13 @@ module Mastodon::CLI
pool = Concurrent::FixedThreadPool.new(options[:concurrency], max_queue: options[:concurrency] * 10)
importers = indices.index_with { |index| "Importer::#{index.name}Importer".constantize.new(batch_size: options[:batch_size], executor: pool, full: options[:full], from: options[:from], to: options[:to]) }
progress = ProgressBar.create(total: nil, format: '%t%c/%u |%b%i| %e (%r docs/s)', autofinish: false)
progress = ProgressBar.create(
{
total: nil,
format: '%t%c/%u |%b%i| %e (%r docs/s)',
autofinish: false,
}.merge(progress_output_options)
)
Chewy::Stash::Specification.reset! if options[:reset_chewy]
@ -119,5 +125,9 @@ module Mastodon::CLI
say('Cannot run with this batch_size setting, must be at least 1', :red)
exit(1)
end
def progress_output_options
Rails.env.test? ? { output: ProgressBar::Outputs::Null } : {}
end
end
end

View file

@ -207,7 +207,7 @@
"prettier": "^3.0.0",
"react-test-renderer": "^18.2.0",
"stylelint": "^15.10.1",
"stylelint-config-standard-scss": "^11.0.0",
"stylelint-config-standard-scss": "^12.0.0",
"typescript": "^5.0.4",
"webpack-dev-server": "^3.11.3",
"yargs": "^17.7.2"

View file

@ -1,23 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V1::Accounts::IdentityProofsController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
let(:account) { Fabricate(:account) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
it 'returns http success' do
get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200)
end
end
end

View file

@ -1,25 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V1::Accounts::ListsController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:lists') }
let(:account) { Fabricate(:account) }
let(:list) { Fabricate(:list, account: user.account) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
user.account.follow!(account)
list.accounts << account
end
describe 'GET #index' do
it 'returns http success' do
get :index, params: { account_id: account.id }
expect(response).to have_http_status(200)
end
end
end

View file

@ -1,23 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V1::Accounts::LookupController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
let(:account) { Fabricate(:account) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #show' do
it 'returns http success' do
get :show, params: { account_id: account.id, acct: account.acct }
expect(response).to have_http_status(200)
end
end
end

View file

@ -1,40 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::V1::Accounts::PinsController do
let(:john) { Fabricate(:user) }
let(:kevin) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: john.id, scopes: 'write:accounts') }
before do
kevin.account.followers << john.account
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'POST #create' do
subject { post :create, params: { account_id: kevin.account.id } }
it 'creates account_pin', :aggregate_failures do
expect do
subject
end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(1)
expect(response).to have_http_status(200)
end
end
describe 'DELETE #destroy' do
subject { delete :destroy, params: { account_id: kevin.account.id } }
before do
Fabricate(:account_pin, account: john.account, target_account: kevin.account)
end
it 'destroys account_pin', :aggregate_failures do
expect do
subject
end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(-1)
expect(response).to have_http_status(200)
end
end
end

View file

@ -1,22 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Api::V1::Accounts::SearchController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #show' do
it 'returns http success' do
get :show, params: { q: 'query' }
expect(response).to have_http_status(200)
end
end
end

View file

@ -1,23 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V1::FeaturedTags::SuggestionsController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
let(:account) { Fabricate(:account) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
it 'returns http success' do
get :index, params: { account_id: account.id, limit: 2 }
expect(response).to have_http_status(200)
end
end
end

View file

@ -1,22 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe Api::V2::SuggestionsController do
render_views
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
it 'returns http success' do
get :index
expect(response).to have_http_status(200)
end
end
end

View file

@ -34,23 +34,21 @@ describe Mastodon::CLI::Accounts do
let(:action) { :create }
shared_examples 'a new user with given email address and username' do
it 'creates a new user with the specified email address' do
subject
expect(User.find_by(email: options[:email])).to be_present
end
it 'creates a new local account with the specified username' do
subject
expect(Account.find_local('tootctl_username')).to be_present
end
it 'returns "OK" and newly generated password' do
it 'creates user and accounts from options and displays success message' do
allow(SecureRandom).to receive(:hex).and_return('test_password')
expect { subject }
.to output_results("OK\nNew password: test_password")
.to output_results('OK', 'New password: test_password')
expect(user_from_options).to be_present
expect(account_from_options).to be_present
end
def user_from_options
User.find_by(email: options[:email])
end
def account_from_options
Account.find_local('tootctl_username')
end
end
@ -79,7 +77,8 @@ describe Mastodon::CLI::Accounts do
it_behaves_like 'a new user with given email address and username'
it 'creates a new user with confirmed status' do
subject
expect { subject }
.to output_results('New password')
user = User.find_by(email: options[:email])
@ -97,7 +96,8 @@ describe Mastodon::CLI::Accounts do
it_behaves_like 'a new user with given email address and username'
it 'creates a new user with approved status' do
subject
expect { subject }
.to output_results('New password')
user = User.find_by(email: options[:email])
@ -113,7 +113,8 @@ describe Mastodon::CLI::Accounts do
it_behaves_like 'a new user with given email address and username'
it 'creates a new user and assigns the specified role' do
subject
expect { subject }
.to output_results('New password')
role = User.find_by(email: options[:email])&.role
@ -150,7 +151,8 @@ describe Mastodon::CLI::Accounts do
let(:options) { { email: 'tootctl_new@example.com', reattach: true, force: true } }
it 'reattaches the account to the new user and deletes the previous user' do
subject
expect { subject }
.to output_results('New password')
user = Account.find_local('tootctl_username')&.user
@ -199,14 +201,9 @@ describe Mastodon::CLI::Accounts do
let(:arguments) { [user.account.username] }
context 'when no option is provided' do
it 'returns a successful message' do
it 'returns a successful message and preserves user' do
expect { subject }
.to output_results('OK')
end
it 'does not modify the user' do
subject
expect(user).to eq(user.reload)
end
end
@ -227,7 +224,8 @@ describe Mastodon::CLI::Accounts do
let(:options) { { role: default_role.name } }
it "updates the user's role to the specified role" do
subject
expect { subject }
.to output_results('OK')
role = user.reload.role
@ -242,7 +240,8 @@ describe Mastodon::CLI::Accounts do
let(:user) { Fabricate(:user, role: role) }
it "removes the user's role successfully" do
subject
expect { subject }
.to output_results('OK')
role = user.reload.role
@ -255,13 +254,15 @@ describe Mastodon::CLI::Accounts do
let(:options) { { email: 'new_email@email.com' } }
it "sets the user's unconfirmed email to the provided email address" do
subject
expect { subject }
.to output_results('OK')
expect(user.reload.unconfirmed_email).to eq(options[:email])
end
it "does not update the user's original email address" do
subject
expect { subject }
.to output_results('OK')
expect(user.reload.email).to eq('old_email@email.com')
end
@ -271,13 +272,15 @@ describe Mastodon::CLI::Accounts do
let(:options) { { email: 'new_email@email.com', confirm: true } }
it "updates the user's email address to the provided email" do
subject
expect { subject }
.to output_results('OK')
expect(user.reload.email).to eq(options[:email])
end
it "sets the user's email address as confirmed" do
subject
expect { subject }
.to output_results('OK')
expect(user.reload.confirmed?).to be(true)
end
@ -289,7 +292,8 @@ describe Mastodon::CLI::Accounts do
let(:options) { { confirm: true } }
it "confirms the user's email address" do
subject
expect { subject }
.to output_results('OK')
expect(user.reload.confirmed?).to be(true)
end
@ -304,7 +308,9 @@ describe Mastodon::CLI::Accounts do
end
it 'approves the user' do
expect { subject }.to change { user.reload.approved }.from(false).to(true)
expect { subject }
.to output_results('OK')
.and change { user.reload.approved }.from(false).to(true)
end
end
@ -313,7 +319,9 @@ describe Mastodon::CLI::Accounts do
let(:options) { { disable: true } }
it 'disables the user' do
expect { subject }.to change { user.reload.disabled }.from(false).to(true)
expect { subject }
.to output_results('OK')
.and change { user.reload.disabled }.from(false).to(true)
end
end
@ -322,7 +330,9 @@ describe Mastodon::CLI::Accounts do
let(:options) { { enable: true } }
it 'enables the user' do
expect { subject }.to change { user.reload.disabled }.from(true).to(false)
expect { subject }
.to output_results('OK')
.and change { user.reload.disabled }.from(true).to(false)
end
end
@ -342,7 +352,9 @@ describe Mastodon::CLI::Accounts do
let(:options) { { disable_2fa: true } }
it 'disables the two-factor authentication for the user' do
expect { subject }.to change { user.reload.otp_required_for_login }.from(true).to(false)
expect { subject }
.to output_results('OK')
.and change { user.reload.otp_required_for_login }.from(true).to(false)
end
end
@ -392,7 +404,8 @@ describe Mastodon::CLI::Accounts do
let(:arguments) { [account.username] }
it 'deletes the specified user successfully' do
subject
expect { subject }
.to output_results('Deleting')
expect(delete_account_service).to have_received(:call).with(account, reserve_email: false).once
end
@ -400,15 +413,10 @@ describe Mastodon::CLI::Accounts do
context 'with --dry-run option' do
let(:options) { { dry_run: true } }
it 'does not delete the specified user' do
subject
expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false)
end
it 'outputs a successful message in dry run mode' do
it 'outputs a successful message in dry run mode and does not delete the user' do
expect { subject }
.to output_results('OK (DRY RUN)')
expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false)
end
end
@ -427,7 +435,8 @@ describe Mastodon::CLI::Accounts do
let(:options) { { email: account.user.email } }
it 'deletes the specified user successfully' do
subject
expect { subject }
.to output_results('Deleting')
expect(delete_account_service).to have_received(:call).with(account, reserve_email: false).once
end
@ -435,15 +444,12 @@ describe Mastodon::CLI::Accounts do
context 'with --dry-run option' do
let(:options) { { email: account.user.email, dry_run: true } }
it 'does not delete the user' do
subject
expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false)
end
it 'outputs a successful message in dry run mode' do
it 'outputs a successful message in dry run mode and does not delete the user' do
expect { subject }
.to output_results('OK (DRY RUN)')
expect(delete_account_service)
.to_not have_received(:call)
.with(account, reserve_email: false)
end
end
@ -472,7 +478,8 @@ describe Mastodon::CLI::Accounts do
let(:options) { { all: true } }
it 'approves all pending registrations' do
subject
expect { subject }
.to output_results('OK')
expect(User.pluck(:approved).all?(true)).to be(true)
end
@ -482,20 +489,20 @@ describe Mastodon::CLI::Accounts do
context 'when the number is positive' do
let(:options) { { number: 2 } }
it 'approves the earliest n pending registrations' do
subject
n_earliest_pending_registrations = User.order(created_at: :asc).first(options[:number])
it 'approves the earliest n pending registrations but not the remaining ones' do
expect { subject }
.to output_results('OK')
expect(n_earliest_pending_registrations.all?(&:approved?)).to be(true)
expect(pending_registrations.all?(&:approved?)).to be(false)
end
it 'does not approve the remaining pending registrations' do
subject
def n_earliest_pending_registrations
User.order(created_at: :asc).first(options[:number])
end
pending_registrations = User.order(created_at: :asc).last(total_users - options[:number])
expect(pending_registrations.all?(&:approved?)).to be(false)
def pending_registrations
User.order(created_at: :asc).last(total_users - options[:number])
end
end
@ -512,15 +519,10 @@ describe Mastodon::CLI::Accounts do
context 'when the given number is greater than the number of users' do
let(:options) { { number: total_users * 2 } }
it 'approves all users' do
subject
expect(User.pluck(:approved).all?(true)).to be(true)
end
it 'does not raise any error' do
it 'approves all users and does not raise any error' do
expect { subject }
.to_not raise_error
.to output_results('OK')
expect(User.pluck(:approved).all?(true)).to be(true)
end
end
end
@ -531,7 +533,8 @@ describe Mastodon::CLI::Accounts do
let(:arguments) { [user.account.username] }
it 'approves the specified user successfully' do
subject
expect { subject }
.to output_results('OK')
expect(user.reload.approved?).to be(true)
end
@ -575,18 +578,13 @@ describe Mastodon::CLI::Accounts do
stub_parallelize_with_progress!
end
it 'makes all local accounts follow the target account' do
subject
it 'displays a successful message and makes all local accounts follow the target account' do
expect { subject }
.to output_results("OK, followed target from #{Account.local.count} accounts")
expect(follow_service).to have_received(:call).with(follower_bob, target_account, any_args).once
expect(follow_service).to have_received(:call).with(follower_rony, target_account, any_args).once
expect(follow_service).to have_received(:call).with(follower_charles, target_account, any_args).once
end
it 'displays a successful message' do
expect { subject }
.to output_results("OK, followed target from #{Account.local.count} accounts")
end
end
end
@ -618,18 +616,13 @@ describe Mastodon::CLI::Accounts do
stub_parallelize_with_progress!
end
it 'makes all local accounts unfollow the target account' do
subject
it 'displays a successful message and makes all local accounts unfollow the target account' do
expect { subject }
.to output_results('OK, unfollowed target from 3 accounts')
expect(unfollow_service).to have_received(:call).with(follower_chris, target_account).once
expect(unfollow_service).to have_received(:call).with(follower_rambo, target_account).once
expect(unfollow_service).to have_received(:call).with(follower_ana, target_account).once
end
it 'displays a successful message' do
expect { subject }
.to output_results('OK, unfollowed target from 3 accounts')
end
end
end
@ -651,22 +644,17 @@ describe Mastodon::CLI::Accounts do
let(:user) { account.user }
let(:arguments) { [account.username] }
it 'creates a new backup for the specified user' do
expect { subject }.to change { user.backups.count }.by(1)
end
it 'creates a backup job' do
allow(BackupWorker).to receive(:perform_async)
subject
latest_backup = user.backups.last
before { allow(BackupWorker).to receive(:perform_async) }
it 'creates a new backup and backup job for the specified user and outputs success message' do
expect { subject }
.to change { user.backups.count }.by(1)
.and output_results('OK')
expect(BackupWorker).to have_received(:perform_async).with(latest_backup.id).once
end
it 'displays a successful message' do
expect { subject }
.to output_results('OK')
def latest_backup
user.backups.last
end
end
end
@ -691,7 +679,8 @@ describe Mastodon::CLI::Accounts do
allow(remote_account_example_com).to receive(:reset_avatar!)
allow(account_example_net).to receive(:reset_avatar!)
cli.refresh
expect { cli.refresh }
.to output_results('Refreshed 2 accounts')
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(remote_account_example_com).to have_received(:reset_avatar!).once
@ -701,7 +690,8 @@ describe Mastodon::CLI::Accounts do
it 'does not refresh avatar for local accounts' do
allow(local_account).to receive(:reset_avatar!)
cli.refresh
expect { cli.refresh }
.to output_results('Refreshed 2 accounts')
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(local_account).to_not have_received(:reset_avatar!)
@ -711,7 +701,8 @@ describe Mastodon::CLI::Accounts do
allow(remote_account_example_com).to receive(:reset_header!)
allow(account_example_net).to receive(:reset_header!)
cli.refresh
expect { cli.refresh }
.to output_results('Refreshed 2 accounts')
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(remote_account_example_com).to have_received(:reset_header!).once
@ -721,7 +712,8 @@ describe Mastodon::CLI::Accounts do
it 'does not refresh the header for local accounts' do
allow(local_account).to receive(:reset_header!)
cli.refresh
expect { cli.refresh }
.to output_results('Refreshed 2 accounts')
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(local_account).to_not have_received(:reset_header!)
@ -742,7 +734,8 @@ describe Mastodon::CLI::Accounts do
allow(remote_account_example_com).to receive(:reset_avatar!)
allow(account_example_net).to receive(:reset_avatar!)
cli.refresh
expect { cli.refresh }
.to output_results('Refreshed 2 accounts')
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(local_account).to_not have_received(:reset_avatar!)
@ -755,7 +748,8 @@ describe Mastodon::CLI::Accounts do
allow(remote_account_example_com).to receive(:reset_header!)
allow(account_example_net).to receive(:reset_header!)
cli.refresh
expect { cli.refresh }
.to output_results('Refreshed 2 accounts')
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(local_account).to_not have_received(:reset_header!)
@ -788,7 +782,8 @@ describe Mastodon::CLI::Accounts do
allow(account_example_com_a).to receive(:reset_avatar!)
allow(account_example_com_b).to receive(:reset_avatar!)
cli.refresh(*arguments)
expect { cli.refresh(*arguments) }
.to output_results('OK')
expect(account_example_com_a).to have_received(:reset_avatar!).once
expect(account_example_com_b).to have_received(:reset_avatar!).once
@ -797,7 +792,8 @@ describe Mastodon::CLI::Accounts do
it 'does not reset the avatar for unspecified accounts' do
allow(account_example_net).to receive(:reset_avatar!)
cli.refresh(*arguments)
expect { cli.refresh(*arguments) }
.to output_results('OK')
expect(account_example_net).to_not have_received(:reset_avatar!)
end
@ -806,7 +802,8 @@ describe Mastodon::CLI::Accounts do
allow(account_example_com_a).to receive(:reset_header!)
allow(account_example_com_b).to receive(:reset_header!)
cli.refresh(*arguments)
expect { cli.refresh(*arguments) }
.to output_results('OK')
expect(account_example_com_a).to have_received(:reset_header!).once
expect(account_example_com_b).to have_received(:reset_header!).once
@ -815,7 +812,8 @@ describe Mastodon::CLI::Accounts do
it 'does not reset the header for unspecified accounts' do
allow(account_example_net).to receive(:reset_header!)
cli.refresh(*arguments)
expect { cli.refresh(*arguments) }
.to output_results('OK')
expect(account_example_net).to_not have_received(:reset_header!)
end
@ -848,7 +846,8 @@ describe Mastodon::CLI::Accounts do
allow(account_example_com_a).to receive(:reset_avatar!)
allow(account_example_com_b).to receive(:reset_avatar!)
cli.refresh(*arguments)
expect { cli.refresh(*arguments) }
.to output_results('OK (DRY RUN)')
expect(account_example_com_a).to_not have_received(:reset_avatar!)
expect(account_example_com_b).to_not have_received(:reset_avatar!)
@ -858,7 +857,8 @@ describe Mastodon::CLI::Accounts do
allow(account_example_com_a).to receive(:reset_header!)
allow(account_example_com_b).to receive(:reset_header!)
cli.refresh(*arguments)
expect { cli.refresh(*arguments) }
.to output_results('OK (DRY RUN)')
expect(account_example_com_a).to_not have_received(:reset_header!)
expect(account_example_com_b).to_not have_received(:reset_header!)
@ -884,7 +884,8 @@ describe Mastodon::CLI::Accounts do
allow(account_example_com_a).to receive(:reset_avatar!)
allow(account_example_com_b).to receive(:reset_avatar!)
cli.refresh
expect { cli.refresh }
.to output_results('Refreshed 2 accounts')
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(account_example_com_a).to have_received(:reset_avatar!).once
@ -894,7 +895,8 @@ describe Mastodon::CLI::Accounts do
it 'does not refresh the avatar for accounts outside specified domain' do
allow(account_example_net).to receive(:reset_avatar!)
cli.refresh
expect { cli.refresh }
.to output_results('Refreshed 2 accounts')
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(account_example_net).to_not have_received(:reset_avatar!)
@ -904,7 +906,8 @@ describe Mastodon::CLI::Accounts do
allow(account_example_com_a).to receive(:reset_header!)
allow(account_example_com_b).to receive(:reset_header!)
cli.refresh
expect { cli.refresh }
.to output_results('Refreshed 2 accounts')
expect(cli).to have_received(:parallelize_with_progress).with(scope)
expect(account_example_com_a).to have_received(:reset_header!).once
@ -914,7 +917,8 @@ describe Mastodon::CLI::Accounts do
it 'does not refresh the header for accounts outside specified domain' do
allow(account_example_net).to receive(:reset_header!)
cli.refresh
expect { cli.refresh }
.to output_results('Refreshed 2 accounts')
expect(cli).to have_received(:parallelize_with_progress).with(scope).once
expect(account_example_net).to_not have_received(:reset_header!)
@ -949,7 +953,8 @@ describe Mastodon::CLI::Accounts do
old_private_key = account.private_key
old_public_key = account.public_key
subject
expect { subject }
.to output_results('OK')
account.reload
expect(account.private_key).to_not eq(old_private_key)
@ -959,10 +964,12 @@ describe Mastodon::CLI::Accounts do
it 'broadcasts the new keys for the specified account' do
allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_in)
subject
expect { subject }
.to output_results('OK')
expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_in).with(anything, account.id, anything).once
end
end
context 'when the given username is not found' do
let(:arguments) { ['non_existent_username'] }
@ -973,7 +980,6 @@ describe Mastodon::CLI::Accounts do
.and raise_error(SystemExit)
end
end
end
context 'when --all option is provided' do
let!(:accounts) { Fabricate.times(2, :account) }
@ -983,7 +989,8 @@ describe Mastodon::CLI::Accounts do
old_private_keys = accounts.map(&:private_key)
old_public_keys = accounts.map(&:public_key)
subject
expect { subject }
.to output_results('rotated')
accounts.each(&:reload)
expect(accounts.map(&:private_key)).to_not eq(old_private_keys)
@ -993,7 +1000,8 @@ describe Mastodon::CLI::Accounts do
it 'broadcasts the new keys for each account' do
allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_in)
subject
expect { subject }
.to output_results('rotated')
accounts.each do |account|
expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_in).with(anything, account.id, anything).once
@ -1071,15 +1079,11 @@ describe Mastodon::CLI::Accounts do
allow(from_account).to receive(:destroy)
end
it 'merges "from_account" into "to_account"' do
subject
it 'merges `from_account` into `to_account` and deletes `from_account`' do
expect { subject }
.to output_results('OK')
expect(to_account).to have_received(:merge_with!).with(from_account).once
end
it 'deletes "from_account"' do
subject
expect(from_account).to have_received(:destroy).once
end
end
@ -1099,15 +1103,11 @@ describe Mastodon::CLI::Accounts do
allow(from_account).to receive(:destroy)
end
it 'merges "from_account" into "to_account"' do
subject
it 'merges "from_account" into "to_account" and deletes from_account' do
expect { subject }
.to output_results('OK')
expect(to_account).to have_received(:merge_with!).with(from_account).once
end
it 'deletes "from_account"' do
subject
expect(from_account).to have_received(:destroy)
end
end
@ -1134,28 +1134,23 @@ describe Mastodon::CLI::Accounts do
stub_request(:head, 'https://example.net/users/tales').to_return(status: 200)
end
it 'deletes all inactive remote accounts that longer exist in the origin server' do
subject
def expect_delete_inactive_remote_accounts
expect(delete_account_service).to have_received(:call).with(bob, reserve_username: false).once
expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once
end
it 'does not delete any active remote account that still exists in the origin server' do
subject
def expect_not_delete_active_accounts
expect(delete_account_service).to_not have_received(:call).with(tom, reserve_username: false)
expect(delete_account_service).to_not have_received(:call).with(ana, reserve_username: false)
expect(delete_account_service).to_not have_received(:call).with(tales, reserve_username: false)
end
it 'touches inactive remote accounts that have not been deleted' do
expect { subject }.to(change { tales.reload.updated_at })
end
it 'displays the summary correctly' do
it 'touches inactive remote accounts that have not been deleted and summarizes activity' do
expect { subject }
.to output_results('Visited 5 accounts, removed 2')
.to change { tales.reload.updated_at }
.and output_results('Visited 5 accounts, removed 2')
expect_delete_inactive_remote_accounts
expect_not_delete_active_accounts
end
end
@ -1168,16 +1163,15 @@ describe Mastodon::CLI::Accounts do
stub_request(:head, 'https://example.net/users/tales').to_return(status: 404)
end
it 'deletes inactive remote accounts that longer exist in the specified domain' do
subject
def expect_delete_inactive_remote_accounts
expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once
expect(delete_account_service).to have_received(:call).with(tales, reserve_username: false).once
end
it 'displays the summary correctly' do
it 'displays the summary correctly and deletes inactive remote accounts' do
expect { subject }
.to output_results('Visited 2 accounts, removed 2')
expect_delete_inactive_remote_accounts
end
end
@ -1189,15 +1183,14 @@ describe Mastodon::CLI::Accounts do
stub_request(:head, 'https://example.net/users/gon').to_return(status: 200)
end
it 'skips accounts from the unavailable domain' do
subject
def expect_skip_accounts_from_unavailable_domain
expect(delete_account_service).to_not have_received(:call).with(tales, reserve_username: false)
end
it 'displays the summary correctly' do
it 'displays the summary correctly and skip accounts from unavailable domains' do
expect { subject }
.to output_results("Visited 5 accounts, removed 0\nThe following domains were not available during the check:\n example.net")
expect_skip_accounts_from_unavailable_domain
end
end
@ -1268,25 +1261,14 @@ describe Mastodon::CLI::Accounts do
before do
accounts.each { |account| target_account.follow!(account) }
end
it 'resets all "following" relationships from the target account' do
subject
expect(target_account.reload.following).to be_empty
end
it 'calls BootstrapTimelineWorker once to rebuild the timeline' do
allow(BootstrapTimelineWorker).to receive(:perform_async)
subject
expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once
end
it 'displays a successful message' do
it 'resets following relationships and displays a successful message and rebuilds timeline' do
expect { subject }
.to output_results("Processed #{total_relationships} relationships")
expect(target_account.reload.following).to be_empty
expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once
end
end
@ -1297,15 +1279,10 @@ describe Mastodon::CLI::Accounts do
accounts.each { |account| account.follow!(target_account) }
end
it 'resets all "followers" relationships from the target account' do
subject
expect(target_account.reload.followers).to be_empty
end
it 'displays a successful message' do
it 'resets followers relationships and displays a successful message' do
expect { subject }
.to output_results("Processed #{total_relationships} relationships")
expect(target_account.reload.followers).to be_empty
end
end
@ -1315,31 +1292,15 @@ describe Mastodon::CLI::Accounts do
before do
accounts.first(2).each { |account| account.follow!(target_account) }
accounts.last(1).each { |account| target_account.follow!(account) }
end
it 'resets all "followers" relationships from the target account' do
subject
expect(target_account.reload.followers).to be_empty
end
it 'resets all "following" relationships from the target account' do
subject
expect(target_account.reload.following).to be_empty
end
it 'calls BootstrapTimelineWorker once to rebuild the timeline' do
allow(BootstrapTimelineWorker).to receive(:perform_async)
subject
expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once
end
it 'displays a successful message' do
it 'resets followers and following and displays a successful message and rebuilds timeline' do
expect { subject }
.to output_results("Processed #{total_relationships} relationships")
expect(target_account.reload.followers).to be_empty
expect(target_account.reload.following).to be_empty
expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once
end
end
end
@ -1360,57 +1321,51 @@ describe Mastodon::CLI::Accounts do
stub_parallelize_with_progress!
end
it 'prunes all remote accounts with no interactions with local users' do
subject
def expect_prune_remote_accounts_without_interaction
prunable_account_ids = prunable_accounts.pluck(:id)
expect(Account.where(id: prunable_account_ids).count).to eq(0)
end
it 'displays a successful message' do
it 'displays a successful message and handles accounts correctly' do
expect { subject }
.to output_results("OK, pruned #{prunable_accounts.size} accounts")
expect_prune_remote_accounts_without_interaction
expect_not_prune_local_accounts
expect_not_prune_bot_accounts
expect_not_prune_group_accounts
expect_not_prune_mentioned_accounts
end
it 'does not prune local accounts' do
subject
def expect_not_prune_local_accounts
expect(Account.exists?(id: local_account.id)).to be(true)
end
it 'does not prune bot accounts' do
subject
def expect_not_prune_bot_accounts
expect(Account.exists?(id: bot_account.id)).to be(true)
end
it 'does not prune group accounts' do
subject
def expect_not_prune_group_accounts
expect(Account.exists?(id: group_account.id)).to be(true)
end
it 'does not prune accounts that have been mentioned' do
subject
def expect_not_prune_mentioned_accounts
expect(Account.exists?(id: mentioned_account.id)).to be true
end
context 'with --dry-run option' do
let(:options) { { dry_run: true } }
it 'does not prune any account' do
subject
def expect_no_account_prunes
prunable_account_ids = prunable_accounts.pluck(:id)
expect(Account.where(id: prunable_account_ids).count).to eq(prunable_accounts.size)
end
it 'displays a successful message with (DRY RUN)' do
it 'displays a successful message with (DRY RUN) and doesnt prune anything' do
expect { subject }
.to output_results("OK, pruned #{prunable_accounts.size} accounts (DRY RUN)")
expect_no_account_prunes
end
end
end
@ -1430,7 +1385,8 @@ describe Mastodon::CLI::Accounts do
shared_examples 'a successful migration' do
it 'calls the MoveService for the last migration' do
subject
expect { subject }
.to output_results('OK')
last_migration = source_account.migrations.last
@ -1540,7 +1496,8 @@ describe Mastodon::CLI::Accounts do
end
it 'creates a migration for the specified account with the target account' do
subject
expect { subject }
.to output_results('migrated')
last_migration = source_account.migrations.last

View file

@ -33,26 +33,25 @@ describe Mastodon::CLI::IpBlocks do
let(:arguments) { ip_list }
shared_examples 'ip address blocking' do
it 'blocks all specified IP addresses' do
subject
blocked_ip_addresses = IpBlock.where(ip: ip_list).pluck(:ip)
expected_ip_addresses = ip_list.map { |ip| IPAddr.new(ip) }
expect(blocked_ip_addresses).to match_array(expected_ip_addresses)
def blocked_ip_addresses
IpBlock.where(ip: ip_list).pluck(:ip)
end
it 'sets the severity for all blocked IP addresses' do
subject
blocked_ips_severity = IpBlock.where(ip: ip_list).pluck(:severity).all?(options[:severity])
expect(blocked_ips_severity).to be(true)
def expected_ip_addresses
ip_list.map { |ip| IPAddr.new(ip) }
end
it 'displays a success message with a summary' do
def blocked_ips_severity
IpBlock.where(ip: ip_list).pluck(:severity).all?(options[:severity])
end
it 'blocks and sets severity for ip address and displays summary' do
expect { subject }
.to output_results("Added #{ip_list.size}, skipped 0, failed 0")
expect(blocked_ip_addresses)
.to match_array(expected_ip_addresses)
expect(blocked_ips_severity)
.to be(true)
end
end
@ -64,17 +63,13 @@ describe Mastodon::CLI::IpBlocks do
let!(:blocked_ip) { IpBlock.create(ip: ip_list.last, severity: options[:severity]) }
let(:arguments) { ip_list }
it 'skips the already blocked IP address' do
allow(IpBlock).to receive(:new).and_call_original
before { allow(IpBlock).to receive(:new).and_call_original }
subject
expect(IpBlock).to_not have_received(:new).with(ip: ip_list.last)
end
it 'displays the correct summary' do
it 'skips already block ip and displays the correct summary' do
expect { subject }
.to output_results("#{ip_list.last} is already blocked\nAdded #{ip_list.size - 1}, skipped 1, failed 0")
expect(IpBlock).to_not have_received(:new).with(ip: ip_list.last)
end
context 'with --force option' do
@ -83,7 +78,8 @@ describe Mastodon::CLI::IpBlocks do
it 'overwrites the existing IP block record' do
expect { subject }
.to change { blocked_ip.reload.severity }
.to output_results('Added 11')
.and change { blocked_ip.reload.severity }
.from('no_access')
.to('sign_up_requires_approval')
end
@ -179,15 +175,10 @@ describe Mastodon::CLI::IpBlocks do
ip_list.each { |ip| IpBlock.create(ip: ip, severity: :no_access) }
end
it 'removes exact IP blocks' do
subject
expect(IpBlock.where(ip: ip_list)).to_not exist
end
it 'displays success message with a summary' do
it 'removes exact ip blocks and displays success message with a summary' do
expect { subject }
.to output_results("Removed #{ip_list.size}, skipped 0")
expect(IpBlock.where(ip: ip_list)).to_not exist
end
end
@ -198,16 +189,20 @@ describe Mastodon::CLI::IpBlocks do
let(:arguments) { ['192.168.0.5', '10.0.1.50'] }
let(:options) { { force: true } }
it 'removes blocks for IP ranges that cover given IP(s)' do
subject
it 'removes blocks for IP ranges that cover given IP(s) and keeps other ranges' do
expect { subject }
.to output_results('Removed 2')
expect(IpBlock.where(id: [first_ip_range_block.id, second_ip_range_block.id])).to_not exist
expect(covered_ranges).to_not exist
expect(other_ranges).to exist
end
it 'does not remove other IP ranges' do
subject
def covered_ranges
IpBlock.where(id: [first_ip_range_block.id, second_ip_range_block.id])
end
expect(IpBlock.where(id: third_ip_range_block.id)).to exist
def other_ranges
IpBlock.where(id: third_ip_range_block.id)
end
end
@ -215,14 +210,12 @@ describe Mastodon::CLI::IpBlocks do
let(:unblocked_ip) { '192.0.2.1' }
let(:arguments) { [unblocked_ip] }
it 'skips the IP address' do
it 'skips the IP address and displays summary' do
expect { subject }
.to output_results("#{unblocked_ip} is not yet blocked")
end
it 'displays the summary correctly' do
expect { subject }
.to output_results('Removed 0, skipped 1')
.to output_results(
"#{unblocked_ip} is not yet blocked",
'Removed 0, skipped 1'
)
end
end
@ -230,14 +223,12 @@ describe Mastodon::CLI::IpBlocks do
let(:invalid_ip) { '320.15.175.0' }
let(:arguments) { [invalid_ip] }
it 'skips the invalid IP address' do
it 'skips the invalid IP address and displays summary' do
expect { subject }
.to output_results("#{invalid_ip} is invalid")
end
it 'displays the summary correctly' do
expect { subject }
.to output_results('Removed 0, skipped 1')
.to output_results(
"#{invalid_ip} is invalid",
'Removed 0, skipped 1'
)
end
end
@ -265,7 +256,7 @@ describe Mastodon::CLI::IpBlocks do
.to output_results("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}")
end
it 'does not export bloked IPs with different severities' do
it 'does not export blocked IPs with different severities' do
expect { subject }
.to_not output_results("#{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}")
end
@ -279,7 +270,7 @@ describe Mastodon::CLI::IpBlocks do
.to output_results("deny #{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};\ndeny #{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix};")
end
it 'does not export bloked IPs with different severities' do
it 'does not export blocked IPs with different severities' do
expect { subject }
.to_not output_results("deny #{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};")
end

View file

@ -20,37 +20,30 @@ describe Mastodon::CLI::Settings do
describe '#open' do
let(:action) { :open }
it 'changes "registrations_mode" to "open"' do
expect { subject }.to change(Setting, :registrations_mode).from(nil).to('open')
end
it 'displays success message' do
it 'changes "registrations_mode" to "open" and displays success' do
expect { subject }
.to output_results('OK')
.to change(Setting, :registrations_mode).from(nil).to('open')
.and output_results('OK')
end
end
describe '#approved' do
let(:action) { :approved }
it 'changes "registrations_mode" to "approved"' do
expect { subject }.to change(Setting, :registrations_mode).from(nil).to('approved')
end
it 'displays success message' do
it 'changes "registrations_mode" to "approved" and displays success' do
expect { subject }
.to output_results('OK')
.to change(Setting, :registrations_mode).from(nil).to('approved')
.and output_results('OK')
end
context 'with --require-reason' do
let(:options) { { require_reason: true } }
it 'changes "registrations_mode" to "approved"' do
expect { subject }.to change(Setting, :registrations_mode).from(nil).to('approved')
end
it 'sets "require_invite_text" to "true"' do
expect { subject }.to change(Setting, :require_invite_text).from(false).to(true)
it 'changes registrations_mode and require_invite_text' do
expect { subject }
.to output_results('OK')
.and change(Setting, :registrations_mode).from(nil).to('approved')
.and change(Setting, :require_invite_text).from(false).to(true)
end
end
end
@ -58,13 +51,10 @@ describe Mastodon::CLI::Settings do
describe '#close' do
let(:action) { :close }
it 'changes "registrations_mode" to "none"' do
expect { subject }.to change(Setting, :registrations_mode).from(nil).to('none')
end
it 'displays success message' do
it 'changes "registrations_mode" to "none" and displays success' do
expect { subject }
.to output_results('OK')
.to change(Setting, :registrations_mode).from(nil).to('none')
.and output_results('OK')
end
end
end

View file

@ -104,7 +104,6 @@ RSpec.configure do |config|
end
config.before :each, type: :cli do
stub_stdout
stub_reset_connection_pools
end
@ -163,14 +162,6 @@ def attachment_fixture(name)
Rails.root.join('spec', 'fixtures', 'files', name).open
end
def stub_stdout
# TODO: Is there a bettery way to:
# - Avoid CLI command output being printed out
# - Allow rspec to assert things against STDOUT
# - Avoid disabling stdout for other desirable output (deprecation warnings, for example)
allow($stdout).to receive(:write)
end
def stub_reset_connection_pools
# TODO: Is there a better way to correctly run specs without stubbing this?
# (Avoids reset_connection_pools! in test env)

View file

@ -2,20 +2,16 @@
require 'rails_helper'
describe Api::V1::Accounts::FamiliarFollowersController do
render_views
describe 'Accounts Familiar Followers API' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:follows') }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'read:follows' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:account) { Fabricate(:account) }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'GET #index' do
describe 'GET /api/v1/accounts/familiar_followers' do
it 'returns http success' do
get :index, params: { account_id: account.id, limit: 2 }
get '/api/v1/accounts/familiar_followers', params: { account_id: account.id, limit: 2 }, headers: headers
expect(response).to have_http_status(200)
end
@ -26,7 +22,7 @@ describe Api::V1::Accounts::FamiliarFollowersController do
it 'removes duplicate account IDs from params' do
account_ids = [account_a, account_b, account_b, account_a, account_a].map { |a| a.id.to_s }
get :index, params: { id: account_ids }
get '/api/v1/accounts/familiar_followers', params: { id: account_ids }, headers: headers
expect(body_as_json.pluck(:id)).to contain_exactly(account_a.id.to_s, account_b.id.to_s)
end

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Accounts Identity Proofs API' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'read:accounts' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:account) { Fabricate(:account) }
describe 'GET /api/v1/accounts/identity_proofs' do
it 'returns http success' do
get "/api/v1/accounts/#{account.id}/identity_proofs", params: { limit: 2 }, headers: headers
expect(response).to have_http_status(200)
end
end
end

View file

@ -0,0 +1,25 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Accounts Lists API' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'read:lists' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:account) { Fabricate(:account) }
let(:list) { Fabricate(:list, account: user.account) }
before do
user.account.follow!(account)
list.accounts << account
end
describe 'GET /api/v1/accounts/lists' do
it 'returns http success' do
get "/api/v1/accounts/#{account.id}/lists", headers: headers
expect(response).to have_http_status(200)
end
end
end

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Accounts Lookup API' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'read:accounts' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:account) { Fabricate(:account) }
describe 'GET /api/v1/accounts/lookup' do
it 'returns http success' do
get '/api/v1/accounts/lookup', params: { account_id: account.id, acct: account.acct }, headers: headers
expect(response).to have_http_status(200)
end
end
end

View file

@ -2,21 +2,17 @@
require 'rails_helper'
describe Api::V1::Accounts::NotesController do
render_views
describe 'Accounts Notes API' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:accounts') }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'write:accounts' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:account) { Fabricate(:account) }
let(:comment) { 'foo' }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'POST #create' do
describe 'POST /api/v1/accounts/:account_id/note' do
subject do
post :create, params: { account_id: account.id, comment: comment }
post "/api/v1/accounts/#{account.id}/note", params: { comment: comment }, headers: headers
end
context 'when account note has reasonable length', :aggregate_failures do

View file

@ -0,0 +1,41 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Accounts Pins API' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'write:accounts' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:kevin) { Fabricate(:user) }
before do
kevin.account.followers << user.account
end
describe 'POST /api/v1/accounts/:account_id/pin' do
subject { post "/api/v1/accounts/#{kevin.account.id}/pin", headers: headers }
it 'creates account_pin', :aggregate_failures do
expect do
subject
end.to change { AccountPin.where(account: user.account, target_account: kevin.account).count }.by(1)
expect(response).to have_http_status(200)
end
end
describe 'POST /api/v1/accounts/:account_id/unpin' do
subject { post "/api/v1/accounts/#{kevin.account.id}/unpin", headers: headers }
before do
Fabricate(:account_pin, account: user.account, target_account: kevin.account)
end
it 'destroys account_pin', :aggregate_failures do
expect do
subject
end.to change { AccountPin.where(account: user.account, target_account: kevin.account).count }.by(-1)
expect(response).to have_http_status(200)
end
end
end

View file

@ -31,8 +31,8 @@ describe 'GET /api/v1/accounts/relationships' do
.to have_http_status(200)
expect(body_as_json)
.to be_an(Enumerable)
.and have_attributes(
first: include(
.and contain_exactly(
include(
following: true,
followed_by: false
)
@ -53,9 +53,11 @@ describe 'GET /api/v1/accounts/relationships' do
expect(body_as_json)
.to be_an(Enumerable)
.and have_attributes(
size: 2,
first: include(simon_item),
second: include(lewis_item)
size: 2
)
.and contain_exactly(
include(simon_item),
include(lewis_item)
)
end
end
@ -71,10 +73,12 @@ describe 'GET /api/v1/accounts/relationships' do
expect(body_as_json)
.to be_an(Enumerable)
.and have_attributes(
size: 3,
first: include(simon_item),
second: include(lewis_item),
third: include(bob_item)
size: 3
)
.and contain_exactly(
include(simon_item),
include(lewis_item),
include(bob_item)
)
end
end
@ -88,9 +92,11 @@ describe 'GET /api/v1/accounts/relationships' do
expect(body_as_json)
.to be_an(Enumerable)
.and have_attributes(
size: 2,
first: include(simon_item),
second: include(lewis_item)
size: 2
)
.and contain_exactly(
include(simon_item),
include(lewis_item)
)
end
end
@ -116,7 +122,6 @@ describe 'GET /api/v1/accounts/relationships' do
muting: false,
requested: false,
domain_blocking: false,
}
end
@ -129,7 +134,6 @@ describe 'GET /api/v1/accounts/relationships' do
muting: false,
requested: false,
domain_blocking: false,
}
end
end
@ -149,8 +153,10 @@ describe 'GET /api/v1/accounts/relationships' do
expect(body_as_json)
.to be_an(Enumerable)
.and have_attributes(
size: 1,
first: include(
size: 1
)
.and contain_exactly(
include(
following: true,
showing_reblogs: true
)
@ -168,8 +174,8 @@ describe 'GET /api/v1/accounts/relationships' do
expect(body_as_json)
.to be_an(Enumerable)
.and have_attributes(
first: include(
.and contain_exactly(
include(
following: false,
showing_reblogs: false
)

View file

@ -0,0 +1,18 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Accounts Search API' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'read:accounts' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v1/accounts/search' do
it 'returns http success' do
get '/api/v1/accounts/search', params: { q: 'query' }, headers: headers
expect(response).to have_http_status(200)
end
end
end

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Featured Tags Suggestions API' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'read:accounts' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
let(:account) { Fabricate(:account) }
describe 'GET /api/v1/featured_tags/suggestions' do
it 'returns http success' do
get '/api/v1/featured_tags/suggestions', params: { account_id: account.id, limit: 2 }, headers: headers
expect(response).to have_http_status(200)
end
end
end

View file

@ -0,0 +1,18 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Suggestions API' do
let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:scopes) { 'read' }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
describe 'GET /api/v2/suggestions' do
it 'returns http success' do
get '/api/v2/suggestions', headers: headers
expect(response).to have_http_status(200)
end
end
end

View file

@ -11,13 +11,14 @@ RSpec.describe FanOutOnWriteService, type: :service do
let(:visibility) { 'public' }
let(:searchability) { 'public' }
let(:subscription_policy) { :allow }
let(:status) { Fabricate(:status, account: alice, visibility: visibility, searchability: searchability, text: 'Hello @bob #hoge') }
let(:status) { Fabricate(:status, account: alice, visibility: visibility, searchability: searchability, text: 'Hello @bob @eve #hoge') }
let!(:alice) { Fabricate(:user, current_sign_in_at: last_active_at, account_attributes: { master_settings: { subscription_policy: subscription_policy } }).account }
let!(:bob) { Fabricate(:user, current_sign_in_at: last_active_at, account_attributes: { username: 'bob' }).account }
let!(:tom) { Fabricate(:user, current_sign_in_at: last_active_at).account }
let!(:ohagi) { Fabricate(:user, current_sign_in_at: last_active_at).account }
let!(:tagf) { Fabricate(:user, current_sign_in_at: last_active_at).account }
let!(:eve) { Fabricate(:user, current_sign_in_at: last_active_at, account_attributes: { username: 'eve' }).account }
let!(:list) { nil }
let!(:empty_list) { nil }
@ -256,6 +257,25 @@ RSpec.describe FanOutOnWriteService, type: :service do
end
end
end
context 'when handling status updates', :sidekiq_fake do
before do
subject.call(status)
status.snapshot!(at_time: status.created_at, rate_limit: false)
status.update!(text: 'Hello @bob @eve #hoge (edited)')
status.snapshot!(account_id: status.account_id)
redis.set("subscribed:timeline:#{eve.id}:notifications", '1')
Sidekiq::Worker.clear_all
end
it 'pushes the update to mentioned users through the notifications streaming channel' do
subject.call(status, update: true)
expect(PushUpdateWorker).to have_enqueued_sidekiq_job(anything, status.id, "timeline:#{eve.id}:notifications", { 'update' => true })
end
end
end
context 'when status is limited' do

397
yarn.lock
View file

@ -52,7 +52,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9, @babel/compat-data@npm:^7.23.3, @babel/compat-data@npm:^7.23.5":
"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.3, @babel/compat-data@npm:^7.23.5":
version: 7.23.5
resolution: "@babel/compat-data@npm:7.23.5"
checksum: 081278ed46131a890ad566a59c61600a5f9557bd8ee5e535890c8548192532ea92590742fd74bd9db83d74c669ef8a04a7e1c85cdea27f960233e3b83c3a957c
@ -60,37 +60,37 @@ __metadata:
linkType: hard
"@babel/core@npm:^7.10.4, @babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1":
version: 7.23.5
resolution: "@babel/core@npm:7.23.5"
version: 7.23.6
resolution: "@babel/core@npm:7.23.6"
dependencies:
"@ampproject/remapping": "npm:^2.2.0"
"@babel/code-frame": "npm:^7.23.5"
"@babel/generator": "npm:^7.23.5"
"@babel/helper-compilation-targets": "npm:^7.22.15"
"@babel/generator": "npm:^7.23.6"
"@babel/helper-compilation-targets": "npm:^7.23.6"
"@babel/helper-module-transforms": "npm:^7.23.3"
"@babel/helpers": "npm:^7.23.5"
"@babel/parser": "npm:^7.23.5"
"@babel/helpers": "npm:^7.23.6"
"@babel/parser": "npm:^7.23.6"
"@babel/template": "npm:^7.22.15"
"@babel/traverse": "npm:^7.23.5"
"@babel/types": "npm:^7.23.5"
"@babel/traverse": "npm:^7.23.6"
"@babel/types": "npm:^7.23.6"
convert-source-map: "npm:^2.0.0"
debug: "npm:^4.1.0"
gensync: "npm:^1.0.0-beta.2"
json5: "npm:^2.2.3"
semver: "npm:^6.3.1"
checksum: 311a512a870ee330a3f9a7ea89e5df790b2b5af0b1bd98b10b4edc0de2ac440f0df4d69ea2c0ee38a4b89041b9a495802741d93603be7d4fd834ec8bb6970bd2
checksum: a02bae7d916029b70706dc301535e1b31e5d216f55d4ee6f64a15825c6b69ee2c14c52a213d1497ec414e925ed4e9d897d41fb0d75df9fea28ed2c0008790e31
languageName: node
linkType: hard
"@babel/generator@npm:^7.23.5, @babel/generator@npm:^7.7.2":
version: 7.23.5
resolution: "@babel/generator@npm:7.23.5"
"@babel/generator@npm:^7.23.6, @babel/generator@npm:^7.7.2":
version: 7.23.6
resolution: "@babel/generator@npm:7.23.6"
dependencies:
"@babel/types": "npm:^7.23.5"
"@babel/types": "npm:^7.23.6"
"@jridgewell/gen-mapping": "npm:^0.3.2"
"@jridgewell/trace-mapping": "npm:^0.3.17"
jsesc: "npm:^2.5.1"
checksum: 14c6e874f796c4368e919bed6003bb0adc3ce837760b08f9e646d20aeb5ae7d309723ce6e4f06bcb4a2b5753145446c8e4425851380f695e40e71e1760f49e7b
checksum: 53540e905cd10db05d9aee0a5304e36927f455ce66f95d1253bb8a179f286b88fa7062ea0db354c566fe27f8bb96567566084ffd259f8feaae1de5eccc8afbda
languageName: node
linkType: hard
@ -122,16 +122,16 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-compilation-targets@npm:^7.22.15, @babel/helper-compilation-targets@npm:^7.22.6":
version: 7.22.15
resolution: "@babel/helper-compilation-targets@npm:7.22.15"
"@babel/helper-compilation-targets@npm:^7.22.15, @babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.23.6":
version: 7.23.6
resolution: "@babel/helper-compilation-targets@npm:7.23.6"
dependencies:
"@babel/compat-data": "npm:^7.22.9"
"@babel/helper-validator-option": "npm:^7.22.15"
browserslist: "npm:^4.21.9"
"@babel/compat-data": "npm:^7.23.5"
"@babel/helper-validator-option": "npm:^7.23.5"
browserslist: "npm:^4.22.2"
lru-cache: "npm:^5.1.1"
semver: "npm:^6.3.1"
checksum: 45b9286861296e890f674a3abb199efea14a962a27d9b8adeb44970a9fd5c54e73a9e342e8414d2851cf4f98d5994537352fbce7b05ade32e9849bbd327f9ff1
checksum: ba38506d11185f48b79abf439462ece271d3eead1673dd8814519c8c903c708523428806f05f2ec5efd0c56e4e278698fac967e5a4b5ee842c32415da54bc6fa
languageName: node
linkType: hard
@ -342,14 +342,14 @@ __metadata:
languageName: node
linkType: hard
"@babel/helpers@npm:^7.23.5":
version: 7.23.5
resolution: "@babel/helpers@npm:7.23.5"
"@babel/helpers@npm:^7.23.6":
version: 7.23.6
resolution: "@babel/helpers@npm:7.23.6"
dependencies:
"@babel/template": "npm:^7.22.15"
"@babel/traverse": "npm:^7.23.5"
"@babel/types": "npm:^7.23.5"
checksum: a37e2728eb4378a4888e5d614e28de7dd79b55ac8acbecd0e5c761273e2a02a8f33b34b1932d9069db55417ace2937cbf8ec37c42f1030ce6d228857d7ccaa4f
"@babel/traverse": "npm:^7.23.6"
"@babel/types": "npm:^7.23.6"
checksum: df1cf6607676ad36f52f652ec03536f2732d70aef5e76dba5c964e34d49f3c2d3dcf9fb3740db359f53071d74b64606a833d5ba156f79f437f71bfe06e2e7e19
languageName: node
linkType: hard
@ -364,12 +364,12 @@ __metadata:
languageName: node
linkType: hard
"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.5":
version: 7.23.5
resolution: "@babel/parser@npm:7.23.5"
"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.6":
version: 7.23.6
resolution: "@babel/parser@npm:7.23.6"
bin:
parser: ./bin/babel-parser.js
checksum: 3356aa90d7bafb4e2c7310e7c2c3d443c4be4db74913f088d3d577a1eb914ea4188e05fd50a47ce907a27b755c4400c4e3cbeee73dbeb37761f6ca85954f5a20
checksum: 6f76cd5ccae1fa9bcab3525b0865c6222e9c1d22f87abc69f28c5c7b2c8816a13361f5bd06bddbd5faf903f7320a8feba02545c981468acec45d12a03db7755e
languageName: node
linkType: hard
@ -836,14 +836,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-for-of@npm:^7.23.3":
version: 7.23.3
resolution: "@babel/plugin-transform-for-of@npm:7.23.3"
"@babel/plugin-transform-for-of@npm:^7.23.6":
version: 7.23.6
resolution: "@babel/plugin-transform-for-of@npm:7.23.6"
dependencies:
"@babel/helper-plugin-utils": "npm:^7.22.5"
"@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5"
peerDependencies:
"@babel/core": ^7.0.0-0
checksum: 8a36202cfee312ba80e509c7c2131e6773524e572b4dc64a8ee95bd912634fdeb5ea91c6c7747ee30e03562d0f0d333f88ed7dbb929b36b60b8d74189189e12f
checksum: 46681b6ab10f3ca2d961f50d4096b62ab5d551e1adad84e64be1ee23e72eb2f26a1e30e617e853c74f1349fffe4af68d33921a128543b6f24b6d46c09a3e2aec
languageName: node
linkType: hard
@ -1200,8 +1201,8 @@ __metadata:
linkType: hard
"@babel/plugin-transform-runtime@npm:^7.22.4":
version: 7.23.4
resolution: "@babel/plugin-transform-runtime@npm:7.23.4"
version: 7.23.6
resolution: "@babel/plugin-transform-runtime@npm:7.23.6"
dependencies:
"@babel/helper-module-imports": "npm:^7.22.15"
"@babel/helper-plugin-utils": "npm:^7.22.5"
@ -1211,7 +1212,7 @@ __metadata:
semver: "npm:^6.3.1"
peerDependencies:
"@babel/core": ^7.0.0-0
checksum: 6ac29012550cdd10b65ec43fef0c7f43904ec458c43d597f627d8f52807413e57ea94e3986dbace576d734e67c2d09be5e43e77c72567d18f8c4ac5e19844625
checksum: 94a7ee92f073df53fd8bebf9ed391a95553716077da1c6c3a57f10f042358c938495d55e6b09b4b50544c01f03560c4770c17698e1c24817a15d3668e8231249
languageName: node
linkType: hard
@ -1333,11 +1334,11 @@ __metadata:
linkType: hard
"@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.12.1, @babel/preset-env@npm:^7.22.4":
version: 7.23.5
resolution: "@babel/preset-env@npm:7.23.5"
version: 7.23.6
resolution: "@babel/preset-env@npm:7.23.6"
dependencies:
"@babel/compat-data": "npm:^7.23.5"
"@babel/helper-compilation-targets": "npm:^7.22.15"
"@babel/helper-compilation-targets": "npm:^7.23.6"
"@babel/helper-plugin-utils": "npm:^7.22.5"
"@babel/helper-validator-option": "npm:^7.23.5"
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.23.3"
@ -1377,7 +1378,7 @@ __metadata:
"@babel/plugin-transform-dynamic-import": "npm:^7.23.4"
"@babel/plugin-transform-exponentiation-operator": "npm:^7.23.3"
"@babel/plugin-transform-export-namespace-from": "npm:^7.23.4"
"@babel/plugin-transform-for-of": "npm:^7.23.3"
"@babel/plugin-transform-for-of": "npm:^7.23.6"
"@babel/plugin-transform-function-name": "npm:^7.23.3"
"@babel/plugin-transform-json-strings": "npm:^7.23.4"
"@babel/plugin-transform-literals": "npm:^7.23.3"
@ -1418,7 +1419,7 @@ __metadata:
semver: "npm:^6.3.1"
peerDependencies:
"@babel/core": ^7.0.0-0
checksum: 2a0e1274dec045186e131c6433659b75492583290e8d41633c616f6bff829cb2e4b2f9a57f556283a54db3bd6aa697911e56a36f607911a29b731c445a5b5a06
checksum: 5b24d179af52f082d04b9b98cc4777e37bf31a97cef5a91d8917e996dbd75f2f743c88c40f80744cb8529355bb674619d150c0260c32d834aa4067e21d0c8962
languageName: node
linkType: hard
@ -1483,11 +1484,11 @@ __metadata:
linkType: hard
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
version: 7.23.5
resolution: "@babel/runtime@npm:7.23.5"
version: 7.23.6
resolution: "@babel/runtime@npm:7.23.6"
dependencies:
regenerator-runtime: "npm:^0.14.0"
checksum: ca679cc91bb7e424bc2db87bb58cc3b06ade916b9adb21fbbdc43e54cdaacb3eea201ceba2a0464b11d2eb65b9fe6a6ffcf4d7521fa52994f19be96f1af14788
checksum: d886954e985ef8e421222f7a2848884d96a752e0020d3078b920dd104e672fdf23bcc6f51a44313a048796319f1ac9d09c2c88ec8cbb4e1f09174bcd3335b9ff
languageName: node
linkType: hard
@ -1502,32 +1503,32 @@ __metadata:
languageName: node
linkType: hard
"@babel/traverse@npm:7, @babel/traverse@npm:^7.23.5":
version: 7.23.5
resolution: "@babel/traverse@npm:7.23.5"
"@babel/traverse@npm:7, @babel/traverse@npm:^7.23.6":
version: 7.23.6
resolution: "@babel/traverse@npm:7.23.6"
dependencies:
"@babel/code-frame": "npm:^7.23.5"
"@babel/generator": "npm:^7.23.5"
"@babel/generator": "npm:^7.23.6"
"@babel/helper-environment-visitor": "npm:^7.22.20"
"@babel/helper-function-name": "npm:^7.23.0"
"@babel/helper-hoist-variables": "npm:^7.22.5"
"@babel/helper-split-export-declaration": "npm:^7.22.6"
"@babel/parser": "npm:^7.23.5"
"@babel/types": "npm:^7.23.5"
debug: "npm:^4.1.0"
"@babel/parser": "npm:^7.23.6"
"@babel/types": "npm:^7.23.6"
debug: "npm:^4.3.1"
globals: "npm:^11.1.0"
checksum: c5ea793080ca6719b0a1612198fd25e361cee1f3c14142d7a518d2a1eeb5c1d21f7eec1b26c20ea6e1ddd8ed12ab50b960ff95ffd25be353b6b46e1b54d6f825
checksum: 5b4ebb94a00a7e1daf111e4b0b45a7998d5b7598637a14e75e855e88cc1b702789e09a958726b5d599a003be1e9032dbdfde4b88ea6061332228738950d5582d
languageName: node
linkType: hard
"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3":
version: 7.23.5
resolution: "@babel/types@npm:7.23.5"
"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.6, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3":
version: 7.23.6
resolution: "@babel/types@npm:7.23.6"
dependencies:
"@babel/helper-string-parser": "npm:^7.23.4"
"@babel/helper-validator-identifier": "npm:^7.22.20"
to-fast-properties: "npm:^2.0.0"
checksum: 7dd5e2f59828ed046ad0b06b039df2524a8b728d204affb4fc08da2502b9dd3140b1356b5166515d229dc811539a8b70dcd4bc507e06d62a89f4091a38d0b0fb
checksum: 42cefce8a68bd09bb5828b4764aa5586c53c60128ac2ac012e23858e1c179347a4aac9c66fc577994fbf57595227611c5ec8270bf0cfc94ff033bbfac0550b70
languageName: node
linkType: hard
@ -1726,9 +1727,9 @@ __metadata:
languageName: node
linkType: hard
"@eslint/eslintrc@npm:^2.1.3":
version: 2.1.3
resolution: "@eslint/eslintrc@npm:2.1.3"
"@eslint/eslintrc@npm:^2.1.4":
version: 2.1.4
resolution: "@eslint/eslintrc@npm:2.1.4"
dependencies:
ajv: "npm:^6.12.4"
debug: "npm:^4.3.2"
@ -1739,14 +1740,14 @@ __metadata:
js-yaml: "npm:^4.1.0"
minimatch: "npm:^3.1.2"
strip-json-comments: "npm:^3.1.1"
checksum: f4103f4346126292eb15581c5a1d12bef03410fd3719dedbdb92e1f7031d46a5a2d60de8566790445d5d4b70b75ba050876799a11f5fff8265a91ee3fa77dab0
checksum: 32f67052b81768ae876c84569ffd562491ec5a5091b0c1e1ca1e0f3c24fb42f804952fdd0a137873bc64303ba368a71ba079a6f691cee25beee9722d94cc8573
languageName: node
linkType: hard
"@eslint/js@npm:8.54.0":
version: 8.54.0
resolution: "@eslint/js@npm:8.54.0"
checksum: d61fb4a0be6af2d8cb290121c329697664a75d6255a29926d5454fb02aeb02b87112f67fdf218d10abac42f90c570ac366126751baefc5405d0e017ed0c946c5
"@eslint/js@npm:8.55.0":
version: 8.55.0
resolution: "@eslint/js@npm:8.55.0"
checksum: 88ab9fc57a651becd2b32ec40a3958db27fae133b1ae77bebd733aa5bbd00a92f325bb02f20ad680d31c731fa49b22f060a4777dd52eb3e27da013d940bd978d
languageName: node
linkType: hard
@ -2451,7 +2452,7 @@ __metadata:
stacktrace-js: "npm:^2.0.2"
stringz: "npm:^2.1.0"
stylelint: "npm:^15.10.1"
stylelint-config-standard-scss: "npm:^11.0.0"
stylelint-config-standard-scss: "npm:^12.0.0"
substring-trie: "npm:^1.0.2"
terser-webpack-plugin: "npm:^4.2.3"
tesseract.js: "npm:^2.1.5"
@ -3046,11 +3047,11 @@ __metadata:
linkType: hard
"@types/emoji-mart@npm:^3.0.9":
version: 3.0.13
resolution: "@types/emoji-mart@npm:3.0.13"
version: 3.0.14
resolution: "@types/emoji-mart@npm:3.0.14"
dependencies:
"@types/react": "npm:*"
checksum: 840f920c3242e1d274f0102e67cb2d00434e1fd370e0bcc8983b43b6b62322b01e3ddcd5fb078c60883e613530a7c70b8c40060624897543cd4da9441ca81486
checksum: 23ded65fce9b3355fbe903d3971cb67cc827a5d587464bb7e3f349615527ef4a9197b3bb59fa84c4391d1b901e7f200f686a7fc83f649ae2a51a0fb948cbadfb
languageName: node
linkType: hard
@ -3194,12 +3195,12 @@ __metadata:
linkType: hard
"@types/jest@npm:^29.5.2":
version: 29.5.10
resolution: "@types/jest@npm:29.5.10"
version: 29.5.11
resolution: "@types/jest@npm:29.5.11"
dependencies:
expect: "npm:^29.0.0"
pretty-format: "npm:^29.0.0"
checksum: b46171d59d12a5f69bbe710f65eaf59a8073337c6b4a67dff8158575caec53f1c61f8a7d645b34d6ac3c4ea398acd30f0c5d1c4a131c0c918798019264a3397d
checksum: 524a3394845214581278bf4d75055927261fbeac7e1a89cd621bd0636da37d265fe0a85eac58b5778758faad1cbd7c7c361dfc190c78ebde03a91cce33463261
languageName: node
linkType: hard
@ -3393,11 +3394,11 @@ __metadata:
linkType: hard
"@types/react-helmet@npm:^6.1.6":
version: 6.1.9
resolution: "@types/react-helmet@npm:6.1.9"
version: 6.1.11
resolution: "@types/react-helmet@npm:6.1.11"
dependencies:
"@types/react": "npm:*"
checksum: d1823582903d6e70f1f447c7bec9e844b6f85f5de84cbcde5c8bbeecc064db1394c786ed9b9ded30544afe5c91e57c7e8105171df1643998f64c0aeab9f7f2aa
checksum: f7b3bb2151d992a108ae46fed876fb9c8119108397d9a01d150c5642782997542c8b3c52e742b56e8689b7dbfa62ca9cfc76aa7e05dec4e60c652f7ef53fa783
languageName: node
linkType: hard
@ -3514,13 +3515,13 @@ __metadata:
linkType: hard
"@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7":
version: 18.2.41
resolution: "@types/react@npm:18.2.41"
version: 18.2.43
resolution: "@types/react@npm:18.2.43"
dependencies:
"@types/prop-types": "npm:*"
"@types/scheduler": "npm:*"
csstype: "npm:^3.0.2"
checksum: 5cc72491ce8be95e7bbedd8bf039ca971772ecd22d989feb045af7e73247c7e6cff25a2f1c2200be461fb2f6b5aacef739e1ba9fd83c744209dfd3ce8aa75afe
checksum: 10477a50fbd3c0cc5b8a2ade679f442717f68fb27c8460b2aa1d3256cd18c48f742bbe5b9ee37a8c4c5f832ffa37b3a23c09fd96dd880a8e3182d8929c05e803
languageName: node
linkType: hard
@ -3701,14 +3702,14 @@ __metadata:
linkType: hard
"@typescript-eslint/eslint-plugin@npm:^6.0.0":
version: 6.11.0
resolution: "@typescript-eslint/eslint-plugin@npm:6.11.0"
version: 6.13.2
resolution: "@typescript-eslint/eslint-plugin@npm:6.13.2"
dependencies:
"@eslint-community/regexpp": "npm:^4.5.1"
"@typescript-eslint/scope-manager": "npm:6.11.0"
"@typescript-eslint/type-utils": "npm:6.11.0"
"@typescript-eslint/utils": "npm:6.11.0"
"@typescript-eslint/visitor-keys": "npm:6.11.0"
"@typescript-eslint/scope-manager": "npm:6.13.2"
"@typescript-eslint/type-utils": "npm:6.13.2"
"@typescript-eslint/utils": "npm:6.13.2"
"@typescript-eslint/visitor-keys": "npm:6.13.2"
debug: "npm:^4.3.4"
graphemer: "npm:^1.4.0"
ignore: "npm:^5.2.4"
@ -3721,44 +3722,44 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 6645aa09b9d51c5e3ea781eaf74da75b94f83f3e2d7b3dd988d5ce7eb82dd87e3509471cf2ee8c6b2428d907df5f1b02f29dbd04f54c2653f9566c8c4ce98009
checksum: 531a4406d872738d165c6a66cb26e976523c94053b022a8210dc9fd10e91b79b705bc0fcc77145e9744e4108b53bdba55e02a10dc17757b22be92aff57849384
languageName: node
linkType: hard
"@typescript-eslint/parser@npm:^6.0.0":
version: 6.11.0
resolution: "@typescript-eslint/parser@npm:6.11.0"
version: 6.13.2
resolution: "@typescript-eslint/parser@npm:6.13.2"
dependencies:
"@typescript-eslint/scope-manager": "npm:6.11.0"
"@typescript-eslint/types": "npm:6.11.0"
"@typescript-eslint/typescript-estree": "npm:6.11.0"
"@typescript-eslint/visitor-keys": "npm:6.11.0"
"@typescript-eslint/scope-manager": "npm:6.13.2"
"@typescript-eslint/types": "npm:6.13.2"
"@typescript-eslint/typescript-estree": "npm:6.13.2"
"@typescript-eslint/visitor-keys": "npm:6.13.2"
debug: "npm:^4.3.4"
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
peerDependenciesMeta:
typescript:
optional: true
checksum: e7caeb20069102e21f468fc0dbe7ff6fb6b1efa9e72f4c9f39d4a865ed0633f39130b593ef9ae8f394ca1d70563e15410faf30a482a97809951eaac6ed3a67da
checksum: 2c62b8cd8a37eb2ea59cd00e559f51a9f57af746e2040e872af3c58ddd3f4071ad7b7009789bdeb0e0d4ee0343bfe96ee77288020f3ae22d08e1674203f5e156
languageName: node
linkType: hard
"@typescript-eslint/scope-manager@npm:6.11.0":
version: 6.11.0
resolution: "@typescript-eslint/scope-manager@npm:6.11.0"
"@typescript-eslint/scope-manager@npm:6.13.2":
version: 6.13.2
resolution: "@typescript-eslint/scope-manager@npm:6.13.2"
dependencies:
"@typescript-eslint/types": "npm:6.11.0"
"@typescript-eslint/visitor-keys": "npm:6.11.0"
checksum: d8999e2d1a4cbde8a79df5e3ec416f0e3db9532d39f2f4bb5a0ebdf954ae75c183d3277579ba05268fe2c88e88ef87f0fa12f02bb8d95d9e67d92e411241f3a3
"@typescript-eslint/types": "npm:6.13.2"
"@typescript-eslint/visitor-keys": "npm:6.13.2"
checksum: 9b159e5bb10dfb5953e71488200b4126378fc7e987ce7d90946aea9ec40cd66c7ada92399657c5d9794189b764ca6f4eb38a8dcb9e4c5aa50ab6000a39636b9c
languageName: node
linkType: hard
"@typescript-eslint/type-utils@npm:6.11.0":
version: 6.11.0
resolution: "@typescript-eslint/type-utils@npm:6.11.0"
"@typescript-eslint/type-utils@npm:6.13.2":
version: 6.13.2
resolution: "@typescript-eslint/type-utils@npm:6.13.2"
dependencies:
"@typescript-eslint/typescript-estree": "npm:6.11.0"
"@typescript-eslint/utils": "npm:6.11.0"
"@typescript-eslint/typescript-estree": "npm:6.13.2"
"@typescript-eslint/utils": "npm:6.13.2"
debug: "npm:^4.3.4"
ts-api-utils: "npm:^1.0.1"
peerDependencies:
@ -3766,23 +3767,23 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: ff68f2e052b8d688f1dc1a0050746704c8e0ab6263b47f1f52da73a7d251678e4950af23a95e1cd8e3fcea2457e6e5294ddbe01d29dafa2fdfb5b11ed9452a3f
checksum: 1ca97c78abdf479aea0c54e869fda2ae2f69de1974cc063062ce7b5b16c7fdf497ea15c50a29dd5941ea1b6b77e8f1213a5c272a747e334ac69ede083f327468
languageName: node
linkType: hard
"@typescript-eslint/types@npm:6.11.0":
version: 6.11.0
resolution: "@typescript-eslint/types@npm:6.11.0"
checksum: 23182813db39a5e9b9bcc1e85306c953f7b8b22d3885e41fcac0bd725c170fbcb70f4ce55633678cc5921dcf062fa0e55635eb39480c118a4411a00354820223
"@typescript-eslint/types@npm:6.13.2":
version: 6.13.2
resolution: "@typescript-eslint/types@npm:6.13.2"
checksum: 029918ca5b1442bb4bc435773504ce32191e2c3e2fde8d4176bb6513f03e3dfa2aa9724b2d22b1640656d666b97f7a7ebfeaf67b881d5e07250828fa83e3ebe8
languageName: node
linkType: hard
"@typescript-eslint/typescript-estree@npm:6.11.0":
version: 6.11.0
resolution: "@typescript-eslint/typescript-estree@npm:6.11.0"
"@typescript-eslint/typescript-estree@npm:6.13.2":
version: 6.13.2
resolution: "@typescript-eslint/typescript-estree@npm:6.13.2"
dependencies:
"@typescript-eslint/types": "npm:6.11.0"
"@typescript-eslint/visitor-keys": "npm:6.11.0"
"@typescript-eslint/types": "npm:6.13.2"
"@typescript-eslint/visitor-keys": "npm:6.13.2"
debug: "npm:^4.3.4"
globby: "npm:^11.1.0"
is-glob: "npm:^4.0.3"
@ -3791,34 +3792,34 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 3e183e554e1bc74f065da3015f7137eb40c262f989c547701b1e3f4f20134e574e56b749288cd00d77b9d1ddb705546613c2457661ffc63b6060ffa97ba3aac8
checksum: 1c4c59dce0c51fdfee34d9f418e64fe28e3ec1a97661efc8a3d2780bdff36aff38de9090d356a968f394fa6d4e9c058936ce9cd260d4c44a52761ecd74915bce
languageName: node
linkType: hard
"@typescript-eslint/utils@npm:6.11.0, @typescript-eslint/utils@npm:^6.5.0":
version: 6.11.0
resolution: "@typescript-eslint/utils@npm:6.11.0"
"@typescript-eslint/utils@npm:6.13.2, @typescript-eslint/utils@npm:^6.5.0":
version: 6.13.2
resolution: "@typescript-eslint/utils@npm:6.13.2"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.4.0"
"@types/json-schema": "npm:^7.0.12"
"@types/semver": "npm:^7.5.0"
"@typescript-eslint/scope-manager": "npm:6.11.0"
"@typescript-eslint/types": "npm:6.11.0"
"@typescript-eslint/typescript-estree": "npm:6.11.0"
"@typescript-eslint/scope-manager": "npm:6.13.2"
"@typescript-eslint/types": "npm:6.13.2"
"@typescript-eslint/typescript-estree": "npm:6.13.2"
semver: "npm:^7.5.4"
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
checksum: c91eb4578607959acc2b43ddc791571682e45601a19b25d5d120786ed4af607656f83c5c1fa71972e549ddfb5542acf2f7d443ae93b32ee28192c22c106b8883
checksum: 84969be91e7949868eaaa289288c9d71927f0e427b572501b0991d8d62b40a4234f7287c35b35d276ccbb53e9ea5457b8250fcf4941e60e6b9ba4065fbfba416
languageName: node
linkType: hard
"@typescript-eslint/visitor-keys@npm:6.11.0":
version: 6.11.0
resolution: "@typescript-eslint/visitor-keys@npm:6.11.0"
"@typescript-eslint/visitor-keys@npm:6.13.2":
version: 6.13.2
resolution: "@typescript-eslint/visitor-keys@npm:6.13.2"
dependencies:
"@typescript-eslint/types": "npm:6.11.0"
"@typescript-eslint/types": "npm:6.13.2"
eslint-visitor-keys: "npm:^3.4.1"
checksum: 5f48329422b7f286196661d39e93e9defd7c5cf80e6c84c8d03459853f5d9f86a5e91c5e80ea572dcdb907ebbe503bbcc77aeb8b468c294b2aa7b3ccfc81cb88
checksum: c173bc1fcc42c3075a5ee094e7f3bf0279d98315c25ff49e20d02d79022b1d0402accfa113b070afb4d52a6f6d180594b67baa8b6a784eabdf82b54dd1ff454c
languageName: node
linkType: hard
@ -5189,17 +5190,17 @@ __metadata:
languageName: node
linkType: hard
"browserslist@npm:^4.0.0, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.21.9, browserslist@npm:^4.22.1":
version: 4.22.1
resolution: "browserslist@npm:4.22.1"
"browserslist@npm:^4.0.0, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.22.1, browserslist@npm:^4.22.2":
version: 4.22.2
resolution: "browserslist@npm:4.22.2"
dependencies:
caniuse-lite: "npm:^1.0.30001541"
electron-to-chromium: "npm:^1.4.535"
node-releases: "npm:^2.0.13"
caniuse-lite: "npm:^1.0.30001565"
electron-to-chromium: "npm:^1.4.601"
node-releases: "npm:^2.0.14"
update-browserslist-db: "npm:^1.0.13"
bin:
browserslist: cli.js
checksum: 6810f2d63f171d0b7b8d38cf091708e00cb31525501810a507839607839320d66e657293b0aa3d7f051ecbc025cb07390a90c037682c1d05d12604991e41050b
checksum: 2a331aab90503130043ca41dd5d281fa1e89d5e076d07a2d75e76bf4d693bd56e73d5abcd8c4f39119da6328d450578c216cf1cd5c99b82d8a90a2ae6271b465
languageName: node
linkType: hard
@ -5427,10 +5428,10 @@ __metadata:
languageName: node
linkType: hard
"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001541":
version: 1.0.30001561
resolution: "caniuse-lite@npm:1.0.30001561"
checksum: 6e84c84026fee53edbdbb5aded7a04a036aae4c2e367cf6bdc90c6783a591e2fdcfcdebcc4e774aca61092e542a61200c8c16b06659396492426033c4dbcc618
"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001565":
version: 1.0.30001568
resolution: "caniuse-lite@npm:1.0.30001568"
checksum: 13f01e5a2481134bd61cf565ce9fecbd8e107902927a0dcf534230a92191a81f1715792170f5f39719c767c3a96aa6df9917a8d5601f15bbd5e4041a8cfecc99
languageName: node
linkType: hard
@ -6441,7 +6442,7 @@ __metadata:
languageName: node
linkType: hard
"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.4":
"debug@npm:4, debug@npm:4.3.4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4":
version: 4.3.4
resolution: "debug@npm:4.3.4"
dependencies:
@ -6983,10 +6984,10 @@ __metadata:
languageName: node
linkType: hard
"electron-to-chromium@npm:^1.4.535":
version: 1.4.576
resolution: "electron-to-chromium@npm:1.4.576"
checksum: b0b9e7ba803bf93ffac9cb830ed2b0e0eb07f20066127065f9ab9e08e4e6a5812040e03d76f6ee9bc59e03fb938fd414e83d4883b29111303e9e88633cf2dce4
"electron-to-chromium@npm:^1.4.601":
version: 1.4.609
resolution: "electron-to-chromium@npm:1.4.609"
checksum: 9675a79388acbaff5953a4c61589af7da93e0d1f9d6a3b284c7630f10126eb0998557b07448514214d5a3d19025310039b55f405ab701b1253130fc94907f743
languageName: node
linkType: hard
@ -7341,13 +7342,13 @@ __metadata:
linkType: hard
"eslint-config-prettier@npm:^9.0.0":
version: 9.0.0
resolution: "eslint-config-prettier@npm:9.0.0"
version: 9.1.0
resolution: "eslint-config-prettier@npm:9.1.0"
peerDependencies:
eslint: ">=7.0.0"
bin:
eslint-config-prettier: bin/cli.js
checksum: bc1f661915845c631824178942e5d02f858fe6d0ea796f0050d63e0f681927b92696e81139dd04714c08c3e7de580fd079c66162e40070155ba79eaee78ab5d0
checksum: 6d332694b36bc9ac6fdb18d3ca2f6ac42afa2ad61f0493e89226950a7091e38981b66bac2b47ba39d15b73fff2cd32c78b850a9cf9eed9ca9a96bfb2f3a2f10d
languageName: node
linkType: hard
@ -7583,13 +7584,13 @@ __metadata:
linkType: hard
"eslint@npm:^8.41.0":
version: 8.54.0
resolution: "eslint@npm:8.54.0"
version: 8.55.0
resolution: "eslint@npm:8.55.0"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.2.0"
"@eslint-community/regexpp": "npm:^4.6.1"
"@eslint/eslintrc": "npm:^2.1.3"
"@eslint/js": "npm:8.54.0"
"@eslint/eslintrc": "npm:^2.1.4"
"@eslint/js": "npm:8.55.0"
"@humanwhocodes/config-array": "npm:^0.11.13"
"@humanwhocodes/module-importer": "npm:^1.0.1"
"@nodelib/fs.walk": "npm:^1.2.8"
@ -7626,7 +7627,7 @@ __metadata:
text-table: "npm:^0.2.0"
bin:
eslint: bin/eslint.js
checksum: 4f205f832bdbd0218cde374b067791f4f76d7abe8de86b2dc849c273899051126d912ebf71531ee49b8eeaa22cad77febdc8f2876698dc2a76e84a8cb976af22
checksum: d28c0b60f19bb7d355cb8393e77b018c8f548dba3f820b799c89bb2e0c436ee26084e700c5e57e1e97e7972ec93065277849141b82e7b0c0d02c2dc1e553a2a1
languageName: node
linkType: hard
@ -11958,10 +11959,10 @@ __metadata:
languageName: node
linkType: hard
"node-releases@npm:^2.0.13":
version: 2.0.13
resolution: "node-releases@npm:2.0.13"
checksum: 2fb44bf70fc949d27f3a48a7fd1a9d1d603ddad4ccd091f26b3fb8b1da976605d919330d7388ccd55ca2ade0dc8b2e12841ba19ef249c8bb29bf82532d401af7
"node-releases@npm:^2.0.14":
version: 2.0.14
resolution: "node-releases@npm:2.0.14"
checksum: 199fc93773ae70ec9969bc6d5ac5b2bbd6eb986ed1907d751f411fef3ede0e4bfdb45ceb43711f8078bea237b6036db8b1bf208f6ff2b70c7d615afd157f3ab9
languageName: node
linkType: hard
@ -13340,11 +13341,11 @@ __metadata:
linkType: hard
"prettier@npm:^3.0.0":
version: 3.1.0
resolution: "prettier@npm:3.1.0"
version: 3.1.1
resolution: "prettier@npm:3.1.1"
bin:
prettier: bin/prettier.cjs
checksum: a45ea70aa97fde162ea4c4aba3dfc7859aa6a732a1db34458d9535dc3c2c16d3bc3fb5689e6cd76aa835562555303b02d9449fd2e15af3b73c8053557e25c5b6
checksum: facc944ba20e194ff4db765e830ffbcb642803381f0d2033ed397e79904fa4ccc877dc25ad68f42d36985c01d051c990ca1b905fb83d2d7d65fe69e4386fa1a3
languageName: node
linkType: hard
@ -15792,62 +15793,62 @@ __metadata:
languageName: node
linkType: hard
"stylelint-config-recommended-scss@npm:^13.1.0":
version: 13.1.0
resolution: "stylelint-config-recommended-scss@npm:13.1.0"
"stylelint-config-recommended-scss@npm:^14.0.0":
version: 14.0.0
resolution: "stylelint-config-recommended-scss@npm:14.0.0"
dependencies:
postcss-scss: "npm:^4.0.9"
stylelint-config-recommended: "npm:^13.0.0"
stylelint-scss: "npm:^5.3.0"
stylelint-config-recommended: "npm:^14.0.0"
stylelint-scss: "npm:^6.0.0"
peerDependencies:
postcss: ^8.3.3
stylelint: ^15.10.0
stylelint: ^16.0.2
peerDependenciesMeta:
postcss:
optional: true
checksum: e07d0172c7936b4f644138e4129df2f187d297f1f96ce5865ab21ccd1c22caf94220f7caf9d6985e93e515de4c0356f6cb9c924d00df2eee5b3bc237f7e5bb48
checksum: 9ddc92e7a5fa131b41cee1ab1f69251934ca35c0e2803dc613329cdead7b8b27d8457048a63db29f61a1442e7cdef14207f88a3abce00ec53fdefe0d604f7de3
languageName: node
linkType: hard
"stylelint-config-recommended@npm:^13.0.0":
version: 13.0.0
resolution: "stylelint-config-recommended@npm:13.0.0"
"stylelint-config-recommended@npm:^14.0.0":
version: 14.0.0
resolution: "stylelint-config-recommended@npm:14.0.0"
peerDependencies:
stylelint: ^15.10.0
checksum: 80420a1ab616e8637b66223f88c597388990d9991cd6a28b8372049b83329d893412f83029bb253a82b52387e497b62e042bc898064a2f22574b0d8921f01dd2
stylelint: ^16.0.0
checksum: 4ad15c36e8c03291aa7bbe4b672ebfb0f46ab698e7580a0da8d29644046d102d7f31dbf00a2a6eab94b565c390c6fb0d5d528737b83ac3acf6dc2ef085a90b11
languageName: node
linkType: hard
"stylelint-config-standard-scss@npm:^11.0.0":
version: 11.1.0
resolution: "stylelint-config-standard-scss@npm:11.1.0"
"stylelint-config-standard-scss@npm:^12.0.0":
version: 12.0.0
resolution: "stylelint-config-standard-scss@npm:12.0.0"
dependencies:
stylelint-config-recommended-scss: "npm:^13.1.0"
stylelint-config-standard: "npm:^34.0.0"
stylelint-config-recommended-scss: "npm:^14.0.0"
stylelint-config-standard: "npm:^35.0.0"
peerDependencies:
postcss: ^8.3.3
stylelint: ^15.10.0
stylelint: ^16.0.2
peerDependenciesMeta:
postcss:
optional: true
checksum: 22d00e75c1eacce9883fd48c3d67b1107b0e39d7d86e9f73deaa332b11c39a9678c947ae2c34cd5159a452ec9a857694ed58b5a851087480d3c9a66dab629415
checksum: 7f3ccfb4175f9c50b69d30ca35a97887008c5ba493dbe7d5bce0b57b1eafd21b268177b82404368e7780600077cba784f98e1046671724be3b29a00c6a7913a4
languageName: node
linkType: hard
"stylelint-config-standard@npm:^34.0.0":
version: 34.0.0
resolution: "stylelint-config-standard@npm:34.0.0"
"stylelint-config-standard@npm:^35.0.0":
version: 35.0.0
resolution: "stylelint-config-standard@npm:35.0.0"
dependencies:
stylelint-config-recommended: "npm:^13.0.0"
stylelint-config-recommended: "npm:^14.0.0"
peerDependencies:
stylelint: ^15.10.0
checksum: 2494468af2359490b6ebb9723d9653f9e31db3a0772b8d9f0e081018b0079ef84ae6f90dcf94c879a3c374f299e334941e3dcff1afb603c2284d3103085b71fb
stylelint: ^16.0.0
checksum: 791fbc26cc3029ce3c2423a643e903545b5e4cd605251b18f0ce790bac6fbaaf380469845c1ff45f4e320126af9f8a9dc1ca85d0df9274277ae60da91e81895b
languageName: node
linkType: hard
"stylelint-scss@npm:^5.3.0":
version: 5.3.1
resolution: "stylelint-scss@npm:5.3.1"
"stylelint-scss@npm:^6.0.0":
version: 6.0.0
resolution: "stylelint-scss@npm:6.0.0"
dependencies:
known-css-properties: "npm:^0.29.0"
postcss-media-query-parser: "npm:^0.2.3"
@ -15855,8 +15856,8 @@ __metadata:
postcss-selector-parser: "npm:^6.0.13"
postcss-value-parser: "npm:^4.2.0"
peerDependencies:
stylelint: ^14.5.1 || ^15.0.0
checksum: 5dfed5f9ac9812cd2ac6ef0272c720dee0326aaaee2998315a23bdcd71b8f04427f29cad634793eea2b45984182e20f03e90d43501e8e4d55bc956f80e2de477
stylelint: ^16.0.2
checksum: f5e971d19ef6879ae5c18cb8fba8033fe7928f241178e6afd80357cc080d2feddfd6f7fe564aaa696008aa10345df5885d9a4471c926b3e266088e015927782e
languageName: node
linkType: hard
@ -16530,22 +16531,22 @@ __metadata:
linkType: hard
"typescript@npm:5, typescript@npm:^5.0.4":
version: 5.3.2
resolution: "typescript@npm:5.3.2"
version: 5.3.3
resolution: "typescript@npm:5.3.3"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: d7dbe1fbe19039e36a65468ea64b5d338c976550394ba576b7af9c68ed40c0bc5d12ecce390e4b94b287a09a71bd3229f19c2d5680611f35b7c53a3898791159
checksum: e33cef99d82573624fc0f854a2980322714986bc35b9cb4d1ce736ed182aeab78e2cb32b385efa493b2a976ef52c53e20d6c6918312353a91850e2b76f1ea44f
languageName: node
linkType: hard
"typescript@patch:typescript@npm%3A5#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin<compat/typescript>":
version: 5.3.2
resolution: "typescript@patch:typescript@npm%3A5.3.2#optional!builtin<compat/typescript>::version=5.3.2&hash=e012d7"
version: 5.3.3
resolution: "typescript@patch:typescript@npm%3A5.3.3#optional!builtin<compat/typescript>::version=5.3.3&hash=e012d7"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 73c8bad74e732d93211c9d77f28b03307e2f5fc6a0afc73f4b783261ab567686a16d6ae958bdaef383a00be1b0b8c8b6741dd6ca3d13af4963fa7e47456d49c7
checksum: 1d0a5f4ce496c42caa9a30e659c467c5686eae15d54b027ee7866744952547f1be1262f2d40de911618c242b510029d51d43ff605dba8fb740ec85ca2d3f9500
languageName: node
linkType: hard
@ -17782,8 +17783,8 @@ __metadata:
linkType: hard
"ws@npm:^8.11.0, ws@npm:^8.12.1, ws@npm:^8.14.2":
version: 8.14.2
resolution: "ws@npm:8.14.2"
version: 8.15.1
resolution: "ws@npm:8.15.1"
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ">=5.0.2"
@ -17792,7 +17793,7 @@ __metadata:
optional: true
utf-8-validate:
optional: true
checksum: 35b4c2da048b8015c797fd14bcb5a5766216ce65c8a5965616a5440ca7b6c3681ee3cbd0ea0c184a59975556e9d58f2002abf8485a14d11d3371770811050a16
checksum: 9964360dd5ab35c7376bd7c4295a3c8bd44ea0838c9413742548a6fb3ec371fc6c18552d5b8e76bdc21536db1909765612815bae072674b5ec69971605395a96
languageName: node
linkType: hard