Merge pull request #2994 from ClearlyClaire/glitch-soc/merge-upstream

Merge upstream changes up to aff5182375
main
Claire 2025-03-12 21:23:52 +01:00 committed by GitHub
commit 0fecbac498
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 1437 additions and 287 deletions

View File

@ -316,3 +316,24 @@ MAX_POLL_OPTION_CHARS=100
# -----------------------
IP_RETENTION_PERIOD=31556952
SESSION_RETENTION_PERIOD=31556952
# Fetch All Replies Behavior
# --------------------------
# When a user expands a post (DetailedStatus view), fetch all of its replies
# (default: false)
FETCH_REPLIES_ENABLED=false
# Period to wait between fetching replies (in minutes)
FETCH_REPLIES_COOLDOWN_MINUTES=15
# Period to wait after a post is first created before fetching its replies (in minutes)
FETCH_REPLIES_INITIAL_WAIT_MINUTES=5
# Max number of replies to fetch - total, recursively through a whole reply tree
FETCH_REPLIES_MAX_GLOBAL=1000
# Max number of replies to fetch - for a single post
FETCH_REPLIES_MAX_SINGLE=500
# Max number of replies Collection pages to fetch - total
FETCH_REPLIES_MAX_PAGES=500

View File

@ -14,12 +14,12 @@ ARG BASE_REGISTRY="docker.io"
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.4.x"]
# renovate: datasource=docker depName=docker.io/ruby
ARG RUBY_VERSION="3.4.2"
# # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
# # Node.js version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
# renovate: datasource=node-version depName=node
ARG NODE_MAJOR_VERSION="22"
# Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"]
ARG DEBIAN_VERSION="bookworm"
# Node image to use for base image based on combined variables (ex: 20-bookworm-slim)
# Node.js image to use for base image based on combined variables (ex: 20-bookworm-slim)
FROM ${BASE_REGISTRY}/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim AS node
# Ruby image to use for base image based on combined variables (ex: 3.4.x-slim-bookworm)
FROM ${BASE_REGISTRY}/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} AS ruby
@ -61,7 +61,7 @@ ENV \
ENV \
# Configure the IP to bind Mastodon to when serving traffic
BIND="0.0.0.0" \
# Use production settings for Yarn, Node and related nodejs based tools
# Use production settings for Yarn, Node.js and related tools
NODE_ENV="production" \
# Use production settings for Ruby on Rails
RAILS_ENV="production" \
@ -128,13 +128,6 @@ RUN \
# Create temporary build layer from base image
FROM ruby AS build
# Copy Node package configuration files into working directory
COPY package.json yarn.lock .yarnrc.yml /opt/mastodon/
COPY .yarn /opt/mastodon/.yarn
COPY --from=node /usr/local/bin /usr/local/bin
COPY --from=node /usr/local/lib /usr/local/lib
ARG TARGETPLATFORM
# hadolint ignore=DL3008
@ -188,12 +181,6 @@ RUN \
libx265-dev \
;
RUN \
# Configure Corepack
rm /usr/local/bin/yarn*; \
corepack enable; \
corepack prepare --activate;
# Create temporary libvips specific build layer from build layer
FROM build AS libvips
@ -284,38 +271,37 @@ RUN \
# Download and install required Gems
bundle install -j"$(nproc)";
# Create temporary node specific build layer from build layer
FROM build AS yarn
# Create temporary assets build layer from build layer
FROM build AS precompiler
ARG TARGETPLATFORM
# Copy Node package configuration files into working directory
COPY package.json yarn.lock .yarnrc.yml /opt/mastodon/
COPY streaming/package.json /opt/mastodon/streaming/
COPY .yarn /opt/mastodon/.yarn
# Copy Mastodon sources into layer
COPY . /opt/mastodon/
# Copy Node.js binaries/libraries into layer
COPY --from=node /usr/local/bin /usr/local/bin
COPY --from=node /usr/local/lib /usr/local/lib
RUN \
# Configure Corepack
rm /usr/local/bin/yarn*; \
corepack enable; \
corepack prepare --activate;
# hadolint ignore=DL3008
RUN \
--mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
--mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
# Install Node packages
# Install Node.js packages
yarn workspaces focus --production @mastodon/mastodon;
# Create temporary assets build layer from build layer
FROM build AS precompiler
# Copy Mastodon sources into precompiler layer
COPY . /opt/mastodon/
# Copy bundler and node packages from build layer to container
COPY --from=yarn /opt/mastodon /opt/mastodon/
COPY --from=bundler /opt/mastodon /opt/mastodon/
COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/
# Copy libvips components to layer for precompiler
# Copy libvips components into layer for precompiler
COPY --from=libvips /usr/local/libvips/bin /usr/local/bin
COPY --from=libvips /usr/local/libvips/lib /usr/local/lib
ARG TARGETPLATFORM
# Copy bundler packages into layer for precompiler
COPY --from=bundler /opt/mastodon /opt/mastodon/
COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/
RUN \
ldconfig; \

View File

@ -10,29 +10,29 @@ GIT
GEM
remote: https://rubygems.org/
specs:
actioncable (8.0.1)
actionpack (= 8.0.1)
activesupport (= 8.0.1)
actioncable (8.0.2)
actionpack (= 8.0.2)
activesupport (= 8.0.2)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6)
actionmailbox (8.0.1)
actionpack (= 8.0.1)
activejob (= 8.0.1)
activerecord (= 8.0.1)
activestorage (= 8.0.1)
activesupport (= 8.0.1)
actionmailbox (8.0.2)
actionpack (= 8.0.2)
activejob (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
mail (>= 2.8.0)
actionmailer (8.0.1)
actionpack (= 8.0.1)
actionview (= 8.0.1)
activejob (= 8.0.1)
activesupport (= 8.0.1)
actionmailer (8.0.2)
actionpack (= 8.0.2)
actionview (= 8.0.2)
activejob (= 8.0.2)
activesupport (= 8.0.2)
mail (>= 2.8.0)
rails-dom-testing (~> 2.2)
actionpack (8.0.1)
actionview (= 8.0.1)
activesupport (= 8.0.1)
actionpack (8.0.2)
actionview (= 8.0.2)
activesupport (= 8.0.2)
nokogiri (>= 1.8.5)
rack (>= 2.2.4)
rack-session (>= 1.0.1)
@ -40,15 +40,15 @@ GEM
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
useragent (~> 0.16)
actiontext (8.0.1)
actionpack (= 8.0.1)
activerecord (= 8.0.1)
activestorage (= 8.0.1)
activesupport (= 8.0.1)
actiontext (8.0.2)
actionpack (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
actionview (8.0.1)
activesupport (= 8.0.1)
actionview (8.0.2)
activesupport (= 8.0.2)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
@ -58,22 +58,22 @@ GEM
activemodel (>= 4.1)
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
activejob (8.0.1)
activesupport (= 8.0.1)
activejob (8.0.2)
activesupport (= 8.0.2)
globalid (>= 0.3.6)
activemodel (8.0.1)
activesupport (= 8.0.1)
activerecord (8.0.1)
activemodel (= 8.0.1)
activesupport (= 8.0.1)
activemodel (8.0.2)
activesupport (= 8.0.2)
activerecord (8.0.2)
activemodel (= 8.0.2)
activesupport (= 8.0.2)
timeout (>= 0.4.0)
activestorage (8.0.1)
actionpack (= 8.0.1)
activejob (= 8.0.1)
activerecord (= 8.0.1)
activesupport (= 8.0.1)
activestorage (8.0.2)
actionpack (= 8.0.2)
activejob (= 8.0.2)
activerecord (= 8.0.2)
activesupport (= 8.0.2)
marcel (~> 1.0)
activesupport (8.0.1)
activesupport (8.0.2)
base64
benchmark (>= 0.3)
bigdecimal
@ -333,7 +333,7 @@ GEM
azure-blob (~> 0.5.2)
hashie (~> 5.0)
jmespath (1.6.2)
json (2.10.1)
json (2.10.2)
json-canonicalization (1.0.0)
json-jwt (1.16.7)
activesupport (>= 4.2)
@ -637,20 +637,20 @@ GEM
rackup (1.0.1)
rack (< 3)
webrick
rails (8.0.1)
actioncable (= 8.0.1)
actionmailbox (= 8.0.1)
actionmailer (= 8.0.1)
actionpack (= 8.0.1)
actiontext (= 8.0.1)
actionview (= 8.0.1)
activejob (= 8.0.1)
activemodel (= 8.0.1)
activerecord (= 8.0.1)
activestorage (= 8.0.1)
activesupport (= 8.0.1)
rails (8.0.2)
actioncable (= 8.0.2)
actionmailbox (= 8.0.2)
actionmailer (= 8.0.2)
actionpack (= 8.0.2)
actiontext (= 8.0.2)
actionview (= 8.0.2)
activejob (= 8.0.2)
activemodel (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
bundler (>= 1.15.0)
railties (= 8.0.1)
railties (= 8.0.2)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
@ -661,9 +661,9 @@ GEM
rails-i18n (8.0.1)
i18n (>= 0.7, < 2)
railties (>= 8.0.0, < 9)
railties (8.0.1)
actionpack (= 8.0.1)
activesupport (= 8.0.1)
railties (8.0.2)
actionpack (= 8.0.2)
activesupport (= 8.0.2)
irb (~> 1.13)
rackup (>= 1.0.0)
rake (>= 12.2)
@ -742,7 +742,7 @@ GEM
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.38.1)
parser (>= 3.3.1.0)
rubocop-capybara (2.22.0)
rubocop-capybara (2.22.1)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-i18n (3.2.3)

View File

@ -58,6 +58,8 @@ class Api::V1::StatusesController < Api::BaseController
statuses = [@status] + @context.ancestors + @context.descendants
render json: @context, serializer: REST::ContextSerializer, relationships: StatusRelationshipsPresenter.new(statuses, current_user&.account_id)
ActivityPub::FetchAllRepliesWorker.perform_async(@status.id) if !current_account.nil? && @status.should_fetch_replies?
end
def create

View File

@ -155,24 +155,49 @@ module JsonLdHelper
end
end
def fetch_resource(uri, id_is_known, on_behalf_of = nil, request_options: {})
# Fetch the resource given by uri.
# @param uri [String]
# @param id_is_known [Boolean]
# @param on_behalf_of [nil, Account]
# @param raise_on_error [Symbol<:all, :temporary, :none>] See {#fetch_resource_without_id_validation} for possible values
def fetch_resource(uri, id_is_known, on_behalf_of = nil, raise_on_error: :none, request_options: {})
unless id_is_known
json = fetch_resource_without_id_validation(uri, on_behalf_of)
json = fetch_resource_without_id_validation(uri, on_behalf_of, raise_on_error: raise_on_error)
return if !json.is_a?(Hash) || unsupported_uri_scheme?(json['id'])
uri = json['id']
end
json = fetch_resource_without_id_validation(uri, on_behalf_of, request_options: request_options)
json = fetch_resource_without_id_validation(uri, on_behalf_of, raise_on_error: raise_on_error, request_options: request_options)
json.present? && json['id'] == uri ? json : nil
end
def fetch_resource_without_id_validation(uri, on_behalf_of = nil, raise_on_temporary_error = false, request_options: {})
# Fetch the resource given by uri
#
# If an error is raised, it contains the response and can be captured for handling like
#
# begin
# fetch_resource_without_id_validation(uri, nil, true)
# rescue Mastodon::UnexpectedResponseError => e
# e.response
# end
#
# @param uri [String]
# @param on_behalf_of [nil, Account]
# @param raise_on_error [Symbol<:all, :temporary, :none>]
# - +:all+ - raise if response code is not in the 2xx range
# - +:temporary+ - raise if the response code is not an "unsalvageable error" like a 404
# (see {#response_error_unsalvageable} )
# - +:none+ - do not raise, return +nil+
def fetch_resource_without_id_validation(uri, on_behalf_of = nil, raise_on_error: :none, request_options: {})
on_behalf_of ||= Account.representative
build_request(uri, on_behalf_of, options: request_options).perform do |response|
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) || !raise_on_temporary_error
raise Mastodon::UnexpectedResponseError, response if !response_successful?(response) && (
raise_on_error == :all ||
(!response_error_unsalvageable?(response) && raise_on_error == :temporary)
)
body_to_json(response.body_with_limit) if response.code == 200 && valid_activitypub_content_type?(response)
end

View File

@ -153,7 +153,7 @@
"column.domain_blocks": "Blokerede domæner",
"column.edit_list": "Redigér liste",
"column.favourites": "Favoritter",
"column.firehose": "Realtids-strømme",
"column.firehose": "Aktuelt",
"column.follow_requests": "Følgeanmodninger",
"column.home": "Hjem",
"column.list_members": "Håndtér listemedlemmer",

View File

@ -1,10 +1,10 @@
{
"about.blocks": "Moderirani strežniki",
"about.contact": "Stik:",
"about.disclaimer": "Mastodon je prosto, odprto-kodno programje in blagovna znamka Mastodon gGmbH.",
"about.disclaimer": "Mastodon je prosto, odprtokodno programje in blagovna znamka podjetja Mastodon gGmbH.",
"about.domain_blocks.no_reason_available": "Razlog ni na voljo",
"about.domain_blocks.preamble": "Mastodon vam splošno omogoča ogled vsebin in interakcijo z uporabniki iz vseh drugih strežnikov v fediverzumu. To so izjeme, opravljene na tem strežniku.",
"about.domain_blocks.silenced.explanation": "V splošnem ne boste videli profilov in vsebin s tega strežnika, če jih eksplicino ne poiščete ali nanje naročite s sledenjem.",
"about.domain_blocks.preamble": "Mastodon vam na splošno omogoča ogled vsebin in interakcijo z uporabniki z vseh drugih strežnikov v fediverzumu. Tu so navedene izjeme, ki jih postavlja ta strežnik.",
"about.domain_blocks.silenced.explanation": "V splošnem ne boste videli profilov in vsebin s tega strežnika, razen če jih izrecno poiščete ali jim začnete slediti.",
"about.domain_blocks.silenced.title": "Omejeno",
"about.domain_blocks.suspended.explanation": "Nobeni podatki s tega strežnika ne bodo obdelani, shranjeni ali izmenjani, zaradi česar je nemogoča kakršna koli interakcija ali komunikacija z uporabniki s tega strežnika.",
"about.domain_blocks.suspended.title": "Suspendiran",
@ -29,11 +29,11 @@
"account.endorse": "Izpostavi v profilu",
"account.featured_tags.last_status_at": "Zadnja objava {date}",
"account.featured_tags.last_status_never": "Ni objav",
"account.featured_tags.title": "Izpostavljeni ključniki {name}",
"account.featured_tags.title": "Izpostavljeni ključniki osebe {name}",
"account.follow": "Sledi",
"account.follow_back": "Sledi nazaj",
"account.followers": "Sledilci",
"account.followers.empty": "Nihče ne sledi temu uporabniku.",
"account.followers.empty": "Nihče še ne sledi temu uporabniku.",
"account.followers_counter": "{count, plural, one {{counter} sledilec} two {{counter} sledilca} few {{counter} sledilci} other {{counter} sledilcev}}",
"account.following": "Sledim",
"account.following_counter": "{count, plural, one {{counter} sleden} two {{counter} sledena} few {{counter} sledeni} other {{counter} sledenih}}",
@ -45,9 +45,9 @@
"account.languages": "Spremeni naročene jezike",
"account.link_verified_on": "Lastništvo te povezave je bilo preverjeno {date}",
"account.locked_info": "Stanje zasebnosti računa je nastavljeno na zaklenjeno. Lastnik ročno pregleda, kdo ga lahko spremlja.",
"account.media": "Mediji",
"account.media": "Predstavnosti",
"account.mention": "Omeni @{name}",
"account.moved_to": "{name} nakazuje, da ima zdaj nov račun:",
"account.moved_to": "{name} sporoča, da ima zdaj nov račun:",
"account.mute": "Utišaj @{name}",
"account.mute_notifications_short": "Utišaj obvestila",
"account.mute_short": "Utišaj",
@ -68,14 +68,14 @@
"account.unblock_short": "Odblokiraj",
"account.unendorse": "Ne vključi v profil",
"account.unfollow": "Ne sledi več",
"account.unmute": "Odtišaj @{name}",
"account.unmute": "Povrni glas @{name}",
"account.unmute_notifications_short": "Izklopi utišanje obvestil",
"account.unmute_short": "Odtišaj",
"account_note.placeholder": "Kliknite za dodajanje opombe",
"account.unmute_short": "Povrni glas",
"account_note.placeholder": "Kliknite, da dodate opombo",
"admin.dashboard.daily_retention": "Mera ohranjanja uporabnikov po dnevih od registracije",
"admin.dashboard.monthly_retention": "Mera ohranjanja uporabnikov po mesecih od registracije",
"admin.dashboard.retention.average": "Povprečje",
"admin.dashboard.retention.cohort": "Mesec prijave",
"admin.dashboard.retention.cohort": "Mesec registracije",
"admin.dashboard.retention.cohort_size": "Novi uporabniki",
"admin.impact_report.instance_accounts": "Profili računov, ki bi jih s tem izbrisali",
"admin.impact_report.instance_followers": "Sledilci, ki bi jih izgubili naši uporabniki",
@ -87,44 +87,61 @@
"alert.unexpected.title": "Ojoj!",
"alt_text_badge.title": "Nadomestno besedilo",
"alt_text_modal.add_alt_text": "Dodaj nadomestno besedilo",
"alt_text_modal.add_text_from_image": "Dodaj besedilo iz slike",
"alt_text_modal.cancel": "Prekliči",
"alt_text_modal.change_thumbnail": "Spremeni sličico",
"alt_text_modal.describe_for_people_with_hearing_impairments": "Podaj opis za ljudi s težavami s sluhom ...",
"alt_text_modal.describe_for_people_with_visual_impairments": "Podaj opis za slabovidne ...",
"alt_text_modal.done": "Opravljeno",
"announcement.announcement": "Obvestilo",
"announcement.announcement": "Oznanilo",
"annual_report.summary.archetype.booster": "Lovec na trende",
"annual_report.summary.archetype.lurker": "Tiholazec",
"annual_report.summary.archetype.oracle": "Orakelj",
"annual_report.summary.archetype.pollster": "Anketar",
"annual_report.summary.archetype.replier": "Priljudnež",
"annual_report.summary.followers.followers": "sledilcev",
"annual_report.summary.followers.total": "",
"annual_report.summary.followers.total": "skupaj {count}",
"annual_report.summary.here_it_is": "Tule je povzetek vašega leta {year}:",
"annual_report.summary.highlighted_post.by_favourites": "- najpriljubljenejša objava",
"annual_report.summary.highlighted_post.by_reblogs": "- največkrat izpostavljena objava",
"annual_report.summary.highlighted_post.by_replies": "- objava z največ odgovori",
"annual_report.summary.highlighted_post.possessive": "{name}",
"annual_report.summary.most_used_app.most_used_app": "najpogosteje uporabljena aplikacija",
"annual_report.summary.most_used_hashtag.most_used_hashtag": "največkrat uporabljen ključnik",
"annual_report.summary.most_used_hashtag.none": "Brez",
"annual_report.summary.new_posts.new_posts": "nove objave",
"annual_report.summary.percentile.text": "<topLabel>S tem ste se uvrstili med zgornjih </topLabel><percentage></percentage><bottomLabel> uporabnikov domene {domain}.</bottomLabel>",
"annual_report.summary.percentile.we_wont_tell_bernie": "Živi duši ne bomo povedali.",
"annual_report.summary.thanks": "Hvala, ker ste del Mastodona!",
"attachments_list.unprocessed": "(neobdelano)",
"audio.hide": "Skrij zvok",
"block_modal.remote_users_caveat": "Od strežnika {domain} bomo zahtevali, da spoštuje vašo odločitev. Izpolnjevanje zahteve ni zagotovljeno, ker nekateri strežniki blokiranja obravnavajo drugače. Javne objave bodo morda še vedno vidne neprijavljenim uporabnikom.",
"block_modal.remote_users_caveat": "Strežnik {domain} bomo pozvali, naj spoštuje vašo odločitev. Kljub temu pa ni gotovo, da bo strežnik prošnjo upošteval, saj nekateri strežniki blokiranja obravnavajo drugače. Javne objave bodo morda še vedno vidne neprijavljenim uporabnikom.",
"block_modal.show_less": "Pokaži manj",
"block_modal.show_more": "Pokaži več",
"block_modal.they_cant_mention": "Ne morejo vas omenjati ali vam slediti.",
"block_modal.they_cant_see_posts": "Ne vidijo vaših objav, vi pa ne njihovih.",
"block_modal.they_will_know": "Ne morejo videti, da so blokirani.",
"block_modal.title": "Blokiraj uporabnika?",
"block_modal.you_wont_see_mentions": "Objav, ki jih omenjajo, ne boste videli.",
"boost_modal.combo": "Če želite preskočiti to, lahko pritisnete {combo}",
"boost_modal.reblog": "Izpostavi objavo?",
"block_modal.they_cant_mention": "Ne more vas omenjati ali vam slediti.",
"block_modal.they_cant_see_posts": "Ne vidi vaših objav, vi pa ne njegovih.",
"block_modal.they_will_know": "Ne more videti, da je blokiran.",
"block_modal.title": "Blokiram uporabnika?",
"block_modal.you_wont_see_mentions": "Objav, ki ga omenjajo, ne boste videli.",
"boost_modal.combo": "Če želite naslednjič to preskočiti, lahko pritisnete {combo}",
"boost_modal.reblog": "Izpostavim objavo?",
"boost_modal.undo_reblog": "Ali želite preklicati izpostavitev objave?",
"bundle_column_error.copy_stacktrace": "Kopiraj poročilo o napaki",
"bundle_column_error.error.body": "Zahtevane strani ni mogoče upodobiti. Vzrok težave je morda hrošč v naši kodi ali pa nezdružljivost z brskalnikom.",
"bundle_column_error.error.title": "Oh, ne!",
"bundle_column_error.network.body": "Pri poskusu nalaganja te strani je prišlo do napake. Vzrok je lahko začasna težava z vašo internetno povezavo ali s tem strežnikom.",
"bundle_column_error.network.title": "Napaka v omrežju",
"bundle_column_error.network.title": "Omrežna napaka",
"bundle_column_error.retry": "Poskusi znova",
"bundle_column_error.return": "Nazaj domov",
"bundle_column_error.routing.body": "Zahtevane strani ni mogoče najti. Ali ste prepričani, da je naslov URL v naslovni vrstici pravilen?",
"bundle_column_error.routing.title": "404",
"bundle_modal_error.close": "Zapri",
"bundle_modal_error.message": "Med nalaganjem prikaza je prišlo do napake.",
"bundle_modal_error.retry": "Poskusi znova",
"closed_registrations.other_server_instructions": "Ker je Mastodon decentraliziran, lahko ustvarite račun na drugem strežniku in ste še vedno v interakciji s tem.",
"closed_registrations_modal.description": "Odpiranje računa na {domain} trenutno ni možno, upoštevajte pa, da ne potrebujete računa prav na {domain}, da bi uporabljali Mastodon.",
"closed_registrations_modal.description": "Odpiranje računa na domeni {domain} trenutno ni možno, upoštevajte pa, da ne potrebujete računa prav na domeni {domain}, da bi uporabljali Mastodon.",
"closed_registrations_modal.find_another_server": "Najdi drug strežnik",
"closed_registrations_modal.preamble": "Mastodon je decentraliziran, kar pomeni, da ni pomembno, kje ustvarite svoj račun; od koder koli je omogočeno sledenje in interakcija z vsemi s tega strežnika. Strežnik lahko gostite tudi sami!",
"closed_registrations_modal.preamble": "Mastodon je decentraliziran, kar pomeni, da ni pomembno, kje ustvarite svoj račun; od koder koli je mogoče slediti in komunicirati z vsemi s tega strežnika. Strežnik lahko gostite tudi sami!",
"closed_registrations_modal.title": "Registracija v Mastodon",
"column.about": "O programu",
"column.blocks": "Blokirani uporabniki",
@ -137,7 +154,7 @@
"column.edit_list": "Uredi seznam",
"column.favourites": "Priljubljeni",
"column.firehose": "Viri v živo",
"column.follow_requests": "Sledi prošnjam",
"column.follow_requests": "Prošnje za sledenje",
"column.home": "Domov",
"column.list_members": "Upravljaj člane seznama",
"column.lists": "Seznami",
@ -155,25 +172,25 @@
"column_search.cancel": "Prekliči",
"column_subheading.settings": "Nastavitve",
"community.column_settings.local_only": "Samo krajevno",
"community.column_settings.media_only": "Samo mediji",
"community.column_settings.media_only": "Samo predstavnosti",
"community.column_settings.remote_only": "Samo oddaljeno",
"compose.language.change": "Spremeni jezik",
"compose.language.search": "Poišči jezik ...",
"compose.language.search": "Poišči jezike ...",
"compose.published.body": "Objavljeno.",
"compose.published.open": "Odpri",
"compose.saved.body": "Objava shranjena.",
"compose_form.direct_message_warning_learn_more": "Izvej več",
"compose_form.encryption_warning": "Objave na Mastodonu niso šifrirane od kraja do kraja. Prek Mastodona ne delite nobenih občutljivih informacij.",
"compose_form.direct_message_warning_learn_more": "Več o tem",
"compose_form.encryption_warning": "Objave na Mastodonu niso šifrirane od konca do konca. Prek Mastodona ne delite nobenih občutljivih informacij.",
"compose_form.hashtag_warning": "Ta objava ne bo navedena pod nobenim ključnikom, ker ni javna. Samo javne objave lahko iščete s ključniki.",
"compose_form.lock_disclaimer": "Vaš račun ni {locked}. Vsakdo vam lahko sledi in si ogleda objave, ki so namenjene samo sledilcem.",
"compose_form.lock_disclaimer.lock": "zaklenjen",
"compose_form.placeholder": "O čem razmišljate?",
"compose_form.poll.duration": "Trajanje ankete",
"compose_form.poll.multiple": "Več možnosti",
"compose_form.poll.multiple": "Izbira več možnosti",
"compose_form.poll.option_placeholder": "Možnost {number}",
"compose_form.poll.single": "Ena izbira",
"compose_form.poll.switch_to_multiple": "Spremenite anketo, da omogočite več izbir",
"compose_form.poll.switch_to_single": "Spremenite anketo, da omogočite eno izbiro",
"compose_form.poll.single": "Izbira ene možnosti",
"compose_form.poll.switch_to_multiple": "Spremenite anketo, da omogočite izbiro več možnosti",
"compose_form.poll.switch_to_single": "Spremenite anketo, da omogočite izbiro ene možnosti",
"compose_form.poll.type": "Slog",
"compose_form.publish": "Objavi",
"compose_form.publish_form": "Objavi",
@ -191,17 +208,24 @@
"confirmations.delete_list.message": "Ali ste prepričani, da želite trajno izbrisati ta seznam?",
"confirmations.delete_list.title": "Želite izbrisati seznam?",
"confirmations.discard_edit_media.confirm": "Opusti",
"confirmations.discard_edit_media.message": "Imate ne shranjene spremembe za medijski opis ali predogled; jih želite kljub temu opustiti?",
"confirmations.discard_edit_media.message": "Spremenjenega opisa predstavnosti ali predogleda niste shranili. Želite spremembe kljub temu opustiti?",
"confirmations.edit.confirm": "Uredi",
"confirmations.edit.message": "Urejanje bo prepisalo sporočilo, ki ga trenutno sestavljate. Ali ste prepričani, da želite nadaljevati?",
"confirmations.edit.title": "Želite prepisati objavo?",
"confirmations.follow_to_list.confirm": "Sledi in dodaj na seznam",
"confirmations.follow_to_list.message": "Osebi {name} morate slediti, preden jo lahko dodate na seznam.",
"confirmations.follow_to_list.title": "Naj sledim uporabniku?",
"confirmations.logout.confirm": "Odjava",
"confirmations.logout.message": "Ali ste prepričani, da se želite odjaviti?",
"confirmations.logout.title": "Se želite odjaviti?",
"confirmations.mute.confirm": "Utišanje",
"confirmations.missing_alt_text.confirm": "Dodaj nadomestno besedilo",
"confirmations.missing_alt_text.message": "Vaša objava vsebuje predstavnosti brez nadomestnega besedila. Če jih dodatno opišete, bodo dostopne večji množici ljudi.",
"confirmations.missing_alt_text.secondary": "Vseeno objavi",
"confirmations.missing_alt_text.title": "Dodam nadomestno besedilo?",
"confirmations.mute.confirm": "Utišaj",
"confirmations.redraft.confirm": "Izbriši in preoblikuj",
"confirmations.redraft.message": "Ali ste prepričani, da želite izbrisati ta status in ga preoblikovati? Vzljubi in izpostavitve bodo izgubljeni, odgovori na izvirno objavo pa bodo osiroteli.",
"confirmations.redraft.title": "Želite izbrisati in predelati objavo?",
"confirmations.redraft.message": "Ali ste prepričani, da želite izbrisati to objavo in jo preoblikovati? Izkazi priljubljenosti in izpostavitve bodo izgubljeni, odgovori na izvirno objavo pa bodo osiroteli.",
"confirmations.redraft.title": "Želite izbrisati in preoblikovati objavo?",
"confirmations.reply.confirm": "Odgovori",
"confirmations.reply.message": "Odgovarjanje bo prepisalo sporočilo, ki ga trenutno sestavljate. Ali ste prepričani, da želite nadaljevati?",
"confirmations.reply.title": "Želite prepisati objavo?",
@ -217,7 +241,7 @@
"conversation.with": "Z {names}",
"copy_icon_button.copied": "Kopirano v odložišče",
"copypaste.copied": "Kopirano",
"copypaste.copy_to_clipboard": "Kopiraj na odložišče",
"copypaste.copy_to_clipboard": "Kopiraj v odložišče",
"directory.federated": "Iz znanega fediverzuma",
"directory.local": "Samo iz {domain}",
"directory.new_arrivals": "Novi prišleki",
@ -226,28 +250,34 @@
"disabled_account_banner.text": "Vaš račun {disabledAccount} je trenutno onemogočen.",
"dismissable_banner.community_timeline": "To so najnovejše javne objave oseb, katerih računi gostujejo na {domain}.",
"dismissable_banner.dismiss": "Opusti",
"dismissable_banner.explore_links": "Danes po fediverzumu najbolj odmevajo te novice. Višje na seznamu so novejše vesti bolj raznolikih objaviteljev.",
"dismissable_banner.explore_statuses": "Danes so po fediverzumu pozornost pritegnile te objave. Višje na seznamu so novejše, bolj izpostavljene in bolj priljubljene objave.",
"dismissable_banner.explore_tags": "Danes se po fediverzumu najpogosteje uporabljajo ti ključniki. Višje na seznamu so ključniki, ki jih uporablja več različnih ljudi.",
"dismissable_banner.public_timeline": "To so najnovejše javne objave ljudi s fediverzuma, ki jim sledijo ljudje na domeni {domain}.",
"domain_block_modal.block": "Blokiraj strežnik",
"domain_block_modal.block_account_instead": "Namesto tega blokiraj @{name}",
"domain_block_modal.they_can_interact_with_old_posts": "Osebe s tega strežnika se lahko odzivajo na vaše stare objave.",
"domain_block_modal.they_cant_follow": "Nihče s tega strežnika vam ne more slediti.",
"domain_block_modal.they_wont_know": "Ne bodo vedeli, da so blokirani.",
"domain_block_modal.title": "Blokiraj domeno?",
"domain_block_modal.you_will_lose_num_followers": "Izgubili boste {followersCount, plural, one {{followersCountDisplay} sledilca} two {{followersCountDisplay} sledilca} few {{followersCountDisplay} sledilce} other {{followersCountDisplay} sledilcev}} in {followingCount, plural, one {{followingCountDisplay} osebo, ki ji sledite} two {{followingCountDisplay} osebi, ki jima sledite} few {{followingCountDisplay} osebe, ki jim sledite} other {{followingCountDisplay} oseb, ki jim sledite}}.",
"domain_block_modal.you_will_lose_relationships": "Izgubili boste vse sledilce in ljudi, ki jim sledite na tem strežniku.",
"domain_block_modal.you_wont_see_posts": "Objav ali obvestil uporabnikov s tega strežnika ne boste videli.",
"domain_pill.activitypub_lets_connect": "Omogoča vam povezovanje in interakcijo z ljudmi, ki niso samo na Mastodonu, ampak tudi na drugih družabnih platformah.",
"domain_pill.activitypub_like_language": "Protokol ActivityPub je kot jezik, s katerim se Mastodon pogovarja z drugimi družabnimi omrežji.",
"domain_pill.activitypub_lets_connect": "Omogoča vam povezovanje in interakcijo z ljudmi, ki niso samo na Mastodonu, ampak tudi na drugih družbenih platformah.",
"domain_pill.activitypub_like_language": "Protokol ActivityPub je kot jezik, v katerem se Mastodon pogovarja z drugimi družabnimi omrežji.",
"domain_pill.server": "Strežnik",
"domain_pill.their_handle": "Njihova ročica:",
"domain_pill.their_server": "Njihovo digitalno domovanje, kjer bivajo vse njihove objave.",
"domain_pill.their_username": "Njihov edinstveni identifikator na njihovem strežniku. Uporabnike z istim uporabniškim imenom lahko najdete na različnih strežnikih.",
"domain_pill.their_handle": "Njegova/njena ročica:",
"domain_pill.their_server": "Njegovo/njeno digitalno domovanje, kjer bivajo vse njegove/njene objave.",
"domain_pill.their_username": "Njegov/njen edinstveni identifikator na njegovem/njenem strežniku. Uporabnike z istim uporabniškim imenom lahko najdete na različnih strežnikih.",
"domain_pill.username": "Uporabniško ime",
"domain_pill.whats_in_a_handle": "Kaj je v ročici?",
"domain_pill.who_they_are": "Ker ročice povedo, kdo je kdo in kje so, ste lahko z osebami v interakciji prek družabnega spleta <button>platform, ki jih poganja ActivityPub</button>.",
"domain_pill.who_you_are": "Ker ročice povedo, kdo ste in kje ste, ste lahko z osebami v interakciji prek družabnega spleta <button>platform, ki jih poganja ActivityPub</button>.",
"domain_pill.who_they_are": "Ker ročice povedo, kdo je kdo in kje je, lahko komunicirate z ljudmi po vsem spletu družbenih <button>platform, ki jih poganja ActivityPub</button>.",
"domain_pill.who_you_are": "Ker ročice povedo, kdo ste in kje ste, lahko komunicirate z ljudmi po vsem spletu družbenih <button>platform, ki jih poganja ActivityPub</button>.",
"domain_pill.your_handle": "Vaša ročica:",
"domain_pill.your_server": "Vaše digitalno domovanje, kjer bivajo vse vaše objave. Vam ta ni všeč? Prenesite ga med strežniki kadar koli in z njim tudi svoje sledilce.",
"domain_pill.your_server": "Vaše digitalno domovanje, kjer bivajo vse vaše objave. Vam ni všeč? Kadar koli ga prenesite med strežniki in z njim tudi svoje sledilce.",
"domain_pill.your_username": "Vaš edinstveni identifikator na tem strežniku. Uporabnike z istim uporabniškim imenom je možno najti na različnih strežnikih.",
"embed.instructions": "Vstavite to objavo na svojo spletno stran tako, da kopirate spodnjo kodo.",
"embed.preview": "Tako bo izgledalo:",
"embed.preview": "Takole bo videti:",
"emoji_button.activity": "Dejavnost",
"emoji_button.clear": "Počisti",
"emoji_button.custom": "Po meri",
@ -263,32 +293,32 @@
"emoji_button.search_results": "Rezultati iskanja",
"emoji_button.symbols": "Simboli",
"emoji_button.travel": "Potovanja in kraji",
"empty_column.account_hides_collections": "Ta uporabnik se je odločil, da te informacije ne bo dal na voljo",
"empty_column.account_hides_collections": "Ta uporabnik se je odločil, da te informacije ne bo delil",
"empty_column.account_suspended": "Račun je suspendiran",
"empty_column.account_timeline": "Tukaj ni objav!",
"empty_column.account_unavailable": "Profil ni na voljo",
"empty_column.blocks": "Niste še blokirali nobenega uporabnika.",
"empty_column.bookmarked_statuses": "Zaenkrat še nimate zaznamovanih objav. Ko objavo zaznamujete, se pojavi tukaj.",
"empty_column.community": "Krajevna časovnica je prazna. Napišite nekaj javnega, da se bo snežna kepa zakotalila!",
"empty_column.community": "Krajevna časovnica je prazna. Napišite nekaj javnega, da se začne polniti!",
"empty_column.direct": "Nimate še nobenih zasebnih omemb. Ko jih boste poslali ali prejeli, se bodo prikazale tukaj.",
"empty_column.domain_blocks": "Zaenkrat ni blokiranih domen.",
"empty_column.explore_statuses": "Trenutno ni nič v trendu. Preverite znova kasneje!",
"empty_column.favourited_statuses": "Nimate priljubljenih objav. Ko boste vzljubili kakšno, bo prikazana tukaj.",
"empty_column.favourites": "Nihče še ni vzljubil te objave. Ko jo bo nekdo, se bo pojavila tukaj.",
"empty_column.explore_statuses": "Trenutno ni novih trendov. Preverite znova kasneje!",
"empty_column.favourited_statuses": "Nimate priljubljenih objav. Ko boste kakšno dodali med priljubljene, bo prikazana tukaj.",
"empty_column.favourites": "Nihče še ni vzljubil te objave. Ko jo bo nekdo, bo naveden tukaj.",
"empty_column.follow_requests": "Nimate prošenj za sledenje. Ko boste prejeli kakšno, se bo prikazala tukaj.",
"empty_column.followed_tags": "Zaenkrat ne sledite še nobenemu ključniku. Ko boste, se bodo pojavili tukaj.",
"empty_column.hashtag": "V tem ključniku še ni nič.",
"empty_column.home": "Vaša domača časovnica je prazna! Sledite več osebam, da jo zapolnite. {suggestions}",
"empty_column.list": "Na tem seznamu ni ničesar. Ko bodo člani tega seznama objavili nove statuse, se bodo pojavili tukaj.",
"empty_column.followed_tags": "Zaenkrat ne sledite še nobenemu ključniku. Ko boste, se bo pojavil tukaj.",
"empty_column.hashtag": "V tem ključniku ni še nič.",
"empty_column.home": "Vaša domača časovnica je prazna! Sledite več osebam, da jo zapolnite.",
"empty_column.list": "Na tem seznamu ni ničesar. Ko bodo člani tega seznama kaj objavili, se bodo te objave pojavile tukaj.",
"empty_column.mutes": "Niste utišali še nobenega uporabnika.",
"empty_column.notification_requests": "Vse prebrano! Tu ni ničesar več. Ko prejmete nova obvestila, se bodo pojavila tu glede na vaše nastavitve.",
"empty_column.notifications": "Nimate še nobenih obvestil. Povežite se z drugimi, da začnete pogovor.",
"empty_column.public": "Tukaj ni ničesar! Da ga napolnite, napišite nekaj javnega ali pa ročno sledite uporabnikom iz drugih strežnikov",
"empty_column.public": "Tukaj ni ničesar! Napišite nekaj javnega ali pa ročno sledite uporabnikom iz drugih strežnikov, da se bo napolnilo",
"error.unexpected_crash.explanation": "Zaradi hrošča v naši kodi ali težave z združljivostjo brskalnika te strani ni mogoče ustrezno prikazati.",
"error.unexpected_crash.explanation_addons": "Te strani ni mogoče ustrezno prikazati. To napako najverjetneje povzroča dodatek briskalnika ali samodejna orodja za prevajanje.",
"error.unexpected_crash.explanation_addons": "Te strani ni mogoče ustrezno prikazati. To napako najverjetneje povzroča dodatek brskalnika ali samodejna orodja za prevajanje.",
"error.unexpected_crash.next_steps": "Poskusite osvežiti stran. Če to ne pomaga, boste morda še vedno lahko uporabljali Mastodon prek drugega brskalnika ali z domorodno aplikacijo.",
"error.unexpected_crash.next_steps_addons": "Poskusite jih onemogočiti in osvežiti stran. Če to ne pomaga, boste morda še vedno lahko uporabljali Mastodon prek drugega brskalnika ali z domorodno aplikacijo.",
"errors.unexpected_crash.copy_stacktrace": "Kopiraj sledenje skladu na odložišče",
"errors.unexpected_crash.copy_stacktrace": "Kopiraj sled sklada na odložišče",
"errors.unexpected_crash.report_issue": "Prijavi težavo",
"explore.suggested_follows": "Ljudje",
"explore.title": "Razišči",
@ -297,7 +327,7 @@
"explore.trending_tags": "Ključniki",
"filter_modal.added.context_mismatch_explanation": "Ta kategorija filtra ne velja za kontekst, v katerem ste dostopali do te objave. Če želite, da je objava filtrirana tudi v tem kontekstu, morate urediti filter.",
"filter_modal.added.context_mismatch_title": "Neujemanje konteksta!",
"filter_modal.added.expired_explanation": "Ta kategorija filtra je pretekla, morali boste spremeniti datum veljavnosti, da bo veljal še naprej.",
"filter_modal.added.expired_explanation": "Ta kategorija filtra je pretekla. Morali boste spremeniti datum veljavnosti, da bo veljal še naprej.",
"filter_modal.added.expired_title": "Filter je pretekel!",
"filter_modal.added.review_and_configure": "Če želite pregledati in nadalje prilagoditi kategorijo filtra, obiščite {settings_link}.",
"filter_modal.added.review_and_configure_title": "Nastavitve filtra",
@ -312,6 +342,7 @@
"filter_modal.select_filter.title": "Filtriraj to objavo",
"filter_modal.title.status": "Filtrirajte objavo",
"filter_warning.matches_filter": "Se ujema s filtrom »<span>{title}</span>«",
"filtered_notifications_banner.pending_requests": "Od {count, plural, =0 {nikogar, ki bi ga poznali} one {nekoga, ki ga morda poznate} two {dveh ljudi, ki ju morda poznate} other {ljudi, ki jih morda poznate}}",
"filtered_notifications_banner.title": "Filtrirana obvestila",
"firehose.all": "Vse",
"firehose.local": "Ta strežnik",
@ -360,9 +391,12 @@
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} objava} two {{counter} objavi} few {{counter} objav} other {{counter} objav}}",
"hashtag.follow": "Sledi ključniku",
"hashtag.unfollow": "Nehaj slediti ključniku",
"hashtags.and_other": "…in še {count, plural, other {#}}",
"hashtags.and_other": "… in še {count, plural, other {#}}",
"hints.profiles.followers_may_be_missing": "Sledilci za ta profil morda manjkajo.",
"hints.profiles.follows_may_be_missing": "Osebe, ki jim ta profil sledi, morda manjkajo.",
"hints.profiles.posts_may_be_missing": "Nekatere objave s tega profila morda manjkajo.",
"hints.profiles.see_more_followers": "Pokaži več sledilcev na {domain}",
"hints.profiles.see_more_follows": "Pokaži več sledenih ljudi na zbirališču {domain}",
"hints.profiles.see_more_posts": "Pokaži več objav na {domain}",
"hints.threads.replies_may_be_missing": "Odgovori z drugih strežnikov morda manjkajo.",
"hints.threads.see_more": "Pokaži več odgovorov na {domain}",
@ -373,9 +407,25 @@
"home.pending_critical_update.link": "Glejte posodobitve",
"home.pending_critical_update.title": "Na voljo je kritična varnostna posodobbitev!",
"home.show_announcements": "Pokaži obvestila",
"ignore_notifications_modal.disclaimer": "Mastodon ne more obveščati uporabnikov, da ste prezrli njihova obvestila. Tudi če jih prezrete, jih lahko uporabniki še vedno pošiljajo.",
"ignore_notifications_modal.filter_instead": "Raje filtriraj",
"ignore_notifications_modal.filter_to_act_users": "Še vedno boste lahko sprejeli, zavrnili ali prijavili uporabnike",
"ignore_notifications_modal.filter_to_avoid_confusion": "Filtriranje pomaga pri izogibanju morebitni zmedi",
"ignore_notifications_modal.filter_to_review_separately": "Filtrirana obvestila lahko pregledate ločeno",
"ignore_notifications_modal.ignore": "Prezri obvestila",
"ignore_notifications_modal.limited_accounts_title": "Naj prezrem obvestila moderiranih računov?",
"ignore_notifications_modal.new_accounts_title": "Naj prezrem obvestila novih računov?",
"ignore_notifications_modal.not_followers_title": "Naj prezrem obvestila ljudi, ki vam ne sledijo?",
"ignore_notifications_modal.not_following_title": "Naj prezrem obvestila ljudi, ki jim ne sledite?",
"ignore_notifications_modal.private_mentions_title": "Naj prezrem obvestila od nezaželenih zasebnih omemb?",
"info_button.label": "Pomoč",
"info_button.what_is_alt_text": "<h1>Kaj je nadomestno besedilo?</h1> <p>Z nadomestnim besedilom dodatno opišemo sliko in tako pomagamo slabovidnim, ljudem s slabo internetno povezavo in tistim, ki jim manjka kontekst.</p> <p>Vaša objava bo veliko bolj dostopna in razumljiva, če boste napisali jasno, jedrnato in nepristransko nadomestno besedilo.</p> <ul> <li>Izpostavite pomembne elemente.</li> <li>Povzemite besedilo v slikah.</li> <li>Pišite v celih stavkih.</li> <li>Zajemite bistvo, ne dolgovezite.</li> <li>Opišite težnje in ključna odkritja, ki ste jih razbrali iz zapletenih grafik (npr. diagramov ali zemljevidov).</li> </ul>",
"interaction_modal.action.favourite": "Med priljubljene lahko dodate, ko se vpišete v svoj račun.",
"interaction_modal.action.follow": "Sledite lahko šele, ko se vpišete v svoj račun.",
"interaction_modal.action.reblog": "Izpostavite lahko šele, ko se vpišete v svoj račun.",
"interaction_modal.action.reply": "Odgovorite lahko šele, ko se vpišete v svoj račun.",
"interaction_modal.action.vote": "Glasujete lahko šele, ko se vpišete v svoj račun.",
"interaction_modal.go": "Naprej",
"interaction_modal.no_account_yet": "Še nimate računa?",
"interaction_modal.on_another_server": "Na drugem strežniku",
"interaction_modal.on_this_server": "Na tem strežniku",
@ -383,6 +433,8 @@
"interaction_modal.title.follow": "Sledi {name}",
"interaction_modal.title.reblog": "Izpostavi objavo {name}",
"interaction_modal.title.reply": "Odgovori na objavo {name}",
"interaction_modal.title.vote": "Izpolni anketo uporabnika/ce {name}",
"interaction_modal.username_prompt": "Npr. {example}",
"intervals.full.days": "{number, plural, one {# dan} two {# dni} few {# dni} other {# dni}}",
"intervals.full.hours": "{number, plural, one {# ura} two {# uri} few {# ure} other {# ur}}",
"intervals.full.minutes": "{number, plural, one {# minuta} two {# minuti} few {# minute} other {# minut}}",
@ -407,7 +459,7 @@
"keyboard_shortcuts.muted": "Odpri seznam utišanih uporabnikov",
"keyboard_shortcuts.my_profile": "Odprite svoj profil",
"keyboard_shortcuts.notifications": "Odpri stolpec z obvestili",
"keyboard_shortcuts.open_media": "Odpri medij",
"keyboard_shortcuts.open_media": "Odpri predstavnost",
"keyboard_shortcuts.pinned": "Odpri seznam pripetih objav",
"keyboard_shortcuts.profile": "Odpri avtorjev profil",
"keyboard_shortcuts.reply": "Odgovori na objavo",
@ -416,26 +468,35 @@
"keyboard_shortcuts.spoilers": "Pokaži/skrij polje CW",
"keyboard_shortcuts.start": "Odpri stolpec \"začni\"",
"keyboard_shortcuts.toggle_hidden": "Pokaži/skrij besedilo za CW",
"keyboard_shortcuts.toggle_sensitivity": "Pokaži/skrij medije",
"keyboard_shortcuts.toggle_sensitivity": "Pokaži/skrij predstavnosti",
"keyboard_shortcuts.toot": "Začni povsem novo objavo",
"keyboard_shortcuts.translate": "za prevod objave",
"keyboard_shortcuts.unfocus": "Odstrani pozornost z območja za sestavljanje besedila/iskanje",
"keyboard_shortcuts.up": "Premakni navzgor po seznamu",
"lightbox.close": "Zapri",
"lightbox.next": "Naslednji",
"lightbox.previous": "Prejšnji",
"lightbox.zoom_in": "Približaj na dejansko velikost",
"lightbox.zoom_out": "Čez cel prikaz",
"limited_account_hint.action": "Vseeno pokaži profil",
"limited_account_hint.title": "Profil so moderatorji strežnika {domain} skrili.",
"link_preview.author": "Avtor_ica {name}",
"link_preview.author": "Avtor/ica {name}",
"link_preview.more_from_author": "Več od {name}",
"link_preview.shares": "{count, plural, one {{counter} objava} two {{counter} objavi} few {{counter} objave} other {{counter} objav}}",
"lists.add_member": "Dodaj",
"lists.add_to_list": "Dodaj na seznam",
"lists.add_to_lists": "Dodaj {name} na sezname",
"lists.create": "Ustvari",
"lists.create_a_list_to_organize": "Uredite si domači vir z novim seznamom",
"lists.create_list": "Ustvari seznam",
"lists.delete": "Izbriši seznam",
"lists.done": "Opravljeno",
"lists.edit": "Uredi seznam",
"lists.exclusive": "Skrij člane v domovanju",
"lists.exclusive_hint": "Objave vseh, ki so na tem seznamu, se ne pokažejo v vašem domačem viru. Tako se izognete podvojenim objavam.",
"lists.find_users_to_add": "Poišči člane za dodajanje",
"lists.list_members": "Člani seznama",
"lists.list_members_count": "{count, plural, one {# član} two {# člana} few {# člani} other {# članov}}",
"lists.list_name": "Ime seznama",
"lists.new_list_name": "Novo ime seznama",
"lists.no_lists_yet": "Ni seznamov.",
@ -446,6 +507,8 @@
"lists.replies_policy.list": "Članom seznama",
"lists.replies_policy.none": "Nikomur",
"lists.save": "Shrani",
"lists.search": "Iskanje",
"lists.show_replies_to": "Vključi odgovore, katerih pošiljatelji so člani seznama in prejemniki",
"load_pending": "{count, plural, one {# nov element} two {# nova elementa} few {# novi elementi} other {# novih elementov}}",
"loading_indicator.label": "Nalaganje …",
"media_gallery.hide": "Skrij",
@ -493,9 +556,17 @@
"notification.admin.report_statuses": "{name} je prijavil/a {target} zaradi {category}",
"notification.admin.report_statuses_other": "{name} je prijavil/a {target}",
"notification.admin.sign_up": "{name} se je vpisal/a",
"notification.admin.sign_up.name_and_others": "Prijavili so se {name} in {count, plural, one {# druga oseba} two {# drugi osebi} few {# druge osebe} other {# drugih oseb}}",
"notification.annual_report.message": "Čaka vas vaš #Wrapstodon {year}! Razkrijte svoje letošnje nepozabne trenutke na Mastodonu!",
"notification.annual_report.view": "Pokaži #Wrapstodon",
"notification.favourite": "{name} je vzljubil/a vašo objavo",
"notification.favourite.name_and_others_with_link": "{name} in <a>{count, plural, one {# druga oseba} two {# drugi osebi} few {# druge osebe} other {# drugih oseb}}</a> je dodalo vašo objavo med priljubljene",
"notification.favourite_pm": "{name} je dodalo vašo zasebno omembo med priljubljene",
"notification.favourite_pm.name_and_others_with_link": "{name} in <a>{count, plural, one {# druga oseba} two {# drugi osebi} few {# druge osebe} other {# drugih oseb}}</a> je dodalo vašo zasebno omembo med priljubljene",
"notification.follow": "{name} vam sledi",
"notification.follow.name_and_others": "{name} in {count, plural, one {<a># druga oseba</a> sta ti sledila} two {<a># drugi osebi</a> so ti sledili} few {<a># druge osebe</a> so ti sledili} other {<a># drugih oseb</a> ti je sledilo}}",
"notification.follow_request": "{name} vam želi slediti",
"notification.follow_request.name_and_others": "{name} in {count, plural, one {# druga oseba bi ti rada sledila} two {# drugi osebi bi ti radi sledili} few {# druge osebe bi ti radi sledili} other {# drugih oseb bi ti radi sledili}}",
"notification.label.mention": "Omemba",
"notification.label.private_mention": "Zasebna omemba",
"notification.label.private_reply": "Zasebni odgovor",
@ -514,6 +585,7 @@
"notification.own_poll": "Vaša anketa je zaključena",
"notification.poll": "Anketa, v kateri ste sodelovali, je zaključena",
"notification.reblog": "{name} je izpostavila/a vašo objavo",
"notification.reblog.name_and_others_with_link": "{name} in <a>{count, plural, one {# druga oseba</a> sta izpostavila tvojo objavo} two {# drugi osebi</a> so izpostavili tvojo objavo} few {# druge osebe</a> so izpostavili tvojo objavo} other {# drugih oseb</a> so izpostavili tvojo objavo}}",
"notification.relationships_severance_event": "Povezave z {name} prekinjene",
"notification.relationships_severance_event.account_suspension": "Skrbnik na {from} je suspendiral račun {target}, kar pomeni, da od računa ne morete več prejemati posodobitev ali imeti z njim interakcij.",
"notification.relationships_severance_event.domain_block": "Skrbnik na {from} je blokiral domeno {target}, vključno z vašimi sledilci ({followersCount}) in {followingCount, plural, one {# računom, ki mu sledite} two {# računoma, ki jima sledite} few {# računi, ki jim sledite} other {# računi, ki jim sledite}}.",
@ -522,12 +594,21 @@
"notification.status": "{name} je pravkar objavil/a",
"notification.update": "{name} je uredil(a) objavo",
"notification_requests.accept": "Sprejmi",
"notification_requests.accept_multiple": "{count, plural, one {Sprejmi # prošnjo …} two {Sprejmi # prošnji …} few {Sprejmi # prošnje …} other {Sprejmi # prošenj …}}",
"notification_requests.confirm_accept_multiple.button": "{count, plural, one {Sprejmi prošnjo} two {Sprejmi prošnji} other {Sprejmi prošnje}}",
"notification_requests.confirm_accept_multiple.message": "Sprejeti nameravate {count, plural, one {eno prošnjo za obvestila} two {dve prošnji za obvestila} few {# prošnje za obvestila} other {# prošenj za obvestila}}. Ali ste prepričani?",
"notification_requests.confirm_accept_multiple.title": "Ali želite sprejeti zahteve za obvestila?",
"notification_requests.confirm_dismiss_multiple.button": "{count, plural, one {Zavrni prošnjo} two {Zavrni prošnji} other {Zavrni prošnje}}",
"notification_requests.confirm_dismiss_multiple.message": "Zavrniti nameravate {count, plural, one {eno prošnjo za obvestila} two {dve prošnji za obvestila} few {# prošnje za obvestila} other {# prošenj za obvestila}}. Do {count, plural, one {nje} two {njiju} other {njih}} ne boste več mogli dostopati. Ali ste prepričani?",
"notification_requests.confirm_dismiss_multiple.title": "Želite opustiti zahteve za obvestila?",
"notification_requests.dismiss": "Zavrni",
"notification_requests.dismiss_multiple": "{count, plural, one {Zavrni # prošnjo …} two {Zavrni # prošnji …} few {Zavrni # prošnje …} other {Zavrni # prošenj …}}",
"notification_requests.edit_selection": "Uredi",
"notification_requests.exit_selection": "Opravljeno",
"notification_requests.explainer_for_limited_account": "Obvestila za ta račun so bila filtrirana, ker je ta račun omejil moderator.",
"notification_requests.explainer_for_limited_remote_account": "Obvestila za ta račun so bila filtrirana, ker je račun ali njegov strežnik omejil moderator.",
"notification_requests.maximize": "Maksimiraj",
"notification_requests.minimize_banner": "Zloži pasico filtriranih obvestil",
"notification_requests.notifications_from": "Obvestila od {name}",
"notification_requests.title": "Filtrirana obvestila",
"notification_requests.view": "Pokaži obvestila",
@ -542,6 +623,7 @@
"notifications.column_settings.filter_bar.category": "Vrstica za hitro filtriranje",
"notifications.column_settings.follow": "Novi sledilci:",
"notifications.column_settings.follow_request": "Nove prošnje za sledenje:",
"notifications.column_settings.group": "Združi",
"notifications.column_settings.mention": "Omembe:",
"notifications.column_settings.poll": "Rezultati ankete:",
"notifications.column_settings.push": "Potisna obvestila",
@ -568,6 +650,9 @@
"notifications.policy.accept": "Sprejmi",
"notifications.policy.accept_hint": "Pokaži med obvestili",
"notifications.policy.drop": "Prezri",
"notifications.policy.drop_hint": "Pošlji v pozabo, od koder se nikdar nič ne vrne",
"notifications.policy.filter": "Filtriraj",
"notifications.policy.filter_hint": "Pošlji med filtrirana prejeta obvestila",
"notifications.policy.filter_limited_accounts_hint": "Omejeno s strani moderatorjev strežnika",
"notifications.policy.filter_limited_accounts_title": "Moderirani računi",
"notifications.policy.filter_new_accounts.hint": "Ustvarjen v {days, plural, one {zadnjem # dnevu} two {zadnjih # dnevih} few {zadnjih # dnevih} other {zadnjih # dnevih}}",
@ -585,12 +670,14 @@
"onboarding.follows.back": "Nazaj",
"onboarding.follows.done": "Opravljeno",
"onboarding.follows.empty": "Žal trenutno ni mogoče prikazati nobenih rezultatov. Lahko poskusite z iskanjem ali brskanjem po strani za raziskovanje, da poiščete osebe, ki jim želite slediti, ali poskusite znova pozneje.",
"onboarding.follows.search": "Išči",
"onboarding.follows.title": "Vaš prvi korak je, da sledite ljudem",
"onboarding.profile.discoverable": "Naj bo moj profil mogoče najti",
"onboarding.profile.discoverable_hint": "Ko se odločite za razkrivanje na Mastodonu, se lahko vaše objave pojavijo v rezultatih iskanja in trendih, vaš profil pa se lahko predlaga ljudem, ki imajo podobne interese kot vi.",
"onboarding.profile.display_name": "Pojavno ime",
"onboarding.profile.display_name_hint": "Vaše polno ime ali lažno ime ...",
"onboarding.profile.note": "Biografija",
"onboarding.profile.note_hint": "Druge osebe lahko @omenite ali #ključite ...",
"onboarding.profile.note_hint": "Lahko @omenite druge osebe ali dodate #ključnike ...",
"onboarding.profile.save_and_continue": "Shrani in nadaljuj",
"onboarding.profile.title": "Nastavitev profila",
"onboarding.profile.upload_avatar": "Naloži sliko profila",
@ -610,6 +697,7 @@
"poll_button.remove_poll": "Odstrani anketo",
"privacy.change": "Spremeni zasebnost objave",
"privacy.direct.long": "Vsem omenjenim v objavi",
"privacy.direct.short": "Zasebna omemba",
"privacy.private.long": "Samo vašim sledilcem",
"privacy.private.short": "Sledilcem",
"privacy.public.long": "Vsem, ki so ali niso na Mastodonu",
@ -621,6 +709,8 @@
"privacy_policy.title": "Pravilnik o zasebnosti",
"recommended": "Priporočeno",
"refresh": "Osveži",
"regeneration_indicator.please_stand_by": "Prosimo, počakajte.",
"regeneration_indicator.preparing_your_home_feed": "Pripravljamo vaš domači vir …",
"relative_time.days": "{number} d",
"relative_time.full.days": "{number, plural, one {pred # dnem} two {pred # dnevoma} few {pred # dnevi} other {pred # dnevi}}",
"relative_time.full.hours": "{number, plural, one {pred # uro} two {pred # urama} few {pred # urami} other {pred # urami}}",
@ -656,7 +746,7 @@
"report.reasons.dislike": "Ni mi všeč",
"report.reasons.dislike_description": "To ni tisto, kar želim videti",
"report.reasons.legal": "To ni legalno",
"report.reasons.legal_description": "Ste mnenja, da krši zakonodajo vaše države ali države strežnika",
"report.reasons.legal_description": "Sem mnenja, da krši zakonodajo moje države ali države strežnika",
"report.reasons.other": "Gre za nekaj drugega",
"report.reasons.other_description": "Težava ne sodi v druge kategorije",
"report.reasons.spam": "To je neželena vsebina",
@ -668,10 +758,10 @@
"report.statuses.subtitle": "Izberite vse, kar ustreza",
"report.statuses.title": "Ali so kakšne objave, ki dokazujejo trditve iz te prijave?",
"report.submit": "Pošlji",
"report.target": "Prijavi {target}",
"report.target": "Prijavljate {target}",
"report.thanks.take_action": "Tukaj so vaše možnosti za nadzor tistega, kar vidite na Mastodonu:",
"report.thanks.take_action_actionable": "Medtem, ko to pregledujemo, lahko proti @{name} ukrepate:",
"report.thanks.title": "Ali ne želite tega videti?",
"report.thanks.title": "Ali ne želite videti tega?",
"report.thanks.title_actionable": "Hvala za prijavo, bomo preverili.",
"report.unfollow": "Ne sledi več @{name}",
"report.unfollow_explanation": "Temu računu sledite. Da ne boste več videli njegovih objav v svojem domačem viru, mu prenehajte slediti.",
@ -695,7 +785,7 @@
"search.search_or_paste": "Iščite ali prilepite URL",
"search_popout.full_text_search_disabled_message": "Ni dostopno na {domain}.",
"search_popout.full_text_search_logged_out_message": "Na voljo le, če ste prijavljeni.",
"search_popout.language_code": "Koda ISO jezika",
"search_popout.language_code": "Jezikovna koda ISO",
"search_popout.options": "Možnosti iskanja",
"search_popout.quick_actions": "Hitra dejanja",
"search_popout.recent": "Nedavna iskanja",
@ -705,8 +795,10 @@
"search_results.all": "Vse",
"search_results.hashtags": "Ključniki",
"search_results.no_results": "Ni rezultatov.",
"search_results.no_search_yet": "Pobrskajte med objavami, profili in ključniki.",
"search_results.see_all": "Poglej vse",
"search_results.statuses": "Objave",
"search_results.title": "Zadetki za \"{q}\"",
"server_banner.about_active_users": "Osebe, ki so uporabljale ta strežnik zadnjih 30 dni (dejavni uporabniki meseca)",
"server_banner.active_users": "dejavnih uporabnikov",
"server_banner.administered_by": "Upravlja:",
@ -724,6 +816,7 @@
"status.bookmark": "Dodaj med zaznamke",
"status.cancel_reblog_private": "Prekliči izpostavitev",
"status.cannot_reblog": "Te objave ni mogoče izpostaviti",
"status.continued_thread": "Nadaljevanje niti",
"status.copy": "Kopiraj povezavo do objave",
"status.delete": "Izbriši",
"status.detailed_status": "Podroben pogled pogovora",
@ -733,7 +826,7 @@
"status.edited": "Zadnje urejanje {date}",
"status.edited_x_times": "Urejeno {count, plural, one {#-krat} two {#-krat} few {#-krat} other {#-krat}}",
"status.embed": "Pridobite kodo za vgradnjo",
"status.favourite": "Priljubljen_a",
"status.favourite": "Priljubljen/a",
"status.favourites": "{count, plural, one {priljubitev} two {priljubitvi} few {priljubitve} other {priljubitev}}",
"status.filter": "Filtriraj to objavo",
"status.history.created": "{name}: ustvarjeno {date}",
@ -741,7 +834,7 @@
"status.load_more": "Naloži več",
"status.media.open": "Kliknite za odpiranje",
"status.media.show": "Kliknite za prikaz",
"status.media_hidden": "Mediji so skriti",
"status.media_hidden": "Predstavnosti so skrite",
"status.mention": "Omeni @{name}",
"status.more": "Več",
"status.mute": "Utišaj @{name}",
@ -758,6 +851,7 @@
"status.redraft": "Izbriši in preoblikuj",
"status.remove_bookmark": "Odstrani zaznamek",
"status.remove_favourite": "Odstrani iz priljubljenih",
"status.replied_in_thread": "Odgovor iz niti",
"status.replied_to": "Odgovoril/a {name}",
"status.reply": "Odgovori",
"status.replyAll": "Odgovori na nit",
@ -767,7 +861,7 @@
"status.show_less_all": "Prikaži manj za vse",
"status.show_more_all": "Pokaži več za vse",
"status.show_original": "Pokaži izvirnik",
"status.title.with_attachments": "{user} je objavil_a {attachmentCount, plural, one {{attachmentCount} priponko} two {{attachmentCount} priponki} few {{attachmentCount} priponke} other {{attachmentCount} priponk}}",
"status.title.with_attachments": "{user} je objavil/a {attachmentCount, plural, one {{attachmentCount} priponko} two {{attachmentCount} priponki} few {{attachmentCount} priponke} other {{attachmentCount} priponk}}",
"status.translate": "Prevedi",
"status.translated_from_with": "Prevedeno iz {lang} s pomočjo {provider}",
"status.uncached_media_warning": "Predogled ni na voljo",
@ -778,7 +872,9 @@
"subscribed_languages.target": "Spremeni naročene jezike za {target}",
"tabs_bar.home": "Domov",
"tabs_bar.notifications": "Obvestila",
"terms_of_service.effective_as_of": "Veljavno od {date}",
"terms_of_service.title": "Pogoji uporabe",
"terms_of_service.upcoming_changes_on": "Spremembe začnejo veljati {date}",
"time_remaining.days": "{number, plural, one {preostaja # dan} two {preostajata # dneva} few {preostajajo # dnevi} other {preostaja # dni}}",
"time_remaining.hours": "{number, plural, one {# ura} other {# ur}} je ostalo",
"time_remaining.minutes": "{number, plural, one {# minuta} other {# minut}} je ostalo",
@ -794,6 +890,11 @@
"upload_button.label": "Dodajte slike, video ali zvočno datoteko",
"upload_error.limit": "Omejitev prenosa datoteke je presežena.",
"upload_error.poll": "Prenos datoteke z anketami ni dovoljen.",
"upload_form.drag_and_drop.instructions": "Predstavnostno priponko lahko poberete tako, da pritisnete preslednico ali vnašalko. S puščicami na tipkovnici premikate priponko v posamezno smer. Priponko lahko odložite na novem položaju s ponovnim pritiskom na preslednico ali vnašalko ali pa dejanje prekličete s tipko ubežnica.",
"upload_form.drag_and_drop.on_drag_cancel": "Premikanje priponke je preklicano. Predstavnostna priponka {item} je padla nazaj na prejšnje mesto.",
"upload_form.drag_and_drop.on_drag_end": "Predstavnostna priponka {item} je padla nazaj.",
"upload_form.drag_and_drop.on_drag_over": "Priponka {item} je bila premaknjena.",
"upload_form.drag_and_drop.on_drag_start": "Pobrana priponka {item}.",
"upload_form.edit": "Uredi",
"upload_progress.label": "Pošiljanje ...",
"upload_progress.processing": "Obdelovanje …",

View File

@ -19,6 +19,7 @@
"account.block_short": "Блокла",
"account.blocked": "Блокланган",
"account.cancel_follow_request": "Киләсе сорау",
"account.copy": "Профиль сылтамасын күчереп ал",
"account.disable_notifications": "@{name} язулары өчен белдерүләр сүндерү",
"account.domain_blocked": "Домен блокланган",
"account.edit_profile": "Профильне үзгәртү",
@ -43,6 +44,8 @@
"account.mention": "@{name} искәртү",
"account.moved_to": "{name} аларның яңа счеты хәзер күрсәтте:",
"account.mute": "@{name} кулланучыга әһәмият бирмәү",
"account.mute_notifications_short": "Искәртүләрне сүндер",
"account.mute_short": "Тавышсыз",
"account.muted": "Әһәмият бирмәнгән",
"account.open_original_page": "Чыганак битен ачу",
"account.posts": "Язма",
@ -58,6 +61,7 @@
"account.unendorse": "Профильдә тәкъдим итмәү",
"account.unfollow": "Язылуны туктату",
"account.unmute": "Kабызыгыз @{name}",
"account.unmute_notifications_short": "Искәртүләрне кабыз",
"account.unmute_short": "Kабызыгыз",
"account_note.placeholder": "Click to add a note",
"admin.dashboard.daily_retention": "Теркәлгәннән соң икенче көнне кулланучыларны тоту коэффициенты",

View File

@ -874,6 +874,7 @@
"tabs_bar.notifications": "Сповіщення",
"terms_of_service.effective_as_of": "Ефективний на {date}",
"terms_of_service.title": "Умови використання",
"terms_of_service.upcoming_changes_on": "Майбутні зміни {date}",
"time_remaining.days": "{number, plural, one {# день} few {# дні} other {# днів}}",
"time_remaining.hours": "{number, plural, one {# година} few {# години} other {# годин}}",
"time_remaining.minutes": "{number, plural, one {# хвилина} few {# хвилини} other {# хвилин}}",

View File

@ -338,7 +338,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
collection = @object['replies']
return if collection.blank?
replies = ActivityPub::FetchRepliesService.new.call(status, collection, allow_synchronous_requests: false, request_id: @options[:request_id])
replies = ActivityPub::FetchRepliesService.new.call(status.account.uri, collection, allow_synchronous_requests: false, request_id: @options[:request_id])
return unless replies.nil?
uri = value_or_id(collection)

View File

@ -0,0 +1,43 @@
# frozen_string_literal: true
module Status::FetchRepliesConcern
extend ActiveSupport::Concern
# enable/disable fetching all replies
FETCH_REPLIES_ENABLED = ENV['FETCH_REPLIES_ENABLED'] == 'true'
# debounce fetching all replies to minimize DoS
FETCH_REPLIES_COOLDOWN_MINUTES = (ENV['FETCH_REPLIES_COOLDOWN_MINUTES'] || 15).to_i.minutes
FETCH_REPLIES_INITIAL_WAIT_MINUTES = (ENV['FETCH_REPLIES_INITIAL_WAIT_MINUTES'] || 5).to_i.minutes
included do
scope :created_recently, -> { where(created_at: FETCH_REPLIES_INITIAL_WAIT_MINUTES.ago..) }
scope :not_created_recently, -> { where(created_at: ..FETCH_REPLIES_INITIAL_WAIT_MINUTES.ago) }
scope :fetched_recently, -> { where(fetched_replies_at: FETCH_REPLIES_COOLDOWN_MINUTES.ago..) }
scope :not_fetched_recently, -> { where(fetched_replies_at: [nil, ..FETCH_REPLIES_COOLDOWN_MINUTES.ago]) }
scope :should_not_fetch_replies, -> { local.or(created_recently.or(fetched_recently)) }
scope :should_fetch_replies, -> { remote.not_created_recently.not_fetched_recently }
# statuses for which we won't receive update or deletion actions,
# and should update when fetching replies
# Status from an account which either
# a) has only remote followers
# b) has local follows that were created after the last update time, or
# c) has no known followers
scope :unsubscribed, lambda {
remote.merge(
Status.left_outer_joins(account: :followers).where.not(followers_accounts: { domain: nil })
.or(where.not('follows.created_at < statuses.updated_at'))
.or(where(follows: { id: nil }))
)
}
end
def should_fetch_replies?
# we aren't brand new, and we haven't fetched replies since the debounce window
FETCH_REPLIES_ENABLED && !local? && created_at <= FETCH_REPLIES_INITIAL_WAIT_MINUTES.ago && (
fetched_replies_at.nil? || fetched_replies_at <= FETCH_REPLIES_COOLDOWN_MINUTES.ago
)
end
end

View File

@ -29,6 +29,7 @@
# edited_at :datetime
# trendable :boolean
# ordered_media_attachment_ids :bigint(8) is an Array
# fetched_replies_at :datetime
#
class Status < ApplicationRecord
@ -36,6 +37,7 @@ class Status < ApplicationRecord
include Discard::Model
include Paginable
include RateLimitable
include Status::FetchRepliesConcern
include Status::SafeReblogInsert
include Status::SearchConcern
include Status::SnapshotConcern

View File

@ -0,0 +1,54 @@
# frozen_string_literal: true
class ActivityPub::FetchAllRepliesService < ActivityPub::FetchRepliesService
include JsonLdHelper
# Limit of replies to fetch per status
MAX_REPLIES = (ENV['FETCH_REPLIES_MAX_SINGLE'] || 500).to_i
def call(status_uri, collection_or_uri, max_pages: 1, request_id: nil)
@status_uri = status_uri
super
end
private
def filter_replies(items)
# Find all statuses that we *shouldn't* update the replies for, and use that as a filter.
# We don't assume that we have the statuses before they're created,
# hence the negative filter -
# "keep all these uris except the ones we already have"
# instead of
# "keep all these uris that match some conditions on existing Status objects"
#
# Typically we assume the number of replies we *shouldn't* fetch is smaller than the
# replies we *should* fetch, so we also minimize the number of uris we should load here.
uris = items.map { |item| value_or_id(item) }
# Expand collection to get replies in the DB that were
# - not included in the collection,
# - that we have locally
# - but we have no local followers and thus don't get updates/deletes for
parent_id = Status.where(uri: @status_uri).pick(:id)
unless parent_id.nil?
unsubscribed_replies = Status
.where.not(uri: uris)
.where(in_reply_to_id: parent_id)
.unsubscribed
.pluck(:uri)
uris.concat(unsubscribed_replies)
end
dont_update = Status.where(uri: uris).should_not_fetch_replies.pluck(:uri)
# touch all statuses that already exist and that we're about to update
Status.where(uri: uris).should_fetch_replies.touch_all(:fetched_replies_at)
# Reject all statuses that we already have in the db
uris = (uris - dont_update).take(MAX_REPLIES)
Rails.logger.debug { "FetchAllRepliesService - #{@collection_or_uri}: Fetching filtered statuses: #{uris}" }
uris
end
end

View File

@ -33,7 +33,7 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService
return collection_or_uri if collection_or_uri.is_a?(Hash)
return if non_matching_uri_hosts?(@account.uri, collection_or_uri)
fetch_resource_without_id_validation(collection_or_uri, local_follower, true)
fetch_resource_without_id_validation(collection_or_uri, local_follower, raise_on_error: :temporary)
end
def process_items(items)

View File

@ -45,7 +45,7 @@ class ActivityPub::FetchFeaturedTagsCollectionService < BaseService
return collection_or_uri if collection_or_uri.is_a?(Hash)
return if non_matching_uri_hosts?(@account.uri, collection_or_uri)
fetch_resource_without_id_validation(collection_or_uri, local_follower, true)
fetch_resource_without_id_validation(collection_or_uri, local_follower, raise_on_error: :temporary)
end
def process_items(items)

View File

@ -13,7 +13,7 @@ class ActivityPub::FetchRemoteStatusService < BaseService
@request_id = request_id || "#{Time.now.utc.to_i}-status-#{uri}"
@json = if prefetched_body.nil?
fetch_resource(uri, true, on_behalf_of)
fetch_status(uri, true, on_behalf_of)
else
body_to_json(prefetched_body, compare_id: uri)
end
@ -80,4 +80,20 @@ class ActivityPub::FetchRemoteStatusService < BaseService
def expected_object_type?
equals_or_includes_any?(@json['type'], ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES)
end
def fetch_status(uri, id_is_known, on_behalf_of = nil)
begin
fetch_resource(uri, id_is_known, on_behalf_of, raise_on_error: :all)
rescue Mastodon::UnexpectedResponseError => e
return unless e.response.code == 404
# If this is a 404 from a public status from a remote account, delete it
existing_status = Status.remote.find_by(uri: uri)
if existing_status&.distributable?
Rails.logger.debug { "FetchRemoteStatusService - Got 404 for orphaned status with URI #{uri}, deleting" }
Tombstone.find_or_create_by(uri: uri, account: existing_status.account)
RemoveStatusService.new.call(existing_status, redraft: false)
end
end
end
end

View File

@ -3,39 +3,59 @@
class ActivityPub::FetchRepliesService < BaseService
include JsonLdHelper
def call(parent_status, collection_or_uri, allow_synchronous_requests: true, request_id: nil)
@account = parent_status.account
# Limit of fetched replies
MAX_REPLIES = 5
def call(reference_uri, collection_or_uri, max_pages: 1, allow_synchronous_requests: true, request_id: nil)
@reference_uri = reference_uri
@allow_synchronous_requests = allow_synchronous_requests
@items = collection_items(collection_or_uri)
@items, n_pages = collection_items(collection_or_uri, max_pages: max_pages)
return if @items.nil?
FetchReplyWorker.push_bulk(filtered_replies) { |reply_uri| [reply_uri, { 'request_id' => request_id }] }
@items = filter_replies(@items)
FetchReplyWorker.push_bulk(@items) { |reply_uri| [reply_uri, { 'request_id' => request_id }] }
@items
[@items, n_pages]
end
private
def collection_items(collection_or_uri)
def collection_items(collection_or_uri, max_pages: 1)
collection = fetch_collection(collection_or_uri)
return unless collection.is_a?(Hash)
collection = fetch_collection(collection['first']) if collection['first'].present?
return unless collection.is_a?(Hash)
items = []
n_pages = 1
while collection.is_a?(Hash)
items.concat(as_array(collection_page_items(collection)))
break if items.size >= MAX_REPLIES
break if n_pages >= max_pages
collection = collection['next'].present? ? fetch_collection(collection['next']) : nil
n_pages += 1
end
[items, n_pages]
end
def collection_page_items(collection)
case collection['type']
when 'Collection', 'CollectionPage'
as_array(collection['items'])
collection['items']
when 'OrderedCollection', 'OrderedCollectionPage'
as_array(collection['orderedItems'])
collection['orderedItems']
end
end
def fetch_collection(collection_or_uri)
return collection_or_uri if collection_or_uri.is_a?(Hash)
return unless @allow_synchronous_requests
return if non_matching_uri_hosts?(@account.uri, collection_or_uri)
return if non_matching_uri_hosts?(@reference_uri, collection_or_uri)
# NOTE: For backward compatibility reasons, Mastodon signs outgoing
# queries incorrectly by default.
@ -45,19 +65,19 @@ class ActivityPub::FetchRepliesService < BaseService
#
# Therefore, retry with correct signatures if this fails.
begin
fetch_resource_without_id_validation(collection_or_uri, nil, true)
fetch_resource_without_id_validation(collection_or_uri, nil, raise_on_error: :temporary)
rescue Mastodon::UnexpectedResponseError => e
raise unless e.response && e.response.code == 401 && Addressable::URI.parse(collection_or_uri).query.present?
fetch_resource_without_id_validation(collection_or_uri, nil, true, request_options: { omit_query_string: false })
fetch_resource_without_id_validation(collection_or_uri, nil, raise_on_error: :temporary, request_options: { omit_query_string: false })
end
end
def filtered_replies
def filter_replies(items)
# Only fetch replies to the same server as the original status to avoid
# amplification attacks.
# Also limit to 5 fetched replies to limit potential for DoS.
@items.map { |item| value_or_id(item) }.reject { |uri| non_matching_uri_hosts?(@account.uri, uri) }.take(5)
items.map { |item| value_or_id(item) }.reject { |uri| non_matching_uri_hosts?(@reference_uri, uri) }.take(MAX_REPLIES)
end
end

View File

@ -69,6 +69,6 @@ class ActivityPub::SynchronizeFollowersService < BaseService
return collection_or_uri if collection_or_uri.is_a?(Hash)
return if non_matching_uri_hosts?(@account.uri, collection_or_uri)
fetch_resource_without_id_validation(collection_or_uri, nil, true)
fetch_resource_without_id_validation(collection_or_uri, nil, raise_on_error: :temporary)
end
end

View File

@ -0,0 +1,68 @@
# frozen_string_literal: true
# Fetch all replies to a status, querying recursively through
# ActivityPub replies collections, fetching any statuses that
# we either don't already have or we haven't checked for new replies
# in the Status::FETCH_REPLIES_COOLDOWN_MINUTES interval
class ActivityPub::FetchAllRepliesWorker
include Sidekiq::Worker
include ExponentialBackoff
include JsonLdHelper
sidekiq_options queue: 'pull', retry: 3
# Global max replies to fetch per request (all replies, recursively)
MAX_REPLIES = (ENV['FETCH_REPLIES_MAX_GLOBAL'] || 1000).to_i
MAX_PAGES = (ENV['FETCH_REPLIES_MAX_PAGES'] || 500).to_i
def perform(root_status_id, options = {})
@root_status = Status.remote.find_by(id: root_status_id)
return unless @root_status&.should_fetch_replies?
@root_status.touch(:fetched_replies_at)
Rails.logger.debug { "FetchAllRepliesWorker - #{@root_status.uri}: Fetching all replies for status: #{@root_status}" }
uris_to_fetch, n_pages = get_replies(@root_status.uri, MAX_PAGES, options)
return if uris_to_fetch.nil?
fetched_uris = uris_to_fetch.clone.to_set
until uris_to_fetch.empty? || fetched_uris.length >= MAX_REPLIES || n_pages >= MAX_PAGES
next_reply = uris_to_fetch.pop
next if next_reply.nil?
new_reply_uris, new_n_pages = get_replies(next_reply, MAX_PAGES - n_pages, options)
next if new_reply_uris.nil?
new_reply_uris = new_reply_uris.reject { |uri| fetched_uris.include?(uri) }
uris_to_fetch.concat(new_reply_uris)
fetched_uris = fetched_uris.merge(new_reply_uris)
n_pages += new_n_pages
end
Rails.logger.debug { "FetchAllRepliesWorker - #{@root_status.uri}: fetched #{fetched_uris.length} replies" }
# Workers shouldn't be returning anything, but this is used in tests
fetched_uris
end
private
def get_replies(status_uri, max_pages, options = {})
replies_collection_or_uri = get_replies_uri(status_uri)
return if replies_collection_or_uri.nil?
ActivityPub::FetchAllRepliesService.new.call(status_uri, replies_collection_or_uri, max_pages: max_pages, **options.deep_symbolize_keys)
end
def get_replies_uri(parent_status_uri)
fetch_resource(parent_status_uri, true)&.fetch('replies', nil)
rescue => e
Rails.logger.info { "FetchAllRepliesWorker - #{@root_status.uri}: Caught exception while resolving replies URI #{parent_status_uri}: #{e} - #{e.message}" }
# Raise if we can't get the collection for top-level status to trigger retry
raise e if parent_status_uri == @root_status.uri
nil
end
end

View File

@ -7,7 +7,7 @@ class ActivityPub::FetchRepliesWorker
sidekiq_options queue: 'pull', retry: 3
def perform(parent_status_id, replies_uri, options = {})
ActivityPub::FetchRepliesService.new.call(Status.find(parent_status_id), replies_uri, **options.deep_symbolize_keys)
ActivityPub::FetchRepliesService.new.call(Status.find(parent_status_id).account.uri, replies_uri, **options.deep_symbolize_keys)
rescue ActiveRecord::RecordNotFound
true
end

View File

@ -49,6 +49,10 @@ el:
attributes:
reblog:
taken: της ανάρτησης υπάρχει ήδη
terms_of_service:
attributes:
effective_date:
too_soon: είναι πολύ σύντομα, πρέπει να είναι μετά από %{date}
user:
attributes:
email:

View File

@ -52,7 +52,7 @@ nl:
terms_of_service:
attributes:
effective_date:
too_soon: is te vroeg, moet later zijn dan %{date}
too_soon: is te vroeg, moet na %{date} zijn
user:
attributes:
email:

View File

@ -18,9 +18,13 @@ sl:
attributes:
domain:
invalid: ni veljavno ime domene
messages:
invalid_domain_on_line: "%{value} ni veljavno ime domene"
models:
account:
attributes:
fields:
fields_with_values_missing_labels: vsebuje vrednosti, ki niso kategorizirane
username:
invalid: samo črke, številke in podčrtaji
reserved: je rezerviran
@ -40,10 +44,15 @@ sl:
attributes:
account_id:
taken: je že na seznamu
must_be_following: mora biti račun, ki mu sledite
status:
attributes:
reblog:
taken: od objave že obstajajo
terms_of_service:
attributes:
effective_date:
too_soon: je prekmalu, naj bo kasneje od %{date}
user:
attributes:
email:

View File

@ -5,10 +5,51 @@ tt:
poll:
options: Сайлаулар
user:
email: Почта адресы
email: Эл. почта адресы
locale: Тел
password: Серсүз
user/account:
username: Кулланучы исеме
user/invite_request:
text: Сәбәп
errors:
attributes:
domain:
invalid: бу домен исеме гамәлдә түгел
messages:
invalid_domain_on_line: "%{value} дөрес домен исеме түгел"
models:
account:
attributes:
username:
invalid: хәрефләр, цифрлар һәм ассызыклау билгеләре генә ярый
admin/webhook:
attributes:
url:
invalid: рөхсәт ителгән URL түгел
doorkeeper/application:
attributes:
website:
invalid: рөхсәт ителгән URL түгел
import:
attributes:
data:
malformed: формат дөрес түгел
list_account:
attributes:
account_id:
taken: инде исемлектә
status:
attributes:
reblog:
taken: язма инде бар
user:
attributes:
email:
blocked: ярамаган эл. почта провайдерын куллана
role_id:
elevated: сезнең хәзерге ролегездән югарырак була алмый
user_role:
attributes:
position:
elevated: сезнең хәзерге ролегездән югарырак була алмый

View File

@ -3,7 +3,19 @@ tt:
devise:
confirmations:
confirmed: Сезнең э. почта адресыгыз уңышлы расланган.
failure:
already_authenticated: Сез кердегез инде.
inactive: Сезнең аккаунтыгыз әле активламаган.
invalid: "%{authentication_keys} яки серсүз дөрес кертелмәгән."
locked: Сезнең хисапъязмагыз блокланган.
not_found_in_database: "%{authentication_keys} яки серсүз дөрес кертелмәгән."
mailer:
confirmation_instructions:
action: Email адресын расла
action_with_app: Расла һәм %{app} эченә кайт
title: Email адресын раслагыз
email_changed:
explanation: 'Сезнең аккаунтыгызның email адресы моңа үзгәртеләчәк:'
reset_password_instructions:
action: Серсүзне үзгәртү
title: Серсүзне алыштыру

View File

@ -60,6 +60,7 @@ sl:
error:
title: Prišlo je do napake
new:
prompt_html: "%{client_name} želi dostopati do vašega računa. <strong>To prošnjo odobrite le, če tega odjemalca prepoznate in mu zaupate.</strong>"
review_permissions: Preglej dovoljenja
title: Potrebna je odobritev
show:
@ -82,6 +83,7 @@ sl:
access_denied: Lastnik virov ali odobritveni strežnik je zavrnil zahtevo.
credential_flow_not_configured: Pretok geselskih pooblastil lastnika virov ni uspel, ker Doorkeeper.configure.resource_owner_from_credentials ni nastavljen.
invalid_client: Odobritev odjemalca ni uspela zaradi neznanega odjemalca, zaradi nevključitve odobritve odjemalca ali zaradi nepodprte metode odobritve.
invalid_code_challenge_method: Metoda za kodo mora biti S256, čistopis ni podprt.
invalid_grant: Predložena odobritev je neveljavna, je potekla, je preklicana, se ne ujema z URI-jem za preusmeritev uporabljenim v zahtevi za odobritev, ali pa je bila izdana drugemu odjemalcu.
invalid_redirect_uri: URI za preusmeritev ni veljaven.
invalid_request:

View File

@ -309,6 +309,7 @@ el:
title: Αρχείο ελέγχου
unavailable_instance: "(μη διαθέσιμο όνομα τομέα)"
announcements:
back: Επιστροφή στις ανακοινώσεις
destroyed_msg: Επιτυχής διαγραφή ανακοίνωσης!
edit:
title: Ενημέρωση ανακοίνωσης

View File

@ -1159,6 +1159,7 @@ et:
set_new_password: Uue salasõna määramine
setup:
email_below_hint_html: Kontrolli rämpsposti kausta või taotle uut. Saad oma e-posti aadressi parandada, kui see on vale.
email_settings_hint_html: Klõpsa aadressile %{email} saadetud linki, et alustada Mastodoni kasutamist. Me oleme ootel.
link_not_received: Kas ei saanud linki?
new_confirmation_instructions_sent: Saad mõne minuti pärast uue kinnituslingiga e-kirja!
title: Kontrolli sisendkasti
@ -1167,6 +1168,7 @@ et:
title: Logi sisse kohta %{domain}
sign_up:
manual_review: Liitumised kohas %{domain} vaadatakse meie moderaatorite poolt käsitsi läbi. Aitamaks meil sinu taotlust läbi vaadata, kirjuta palun natuke endast ja miks soovid kontot kohas %{domain}.
preamble: Selle Mastodoni serveri kontoga saad jälgida mistahes teist isikut fediversumis, sõltumata sellest, kus ta konto on majutatud.
title: Loo konto serverisse %{domain}.
status:
account_status: Konto olek

View File

@ -320,7 +320,7 @@ nl:
title: Nieuwe mededeling
preview:
explanation_html: 'De e-mail wordt verzonden naar <strong>%{display_count} gebruikers</strong>. De volgende tekst wordt in het bericht opgenomen:'
title: Voorbeeld aankondiging notificatie
title: Voorbeeld van mededeling
publish: Inschakelen
published_msg: Publiceren van mededeling geslaagd!
scheduled_for: Ingepland voor %{time}
@ -943,7 +943,7 @@ nl:
chance_to_review_html: "<strong>De gegenereerde gebruiksvoorwaarden worden niet automatisch gepubliceerd.</strong> Je krijgt de gelegenheid om de resultaten eerst te bekijken. Vul de benodigde gegevens in om verder te gaan."
explanation_html: Het sjabloon voor de gebruiksvoorwaarden is uitsluitend bedoeld voor informatieve doeleinden en mag niet worden opgevat als juridisch advies over welk onderwerp dan ook. Raadpleeg een eigen juridisch adviseur over jouw situatie en voor specifieke juridische vragen.
title: Gebruiksvoorwaarden instellen
going_live_on_html: Actueel, met ingang van %{date}
going_live_on_html: Actueel met ingang van %{date}
history: Geschiedenis
live: Actueel
no_history: Er zijn nog geen opgeslagen wijzigingen van de gebruiksvoorwaarden.
@ -1911,7 +1911,7 @@ nl:
user_mailer:
announcement_published:
description: 'De beheerders van %{domain} doen een mededeling:'
subject: Service aankondiging
subject: Service-aankondiging
title: "%{domain} service aankondiging"
appeal_approved:
action: Accountinstellingen
@ -1945,8 +1945,8 @@ nl:
terms_of_service_changed:
agreement: Door %{domain} te blijven gebruiken, ga je akkoord met deze voorwaarden. Als je het niet eens bent met de bijgewerkte voorwaarden, kun je je overeenkomst met %{domain} op elk gewenst moment beëindigen door je account te verwijderen.
changelog: 'In een oogopslag betekent deze update voor jou:'
description: 'Je ontvangt dit bericht, omdat we enkele wijzigingen aanbrengen in onze gebruiksvoorwaarden bij %{domain}. Deze aanpassingen komen van kracht op %{date}. We raden je aan om de bijgewerkte voorwaarden hier volledig te bekijken:'
description_html: Je ontvangt dit bericht, omdat we enkele wijzigingen aanbrengen in onze gebruiksvoorwaarden bij %{domain}. Deze aanpassingen komen van kracht op <strong>%{date}</strong>. We raden je aan om de <a href="%{path}" target="_blank">bijgewerkte voorwaarden hier</a> volledig te bestuderen.
description: 'Je ontvangt dit bericht, omdat we enkele wijzigingen aanbrengen in onze gebruiksvoorwaarden op %{domain}. Deze aanpassingen worden van kracht op %{date}. We raden je aan om de bijgewerkte voorwaarden hier volledig te bekijken:'
description_html: Je ontvangt dit bericht, omdat we enkele wijzigingen aanbrengen in onze gebruiksvoorwaarden op %{domain}. Deze aanpassingen worden van kracht op <strong>%{date}</strong>. We raden je aan om de <a href="%{path}" target="_blank">bijgewerkte voorwaarden hier</a> volledig te bestuderen.
sign_off: Het %{domain}-team
subject: Onze bijgewerkte gebruiksvoorwaarden
subtitle: De gebruiksvoorwaarden van %{domain} veranderen

View File

@ -136,10 +136,14 @@ is:
text: Er hægt að sníða með Markdown-málskipan.
terms_of_service_generator:
admin_email: Löglegar tilkynningar ná yfir andsvör, dómsúrskurði, lokunarbeiðnir og beiðnir frá lögregluembættum.
arbitration_address: Má vera það sama og raunverulegt heimilisfang eða “N/A” ef tölvupóstur er notaður.
arbitration_website: Má vera innfyllingarform á vefsíðu eða “N/A” ef tölvupóstur er notaður.
choice_of_law: Sveitarfélög, héruð eða ríki þar sem ríkjandi lög og reglugerðir skulu stýra meðhöndlun á öllum kröfum.
dmca_address: Fyrir rekstraraðila í BNA ætti að nota heimilisfang sem skráð er í DMCA Designated Agent Directory. Hægt er að verða sér úti um A P.O. pósthólfsskráningu með beinni beiðni; notaðu DMCA Designated Agent Post Office Box Waiver Request til að senda tölvupóst á Copyright Office og lýstu því yfir að þú sért heimavinnandi efnismiðlari (home-based content moderator) sem átt á hættu refsingar eða hefndir vegna þess sem þú miðlar og þurfir því á slíku pósthólfi að halda svo þitt eigið heimilisfang sé ekki gert opinbert.
dmca_email: Má vera sama tölvupóstfang og það sem notað er í “Tölvupóstfang vegna löglegra tilkynninga” hér að ofan.
domain: Einstakt auðkenni á netþjónustunni sem þú býður.
jurisdiction: Settu inn landið þar sem sá býr sem borgar reikningana. Ef það er fyrirtæki eða samtök, skaltu hafa það landið þar sem lögheimili þess er, auk borgar, héraðs, svæðis eða fylkis eins og við á.
min_age: Ætti ekki að vera lægri en sá lágmarksaldur sek kveðið er á um í lögum þíns lögsagnarumdæmis.
user:
chosen_languages: Þegar merkt er við þetta, birtast einungis færslur á völdum tungumálum á opinberum tímalínum
role: Hlutverk stýrir hvaða heimildir notandinn hefur.
@ -343,6 +347,7 @@ is:
dmca_email: Tölvupóstfang tilkynninga vegna DMCA/höfundaréttar
domain: Lén
jurisdiction: Lögsagnarumdæmi
min_age: Lágmarksaldur
user:
role: Hlutverk
time_zone: Tímabelti

View File

@ -132,8 +132,11 @@ lv:
name: Tu vari mainīt tikai burtu lielumu, piemēram, lai tie būtu vieglāk lasāmi
terms_of_service:
changelog: Var veidot ar Markdown pierakstu.
effective_date: Saprātīgs laika logs var būt no 10 līdz 30 dienām no dienas, kad lietotāji tiek apziņoti.
text: Var veidot ar Markdown pierakstu.
terms_of_service_generator:
arbitration_address: Var būt tāda pati kā augstāk esošā fiziskā adrese vai "N/A", ja tiek izmantota e-pasta adrese.
arbitration_website: Var būt tīmekļa veidlapa vai "N/A", ja tiek izmantots e-pasts.
domain: Sniegtā tiešsaistas pakalpojuma neatkārtojama identifikācija.
user:
chosen_languages: Ja ieķeksēts, publiskos laika grafikos tiks parādītas tikai ziņas noteiktajās valodās
@ -327,11 +330,13 @@ lv:
usable: Ļaut ierakstos vietēji izmantot šo tēmturi
terms_of_service:
changelog: Kas ir mainījies?
effective_date: Spēkā stāšanās datums
text: Pakalpojuma izmantošanas nosacījumi
terms_of_service_generator:
admin_email: E-pasta adrese juridiskiem paziņojumiem
choice_of_law: Likuma izvēle
domain: Domēna vārds
min_age: Mazākais pieļaujamais vecums
user:
role: Loma
time_zone: Laika josla

View File

@ -132,18 +132,18 @@ nl:
name: Je kunt elk woord met een hoofdletter beginnen, om zo bijvoorbeeld de tekst leesbaarder te maken
terms_of_service:
changelog: Kan worden opgemaakt met Markdown.
effective_date: Een redelijke periode kan variëren van 10 tot 30 dagen vanaf de datum waarop u uw gebruikers op de hoogte stelt.
effective_date: Een redelijke periode kan variëren van 10 tot 30 dagen vanaf de datum waarop je jouw gebruikers op de hoogte stelt.
text: Kan worden opgemaakt met Markdown.
terms_of_service_generator:
admin_email: Juridische mededelingen zijn o. a. counter-notices, gerechterlijke bevelen, takedown-requests en handhavingsverzoeken.
arbitration_address: Kan hetzelfde zijn als bovenstaand vestigingsadres of "N/A" bij gebruik van e-mail.
arbitration_website: Kan een webformulier zijn, of "N/A" als e-mail wordt gebruikt.
choice_of_law: Stad, regio, grondgebied of staat waar de interne grondwetten van toepassing zijn op alle claims.
arbitration_website: Kan een webformulier zijn, of "N/A" wanneer e-mail wordt gebruikt.
choice_of_law: Stad, regio, grondgebied of staat waar de interne materiële wetten van toepassing zijn op alle aanspraken.
dmca_address: 'Gebruik voor beheerders in de VS: het adres dat is geregistreerd in de DMCA Designated Agent Directory. Op verzoek is er een postbuslijst beschikbaar. Gebruik het DMCA Designated Agent Post Office Box Waiver Request om het Copyright Office te e-mailen en te beschrijven dat je een vanaf huis opererende inhoudsmoderator bent, die wraak of vergelding vreest voor je moderator-acties en daarom een postbus moet gebruiken om jouw huisadres uit het publieke domein te houden.'
dmca_email: Kan hetzelfde e-mailadres zijn dat gebruikt wordt voor "E-mailadres voor juridische berichten" hierboven.
domain: Een unieke identificatie van de online dienst die je levert.
jurisdiction: Vermeld het land waar de persoon woont die de rekeningen betaalt. Is het een bedrijf of iets dergelijks, vermeld dan het land waar het ingeschreven staat en de stad, de regio, het grondgebied of de staat, voor zover van toepassing.
min_age: Mag niet lager zijn dan de minimale vereiste leeftijd volgens de wetten van uw jurisdictie.
min_age: Mag niet lager zijn dan de minimale vereiste leeftijd volgens de wetten van jouw jurisdictie.
user:
chosen_languages: Alleen berichten in de aangevinkte talen worden op de openbare tijdlijnen getoond
role: De rol bepaalt welke rechten de gebruiker heeft.
@ -342,7 +342,7 @@ nl:
admin_email: E-mailadres voor juridische meldingen
arbitration_address: Vestigingsadres voor arbitrage-mededelingen
arbitration_website: Website voor het indienen van arbitrage-mededelingen
choice_of_law: Keuze van recht
choice_of_law: Keuze van rechtsgebied
dmca_address: Vestigingsadres voor DMCA/auteursrecht-mededelingen
dmca_email: E-mailadres voor DMCA/auteursrecht-mededelingen
domain: Domein

View File

@ -3,12 +3,14 @@ sl:
simple_form:
hints:
account:
attribution_domains: Ena na vrstico. Ščiti pred napačno navedbo avtorstva.
discoverable: Vaše javne objave in profil so lahko predstavljeni ali priporočeni v različnih delih Mastodona, vaš profil pa je lahko predlagan drugim uporabnikom.
display_name: Vaše polno ime ali lažno ime.
fields: Vaša domača stran, starost, kar koli.
indexable: Vaše javne objave se lahko pojavijo v rezultatih iskanja na Mastodonu. Ljudje, ki so bili v interakciji z vašimi objavami, jih bodo lahko iskali ne glede na to.
note: 'Druge osebe lahko @omenite ali #ključnite.'
show_collections: Ljudje bodo lahko brskali po vaših sledilcih in sledenih. Ljudje, ki jim sledite, bodo videli, da jim sledite ne glede na to.
unlocked: Ljudje vam bodo lahko sledili, ne da bi zahtevali odobritev. Ne potrdite, če želite pregledati prošnje za sledenje in izbrati, ali želite nove sledilce sprejeti ali zavrniti.
account_alias:
acct: Določite uporabniškoime@domena računa, od katerega se želite preseliti
account_migration:
@ -58,6 +60,7 @@ sl:
setting_display_media_default: Skrij medij, ki je označen kot občutljiv
setting_display_media_hide_all: Vedno skrij vse medije
setting_display_media_show_all: Vedno pokaži medij, ki je označen kot občutljiv
setting_system_scrollbars_ui: Velja zgolj za namizne brskalnike, ki temeljijo na Safariju in Chromeu
setting_use_blurhash: Prelivi temeljijo na barvah skrite vizualne slike, vendar zakrivajo vse podrobnosti
setting_use_pending_items: Skrij posodobitev časovnice za klikom namesto samodejnega posodabljanja
username: Uporabite lahko črke, števke in podčrtaje.
@ -127,6 +130,14 @@ sl:
show_application: Ne glede na to boste vedno lahko pogledali, katera aplikacija je objavila vašo objavo.
tag:
name: Spremenite lahko le npr. velikost črk (velike/male), da je bolj berljivo
terms_of_service:
changelog: Uporabite lahko oblikovanje z Markdown.
effective_date: Razumen čas do uveljavitve je navadno nekje med 10 in 30 dni od datuma, ko ste obvestili svoje uporabnike.
text: Uporabite lahko oblikovanje z Markdown.
terms_of_service_generator:
admin_email: Pravna obvestila vključujejo odgovore na obvestila, sodne naloge, zahteve za odstranitev in zahteve organov pregona.
arbitration_address: Lahko je enak kot fizični naslov zgoraj ali „N/A“, če uporabljate e-pošto.
arbitration_website: Lahko je spletni obrazec ali „N/A“, če uporabljate e-pošto.
user:
chosen_languages: Ko je označeno, bodo v javnih časovnicah prikazane samo objave v izbranih jezikih
user_role:
@ -313,6 +324,18 @@ sl:
name: Ključnik
trendable: Dovoli, da se ta ključnik pojavi med trendi
usable: Dovoli, da objave krajevno uporabljajo ta ključnik
terms_of_service:
changelog: Kaj je novega?
effective_date: Datum začetka veljavnosti
text: Pogoji uporabe
terms_of_service_generator:
admin_email: E-poštni naslov za pravna obvestila
arbitration_address: Fizični naslov za arbitražna obvestila
arbitration_website: Spletišče za vložitev arbitražnih obvestil
dmca_address: Fizični naslov za obvestila DMCA ali o avtorskih pravicah
dmca_email: E-poštni naslov za obvestila DMCA ali o avtorskih pravicah
domain: Domena
min_age: Najmanjša starost
user:
role: Vloga
time_zone: Časovni pas

View File

@ -25,9 +25,12 @@ sl:
other: Objav
two: Objavi
posts_tab_heading: Objave
self_follow_error: Ni dovoljeno slediti lastnemu računu
admin:
account_actions:
action: Izvedi dejanje
already_silenced: Ta račun je že omejen.
already_suspended: Ta račun je že suspendiran.
title: Izvedi moderirano dejanje za %{acct}
account_moderation_notes:
create: Pusti opombo
@ -49,6 +52,7 @@ sl:
title: Spremeni e-naslov za %{username}
change_role:
changed_msg: Vloga uspešno spremenjena!
edit_roles: Upravljaj z uporabniškimi vlogami
label: Spremeni vlogo
no_role: Brez vloge
title: Spremeni vlogo za %{username}
@ -189,6 +193,7 @@ sl:
create_domain_block: Ustvari blokado domene
create_email_domain_block: Ustvari blokado domene e-pošte
create_ip_block: Ustvari pravilo IP
create_relay: Ustvari rele
create_unavailable_domain: Ustvari domeno, ki ni na voljo
create_user_role: Ustvari vlogo
demote_user: Ponižaj uporabnika
@ -200,18 +205,22 @@ sl:
destroy_email_domain_block: Izbriši blokado domene e-pošte
destroy_instance: Očisti domeno
destroy_ip_block: Izbriši pravilo IP
destroy_relay: Izbriši rele
destroy_status: Izbriši objavo
destroy_unavailable_domain: Izbriši nedosegljivo domeno
destroy_user_role: Uniči vlogo
disable_2fa_user: Onemogoči
disable_custom_emoji: Onemogoči emotikon po meri
disable_relay: Onemogoči rele
disable_sign_in_token_auth_user: Onemogoči overjanje z žetonom po e-pošti za uporabnika
disable_user: Onemogoči uporabnika
enable_custom_emoji: Omogoči emotikon po meri
enable_relay: Omogoči rele
enable_sign_in_token_auth_user: Omogoči overjanje z žetonom po e-pošti za uporabnika
enable_user: Omogoči uporabnika
memorialize_account: Spomenificiraj račun
promote_user: Povišaj uporabnika
publish_terms_of_service: Objavi pogoje uporabe
reject_appeal: Zavrni pritožbo
reject_user: Zavrni uporabnika
remove_avatar_user: Odstrani avatar
@ -249,6 +258,7 @@ sl:
create_domain_block_html: "%{name} je blokiral/a domeno %{target}"
create_email_domain_block_html: "%{name} je dal/a na črni seznam e-pošto domene %{target}"
create_ip_block_html: "%{name} je ustvaril/a pravilo za IP %{target}"
create_relay_html: "%{name} je ustvaril/a rele %{target}"
create_unavailable_domain_html: "%{name} je prekinil/a dostavo v domeno %{target}"
create_user_role_html: "%{name} je ustvaril/a vlogo %{target}"
demote_user_html: "%{name} je ponižal/a uporabnika %{target}"
@ -260,18 +270,22 @@ sl:
destroy_email_domain_block_html: "%{name} je odblokiral/a e-pošto domene %{target}"
destroy_instance_html: "%{name} je očistil/a domeno %{target}"
destroy_ip_block_html: "%{name} je izbrisal/a pravilo za IP %{target}"
destroy_relay_html: "%{name} je izbrisal/a rele %{target}"
destroy_status_html: "%{name} je odstranil/a objavo uporabnika %{target}"
destroy_unavailable_domain_html: "%{name} je nadaljeval/a dostav v domeno %{target}"
destroy_user_role_html: "%{name} je izbrisal/a vlogo %{target}"
disable_2fa_user_html: "%{name} je onemogočil/a dvofaktorsko zahtevo za uporabnika %{target}"
disable_custom_emoji_html: "%{name} je onemogočil/a emotikone %{target}"
disable_relay_html: "%{name} je onemogočil/a rele %{target}"
disable_sign_in_token_auth_user_html: "%{name} je onemogočil/a overjanje z žetonom po e-pošti za uporabnika %{target}"
disable_user_html: "%{name} je onemogočil/a prijavo za uporabnika %{target}"
enable_custom_emoji_html: "%{name} je omogočil/a emotikone %{target}"
enable_relay_html: "%{name} je omogočil rele %{target}"
enable_sign_in_token_auth_user_html: "%{name} je omogočil/a overjanje z žetonom po e-pošti za uporabnika %{target}"
enable_user_html: "%{name} je omogočil/a prijavo za uporabnika %{target}"
memorialize_account_html: "%{name} je spremenil/a račun uporabnika %{target} v spominsko stran"
promote_user_html: "%{name} je povišal/a uporabnika %{target}"
publish_terms_of_service_html: "%{name} je posodobil/a pogoje uporabe"
reject_appeal_html: "%{name} je zavrnil/a pritožbo uporabnika %{target} na moderatorsko odločitev"
reject_user_html: "%{name} je zavrnil/a registracijo iz %{target}"
remove_avatar_user_html: "%{name} je odstranil podobo (avatar) uporabnika %{target}"
@ -301,6 +315,7 @@ sl:
title: Dnevnik revizije
unavailable_instance: "(ime domene ni na voljo)"
announcements:
back: Nazaj na oznanila
destroyed_msg: Obvestilo je bilo uspešno izbrisano!
edit:
title: Uredi obvestilo
@ -309,6 +324,9 @@ sl:
new:
create: Ustvari obvestilo
title: Novo obvestilo
preview:
explanation_html: 'E-poštno sporočilo bo poslano <strong>%{display_count} uporabnikom</strong>. Priloženo bo naslednje besedilo:'
title: Pokaži predogled oznanila
publish: Objavi
published_msg: Obvestilo je bilo uspešno objavljeno!
scheduled_for: Načrtovano ob %{time}
@ -486,6 +504,9 @@ sl:
title: Sledi priporočilom
unsuppress: Obnovi sledenje priporočilom
instances:
audit_log:
title: Nedavni revizijski zapisi
view_all: Prikaži ves revizijski dnevnik
availability:
description_html:
few: Če dostava v domeno spodleti <strong>%{count} različne dni</strong> brez uspeha, ne bo nadaljnjih poskusov dostopa, razen če je prejeta dostava <em>iz</em> domene.
@ -622,6 +643,7 @@ sl:
suspend_description_html: Račun in vsa njegova vsebina ne bo dostopna in bo postopoma izbrisana, interakcija z njim pa ne bo več možna. Dejanje je moč povrniti v roku 30 dni. Zaključi vse prijave zoper ta račun.
actions_description_html: Odločite se, katere ukrepe boste sprejeli za rešitev te prijave. Če sprejmete kazenski ukrep proti prijavljenemu računu, mu bo poslano e-poštno obvestilo, razen če je izbrana kategorija <strong>Neželena pošta</strong>.
actions_description_remote_html: Odločite se za dejanje, ki bo odločilo o tej prijavi. To bo vplivalo le na to, kako <strong>vaš</strong> strežnik komunicira s tem oddaljenim računom in obravnava njegovo vsebino.
actions_no_posts: To poročilo ni vezano na nobene objave, ki bi jih lahko izbrisali
add_to_report: Dodaj več v prijavo
already_suspended_badges:
local: Že suspendiran na tem strežniku
@ -838,6 +860,7 @@ sl:
back_to_account: Nazaj na stran računa
back_to_report: Nazaj na stran prijave
batch:
add_to_report: 'Dodaj poročilu #%{id}'
remove_from_report: Odstrani iz prijave
report: Poročaj
contents: Vsebina
@ -849,12 +872,17 @@ sl:
media:
title: Mediji
metadata: Metapodatki
no_history: Ta objava ni bila spremenjena
no_status_selected: Nobena objava ni bila spremenjena, ker ni bila nobena izbrana
open: Odpri objavo
original_status: Izvorna objava
reblogs: Ponovljeni blogi
replied_to_html: V odgovor %{acct_link}
status_changed: Objava spremenjena
status_title: Avtor/ica objave @%{name}
title: Objave računa - @%{name}
trending: V trendu
view_publicly: Prikaži javno
visibility: Vidnost
with_media: Z mediji
strikes:
@ -896,6 +924,9 @@ sl:
message_html: Nobenih pravil strežnika niste določili.
sidekiq_process_check:
message_html: Noben proces Sidekiq ne poteka za %{value} vrst. Preglejte svojo prilagoditev Sidekiq
software_version_check:
action: Oglejte si razpoložljive posodobitve
message_html: Na voljo je posodobitev Mastodona.
software_version_critical_check:
action: Glejte razpoložljive posodobitve
message_html: Na voljo je kritična posodobitev Mastodona. Posodobite čim prej.
@ -922,16 +953,42 @@ sl:
name: Ime
newest: Najnovejše
oldest: Najstarejše
open: Prikaži javno
reset: Ponastavi
review: Stanje pregleda
search: Išči
title: Ključniki
updated_msg: Nastavitve ključnikov uspešno posodobljene
terms_of_service:
back: Nazaj na pogoje uporabe
changelog: Kaj je novega
create: Uporabi svoje
current: Trenutni
draft: Osnutek
generate: Uporabi predlogo
generates:
action: Generiraj
chance_to_review_html: "<strong>Generirani pogoji uporabe ne bodo objavljeni samodejno,</strong> tako da jih boste imeli čas preveriti. Vnesite vse potrebne podatke."
explanation_html: Predloga pogojev uporabe je informativne narave in naj ne služi kot pravno vodilo. O pravnih vprašanjih in specifikah se posvetujte s pravnim strokovnjakom.
title: Postavitev pogojev uporabe
going_live_on_html: Objavljeni, začnejo veljati %{date}
history: Zgodovina
live: Objavljeni
no_history: V pogojih uporabe še ni zabeleženih sprememb.
no_terms_of_service_html: Trenutno nimate nastavljenih pogojev uporabe. Ti naj bi razjasnili pravno razmerje in dodeljevanje odgovornosti med vami in vašimi uporabniki v primeru spora.
notified_on_html: Uporabniki so obveščeni %{date}
notify_users: Obvesti uporabnike
preview:
explanation_html: 'E-poštno sporočilo bo poslano <strong>%{display_count} uporabnikom</strong>, ki so se registrirali pred %{date}. Priloženo bo naslednje besedilo:'
send_preview: Pošlji predogled na %{email}
send_to_all:
few: Pošlji %{display_count} e-poštna sporočila
one: Pošlji %{display_count} e-poštno sporočilo
other: Pošlji %{display_count} e-poštnih sporočil
two: Pošlji %{display_count} e-poštni sporočili
title: Prikaži predogled obvestila pogojev uporabe
publish: Objavi
published_on_html: Objavljeno %{date}
save_draft: Shrani osnutek
title: Pogoji uporabe
title: Upravljanje
@ -1173,6 +1230,7 @@ sl:
set_new_password: Nastavi novo geslo
setup:
email_below_hint_html: Poglejte v mapo neželene pošte ali zaprosite za novega. Če ste podali napačen e-naslov, ga lahko popravite.
email_settings_hint_html: Kliknite na povezavo, ki smo vam jo poslali na %{email}, pa boste lahko začeli uporabljati Mastodon. Tukajle bomo počakali.
link_not_received: Ali ste prejeli povezavo?
new_confirmation_instructions_sent: Čez nekaj minut boste prejeli novo e-sporočilo s potrditveno povezavo!
title: Preverite svojo dohodno e-pošto
@ -1181,6 +1239,7 @@ sl:
title: Vpiši se v %{domain}
sign_up:
manual_review: Registracije na %{domain} ročno pregledajo naši moderatorji. Da nam olajšate obdelavo vaše prijave, zapišite kaj o sebi in zakaj si želite račun na %{domain}.
preamble: Če ustvarite račun na tem strežniku Mastodona, boste lahko sledili komur koli v fediverzumu, ne glede na to, kje gostuje njegov/njen račun.
title: Naj vas namestimo na %{domain}.
status:
account_status: Stanje računa
@ -1192,8 +1251,16 @@ sl:
view_strikes: Pokaži pretekle ukrepe proti mojemu računu
too_fast: Obrazec oddan prehitro, poskusite znova.
use_security_key: Uporabi varnostni ključ
user_agreement_html: Prebral/a sem <a href="%{terms_of_service_path}" target="_blank">pogoje uporabe</a> in <a href="%{privacy_policy_path}" target="_blank">politiko zasebnosti</a> in z obojim soglašam
user_privacy_agreement_html: Prebral sem <a href="%{privacy_policy_path}" target="_blank">politiko zasebnosti</a> in soglašam z njo
author_attribution:
example_title: Vzorčno besedilo
hint_html: Ali pišete novičke ali spletni dnevnik kje drugje poleg Mastodona? Poskrbite, da bo vaše avtorstvo pravilno navedeno, ko bo kdo delil vaše delo na Mastodonu.
instructions: 'Poskrbite, da bo v dokumentu HTML vašega prispevka naslednja koda:'
more_from_html: Več od %{name}
s_blog: Spletni dnevnik %{name}
then_instructions: Nato dodajte ime domene, kamor objavljate, v spodnje polje.
title: Priznanje avtorstva
challenge:
confirm: Nadaljuj
hint_html: "<strong>Namig:</strong> naslednjo uro vas ne bomo več vprašali po vašem geslu."
@ -1404,6 +1471,27 @@ sl:
merge_long: Ohrani obstoječe zapise in dodaj nove
overwrite: Prepiši
overwrite_long: Zamenjaj trenutne zapise z novimi
overwrite_preambles:
blocking_html:
few: Kaže, da želite <strong>zamenjati svoj seznam blokiranih</strong> z do <strong>%{count} računi</strong> iz <strong>%{filename}</strong>.
one: Kaže, da želite <strong>zamenjati svoj seznam blokiranih</strong> z do <strong>%{count} računom</strong> iz <strong>%{filename}</strong>.
other: Kaže, da želite <strong>zamenjati svoj seznam blokiranih</strong> z do <strong>%{count} računi</strong> iz <strong>%{filename}</strong>.
two: Kaže, da želite <strong>zamenjati svoj seznam blokiranih</strong> z do <strong>%{count} računoma</strong> iz <strong>%{filename}</strong>.
bookmarks_html:
few: Kaže, da želite <strong>zamenjati svoje zaznamke</strong> z do <strong>%{count} objavami</strong> iz <strong>%{filename}</strong>.
one: Kaže, da želite <strong>zamenjati svoje zaznamke</strong> z do <strong>%{count} objavo</strong> iz <strong>%{filename}</strong>.
other: Kaže, da želite <strong>zamenjati svoje zaznamke</strong> z do <strong>%{count} objavami</strong> iz <strong>%{filename}</strong>.
two: Kaže, da želite <strong>zamenjati svoje zaznamke</strong> z do <strong>%{count} objavama</strong> iz <strong>%{filename}</strong>.
domain_blocking_html:
few: Kaže, da želite <strong>zamenjati svoj seznam blokiranih domen</strong> z do <strong>%{count} domenami</strong> iz <strong>%{filename}</strong>.
one: Kaže, da želite <strong>zamenjati svoj seznam blokiranih domen</strong> z do <strong>%{count} domeno</strong> iz <strong>%{filename}</strong>.
other: Kaže, da želite <strong>zamenjati svoj seznam blokiranih domen</strong> z do <strong>%{count} domenami</strong> iz <strong>%{filename}</strong>.
two: Kaže, da želite <strong>zamenjati svoj seznam blokiranih domen</strong> z do <strong>%{count} domenama</strong> iz <strong>%{filename}</strong>.
following_html:
few: Kaže, da želite <strong>slediti</strong> do <strong>%{count} računom</strong> iz <strong>%{filename}</strong> in <strong>nehati slediti komur koli drugemu</strong>.
one: Kaže, da želite <strong>slediti</strong> do <strong>%{count} računu</strong> iz <strong>%{filename}</strong> in <strong>nehati slediti komur koli drugemu</strong>.
other: Kaže, da želite <strong>slediti</strong> do <strong>%{count} računom</strong> iz <strong>%{filename}</strong> in <strong>nehati slediti komur koli drugemu</strong>.
two: Kaže, da želite <strong>slediti</strong> do <strong>%{count} računoma</strong> iz <strong>%{filename}</strong> in <strong>nehati slediti komur koli drugemu</strong>.
preface: Podatke, ki ste jih izvozili iz drugega strežnika, lahko uvozite. Na primer seznam oseb, ki jih spremljate ali blokirate.
recent_imports: Nedavni uvozi
states:
@ -1490,6 +1578,7 @@ sl:
media_attachments:
validations:
images_and_video: Videoposnetka ni mogoče priložiti objavi, ki že vsebuje slike
not_found: Predstavnosti %{ids} ne najdem ali pa je že pripeta k drugi objavi
not_ready: Datotek, katerih obdelava ni dokončana, ni mogoče pripeti. Poskusite znova kmalu!
too_many: Ni možno priložiti več kot 4 datoteke
migrations:
@ -1661,6 +1750,7 @@ sl:
scheduled_statuses:
over_daily_limit: Za ta dan ste presegli omejitev %{limit} načrtovanih objav
over_total_limit: Presegli ste omejitev %{limit} načrtovanih objav
too_soon: datum mora biti v prihodnosti
self_destruct:
lead_html: Na žalost se <strong>%{domain}</strong> za vedno zapira. Če ste tu imeli svoj račun, ga v prihodnje ne boste mogli več uporabljati. Zahtevate lahko kopijo svojih podatkov.
title: Ta strežnik se zapira
@ -1864,6 +1954,10 @@ sl:
recovery_instructions_html: Če kdaj izgubite dostop do telefona, lahko uporabite eno od spodnjih obnovitvenih kod, da ponovno pridobite dostop do svojega računa. <strong>Shranite obnovitvene kode</strong>. Lahko jih natisnete in shranite z drugimi pomembnimi dokumenti.
webauthn: Varnostni ključi
user_mailer:
announcement_published:
description: 'Skrbniki domene %{domain} oznanjajo:'
subject: Storitveno oznanilo
title: Storitveno oznanilo %{domain}
appeal_approved:
action: Nastavitve računa
explanation: Pritožbi na ukrep proti vašemu računu z dne %{strike_date}, ki ste jo oddali dne %{appeal_date}, je bilo ugodeno. Vaš račun je znova nesporen.
@ -1894,6 +1988,13 @@ sl:
subject: Do vašega računa je bil opravljen dostop z novega naslova IP
title: Nova prijava
terms_of_service_changed:
agreement: Če boste še naprej uporabljali %{domain}, se strinjate s temi pogoji. Če se ne, lahko kadarkoli odstopite od dogovora z domeno %{domain} tako, da izbrišete svoj račun.
changelog: 'Kratek povzetek tega, kaj ta posodobitev pomeni za vas:'
description: 'To e-poštno sporočilo ste prejeli, ker smo spremenili pogoje uporabe v domeni %{domain}. Posodobitve bodo začele veljati %{date}. Vabimo vas, da si posodobljene pogoje preberete tukaj:'
description_html: To e-poštno sporočilo ste prejeli, ker smo spremenili pogoje uporabe v domeni %{domain}. Posodobitve bodo začele veljati <strong>%{date}</strong>. Vabimo vas, da si posodobljene pogoje preberete <a href="%{path}" target="_blank">na tej povezavi</a>.
sign_off: Ekipa %{domain}
subject: Posodobitve naših pogojev uporabe
subtitle: Spreminjajo se pogoji uporabe domene %{domain}
title: Pomembna posodobitev
warning:
appeal: Pošlji pritožbo
@ -1984,6 +2085,7 @@ sl:
instructions_html: Spodnjo kodo kopirajte in prilepite v HTML svojega spletnega mesta. Nato dodajte naslov svoje spletne strani v eno od dodatnih polj v svojem profilu v zavihku »Uredi profil« in shranite spremembe.
verification: Potrditev
verified_links: Vaše preverjene povezave
website_verification: Overitev spletišča
webauthn_credentials:
add: Dodaj nov varnostni ključ
create:

View File

@ -325,7 +325,8 @@ uk:
create: Створити оголошення
title: Нове оголошення
preview:
title: Попередній перегляд повідомлення
explanation_html: 'Електронний лист буде надіслано <strong>%{display_count} користувачам</strong>. До електронного листа буде включено такий текст:'
title: Попередній перегляд сповіщення
publish: Опублікувати
published_msg: Оголошення успішно опубліковано!
scheduled_for: Заплановано на %{time}

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddFetchedRepliesAtToStatus < ActiveRecord::Migration[7.1]
def change
add_column :statuses, :fetched_replies_at, :datetime, null: true
end
end

View File

@ -1056,6 +1056,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_03_05_074104) do
t.datetime "edited_at", precision: nil
t.boolean "trendable"
t.bigint "ordered_media_attachment_ids", array: true
t.datetime "fetched_replies_at"
t.index ["account_id", "id", "visibility", "updated_at"], name: "index_statuses_20190820", order: { id: :desc }, where: "(deleted_at IS NULL)"
t.index ["account_id"], name: "index_statuses_on_account_id"
t.index ["deleted_at"], name: "index_statuses_on_deleted_at", where: "(deleted_at IS NOT NULL)"

View File

@ -15,6 +15,7 @@ RSpec.describe Api::Web::PushSubscriptionsController do
p256dh: 'BEm_a0bdPDhf0SOsrnB2-ategf1hHoCnpXgQsFj5JCkcoMrMt2WHoPfEYOYPzOIs9mZE8ZUaD7VA5vouy0kEkr8=',
auth: 'eH_C8rq2raXqlcBVDa1gLg==',
},
standard: standard,
},
}
end
@ -36,6 +37,7 @@ RSpec.describe Api::Web::PushSubscriptionsController do
},
}
end
let(:standard) { '1' }
before do
sign_in(user)
@ -51,14 +53,27 @@ RSpec.describe Api::Web::PushSubscriptionsController do
user.reload
expect(created_push_subscription).to have_attributes(
endpoint: eq(create_payload[:subscription][:endpoint]),
key_p256dh: eq(create_payload[:subscription][:keys][:p256dh]),
key_auth: eq(create_payload[:subscription][:keys][:auth])
)
expect(created_push_subscription)
.to have_attributes(
endpoint: eq(create_payload[:subscription][:endpoint]),
key_p256dh: eq(create_payload[:subscription][:keys][:p256dh]),
key_auth: eq(create_payload[:subscription][:keys][:auth])
)
.and be_standard
expect(user.session_activations.first.web_push_subscription).to eq(created_push_subscription)
end
context 'when standard is provided as false value' do
let(:standard) { '0' }
it 'saves push subscription with standard as false' do
post :create, format: :json, params: create_payload
expect(created_push_subscription)
.to_not be_standard
end
end
context 'with a user who has a session with a prior subscription' do
let!(:prior_subscription) { Fabricate(:web_push_subscription, session_activation: user.session_activations.last) }

View File

@ -0,0 +1,127 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Status::FetchRepliesConcern do
ActiveRecord.verbose_query_logs = true
let!(:alice) { Fabricate(:account, username: 'alice') }
let!(:bob) { Fabricate(:account, username: 'bob', domain: 'other.com') }
let!(:account) { alice }
let!(:status_old) { Fabricate(:status, account: account, fetched_replies_at: 1.year.ago, created_at: 1.year.ago) }
let!(:status_fetched_recently) { Fabricate(:status, account: account, fetched_replies_at: 1.second.ago, created_at: 1.year.ago) }
let!(:status_created_recently) { Fabricate(:status, account: account, created_at: 1.second.ago) }
let!(:status_never_fetched) { Fabricate(:status, account: account, created_at: 1.year.ago) }
describe 'should_fetch_replies' do
let!(:statuses) { Status.should_fetch_replies.all }
context 'with a local status' do
it 'never fetches local replies' do
expect(statuses).to eq([])
end
end
context 'with a remote status' do
let(:account) { bob }
it 'fetches old statuses' do
expect(statuses).to include(status_old)
end
it 'fetches statuses that have never been fetched and weren\'t created recently' do
expect(statuses).to include(status_never_fetched)
end
it 'does not fetch statuses that were fetched recently' do
expect(statuses).to_not include(status_fetched_recently)
end
it 'does not fetch statuses that were created recently' do
expect(statuses).to_not include(status_created_recently)
end
end
end
describe 'should_not_fetch_replies' do
let!(:statuses) { Status.should_not_fetch_replies.all }
context 'with a local status' do
it 'does not fetch local statuses' do
expect(statuses).to include(status_old, status_never_fetched, status_fetched_recently, status_never_fetched)
end
end
context 'with a remote status' do
let(:account) { bob }
it 'fetches old statuses' do
expect(statuses).to_not include(status_old)
end
it 'fetches statuses that have never been fetched and weren\'t created recently' do
expect(statuses).to_not include(status_never_fetched)
end
it 'does not fetch statuses that were fetched recently' do
expect(statuses).to include(status_fetched_recently)
end
it 'does not fetch statuses that were created recently' do
expect(statuses).to include(status_created_recently)
end
end
end
describe 'unsubscribed' do
let!(:spike) { Fabricate(:account, username: 'spike', domain: 'other.com') }
let!(:status) { Fabricate(:status, account: bob, updated_at: 1.day.ago) }
context 'when the status is from an account with only remote followers after last update' do
before do
Fabricate(:follow, account: spike, target_account: bob)
end
it 'shows the status as unsubscribed' do
expect(Status.unsubscribed).to eq([status])
end
end
context 'when the status is from an account with only remote followers before last update' do
before do
Fabricate(:follow, account: spike, target_account: bob, created_at: 2.days.ago)
end
it 'shows the status as unsubscribed' do
expect(Status.unsubscribed).to eq([status])
end
end
context 'when status is from account with local followers after last update' do
before do
Fabricate(:follow, account: alice, target_account: bob)
end
it 'shows the status as unsubscribed' do
expect(Status.unsubscribed).to eq([status])
end
end
context 'when status is from account with local followers before last update' do
before do
Fabricate(:follow, account: alice, target_account: bob, created_at: 2.days.ago)
end
it 'does not show the status as unsubscribed' do
expect(Status.unsubscribed).to eq([])
end
end
context 'when the status has no followers' do
it 'shows the status as unsubscribed' do
expect(Status.unsubscribed).to eq([status])
end
end
end
end

View File

@ -16,6 +16,7 @@ RSpec.describe 'API V1 Push Subscriptions' do
subscription: {
endpoint: endpoint,
keys: keys,
standard: standard,
},
}.with_indifferent_access
end
@ -36,6 +37,7 @@ RSpec.describe 'API V1 Push Subscriptions' do
},
}.with_indifferent_access
end
let(:standard) { '1' }
let(:scopes) { 'push' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
@ -66,6 +68,7 @@ RSpec.describe 'API V1 Push Subscriptions' do
user_id: eq(user.id),
access_token_id: eq(token.id)
)
.and be_standard
expect(response.parsed_body.with_indifferent_access)
.to include(
@ -73,6 +76,17 @@ RSpec.describe 'API V1 Push Subscriptions' do
)
end
context 'when standard is provided as false value' do
let(:standard) { '0' }
it 'saves push subscription with standard as false' do
subject
expect(endpoint_push_subscription)
.to_not be_standard
end
end
it 'replaces old subscription on repeat calls' do
2.times { subject }

View File

@ -0,0 +1,124 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe ActivityPub::FetchAllRepliesService do
subject { described_class.new }
let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') }
let(:status) { Fabricate(:status, account: actor) }
let(:collection_uri) { 'http://example.com/replies/1' }
let(:items) do
%w(
http://example.com/self-reply-1
http://example.com/self-reply-2
http://example.com/self-reply-3
http://other.com/other-reply-1
http://other.com/other-reply-2
http://other.com/other-reply-3
http://example.com/self-reply-4
http://example.com/self-reply-5
http://example.com/self-reply-6
)
end
let(:payload) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
type: 'Collection',
id: collection_uri,
items: items,
}.with_indifferent_access
end
describe '#call' do
it 'fetches more than the default maximum and from multiple domains' do
allow(FetchReplyWorker).to receive(:push_bulk)
subject.call(status.uri, payload)
expect(FetchReplyWorker).to have_received(:push_bulk).with(
%w(
http://example.com/self-reply-1
http://example.com/self-reply-2
http://example.com/self-reply-3
http://other.com/other-reply-1
http://other.com/other-reply-2
http://other.com/other-reply-3
http://example.com/self-reply-4
http://example.com/self-reply-5
http://example.com/self-reply-6
)
)
end
context 'with a recent status' do
before do
Fabricate(:status, uri: 'http://example.com/self-reply-2', fetched_replies_at: 1.second.ago, local: false)
end
it 'skips statuses that have been updated recently' do
allow(FetchReplyWorker).to receive(:push_bulk)
subject.call(status.uri, payload)
expect(FetchReplyWorker).to have_received(:push_bulk).with(
%w(
http://example.com/self-reply-1
http://example.com/self-reply-3
http://other.com/other-reply-1
http://other.com/other-reply-2
http://other.com/other-reply-3
http://example.com/self-reply-4
http://example.com/self-reply-5
http://example.com/self-reply-6
)
)
end
end
context 'with an old status' do
before do
Fabricate(:status, uri: 'http://other.com/other-reply-1', fetched_replies_at: 1.year.ago, created_at: 1.year.ago, account: actor)
end
it 'updates the time that fetched statuses were last fetched' do
allow(FetchReplyWorker).to receive(:push_bulk)
subject.call(status.uri, payload)
expect(Status.find_by(uri: 'http://other.com/other-reply-1').fetched_replies_at).to be >= 1.minute.ago
end
end
context 'with unsubscribed replies' do
before do
remote_actor = Fabricate(:account, domain: 'other.com', uri: 'http://other.com/account')
# reply not in the collection from the remote instance, but we know about anyway without anyone following the account
Fabricate(:status, account: remote_actor, in_reply_to_id: status.id, uri: 'http://other.com/account/unsubscribed', fetched_replies_at: 1.year.ago, created_at: 1.year.ago)
end
it 'updates the unsubscribed replies' do
allow(FetchReplyWorker).to receive(:push_bulk)
subject.call(status.uri, payload)
expect(FetchReplyWorker).to have_received(:push_bulk).with(
%w(
http://example.com/self-reply-1
http://example.com/self-reply-2
http://example.com/self-reply-3
http://other.com/other-reply-1
http://other.com/other-reply-2
http://other.com/other-reply-3
http://example.com/self-reply-4
http://example.com/self-reply-5
http://example.com/self-reply-6
http://other.com/account/unsubscribed
)
)
end
end
end
end

View File

@ -9,6 +9,9 @@ RSpec.describe ActivityPub::FetchRemoteStatusService do
let!(:sender) { Fabricate(:account, domain: 'foo.bar', uri: 'https://foo.bar') }
let(:follower) { Fabricate(:account, username: 'alice') }
let(:follow) { nil }
let(:response) { { body: Oj.dump(object), headers: { 'content-type': 'application/activity+json' } } }
let(:existing_status) { nil }
let(:note) do
@ -23,13 +26,14 @@ RSpec.describe ActivityPub::FetchRemoteStatusService do
before do
stub_request(:get, 'https://foo.bar/watch?v=12345').to_return(status: 404, body: '')
stub_request(:get, object[:id]).to_return(body: Oj.dump(object))
stub_request(:get, object[:id]).to_return(**response)
end
describe '#call' do
before do
follow
existing_status
subject.call(object[:id], prefetched_body: Oj.dump(object))
subject.call(object[:id])
end
context 'with Note object' do
@ -254,6 +258,45 @@ RSpec.describe ActivityPub::FetchRemoteStatusService do
expect(existing_status.text).to eq 'Lorem ipsum'
expect(existing_status.edits).to_not be_empty
end
context 'when the status appears to have been deleted at source' do
let(:response) { { status: 404, body: '' } }
shared_examples 'no delete' do
it 'does not delete the status' do
existing_status.reload
expect(existing_status.text).to eq 'Foo'
expect(existing_status.edits).to be_empty
end
end
context 'when the status is orphaned/unsubscribed' do
it 'deletes the orphaned status' do
expect { existing_status.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end
context 'when the status is from an account with only remote followers' do
let(:follower) { Fabricate(:account, username: 'alice', domain: 'foo.bar') }
let(:follow) { Fabricate(:follow, account: follower, target_account: sender, created_at: 2.days.ago) }
it 'deletes the orphaned status' do
expect { existing_status.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
context 'when the status is private' do
let(:existing_status) { Fabricate(:status, account: sender, text: 'Foo', uri: note[:id], visibility: :private) }
it_behaves_like 'no delete'
end
context 'when the status is direct' do
let(:existing_status) { Fabricate(:status, account: sender, text: 'Foo', uri: note[:id], visibility: :direct) }
it_behaves_like 'no delete'
end
end
end
end
context 'with a Create activity' do

View File

@ -40,7 +40,7 @@ RSpec.describe ActivityPub::FetchRepliesService do
it 'queues the expected worker' do
allow(FetchReplyWorker).to receive(:push_bulk)
subject.call(status, payload)
subject.call(status.account.uri, payload)
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1'])
end
@ -50,7 +50,7 @@ RSpec.describe ActivityPub::FetchRepliesService do
it 'spawns workers for up to 5 replies on the same server' do
allow(FetchReplyWorker).to receive(:push_bulk)
subject.call(status, payload)
subject.call(status.account.uri, payload)
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
end
@ -64,7 +64,7 @@ RSpec.describe ActivityPub::FetchRepliesService do
it 'spawns workers for up to 5 replies on the same server' do
allow(FetchReplyWorker).to receive(:push_bulk)
subject.call(status, collection_uri)
subject.call(status.account.uri, collection_uri)
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
end
@ -85,7 +85,7 @@ RSpec.describe ActivityPub::FetchRepliesService do
it 'spawns workers for up to 5 replies on the same server' do
allow(FetchReplyWorker).to receive(:push_bulk)
subject.call(status, payload)
subject.call(status.account.uri, payload)
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
end
@ -99,7 +99,7 @@ RSpec.describe ActivityPub::FetchRepliesService do
it 'spawns workers for up to 5 replies on the same server' do
allow(FetchReplyWorker).to receive(:push_bulk)
subject.call(status, collection_uri)
subject.call(status.account.uri, collection_uri)
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
end
@ -124,7 +124,7 @@ RSpec.describe ActivityPub::FetchRepliesService do
it 'spawns workers for up to 5 replies on the same server' do
allow(FetchReplyWorker).to receive(:push_bulk)
subject.call(status, payload)
subject.call(status.account.uri, payload)
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
end
@ -138,7 +138,7 @@ RSpec.describe ActivityPub::FetchRepliesService do
it 'spawns workers for up to 5 replies on the same server' do
allow(FetchReplyWorker).to receive(:push_bulk)
subject.call(status, collection_uri)
subject.call(status.account.uri, collection_uri)
expect(FetchReplyWorker).to have_received(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5'])
end

View File

@ -0,0 +1,281 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe ActivityPub::FetchAllRepliesWorker do
subject { described_class.new }
let(:top_items) do
[
'http://example.com/self-reply-1',
'http://other.com/other-reply-2',
'http://example.com/self-reply-3',
]
end
let(:top_items_paged) do
[
'http://example.com/self-reply-4',
'http://other.com/other-reply-5',
'http://example.com/self-reply-6',
]
end
let(:nested_items) do
[
'http://example.com/nested-self-reply-1',
'http://other.com/nested-other-reply-2',
'http://example.com/nested-self-reply-3',
]
end
let(:nested_items_paged) do
[
'http://example.com/nested-self-reply-4',
'http://other.com/nested-other-reply-5',
'http://example.com/nested-self-reply-6',
]
end
let(:all_items) do
top_items + top_items_paged + nested_items + nested_items_paged
end
let(:top_note_uri) do
'http://example.com/top-post'
end
let(:top_collection_uri) do
'http://example.com/top-post/replies'
end
# The reply uri that has the nested replies under it
let(:reply_note_uri) do
'http://other.com/other-reply-2'
end
# The collection uri of nested replies
let(:reply_collection_uri) do
'http://other.com/other-reply-2/replies'
end
let(:replies_top) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: top_collection_uri,
type: 'Collection',
items: top_items + top_items_paged,
}
end
let(:replies_nested) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: reply_collection_uri,
type: 'Collection',
items: nested_items + nested_items_paged,
}
end
# The status resource for the top post
let(:top_object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: top_note_uri,
type: 'Note',
content: 'Lorem ipsum',
replies: replies_top,
attributedTo: 'https://example.com',
}
end
# The status resource that has the uri to the replies collection
let(:reply_object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: reply_note_uri,
type: 'Note',
content: 'Lorem ipsum',
replies: replies_nested,
attributedTo: 'https://other.com',
}
end
let(:empty_object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: 'https://example.com/empty',
type: 'Note',
content: 'Lorem ipsum',
replies: [],
attributedTo: 'https://example.com',
}
end
let(:account) { Fabricate(:account, domain: 'example.com') }
let(:status) do
Fabricate(
:status,
account: account,
uri: top_note_uri,
created_at: 1.day.ago - Status::FetchRepliesConcern::FETCH_REPLIES_INITIAL_WAIT_MINUTES
)
end
before do
stub_const('Status::FetchRepliesConcern::FETCH_REPLIES_ENABLED', true)
allow(FetchReplyWorker).to receive(:push_bulk)
all_items.each do |item|
next if [top_note_uri, reply_note_uri].include? item
stub_request(:get, item).to_return(status: 200, body: Oj.dump(empty_object), headers: { 'Content-Type': 'application/activity+json' })
end
stub_request(:get, top_note_uri).to_return(status: 200, body: Oj.dump(top_object), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, reply_note_uri).to_return(status: 200, body: Oj.dump(reply_object), headers: { 'Content-Type': 'application/activity+json' })
end
shared_examples 'fetches all replies' do
it 'fetches statuses recursively' do
got_uris = subject.perform(status.id)
expect(got_uris).to match_array(all_items)
end
it 'respects the maximum limits set by not recursing after the max is reached' do
stub_const('ActivityPub::FetchAllRepliesWorker::MAX_REPLIES', 5)
got_uris = subject.perform(status.id)
expect(got_uris).to match_array(top_items + top_items_paged)
end
end
describe 'perform' do
context 'when the payload is a Note with replies as a Collection of inlined replies' do
it_behaves_like 'fetches all replies'
end
context 'when the payload is a Note with replies as a URI to a Collection' do
let(:top_object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: top_note_uri,
type: 'Note',
content: 'Lorem ipsum',
replies: top_collection_uri,
attributedTo: 'https://example.com',
}
end
let(:reply_object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: reply_note_uri,
type: 'Note',
content: 'Lorem ipsum',
replies: reply_collection_uri,
attributedTo: 'https://other.com',
}
end
before do
stub_request(:get, top_collection_uri).to_return(status: 200, body: Oj.dump(replies_top), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, reply_collection_uri).to_return(status: 200, body: Oj.dump(replies_nested), headers: { 'Content-Type': 'application/activity+json' })
end
it_behaves_like 'fetches all replies'
end
context 'when the payload is a Note with replies as a paginated collection' do
let(:top_page_2_uri) do
"#{top_collection_uri}/2"
end
let(:reply_page_2_uri) do
"#{reply_collection_uri}/2"
end
let(:top_object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: top_note_uri,
type: 'Note',
content: 'Lorem ipsum',
replies: {
type: 'Collection',
id: top_collection_uri,
first: {
type: 'CollectionPage',
partOf: top_collection_uri,
items: top_items,
next: top_page_2_uri,
},
},
attributedTo: 'https://example.com',
}
end
let(:reply_object) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: reply_note_uri,
type: 'Note',
content: 'Lorem ipsum',
replies: {
type: 'Collection',
id: reply_collection_uri,
first: {
type: 'CollectionPage',
partOf: reply_collection_uri,
items: nested_items,
next: reply_page_2_uri,
},
},
attributedTo: 'https://other.com',
}
end
let(:top_page_two) do
{
type: 'CollectionPage',
id: top_page_2_uri,
partOf: top_collection_uri,
items: top_items_paged,
}
end
let(:reply_page_two) do
{
type: 'CollectionPage',
id: reply_page_2_uri,
partOf: reply_collection_uri,
items: nested_items_paged,
}
end
before do
stub_request(:get, top_page_2_uri).to_return(status: 200, body: Oj.dump(top_page_two), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, reply_page_2_uri).to_return(status: 200, body: Oj.dump(reply_page_two), headers: { 'Content-Type': 'application/activity+json' })
end
it_behaves_like 'fetches all replies'
it 'limits by max pages' do
stub_const('ActivityPub::FetchAllRepliesWorker::MAX_PAGES', 3)
got_uris = subject.perform(status.id)
expect(got_uris).to match_array(top_items + top_items_paged + nested_items)
end
end
context 'when replies should not be fetched' do
# ensure that we should not fetch by setting the status to be created in the debounce window
let(:status) { Fabricate(:status, account: account, uri: top_note_uri, created_at: DateTime.now) }
before do
stub_const('Status::FetchRepliesConcern::FETCH_REPLIES_INITIAL_WAIT_MINUTES', 1.week)
end
it 'returns nil without fetching' do
got_uris = subject.perform(status.id)
expect(got_uris).to be_nil
assert_not_requested :get, top_note_uri
end
end
end
end

132
yarn.lock
View File

@ -74,38 +74,38 @@ __metadata:
linkType: hard
"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1, @babel/core@npm:^7.24.4, @babel/core@npm:^7.25.0":
version: 7.26.9
resolution: "@babel/core@npm:7.26.9"
version: 7.26.10
resolution: "@babel/core@npm:7.26.10"
dependencies:
"@ampproject/remapping": "npm:^2.2.0"
"@babel/code-frame": "npm:^7.26.2"
"@babel/generator": "npm:^7.26.9"
"@babel/generator": "npm:^7.26.10"
"@babel/helper-compilation-targets": "npm:^7.26.5"
"@babel/helper-module-transforms": "npm:^7.26.0"
"@babel/helpers": "npm:^7.26.9"
"@babel/parser": "npm:^7.26.9"
"@babel/helpers": "npm:^7.26.10"
"@babel/parser": "npm:^7.26.10"
"@babel/template": "npm:^7.26.9"
"@babel/traverse": "npm:^7.26.9"
"@babel/types": "npm:^7.26.9"
"@babel/traverse": "npm:^7.26.10"
"@babel/types": "npm:^7.26.10"
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: 10c0/ed7212ff42a9453765787019b7d191b167afcacd4bd8fec10b055344ef53fa0cc648c9a80159ae4ecf870016a6318731e087042dcb68d1a2a9d34eb290dc014b
checksum: 10c0/e046e0e988ab53841b512ee9d263ca409f6c46e2a999fe53024688b92db394346fa3aeae5ea0866331f62133982eee05a675d22922a4603c3f603aa09a581d62
languageName: node
linkType: hard
"@babel/generator@npm:^7.26.9, @babel/generator@npm:^7.7.2":
version: 7.26.9
resolution: "@babel/generator@npm:7.26.9"
"@babel/generator@npm:^7.26.10, @babel/generator@npm:^7.7.2":
version: 7.26.10
resolution: "@babel/generator@npm:7.26.10"
dependencies:
"@babel/parser": "npm:^7.26.9"
"@babel/types": "npm:^7.26.9"
"@babel/parser": "npm:^7.26.10"
"@babel/types": "npm:^7.26.10"
"@jridgewell/gen-mapping": "npm:^0.3.5"
"@jridgewell/trace-mapping": "npm:^0.3.25"
jsesc: "npm:^3.0.2"
checksum: 10c0/6b78872128205224a9a9761b9ea7543a9a7902a04b82fc2f6801ead4de8f59056bab3fd17b1f834ca7b049555fc4c79234b9a6230dd9531a06525306050becad
checksum: 10c0/88b3b3ea80592fc89349c4e1a145e1386e4042866d2507298adf452bf972f68d13bf699a845e6ab8c028bd52c2247013eb1221b86e1db5c9779faacba9c4b10e
languageName: node
linkType: hard
@ -171,7 +171,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-define-polyfill-provider@npm:^0.6.1, @babel/helper-define-polyfill-provider@npm:^0.6.2, @babel/helper-define-polyfill-provider@npm:^0.6.3":
"@babel/helper-define-polyfill-provider@npm:^0.6.1, @babel/helper-define-polyfill-provider@npm:^0.6.3":
version: 0.6.3
resolution: "@babel/helper-define-polyfill-provider@npm:0.6.3"
dependencies:
@ -303,24 +303,24 @@ __metadata:
languageName: node
linkType: hard
"@babel/helpers@npm:^7.26.9":
version: 7.26.9
resolution: "@babel/helpers@npm:7.26.9"
"@babel/helpers@npm:^7.26.10":
version: 7.26.10
resolution: "@babel/helpers@npm:7.26.10"
dependencies:
"@babel/template": "npm:^7.26.9"
"@babel/types": "npm:^7.26.9"
checksum: 10c0/3d4dbc4a33fe4181ed810cac52318b578294745ceaec07e2f6ecccf6cda55d25e4bfcea8f085f333bf911c9e1fc13320248dd1d5315ab47ad82ce1077410df05
"@babel/types": "npm:^7.26.10"
checksum: 10c0/f99e1836bcffce96db43158518bb4a24cf266820021f6461092a776cba2dc01d9fc8b1b90979d7643c5c2ab7facc438149064463a52dd528b21c6ab32509784f
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.26.9":
version: 7.26.9
resolution: "@babel/parser@npm:7.26.9"
"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.26.10, @babel/parser@npm:^7.26.9":
version: 7.26.10
resolution: "@babel/parser@npm:7.26.10"
dependencies:
"@babel/types": "npm:^7.26.9"
"@babel/types": "npm:^7.26.10"
bin:
parser: ./bin/babel-parser.js
checksum: 10c0/4b9ef3c9a0d4c328e5e5544f50fe8932c36f8a2c851e7f14a85401487cd3da75cad72c2e1bcec1eac55599a6bbb2fdc091f274c4fcafa6bdd112d4915ff087fc
checksum: 10c0/c47f5c0f63cd12a663e9dc94a635f9efbb5059d98086a92286d7764357c66bceba18ccbe79333e01e9be3bfb8caba34b3aaebfd8e62c3d5921c8cf907267be75
languageName: node
linkType: hard
@ -1137,18 +1137,18 @@ __metadata:
linkType: hard
"@babel/plugin-transform-runtime@npm:^7.22.4":
version: 7.26.9
resolution: "@babel/plugin-transform-runtime@npm:7.26.9"
version: 7.26.10
resolution: "@babel/plugin-transform-runtime@npm:7.26.10"
dependencies:
"@babel/helper-module-imports": "npm:^7.25.9"
"@babel/helper-plugin-utils": "npm:^7.26.5"
babel-plugin-polyfill-corejs2: "npm:^0.4.10"
babel-plugin-polyfill-corejs3: "npm:^0.10.6"
babel-plugin-polyfill-corejs3: "npm:^0.11.0"
babel-plugin-polyfill-regenerator: "npm:^0.6.1"
semver: "npm:^6.3.1"
peerDependencies:
"@babel/core": ^7.0.0-0
checksum: 10c0/2c4d77d0671badc7fd53dcd7015df5db892712436c7e9740ffb2f5b85e8591e5bfe208f78dff402b4ee2d55d0f7a3c0a1102c683f333f4ee0cfa62f68ea68842
checksum: 10c0/4b70a63b904a3f7faa6ca95f9034d2f29330764820b06cf1814dda4ab0482b233a28241e98d8497bc1690dd31972e72861d8534ae0e37f26e04637e7d615e43d
languageName: node
linkType: hard
@ -1403,11 +1403,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.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.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.26.9
resolution: "@babel/runtime@npm:7.26.9"
version: 7.26.10
resolution: "@babel/runtime@npm:7.26.10"
dependencies:
regenerator-runtime: "npm:^0.14.0"
checksum: 10c0/e8517131110a6ec3a7360881438b85060e49824e007f4a64b5dfa9192cf2bb5c01e84bfc109f02d822c7edb0db926928dd6b991e3ee460b483fb0fac43152d9b
checksum: 10c0/6dc6d88c7908f505c4f7770fb4677dfa61f68f659b943c2be1f2a99cb6680343462867abf2d49822adc435932919b36c77ac60125793e719ea8745f2073d3745
languageName: node
linkType: hard
@ -1422,28 +1422,28 @@ __metadata:
languageName: node
linkType: hard
"@babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.8, @babel/traverse@npm:^7.26.9":
version: 7.26.9
resolution: "@babel/traverse@npm:7.26.9"
"@babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.10, @babel/traverse@npm:^7.26.8":
version: 7.26.10
resolution: "@babel/traverse@npm:7.26.10"
dependencies:
"@babel/code-frame": "npm:^7.26.2"
"@babel/generator": "npm:^7.26.9"
"@babel/parser": "npm:^7.26.9"
"@babel/generator": "npm:^7.26.10"
"@babel/parser": "npm:^7.26.10"
"@babel/template": "npm:^7.26.9"
"@babel/types": "npm:^7.26.9"
"@babel/types": "npm:^7.26.10"
debug: "npm:^4.3.1"
globals: "npm:^11.1.0"
checksum: 10c0/51dd57fa39ea34d04816806bfead04c74f37301269d24c192d1406dc6e244fea99713b3b9c5f3e926d9ef6aa9cd5c062ad4f2fc1caa9cf843d5e864484ac955e
checksum: 10c0/4e86bb4e3c30a6162bb91df86329df79d96566c3e2d9ccba04f108c30473a3a4fd360d9990531493d90f6a12004f10f616bf9b9229ca30c816b708615e9de2ac
languageName: node
linkType: hard
"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.9, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4":
version: 7.26.9
resolution: "@babel/types@npm:7.26.9"
"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.10, @babel/types@npm:^7.26.9, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4":
version: 7.26.10
resolution: "@babel/types@npm:7.26.10"
dependencies:
"@babel/helper-string-parser": "npm:^7.25.9"
"@babel/helper-validator-identifier": "npm:^7.25.9"
checksum: 10c0/999c56269ba00e5c57aa711fbe7ff071cd6990bafd1b978341ea7572cc78919986e2aa6ee51dacf4b6a7a6fa63ba4eb3f1a03cf55eee31b896a56d068b895964
checksum: 10c0/7a7f83f568bfc3dfabfaf9ae3a97ab5c061726c0afa7dcd94226d4f84a81559da368ed79671e3a8039d16f12476cf110381a377ebdea07587925f69628200dac
languageName: node
linkType: hard
@ -5244,13 +5244,13 @@ __metadata:
linkType: hard
"axios@npm:^1.4.0":
version: 1.8.2
resolution: "axios@npm:1.8.2"
version: 1.8.3
resolution: "axios@npm:1.8.3"
dependencies:
follow-redirects: "npm:^1.15.6"
form-data: "npm:^4.0.0"
proxy-from-env: "npm:^1.1.0"
checksum: 10c0/d8c2969e4642dc6d39555ac58effe06c051ba7aac2bd40cad7a9011c019fb2f16ee011c5a6906cb25b8a4f87258c359314eb981f852e60ad445ecaeb793c7aa2
checksum: 10c0/de75da9859adf0a6481d4af2b687db357a054d20f0d69b99d502b71dae3578326b1fdc0951dabaef769827484941cda93d3f89150bf9e04f05f6615fb8316780
languageName: node
linkType: hard
@ -5387,18 +5387,6 @@ __metadata:
languageName: node
linkType: hard
"babel-plugin-polyfill-corejs3@npm:^0.10.6":
version: 0.10.6
resolution: "babel-plugin-polyfill-corejs3@npm:0.10.6"
dependencies:
"@babel/helper-define-polyfill-provider": "npm:^0.6.2"
core-js-compat: "npm:^3.38.0"
peerDependencies:
"@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
checksum: 10c0/3a69220471b07722c2ae6537310bf26b772514e12b601398082965459c838be70a0ca70b0662f0737070654ff6207673391221d48599abb4a2b27765206d9f79
languageName: node
linkType: hard
"babel-plugin-polyfill-corejs3@npm:^0.11.0":
version: 0.11.1
resolution: "babel-plugin-polyfill-corejs3@npm:0.11.1"
@ -6477,7 +6465,7 @@ __metadata:
languageName: node
linkType: hard
"core-js-compat@npm:^3.38.0, core-js-compat@npm:^3.40.0":
"core-js-compat@npm:^3.40.0":
version: 3.40.0
resolution: "core-js-compat@npm:3.40.0"
dependencies:
@ -13182,19 +13170,19 @@ __metadata:
languageName: node
linkType: hard
"pg-pool@npm:^3.7.1":
version: 3.7.1
resolution: "pg-pool@npm:3.7.1"
"pg-pool@npm:^3.8.0":
version: 3.8.0
resolution: "pg-pool@npm:3.8.0"
peerDependencies:
pg: ">=8.0"
checksum: 10c0/65bff013102684774f4cfdffbfe0a2b0614252234561d391608f7fd915477e44f5fd0e1968ecc2f42032dcf8bac241d2f724c4f3df90384567d22df37dd3b6ba
checksum: 10c0/c05287b0caafeab43807e6ad22d153c09c473dbeb5b2cea13b83102376e9a56f46b91fa9adf9d53885ce198280c6a95555390987c42b3858d1936d3e0cdc83aa
languageName: node
linkType: hard
"pg-protocol@npm:*, pg-protocol@npm:^1.7.1":
version: 1.7.1
resolution: "pg-protocol@npm:1.7.1"
checksum: 10c0/3168d407ddc4c0fa2403eb9b49205399d4bc53dadbafdfcc5d25fa61b860a31c25df25704cf14c8140c80f0a41061d586e5fd5ce9bf800dfb91e9ce810bc2c37
"pg-protocol@npm:*, pg-protocol@npm:^1.8.0":
version: 1.8.0
resolution: "pg-protocol@npm:1.8.0"
checksum: 10c0/2be784955599d84b564795952cee52cc2b8eab0be43f74fc1061506353801e282c1d52c9e0691a9b72092c1f3fde370e9b181e80fef6bb82a9b8d1618bfa91e6
languageName: node
linkType: hard
@ -13227,13 +13215,13 @@ __metadata:
linkType: hard
"pg@npm:^8.5.0":
version: 8.13.3
resolution: "pg@npm:8.13.3"
version: 8.14.0
resolution: "pg@npm:8.14.0"
dependencies:
pg-cloudflare: "npm:^1.1.1"
pg-connection-string: "npm:^2.7.0"
pg-pool: "npm:^3.7.1"
pg-protocol: "npm:^1.7.1"
pg-pool: "npm:^3.8.0"
pg-protocol: "npm:^1.8.0"
pg-types: "npm:^2.1.0"
pgpass: "npm:1.x"
peerDependencies:
@ -13244,7 +13232,7 @@ __metadata:
peerDependenciesMeta:
pg-native:
optional: true
checksum: 10c0/7296f0e5930b35faef471be2673210cda553b30f1b8e9d176fcc286aa43248e17e09336032bf5a6bba55d2cc2d03afb8a407b5a6e6bc56ebb331c02d1a7ccc05
checksum: 10c0/14d9fe726189107b028d5603b299776d039e36ed657c99057bcc1c125f889cb46536e0c48c6d98952231733c788f98c631bf74d5f8c9cbf85c4ac7c0a119b8b4
languageName: node
linkType: hard