mirror of
https://git.kescher.at/CatCatNya/catstodon.git
synced 2025-01-18 12:44:04 +01:00
Merge commit '34cd7d6585992c03298c175ab5d22ad059b58cdb' into glitch-soc/merge-upstream
Conflicts: - `CONTRIBUTING.md`: Upstream changed the file, while we had a different one. Updated the common parts. - `README.md`: Upstream changed the file, while we had a different one. Updated the common parts. - `app/helpers/application_helper.rb`: Upstream added helpers where glitch-soc had extra ones. Added upstream's new helpers. - `app/models/form/admin_settings.rb`: Upstream added some custom handling of one setting, while glitch-soc had additional code. Ported upstream's code. - `lib/mastodon/version.rb`: Upstream moved some things to `config/mastodon.yml`. Did the same. - `spec/requests/api/v1/accounts/credentials_spec.rb`: I don't know honestly.
This commit is contained in:
commit
155dc4bc4b
127 changed files with 1766 additions and 1224 deletions
|
@ -1,10 +1,6 @@
|
||||||
[production]
|
|
||||||
defaults
|
defaults
|
||||||
> 0.2%
|
> 0.2%
|
||||||
firefox >= 78
|
firefox >= 78
|
||||||
ios >= 15.6
|
ios >= 15.6
|
||||||
not dead
|
not dead
|
||||||
not OperaMini all
|
not OperaMini all
|
||||||
|
|
||||||
[development]
|
|
||||||
supports es6-module
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ body:
|
||||||
Any additional technical details you may have, like logs or error traces
|
Any additional technical details you may have, like logs or error traces
|
||||||
value: |
|
value: |
|
||||||
If this is happening on your own Mastodon server, please fill out those:
|
If this is happening on your own Mastodon server, please fill out those:
|
||||||
- Ruby version: (from `ruby --version`, eg. v3.3.5)
|
- Ruby version: (from `ruby --version`, eg. v3.4.1)
|
||||||
- Node.js version: (from `node --version`, eg. v20.18.0)
|
- Node.js version: (from `node --version`, eg. v20.18.0)
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/3.troubleshooting.yml
vendored
2
.github/ISSUE_TEMPLATE/3.troubleshooting.yml
vendored
|
@ -60,7 +60,7 @@ body:
|
||||||
value: |
|
value: |
|
||||||
Please at least include those informations:
|
Please at least include those informations:
|
||||||
- Operating system: (eg. Ubuntu 22.04)
|
- Operating system: (eg. Ubuntu 22.04)
|
||||||
- Ruby version: (from `ruby --version`, eg. v3.3.5)
|
- Ruby version: (from `ruby --version`, eg. v3.4.1)
|
||||||
- Node.js version: (from `node --version`, eg. v20.18.0)
|
- Node.js version: (from `node --version`, eg. v20.18.0)
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|
5
.github/renovate.json5
vendored
5
.github/renovate.json5
vendored
|
@ -14,11 +14,6 @@
|
||||||
// If we do not want a package to be grouped with others, we need to set its groupName
|
// If we do not want a package to be grouped with others, we need to set its groupName
|
||||||
// to `null` after any other rule set it to something.
|
// to `null` after any other rule set it to something.
|
||||||
dependencyDashboardHeader: 'This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more. Before approving any upgrade: read the description and comments in the [`renovate.json5` file](https://github.com/mastodon/mastodon/blob/main/.github/renovate.json5).',
|
dependencyDashboardHeader: 'This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more. Before approving any upgrade: read the description and comments in the [`renovate.json5` file](https://github.com/mastodon/mastodon/blob/main/.github/renovate.json5).',
|
||||||
constraints: {
|
|
||||||
// Mastodon should work on Ruby 3.4, but its test dependencies are currently uninstallable on Ruby 3.4.
|
|
||||||
// TODO: remove this once https://github.com/briandunn/flatware/issues/103 is fixed
|
|
||||||
ruby: '3.3',
|
|
||||||
},
|
|
||||||
postUpdateOptions: ['yarnDedupeHighest'],
|
postUpdateOptions: ['yarnDedupeHighest'],
|
||||||
packageRules: [
|
packageRules: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,7 +51,7 @@ jobs:
|
||||||
|
|
||||||
# Create or update the pull request
|
# Create or update the pull request
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v7.0.5
|
uses: peter-evans/create-pull-request@v7.0.6
|
||||||
with:
|
with:
|
||||||
commit-message: 'New Crowdin translations'
|
commit-message: 'New Crowdin translations'
|
||||||
title: 'New Crowdin Translations for ${{ github.base_ref || github.ref_name }} (automated)'
|
title: 'New Crowdin Translations for ${{ github.base_ref || github.ref_name }} (automated)'
|
||||||
|
|
2
.github/workflows/crowdin-download.yml
vendored
2
.github/workflows/crowdin-download.yml
vendored
|
@ -53,7 +53,7 @@ jobs:
|
||||||
|
|
||||||
# Create or update the pull request
|
# Create or update the pull request
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v7.0.5
|
uses: peter-evans/create-pull-request@v7
|
||||||
with:
|
with:
|
||||||
commit-message: 'New Crowdin translations'
|
commit-message: 'New Crowdin translations'
|
||||||
title: 'New Crowdin Translations (automated)'
|
title: 'New Crowdin Translations (automated)'
|
||||||
|
|
4
.github/workflows/test-ruby.yml
vendored
4
.github/workflows/test-ruby.yml
vendored
|
@ -125,6 +125,7 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
ruby-version:
|
ruby-version:
|
||||||
- '3.2'
|
- '3.2'
|
||||||
|
- '3.3'
|
||||||
- '.ruby-version'
|
- '.ruby-version'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
@ -226,6 +227,7 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
ruby-version:
|
ruby-version:
|
||||||
- '3.2'
|
- '3.2'
|
||||||
|
- '3.3'
|
||||||
- '.ruby-version'
|
- '.ruby-version'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
@ -304,6 +306,7 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
ruby-version:
|
ruby-version:
|
||||||
- '3.2'
|
- '3.2'
|
||||||
|
- '3.3'
|
||||||
- '.ruby-version'
|
- '.ruby-version'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
@ -420,6 +423,7 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
ruby-version:
|
ruby-version:
|
||||||
- '3.2'
|
- '3.2'
|
||||||
|
- '3.3'
|
||||||
- '.ruby-version'
|
- '.ruby-version'
|
||||||
search-image:
|
search-image:
|
||||||
- docker.elastic.co/elasticsearch/elasticsearch:7.17.13
|
- docker.elastic.co/elasticsearch/elasticsearch:7.17.13
|
||||||
|
|
2
.nvmrc
2
.nvmrc
|
@ -1 +1 @@
|
||||||
22.12
|
22.13
|
||||||
|
|
|
@ -29,9 +29,6 @@ Style/IfUnlessModifier:
|
||||||
Style/KeywordArgumentsMerging:
|
Style/KeywordArgumentsMerging:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Style/MultipleComparison:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
Style/NumericLiterals:
|
Style/NumericLiterals:
|
||||||
AllowedPatterns:
|
AllowedPatterns:
|
||||||
- \d{4}_\d{2}_\d{2}_\d{6}
|
- \d{4}_\d{2}_\d{2}_\d{6}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# This configuration was generated by
|
# This configuration was generated by
|
||||||
# `rubocop --auto-gen-config --auto-gen-only-exclude --no-offense-counts --no-auto-gen-timestamp`
|
# `rubocop --auto-gen-config --auto-gen-only-exclude --no-offense-counts --no-auto-gen-timestamp`
|
||||||
# using RuboCop version 1.69.1.
|
# using RuboCop version 1.69.2.
|
||||||
# The point is for the user to remove these configuration records
|
# The point is for the user to remove these configuration records
|
||||||
# one by one as the offenses are removed from the code base.
|
# one by one as the offenses are removed from the code base.
|
||||||
# Note that changes in the inspected code, or installation of new
|
# Note that changes in the inspected code, or installation of new
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
Lint/NonLocalExitFromIterator:
|
Lint/NonLocalExitFromIterator:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/helpers/jsonld_helper.rb'
|
- 'app/helpers/json_ld_helper.rb'
|
||||||
|
|
||||||
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
|
@ -82,7 +82,7 @@ Style/MutableConstant:
|
||||||
# AllowedMethods: respond_to_missing?
|
# AllowedMethods: respond_to_missing?
|
||||||
Style/OptionalBooleanParameter:
|
Style/OptionalBooleanParameter:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/helpers/jsonld_helper.rb'
|
- 'app/helpers/json_ld_helper.rb'
|
||||||
- 'app/lib/admin/system_check/message.rb'
|
- 'app/lib/admin/system_check/message.rb'
|
||||||
- 'app/lib/request.rb'
|
- 'app/lib/request.rb'
|
||||||
- 'app/lib/webfinger.rb'
|
- 'app/lib/webfinger.rb'
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
3.3.6
|
3.4.1
|
||||||
|
|
|
@ -51,7 +51,7 @@ You can contribute in the following ways:
|
||||||
If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon).
|
If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon).
|
||||||
|
|
||||||
Please review the org-level [contribution guidelines] for high-level acceptance
|
Please review the org-level [contribution guidelines] for high-level acceptance
|
||||||
criteria guidance.
|
criteria guidance and the [DEVELOPMENT] guide for environment-specific details.
|
||||||
|
|
||||||
[contribution guidelines]: https://github.com/mastodon/.github/blob/main/CONTRIBUTING.md
|
[contribution guidelines]: https://github.com/mastodon/.github/blob/main/CONTRIBUTING.md
|
||||||
|
|
||||||
|
@ -94,3 +94,5 @@ It is not always possible to phrase every change in such a manner, but it is des
|
||||||
The [Mastodon documentation](https://docs.joinmastodon.org) is a statically generated site. You can [submit merge requests to mastodon/documentation](https://github.com/mastodon/documentation).
|
The [Mastodon documentation](https://docs.joinmastodon.org) is a statically generated site. You can [submit merge requests to mastodon/documentation](https://github.com/mastodon/documentation).
|
||||||
|
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
|
[DEVELOPMENT]: docs/DEVELOPMENT.md
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
ARG TARGETPLATFORM=${TARGETPLATFORM}
|
ARG TARGETPLATFORM=${TARGETPLATFORM}
|
||||||
ARG BUILDPLATFORM=${BUILDPLATFORM}
|
ARG BUILDPLATFORM=${BUILDPLATFORM}
|
||||||
|
|
||||||
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"]
|
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.4.x"]
|
||||||
# renovate: datasource=docker depName=docker.io/ruby
|
# renovate: datasource=docker depName=docker.io/ruby
|
||||||
ARG RUBY_VERSION="3.3.6"
|
ARG RUBY_VERSION="3.4.1"
|
||||||
# # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
|
# # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
|
||||||
# renovate: datasource=node-version depName=node
|
# renovate: datasource=node-version depName=node
|
||||||
ARG NODE_MAJOR_VERSION="22"
|
ARG NODE_MAJOR_VERSION="22"
|
||||||
|
@ -20,7 +20,7 @@ ARG NODE_MAJOR_VERSION="22"
|
||||||
ARG DEBIAN_VERSION="bookworm"
|
ARG DEBIAN_VERSION="bookworm"
|
||||||
# Node image to use for base image based on combined variables (ex: 20-bookworm-slim)
|
# Node image to use for base image based on combined variables (ex: 20-bookworm-slim)
|
||||||
FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim AS node
|
FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim AS node
|
||||||
# Ruby image to use for base image based on combined variables (ex: 3.3.x-slim-bookworm)
|
# Ruby image to use for base image based on combined variables (ex: 3.4.x-slim-bookworm)
|
||||||
FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} AS ruby
|
FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} AS ruby
|
||||||
|
|
||||||
# Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
|
# Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
|
||||||
|
|
4
Gemfile
4
Gemfile
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
ruby '>= 3.2.0', '< 3.5'
|
ruby '>= 3.2.0', '< 3.5.0'
|
||||||
|
|
||||||
gem 'propshaft'
|
gem 'propshaft'
|
||||||
gem 'puma', '~> 6.3'
|
gem 'puma', '~> 6.3'
|
||||||
|
@ -108,7 +108,7 @@ group :opentelemetry do
|
||||||
gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.21.0', require: false
|
gem 'opentelemetry-instrumentation-active_model_serializers', '~> 0.21.0', require: false
|
||||||
gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.21.2', require: false
|
gem 'opentelemetry-instrumentation-concurrent_ruby', '~> 0.21.2', require: false
|
||||||
gem 'opentelemetry-instrumentation-excon', '~> 0.22.0', require: false
|
gem 'opentelemetry-instrumentation-excon', '~> 0.22.0', require: false
|
||||||
gem 'opentelemetry-instrumentation-faraday', '~> 0.24.1', require: false
|
gem 'opentelemetry-instrumentation-faraday', '~> 0.25.0', require: false
|
||||||
gem 'opentelemetry-instrumentation-http', '~> 0.23.2', require: false
|
gem 'opentelemetry-instrumentation-http', '~> 0.23.2', require: false
|
||||||
gem 'opentelemetry-instrumentation-http_client', '~> 0.22.3', require: false
|
gem 'opentelemetry-instrumentation-http_client', '~> 0.22.3', require: false
|
||||||
gem 'opentelemetry-instrumentation-net_http', '~> 0.22.4', require: false
|
gem 'opentelemetry-instrumentation-net_http', '~> 0.22.4', require: false
|
||||||
|
|
32
Gemfile.lock
32
Gemfile.lock
|
@ -94,7 +94,7 @@ GEM
|
||||||
ast (2.4.2)
|
ast (2.4.2)
|
||||||
attr_required (1.0.2)
|
attr_required (1.0.2)
|
||||||
aws-eventstream (1.3.0)
|
aws-eventstream (1.3.0)
|
||||||
aws-partitions (1.1029.0)
|
aws-partitions (1.1032.0)
|
||||||
aws-sdk-core (3.214.1)
|
aws-sdk-core (3.214.1)
|
||||||
aws-eventstream (~> 1, >= 1.3.0)
|
aws-eventstream (~> 1, >= 1.3.0)
|
||||||
aws-partitions (~> 1, >= 1.992.0)
|
aws-partitions (~> 1, >= 1.992.0)
|
||||||
|
@ -103,7 +103,7 @@ GEM
|
||||||
aws-sdk-kms (1.96.0)
|
aws-sdk-kms (1.96.0)
|
||||||
aws-sdk-core (~> 3, >= 3.210.0)
|
aws-sdk-core (~> 3, >= 3.210.0)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sdk-s3 (1.176.1)
|
aws-sdk-s3 (1.177.0)
|
||||||
aws-sdk-core (~> 3, >= 3.210.0)
|
aws-sdk-core (~> 3, >= 3.210.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
|
@ -160,7 +160,7 @@ GEM
|
||||||
cocoon (1.2.15)
|
cocoon (1.2.15)
|
||||||
color_diff (0.1)
|
color_diff (0.1)
|
||||||
concurrent-ruby (1.3.4)
|
concurrent-ruby (1.3.4)
|
||||||
connection_pool (2.4.1)
|
connection_pool (2.5.0)
|
||||||
cose (1.3.1)
|
cose (1.3.1)
|
||||||
cbor (~> 0.5.9)
|
cbor (~> 0.5.9)
|
||||||
openssl-signature_algorithm (~> 1.0)
|
openssl-signature_algorithm (~> 1.0)
|
||||||
|
@ -233,16 +233,16 @@ GEM
|
||||||
faraday-net_http (3.4.0)
|
faraday-net_http (3.4.0)
|
||||||
net-http (>= 0.5.0)
|
net-http (>= 0.5.0)
|
||||||
fast_blank (1.0.1)
|
fast_blank (1.0.1)
|
||||||
fastimage (2.3.1)
|
fastimage (2.4.0)
|
||||||
ffi (1.17.1)
|
ffi (1.17.1)
|
||||||
ffi-compiler (1.3.2)
|
ffi-compiler (1.3.2)
|
||||||
ffi (>= 1.15.5)
|
ffi (>= 1.15.5)
|
||||||
rake
|
rake
|
||||||
flatware (2.3.3)
|
flatware (2.3.4)
|
||||||
drb
|
drb
|
||||||
thor (< 2.0)
|
thor (< 2.0)
|
||||||
flatware-rspec (2.3.3)
|
flatware-rspec (2.3.4)
|
||||||
flatware (= 2.3.3)
|
flatware (= 2.3.4)
|
||||||
rspec (>= 3.6)
|
rspec (>= 3.6)
|
||||||
fog-core (2.5.0)
|
fog-core (2.5.0)
|
||||||
builder
|
builder
|
||||||
|
@ -490,7 +490,7 @@ GEM
|
||||||
opentelemetry-instrumentation-active_job (0.7.8)
|
opentelemetry-instrumentation-active_job (0.7.8)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
opentelemetry-instrumentation-active_model_serializers (0.21.0)
|
opentelemetry-instrumentation-active_model_serializers (0.21.1)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-active_support (>= 0.7.0)
|
opentelemetry-instrumentation-active_support (>= 0.7.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
|
@ -510,7 +510,7 @@ GEM
|
||||||
opentelemetry-instrumentation-excon (0.22.5)
|
opentelemetry-instrumentation-excon (0.22.5)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
opentelemetry-instrumentation-faraday (0.24.8)
|
opentelemetry-instrumentation-faraday (0.25.0)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
opentelemetry-instrumentation-http (0.23.5)
|
opentelemetry-instrumentation-http (0.23.5)
|
||||||
|
@ -522,7 +522,7 @@ GEM
|
||||||
opentelemetry-instrumentation-net_http (0.22.8)
|
opentelemetry-instrumentation-net_http (0.22.8)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
opentelemetry-instrumentation-pg (0.29.1)
|
opentelemetry-instrumentation-pg (0.29.2)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-helpers-sql-obfuscation
|
opentelemetry-helpers-sql-obfuscation
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
|
@ -709,7 +709,7 @@ GEM
|
||||||
rspec-mocks (~> 3.0)
|
rspec-mocks (~> 3.0)
|
||||||
sidekiq (>= 5, < 8)
|
sidekiq (>= 5, < 8)
|
||||||
rspec-support (3.13.2)
|
rspec-support (3.13.2)
|
||||||
rubocop (1.69.2)
|
rubocop (1.70.0)
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
language_server-protocol (>= 3.17.0)
|
language_server-protocol (>= 3.17.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
|
@ -723,7 +723,7 @@ GEM
|
||||||
parser (>= 3.3.1.0)
|
parser (>= 3.3.1.0)
|
||||||
rubocop-capybara (2.21.0)
|
rubocop-capybara (2.21.0)
|
||||||
rubocop (~> 1.41)
|
rubocop (~> 1.41)
|
||||||
rubocop-performance (1.23.0)
|
rubocop-performance (1.23.1)
|
||||||
rubocop (>= 1.48.1, < 2.0)
|
rubocop (>= 1.48.1, < 2.0)
|
||||||
rubocop-ast (>= 1.31.1, < 2.0)
|
rubocop-ast (>= 1.31.1, < 2.0)
|
||||||
rubocop-rails (2.28.0)
|
rubocop-rails (2.28.0)
|
||||||
|
@ -744,7 +744,7 @@ GEM
|
||||||
ruby-vips (2.2.2)
|
ruby-vips (2.2.2)
|
||||||
ffi (~> 1.12)
|
ffi (~> 1.12)
|
||||||
logger
|
logger
|
||||||
rubyzip (2.3.2)
|
rubyzip (2.4.1)
|
||||||
rufus-scheduler (3.9.2)
|
rufus-scheduler (3.9.2)
|
||||||
fugit (~> 1.1, >= 1.11.1)
|
fugit (~> 1.1, >= 1.11.1)
|
||||||
safety_net_attestation (0.4.0)
|
safety_net_attestation (0.4.0)
|
||||||
|
@ -809,7 +809,7 @@ GEM
|
||||||
unicode-display_width (>= 1.1.1, < 3)
|
unicode-display_width (>= 1.1.1, < 3)
|
||||||
terrapin (1.0.1)
|
terrapin (1.0.1)
|
||||||
climate_control
|
climate_control
|
||||||
test-prof (1.4.3)
|
test-prof (1.4.4)
|
||||||
thor (1.3.2)
|
thor (1.3.2)
|
||||||
tilt (2.5.0)
|
tilt (2.5.0)
|
||||||
timeout (0.4.3)
|
timeout (0.4.3)
|
||||||
|
@ -963,7 +963,7 @@ DEPENDENCIES
|
||||||
opentelemetry-instrumentation-active_model_serializers (~> 0.21.0)
|
opentelemetry-instrumentation-active_model_serializers (~> 0.21.0)
|
||||||
opentelemetry-instrumentation-concurrent_ruby (~> 0.21.2)
|
opentelemetry-instrumentation-concurrent_ruby (~> 0.21.2)
|
||||||
opentelemetry-instrumentation-excon (~> 0.22.0)
|
opentelemetry-instrumentation-excon (~> 0.22.0)
|
||||||
opentelemetry-instrumentation-faraday (~> 0.24.1)
|
opentelemetry-instrumentation-faraday (~> 0.25.0)
|
||||||
opentelemetry-instrumentation-http (~> 0.23.2)
|
opentelemetry-instrumentation-http (~> 0.23.2)
|
||||||
opentelemetry-instrumentation-http_client (~> 0.22.3)
|
opentelemetry-instrumentation-http_client (~> 0.22.3)
|
||||||
opentelemetry-instrumentation-net_http (~> 0.22.4)
|
opentelemetry-instrumentation-net_http (~> 0.22.4)
|
||||||
|
@ -1034,7 +1034,7 @@ DEPENDENCIES
|
||||||
xorcist (~> 1.1)
|
xorcist (~> 1.1)
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 3.3.6p108
|
ruby 3.4.1p0
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.6.2
|
2.6.2
|
||||||
|
|
147
README.md
147
README.md
|
@ -14,27 +14,27 @@ Mastodon Glitch Edition is a fork of [Mastodon](https://github.com/mastodon/mast
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<h1><picture>
|
> [!NOTE]
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="./lib/assets/wordmark.dark.png?raw=true">
|
> Want to learn more about Mastodon?
|
||||||
<source media="(prefers-color-scheme: light)" srcset="./lib/assets/wordmark.light.png?raw=true">
|
> Click below to find out more in a video.
|
||||||
<img alt="Mastodon" src="./lib/assets/wordmark.light.png?raw=true" height="34">
|
|
||||||
</picture></h1>
|
|
||||||
|
|
||||||
[![GitHub release](https://img.shields.io/github/release/mastodon/mastodon.svg)][releases]
|
<p align="center">
|
||||||
[![Ruby Testing](https://github.com/mastodon/mastodon/actions/workflows/test-ruby.yml/badge.svg)](https://github.com/mastodon/mastodon/actions/workflows/test-ruby.yml)
|
<a style="text-decoration:none" href="https://www.youtube.com/watch?v=IPSbNdBmWKE">
|
||||||
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg)][crowdin]
|
<img alt="Mastodon hero image" src="https://github.com/user-attachments/assets/ef53f5e9-c0d8-484d-9f53-00efdebb92c3" />
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
[releases]: https://github.com/mastodon/mastodon/releases
|
<p align="center">
|
||||||
[crowdin]: https://crowdin.com/project/mastodon
|
<a style="text-decoration:none" href="https://github.com/mastodon/mastodon/releases">
|
||||||
|
<img src="https://img.shields.io/github/release/mastodon/mastodon.svg" alt="Release" /></a>
|
||||||
|
<a style="text-decoration:none" href="https://github.com/mastodon/mastodon/actions/workflows/test-ruby.yml">
|
||||||
|
<img src="https://github.com/mastodon/mastodon/actions/workflows/test-ruby.yml/badge.svg" alt="Ruby Testing" /></a>
|
||||||
|
<a style="text-decoration:none" href="https://crowdin.com/project/mastodon">
|
||||||
|
<img src="https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg" alt="Crowdin" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
Mastodon is a **free, open-source social network server** based on ActivityPub where users can follow friends and discover new ones. On Mastodon, users can publish anything they want: links, pictures, text, and video. All Mastodon servers are interoperable as a federated network (users on one server can seamlessly communicate with users from another one, including non-Mastodon software that implements ActivityPub!)
|
Mastodon is a **free, open-source social network server** based on ActivityPub where users can follow friends and discover new ones. On Mastodon, users can publish anything they want: links, pictures, text, and video. All Mastodon servers are interoperable as a federated network (users on one server can seamlessly communicate with users from another one, including non-Mastodon software that implements ActivityPub!)
|
||||||
|
|
||||||
Click below to **learn more** in a video:
|
|
||||||
|
|
||||||
[![Screenshot](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/ezgif-2-60f1b00403.gif)][youtube_demo]
|
|
||||||
|
|
||||||
[youtube_demo]: https://www.youtube.com/watch?v=IPSbNdBmWKE
|
|
||||||
|
|
||||||
## Navigation
|
## Navigation
|
||||||
|
|
||||||
- [Project homepage 🐘](https://joinmastodon.org)
|
- [Project homepage 🐘](https://joinmastodon.org)
|
||||||
|
@ -53,25 +53,15 @@ Click below to **learn more** in a video:
|
||||||
|
|
||||||
<img src="/app/javascript/images/elephant_ui_working.svg?raw=true" align="right" width="30%" />
|
<img src="/app/javascript/images/elephant_ui_working.svg?raw=true" align="right" width="30%" />
|
||||||
|
|
||||||
### No vendor lock-in: Fully interoperable with any conforming platform
|
**No vendor lock-in: Fully interoperable with any conforming platform** - It doesn't have to be Mastodon; whatever implements ActivityPub is part of the social network! [Learn more](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/)
|
||||||
|
|
||||||
It doesn't have to be Mastodon; whatever implements ActivityPub is part of the social network! [Learn more](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/)
|
**Real-time, chronological timeline updates** - updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well!
|
||||||
|
|
||||||
### Real-time, chronological timeline updates
|
**Media attachments like images and short videos** - upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos loop continuously!
|
||||||
|
|
||||||
Updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well!
|
**Safety and moderation tools** - Mastodon includes private posts, locked accounts, phrase filtering, muting, blocking, and all sorts of other features, along with a reporting and moderation system. [Learn more](https://blog.joinmastodon.org/2018/07/cage-the-mastodon/)
|
||||||
|
|
||||||
### Media attachments like images and short videos
|
**OAuth2 and a straightforward REST API** - Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Streaming APIs. This results in a rich app ecosystem with a lot of choices!
|
||||||
|
|
||||||
Upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos loop continuously!
|
|
||||||
|
|
||||||
### Safety and moderation tools
|
|
||||||
|
|
||||||
Mastodon includes private posts, locked accounts, phrase filtering, muting, blocking, and all sorts of other features, along with a reporting and moderation system. [Learn more](https://blog.joinmastodon.org/2018/07/cage-the-mastodon/)
|
|
||||||
|
|
||||||
### OAuth2 and a straightforward REST API
|
|
||||||
|
|
||||||
Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Streaming APIs. This results in a rich app ecosystem with a lot of choices!
|
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
|
@ -90,85 +80,40 @@ Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Stre
|
||||||
|
|
||||||
The repository includes deployment configurations for **Docker and docker-compose** as well as specific platforms like **Heroku**, and **Scalingo**. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). The [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the documentation.
|
The repository includes deployment configurations for **Docker and docker-compose** as well as specific platforms like **Heroku**, and **Scalingo**. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). The [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the documentation.
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
### Vagrant
|
|
||||||
|
|
||||||
A **Vagrant** configuration is included for development purposes. To use it, complete the following steps:
|
|
||||||
|
|
||||||
- Install Vagrant and Virtualbox
|
|
||||||
- Install the `vagrant-hostsupdater` plugin: `vagrant plugin install vagrant-hostsupdater`
|
|
||||||
- Run `vagrant up`
|
|
||||||
- Run `vagrant ssh -c "cd /vagrant && bin/dev"`
|
|
||||||
- Open `http://mastodon.local` in your browser
|
|
||||||
|
|
||||||
### macOS
|
|
||||||
|
|
||||||
To set up **macOS** for native development, complete the following steps:
|
|
||||||
|
|
||||||
- Install [Homebrew] and run `brew install postgresql@14 redis imagemagick
|
|
||||||
libidn nvm` to install the required project dependencies
|
|
||||||
- Use a Ruby version manager to activate the ruby in `.ruby-version` and run
|
|
||||||
`nvm use` to activate the node version from `.nvmrc`
|
|
||||||
- Run the `bin/setup` script, which will install the required ruby gems and node
|
|
||||||
packages and prepare the database for local development
|
|
||||||
- Finally, run the `bin/dev` script which will launch services via `overmind`
|
|
||||||
(if installed) or `foreman`
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
|
|
||||||
For production hosting and deployment with **Docker**, use the `Dockerfile` and
|
|
||||||
`docker-compose.yml` in the project root directory.
|
|
||||||
|
|
||||||
For local development, install and launch [Docker], and run:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
docker compose -f .devcontainer/compose.yaml up -d
|
|
||||||
docker compose -f .devcontainer/compose.yaml exec app bin/setup
|
|
||||||
docker compose -f .devcontainer/compose.yaml exec app bin/dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### Dev Containers
|
|
||||||
|
|
||||||
Within IDEs that support the [Development Containers] specification, start the
|
|
||||||
"Mastodon on local machine" container from the editor. The necessary `docker
|
|
||||||
compose` commands to build and setup the container should run automatically. For
|
|
||||||
**Visual Studio Code** this requires installing the [Dev Container extension].
|
|
||||||
|
|
||||||
### GitHub Codespaces
|
|
||||||
|
|
||||||
[GitHub Codespaces] provides a web-based version of VS Code and a cloud hosted
|
|
||||||
development environment configured with the software needed for this project.
|
|
||||||
|
|
||||||
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)][codespace]
|
|
||||||
|
|
||||||
- Click the button to create a new codespace, and confirm the options
|
|
||||||
- Wait for the environment to build (takes a few minutes)
|
|
||||||
- When the editor is ready, run `bin/dev` in the terminal
|
|
||||||
- Wait for an _Open in Browser_ prompt. This will open Mastodon
|
|
||||||
- On the _Ports_ tab "stream" setting change _Port visibility_ → _Public_
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Mastodon is **free, open-source software** licensed under **AGPLv3**.
|
Mastodon is **free, open-source software** licensed under **AGPLv3**.
|
||||||
|
|
||||||
You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository or submit translations using Crowdin. To get started, take a look at [CONTRIBUTING.md](CONTRIBUTING.md). If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon).
|
You can open issues for bugs you've found or features you think are missing. You
|
||||||
|
can also submit pull requests to this repository or translations via Crowdin. To
|
||||||
|
get started, look at the [CONTRIBUTING] and [DEVELOPMENT] guides. For changes
|
||||||
|
accepted into Mastodon, you can request to be paid through our [OpenCollective].
|
||||||
|
|
||||||
**IRC channel**: #mastodon on irc.libera.chat
|
**IRC channel**: #mastodon on [`irc.libera.chat`](https://libera.chat)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (C) 2016-2024 Eugen Rochko & other Mastodon contributors (see [AUTHORS.md](AUTHORS.md))
|
Copyright (c) 2016-2024 Eugen Rochko (+ [`mastodon authors`](AUTHORS.md))
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
Licensed under GNU Affero General Public License as stated in the [LICENSE](LICENSE):
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
```
|
||||||
|
Copyright (c) 2016-2024 Eugen Rochko & other Mastodon contributors
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
This program is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU Affero General Public License as published by the Free
|
||||||
|
Software Foundation, either version 3 of the License, or (at your option) any
|
||||||
|
later version.
|
||||||
|
|
||||||
[codespace]: https://codespaces.new/mastodon/mastodon?quickstart=1&devcontainer_path=.devcontainer%2Fcodespaces%2Fdevcontainer.json
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
[Dev Container extension]: https://containers.dev/supporting#dev-containers
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
[Development Containers]: https://containers.dev/supporting
|
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||||
[Docker]: https://docs.docker.com
|
details.
|
||||||
[GitHub Codespaces]: https://docs.github.com/en/codespaces
|
|
||||||
[Homebrew]: https://brew.sh
|
You should have received a copy of the GNU Affero General Public License along
|
||||||
|
with this program. If not, see https://www.gnu.org/licenses/
|
||||||
|
```
|
||||||
|
|
||||||
|
[CONTRIBUTING]: CONTRIBUTING.md
|
||||||
|
[DEVELOPMENT]: docs/DEVELOPMENT.md
|
||||||
|
[OpenCollective]: https://opencollective.com/mastodon
|
||||||
|
|
|
@ -80,10 +80,31 @@ class Api::V2::NotificationsController < Api::BaseController
|
||||||
return [] if @notifications.empty?
|
return [] if @notifications.empty?
|
||||||
|
|
||||||
MastodonOTELTracer.in_span('Api::V2::NotificationsController#load_grouped_notifications') do
|
MastodonOTELTracer.in_span('Api::V2::NotificationsController#load_grouped_notifications') do
|
||||||
NotificationGroup.from_notifications(@notifications, pagination_range: (@notifications.last.id)..(@notifications.first.id), grouped_types: params[:grouped_types])
|
pagination_range = (@notifications.last.id)..@notifications.first.id
|
||||||
|
|
||||||
|
# If the page is incomplete, we know we are on the last page
|
||||||
|
if incomplete_page?
|
||||||
|
if paginating_up?
|
||||||
|
pagination_range = @notifications.last.id...(params[:max_id]&.to_i)
|
||||||
|
else
|
||||||
|
range_start = params[:since_id]&.to_i
|
||||||
|
range_start += 1 unless range_start.nil?
|
||||||
|
pagination_range = range_start..(@notifications.first.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
NotificationGroup.from_notifications(@notifications, pagination_range: pagination_range, grouped_types: params[:grouped_types])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def incomplete_page?
|
||||||
|
@notifications.size < limit_param(DEFAULT_NOTIFICATIONS_LIMIT)
|
||||||
|
end
|
||||||
|
|
||||||
|
def paginating_up?
|
||||||
|
params[:min_id].present?
|
||||||
|
end
|
||||||
|
|
||||||
def browserable_account_notifications
|
def browserable_account_notifications
|
||||||
current_account.notifications.without_suspended.browserable(
|
current_account.notifications.without_suspended.browserable(
|
||||||
types: Array(browserable_params[:types]),
|
types: Array(browserable_params[:types]),
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CustomCssController < ActionController::Base # rubocop:disable Rails/ApplicationController
|
class CustomCssController < ActionController::Base # rubocop:disable Rails/ApplicationController
|
||||||
before_action :set_user_roles
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
expires_in 3.minutes, public: true
|
expires_in 1.month, public: true
|
||||||
render content_type: 'text/css'
|
render content_type: 'text/css'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -14,8 +12,4 @@ class CustomCssController < ActionController::Base # rubocop:disable Rails/Appli
|
||||||
Setting.custom_css
|
Setting.custom_css
|
||||||
end
|
end
|
||||||
helper_method :custom_css_styles
|
helper_method :custom_css_styles
|
||||||
|
|
||||||
def set_user_roles
|
|
||||||
@user_roles = UserRole.providing_styles
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -239,6 +239,14 @@ module ApplicationHelper
|
||||||
I18n.t 'user_mailer.welcome.hashtags_recent_count', people: number_with_delimiter(people), count: people
|
I18n.t 'user_mailer.welcome.hashtags_recent_count', people: number_with_delimiter(people), count: people
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def app_store_url_ios
|
||||||
|
'https://apps.apple.com/app/mastodon-for-iphone-and-ipad/id1571998974'
|
||||||
|
end
|
||||||
|
|
||||||
|
def app_store_url_android
|
||||||
|
'https://play.google.com/store/apps/details?id=org.joinmastodon.android'
|
||||||
|
end
|
||||||
|
|
||||||
# glitch-soc addition to handle the multiple flavors
|
# glitch-soc addition to handle the multiple flavors
|
||||||
def preload_locale_pack
|
def preload_locale_pack
|
||||||
supported_locales = Themes.instance.flavour(current_flavour)['locales']
|
supported_locales = Themes.instance.flavour(current_flavour)['locales']
|
||||||
|
|
|
@ -27,8 +27,31 @@ module ThemeHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def custom_stylesheet
|
||||||
|
if active_custom_stylesheet.present?
|
||||||
|
stylesheet_link_tag(
|
||||||
|
custom_css_path(active_custom_stylesheet),
|
||||||
|
host: root_url,
|
||||||
|
media: :all,
|
||||||
|
skip_pipeline: true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def active_custom_stylesheet
|
||||||
|
if cached_custom_css_digest.present?
|
||||||
|
[:custom, cached_custom_css_digest.to_s.first(8)]
|
||||||
|
.compact_blank
|
||||||
|
.join('-')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def cached_custom_css_digest
|
||||||
|
Rails.cache.read(:setting_digest_custom_css)
|
||||||
|
end
|
||||||
|
|
||||||
def theme_color_for(theme)
|
def theme_color_for(theme)
|
||||||
theme == 'mastodon-light' ? Themes::THEME_COLORS[:light] : Themes::THEME_COLORS[:dark]
|
theme == 'mastodon-light' ? Themes::THEME_COLORS[:light] : Themes::THEME_COLORS[:dark]
|
||||||
end
|
end
|
||||||
|
|
|
@ -119,7 +119,11 @@ function loaded() {
|
||||||
formattedContent = dateFormat.format(datetime);
|
formattedContent = dateFormat.format(datetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
content.title = formattedContent;
|
const timeGiven = content.dateTime.includes('T');
|
||||||
|
content.title = timeGiven
|
||||||
|
? dateTimeFormat.format(datetime)
|
||||||
|
: dateFormat.format(datetime);
|
||||||
|
|
||||||
content.textContent = formattedContent;
|
content.textContent = formattedContent;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Iterable, fromJS } from 'immutable';
|
import { fromJS, isIndexed } from 'immutable';
|
||||||
|
|
||||||
import { hydrateCompose } from './compose';
|
import { hydrateCompose } from './compose';
|
||||||
import { importFetchedAccounts } from './importer';
|
import { importFetchedAccounts } from './importer';
|
||||||
|
@ -9,8 +9,7 @@ export const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY';
|
||||||
|
|
||||||
const convertState = rawState =>
|
const convertState = rawState =>
|
||||||
fromJS(rawState, (k, v) =>
|
fromJS(rawState, (k, v) =>
|
||||||
Iterable.isIndexed(v) ? v.toList() : v.toMap());
|
isIndexed(v) ? v.toList() : v.toMap());
|
||||||
|
|
||||||
|
|
||||||
export function hydrateStore(rawState) {
|
export function hydrateStore(rawState) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component } from 'react';
|
import { Component } from 'react';
|
||||||
|
|
||||||
import type { IntlShape } from 'react-intl';
|
import type { MessageDescriptor, PrimitiveType, IntlShape } from 'react-intl';
|
||||||
import { injectIntl, defineMessages } from 'react-intl';
|
import { injectIntl, defineMessages } from 'react-intl';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -102,7 +102,13 @@ const getUnitDelay = (units: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const timeAgoString = (
|
export const timeAgoString = (
|
||||||
intl: Pick<IntlShape, 'formatDate' | 'formatMessage'>,
|
intl: {
|
||||||
|
formatDate: IntlShape['formatDate'];
|
||||||
|
formatMessage: (
|
||||||
|
{ id, defaultMessage }: MessageDescriptor,
|
||||||
|
values?: Record<string, PrimitiveType>,
|
||||||
|
) => string;
|
||||||
|
},
|
||||||
date: Date,
|
date: Date,
|
||||||
now: number,
|
now: number,
|
||||||
year: number,
|
year: number,
|
||||||
|
|
|
@ -335,15 +335,29 @@ class Announcement extends ImmutablePureComponent {
|
||||||
const endsAt = announcement.get('ends_at') && new Date(announcement.get('ends_at'));
|
const endsAt = announcement.get('ends_at') && new Date(announcement.get('ends_at'));
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const hasTimeRange = startsAt && endsAt;
|
const hasTimeRange = startsAt && endsAt;
|
||||||
const skipYear = hasTimeRange && startsAt.getFullYear() === endsAt.getFullYear() && endsAt.getFullYear() === now.getFullYear();
|
|
||||||
const skipEndDate = hasTimeRange && startsAt.getDate() === endsAt.getDate() && startsAt.getMonth() === endsAt.getMonth() && startsAt.getFullYear() === endsAt.getFullYear();
|
|
||||||
const skipTime = announcement.get('all_day');
|
const skipTime = announcement.get('all_day');
|
||||||
|
|
||||||
|
let timestamp = null;
|
||||||
|
if (hasTimeRange) {
|
||||||
|
const skipYear = startsAt.getFullYear() === endsAt.getFullYear() && endsAt.getFullYear() === now.getFullYear();
|
||||||
|
const skipEndDate = startsAt.getDate() === endsAt.getDate() && startsAt.getMonth() === endsAt.getMonth() && startsAt.getFullYear() === endsAt.getFullYear();
|
||||||
|
timestamp = (
|
||||||
|
<>
|
||||||
|
<FormattedDate value={startsAt} year={(skipYear || startsAt.getFullYear() === now.getFullYear()) ? undefined : 'numeric'} month='short' day='2-digit' hour={skipTime ? undefined : '2-digit'} minute={skipTime ? undefined : '2-digit'} /> - <FormattedDate value={endsAt} year={(skipYear || endsAt.getFullYear() === now.getFullYear()) ? undefined : 'numeric'} month={skipEndDate ? undefined : 'short'} day={skipEndDate ? undefined : '2-digit'} hour={skipTime ? undefined : '2-digit'} minute={skipTime ? undefined : '2-digit'} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const publishedAt = new Date(announcement.get('published_at'));
|
||||||
|
timestamp = (
|
||||||
|
<FormattedDate value={publishedAt} year={publishedAt.getFullYear() === now.getFullYear() ? undefined : 'numeric'} month='short' day='2-digit' hour={skipTime ? undefined : '2-digit'} minute={skipTime ? undefined : '2-digit'} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='announcements__item'>
|
<div className='announcements__item'>
|
||||||
<strong className='announcements__item__range'>
|
<strong className='announcements__item__range'>
|
||||||
<FormattedMessage id='announcement.announcement' defaultMessage='Announcement' />
|
<FormattedMessage id='announcement.announcement' defaultMessage='Announcement' />
|
||||||
{hasTimeRange && <span> · <FormattedDate value={startsAt} year={(skipYear || startsAt.getFullYear() === now.getFullYear()) ? undefined : 'numeric'} month='short' day='2-digit' hour={skipTime ? undefined : '2-digit'} minute={skipTime ? undefined : '2-digit'} /> - <FormattedDate value={endsAt} year={(skipYear || endsAt.getFullYear() === now.getFullYear()) ? undefined : 'numeric'} month={skipEndDate ? undefined : 'short'} day={skipEndDate ? undefined : '2-digit'} hour={skipTime ? undefined : '2-digit'} minute={skipTime ? undefined : '2-digit'} /></span>}
|
<span> · {timestamp}</span>
|
||||||
</strong>
|
</strong>
|
||||||
|
|
||||||
<Content announcement={announcement} />
|
<Content announcement={announcement} />
|
||||||
|
|
|
@ -457,6 +457,7 @@
|
||||||
"keyboard_shortcuts.toggle_hidden": "Dangos/cuddio testun tu ôl i CW",
|
"keyboard_shortcuts.toggle_hidden": "Dangos/cuddio testun tu ôl i CW",
|
||||||
"keyboard_shortcuts.toggle_sensitivity": "Dangos/cuddio cyfryngau",
|
"keyboard_shortcuts.toggle_sensitivity": "Dangos/cuddio cyfryngau",
|
||||||
"keyboard_shortcuts.toot": "Dechrau post newydd",
|
"keyboard_shortcuts.toot": "Dechrau post newydd",
|
||||||
|
"keyboard_shortcuts.translate": "i gyfieithu postiad",
|
||||||
"keyboard_shortcuts.unfocus": "Dad-ffocysu ardal cyfansoddi testun/chwilio",
|
"keyboard_shortcuts.unfocus": "Dad-ffocysu ardal cyfansoddi testun/chwilio",
|
||||||
"keyboard_shortcuts.up": "Symud yn uwch yn y rhestr",
|
"keyboard_shortcuts.up": "Symud yn uwch yn y rhestr",
|
||||||
"lightbox.close": "Cau",
|
"lightbox.close": "Cau",
|
||||||
|
@ -835,6 +836,7 @@
|
||||||
"status.reblogs.empty": "Does neb wedi hybio'r post yma eto. Pan y bydd rhywun yn gwneud, byddent yn ymddangos yma.",
|
"status.reblogs.empty": "Does neb wedi hybio'r post yma eto. Pan y bydd rhywun yn gwneud, byddent yn ymddangos yma.",
|
||||||
"status.redraft": "Dileu ac ailddrafftio",
|
"status.redraft": "Dileu ac ailddrafftio",
|
||||||
"status.remove_bookmark": "Tynnu nod tudalen",
|
"status.remove_bookmark": "Tynnu nod tudalen",
|
||||||
|
"status.remove_favourite": "Tynnu o'r ffefrynnau",
|
||||||
"status.replied_in_thread": "Atebodd mewn edefyn",
|
"status.replied_in_thread": "Atebodd mewn edefyn",
|
||||||
"status.replied_to": "Wedi ateb {name}",
|
"status.replied_to": "Wedi ateb {name}",
|
||||||
"status.reply": "Ateb",
|
"status.reply": "Ateb",
|
||||||
|
|
|
@ -482,6 +482,7 @@
|
||||||
"lists.exclusive": "Skjul medlemmer i Hjem",
|
"lists.exclusive": "Skjul medlemmer i Hjem",
|
||||||
"lists.exclusive_hint": "Er nogen er på denne liste, skjul personen i hjemme-feeds for at undgå at se vedkommendes indlæg to gange.",
|
"lists.exclusive_hint": "Er nogen er på denne liste, skjul personen i hjemme-feeds for at undgå at se vedkommendes indlæg to gange.",
|
||||||
"lists.find_users_to_add": "Find brugere at tilføje",
|
"lists.find_users_to_add": "Find brugere at tilføje",
|
||||||
|
"lists.list_members": "Liste over medlemmer",
|
||||||
"lists.list_members_count": "{count, plural, one {# medlem} other {# medlemmer}}",
|
"lists.list_members_count": "{count, plural, one {# medlem} other {# medlemmer}}",
|
||||||
"lists.list_name": "Listetitel",
|
"lists.list_name": "Listetitel",
|
||||||
"lists.new_list_name": "Ny listetitel",
|
"lists.new_list_name": "Ny listetitel",
|
||||||
|
|
|
@ -362,6 +362,7 @@
|
||||||
"footer.privacy_policy": "Privatlívspolitikkur",
|
"footer.privacy_policy": "Privatlívspolitikkur",
|
||||||
"footer.source_code": "Vís keldukotuna",
|
"footer.source_code": "Vís keldukotuna",
|
||||||
"footer.status": "Støða",
|
"footer.status": "Støða",
|
||||||
|
"footer.terms_of_service": "Tænastutreytir",
|
||||||
"generic.saved": "Goymt",
|
"generic.saved": "Goymt",
|
||||||
"getting_started.heading": "At byrja",
|
"getting_started.heading": "At byrja",
|
||||||
"hashtag.admin_moderation": "Lat umsjónarmarkamót upp fyri #{name}",
|
"hashtag.admin_moderation": "Lat umsjónarmarkamót upp fyri #{name}",
|
||||||
|
@ -858,6 +859,7 @@
|
||||||
"subscribed_languages.target": "Broyt haldaramál fyri {target}",
|
"subscribed_languages.target": "Broyt haldaramál fyri {target}",
|
||||||
"tabs_bar.home": "Heim",
|
"tabs_bar.home": "Heim",
|
||||||
"tabs_bar.notifications": "Fráboðanir",
|
"tabs_bar.notifications": "Fráboðanir",
|
||||||
|
"terms_of_service.title": "Tænastutreytir",
|
||||||
"time_remaining.days": "{number, plural, one {# dagur} other {# dagar}} eftir",
|
"time_remaining.days": "{number, plural, one {# dagur} other {# dagar}} eftir",
|
||||||
"time_remaining.hours": "{number, plural, one {# tími} other {# tímar}} eftir",
|
"time_remaining.hours": "{number, plural, one {# tími} other {# tímar}} eftir",
|
||||||
"time_remaining.minutes": "{number, plural, one {# minuttur} other {# minuttir}} eftir",
|
"time_remaining.minutes": "{number, plural, one {# minuttur} other {# minuttir}} eftir",
|
||||||
|
|
|
@ -453,10 +453,11 @@
|
||||||
"keyboard_shortcuts.requests": "Követési kérések listájának megnyitása",
|
"keyboard_shortcuts.requests": "Követési kérések listájának megnyitása",
|
||||||
"keyboard_shortcuts.search": "Fókuszálás a keresősávra",
|
"keyboard_shortcuts.search": "Fókuszálás a keresősávra",
|
||||||
"keyboard_shortcuts.spoilers": "Tartalmi figyelmeztetés mező megjelenítése/elrejtése",
|
"keyboard_shortcuts.spoilers": "Tartalmi figyelmeztetés mező megjelenítése/elrejtése",
|
||||||
"keyboard_shortcuts.start": "\"Első lépések\" oszlop megnyitása",
|
"keyboard_shortcuts.start": "„Első lépések” oszlop megnyitása",
|
||||||
"keyboard_shortcuts.toggle_hidden": "Tartalmi figyelmeztetéssel ellátott szöveg megjelenítése/elrejtése",
|
"keyboard_shortcuts.toggle_hidden": "Tartalmi figyelmeztetéssel ellátott szöveg megjelenítése/elrejtése",
|
||||||
"keyboard_shortcuts.toggle_sensitivity": "Média megjelenítése/elrejtése",
|
"keyboard_shortcuts.toggle_sensitivity": "Média megjelenítése/elrejtése",
|
||||||
"keyboard_shortcuts.toot": "Új bejegyzés írása",
|
"keyboard_shortcuts.toot": "Új bejegyzés írása",
|
||||||
|
"keyboard_shortcuts.translate": "Bejegyzés lefordítása",
|
||||||
"keyboard_shortcuts.unfocus": "Szerkesztés/keresés fókuszból való kivétele",
|
"keyboard_shortcuts.unfocus": "Szerkesztés/keresés fókuszból való kivétele",
|
||||||
"keyboard_shortcuts.up": "Mozgás felfelé a listában",
|
"keyboard_shortcuts.up": "Mozgás felfelé a listában",
|
||||||
"lightbox.close": "Bezárás",
|
"lightbox.close": "Bezárás",
|
||||||
|
|
|
@ -457,6 +457,7 @@
|
||||||
"keyboard_shortcuts.toggle_hidden": "Monstrar/celar texto detra advertimento de contento",
|
"keyboard_shortcuts.toggle_hidden": "Monstrar/celar texto detra advertimento de contento",
|
||||||
"keyboard_shortcuts.toggle_sensitivity": "Monstrar/celar multimedia",
|
"keyboard_shortcuts.toggle_sensitivity": "Monstrar/celar multimedia",
|
||||||
"keyboard_shortcuts.toot": "Initiar un nove message",
|
"keyboard_shortcuts.toot": "Initiar un nove message",
|
||||||
|
"keyboard_shortcuts.translate": "a traducer un message",
|
||||||
"keyboard_shortcuts.unfocus": "Disfocalisar le area de composition de texto/de recerca",
|
"keyboard_shortcuts.unfocus": "Disfocalisar le area de composition de texto/de recerca",
|
||||||
"keyboard_shortcuts.up": "Displaciar in alto in le lista",
|
"keyboard_shortcuts.up": "Displaciar in alto in le lista",
|
||||||
"lightbox.close": "Clauder",
|
"lightbox.close": "Clauder",
|
||||||
|
@ -836,6 +837,7 @@
|
||||||
"status.reblogs.empty": "Necuno ha ancora impulsate iste message. Quando alcuno lo face, le impulsos apparera hic.",
|
"status.reblogs.empty": "Necuno ha ancora impulsate iste message. Quando alcuno lo face, le impulsos apparera hic.",
|
||||||
"status.redraft": "Deler e reconciper",
|
"status.redraft": "Deler e reconciper",
|
||||||
"status.remove_bookmark": "Remover marcapagina",
|
"status.remove_bookmark": "Remover marcapagina",
|
||||||
|
"status.remove_favourite": "Remover del favoritos",
|
||||||
"status.replied_in_thread": "Respondite in le discussion",
|
"status.replied_in_thread": "Respondite in le discussion",
|
||||||
"status.replied_to": "Respondite a {name}",
|
"status.replied_to": "Respondite a {name}",
|
||||||
"status.reply": "Responder",
|
"status.reply": "Responder",
|
||||||
|
|
|
@ -414,6 +414,7 @@
|
||||||
"interaction_modal.title.reblog": "{name} 님의 게시물을 부스트",
|
"interaction_modal.title.reblog": "{name} 님의 게시물을 부스트",
|
||||||
"interaction_modal.title.reply": "{name} 님의 게시물에 답글",
|
"interaction_modal.title.reply": "{name} 님의 게시물에 답글",
|
||||||
"interaction_modal.title.vote": "{name} 님의 투표에 참여",
|
"interaction_modal.title.vote": "{name} 님의 투표에 참여",
|
||||||
|
"interaction_modal.username_prompt": "예시: {example}",
|
||||||
"intervals.full.days": "{number} 일",
|
"intervals.full.days": "{number} 일",
|
||||||
"intervals.full.hours": "{number} 시간",
|
"intervals.full.hours": "{number} 시간",
|
||||||
"intervals.full.minutes": "{number} 분",
|
"intervals.full.minutes": "{number} 분",
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
"account.mute_notifications_short": "Izslēgt paziņojumu skaņu",
|
"account.mute_notifications_short": "Izslēgt paziņojumu skaņu",
|
||||||
"account.mute_short": "Apklusināt",
|
"account.mute_short": "Apklusināt",
|
||||||
"account.muted": "Apklusināts",
|
"account.muted": "Apklusināts",
|
||||||
"account.mutual": "Savstarpējs",
|
"account.mutual": "Abpusēji",
|
||||||
"account.no_bio": "Apraksts nav sniegts.",
|
"account.no_bio": "Apraksts nav sniegts.",
|
||||||
"account.open_original_page": "Atvērt oriģinālo lapu",
|
"account.open_original_page": "Atvērt oriģinālo lapu",
|
||||||
"account.posts": "Ieraksti",
|
"account.posts": "Ieraksti",
|
||||||
|
@ -85,6 +85,7 @@
|
||||||
"alert.rate_limited.title": "Biežums ierobežots",
|
"alert.rate_limited.title": "Biežums ierobežots",
|
||||||
"alert.unexpected.message": "Radās negaidīta kļūda.",
|
"alert.unexpected.message": "Radās negaidīta kļūda.",
|
||||||
"alert.unexpected.title": "Ups!",
|
"alert.unexpected.title": "Ups!",
|
||||||
|
"alt_text_badge.title": "Alt teksts",
|
||||||
"announcement.announcement": "Paziņojums",
|
"announcement.announcement": "Paziņojums",
|
||||||
"annual_report.summary.archetype.oracle": "Orākuls",
|
"annual_report.summary.archetype.oracle": "Orākuls",
|
||||||
"annual_report.summary.archetype.replier": "Sabiedriskais tauriņš",
|
"annual_report.summary.archetype.replier": "Sabiedriskais tauriņš",
|
||||||
|
|
|
@ -837,6 +837,7 @@
|
||||||
"status.reblogs.empty": "Ingen har framheva dette tutet enno. Om nokon gjer, så dukkar det opp her.",
|
"status.reblogs.empty": "Ingen har framheva dette tutet enno. Om nokon gjer, så dukkar det opp her.",
|
||||||
"status.redraft": "Slett & skriv på nytt",
|
"status.redraft": "Slett & skriv på nytt",
|
||||||
"status.remove_bookmark": "Fjern bokmerke",
|
"status.remove_bookmark": "Fjern bokmerke",
|
||||||
|
"status.remove_favourite": "Fjern frå favorittar",
|
||||||
"status.replied_in_thread": "Svara i tråden",
|
"status.replied_in_thread": "Svara i tråden",
|
||||||
"status.replied_to": "Svarte {name}",
|
"status.replied_to": "Svarte {name}",
|
||||||
"status.reply": "Svar",
|
"status.reply": "Svar",
|
||||||
|
|
|
@ -406,6 +406,9 @@
|
||||||
"ignore_notifications_modal.not_followers_title": "Ignoruj powiadomienia od użytkowników którzy cię nie obserwują?",
|
"ignore_notifications_modal.not_followers_title": "Ignoruj powiadomienia od użytkowników którzy cię nie obserwują?",
|
||||||
"ignore_notifications_modal.not_following_title": "Ignoruj powiadomienia od użytkowników których nie obserwujesz?",
|
"ignore_notifications_modal.not_following_title": "Ignoruj powiadomienia od użytkowników których nie obserwujesz?",
|
||||||
"ignore_notifications_modal.private_mentions_title": "Ignoruj powiadomienia o nieproszonych wzmiankach prywatnych?",
|
"ignore_notifications_modal.private_mentions_title": "Ignoruj powiadomienia o nieproszonych wzmiankach prywatnych?",
|
||||||
|
"interaction_modal.action.favourite": "Aby kontynuować, musisz dodać do ulubionych na swoim koncie.",
|
||||||
|
"interaction_modal.action.follow": "Aby kontynuować, musisz obserwować ze swojego konta.",
|
||||||
|
"interaction_modal.no_account_yet": "Nie masz jeszcze konta?",
|
||||||
"interaction_modal.on_another_server": "Na innym serwerze",
|
"interaction_modal.on_another_server": "Na innym serwerze",
|
||||||
"interaction_modal.on_this_server": "Na tym serwerze",
|
"interaction_modal.on_this_server": "Na tym serwerze",
|
||||||
"interaction_modal.title.favourite": "Polub wpis użytkownika {name}",
|
"interaction_modal.title.favourite": "Polub wpis użytkownika {name}",
|
||||||
|
|
|
@ -243,12 +243,12 @@
|
||||||
"dismissable_banner.explore_statuses": "Estas publicações através do fediverse estão ganhando atenção hoje. Publicações mais recentes com mais boosts e favoritos são classificados mais altamente.",
|
"dismissable_banner.explore_statuses": "Estas publicações através do fediverse estão ganhando atenção hoje. Publicações mais recentes com mais boosts e favoritos são classificados mais altamente.",
|
||||||
"dismissable_banner.explore_tags": "Estas hashtags estão ganhando atenção hoje no fediverse. Hashtags usadas por muitas pessoas diferentes são classificadas mais altamente.",
|
"dismissable_banner.explore_tags": "Estas hashtags estão ganhando atenção hoje no fediverse. Hashtags usadas por muitas pessoas diferentes são classificadas mais altamente.",
|
||||||
"dismissable_banner.public_timeline": "Estas são as publicações mais recentes das pessoas no fediverse que as pessoas do {domain} seguem.",
|
"dismissable_banner.public_timeline": "Estas são as publicações mais recentes das pessoas no fediverse que as pessoas do {domain} seguem.",
|
||||||
"domain_block_modal.block": "Servidor de blocos.",
|
"domain_block_modal.block": "Bloquear servidor",
|
||||||
"domain_block_modal.block_account_instead": "Bloco @(nome)",
|
"domain_block_modal.block_account_instead": "Bloquear @{name}",
|
||||||
"domain_block_modal.they_can_interact_with_old_posts": "Pessoas deste servidor podem interagir com suas publicações antigas.",
|
"domain_block_modal.they_can_interact_with_old_posts": "Pessoas deste servidor podem interagir com suas publicações antigas.",
|
||||||
"domain_block_modal.they_cant_follow": "Ninguém deste servidor pode lhe seguir.",
|
"domain_block_modal.they_cant_follow": "Ninguém deste servidor pode lhe seguir.",
|
||||||
"domain_block_modal.they_wont_know": "Eles não saberão que foram bloqueados.",
|
"domain_block_modal.they_wont_know": "Eles não saberão que foram bloqueados.",
|
||||||
"domain_block_modal.title": "Dominio do bloco",
|
"domain_block_modal.title": "Bloquear domínio?",
|
||||||
"domain_block_modal.you_will_lose_num_followers": "Você perderá {followersCount, plural, one {{followersCountDisplay} seguidor} other {{followersCountDisplay} seguidores}} e {followingCount, plural, one {{followingCountDisplay} pessoa que você segue} other {{followingCountDisplay} pessoas que você segue}}.",
|
"domain_block_modal.you_will_lose_num_followers": "Você perderá {followersCount, plural, one {{followersCountDisplay} seguidor} other {{followersCountDisplay} seguidores}} e {followingCount, plural, one {{followingCountDisplay} pessoa que você segue} other {{followingCountDisplay} pessoas que você segue}}.",
|
||||||
"domain_block_modal.you_will_lose_relationships": "Você irá perder todos os seguidores e pessoas que você segue neste servidor.",
|
"domain_block_modal.you_will_lose_relationships": "Você irá perder todos os seguidores e pessoas que você segue neste servidor.",
|
||||||
"domain_block_modal.you_wont_see_posts": "Você não verá postagens ou notificações de usuários neste servidor.",
|
"domain_block_modal.you_wont_see_posts": "Você não verá postagens ou notificações de usuários neste servidor.",
|
||||||
|
|
|
@ -85,7 +85,7 @@
|
||||||
"alert.rate_limited.title": "Limite de tentativas",
|
"alert.rate_limited.title": "Limite de tentativas",
|
||||||
"alert.unexpected.message": "Ocorreu um erro inesperado.",
|
"alert.unexpected.message": "Ocorreu um erro inesperado.",
|
||||||
"alert.unexpected.title": "Bolas!",
|
"alert.unexpected.title": "Bolas!",
|
||||||
"alt_text_badge.title": "Texto alternativo",
|
"alt_text_badge.title": "Texto descritivo",
|
||||||
"announcement.announcement": "Mensagem de manutenção",
|
"announcement.announcement": "Mensagem de manutenção",
|
||||||
"annual_report.summary.archetype.booster": "O caçador de frescura",
|
"annual_report.summary.archetype.booster": "O caçador de frescura",
|
||||||
"annual_report.summary.archetype.lurker": "O espreitador",
|
"annual_report.summary.archetype.lurker": "O espreitador",
|
||||||
|
@ -244,7 +244,7 @@
|
||||||
"dismissable_banner.explore_tags": "Estas etiquetas estão a ganhar força no fediverso atualmente. As etiquetas que são utilizadas por mais pessoas diferentes são classificadas numa posição mais elevada.",
|
"dismissable_banner.explore_tags": "Estas etiquetas estão a ganhar força no fediverso atualmente. As etiquetas que são utilizadas por mais pessoas diferentes são classificadas numa posição mais elevada.",
|
||||||
"dismissable_banner.public_timeline": "Estas são as publicações públicas mais recentes de pessoas no fediverso que as pessoas em {domain} seguem.",
|
"dismissable_banner.public_timeline": "Estas são as publicações públicas mais recentes de pessoas no fediverso que as pessoas em {domain} seguem.",
|
||||||
"domain_block_modal.block": "Bloquear servidor",
|
"domain_block_modal.block": "Bloquear servidor",
|
||||||
"domain_block_modal.block_account_instead": "Bloquear antes @{name}",
|
"domain_block_modal.block_account_instead": "Em vez disso, bloquear @{name}",
|
||||||
"domain_block_modal.they_can_interact_with_old_posts": "As pessoas deste servidor podem interagir com as tuas publicações antigas.",
|
"domain_block_modal.they_can_interact_with_old_posts": "As pessoas deste servidor podem interagir com as tuas publicações antigas.",
|
||||||
"domain_block_modal.they_cant_follow": "Ninguém deste servidor pode seguir-te.",
|
"domain_block_modal.they_cant_follow": "Ninguém deste servidor pode seguir-te.",
|
||||||
"domain_block_modal.they_wont_know": "Eles não saberão que foram bloqueados.",
|
"domain_block_modal.they_wont_know": "Eles não saberão que foram bloqueados.",
|
||||||
|
@ -260,7 +260,7 @@
|
||||||
"domain_pill.their_username": "O identificador único dele no seu servidor. É possível encontrar utilizadores com o mesmo nome de utilizador em servidores diferentes.",
|
"domain_pill.their_username": "O identificador único dele no seu servidor. É possível encontrar utilizadores com o mesmo nome de utilizador em servidores diferentes.",
|
||||||
"domain_pill.username": "Nome de utilizador",
|
"domain_pill.username": "Nome de utilizador",
|
||||||
"domain_pill.whats_in_a_handle": "Em que consiste um identificador?",
|
"domain_pill.whats_in_a_handle": "Em que consiste um identificador?",
|
||||||
"domain_pill.who_they_are": "Uma vez que os identificadores dizem quem é alguém e onde está, pode interagir com as pessoas através da rede social de <button>plataformas que suportam ActivityPub</button>.",
|
"domain_pill.who_they_are": "Uma vez que os identificadores dizem quem é alguém e onde está, podes interagir com as pessoas através da rede social de <button>plataformas que suportam ActivityPub</button>.",
|
||||||
"domain_pill.who_you_are": "Uma vez que o teu identificador indica quem és e onde estás, as pessoas podem interagir contigo através da rede social de <button>plataformas que suportam ActivityPub</button>.",
|
"domain_pill.who_you_are": "Uma vez que o teu identificador indica quem és e onde estás, as pessoas podem interagir contigo através da rede social de <button>plataformas que suportam ActivityPub</button>.",
|
||||||
"domain_pill.your_handle": "O teu identificador:",
|
"domain_pill.your_handle": "O teu identificador:",
|
||||||
"domain_pill.your_server": "A tua casa digital, onde se encontram todas as tuas publicações. Não gostas deste? Muda de servidor a qualquer momento e leva também os teus seguidores.",
|
"domain_pill.your_server": "A tua casa digital, onde se encontram todas as tuas publicações. Não gostas deste? Muda de servidor a qualquer momento e leva também os teus seguidores.",
|
||||||
|
@ -457,6 +457,7 @@
|
||||||
"keyboard_shortcuts.toggle_hidden": "mostrar / esconder texto atrás do aviso de conteúdo",
|
"keyboard_shortcuts.toggle_hidden": "mostrar / esconder texto atrás do aviso de conteúdo",
|
||||||
"keyboard_shortcuts.toggle_sensitivity": "mostrar / ocultar multimédia",
|
"keyboard_shortcuts.toggle_sensitivity": "mostrar / ocultar multimédia",
|
||||||
"keyboard_shortcuts.toot": "criar uma nova publicação",
|
"keyboard_shortcuts.toot": "criar uma nova publicação",
|
||||||
|
"keyboard_shortcuts.translate": "traduzir uma publicação",
|
||||||
"keyboard_shortcuts.unfocus": "remover o foco da área de texto / pesquisa",
|
"keyboard_shortcuts.unfocus": "remover o foco da área de texto / pesquisa",
|
||||||
"keyboard_shortcuts.up": "mover para cima na lista",
|
"keyboard_shortcuts.up": "mover para cima na lista",
|
||||||
"lightbox.close": "Fechar",
|
"lightbox.close": "Fechar",
|
||||||
|
@ -641,10 +642,10 @@
|
||||||
"notifications.policy.filter_hint": "Enviar para a caixa de notificações filtradas",
|
"notifications.policy.filter_hint": "Enviar para a caixa de notificações filtradas",
|
||||||
"notifications.policy.filter_limited_accounts_hint": "Limitado pelos moderadores do servidor",
|
"notifications.policy.filter_limited_accounts_hint": "Limitado pelos moderadores do servidor",
|
||||||
"notifications.policy.filter_limited_accounts_title": "Contas moderadas",
|
"notifications.policy.filter_limited_accounts_title": "Contas moderadas",
|
||||||
"notifications.policy.filter_new_accounts.hint": "Criada {days, plural, one {no último dia} other {nos últimos # dias}}",
|
"notifications.policy.filter_new_accounts.hint": "Criadas {days, plural, one {no último dia} other {nos últimos # dias}}",
|
||||||
"notifications.policy.filter_new_accounts_title": "Novas contas",
|
"notifications.policy.filter_new_accounts_title": "Novas contas",
|
||||||
"notifications.policy.filter_not_followers_hint": "Incluindo pessoas que te seguem há menos de {days, plural, one {um dia} other {# dias}}",
|
"notifications.policy.filter_not_followers_hint": "Incluindo pessoas que te seguem há menos de {days, plural, one {um dia} other {# dias}}",
|
||||||
"notifications.policy.filter_not_followers_title": "Pessoas não te seguem",
|
"notifications.policy.filter_not_followers_title": "Pessoas que não te seguem",
|
||||||
"notifications.policy.filter_not_following_hint": "Até que os aproves manualmente",
|
"notifications.policy.filter_not_following_hint": "Até que os aproves manualmente",
|
||||||
"notifications.policy.filter_not_following_title": "Pessoas que não segues",
|
"notifications.policy.filter_not_following_title": "Pessoas que não segues",
|
||||||
"notifications.policy.filter_private_mentions_hint": "Filtrado, a não ser que seja em resposta à tua própria menção ou se seguires o remetente",
|
"notifications.policy.filter_private_mentions_hint": "Filtrado, a não ser que seja em resposta à tua própria menção ou se seguires o remetente",
|
||||||
|
@ -836,6 +837,7 @@
|
||||||
"status.reblogs.empty": "Ainda ninguém impulsionou esta publicação. Quando alguém o fizer, aparecerá aqui.",
|
"status.reblogs.empty": "Ainda ninguém impulsionou esta publicação. Quando alguém o fizer, aparecerá aqui.",
|
||||||
"status.redraft": "Eliminar e reescrever",
|
"status.redraft": "Eliminar e reescrever",
|
||||||
"status.remove_bookmark": "Retirar dos marcadores",
|
"status.remove_bookmark": "Retirar dos marcadores",
|
||||||
|
"status.remove_favourite": "Remover dos favoritos",
|
||||||
"status.replied_in_thread": "Responder na conversa",
|
"status.replied_in_thread": "Responder na conversa",
|
||||||
"status.replied_to": "Respondeu a {name}",
|
"status.replied_to": "Respondeu a {name}",
|
||||||
"status.reply": "Responder",
|
"status.reply": "Responder",
|
||||||
|
|
|
@ -141,7 +141,7 @@
|
||||||
"column.bookmarks": "Bokmärken",
|
"column.bookmarks": "Bokmärken",
|
||||||
"column.community": "Lokal tidslinje",
|
"column.community": "Lokal tidslinje",
|
||||||
"column.create_list": "Skapa lista",
|
"column.create_list": "Skapa lista",
|
||||||
"column.direct": "Privata nämningar",
|
"column.direct": "Privata omnämnande",
|
||||||
"column.directory": "Bläddra bland profiler",
|
"column.directory": "Bläddra bland profiler",
|
||||||
"column.domain_blocks": "Blockerade domäner",
|
"column.domain_blocks": "Blockerade domäner",
|
||||||
"column.edit_list": "Redigera lista",
|
"column.edit_list": "Redigera lista",
|
||||||
|
@ -239,6 +239,10 @@
|
||||||
"disabled_account_banner.text": "Ditt konto {disabledAccount} är för närvarande inaktiverat.",
|
"disabled_account_banner.text": "Ditt konto {disabledAccount} är för närvarande inaktiverat.",
|
||||||
"dismissable_banner.community_timeline": "Dessa är de senaste offentliga inläggen från personer vars konton tillhandahålls av {domain}.",
|
"dismissable_banner.community_timeline": "Dessa är de senaste offentliga inläggen från personer vars konton tillhandahålls av {domain}.",
|
||||||
"dismissable_banner.dismiss": "Avfärda",
|
"dismissable_banner.dismiss": "Avfärda",
|
||||||
|
"dismissable_banner.explore_links": "Dessa nyhetshistorier delas mest på fediversum idag. Nyare nyhetshistorier som publiceras av fler olika personer rankas högre.",
|
||||||
|
"dismissable_banner.explore_statuses": "Dessa inlägg från fediversum vinner dragkraft idag. Nyare inlägg som många boostar och favoritmarkerar rankas högre.",
|
||||||
|
"dismissable_banner.explore_tags": "De här hashtaggarna vinner dragkraft i fediversum idag. Hashtaggar som används av fler olika personer rankas högre.",
|
||||||
|
"dismissable_banner.public_timeline": "De här är de aktuella publika inlägg från personer i fediversum som personer i {domain} följer.",
|
||||||
"domain_block_modal.block": "Blockera server",
|
"domain_block_modal.block": "Blockera server",
|
||||||
"domain_block_modal.block_account_instead": "Blockera @{name} istället",
|
"domain_block_modal.block_account_instead": "Blockera @{name} istället",
|
||||||
"domain_block_modal.they_can_interact_with_old_posts": "Personer från denna server kan interagera med dina gamla inlägg.",
|
"domain_block_modal.they_can_interact_with_old_posts": "Personer från denna server kan interagera med dina gamla inlägg.",
|
||||||
|
@ -285,7 +289,7 @@
|
||||||
"empty_column.blocks": "Du har ännu ej blockerat några användare.",
|
"empty_column.blocks": "Du har ännu ej blockerat några användare.",
|
||||||
"empty_column.bookmarked_statuses": "Du har inte bokmärkt några inlägg än. När du bokmärker ett inlägg kommer det synas här.",
|
"empty_column.bookmarked_statuses": "Du har inte bokmärkt några inlägg än. När du bokmärker ett inlägg kommer det synas här.",
|
||||||
"empty_column.community": "Den lokala tidslinjen är tom. Skriv något offentligt för att sätta bollen i rullning!",
|
"empty_column.community": "Den lokala tidslinjen är tom. Skriv något offentligt för att sätta bollen i rullning!",
|
||||||
"empty_column.direct": "Du har inga privata nämningar. När du skickar eller tar emot ett direktmeddelande kommer det att visas här.",
|
"empty_column.direct": "Du har inga privata omnämninande. När du skickar eller tar emot ett direktmeddelande kommer det att visas här.",
|
||||||
"empty_column.domain_blocks": "Det finns ännu inga dolda domäner.",
|
"empty_column.domain_blocks": "Det finns ännu inga dolda domäner.",
|
||||||
"empty_column.explore_statuses": "Ingenting är trendigt just nu. Kom tillbaka senare!",
|
"empty_column.explore_statuses": "Ingenting är trendigt just nu. Kom tillbaka senare!",
|
||||||
"empty_column.favourited_statuses": "Du har inga favoritmarkerade inlägg ännu. När du favoritmärker ett så kommer det att dyka upp här.",
|
"empty_column.favourited_statuses": "Du har inga favoritmarkerade inlägg ännu. När du favoritmärker ett så kommer det att dyka upp här.",
|
||||||
|
@ -402,7 +406,14 @@
|
||||||
"ignore_notifications_modal.new_accounts_title": "Vill du ignorera aviseringar från nya konton?",
|
"ignore_notifications_modal.new_accounts_title": "Vill du ignorera aviseringar från nya konton?",
|
||||||
"ignore_notifications_modal.not_followers_title": "Vill du ignorera aviseringar från personer som inte följer dig?",
|
"ignore_notifications_modal.not_followers_title": "Vill du ignorera aviseringar från personer som inte följer dig?",
|
||||||
"ignore_notifications_modal.not_following_title": "Vill du blockera aviseringar från personer som du inte följer dig?",
|
"ignore_notifications_modal.not_following_title": "Vill du blockera aviseringar från personer som du inte följer dig?",
|
||||||
"ignore_notifications_modal.private_mentions_title": "Vill du ignorera aviseringar från oönskade privata omnämningar?",
|
"ignore_notifications_modal.private_mentions_title": "Vill du ignorera aviseringar från oombedda privata omnämnanden?",
|
||||||
|
"interaction_modal.action.favourite": "För att fortsätta, måste du favoritmarkera från ditt konto.",
|
||||||
|
"interaction_modal.action.follow": "För att fortsätta, måste du följa från ditt konto.",
|
||||||
|
"interaction_modal.action.reblog": "För att fortsätta, måste du boosta från ditt konto.",
|
||||||
|
"interaction_modal.action.reply": "För att fortsätta, måste du svara från ditt konto.",
|
||||||
|
"interaction_modal.action.vote": "För att fortsätta, måste du rösta från ditt konto.",
|
||||||
|
"interaction_modal.go": "Vidare",
|
||||||
|
"interaction_modal.no_account_yet": "Har du inget konto än?",
|
||||||
"interaction_modal.on_another_server": "På en annan server",
|
"interaction_modal.on_another_server": "På en annan server",
|
||||||
"interaction_modal.on_this_server": "På denna server",
|
"interaction_modal.on_this_server": "På denna server",
|
||||||
"interaction_modal.title.favourite": "Favoritmarkera {name}s inlägg",
|
"interaction_modal.title.favourite": "Favoritmarkera {name}s inlägg",
|
||||||
|
@ -410,6 +421,7 @@
|
||||||
"interaction_modal.title.reblog": "Boosta {name}s inlägg",
|
"interaction_modal.title.reblog": "Boosta {name}s inlägg",
|
||||||
"interaction_modal.title.reply": "Svara på {name}s inlägg",
|
"interaction_modal.title.reply": "Svara på {name}s inlägg",
|
||||||
"interaction_modal.title.vote": "Rösta i {name}s enkät",
|
"interaction_modal.title.vote": "Rösta i {name}s enkät",
|
||||||
|
"interaction_modal.username_prompt": "T.ex. {example}",
|
||||||
"intervals.full.days": "{number, plural, one {# dag} other {# dagar}}",
|
"intervals.full.days": "{number, plural, one {# dag} other {# dagar}}",
|
||||||
"intervals.full.hours": "{number, plural, one {# timme} other {# timmar}}",
|
"intervals.full.hours": "{number, plural, one {# timme} other {# timmar}}",
|
||||||
"intervals.full.minutes": "{number, plural, one {# minut} other {# minuter}}",
|
"intervals.full.minutes": "{number, plural, one {# minut} other {# minuter}}",
|
||||||
|
@ -419,7 +431,7 @@
|
||||||
"keyboard_shortcuts.column": "Fokusera kolumn",
|
"keyboard_shortcuts.column": "Fokusera kolumn",
|
||||||
"keyboard_shortcuts.compose": "Fokusera skrivfältet",
|
"keyboard_shortcuts.compose": "Fokusera skrivfältet",
|
||||||
"keyboard_shortcuts.description": "Beskrivning",
|
"keyboard_shortcuts.description": "Beskrivning",
|
||||||
"keyboard_shortcuts.direct": "för att öppna privata nämningskolumnen",
|
"keyboard_shortcuts.direct": "för att öppna privata omnämnandekolumnen",
|
||||||
"keyboard_shortcuts.down": "Flytta ner i listan",
|
"keyboard_shortcuts.down": "Flytta ner i listan",
|
||||||
"keyboard_shortcuts.enter": "Öppna inlägg",
|
"keyboard_shortcuts.enter": "Öppna inlägg",
|
||||||
"keyboard_shortcuts.favourite": "Favoritmarkera inlägg",
|
"keyboard_shortcuts.favourite": "Favoritmarkera inlägg",
|
||||||
|
@ -445,6 +457,7 @@
|
||||||
"keyboard_shortcuts.toggle_hidden": "Visa/gömma text bakom CW",
|
"keyboard_shortcuts.toggle_hidden": "Visa/gömma text bakom CW",
|
||||||
"keyboard_shortcuts.toggle_sensitivity": "Visa/gömma media",
|
"keyboard_shortcuts.toggle_sensitivity": "Visa/gömma media",
|
||||||
"keyboard_shortcuts.toot": "Starta nytt inlägg",
|
"keyboard_shortcuts.toot": "Starta nytt inlägg",
|
||||||
|
"keyboard_shortcuts.translate": "för att översätta ett inlägg",
|
||||||
"keyboard_shortcuts.unfocus": "Avfokusera skrivfält/sökfält",
|
"keyboard_shortcuts.unfocus": "Avfokusera skrivfält/sökfält",
|
||||||
"keyboard_shortcuts.up": "Flytta uppåt i listan",
|
"keyboard_shortcuts.up": "Flytta uppåt i listan",
|
||||||
"lightbox.close": "Stäng",
|
"lightbox.close": "Stäng",
|
||||||
|
@ -466,6 +479,7 @@
|
||||||
"lists.delete": "Radera lista",
|
"lists.delete": "Radera lista",
|
||||||
"lists.done": "Klar",
|
"lists.done": "Klar",
|
||||||
"lists.edit": "Redigera lista",
|
"lists.edit": "Redigera lista",
|
||||||
|
"lists.exclusive": "Dölj medlemmar i Hem flödet",
|
||||||
"lists.exclusive_hint": "Om någon är med på den här listan, göm dem i ditt Hemtidlinje för att undvika att se deras inlägg två gånger.",
|
"lists.exclusive_hint": "Om någon är med på den här listan, göm dem i ditt Hemtidlinje för att undvika att se deras inlägg två gånger.",
|
||||||
"lists.find_users_to_add": "Hitta användare att lägga till",
|
"lists.find_users_to_add": "Hitta användare att lägga till",
|
||||||
"lists.list_members": "Lista medlemmar",
|
"lists.list_members": "Lista medlemmar",
|
||||||
|
@ -474,12 +488,14 @@
|
||||||
"lists.new_list_name": "Nytt listnamn",
|
"lists.new_list_name": "Nytt listnamn",
|
||||||
"lists.no_lists_yet": "Ännu inga listor.",
|
"lists.no_lists_yet": "Ännu inga listor.",
|
||||||
"lists.no_members_yet": "Inga medlemmar ännu.",
|
"lists.no_members_yet": "Inga medlemmar ännu.",
|
||||||
|
"lists.no_results_found": "Inga resultat hittades.",
|
||||||
"lists.remove_member": "Ta bort",
|
"lists.remove_member": "Ta bort",
|
||||||
"lists.replies_policy.followed": "Alla användare som följs",
|
"lists.replies_policy.followed": "Alla användare som följs",
|
||||||
"lists.replies_policy.list": "Medlemmar i listan",
|
"lists.replies_policy.list": "Medlemmar i listan",
|
||||||
"lists.replies_policy.none": "Ingen",
|
"lists.replies_policy.none": "Ingen",
|
||||||
"lists.save": "Spara",
|
"lists.save": "Spara",
|
||||||
"lists.search": "Sök",
|
"lists.search": "Sök",
|
||||||
|
"lists.show_replies_to": "Inkludera svar från listmedlemmar till",
|
||||||
"load_pending": "{count, plural, one {# nytt objekt} other {# nya objekt}}",
|
"load_pending": "{count, plural, one {# nytt objekt} other {# nya objekt}}",
|
||||||
"loading_indicator.label": "Laddar…",
|
"loading_indicator.label": "Laddar…",
|
||||||
"media_gallery.hide": "Dölj",
|
"media_gallery.hide": "Dölj",
|
||||||
|
@ -500,7 +516,7 @@
|
||||||
"navigation_bar.bookmarks": "Bokmärken",
|
"navigation_bar.bookmarks": "Bokmärken",
|
||||||
"navigation_bar.community_timeline": "Lokal tidslinje",
|
"navigation_bar.community_timeline": "Lokal tidslinje",
|
||||||
"navigation_bar.compose": "Författa nytt inlägg",
|
"navigation_bar.compose": "Författa nytt inlägg",
|
||||||
"navigation_bar.direct": "Privata nämningar",
|
"navigation_bar.direct": "Privata omnämnande",
|
||||||
"navigation_bar.discover": "Upptäck",
|
"navigation_bar.discover": "Upptäck",
|
||||||
"navigation_bar.domain_blocks": "Dolda domäner",
|
"navigation_bar.domain_blocks": "Dolda domäner",
|
||||||
"navigation_bar.explore": "Utforska",
|
"navigation_bar.explore": "Utforska",
|
||||||
|
@ -532,12 +548,14 @@
|
||||||
"notification.annual_report.view": "Visa #Wrapstodon",
|
"notification.annual_report.view": "Visa #Wrapstodon",
|
||||||
"notification.favourite": "{name} favoritmarkerade ditt inlägg",
|
"notification.favourite": "{name} favoritmarkerade ditt inlägg",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} och <a>{count, plural, one {# annan} other {# andra}}</a> har favoritmarkerat ditt inlägg",
|
"notification.favourite.name_and_others_with_link": "{name} och <a>{count, plural, one {# annan} other {# andra}}</a> har favoritmarkerat ditt inlägg",
|
||||||
|
"notification.favourite_pm": "{name} favoritmarkerade ditt privata omnämnande",
|
||||||
|
"notification.favourite_pm.name_and_others_with_link": "{name} och <a>{count, plural, one {# annan} other {# andra}}</a> favoritmarkerade ditt privata omnämnande",
|
||||||
"notification.follow": "{name} följer dig",
|
"notification.follow": "{name} följer dig",
|
||||||
"notification.follow.name_and_others": "{name} och <a>{count, plural, one {# annan} other {# andra}}</a> följer dig",
|
"notification.follow.name_and_others": "{name} och <a>{count, plural, one {# annan} other {# andra}}</a> följer dig",
|
||||||
"notification.follow_request": "{name} har begärt att följa dig",
|
"notification.follow_request": "{name} har begärt att följa dig",
|
||||||
"notification.follow_request.name_and_others": "{name} och {count, plural, one {# en annan} other {# andra}} har bett att följa dig",
|
"notification.follow_request.name_and_others": "{name} och {count, plural, one {# en annan} other {# andra}} har bett att följa dig",
|
||||||
"notification.label.mention": "Nämn",
|
"notification.label.mention": "Nämn",
|
||||||
"notification.label.private_mention": "Privat nämning",
|
"notification.label.private_mention": "Privat omnämnande",
|
||||||
"notification.label.private_reply": "Privata svar",
|
"notification.label.private_reply": "Privata svar",
|
||||||
"notification.label.reply": "Svar",
|
"notification.label.reply": "Svar",
|
||||||
"notification.mention": "Nämn",
|
"notification.mention": "Nämn",
|
||||||
|
@ -640,6 +658,7 @@
|
||||||
"onboarding.follows.done": "Färdig",
|
"onboarding.follows.done": "Färdig",
|
||||||
"onboarding.follows.empty": "Tyvärr kan inga resultat visas just nu. Du kan prova att använda sökfunktionen eller utforska sidan för att hitta personer att följa, eller försök igen senare.",
|
"onboarding.follows.empty": "Tyvärr kan inga resultat visas just nu. Du kan prova att använda sökfunktionen eller utforska sidan för att hitta personer att följa, eller försök igen senare.",
|
||||||
"onboarding.follows.search": "Sök",
|
"onboarding.follows.search": "Sök",
|
||||||
|
"onboarding.follows.title": "Följ människor för att komma igång",
|
||||||
"onboarding.profile.discoverable": "Gör min profil upptäckbar",
|
"onboarding.profile.discoverable": "Gör min profil upptäckbar",
|
||||||
"onboarding.profile.discoverable_hint": "När du väljer att vara upptäckbar på Mastodon kan dina inlägg visas i sök- och trendresultat, och din profil kan föreslås för personer med liknande intressen som du.",
|
"onboarding.profile.discoverable_hint": "När du väljer att vara upptäckbar på Mastodon kan dina inlägg visas i sök- och trendresultat, och din profil kan föreslås för personer med liknande intressen som du.",
|
||||||
"onboarding.profile.display_name": "Visningsnamn",
|
"onboarding.profile.display_name": "Visningsnamn",
|
||||||
|
@ -677,6 +696,8 @@
|
||||||
"privacy_policy.title": "Integritetspolicy",
|
"privacy_policy.title": "Integritetspolicy",
|
||||||
"recommended": "Rekommenderas",
|
"recommended": "Rekommenderas",
|
||||||
"refresh": "Läs om",
|
"refresh": "Läs om",
|
||||||
|
"regeneration_indicator.please_stand_by": "Vänligen vänta.",
|
||||||
|
"regeneration_indicator.preparing_your_home_feed": "Förbereder ditt hemflöde…",
|
||||||
"relative_time.days": "{number}d",
|
"relative_time.days": "{number}d",
|
||||||
"relative_time.full.days": "{number, plural, one {# dag} other {# dagar}} sedan",
|
"relative_time.full.days": "{number, plural, one {# dag} other {# dagar}} sedan",
|
||||||
"relative_time.full.hours": "{number, plural, one {# timme} other {# timmar}} sedan",
|
"relative_time.full.hours": "{number, plural, one {# timme} other {# timmar}} sedan",
|
||||||
|
@ -760,15 +781,18 @@
|
||||||
"search_results.accounts": "Profiler",
|
"search_results.accounts": "Profiler",
|
||||||
"search_results.all": "Alla",
|
"search_results.all": "Alla",
|
||||||
"search_results.hashtags": "Hashtaggar",
|
"search_results.hashtags": "Hashtaggar",
|
||||||
|
"search_results.no_results": "Inga resultat.",
|
||||||
|
"search_results.no_search_yet": "Prova att söka efter inlägg, profiler eller hashtags.",
|
||||||
"search_results.see_all": "Visa alla",
|
"search_results.see_all": "Visa alla",
|
||||||
"search_results.statuses": "Inlägg",
|
"search_results.statuses": "Inlägg",
|
||||||
|
"search_results.title": "Sök efter \"{q}\"",
|
||||||
"server_banner.about_active_users": "Personer som använt denna server de senaste 30 dagarna (månatligt aktiva användare)",
|
"server_banner.about_active_users": "Personer som använt denna server de senaste 30 dagarna (månatligt aktiva användare)",
|
||||||
"server_banner.active_users": "aktiva användare",
|
"server_banner.active_users": "aktiva användare",
|
||||||
"server_banner.administered_by": "Administrerad av:",
|
"server_banner.administered_by": "Administrerad av:",
|
||||||
"server_banner.is_one_of_many": "{domain} är en av de många oberoende Mastodon-servrar som du kan använda för att delta i Fediversen.",
|
"server_banner.is_one_of_many": "{domain} är en av de många oberoende Mastodon-servrar som du kan använda för att delta i Fediversen.",
|
||||||
"server_banner.server_stats": "Serverstatistik:",
|
"server_banner.server_stats": "Serverstatistik:",
|
||||||
"sign_in_banner.create_account": "Skapa konto",
|
"sign_in_banner.create_account": "Skapa konto",
|
||||||
"sign_in_banner.follow_anyone": "Följ vem som helst över Fediverse och se allt i kronologisk ordning. Inga algoritmer, inga annonser och inga klickbeten i sikte.",
|
"sign_in_banner.follow_anyone": "Följ vem som helst över Fediversum och se allt i kronologisk ordning. Inga algoritmer, annonser eller klickbeten i sikte.",
|
||||||
"sign_in_banner.mastodon_is": "Mastodon är det bästa sättet att hänga med i vad som händer.",
|
"sign_in_banner.mastodon_is": "Mastodon är det bästa sättet att hänga med i vad som händer.",
|
||||||
"sign_in_banner.sign_in": "Logga in",
|
"sign_in_banner.sign_in": "Logga in",
|
||||||
"sign_in_banner.sso_redirect": "Logga in eller registrera dig",
|
"sign_in_banner.sso_redirect": "Logga in eller registrera dig",
|
||||||
|
@ -783,8 +807,8 @@
|
||||||
"status.copy": "Kopiera inläggslänk",
|
"status.copy": "Kopiera inläggslänk",
|
||||||
"status.delete": "Radera",
|
"status.delete": "Radera",
|
||||||
"status.detailed_status": "Detaljerad samtalsvy",
|
"status.detailed_status": "Detaljerad samtalsvy",
|
||||||
"status.direct": "Nämn @{name} privat",
|
"status.direct": "Omnämn @{name} privat",
|
||||||
"status.direct_indicator": "Privat nämning",
|
"status.direct_indicator": "Privat omnämnande",
|
||||||
"status.edit": "Redigera",
|
"status.edit": "Redigera",
|
||||||
"status.edited": "Senast ändrad {date}",
|
"status.edited": "Senast ändrad {date}",
|
||||||
"status.edited_x_times": "Redigerad {count, plural, one {{count} gång} other {{count} gånger}}",
|
"status.edited_x_times": "Redigerad {count, plural, one {{count} gång} other {{count} gånger}}",
|
||||||
|
@ -813,6 +837,7 @@
|
||||||
"status.reblogs.empty": "Ingen har boostat detta inlägg än. När någon gör det kommer de synas här.",
|
"status.reblogs.empty": "Ingen har boostat detta inlägg än. När någon gör det kommer de synas här.",
|
||||||
"status.redraft": "Radera & gör om",
|
"status.redraft": "Radera & gör om",
|
||||||
"status.remove_bookmark": "Ta bort bokmärke",
|
"status.remove_bookmark": "Ta bort bokmärke",
|
||||||
|
"status.remove_favourite": "Ta bort från Favoriter",
|
||||||
"status.replied_in_thread": "Svarade i tråden",
|
"status.replied_in_thread": "Svarade i tråden",
|
||||||
"status.replied_to": "Svarade på {name}",
|
"status.replied_to": "Svarade på {name}",
|
||||||
"status.reply": "Svara",
|
"status.reply": "Svara",
|
||||||
|
@ -834,6 +859,7 @@
|
||||||
"subscribed_languages.target": "Ändra språkprenumerationer för {target}",
|
"subscribed_languages.target": "Ändra språkprenumerationer för {target}",
|
||||||
"tabs_bar.home": "Hem",
|
"tabs_bar.home": "Hem",
|
||||||
"tabs_bar.notifications": "Aviseringar",
|
"tabs_bar.notifications": "Aviseringar",
|
||||||
|
"terms_of_service.title": "Användarvillkor",
|
||||||
"time_remaining.days": "{number, plural, one {# dag} other {# dagar}} kvar",
|
"time_remaining.days": "{number, plural, one {# dag} other {# dagar}} kvar",
|
||||||
"time_remaining.hours": "{number, plural, one {# timme} other {# timmar}} kvar",
|
"time_remaining.hours": "{number, plural, one {# timme} other {# timmar}} kvar",
|
||||||
"time_remaining.minutes": "{number, plural, one {# minut} other {# minuter}} kvar",
|
"time_remaining.minutes": "{number, plural, one {# minut} other {# minuter}} kvar",
|
||||||
|
|
|
@ -659,6 +659,10 @@ code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status-card {
|
||||||
|
contain: unset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.block-icon {
|
.block-icon {
|
||||||
|
|
|
@ -13,7 +13,7 @@ class ActivityPub::TagManager
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
def public_collection?(uri)
|
def public_collection?(uri)
|
||||||
uri == COLLECTIONS[:public] || uri == 'as:Public' || uri == 'Public'
|
uri == COLLECTIONS[:public] || %w(as:Public Public).include?(uri)
|
||||||
end
|
end
|
||||||
|
|
||||||
def url_for(target)
|
def url_for(target)
|
||||||
|
|
|
@ -3,14 +3,18 @@
|
||||||
module ApplicationExtension
|
module ApplicationExtension
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
APP_NAME_LIMIT = 60
|
||||||
|
APP_REDIRECT_URI_LIMIT = 2_000
|
||||||
|
APP_WEBSITE_LIMIT = 2_000
|
||||||
|
|
||||||
included do
|
included do
|
||||||
include Redisable
|
include Redisable
|
||||||
|
|
||||||
has_many :created_users, class_name: 'User', foreign_key: 'created_by_application_id', inverse_of: :created_by_application
|
has_many :created_users, class_name: 'User', foreign_key: 'created_by_application_id', inverse_of: :created_by_application
|
||||||
|
|
||||||
validates :name, length: { maximum: 60 }
|
validates :name, length: { maximum: APP_NAME_LIMIT }
|
||||||
validates :website, url: true, length: { maximum: 2_000 }, if: :website?
|
validates :redirect_uri, length: { maximum: APP_REDIRECT_URI_LIMIT }
|
||||||
validates :redirect_uri, length: { maximum: 2_000 }
|
validates :website, url: true, length: { maximum: APP_WEBSITE_LIMIT }, if: :website?
|
||||||
|
|
||||||
# The relationship used between Applications and AccessTokens is using
|
# The relationship used between Applications and AccessTokens is using
|
||||||
# dependent: delete_all, which means the ActiveRecord callback in
|
# dependent: delete_all, which means the ActiveRecord callback in
|
||||||
|
|
|
@ -111,16 +111,10 @@ class Request
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
# If we are using a persistent connection, we have to
|
|
||||||
# read every response to be able to move forward at all.
|
|
||||||
# However, simply calling #to_s or #flush may not be safe,
|
|
||||||
# as the response body, if malicious, could be too big
|
|
||||||
# for our memory. So we use the #body_with_limit method
|
|
||||||
response.body_with_limit if http_client.persistent?
|
|
||||||
|
|
||||||
yield response if block_given?
|
yield response if block_given?
|
||||||
ensure
|
ensure
|
||||||
http_client.close unless http_client.persistent?
|
response.truncated_body if http_client.persistent? && !response.connection.finished_request?
|
||||||
|
http_client.close unless http_client.persistent? && response.connection.finished_request?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -107,23 +107,23 @@ class Account < ApplicationRecord
|
||||||
validates_with UniqueUsernameValidator, if: -> { will_save_change_to_username? }
|
validates_with UniqueUsernameValidator, if: -> { will_save_change_to_username? }
|
||||||
|
|
||||||
# Remote user validations, also applies to internal actors
|
# Remote user validations, also applies to internal actors
|
||||||
validates :username, format: { with: USERNAME_ONLY_RE }, if: -> { (!local? || actor_type == 'Application') && will_save_change_to_username? }
|
validates :username, format: { with: USERNAME_ONLY_RE }, if: -> { (remote? || actor_type_application?) && will_save_change_to_username? }
|
||||||
|
|
||||||
# Remote user validations
|
# Remote user validations
|
||||||
validates :uri, presence: true, unless: :local?, on: :create
|
validates :uri, presence: true, unless: :local?, on: :create
|
||||||
|
|
||||||
# Local user validations
|
# Local user validations
|
||||||
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: USERNAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
|
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: USERNAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_username? && !actor_type_application? }
|
||||||
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
|
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? && !actor_type_application? }
|
||||||
validates :display_name, length: { maximum: DISPLAY_NAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_display_name? }
|
validates :display_name, length: { maximum: DISPLAY_NAME_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_display_name? }
|
||||||
validates :note, note_length: { maximum: NOTE_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_note? }
|
validates :note, note_length: { maximum: NOTE_LENGTH_LIMIT }, if: -> { local? && will_save_change_to_note? }
|
||||||
validates :fields, length: { maximum: DEFAULT_FIELDS_SIZE }, if: -> { local? && will_save_change_to_fields? }
|
validates :fields, length: { maximum: DEFAULT_FIELDS_SIZE }, if: -> { local? && will_save_change_to_fields? }
|
||||||
validates_with EmptyProfileFieldNamesValidator, if: -> { local? && will_save_change_to_fields? }
|
validates_with EmptyProfileFieldNamesValidator, if: -> { local? && will_save_change_to_fields? }
|
||||||
with_options on: :create do
|
with_options on: :create, if: :local? do
|
||||||
validates :uri, absence: true, if: :local?
|
validates :followers_url, absence: true
|
||||||
validates :inbox_url, absence: true, if: :local?
|
validates :inbox_url, absence: true
|
||||||
validates :shared_inbox_url, absence: true, if: :local?
|
validates :shared_inbox_url, absence: true
|
||||||
validates :followers_url, absence: true, if: :local?
|
validates :uri, absence: true
|
||||||
end
|
end
|
||||||
|
|
||||||
normalizes :username, with: ->(username) { username.squish }
|
normalizes :username, with: ->(username) { username.squish }
|
||||||
|
@ -186,6 +186,10 @@ class Account < ApplicationRecord
|
||||||
domain.nil?
|
domain.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remote?
|
||||||
|
domain.present?
|
||||||
|
end
|
||||||
|
|
||||||
def moved?
|
def moved?
|
||||||
moved_to_account_id.present?
|
moved_to_account_id.present?
|
||||||
end
|
end
|
||||||
|
@ -204,6 +208,10 @@ class Account < ApplicationRecord
|
||||||
self.actor_type = ActiveModel::Type::Boolean.new.cast(val) ? 'Service' : 'Person'
|
self.actor_type = ActiveModel::Type::Boolean.new.cast(val) ? 'Service' : 'Person'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def actor_type_application?
|
||||||
|
actor_type == 'Application'
|
||||||
|
end
|
||||||
|
|
||||||
def group?
|
def group?
|
||||||
actor_type == 'Group'
|
actor_type == 'Group'
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,6 +27,7 @@ class AccountWarning < ApplicationRecord
|
||||||
suspend: 4_000,
|
suspend: 4_000,
|
||||||
}, suffix: :action
|
}, suffix: :action
|
||||||
|
|
||||||
|
APPEAL_WINDOW = 20.days
|
||||||
RECENT_PERIOD = 3.months.freeze
|
RECENT_PERIOD = 3.months.freeze
|
||||||
|
|
||||||
normalizes :text, with: ->(text) { text.to_s }, apply_to_nil: true
|
normalizes :text, with: ->(text) { text.to_s }, apply_to_nil: true
|
||||||
|
@ -49,6 +50,10 @@ class AccountWarning < ApplicationRecord
|
||||||
overruled_at.present?
|
overruled_at.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def appeal_eligible?
|
||||||
|
created_at >= APPEAL_WINDOW.ago
|
||||||
|
end
|
||||||
|
|
||||||
def to_log_human_identifier
|
def to_log_human_identifier
|
||||||
target_account.acct
|
target_account.acct
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
#
|
#
|
||||||
class Appeal < ApplicationRecord
|
class Appeal < ApplicationRecord
|
||||||
MAX_STRIKE_AGE = 20.days
|
|
||||||
|
|
||||||
TEXT_LENGTH_LIMIT = 2_000
|
TEXT_LENGTH_LIMIT = 2_000
|
||||||
|
|
||||||
belongs_to :account
|
belongs_to :account
|
||||||
|
@ -68,6 +66,6 @@ class Appeal < ApplicationRecord
|
||||||
private
|
private
|
||||||
|
|
||||||
def validate_time_frame
|
def validate_time_frame
|
||||||
errors.add(:base, I18n.t('strikes.errors.too_late')) if strike.created_at < MAX_STRIKE_AGE.ago
|
errors.add(:base, I18n.t('strikes.errors.too_late')) unless strike.appeal_eligible?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -84,6 +84,10 @@ class Form::AdminSettings
|
||||||
flavour_and_skin
|
flavour_and_skin
|
||||||
).freeze
|
).freeze
|
||||||
|
|
||||||
|
DIGEST_KEYS = %i(
|
||||||
|
custom_css
|
||||||
|
).freeze
|
||||||
|
|
||||||
OVERRIDEN_SETTINGS = {
|
OVERRIDEN_SETTINGS = {
|
||||||
authorized_fetch: :authorized_fetch_mode?,
|
authorized_fetch: :authorized_fetch_mode?,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
@ -137,6 +141,8 @@ class Form::AdminSettings
|
||||||
KEYS.each do |key|
|
KEYS.each do |key|
|
||||||
next if PSEUDO_KEYS.include?(key) || !instance_variable_defined?(:"@#{key}")
|
next if PSEUDO_KEYS.include?(key) || !instance_variable_defined?(:"@#{key}")
|
||||||
|
|
||||||
|
cache_digest_value(key) if DIGEST_KEYS.include?(key)
|
||||||
|
|
||||||
if UPLOAD_KEYS.include?(key)
|
if UPLOAD_KEYS.include?(key)
|
||||||
public_send(key).save
|
public_send(key).save
|
||||||
else
|
else
|
||||||
|
@ -156,6 +162,18 @@ class Form::AdminSettings
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def cache_digest_value(key)
|
||||||
|
Rails.cache.delete(:"setting_digest_#{key}")
|
||||||
|
|
||||||
|
key_value = instance_variable_get(:"@#{key}")
|
||||||
|
if key_value.present?
|
||||||
|
Rails.cache.write(
|
||||||
|
:"setting_digest_#{key}",
|
||||||
|
Digest::SHA256.hexdigest(key_value)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def typecast_value(key, value)
|
def typecast_value(key, value)
|
||||||
if BOOLEAN_KEYS.include?(key)
|
if BOOLEAN_KEYS.include?(key)
|
||||||
value == '1'
|
value == '1'
|
||||||
|
|
|
@ -64,21 +64,31 @@ class NotificationGroup < ActiveModelSerializers::Model
|
||||||
binds = [
|
binds = [
|
||||||
account_id,
|
account_id,
|
||||||
SAMPLE_ACCOUNTS_SIZE,
|
SAMPLE_ACCOUNTS_SIZE,
|
||||||
pagination_range.begin,
|
|
||||||
pagination_range.end,
|
|
||||||
ActiveRecord::Relation::QueryAttribute.new('group_keys', group_keys, ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.new(ActiveModel::Type::String.new)),
|
ActiveRecord::Relation::QueryAttribute.new('group_keys', group_keys, ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.new(ActiveModel::Type::String.new)),
|
||||||
|
pagination_range.begin || 0,
|
||||||
]
|
]
|
||||||
|
binds << pagination_range.end unless pagination_range.end.nil?
|
||||||
|
|
||||||
|
upper_bound_cond = begin
|
||||||
|
if pagination_range.end.nil?
|
||||||
|
''
|
||||||
|
elsif pagination_range.exclude_end?
|
||||||
|
'AND id < $5'
|
||||||
|
else
|
||||||
|
'AND id <= $5'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
ActiveRecord::Base.connection.select_all(<<~SQL.squish, 'grouped_notifications', binds).cast_values.to_h { |k, *values| [k, values] }
|
ActiveRecord::Base.connection.select_all(<<~SQL.squish, 'grouped_notifications', binds).cast_values.to_h { |k, *values| [k, values] }
|
||||||
SELECT
|
SELECT
|
||||||
groups.group_key,
|
groups.group_key,
|
||||||
(SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4 ORDER BY id DESC LIMIT 1),
|
(SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond} ORDER BY id DESC LIMIT 1),
|
||||||
array(SELECT from_account_id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4 ORDER BY id DESC LIMIT $2),
|
array(SELECT from_account_id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond} ORDER BY id DESC LIMIT $2),
|
||||||
(SELECT count(*) FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4) AS notifications_count,
|
(SELECT count(*) FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond}) AS notifications_count,
|
||||||
(SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id >= $3 ORDER BY id ASC LIMIT 1) AS min_id,
|
(SELECT id FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id >= $4 ORDER BY id ASC LIMIT 1) AS min_id,
|
||||||
(SELECT created_at FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key AND id <= $4 ORDER BY id DESC LIMIT 1)
|
(SELECT created_at FROM notifications WHERE notifications.account_id = $1 AND notifications.group_key = groups.group_key #{upper_bound_cond} ORDER BY id DESC LIMIT 1)
|
||||||
FROM
|
FROM
|
||||||
unnest($5::text[]) AS groups(group_key);
|
unnest($3::text[]) AS groups(group_key);
|
||||||
SQL
|
SQL
|
||||||
else
|
else
|
||||||
binds = [
|
binds = [
|
||||||
|
|
|
@ -61,11 +61,7 @@ class Poll < ApplicationRecord
|
||||||
votes.where(account: account).pluck(:choice)
|
votes.where(account: account).pluck(:choice)
|
||||||
end
|
end
|
||||||
|
|
||||||
delegate :local?, to: :account
|
delegate :local?, :remote?, to: :account
|
||||||
|
|
||||||
def remote?
|
|
||||||
!local?
|
|
||||||
end
|
|
||||||
|
|
||||||
def emojis
|
def emojis
|
||||||
@emojis ||= CustomEmoji.from_text(options.join(' '), account.domain)
|
@emojis ||= CustomEmoji.from_text(options.join(' '), account.domain)
|
||||||
|
|
|
@ -16,7 +16,7 @@ class Trends::Links < Trends::Base
|
||||||
class Query < Trends::Query
|
class Query < Trends::Query
|
||||||
def to_arel
|
def to_arel
|
||||||
scope = PreviewCard.joins(:trend).reorder(score: :desc)
|
scope = PreviewCard.joins(:trend).reorder(score: :desc)
|
||||||
scope = scope.reorder(language_order_clause.desc, score: :desc) if preferred_languages.present?
|
scope = scope.merge(language_order_clause) if preferred_languages.present?
|
||||||
scope = scope.merge(PreviewCardTrend.allowed) if @allowed
|
scope = scope.merge(PreviewCardTrend.allowed) if @allowed
|
||||||
scope = scope.offset(@offset) if @offset.present?
|
scope = scope.offset(@offset) if @offset.present?
|
||||||
scope = scope.limit(@limit) if @limit.present?
|
scope = scope.limit(@limit) if @limit.present?
|
||||||
|
@ -26,7 +26,7 @@ class Trends::Links < Trends::Base
|
||||||
private
|
private
|
||||||
|
|
||||||
def language_order_clause
|
def language_order_clause
|
||||||
Arel::Nodes::Case.new.when(PreviewCardTrend.arel_table[:language].in(preferred_languages)).then(1).else(0)
|
language_order_for(PreviewCardTrend)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,13 @@ class Trends::Query
|
||||||
to_arel.to_a
|
to_arel.to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def language_order_for(trend_class)
|
||||||
|
trend_class
|
||||||
|
.reorder(nil)
|
||||||
|
.in_order_of(:language, [preferred_languages], filter: false)
|
||||||
|
.order(score: :desc)
|
||||||
|
end
|
||||||
|
|
||||||
def preferred_languages
|
def preferred_languages
|
||||||
if @account&.chosen_languages.present?
|
if @account&.chosen_languages.present?
|
||||||
@account.chosen_languages
|
@account.chosen_languages
|
||||||
|
|
|
@ -15,7 +15,7 @@ class Trends::Statuses < Trends::Base
|
||||||
class Query < Trends::Query
|
class Query < Trends::Query
|
||||||
def to_arel
|
def to_arel
|
||||||
scope = Status.joins(:trend).reorder(score: :desc)
|
scope = Status.joins(:trend).reorder(score: :desc)
|
||||||
scope = scope.reorder(language_order_clause.desc, score: :desc) if preferred_languages.present?
|
scope = scope.merge(language_order_clause) if preferred_languages.present?
|
||||||
scope = scope.merge(StatusTrend.allowed) if @allowed
|
scope = scope.merge(StatusTrend.allowed) if @allowed
|
||||||
scope = scope.not_excluded_by_account(@account).not_domain_blocked_by_account(@account) if @account.present?
|
scope = scope.not_excluded_by_account(@account).not_domain_blocked_by_account(@account) if @account.present?
|
||||||
scope = scope.offset(@offset) if @offset.present?
|
scope = scope.offset(@offset) if @offset.present?
|
||||||
|
@ -26,7 +26,7 @@ class Trends::Statuses < Trends::Base
|
||||||
private
|
private
|
||||||
|
|
||||||
def language_order_clause
|
def language_order_clause
|
||||||
Arel::Nodes::Case.new.when(StatusTrend.arel_table[:language].in(preferred_languages)).then(1).else(0)
|
language_order_for(StatusTrend)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@ class Trends::Tags < Trends::Base
|
||||||
|
|
||||||
class Query < Trends::Query
|
class Query < Trends::Query
|
||||||
def to_arel
|
def to_arel
|
||||||
scope = Tag.joins(:trend).reorder(language_order_clause.desc, score: :desc)
|
scope = Tag.joins(:trend).reorder(score: :desc)
|
||||||
|
scope = scope.merge(language_order_clause) if preferred_languages.present?
|
||||||
scope = scope.merge(TagTrend.allowed) if @allowed
|
scope = scope.merge(TagTrend.allowed) if @allowed
|
||||||
scope = scope.offset(@offset) if @offset.present?
|
scope = scope.offset(@offset) if @offset.present?
|
||||||
scope = scope.limit(@limit) if @limit.present?
|
scope = scope.limit(@limit) if @limit.present?
|
||||||
|
@ -25,7 +26,7 @@ class Trends::Tags < Trends::Base
|
||||||
private
|
private
|
||||||
|
|
||||||
def language_order_clause
|
def language_order_clause
|
||||||
Arel::Nodes::Case.new.when(TagTrend.arel_table[:language].in(preferred_languages)).then(1).else(0)
|
language_order_for(TagTrend)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ class UserRole < ApplicationRecord
|
||||||
NOBODY_POSITION = -1
|
NOBODY_POSITION = -1
|
||||||
|
|
||||||
POSITION_LIMIT = (2**31) - 1
|
POSITION_LIMIT = (2**31) - 1
|
||||||
|
CSS_COLORS = /\A#?(?:[A-F0-9]{3}){1,2}\z/i # CSS-style hex colors
|
||||||
|
|
||||||
module Flags
|
module Flags
|
||||||
NONE = 0
|
NONE = 0
|
||||||
|
@ -90,7 +91,7 @@ class UserRole < ApplicationRecord
|
||||||
attr_writer :current_account
|
attr_writer :current_account
|
||||||
|
|
||||||
validates :name, presence: true, unless: :everyone?
|
validates :name, presence: true, unless: :everyone?
|
||||||
validates :color, format: { with: /\A#?(?:[A-F0-9]{3}){1,2}\z/i }, unless: -> { color.blank? }
|
validates :color, format: { with: CSS_COLORS }, if: :color?
|
||||||
validates :position, numericality: { in: (-POSITION_LIMIT..POSITION_LIMIT) }
|
validates :position, numericality: { in: (-POSITION_LIMIT..POSITION_LIMIT) }
|
||||||
|
|
||||||
validate :validate_permissions_elevation
|
validate :validate_permissions_elevation
|
||||||
|
@ -101,9 +102,6 @@ class UserRole < ApplicationRecord
|
||||||
before_validation :set_position
|
before_validation :set_position
|
||||||
|
|
||||||
scope :assignable, -> { where.not(id: EVERYONE_ROLE_ID).order(position: :asc) }
|
scope :assignable, -> { where.not(id: EVERYONE_ROLE_ID).order(position: :asc) }
|
||||||
scope :highlighted, -> { where(highlighted: true) }
|
|
||||||
scope :with_color, -> { where.not(color: [nil, '']) }
|
|
||||||
scope :providing_styles, -> { highlighted.with_color }
|
|
||||||
|
|
||||||
has_many :users, inverse_of: :role, foreign_key: 'role_id', dependent: :nullify
|
has_many :users, inverse_of: :role, foreign_key: 'role_id', dependent: :nullify
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ class AccountWarningPolicy < ApplicationPolicy
|
||||||
end
|
end
|
||||||
|
|
||||||
def appeal?
|
def appeal?
|
||||||
target? && record.created_at >= Appeal::MAX_STRIKE_AGE.ago
|
target? && record.appeal_eligible?
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -12,7 +12,7 @@ class Admin::StatusPolicy < ApplicationPolicy
|
||||||
end
|
end
|
||||||
|
|
||||||
def show?
|
def show?
|
||||||
role.can?(:manage_reports, :manage_users) && (record.public_visibility? || record.unlisted_visibility? || record.reported? || viewable_through_normal_policy?)
|
role.can?(:manage_reports, :manage_users) && eligible_to_show?
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy?
|
def destroy?
|
||||||
|
@ -29,6 +29,10 @@ class Admin::StatusPolicy < ApplicationPolicy
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def eligible_to_show?
|
||||||
|
record.distributable? || record.reported? || viewable_through_normal_policy?
|
||||||
|
end
|
||||||
|
|
||||||
def viewable_through_normal_policy?
|
def viewable_through_normal_policy?
|
||||||
StatusPolicy.new(current_account, record, @preloaded_relations).show?
|
StatusPolicy.new(current_account, record, @preloaded_relations).show?
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,10 +10,16 @@ class UserRolePolicy < ApplicationPolicy
|
||||||
end
|
end
|
||||||
|
|
||||||
def update?
|
def update?
|
||||||
role.can?(:manage_roles) && (role.overrides?(record) || role.id == record.id)
|
role.can?(:manage_roles) && (role.overrides?(record) || self_editing?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy?
|
def destroy?
|
||||||
!record.everyone? && role.can?(:manage_roles) && role.overrides?(record) && role.id != record.id
|
!record.everyone? && role.can?(:manage_roles) && role.overrides?(record) && !self_editing?
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def self_editing?
|
||||||
|
role.id == record.id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,8 +8,4 @@ class REST::ScheduledStatusSerializer < ActiveModel::Serializer
|
||||||
def id
|
def id
|
||||||
object.id.to_s
|
object.id.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def params
|
|
||||||
object.params.without('application_id')
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
.report-notes__item__header
|
.report-notes__item__header
|
||||||
%span.username
|
%span.username
|
||||||
= link_to report_note.account.username, admin_account_path(report_note.account_id)
|
= link_to report_note.account.username, admin_account_path(report_note.account_id)
|
||||||
%time.relative-formatted{ datetime: report_note.created_at.iso8601 }
|
%time.relative-formatted{ datetime: report_note.created_at.iso8601, title: report_note.created_at }
|
||||||
= l report_note.created_at.to_date
|
= l report_note.created_at.to_date
|
||||||
|
|
||||||
.report-notes__item__content
|
.report-notes__item__content
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
= link_to report.account.username, admin_account_path(report.account_id)
|
= link_to report.account.username, admin_account_path(report.account_id)
|
||||||
- else
|
- else
|
||||||
= link_to report.account.domain, admin_instance_path(report.account.domain)
|
= link_to report.account.domain, admin_instance_path(report.account.domain)
|
||||||
%time.relative-formatted{ datetime: report.created_at.iso8601 }
|
%time.relative-formatted{ datetime: report.created_at.iso8601, title: report.created_at }
|
||||||
= l report.created_at.to_date
|
= l report.created_at.to_date
|
||||||
.report-notes__item__content
|
.report-notes__item__content
|
||||||
= simple_format(h(report.comment))
|
= simple_format(h(report.comment))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
.announcements-list__item
|
.announcements-list__item
|
||||||
- if can?(:update, role)
|
- if can?(:update, role)
|
||||||
= link_to edit_admin_role_path(role), class: 'announcements-list__item__title' do
|
= link_to edit_admin_role_path(role), class: 'announcements-list__item__title' do
|
||||||
%span.user-role{ class: "user-role-#{role.id}" }
|
%span.user-role
|
||||||
= material_symbol 'group'
|
= material_symbol 'group'
|
||||||
|
|
||||||
- if role.everyone?
|
- if role.everyone?
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
= role.name
|
= role.name
|
||||||
- else
|
- else
|
||||||
%span.announcements-list__item__title
|
%span.announcements-list__item__title
|
||||||
%span.user-role{ class: "user-role-#{role.id}" }
|
%span.user-role
|
||||||
= material_symbol 'group'
|
= material_symbol 'group'
|
||||||
|
|
||||||
- if role.everyone?
|
- if role.everyone?
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
%div
|
%div
|
||||||
- if defined?(show_apps_buttons) && show_apps_buttons
|
- if defined?(show_apps_buttons) && show_apps_buttons
|
||||||
.email-welcome-apps-btns
|
.email-welcome-apps-btns
|
||||||
= link_to image_tag(frontend_asset_url('images/mailer-new/store-icons/btn-app-store.png'), alt: t('user_mailer.welcome.apps_ios_action'), width: 120, height: 40), 'https://apps.apple.com/app/mastodon-for-iphone-and-ipad/id1571998974'
|
= link_to image_tag(frontend_asset_url('images/mailer-new/store-icons/btn-app-store.png'), alt: t('user_mailer.welcome.apps_ios_action'), width: 120, height: 40), app_store_url_ios
|
||||||
= link_to image_tag(frontend_asset_url('images/mailer-new/store-icons/btn-google-play.png'), alt: t('user_mailer.welcome.apps_android_action'), width: 120, height: 40), 'https://play.google.com/store/apps/details?id=org.joinmastodon.android'
|
= link_to image_tag(frontend_asset_url('images/mailer-new/store-icons/btn-google-play.png'), alt: t('user_mailer.welcome.apps_android_action'), width: 120, height: 40), app_store_url_android
|
||||||
- elsif defined?(button_text) && defined?(button_url) && defined?(checked) && !checked
|
- elsif defined?(button_text) && defined?(button_url) && defined?(checked) && !checked
|
||||||
= render 'application/mailer/button', text: button_text, url: button_url, has_arrow: false
|
= render 'application/mailer/button', text: button_text, url: button_url, has_arrow: false
|
||||||
/[if mso]
|
/[if mso]
|
||||||
|
|
|
@ -2,9 +2,3 @@
|
||||||
<%= raw custom_css_styles %>
|
<%= raw custom_css_styles %>
|
||||||
|
|
||||||
<%- end %>
|
<%- end %>
|
||||||
<%- @user_roles.each do |role| %>
|
|
||||||
.user-role-<%= role.id %> {
|
|
||||||
--user-role-accent: <%= role.color %>;
|
|
||||||
}
|
|
||||||
|
|
||||||
<%- end %>
|
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
.report-notes__item__header
|
.report-notes__item__header
|
||||||
%span.username
|
%span.username
|
||||||
= link_to @appeal.account.username, can?(:show, @appeal.account) ? admin_account_path(@appeal.account_id) : short_account_url(@appeal.account)
|
= link_to @appeal.account.username, can?(:show, @appeal.account) ? admin_account_path(@appeal.account_id) : short_account_url(@appeal.account)
|
||||||
%time.relative-formatted{ datetime: @appeal.created_at.iso8601 }
|
%time.relative-formatted{ datetime: @appeal.created_at.iso8601, title: @appeal.created_at }
|
||||||
= l @appeal.created_at.to_date
|
= l @appeal.created_at.to_date
|
||||||
|
|
||||||
.report-notes__item__content
|
.report-notes__item__content
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
= csrf_meta_tags unless skip_csrf_meta_tags?
|
= csrf_meta_tags unless skip_csrf_meta_tags?
|
||||||
%meta{ name: 'style-nonce', content: request.content_security_policy_nonce }
|
%meta{ name: 'style-nonce', content: request.content_security_policy_nonce }
|
||||||
|
|
||||||
= stylesheet_link_tag custom_css_path, skip_pipeline: true, host: root_url, media: 'all'
|
= custom_stylesheet
|
||||||
|
|
||||||
= yield :header_tags
|
= yield :header_tags
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,8 @@
|
||||||
|
|
||||||
5. <%= t('user_mailer.welcome.apps_title') %>
|
5. <%= t('user_mailer.welcome.apps_title') %>
|
||||||
<%= t('user_mailer.welcome.apps_step') %>
|
<%= t('user_mailer.welcome.apps_step') %>
|
||||||
* iOS: https://apps.apple.com/app/mastodon-for-iphone-and-ipad/id1571998974
|
* iOS: <%= app_store_url_ios %>
|
||||||
* Android: https://play.google.com/store/apps/details?id=org.joinmastodon.android
|
* Android: <%= app_store_url_android %>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
18
config/initializers/settings_digests.rb
Normal file
18
config/initializers/settings_digests.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
Rails.application.config.to_prepare do
|
||||||
|
custom_css = begin
|
||||||
|
Setting.custom_css
|
||||||
|
rescue ActiveRecord::AdapterError # Running without a database, not migrated, no connection, etc
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if custom_css.present?
|
||||||
|
Rails
|
||||||
|
.cache
|
||||||
|
.write(
|
||||||
|
:setting_digest_custom_css,
|
||||||
|
Digest::SHA256.hexdigest(custom_css)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
|
@ -24,6 +24,8 @@ cy:
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
fields:
|
||||||
|
fields_with_values_missing_labels: yn cynnwys gwerthoedd gyda labeli coll
|
||||||
username:
|
username:
|
||||||
invalid: rhaid iddo gynnwys dim ond llythrennau, rhifau a thanlinellau
|
invalid: rhaid iddo gynnwys dim ond llythrennau, rhifau a thanlinellau
|
||||||
reserved: wedi ei neilltuo
|
reserved: wedi ei neilltuo
|
||||||
|
|
|
@ -24,6 +24,8 @@ gl:
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
fields:
|
||||||
|
fields_with_values_missing_labels: contén valores aos que lle faltan etiquetas
|
||||||
username:
|
username:
|
||||||
invalid: só letras, números e trazo baixo
|
invalid: só letras, números e trazo baixo
|
||||||
reserved: está reservado
|
reserved: está reservado
|
||||||
|
|
|
@ -24,6 +24,8 @@ hu:
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
fields:
|
||||||
|
fields_with_values_missing_labels: hiányzó címkékkel rendelkező értékeket tartalmaz
|
||||||
username:
|
username:
|
||||||
invalid: csak betűket, számokat vagy alávonást tartalmazhat
|
invalid: csak betűket, számokat vagy alávonást tartalmazhat
|
||||||
reserved: foglalt
|
reserved: foglalt
|
||||||
|
|
|
@ -24,6 +24,8 @@ ia:
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
fields:
|
||||||
|
fields_with_values_missing_labels: contine valores con etiquettas perdite
|
||||||
username:
|
username:
|
||||||
invalid: debe continer solmente litteras, numeros e lineettas basse
|
invalid: debe continer solmente litteras, numeros e lineettas basse
|
||||||
reserved: es reservate
|
reserved: es reservate
|
||||||
|
|
|
@ -24,6 +24,8 @@ lv:
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
fields:
|
||||||
|
fields_with_values_missing_labels: satur vērtības ar trūkstošām iezīmēm
|
||||||
username:
|
username:
|
||||||
invalid: drīkst saturēt tikai burtus, ciparus un pasvītras
|
invalid: drīkst saturēt tikai burtus, ciparus un pasvītras
|
||||||
reserved: ir rezervēts
|
reserved: ir rezervēts
|
||||||
|
@ -39,6 +41,11 @@ lv:
|
||||||
attributes:
|
attributes:
|
||||||
data:
|
data:
|
||||||
malformed: ir nepareizi veidots
|
malformed: ir nepareizi veidots
|
||||||
|
list_account:
|
||||||
|
attributes:
|
||||||
|
account_id:
|
||||||
|
taken: jau ir sarakstā
|
||||||
|
must_be_following: jābūt kontam, kuram seko
|
||||||
status:
|
status:
|
||||||
attributes:
|
attributes:
|
||||||
reblog:
|
reblog:
|
||||||
|
|
|
@ -24,6 +24,8 @@ pt-PT:
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
fields:
|
||||||
|
fields_with_values_missing_labels: contém valores com etiquetas em falta
|
||||||
username:
|
username:
|
||||||
invalid: deve conter apenas letras, números e traços inferiores
|
invalid: deve conter apenas letras, números e traços inferiores
|
||||||
reserved: está reservado
|
reserved: está reservado
|
||||||
|
|
|
@ -24,6 +24,8 @@ sv:
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
fields:
|
||||||
|
fields_with_values_missing_labels: innehåller värden med saknade etiketter
|
||||||
username:
|
username:
|
||||||
invalid: endast bokstäver, siffror och understrykning
|
invalid: endast bokstäver, siffror och understrykning
|
||||||
reserved: är reserverat
|
reserved: är reserverat
|
||||||
|
|
|
@ -25,7 +25,7 @@ tr:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
fields:
|
fields:
|
||||||
fields_with_values_missing_labels: değerleri eksik etiketler içeriyor
|
fields_with_values_missing_labels: etiketleri eksik değerler içeriyor
|
||||||
username:
|
username:
|
||||||
invalid: sadece harfler, sayılar ve alt çizgiler
|
invalid: sadece harfler, sayılar ve alt çizgiler
|
||||||
reserved: kullanılamaz
|
reserved: kullanılamaz
|
||||||
|
|
|
@ -134,6 +134,7 @@ sk:
|
||||||
media: Mediálne prílohy
|
media: Mediálne prílohy
|
||||||
mutes: Stíšenia
|
mutes: Stíšenia
|
||||||
notifications: Upozornenia
|
notifications: Upozornenia
|
||||||
|
profile: Váš Mastodon profil
|
||||||
push: Upozornenia push
|
push: Upozornenia push
|
||||||
reports: Hlásenia
|
reports: Hlásenia
|
||||||
search: Vyhľadávanie
|
search: Vyhľadávanie
|
||||||
|
|
|
@ -214,6 +214,7 @@ fo:
|
||||||
enable_user: Ger brúkara virknan
|
enable_user: Ger brúkara virknan
|
||||||
memorialize_account: Minnst til Konto
|
memorialize_account: Minnst til Konto
|
||||||
promote_user: Vís fram Brúkara
|
promote_user: Vís fram Brúkara
|
||||||
|
publish_terms_of_service: Útgev tænastutreytir
|
||||||
reject_appeal: Avvís mótmali
|
reject_appeal: Avvís mótmali
|
||||||
reject_user: Avvís Brúkara
|
reject_user: Avvís Brúkara
|
||||||
remove_avatar_user: Sletta Avatar
|
remove_avatar_user: Sletta Avatar
|
||||||
|
@ -278,6 +279,7 @@ fo:
|
||||||
enable_user_html: "%{name} gjørdi innritan virkna fyri brúkaran %{target}"
|
enable_user_html: "%{name} gjørdi innritan virkna fyri brúkaran %{target}"
|
||||||
memorialize_account_html: "%{name} broytti kontuna hjá %{target} til eina minnissíðu"
|
memorialize_account_html: "%{name} broytti kontuna hjá %{target} til eina minnissíðu"
|
||||||
promote_user_html: "%{name} flutti brúkaran %{target} fram"
|
promote_user_html: "%{name} flutti brúkaran %{target} fram"
|
||||||
|
publish_terms_of_service_html: "%{name} útgav dagføringar til tænastutreytirnar"
|
||||||
reject_appeal_html: "%{name} avvísti umsjónaráheitan frá %{target}"
|
reject_appeal_html: "%{name} avvísti umsjónaráheitan frá %{target}"
|
||||||
reject_user_html: "%{name} avvísti skráseting hjá %{target}"
|
reject_user_html: "%{name} avvísti skráseting hjá %{target}"
|
||||||
remove_avatar_user_html: "%{name} strikaði eftirgjørda skapningin hjá %{target}"
|
remove_avatar_user_html: "%{name} strikaði eftirgjørda skapningin hjá %{target}"
|
||||||
|
@ -925,6 +927,32 @@ fo:
|
||||||
search: Leita
|
search: Leita
|
||||||
title: Frámerki
|
title: Frámerki
|
||||||
updated_msg: Frámerkjastillingar dagførdar
|
updated_msg: Frámerkjastillingar dagførdar
|
||||||
|
terms_of_service:
|
||||||
|
back: Aftur til tænastutreytir
|
||||||
|
changelog: Hvat er broytt
|
||||||
|
create: Brúka tínar egnu
|
||||||
|
current: Núverandi
|
||||||
|
draft: Kladda
|
||||||
|
generate: Brúka leist
|
||||||
|
generates:
|
||||||
|
action: Framleið
|
||||||
|
chance_to_review_html: "<strong>Framleiddu tænastutreytirnar verða ikki útgivnar av sær sjálvum.</strong> Tú fær møguleika at eftirhyggja úrslitini. Vinarliga útfyll neyðugu smálutirnar fyri at halda fram."
|
||||||
|
explanation_html: Leisturin við tænastutreytum er einans til kunningar og skal ikki fatast sum løgfrøðislig ráðgeving yvirhøvur. Vinarliga spyr tín egna løgfrøðisliga ráðgeva um tína støðu og ítøkiligu løgfrøðisligu spurningarnar hjá tær.
|
||||||
|
title: Uppseting av tænastutreytum
|
||||||
|
history: Søga
|
||||||
|
live: Beinleiðis
|
||||||
|
no_history: Enn eru ongar skrásettar broytingar í tænastutreytunum.
|
||||||
|
no_terms_of_service_html: Í løtuni hevur tú ongar tænastutreytir uppsettar. Hugsanin við tænastutreytum er at veita greidleika og at verja teg ímóti møguligum ábyrgdum í ósemjum við tínar brúkarar.
|
||||||
|
notified_on_html: Fráboðan latin brúkarum %{date}
|
||||||
|
notify_users: Gev brúkarum fráboðan
|
||||||
|
preview:
|
||||||
|
explanation_html: 'Teldubrævið verður sent til <strong>%{display_count} brúkarar</strong>, sum hava stovna kontu áðrenn %{date}. Fylgjandi tekstur kemur við í teldubrævið:'
|
||||||
|
send_preview: Send undanvísing til %{email}
|
||||||
|
title: Undanvís fráboðan um tænastutreytir
|
||||||
|
publish: Útgev
|
||||||
|
published_on_html: Útgivið %{date}
|
||||||
|
save_draft: Goym kladdu
|
||||||
|
title: Tænastutreytir
|
||||||
title: Umsiting
|
title: Umsiting
|
||||||
trends:
|
trends:
|
||||||
allow: Loyv
|
allow: Loyv
|
||||||
|
@ -1156,6 +1184,7 @@ fo:
|
||||||
set_new_password: Áset nýtt loyniorð
|
set_new_password: Áset nýtt loyniorð
|
||||||
setup:
|
setup:
|
||||||
email_below_hint_html: Kekka mappuna við ruskposti ella bið um ein annan. Tú kanst rætta teldupostadressuna, um hon er skeiv.
|
email_below_hint_html: Kekka mappuna við ruskposti ella bið um ein annan. Tú kanst rætta teldupostadressuna, um hon er skeiv.
|
||||||
|
email_settings_hint_html: Trýst á leinkið, sum vit sendu til %{email} fyri at byrja at brúka Mastodon. Vit bíða beint her.
|
||||||
link_not_received: Fekk tú einki leinki?
|
link_not_received: Fekk tú einki leinki?
|
||||||
new_confirmation_instructions_sent: Tú fer at móttaka eitt nýtt teldubræv við váttanarleinkinum um nakrar fáar minuttir!
|
new_confirmation_instructions_sent: Tú fer at móttaka eitt nýtt teldubræv við váttanarleinkinum um nakrar fáar minuttir!
|
||||||
title: Kekka innbakkan hjá tær
|
title: Kekka innbakkan hjá tær
|
||||||
|
@ -1164,6 +1193,7 @@ fo:
|
||||||
title: Rita inn á %{domain}
|
title: Rita inn á %{domain}
|
||||||
sign_up:
|
sign_up:
|
||||||
manual_review: Tilmeldingar til %{domain} fara ígjøgnum eina manuella eftirkanning av okkara kjakleiðarum. Fyri at hjálpa okkum at skunda undir skrásetingina, skriva eitt sindur um teg sjálva/n og hví tú vil hava eina kontu á %{domain}.
|
manual_review: Tilmeldingar til %{domain} fara ígjøgnum eina manuella eftirkanning av okkara kjakleiðarum. Fyri at hjálpa okkum at skunda undir skrásetingina, skriva eitt sindur um teg sjálva/n og hví tú vil hava eina kontu á %{domain}.
|
||||||
|
preamble: Við eini kontu á hesum Mastodon ambætaranum ber til hjá tær at fylgja ein og hvønn annan persón á fediversinum, óansæð hvar teirra konta er hýst.
|
||||||
title: Latum okkum fáa teg settan upp á %{domain}.
|
title: Latum okkum fáa teg settan upp á %{domain}.
|
||||||
status:
|
status:
|
||||||
account_status: Kontustøða
|
account_status: Kontustøða
|
||||||
|
@ -1175,6 +1205,7 @@ fo:
|
||||||
view_strikes: Vís eldri atsóknir móti tíni kontu
|
view_strikes: Vís eldri atsóknir móti tíni kontu
|
||||||
too_fast: Oyðublaðið innsent ov skjótt, royn aftur.
|
too_fast: Oyðublaðið innsent ov skjótt, royn aftur.
|
||||||
use_security_key: Brúka trygdarlykil
|
use_security_key: Brúka trygdarlykil
|
||||||
|
user_agreement_html: Eg havi lisið og taki undir við <a href="%{terms_of_service_path}" target="_blank">tænastutreytunum</a> og <a href="%{privacy_policy_path}" target="_blank">privatlívspolitikkinum</a>
|
||||||
author_attribution:
|
author_attribution:
|
||||||
example_title: Tekstadømi
|
example_title: Tekstadømi
|
||||||
hint_html: Skrivar tú tíðindi ella greinar til bloggin uttanfyri Mastodon? Her kanst tú stýra, hvussu tú verður tilsipað/ur, tá ið títt tilfar verður deilt á Mastodon.
|
hint_html: Skrivar tú tíðindi ella greinar til bloggin uttanfyri Mastodon? Her kanst tú stýra, hvussu tú verður tilsipað/ur, tá ið títt tilfar verður deilt á Mastodon.
|
||||||
|
@ -1836,6 +1867,8 @@ fo:
|
||||||
too_late: Tað er ov seint at kæra hesa atsókn
|
too_late: Tað er ov seint at kæra hesa atsókn
|
||||||
tags:
|
tags:
|
||||||
does_not_match_previous_name: samsvarar ikki við undanfarna navnið
|
does_not_match_previous_name: samsvarar ikki við undanfarna navnið
|
||||||
|
terms_of_service:
|
||||||
|
title: Tænastutreytir
|
||||||
themes:
|
themes:
|
||||||
contrast: Mastodon (høgur kontrastur)
|
contrast: Mastodon (høgur kontrastur)
|
||||||
default: Mastodon (myrkt)
|
default: Mastodon (myrkt)
|
||||||
|
@ -1896,6 +1929,15 @@ fo:
|
||||||
further_actions_html: Var hetta ikki tú, so mæla vit til, at tú %{action} beinan vegin og at tú ger váttan í tveimum stigum virkna fyri at konta tín kann vera trygg.
|
further_actions_html: Var hetta ikki tú, so mæla vit til, at tú %{action} beinan vegin og at tú ger váttan í tveimum stigum virkna fyri at konta tín kann vera trygg.
|
||||||
subject: Atgongd er fingin til kontu tína frá eini nýggjari IP adressu
|
subject: Atgongd er fingin til kontu tína frá eini nýggjari IP adressu
|
||||||
title: Ein nýggj innritan
|
title: Ein nýggj innritan
|
||||||
|
terms_of_service_changed:
|
||||||
|
agreement: Við framhaldandi at brúka %{domain} góðtekur tú hesar treytir. Tekur tú ikki undir við dagførdu treytunum, so kanst tú til einhvørja tíð uppsiga avtaluna við %{domain} við at strika kontu tína.
|
||||||
|
changelog: 'Í stuttum merkir henda dagføringin:'
|
||||||
|
description: 'Tú móttekur hetta teldubrævið, tí at vit gera nakrar broytingar í okkara tænastutreytum á %{domain}. Vit eggja tær til at eftirhyggja dagførdu treytirnar her:'
|
||||||
|
description_html: Tú móttekur hetta teldubrævið, tí at vit gera nakrar broytingar í okkara tænastutreytum á %{domain}. Vit eggja tær til at eftirhyggja <a href="%{path}" target="_blank">dagførdu og samlaðu treytirnar her</a>.
|
||||||
|
sign_off: "%{domain} toymið"
|
||||||
|
subject: Dagføringar til okkara tænastutreytir
|
||||||
|
subtitle: Tænastutreytirnar hjá %{domain} eru við at verða broyttar
|
||||||
|
title: Týdningarmikil dagføring
|
||||||
warning:
|
warning:
|
||||||
appeal: Innsend eina kæru
|
appeal: Innsend eina kæru
|
||||||
appeal_description: Trýrt tú, at hetta er ein feilur, so kanst tú senda eina kæru til starvsfólkini á %{instance}.
|
appeal_description: Trýrt tú, at hetta er ein feilur, so kanst tú senda eina kæru til starvsfólkini á %{instance}.
|
||||||
|
|
|
@ -1859,9 +1859,9 @@ gl:
|
||||||
'63113904': 2 anos
|
'63113904': 2 anos
|
||||||
'7889238': 3 meses
|
'7889238': 3 meses
|
||||||
min_age_label: Límite temporal
|
min_age_label: Límite temporal
|
||||||
min_favs: Manter as publicacións favorecidas polo menos
|
min_favs: Manter publicacións favorecidas polo menos
|
||||||
min_favs_hint: Non elimina ningunha das túas publicacións que recibiron alomenos esta cantidade de favorecementos. Deixa en branco para eliminar publicacións independentemente do número de favorecementos
|
min_favs_hint: Non elimina ningunha das túas publicacións que recibiron alomenos esta cantidade de favorecementos. Deixa en branco para eliminar publicacións independentemente do número de favorecementos
|
||||||
min_reblogs: Manter publicacións promovidas máis de
|
min_reblogs: Manter publicacións promovidas polo menos
|
||||||
min_reblogs_hint: Non elimina ningunha das túas publicacións se foron promovidas máis deste número de veces. Deixa en branco para eliminar publicacións independentemente do seu número de promocións
|
min_reblogs_hint: Non elimina ningunha das túas publicacións se foron promovidas máis deste número de veces. Deixa en branco para eliminar publicacións independentemente do seu número de promocións
|
||||||
stream_entries:
|
stream_entries:
|
||||||
sensitive_content: Contido sensible
|
sensitive_content: Contido sensible
|
||||||
|
|
|
@ -217,6 +217,7 @@ lv:
|
||||||
enable_user: Ieslēgt Lietotāju
|
enable_user: Ieslēgt Lietotāju
|
||||||
memorialize_account: Saglabāt Kontu Piemiņai
|
memorialize_account: Saglabāt Kontu Piemiņai
|
||||||
promote_user: Izceltt Lietotāju
|
promote_user: Izceltt Lietotāju
|
||||||
|
publish_terms_of_service: Publicēt pakalpojuma izmantošanas noteikumus
|
||||||
reject_appeal: Noraidīt Apelāciju
|
reject_appeal: Noraidīt Apelāciju
|
||||||
reject_user: Noraidīt lietotāju
|
reject_user: Noraidīt lietotāju
|
||||||
remove_avatar_user: Noņemt profila attēlu
|
remove_avatar_user: Noņemt profila attēlu
|
||||||
|
@ -273,6 +274,7 @@ lv:
|
||||||
enable_user_html: "%{name} iespējoja pieteikšanos lietotājam %{target}"
|
enable_user_html: "%{name} iespējoja pieteikšanos lietotājam %{target}"
|
||||||
memorialize_account_html: "%{name} pārvērta %{target} kontu par atmiņas lapu"
|
memorialize_account_html: "%{name} pārvērta %{target} kontu par atmiņas lapu"
|
||||||
promote_user_html: "%{name} paaugstināja lietotāju %{target}"
|
promote_user_html: "%{name} paaugstināja lietotāju %{target}"
|
||||||
|
publish_terms_of_service_html: "%{name} padarīja pieejamus pakalpojuma izmantošanas noteikumu atjauninājumus"
|
||||||
reject_appeal_html: "%{name} noraidīja satura pārraudzības lēmuma iebildumu no %{target}"
|
reject_appeal_html: "%{name} noraidīja satura pārraudzības lēmuma iebildumu no %{target}"
|
||||||
reject_user_html: "%{name} noraidīja reģistrēšanos no %{target}"
|
reject_user_html: "%{name} noraidīja reģistrēšanos no %{target}"
|
||||||
remove_avatar_user_html: "%{name} noņēma %{target} profila attēlu"
|
remove_avatar_user_html: "%{name} noņēma %{target} profila attēlu"
|
||||||
|
@ -641,7 +643,7 @@ lv:
|
||||||
create_and_resolve: Atrisināt ar piezīmi
|
create_and_resolve: Atrisināt ar piezīmi
|
||||||
create_and_unresolve: Atvērt atkārtoti ar piezīmi
|
create_and_unresolve: Atvērt atkārtoti ar piezīmi
|
||||||
delete: Dzēst
|
delete: Dzēst
|
||||||
placeholder: Apraksti veiktās darbības vai citus saistītus atjauninājumus...
|
placeholder: Jāapraksta veiktās darbības vai jebkuri citi saistītie atjauninājumi...
|
||||||
title: Piezīmes
|
title: Piezīmes
|
||||||
notes_description_html: Skati un atstāj piezīmes citiem moderatoriem un sev nākotnei
|
notes_description_html: Skati un atstāj piezīmes citiem moderatoriem un sev nākotnei
|
||||||
processed_msg: 'Pārskats #%{id} veiksmīgi apstrādāts'
|
processed_msg: 'Pārskats #%{id} veiksmīgi apstrādāts'
|
||||||
|
@ -746,13 +748,13 @@ lv:
|
||||||
rules:
|
rules:
|
||||||
add_new: Pievienot noteikumu
|
add_new: Pievienot noteikumu
|
||||||
delete: Dzēst
|
delete: Dzēst
|
||||||
description_html: Lai gan lielākā daļa apgalvo, ka ir izlasījuši pakalpojumu sniegšanas noteikumus un piekrīt tiem, parasti cilvēki to izlasa tikai pēc problēmas rašanās. <strong>Padariet vienkāršāku sava servera noteikumu uztveršanu, veidojot tos vienkāršā sarakstā pa punktiem.</strong> Centieties, lai atsevišķi noteikumi būtu īsi un vienkārši, taču arī nesadaliet tos daudzos atsevišķos vienumos.
|
description_html: Kaut arī lielākā daļa apgalvo, ka ir lasījuši un piekrīt pakalpojuma izmantošanas noteikumiem, parasti cilvēki tos neizlasa, līdz rodas sarežģījumi. <strong>Padari vienkāršāku sava servera noteikumu pārskatīšanu, sniedzot tos vienkāršā uzsvēruma punktu sarakstā!</strong> Jāmēģina atsevišķus noteikumus veidot īsus un vienkāršus, bet jāmēģina arī tos nesadalīt daudzos atsevišķos vienumos.
|
||||||
edit: Labot nosacījumu
|
edit: Labot nosacījumu
|
||||||
empty: Servera noteikumi vēl nav definēti.
|
empty: Vēl nav pievienots neviens servera noteikums.
|
||||||
title: Servera noteikumi
|
title: Servera noteikumi
|
||||||
settings:
|
settings:
|
||||||
about:
|
about:
|
||||||
manage_rules: Pārvaldīt servera nosacījumus
|
manage_rules: Pārvaldīt servera noteikumus
|
||||||
preamble: Sniedz padziļinātu informāciju par to, kā serveris tiek darbināts, moderēts un finansēts.
|
preamble: Sniedz padziļinātu informāciju par to, kā serveris tiek darbināts, moderēts un finansēts.
|
||||||
rules_hint: Noteikumiem, kas taviem lietotājiem ir jāievēro, ir īpaša sadaļa.
|
rules_hint: Noteikumiem, kas taviem lietotājiem ir jāievēro, ir īpaša sadaļa.
|
||||||
title: Par
|
title: Par
|
||||||
|
@ -821,6 +823,7 @@ lv:
|
||||||
back_to_account: Atpakaļ uz konta lapu
|
back_to_account: Atpakaļ uz konta lapu
|
||||||
back_to_report: Atpakaļ uz paziņojumu lapu
|
back_to_report: Atpakaļ uz paziņojumu lapu
|
||||||
batch:
|
batch:
|
||||||
|
add_to_report: 'Pievienot atskaitei #%{id}'
|
||||||
remove_from_report: Noņemt no ziņojuma
|
remove_from_report: Noņemt no ziņojuma
|
||||||
report: Ziņojums
|
report: Ziņojums
|
||||||
contents: Saturs
|
contents: Saturs
|
||||||
|
@ -832,13 +835,17 @@ lv:
|
||||||
media:
|
media:
|
||||||
title: Multivide
|
title: Multivide
|
||||||
metadata: Metadati
|
metadata: Metadati
|
||||||
|
no_history: Šis ieraksts nav bijis labots
|
||||||
no_status_selected: Neviena ziņa netika mainīta, jo neviena netika atlasīta
|
no_status_selected: Neviena ziņa netika mainīta, jo neviena netika atlasīta
|
||||||
open: Atvērt ziņu
|
open: Atvērt ziņu
|
||||||
original_status: Oriģinālā ziņa
|
original_status: Oriģinālā ziņa
|
||||||
reblogs: Reblogi
|
reblogs: Reblogi
|
||||||
|
replied_to_html: Atbildēja %{acct_link}
|
||||||
status_changed: Ziņa mainīta
|
status_changed: Ziņa mainīta
|
||||||
status_title: Publicēja @%{name}
|
status_title: Publicēja @%{name}
|
||||||
|
title: Konta ieraksti - @%{name}
|
||||||
trending: Aktuāli
|
trending: Aktuāli
|
||||||
|
view_publicly: Skatīt publiski
|
||||||
visibility: Redzamība
|
visibility: Redzamība
|
||||||
with_media: Ar multividi
|
with_media: Ar multividi
|
||||||
strikes:
|
strikes:
|
||||||
|
@ -876,8 +883,8 @@ lv:
|
||||||
message_html: 'Nesaderīga Elasticsearch versija: %{value}'
|
message_html: 'Nesaderīga Elasticsearch versija: %{value}'
|
||||||
version_comparison: Darbojas Elasticsearch %{running_version}, tomēr ir nepieciešama %{required_version}
|
version_comparison: Darbojas Elasticsearch %{running_version}, tomēr ir nepieciešama %{required_version}
|
||||||
rules_check:
|
rules_check:
|
||||||
action: Pārvaldīt servera nosacījumus
|
action: Pārvaldīt servera noteikumus
|
||||||
message_html: Tu neesi definējis nevienu servera nosacījumu.
|
message_html: Nav pievienots neviens servera noteikums.
|
||||||
sidekiq_process_check:
|
sidekiq_process_check:
|
||||||
message_html: Rindā(s) %{value} nedarbojas neviens Sidekiq process. Lūdzu, pārskati savu Sidekiq konfigurāciju
|
message_html: Rindā(s) %{value} nedarbojas neviens Sidekiq process. Lūdzu, pārskati savu Sidekiq konfigurāciju
|
||||||
software_version_check:
|
software_version_check:
|
||||||
|
@ -907,16 +914,42 @@ lv:
|
||||||
name: Nosaukums
|
name: Nosaukums
|
||||||
newest: Jaunākie
|
newest: Jaunākie
|
||||||
oldest: Vecākie
|
oldest: Vecākie
|
||||||
|
open: Apskatīt publiski
|
||||||
reset: Atiestatīt
|
reset: Atiestatīt
|
||||||
review: Pārskatīt stāvokli
|
review: Pārskatīt stāvokli
|
||||||
search: Meklēt
|
search: Meklēt
|
||||||
title: Tēmturi
|
title: Tēmturi
|
||||||
updated_msg: Tēmtura iestatījumi ir veiksmīgi atjaunināti
|
updated_msg: Tēmtura iestatījumi ir veiksmīgi atjaunināti
|
||||||
terms_of_service:
|
terms_of_service:
|
||||||
|
back: Atpakaļ uz pakalpojuma izmantošanas noteikumiem
|
||||||
changelog: Kas ir mainījies
|
changelog: Kas ir mainījies
|
||||||
|
create: Izmantot savus
|
||||||
|
current: Pašreizējie
|
||||||
|
draft: Melnraksts
|
||||||
|
generate: Izmantot sagatavi
|
||||||
|
generates:
|
||||||
|
action: Izveidot
|
||||||
|
chance_to_review_html: "<strong>Izveidotie pakalpojuma izmantošanas noteikumi netiks automātiski publicēti.</strong> Būs iespēja izskatīt iznākumu. Lūgums norādīt nepieciešamo informāciju, lai turpinātu."
|
||||||
|
explanation_html: Pakalpojuma izmantošanas noteikumu sagatave tiek piedāvāta tikai izzināšanas nolūkam, un to nevajadzētu izmantot kā juridisku padomu jebkurā jautājumā. Lūgums sazināties ar savu juridisko padomdevēju par saviem apstākļiem un noteiktiem juridiskiem jautājumiem.
|
||||||
|
title: Pakalpojuma izmantošānas noteikumu uzstādīšana
|
||||||
history: Vēsture
|
history: Vēsture
|
||||||
|
live: Darbībā
|
||||||
|
no_history: Nav ierakstu par pakalpojuma izmantošanas noteikumu izmaiņām.
|
||||||
|
no_terms_of_service_html: Pašlaik nav uzstādīti pakalpojuma izmantošanas noteikumi. Tie ir paredzēti, lai sniegtu skaidrību un aizsargātu no iespējamas atbildības strīdos ar lietotājiem.
|
||||||
|
notified_on_html: Lietotājiem paziņots %{date}
|
||||||
|
notify_users: Paziņot lietotājiem
|
||||||
|
preview:
|
||||||
|
explanation_html: 'E-pasta ziņojums tiks nosūtīts <strong>%{display_count} lietotājiem</strong>, kuri ir reģistrējušies pirms %{date}. Šis teksts tiks iekļauts e-pasta ziņojumā:'
|
||||||
|
send_preview: Nosūtīt priekšskatījumu uz %{email}
|
||||||
|
send_to_all:
|
||||||
|
one: Nosūtīt %{display_count} e-pasta ziņojumu
|
||||||
|
other: Nosūtīt %{display_count} e-pasta ziņojumus
|
||||||
|
zero: Nosūtīt %{display_count} e-pasta ziņojumu
|
||||||
|
title: Priekškatīt pakalpojuma izmantošanas noteikumu paziņojumu
|
||||||
publish: Publicēt
|
publish: Publicēt
|
||||||
published_on_html: Publicēts %{date}
|
published_on_html: Publicēti %{date}
|
||||||
|
save_draft: Saglabāt melnrakstu
|
||||||
|
title: Pakalpojuma izmantošanas noteikumi
|
||||||
title: Pārvaldība
|
title: Pārvaldība
|
||||||
trends:
|
trends:
|
||||||
allow: Atļaut
|
allow: Atļaut
|
||||||
|
@ -1157,6 +1190,7 @@ lv:
|
||||||
view_strikes: Skati iepriekšējos brīdinājumus par savu kontu
|
view_strikes: Skati iepriekšējos brīdinājumus par savu kontu
|
||||||
too_fast: Veidlapa ir iesniegta pārāk ātri, mēģini vēlreiz.
|
too_fast: Veidlapa ir iesniegta pārāk ātri, mēģini vēlreiz.
|
||||||
use_security_key: Lietot drošības atslēgu
|
use_security_key: Lietot drošības atslēgu
|
||||||
|
user_agreement_html: Es esmu izlasījis un piekrītu <a href="%{terms_of_service_path}" target="_blank">pakalpojuma izmantošanas noteikumiem</a> un <a href="%{privacy_policy_path}" target="_blank">privātuma nosacījumiem</a>
|
||||||
author_attribution:
|
author_attribution:
|
||||||
example_title: Parauga teksts
|
example_title: Parauga teksts
|
||||||
more_from_html: Vairāk no %{name}
|
more_from_html: Vairāk no %{name}
|
||||||
|
@ -1777,6 +1811,8 @@ lv:
|
||||||
too_late: Brīdinājuma apstrīdēšanas laiks ir nokavēts
|
too_late: Brīdinājuma apstrīdēšanas laiks ir nokavēts
|
||||||
tags:
|
tags:
|
||||||
does_not_match_previous_name: nesakrīt ar iepriekšējo nosaukumu
|
does_not_match_previous_name: nesakrīt ar iepriekšējo nosaukumu
|
||||||
|
terms_of_service:
|
||||||
|
title: Pakalpojuma izmantošanas noteikumi
|
||||||
themes:
|
themes:
|
||||||
contrast: Mastodon (Augsts kontrasts)
|
contrast: Mastodon (Augsts kontrasts)
|
||||||
default: Mastodon (Tumšs)
|
default: Mastodon (Tumšs)
|
||||||
|
@ -1826,6 +1862,15 @@ lv:
|
||||||
further_actions_html: Ja tas nebiji tu, iesakām nekavējoties %{action} un iespējot divu faktoru autentifikāciju, lai tavs konts būtu drošībā.
|
further_actions_html: Ja tas nebiji tu, iesakām nekavējoties %{action} un iespējot divu faktoru autentifikāciju, lai tavs konts būtu drošībā.
|
||||||
subject: Tavam kontam ir piekļūts no jaunas IP adreses
|
subject: Tavam kontam ir piekļūts no jaunas IP adreses
|
||||||
title: Jauna pieteikšanās
|
title: Jauna pieteikšanās
|
||||||
|
terms_of_service_changed:
|
||||||
|
agreement: Ar %{domain} izmantošanas tuprināšanu tiek piekrists šiem noteikumiem. Ja ir iebildumi pret atjauninātajiem noteikumiem, savu piekrišanu var atcelt jebkurā laikā ar sava konta izdzēšanu.
|
||||||
|
changelog: 'Šeit īsumā ir aprakstīts, ko šis atjauninājums nozīmē:'
|
||||||
|
description: 'Šis e-pasta ziņojums tika saņemts, jo mēs veicam dažas izmaiņas savos pakalpojuma izmantošanas noteikumos %{domain}. Mēs aicinām pārskatīt pilnus atjauninātos noteikumus šeit:'
|
||||||
|
description_html: Šis e-pasta ziņojums tika saņemts, jo mēs veicam dažas izmaiņas savos pakalpojuma izmantošanas noteikumos %{domain}. Mēs aicinām pārskatīt <a href="%{path}" target="_blank">pilnus atjauninātos noteikumus šeit</a>.
|
||||||
|
sign_off: "%{domain} komanda"
|
||||||
|
subject: Mūsu pakalpojuma izmantošanas noteikumu atjauninājumi
|
||||||
|
subtitle: Mainās %{domain} pakalpojuma izmantošanas noteikumi
|
||||||
|
title: Svarīgs atjauninājums
|
||||||
warning:
|
warning:
|
||||||
appeal: Iesniegt apelāciju
|
appeal: Iesniegt apelāciju
|
||||||
appeal_description: Ja uzskatāt, ka tā ir kļūda, varat iesniegt apelāciju %{instance} darbiniekiem.
|
appeal_description: Ja uzskatāt, ka tā ir kļūda, varat iesniegt apelāciju %{instance} darbiniekiem.
|
||||||
|
|
|
@ -10,7 +10,7 @@ pt-PT:
|
||||||
followers:
|
followers:
|
||||||
one: Seguidor
|
one: Seguidor
|
||||||
other: Seguidores
|
other: Seguidores
|
||||||
following: A seguir
|
following: Seguindo
|
||||||
instance_actor_flash: Esta conta é um ator virtual utilizado para representar o servidor em si e não um utilizador individual. É utilizada para efeitos de federação e não deve ser suspensa.
|
instance_actor_flash: Esta conta é um ator virtual utilizado para representar o servidor em si e não um utilizador individual. É utilizada para efeitos de federação e não deve ser suspensa.
|
||||||
last_active: última atividade
|
last_active: última atividade
|
||||||
link_verified_on: A posse desta hiperligação foi verificada em %{date}
|
link_verified_on: A posse desta hiperligação foi verificada em %{date}
|
||||||
|
|
|
@ -130,6 +130,17 @@ fo:
|
||||||
show_application: Óansæð, so er altíð møguligt hjá tær at síggja, hvør app postaði tín post.
|
show_application: Óansæð, so er altíð møguligt hjá tær at síggja, hvør app postaði tín post.
|
||||||
tag:
|
tag:
|
||||||
name: Tú kanst einans broyta millum stórar og smáar stavir, til dømis fyri at gera tað meira lesiligt
|
name: Tú kanst einans broyta millum stórar og smáar stavir, til dømis fyri at gera tað meira lesiligt
|
||||||
|
terms_of_service:
|
||||||
|
changelog: Kunnu vera uppbygdar við Markdown syntaksi.
|
||||||
|
text: Kunnu vera uppbygdar við Markdown syntaksi.
|
||||||
|
terms_of_service_generator:
|
||||||
|
admin_email: Løgfrøðisligar fráboðanir fata um rættarligar mótfráboðanir, úrskurðir, áheitanir um at taka niður og løgfrøðisligar áheitanir.
|
||||||
|
arbitration_address: Kann vera tann sami sum fysiski bústaðurin omanfyri ella "N/A", um teldupostur verður brúktur
|
||||||
|
arbitration_website: Kann vera ein vevformularur ella "N/A", um teldupostur verður brúktur
|
||||||
|
dmca_address: Fyristøðufólk og -feløg í USA brúka bústaðin, ið er skrásettur í DMCA Designated Agent Directory. Ein postsmoguskráseting er tøk, um biðið verður um hana beinleiðis. Brúka DMCA Designated Agent Post Office Box Waiver Request fyri at senda teldubræv til Copyright Office og greið frá, at tú er ein kjakleiðari, sum virkar heimanifrá, og at tú er bangin fyri hevnd ella afturløning fyri tí, tú ger, og at tú hevur tørv á at brúka eina postsmogu fyri at fjala heimabústaðin fyri almenninginum.
|
||||||
|
dmca_email: Kann vera sami teldupoststaður, sum er brúktur til "Teldupoststaður fyri løgfrøðisligar fráboðanir" omanfyri
|
||||||
|
domain: Makaleys eyðmerking av nettænastuni, sum tú veitir.
|
||||||
|
jurisdiction: Lista landið, har sum tann, ið rindar rokningarnar, livir. Er tað eitt felag ella ein onnur eind, lista landið, har tað er skrásett, umframt býin, økið, umveldið ella statin, alt eftir hvat er hóskandi.
|
||||||
user:
|
user:
|
||||||
chosen_languages: Tá hetta er valt, verða einans postar í valdum málum vístir á almennum tíðarlinjum
|
chosen_languages: Tá hetta er valt, verða einans postar í valdum málum vístir á almennum tíðarlinjum
|
||||||
role: Leikluturin stýrir hvørji rættindi, brúkarin hevur.
|
role: Leikluturin stýrir hvørji rættindi, brúkarin hevur.
|
||||||
|
@ -319,6 +330,17 @@ fo:
|
||||||
name: Tvíkrossur
|
name: Tvíkrossur
|
||||||
trendable: Loyv hesum frámerki at síggjast undir rákum
|
trendable: Loyv hesum frámerki at síggjast undir rákum
|
||||||
usable: Loyv postum at brúka hetta frámerki lokalt
|
usable: Loyv postum at brúka hetta frámerki lokalt
|
||||||
|
terms_of_service:
|
||||||
|
changelog: Hvat er broytt?
|
||||||
|
text: Tænastutreytir
|
||||||
|
terms_of_service_generator:
|
||||||
|
admin_email: Teldupoststaður fyri løgfrøðisligar fráboðanir
|
||||||
|
arbitration_address: Fysisk adressa fyri gerðarrættarfráboðanir
|
||||||
|
arbitration_website: Heimasíða har gerðarrættarfráboðanir kunnu innlatast
|
||||||
|
dmca_address: Fysiskur bústaður fyri DMCA/copyright fráboðanir
|
||||||
|
dmca_email: Teldubústaður fyri DMCA/copyright fráboðanir
|
||||||
|
domain: Navnaøki
|
||||||
|
jurisdiction: Løgdømi
|
||||||
user:
|
user:
|
||||||
role: Leiklutur
|
role: Leiklutur
|
||||||
time_zone: Tíðarsona
|
time_zone: Tíðarsona
|
||||||
|
|
|
@ -174,7 +174,7 @@ fr:
|
||||||
admin_account_action:
|
admin_account_action:
|
||||||
include_statuses: Inclure les messages signalés dans le courriel
|
include_statuses: Inclure les messages signalés dans le courriel
|
||||||
send_email_notification: Notifier l’utilisateur par courriel
|
send_email_notification: Notifier l’utilisateur par courriel
|
||||||
text: Attention personnalisée
|
text: Avertissement personnalisé
|
||||||
type: Action
|
type: Action
|
||||||
types:
|
types:
|
||||||
disable: Désactiver
|
disable: Désactiver
|
||||||
|
|
|
@ -53,7 +53,7 @@ lv:
|
||||||
locale: Lietotāja saskarnes, e-pasta ziņojumu un push paziņojumu valoda
|
locale: Lietotāja saskarnes, e-pasta ziņojumu un push paziņojumu valoda
|
||||||
password: Izmanto vismaz 8 rakstzīmes
|
password: Izmanto vismaz 8 rakstzīmes
|
||||||
phrase: Tiks saskaņots neatkarīgi no ziņas teksta reģistra vai satura brīdinājuma
|
phrase: Tiks saskaņots neatkarīgi no ziņas teksta reģistra vai satura brīdinājuma
|
||||||
scopes: Kuriem API lietojumprogrammai būs atļauta piekļuve. Ja izvēlies augstākā līmeņa tvērumu, tev nav jāatlasa atsevišķi vienumi.
|
scopes: Kuriem API lietotnei būs ļauts piekļūt. Ja atlasa augstākā līmeņa tvērumu, nav nepieciešamas atlasīt atsevišķus.
|
||||||
setting_aggregate_reblogs: Nerādīt jaunus izcēlumus ziņām, kas nesen tika palielinātas (ietekmē tikai nesen saņemtos palielinājumus)
|
setting_aggregate_reblogs: Nerādīt jaunus izcēlumus ziņām, kas nesen tika palielinātas (ietekmē tikai nesen saņemtos palielinājumus)
|
||||||
setting_always_send_emails: Parasti e-pasta paziņojumi netiek sūtīti, kad aktīvi izmantojat Mastodon
|
setting_always_send_emails: Parasti e-pasta paziņojumi netiek sūtīti, kad aktīvi izmantojat Mastodon
|
||||||
setting_default_sensitive: Sensitīva multivide pēc noklusējuma ir paslēpti, un tos var atklāt, noklikšķinot
|
setting_default_sensitive: Sensitīva multivide pēc noklusējuma ir paslēpti, un tos var atklāt, noklikšķinot
|
||||||
|
@ -119,8 +119,8 @@ lv:
|
||||||
sign_up_requires_approval: Jaunām reģistrācijām būs nepieciešams tavs apstiprinājums
|
sign_up_requires_approval: Jaunām reģistrācijām būs nepieciešams tavs apstiprinājums
|
||||||
severity: Izvēlies, kas notiks ar pieprasījumiem no šīs IP adreses
|
severity: Izvēlies, kas notiks ar pieprasījumiem no šīs IP adreses
|
||||||
rule:
|
rule:
|
||||||
hint: Izvēles. Sniedz vairāk informācijas par nosacījumu
|
hint: Izvēles. Sniedz vairāk informācijas par noteikumu
|
||||||
text: Apraksti nosacījumus vai prasības šī servera lietotājiem. Centies, lai tas būtu īss un vienkāršs
|
text: Jāapraksta nosacījums vai prasība šī servera lietotājiem. Jāmēģina to veidot īsu un vienkāršu
|
||||||
sessions:
|
sessions:
|
||||||
otp: 'Ievadi divfaktoru kodu, ko ģenerējusi tava tālruņa lietotne, vai izmanto kādu no atkopšanas kodiem:'
|
otp: 'Ievadi divfaktoru kodu, ko ģenerējusi tava tālruņa lietotne, vai izmanto kādu no atkopšanas kodiem:'
|
||||||
webauthn: Ja tā ir USB atslēga, noteikti ievieto to un, ja nepieciešams, pieskaries tai.
|
webauthn: Ja tā ir USB atslēga, noteikti ievieto to un, ja nepieciešams, pieskaries tai.
|
||||||
|
@ -317,6 +317,11 @@ lv:
|
||||||
name: Tēmturis
|
name: Tēmturis
|
||||||
trendable: Atļaut šim tēmturim parādīties zem tendencēm
|
trendable: Atļaut šim tēmturim parādīties zem tendencēm
|
||||||
usable: Ļaut ierakstos vietēji izmantot šo tēmturi
|
usable: Ļaut ierakstos vietēji izmantot šo tēmturi
|
||||||
|
terms_of_service:
|
||||||
|
changelog: Kas ir mainījies?
|
||||||
|
text: Pakalpojuma izmantošanas nosacījumi
|
||||||
|
terms_of_service_generator:
|
||||||
|
domain: Domēna vārds
|
||||||
user:
|
user:
|
||||||
role: Loma
|
role: Loma
|
||||||
time_zone: Laika josla
|
time_zone: Laika josla
|
||||||
|
|
|
@ -161,7 +161,7 @@ pt-PT:
|
||||||
fields:
|
fields:
|
||||||
name: Rótulo
|
name: Rótulo
|
||||||
value: Conteúdo
|
value: Conteúdo
|
||||||
indexable: Incluir mensagens públicas nos resultados da pesquisa
|
indexable: Incluir mensagens públicas nos resultados de pesquisas
|
||||||
show_collections: Mostrar quem sigo e os meus seguidores no perfil
|
show_collections: Mostrar quem sigo e os meus seguidores no perfil
|
||||||
unlocked: Aceitar automaticamente novos seguidores
|
unlocked: Aceitar automaticamente novos seguidores
|
||||||
account_alias:
|
account_alias:
|
||||||
|
@ -205,7 +205,7 @@ pt-PT:
|
||||||
email: Endereço de correio electrónico
|
email: Endereço de correio electrónico
|
||||||
expires_in: Expira em
|
expires_in: Expira em
|
||||||
fields: Metadados de perfil
|
fields: Metadados de perfil
|
||||||
header: Cabeçalho
|
header: Imagem de cabeçalho
|
||||||
honeypot: "%{label} (não preencher)"
|
honeypot: "%{label} (não preencher)"
|
||||||
inbox_url: URL da caixa de entrada do repetidor
|
inbox_url: URL da caixa de entrada do repetidor
|
||||||
irreversible: Expandir em vez de esconder
|
irreversible: Expandir em vez de esconder
|
||||||
|
|
|
@ -130,6 +130,14 @@ sv:
|
||||||
show_application: Du kommer alltid att kunna se vilken app som publicerat ditt inlägg oavsett.
|
show_application: Du kommer alltid att kunna se vilken app som publicerat ditt inlägg oavsett.
|
||||||
tag:
|
tag:
|
||||||
name: Du kan bara ändra skriftläget av bokstäverna, till exempel, för att göra det mer läsbart
|
name: Du kan bara ändra skriftläget av bokstäverna, till exempel, för att göra det mer läsbart
|
||||||
|
terms_of_service:
|
||||||
|
changelog: Kan struktureras med Markdown syntax.
|
||||||
|
text: Kan struktureras med Markdown syntax.
|
||||||
|
terms_of_service_generator:
|
||||||
|
arbitration_address: Kan vara samma som fysisk adress ovan, eller “N/A” om du använder e-post
|
||||||
|
arbitration_website: Kan vara ett webbformulär, eller ”N/A” om du använder e-post
|
||||||
|
dmca_email: Kan vara samma e-postadress som används för “E-postadress för juridiska meddelanden” ovan
|
||||||
|
jurisdiction: Lista det land där vem som än betalar räkningarna bor. Om det är ett företag eller annan enhet, lista landet där det är inkorporerat, och staden, regionen, territoriet eller staten på lämpligt sätt.
|
||||||
user:
|
user:
|
||||||
chosen_languages: Vid aktivering visas bara inlägg på dina valda språk i offentliga tidslinjer
|
chosen_languages: Vid aktivering visas bara inlägg på dina valda språk i offentliga tidslinjer
|
||||||
role: Rollen styr vilka behörigheter användaren har.
|
role: Rollen styr vilka behörigheter användaren har.
|
||||||
|
@ -151,7 +159,7 @@ sv:
|
||||||
name: Etikett
|
name: Etikett
|
||||||
value: Innehåll
|
value: Innehåll
|
||||||
indexable: Inkludera offentliga inlägg i sökresultaten
|
indexable: Inkludera offentliga inlägg i sökresultaten
|
||||||
show_collections: Göm följare och följeslagare på profilen
|
show_collections: Visa följare och följeslagare på profilen
|
||||||
unlocked: Godkänn nya följare automatiskt
|
unlocked: Godkänn nya följare automatiskt
|
||||||
account_alias:
|
account_alias:
|
||||||
acct: Namnet på det gamla kontot
|
acct: Namnet på det gamla kontot
|
||||||
|
@ -224,6 +232,7 @@ sv:
|
||||||
setting_hide_network: Göm ditt nätverk
|
setting_hide_network: Göm ditt nätverk
|
||||||
setting_reduce_motion: Minska rörelser i animationer
|
setting_reduce_motion: Minska rörelser i animationer
|
||||||
setting_system_font_ui: Använd systemets standardfont
|
setting_system_font_ui: Använd systemets standardfont
|
||||||
|
setting_system_scrollbars_ui: Använd systemets standardrullningsfält
|
||||||
setting_theme: Sidans tema
|
setting_theme: Sidans tema
|
||||||
setting_trends: Visa dagens trender
|
setting_trends: Visa dagens trender
|
||||||
setting_unfollow_modal: Visa bekräftelse innan du slutar följa någon
|
setting_unfollow_modal: Visa bekräftelse innan du slutar följa någon
|
||||||
|
@ -318,6 +327,14 @@ sv:
|
||||||
name: Hashtagg
|
name: Hashtagg
|
||||||
trendable: Tillåt denna hashtagg att visas under trender
|
trendable: Tillåt denna hashtagg att visas under trender
|
||||||
usable: Tillåt inlägg att använda denna fyrkantstagg
|
usable: Tillåt inlägg att använda denna fyrkantstagg
|
||||||
|
terms_of_service:
|
||||||
|
changelog: Vad har ändrats?
|
||||||
|
text: Användarvillkor
|
||||||
|
terms_of_service_generator:
|
||||||
|
admin_email: E-postadress för juridiska meddelanden
|
||||||
|
dmca_address: Fysisk adress för meddelanden om DMCA/upphovsrätt
|
||||||
|
dmca_email: Fysisk adress för meddelanden om DMCA/upphovsrätt
|
||||||
|
domain: Domän
|
||||||
user:
|
user:
|
||||||
role: Roll
|
role: Roll
|
||||||
time_zone: Tidszon
|
time_zone: Tidszon
|
||||||
|
|
|
@ -2,3 +2,6 @@
|
||||||
shared:
|
shared:
|
||||||
self_destruct_value: <%= ENV.fetch('SELF_DESTRUCT', nil) %>
|
self_destruct_value: <%= ENV.fetch('SELF_DESTRUCT', nil) %>
|
||||||
software_update_url: <%= ENV.fetch('UPDATE_CHECK_URL', 'https://api.joinmastodon.org/update-check') %>
|
software_update_url: <%= ENV.fetch('UPDATE_CHECK_URL', 'https://api.joinmastodon.org/update-check') %>
|
||||||
|
version:
|
||||||
|
metadata: <%= ['glitch', ENV.fetch('MASTODON_VERSION_METADATA', nil)].compact_blank.join('.') %>
|
||||||
|
prerelease: <%= ENV.fetch('MASTODON_VERSION_PRERELEASE', nil) %>
|
||||||
|
|
|
@ -55,7 +55,8 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
get 'manifest', to: 'manifests#show', defaults: { format: 'json' }
|
get 'manifest', to: 'manifests#show', defaults: { format: 'json' }
|
||||||
get 'intent', to: 'intents#show'
|
get 'intent', to: 'intents#show'
|
||||||
get 'custom.css', to: 'custom_css#show', as: :custom_css
|
get 'custom.css', to: 'custom_css#show'
|
||||||
|
resources :custom_css, only: :show, path: :css
|
||||||
|
|
||||||
get 'remote_interaction_helper', to: 'remote_interaction_helper#index'
|
get 'remote_interaction_helper', to: 'remote_interaction_helper#index'
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,8 @@ services:
|
||||||
- redis
|
- redis
|
||||||
|
|
||||||
sidekiq:
|
sidekiq:
|
||||||
build: .
|
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
||||||
|
# build: .
|
||||||
image: ghcr.io/mastodon/mastodon:v4.3.2
|
image: ghcr.io/mastodon/mastodon:v4.3.2
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
|
|
75
docs/DEVELOPMENT.md
Normal file
75
docs/DEVELOPMENT.md
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# Development
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Before starting local development, read the [CONTRIBUTING] guide to understand
|
||||||
|
what changes are desirable and what general processes to use.
|
||||||
|
|
||||||
|
## Environments
|
||||||
|
|
||||||
|
### Vagrant
|
||||||
|
|
||||||
|
A **Vagrant** configuration is included for development purposes. To use it,
|
||||||
|
complete the following steps:
|
||||||
|
|
||||||
|
- Install Vagrant and Virtualbox
|
||||||
|
- Install the `vagrant-hostsupdater` plugin:
|
||||||
|
`vagrant plugin install vagrant-hostsupdater`
|
||||||
|
- Run `vagrant up`
|
||||||
|
- Run `vagrant ssh -c "cd /vagrant && bin/dev"`
|
||||||
|
- Open `http://mastodon.local` in your browser
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
To set up **macOS** for native development, complete the following steps:
|
||||||
|
|
||||||
|
- Install [Homebrew] and run:
|
||||||
|
`brew install postgresql@14 redis imagemagick libidn nvm`
|
||||||
|
to install the required project dependencies
|
||||||
|
- Use a Ruby version manager to activate the ruby in `.ruby-version` and run
|
||||||
|
`nvm use` to activate the node version from `.nvmrc`
|
||||||
|
- Run the `bin/setup` script, which will install the required ruby gems and node
|
||||||
|
packages and prepare the database for local development
|
||||||
|
- Finally, run the `bin/dev` script which will launch services via `overmind`
|
||||||
|
(if installed) or `foreman`
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
For production hosting and deployment with **Docker**, use the `Dockerfile` and
|
||||||
|
`docker-compose.yml` in the project root directory.
|
||||||
|
|
||||||
|
For local development, install and launch [Docker], and run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker compose -f .devcontainer/compose.yaml up -d
|
||||||
|
docker compose -f .devcontainer/compose.yaml exec app bin/setup
|
||||||
|
docker compose -f .devcontainer/compose.yaml exec app bin/dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dev Containers
|
||||||
|
|
||||||
|
Within IDEs that support the [Development Containers] specification, start the
|
||||||
|
"Mastodon on local machine" container from the editor. The necessary `docker
|
||||||
|
compose` commands to build and setup the container should run automatically. For
|
||||||
|
**Visual Studio Code** this requires installing the [Dev Container extension].
|
||||||
|
|
||||||
|
### GitHub Codespaces
|
||||||
|
|
||||||
|
[GitHub Codespaces] provides a web-based version of VS Code and a cloud hosted
|
||||||
|
development environment configured with the software needed for this project.
|
||||||
|
|
||||||
|
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)][codespace]
|
||||||
|
|
||||||
|
- Click the button to create a new codespace, and confirm the options
|
||||||
|
- Wait for the environment to build (takes a few minutes)
|
||||||
|
- When the editor is ready, run `bin/dev` in the terminal
|
||||||
|
- Wait for an _Open in Browser_ prompt. This will open Mastodon
|
||||||
|
- On the _Ports_ tab "stream" setting change _Port visibility_ → _Public_
|
||||||
|
|
||||||
|
[codespace]: https://codespaces.new/mastodon/mastodon?quickstart=1&devcontainer_path=.devcontainer%2Fcodespaces%2Fdevcontainer.json
|
||||||
|
[CONTRIBUTING]: CONTRIBUTING.md
|
||||||
|
[Dev Container extension]: https://containers.dev/supporting#dev-containers
|
||||||
|
[Development Containers]: https://containers.dev/supporting
|
||||||
|
[Docker]: https://docs.docker.com
|
||||||
|
[GitHub Codespaces]: https://docs.github.com/en/codespaces
|
||||||
|
[Homebrew]: https://brew.sh
|
|
@ -192,6 +192,7 @@ module Mastodon::CLI
|
||||||
verify_schema_version!
|
verify_schema_version!
|
||||||
verify_sidekiq_not_active!
|
verify_sidekiq_not_active!
|
||||||
verify_backup_warning!
|
verify_backup_warning!
|
||||||
|
disable_timeout!
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_deduplications
|
def process_deduplications
|
||||||
|
@ -251,6 +252,13 @@ module Mastodon::CLI
|
||||||
fail_with_message 'Maintenance process stopped.' unless yes?('Continue? (Yes/No)')
|
fail_with_message 'Maintenance process stopped.' unless yes?('Continue? (Yes/No)')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def disable_timeout!
|
||||||
|
# Remove server-configured timeout if present
|
||||||
|
database_connection.execute(<<~SQL.squish)
|
||||||
|
SET statement_timeout = 0
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
def deduplicate_accounts!
|
def deduplicate_accounts!
|
||||||
remove_index_if_exists!(:accounts, 'index_accounts_on_username_and_domain_lower')
|
remove_index_if_exists!(:accounts, 'index_accounts_on_username_and_domain_lower')
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,11 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def prerelease
|
def prerelease
|
||||||
ENV['MASTODON_VERSION_PRERELEASE'].presence || default_prerelease
|
version_configuration[:prerelease].presence || default_prerelease
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_metadata
|
def build_metadata
|
||||||
['glitch', ENV.fetch('MASTODON_VERSION_METADATA', nil)].compact_blank.join('.')
|
version_configuration[:metadata]
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_a
|
def to_a
|
||||||
|
@ -77,5 +77,9 @@ module Mastodon
|
||||||
def user_agent
|
def user_agent
|
||||||
@user_agent ||= "Mastodon/#{Version} (#{HTTP::Request::USER_AGENT}; +http#{Rails.configuration.x.use_https ? 's' : ''}://#{Rails.configuration.x.web_domain}/)"
|
@user_agent ||= "Mastodon/#{Version} (#{HTTP::Request::USER_AGENT}; +http#{Rails.configuration.x.use_https ? 's' : ''}://#{Rails.configuration.x.web_domain}/)"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def version_configuration
|
||||||
|
Rails.configuration.x.mastodon.version
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
"react-hotkeys": "^1.1.4",
|
"react-hotkeys": "^1.1.4",
|
||||||
"react-immutable-proptypes": "^2.2.0",
|
"react-immutable-proptypes": "^2.2.0",
|
||||||
"react-immutable-pure-component": "^2.2.2",
|
"react-immutable-pure-component": "^2.2.2",
|
||||||
"react-intl": "^6.4.2",
|
"react-intl": "^7.0.0",
|
||||||
"react-motion": "^0.5.2",
|
"react-motion": "^0.5.2",
|
||||||
"react-notification": "^6.8.5",
|
"react-notification": "^6.8.5",
|
||||||
"react-overlays": "^5.2.1",
|
"react-overlays": "^5.2.1",
|
||||||
|
@ -201,6 +201,8 @@
|
||||||
"webpack-dev-server": "^3.11.3"
|
"webpack-dev-server": "^3.11.3"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
"@types/react": "^18.2.7",
|
||||||
|
"@types/react-dom": "^18.2.4",
|
||||||
"kind-of": "^6.0.3",
|
"kind-of": "^6.0.3",
|
||||||
"webpack/terser-webpack-plugin": "^4.2.3"
|
"webpack/terser-webpack-plugin": "^4.2.3"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
RSpec.describe Admin::FollowRecommendationsController do
|
|
||||||
render_views
|
|
||||||
|
|
||||||
let(:user) { Fabricate(:admin_user) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
sign_in user, scope: :user
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'GET #show' do
|
|
||||||
it 'returns http success' do
|
|
||||||
get :show
|
|
||||||
|
|
||||||
expect(response).to have_http_status(:success)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,21 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
RSpec.describe Admin::TermsOfService::HistoriesController do
|
|
||||||
render_views
|
|
||||||
|
|
||||||
let(:user) { Fabricate(:admin_user) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
sign_in user, scope: :user
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'GET #show' do
|
|
||||||
it 'returns http success' do
|
|
||||||
get :show
|
|
||||||
|
|
||||||
expect(response).to have_http_status(:success)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -3,6 +3,8 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe ApplicationController do
|
RSpec.describe ApplicationController do
|
||||||
|
render_views
|
||||||
|
|
||||||
controller do
|
controller do
|
||||||
def success
|
def success
|
||||||
head 200
|
head 200
|
||||||
|
@ -23,9 +25,22 @@ RSpec.describe ApplicationController do
|
||||||
|
|
||||||
shared_examples 'respond_with_error' do |code|
|
shared_examples 'respond_with_error' do |code|
|
||||||
it "returns http #{code} for http and renders template" do
|
it "returns http #{code} for http and renders template" do
|
||||||
expect(subject).to render_template("errors/#{code}", layout: 'error')
|
subject
|
||||||
|
|
||||||
expect(response).to have_http_status(code)
|
expect(response)
|
||||||
|
.to have_http_status(code)
|
||||||
|
expect(response.parsed_body)
|
||||||
|
.to have_css('body[class=error]')
|
||||||
|
expect(response.parsed_body.css('h1').to_s)
|
||||||
|
.to include(error_content(code))
|
||||||
|
end
|
||||||
|
|
||||||
|
def error_content(code)
|
||||||
|
if code == 422
|
||||||
|
I18n.t('errors.422.content')
|
||||||
|
else
|
||||||
|
I18n.t("errors.#{code}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,104 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
RSpec.describe Settings::MigrationsController do
|
|
||||||
render_views
|
|
||||||
|
|
||||||
describe 'GET #show' do
|
|
||||||
context 'when user is not sign in' do
|
|
||||||
subject { get :show }
|
|
||||||
|
|
||||||
it { is_expected.to redirect_to new_user_session_path }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when user is sign in' do
|
|
||||||
subject { get :show }
|
|
||||||
|
|
||||||
let(:user) { Fabricate(:account, moved_to_account: moved_to_account).user }
|
|
||||||
|
|
||||||
before { sign_in user, scope: :user }
|
|
||||||
|
|
||||||
context 'when user does not have moved to account' do
|
|
||||||
let(:moved_to_account) { nil }
|
|
||||||
|
|
||||||
it 'renders show page' do
|
|
||||||
expect(subject).to have_http_status 200
|
|
||||||
expect(subject).to render_template :show
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when user has a moved to account' do
|
|
||||||
let(:moved_to_account) { Fabricate(:account) }
|
|
||||||
|
|
||||||
it 'renders show page' do
|
|
||||||
expect(subject).to have_http_status 200
|
|
||||||
expect(subject).to render_template :show
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'POST #create' do
|
|
||||||
context 'when user is not sign in' do
|
|
||||||
subject { post :create }
|
|
||||||
|
|
||||||
it { is_expected.to redirect_to new_user_session_path }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when user is signed in' do
|
|
||||||
subject { post :create, params: { account_migration: { acct: acct, current_password: '12345678' } } }
|
|
||||||
|
|
||||||
let(:user) { Fabricate(:user, password: '12345678') }
|
|
||||||
|
|
||||||
before { sign_in user, scope: :user }
|
|
||||||
|
|
||||||
context 'when migration account is changed' do
|
|
||||||
let(:acct) { Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)]) }
|
|
||||||
|
|
||||||
it 'updates moved to account' do
|
|
||||||
expect(subject).to redirect_to settings_migration_path
|
|
||||||
expect(user.account.reload.moved_to_account_id).to eq acct.id
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when acct is the current account' do
|
|
||||||
let(:acct) { user.account }
|
|
||||||
|
|
||||||
it 'does not update the moved account', :aggregate_failures do
|
|
||||||
subject
|
|
||||||
|
|
||||||
expect(user.account.reload.moved_to_account_id).to be_nil
|
|
||||||
expect(response).to render_template :show
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when target account does not reference the account being moved from' do
|
|
||||||
let(:acct) { Fabricate(:account, also_known_as: []) }
|
|
||||||
|
|
||||||
it 'does not update the moved account', :aggregate_failures do
|
|
||||||
subject
|
|
||||||
|
|
||||||
expect(user.account.reload.moved_to_account_id).to be_nil
|
|
||||||
expect(response).to render_template :show
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when a recent migration already exists' do
|
|
||||||
let(:acct) { Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)]) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
moved_to = Fabricate(:account, also_known_as: [ActivityPub::TagManager.instance.uri_for(user.account)])
|
|
||||||
user.account.migrations.create!(acct: moved_to.acct)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not update the moved account', :aggregate_failures do
|
|
||||||
subject
|
|
||||||
|
|
||||||
expect(user.account.reload.moved_to_account_id).to be_nil
|
|
||||||
expect(response).to render_template :show
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -79,6 +79,26 @@ RSpec.describe ThemeHelper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#custom_stylesheet' do
|
||||||
|
context 'when custom css setting value digest is present' do
|
||||||
|
before { Rails.cache.write(:setting_digest_custom_css, '1a2s3d4f1a2s3d4f') }
|
||||||
|
|
||||||
|
it 'returns value from settings' do
|
||||||
|
expect(custom_stylesheet)
|
||||||
|
.to match('/css/custom-1a2s3d4f.css')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when custom css setting value digest is not present' do
|
||||||
|
before { Rails.cache.delete(:setting_digest_custom_css) }
|
||||||
|
|
||||||
|
it 'returns default value' do
|
||||||
|
expect(custom_stylesheet)
|
||||||
|
.to be_blank
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def html_links
|
def html_links
|
||||||
|
|
|
@ -162,12 +162,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when object publication date is below ISO8601 range' do
|
context 'when object publication date is below ISO8601 range' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
published: '-0977-11-03T08:31:22Z'
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
published: '-0977-11-03T08:31:22Z',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status with a valid creation date', :aggregate_failures do
|
it 'creates status with a valid creation date', :aggregate_failures do
|
||||||
|
@ -184,12 +181,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when object publication date is above ISO8601 range' do
|
context 'when object publication date is above ISO8601 range' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
published: '10000-11-03T08:31:22Z'
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
published: '10000-11-03T08:31:22Z',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status with a valid creation date', :aggregate_failures do
|
it 'creates status with a valid creation date', :aggregate_failures do
|
||||||
|
@ -206,13 +200,10 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when object has been edited' do
|
context 'when object has been edited' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
published: '2022-01-22T15:00:00Z',
|
published: '2022-01-22T15:00:00Z',
|
||||||
updated: '2022-01-22T16:00:00Z',
|
updated: '2022-01-22T16:00:00Z'
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status with appropriate creation and edition dates', :aggregate_failures do
|
it 'creates status with appropriate creation and edition dates', :aggregate_failures do
|
||||||
|
@ -232,13 +223,10 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when object has update date equal to creation date' do
|
context 'when object has update date equal to creation date' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
published: '2022-01-22T15:00:00Z',
|
published: '2022-01-22T15:00:00Z',
|
||||||
updated: '2022-01-22T15:00:00Z',
|
updated: '2022-01-22T15:00:00Z'
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status and does not mark it as edited' do
|
it 'creates status and does not mark it as edited' do
|
||||||
|
@ -254,11 +242,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with an unknown object type' do
|
context 'with an unknown object type' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
type: 'Banana'
|
||||||
type: 'Banana',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not create a status' do
|
it 'does not create a status' do
|
||||||
|
@ -267,13 +253,7 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a standalone' do
|
context 'with a standalone' do
|
||||||
let(:object_json) do
|
let(:object_json) { build_object }
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
expect { subject.perform }.to change(sender.statuses, :count).by(1)
|
expect { subject.perform }.to change(sender.statuses, :count).by(1)
|
||||||
|
@ -296,12 +276,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when public with explicit public address' do
|
context 'when public with explicit public address' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
to: 'https://www.w3.org/ns/activitystreams#Public'
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: 'https://www.w3.org/ns/activitystreams#Public',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -316,12 +293,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when public with as:Public' do
|
context 'when public with as:Public' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
to: 'as:Public'
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: 'as:Public',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -336,12 +310,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when public with Public' do
|
context 'when public with Public' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
to: 'Public'
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: 'Public',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -356,12 +327,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when unlisted with explicit public address' do
|
context 'when unlisted with explicit public address' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
cc: 'https://www.w3.org/ns/activitystreams#Public'
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
cc: 'https://www.w3.org/ns/activitystreams#Public',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -376,12 +344,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when unlisted with as:Public' do
|
context 'when unlisted with as:Public' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
cc: 'as:Public'
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
cc: 'as:Public',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -396,12 +361,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when unlisted with Public' do
|
context 'when unlisted with Public' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
cc: 'Public'
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
cc: 'Public',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -416,12 +378,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when private' do
|
context 'when private' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
to: 'http://example.com/followers'
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: 'http://example.com/followers',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -436,16 +395,13 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'when private with inlined Collection in audience' do
|
context 'when private with inlined Collection in audience' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: {
|
to: {
|
||||||
type: 'OrderedCollection',
|
type: 'OrderedCollection',
|
||||||
id: 'http://example.com/followers',
|
id: 'http://example.com/followers',
|
||||||
first: 'http://example.com/followers?page=true',
|
first: 'http://example.com/followers?page=true',
|
||||||
},
|
}
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -462,12 +418,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
let(:recipient) { Fabricate(:account) }
|
let(:recipient) { Fabricate(:account) }
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
to: ActivityPub::TagManager.instance.uri_for(recipient)
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: ActivityPub::TagManager.instance.uri_for(recipient),
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status with a silent mention' do
|
it 'creates status with a silent mention' do
|
||||||
|
@ -512,16 +465,13 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
let(:recipient) { Fabricate(:account) }
|
let(:recipient) { Fabricate(:account) }
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: ActivityPub::TagManager.instance.uri_for(recipient),
|
to: ActivityPub::TagManager.instance.uri_for(recipient),
|
||||||
tag: {
|
tag: {
|
||||||
type: 'Mention',
|
type: 'Mention',
|
||||||
href: ActivityPub::TagManager.instance.uri_for(recipient),
|
href: ActivityPub::TagManager.instance.uri_for(recipient),
|
||||||
},
|
}
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status with direct visibility' do
|
it 'creates status with direct visibility' do
|
||||||
|
@ -561,12 +511,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
let(:original_status) { Fabricate(:status) }
|
let(:original_status) { Fabricate(:status) }
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
inReplyTo: ActivityPub::TagManager.instance.uri_for(original_status)
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
inReplyTo: ActivityPub::TagManager.instance.uri_for(original_status),
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -586,17 +533,14 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
let(:recipient) { Fabricate(:account) }
|
let(:recipient) { Fabricate(:account) }
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
tag: [
|
tag: [
|
||||||
{
|
{
|
||||||
type: 'Mention',
|
type: 'Mention',
|
||||||
href: ActivityPub::TagManager.instance.uri_for(recipient),
|
href: ActivityPub::TagManager.instance.uri_for(recipient),
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -611,16 +555,13 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with mentions missing href' do
|
context 'with mentions missing href' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
tag: [
|
tag: [
|
||||||
{
|
{
|
||||||
type: 'Mention',
|
type: 'Mention',
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -633,10 +574,7 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with media attachments' do
|
context 'with media attachments' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
attachment: [
|
attachment: [
|
||||||
{
|
{
|
||||||
type: 'Document',
|
type: 'Document',
|
||||||
|
@ -648,8 +586,8 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
mediaType: 'image/png',
|
mediaType: 'image/png',
|
||||||
url: 'http://example.com/emoji.png',
|
url: 'http://example.com/emoji.png',
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status with correctly-ordered media attachments' do
|
it 'creates status with correctly-ordered media attachments' do
|
||||||
|
@ -665,19 +603,16 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with media attachments with long description' do
|
context 'with media attachments with long description' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
attachment: [
|
attachment: [
|
||||||
{
|
{
|
||||||
type: 'Document',
|
type: 'Document',
|
||||||
mediaType: 'image/png',
|
mediaType: 'image/png',
|
||||||
url: 'http://example.com/attachment.png',
|
url: 'http://example.com/attachment.png',
|
||||||
name: '*' * 1500,
|
name: '*' * MediaAttachment::MAX_DESCRIPTION_LENGTH,
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -686,25 +621,22 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
status = sender.statuses.first
|
status = sender.statuses.first
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
expect(status).to_not be_nil
|
||||||
expect(status.media_attachments.map(&:description)).to include('*' * 1500)
|
expect(status.media_attachments.map(&:description)).to include('*' * MediaAttachment::MAX_DESCRIPTION_LENGTH)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with media attachments with long description as summary' do
|
context 'with media attachments with long description as summary' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
attachment: [
|
attachment: [
|
||||||
{
|
{
|
||||||
type: 'Document',
|
type: 'Document',
|
||||||
mediaType: 'image/png',
|
mediaType: 'image/png',
|
||||||
url: 'http://example.com/attachment.png',
|
url: 'http://example.com/attachment.png',
|
||||||
summary: '*' * 1500,
|
summary: '*' * MediaAttachment::MAX_DESCRIPTION_LENGTH,
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -713,16 +645,13 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
status = sender.statuses.first
|
status = sender.statuses.first
|
||||||
|
|
||||||
expect(status).to_not be_nil
|
expect(status).to_not be_nil
|
||||||
expect(status.media_attachments.map(&:description)).to include('*' * 1500)
|
expect(status.media_attachments.map(&:description)).to include('*' * MediaAttachment::MAX_DESCRIPTION_LENGTH)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with media attachments with focal points' do
|
context 'with media attachments with focal points' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
attachment: [
|
attachment: [
|
||||||
{
|
{
|
||||||
type: 'Document',
|
type: 'Document',
|
||||||
|
@ -730,8 +659,8 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
url: 'http://example.com/attachment.png',
|
url: 'http://example.com/attachment.png',
|
||||||
focalPoint: [0.5, -0.7],
|
focalPoint: [0.5, -0.7],
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -746,17 +675,14 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with media attachments missing url' do
|
context 'with media attachments missing url' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
attachment: [
|
attachment: [
|
||||||
{
|
{
|
||||||
type: 'Document',
|
type: 'Document',
|
||||||
mediaType: 'image/png',
|
mediaType: 'image/png',
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -769,18 +695,15 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with hashtags' do
|
context 'with hashtags' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
tag: [
|
tag: [
|
||||||
{
|
{
|
||||||
type: 'Hashtag',
|
type: 'Hashtag',
|
||||||
href: 'http://example.com/blah',
|
href: 'http://example.com/blah',
|
||||||
name: '#test',
|
name: '#test',
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -795,10 +718,7 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with featured hashtags' do
|
context 'with featured hashtags' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: 'https://www.w3.org/ns/activitystreams#Public',
|
to: 'https://www.w3.org/ns/activitystreams#Public',
|
||||||
tag: [
|
tag: [
|
||||||
{
|
{
|
||||||
|
@ -806,8 +726,8 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
href: 'http://example.com/blah',
|
href: 'http://example.com/blah',
|
||||||
name: '#test',
|
name: '#test',
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -829,17 +749,14 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with hashtags missing name' do
|
context 'with hashtags missing name' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
tag: [
|
tag: [
|
||||||
{
|
{
|
||||||
type: 'Hashtag',
|
type: 'Hashtag',
|
||||||
href: 'http://example.com/blah',
|
href: 'http://example.com/blah',
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -852,18 +769,15 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with hashtags invalid name' do
|
context 'with hashtags invalid name' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
tag: [
|
tag: [
|
||||||
{
|
{
|
||||||
type: 'Hashtag',
|
type: 'Hashtag',
|
||||||
href: 'http://example.com/blah',
|
href: 'http://example.com/blah',
|
||||||
name: 'foo, #eh !',
|
name: 'foo, #eh !',
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -876,9 +790,7 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with emojis' do
|
context 'with emojis' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum :tinking:',
|
content: 'Lorem ipsum :tinking:',
|
||||||
tag: [
|
tag: [
|
||||||
{
|
{
|
||||||
|
@ -888,8 +800,8 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
},
|
},
|
||||||
name: 'tinking',
|
name: 'tinking',
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -904,9 +816,7 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with emojis served with invalid content-type' do
|
context 'with emojis served with invalid content-type' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum :tinkong:',
|
content: 'Lorem ipsum :tinkong:',
|
||||||
tag: [
|
tag: [
|
||||||
{
|
{
|
||||||
|
@ -916,8 +826,8 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
},
|
},
|
||||||
name: 'tinkong',
|
name: 'tinkong',
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -932,9 +842,7 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with emojis missing name' do
|
context 'with emojis missing name' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum :tinking:',
|
content: 'Lorem ipsum :tinking:',
|
||||||
tag: [
|
tag: [
|
||||||
{
|
{
|
||||||
|
@ -943,8 +851,8 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
url: 'http://example.com/emoji.png',
|
url: 'http://example.com/emoji.png',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -957,17 +865,15 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with emojis missing icon' do
|
context 'with emojis missing icon' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum :tinking:',
|
content: 'Lorem ipsum :tinking:',
|
||||||
tag: [
|
tag: [
|
||||||
{
|
{
|
||||||
type: 'Emoji',
|
type: 'Emoji',
|
||||||
name: 'tinking',
|
name: 'tinking',
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
|
@ -980,8 +886,7 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with poll' do
|
context 'with poll' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Question',
|
type: 'Question',
|
||||||
content: 'Which color was the submarine?',
|
content: 'Which color was the submarine?',
|
||||||
oneOf: [
|
oneOf: [
|
||||||
|
@ -999,8 +904,8 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
totalItems: 3,
|
totalItems: 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates status with a poll' do
|
it 'creates status with a poll' do
|
||||||
|
@ -1023,12 +928,10 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
let!(:local_status) { Fabricate(:status, poll: poll) }
|
let!(:local_status) { Fabricate(:status, poll: poll) }
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
name: 'Yellow',
|
name: 'Yellow',
|
||||||
inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status),
|
inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status)
|
||||||
}
|
).except(:content)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'adds a vote to the poll with correct uri' do
|
it 'adds a vote to the poll with correct uri' do
|
||||||
|
@ -1050,12 +953,10 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
let!(:local_status) { Fabricate(:status, poll: poll) }
|
let!(:local_status) { Fabricate(:status, poll: poll) }
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
name: 'Yellow',
|
name: 'Yellow',
|
||||||
inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status),
|
inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status)
|
||||||
}
|
).except(:content)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not add a vote to the poll' do
|
it 'does not add a vote to the poll' do
|
||||||
|
@ -1067,10 +968,7 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
context 'with counts' do
|
context 'with counts' do
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
likes: {
|
likes: {
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar', '/likes'].join,
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar', '/likes'].join,
|
||||||
type: 'Collection',
|
type: 'Collection',
|
||||||
|
@ -1080,8 +978,8 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar', '/shares'].join,
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar', '/shares'].join,
|
||||||
type: 'Collection',
|
type: 'Collection',
|
||||||
totalItems: 100,
|
totalItems: 100,
|
||||||
},
|
}
|
||||||
}
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'uses the counts from the created object' do
|
it 'uses the counts from the created object' do
|
||||||
|
@ -1110,12 +1008,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
to: 'https://www.w3.org/ns/activitystreams#Public'
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: 'https://www.w3.org/ns/activitystreams#Public',
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -1145,13 +1040,7 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
subject.perform
|
subject.perform
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) { build_object }
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates status' do
|
it 'creates status' do
|
||||||
status = sender.statuses.first
|
status = sender.statuses.first
|
||||||
|
@ -1166,12 +1055,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
let!(:local_status) { Fabricate(:status) }
|
let!(:local_status) { Fabricate(:status) }
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status)
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
inReplyTo: ActivityPub::TagManager.instance.uri_for(local_status),
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -1190,13 +1076,11 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
subject { described_class.new(json, sender, delivery: true) }
|
subject { described_class.new(json, sender, delivery: true) }
|
||||||
|
|
||||||
let!(:local_account) { Fabricate(:account) }
|
let!(:local_account) { Fabricate(:account) }
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
to: ActivityPub::TagManager.instance.uri_for(local_account)
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
to: ActivityPub::TagManager.instance.uri_for(local_account),
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -1216,12 +1100,9 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
|
|
||||||
let!(:local_account) { Fabricate(:account) }
|
let!(:local_account) { Fabricate(:account) }
|
||||||
let(:object_json) do
|
let(:object_json) do
|
||||||
{
|
build_object(
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
cc: ActivityPub::TagManager.instance.uri_for(local_account)
|
||||||
type: 'Note',
|
)
|
||||||
content: 'Lorem ipsum',
|
|
||||||
cc: ActivityPub::TagManager.instance.uri_for(local_account),
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -1243,17 +1124,19 @@ RSpec.describe ActivityPub::Activity::Create do
|
||||||
subject.perform
|
subject.perform
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:object_json) do
|
let(:object_json) { build_object }
|
||||||
{
|
|
||||||
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
|
||||||
type: 'Note',
|
|
||||||
content: 'Lorem ipsum',
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not create anything' do
|
it 'does not create anything' do
|
||||||
expect(sender.statuses.count).to eq 0
|
expect(sender.statuses.count).to eq 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def build_object(options = {})
|
||||||
|
{
|
||||||
|
id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Lorem ipsum',
|
||||||
|
}.merge(options)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -89,10 +89,8 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :accounts, name: :index_accounts_on_username_and_domain_lower
|
ActiveRecord::Base.connection.remove_index :accounts, name: :index_accounts_on_username_and_domain_lower
|
||||||
_remote_account = Fabricate(:account, username: duplicate_account_username, domain: duplicate_account_domain)
|
duplicate_record(:account, username: duplicate_account_username, domain: duplicate_account_domain)
|
||||||
_remote_account_dupe = Fabricate.build(:account, username: duplicate_account_username, domain: duplicate_account_domain).save(validate: false)
|
duplicate_record(:account, username: duplicate_account_username, domain: nil)
|
||||||
_local_account = Fabricate(:account, username: duplicate_account_username, domain: nil)
|
|
||||||
_local_account_dupe = Fabricate.build(:account, username: duplicate_account_username, domain: nil).save(validate: false)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def choose_local_account_to_keep
|
def choose_local_account_to_keep
|
||||||
|
@ -127,8 +125,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :users, :email
|
ActiveRecord::Base.connection.remove_index :users, :email
|
||||||
Fabricate(:user, email: duplicate_email)
|
duplicate_record(:user, email: duplicate_email)
|
||||||
Fabricate.build(:user, email: duplicate_email).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -156,8 +153,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :users, :confirmation_token
|
ActiveRecord::Base.connection.remove_index :users, :confirmation_token
|
||||||
Fabricate(:user, confirmation_token: duplicate_confirmation_token)
|
duplicate_record(:user, confirmation_token: duplicate_confirmation_token)
|
||||||
Fabricate.build(:user, confirmation_token: duplicate_confirmation_token).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -185,8 +181,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :users, :reset_password_token
|
ActiveRecord::Base.connection.remove_index :users, :reset_password_token
|
||||||
Fabricate(:user, reset_password_token: duplicate_reset_password_token)
|
duplicate_record(:user, reset_password_token: duplicate_reset_password_token)
|
||||||
Fabricate.build(:user, reset_password_token: duplicate_reset_password_token).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -214,8 +209,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :account_domain_blocks, [:account_id, :domain]
|
ActiveRecord::Base.connection.remove_index :account_domain_blocks, [:account_id, :domain]
|
||||||
Fabricate(:account_domain_block, account: account, domain: duplicate_domain)
|
duplicate_record(:account_domain_block, account: account, domain: duplicate_domain)
|
||||||
Fabricate.build(:account_domain_block, account: account, domain: duplicate_domain).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -244,8 +238,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :announcement_reactions, [:account_id, :announcement_id, :name]
|
ActiveRecord::Base.connection.remove_index :announcement_reactions, [:account_id, :announcement_id, :name]
|
||||||
Fabricate(:announcement_reaction, account: account, announcement: announcement, name: name)
|
duplicate_record(:announcement_reaction, account: account, announcement: announcement, name: name)
|
||||||
Fabricate.build(:announcement_reaction, account: account, announcement: announcement, name: name).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -272,8 +265,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :conversations, :uri
|
ActiveRecord::Base.connection.remove_index :conversations, :uri
|
||||||
Fabricate(:conversation, uri: uri)
|
duplicate_record(:conversation, uri: uri)
|
||||||
Fabricate.build(:conversation, uri: uri).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -301,8 +293,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :custom_emojis, [:shortcode, :domain]
|
ActiveRecord::Base.connection.remove_index :custom_emojis, [:shortcode, :domain]
|
||||||
Fabricate(:custom_emoji, shortcode: duplicate_shortcode, domain: duplicate_domain)
|
duplicate_record(:custom_emoji, shortcode: duplicate_shortcode, domain: duplicate_domain)
|
||||||
Fabricate.build(:custom_emoji, shortcode: duplicate_shortcode, domain: duplicate_domain).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -329,8 +320,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :custom_emoji_categories, :name
|
ActiveRecord::Base.connection.remove_index :custom_emoji_categories, :name
|
||||||
Fabricate(:custom_emoji_category, name: duplicate_name)
|
duplicate_record(:custom_emoji_category, name: duplicate_name)
|
||||||
Fabricate.build(:custom_emoji_category, name: duplicate_name).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -357,8 +347,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :domain_allows, :domain
|
ActiveRecord::Base.connection.remove_index :domain_allows, :domain
|
||||||
Fabricate(:domain_allow, domain: domain)
|
duplicate_record(:domain_allow, domain: domain)
|
||||||
Fabricate.build(:domain_allow, domain: domain).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -385,8 +374,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :domain_blocks, :domain
|
ActiveRecord::Base.connection.remove_index :domain_blocks, :domain
|
||||||
Fabricate(:domain_block, domain: domain)
|
duplicate_record(:domain_block, domain: domain)
|
||||||
Fabricate.build(:domain_block, domain: domain).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -413,8 +401,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :email_domain_blocks, :domain
|
ActiveRecord::Base.connection.remove_index :email_domain_blocks, :domain
|
||||||
Fabricate(:email_domain_block, domain: domain)
|
duplicate_record(:email_domain_block, domain: domain)
|
||||||
Fabricate.build(:email_domain_block, domain: domain).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -441,8 +428,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :media_attachments, :shortcode
|
ActiveRecord::Base.connection.remove_index :media_attachments, :shortcode
|
||||||
Fabricate(:media_attachment, shortcode: shortcode)
|
duplicate_record(:media_attachment, shortcode: shortcode)
|
||||||
Fabricate.build(:media_attachment, shortcode: shortcode).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -469,8 +455,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :preview_cards, :url
|
ActiveRecord::Base.connection.remove_index :preview_cards, :url
|
||||||
Fabricate(:preview_card, url: url)
|
duplicate_record(:preview_card, url: url)
|
||||||
Fabricate.build(:preview_card, url: url).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -530,8 +515,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :tags, name: 'index_tags_on_name_lower_btree'
|
ActiveRecord::Base.connection.remove_index :tags, name: 'index_tags_on_name_lower_btree'
|
||||||
Fabricate(:tag, name: name)
|
duplicate_record(:tag, name: name)
|
||||||
Fabricate.build(:tag, name: name).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -558,8 +542,7 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :webauthn_credentials, :external_id
|
ActiveRecord::Base.connection.remove_index :webauthn_credentials, :external_id
|
||||||
Fabricate(:webauthn_credential, external_id: external_id)
|
duplicate_record(:webauthn_credential, external_id: external_id)
|
||||||
Fabricate.build(:webauthn_credential, external_id: external_id).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -586,11 +569,15 @@ RSpec.describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
def prepare_duplicate_data
|
def prepare_duplicate_data
|
||||||
ActiveRecord::Base.connection.remove_index :webhooks, :url
|
ActiveRecord::Base.connection.remove_index :webhooks, :url
|
||||||
Fabricate(:webhook, url: url)
|
duplicate_record(:webhook, url: url)
|
||||||
Fabricate.build(:webhook, url: url).save(validate: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def duplicate_record(fabricator, options = {})
|
||||||
|
Fabricate(fabricator, options)
|
||||||
|
Fabricate.build(fabricator, options).save(validate: false)
|
||||||
|
end
|
||||||
|
|
||||||
def agree_to_backup_warning
|
def agree_to_backup_warning
|
||||||
allow(cli.shell)
|
allow(cli.shell)
|
||||||
.to receive(:yes?)
|
.to receive(:yes?)
|
||||||
|
|
|
@ -4,7 +4,9 @@ require 'rails_helper'
|
||||||
require 'securerandom'
|
require 'securerandom'
|
||||||
|
|
||||||
RSpec.describe Request do
|
RSpec.describe Request do
|
||||||
subject { described_class.new(:get, 'http://example.com') }
|
subject { described_class.new(:get, 'http://example.com', **options) }
|
||||||
|
|
||||||
|
let(:options) { {} }
|
||||||
|
|
||||||
describe '#headers' do
|
describe '#headers' do
|
||||||
it 'returns user agent' do
|
it 'returns user agent' do
|
||||||
|
@ -39,8 +41,8 @@ RSpec.describe Request do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#perform' do
|
describe '#perform' do
|
||||||
context 'with valid host' do
|
context 'with valid host and non-persistent connection' do
|
||||||
before { stub_request(:get, 'http://example.com') }
|
before { stub_request(:get, 'http://example.com').to_return(body: 'lorem ipsum') }
|
||||||
|
|
||||||
it 'executes a HTTP request' do
|
it 'executes a HTTP request' do
|
||||||
expect { |block| subject.perform(&block) }.to yield_control
|
expect { |block| subject.perform(&block) }.to yield_control
|
||||||
|
@ -71,9 +73,9 @@ RSpec.describe Request do
|
||||||
expect(subject.send(:http_client)).to have_received(:close)
|
expect(subject.send(:http_client)).to have_received(:close)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns response which implements body_with_limit' do
|
it 'yields response' do
|
||||||
subject.perform do |response|
|
subject.perform do |response|
|
||||||
expect(response).to respond_to :body_with_limit
|
expect(response.body_with_limit).to eq 'lorem ipsum'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -95,6 +97,43 @@ RSpec.describe Request do
|
||||||
expect { subject.perform }.to raise_error Mastodon::ValidationError
|
expect { subject.perform }.to raise_error Mastodon::ValidationError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with persistent connection' do
|
||||||
|
before { stub_request(:get, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes)) }
|
||||||
|
|
||||||
|
let(:http_client) { described_class.http_client.persistent('http://example.com') }
|
||||||
|
let(:options) { { http_client: http_client } }
|
||||||
|
|
||||||
|
it 'leaves connection open after completely consumed response' do
|
||||||
|
allow(http_client).to receive(:close)
|
||||||
|
|
||||||
|
subject.perform { |response| response.truncated_body(3.megabytes) }
|
||||||
|
|
||||||
|
expect(http_client).to_not have_received(:close)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'leaves connection open after nearly consumed response' do
|
||||||
|
allow(http_client).to receive(:close)
|
||||||
|
|
||||||
|
subject.perform { |response| response.truncated_body(1.8.megabytes) }
|
||||||
|
|
||||||
|
expect(http_client).to_not have_received(:close)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'closes connection after unconsumed response' do
|
||||||
|
allow(http_client).to receive(:close)
|
||||||
|
|
||||||
|
subject.perform
|
||||||
|
|
||||||
|
expect(http_client).to have_received(:close)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'yields response' do
|
||||||
|
subject.perform do |response|
|
||||||
|
expect(response.body_with_limit(2.megabytes).size).to eq 2.megabytes
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "response's body_with_limit method" do
|
describe "response's body_with_limit method" do
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe Account do
|
RSpec.describe Account do
|
||||||
|
include_examples 'Account::Search'
|
||||||
include_examples 'Reviewable'
|
include_examples 'Reviewable'
|
||||||
|
|
||||||
context 'with an account record' do
|
context 'with an account record' do
|
||||||
|
@ -48,14 +49,48 @@ RSpec.describe Account do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#local?' do
|
describe '#local?' do
|
||||||
it 'returns true when the account is local' do
|
it 'returns true when domain is null' do
|
||||||
account = Fabricate(:account, domain: nil)
|
account = Fabricate(:account, domain: nil)
|
||||||
expect(account.local?).to be true
|
expect(account).to be_local
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns false when the account is on a different domain' do
|
it 'returns false when domain is present' do
|
||||||
account = Fabricate(:account, domain: 'foreign.tld')
|
account = Fabricate(:account, domain: 'foreign.tld')
|
||||||
expect(account.local?).to be false
|
expect(account).to_not be_local
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#remote?' do
|
||||||
|
context 'when the domain is null' do
|
||||||
|
subject { Fabricate.build :account, domain: nil }
|
||||||
|
|
||||||
|
it { is_expected.to_not be_remote }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the domain is blank' do
|
||||||
|
subject { Fabricate.build :account, domain: '' }
|
||||||
|
|
||||||
|
it { is_expected.to_not be_remote }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the domain is present' do
|
||||||
|
subject { Fabricate.build :account, domain: 'host.example' }
|
||||||
|
|
||||||
|
it { is_expected.to be_remote }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#actor_type_application?' do
|
||||||
|
context 'when the actor is not of type application' do
|
||||||
|
subject { Fabricate.build :account, actor_type: 'Person' }
|
||||||
|
|
||||||
|
it { is_expected.to_not be_actor_type_application }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the actor is of type application' do
|
||||||
|
subject { Fabricate.build :account, actor_type: 'Application' }
|
||||||
|
|
||||||
|
it { is_expected.to be_actor_type_application }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -324,271 +359,6 @@ RSpec.describe Account do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.search_for' do
|
|
||||||
before do
|
|
||||||
_missing = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Missing',
|
|
||||||
username: 'missing',
|
|
||||||
domain: 'missing.com'
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not return suspended users' do
|
|
||||||
Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username',
|
|
||||||
domain: 'example.com',
|
|
||||||
suspended: true
|
|
||||||
)
|
|
||||||
|
|
||||||
results = described_class.search_for('username')
|
|
||||||
expect(results).to eq []
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not return unapproved users' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username'
|
|
||||||
)
|
|
||||||
|
|
||||||
match.user.update(approved: false)
|
|
||||||
|
|
||||||
results = described_class.search_for('username')
|
|
||||||
expect(results).to eq []
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not return unconfirmed users' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username'
|
|
||||||
)
|
|
||||||
|
|
||||||
match.user.update(confirmed_at: nil)
|
|
||||||
|
|
||||||
results = described_class.search_for('username')
|
|
||||||
expect(results).to eq []
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'accepts ?, \, : and space as delimiter' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'A & l & i & c & e',
|
|
||||||
username: 'username',
|
|
||||||
domain: 'example.com'
|
|
||||||
)
|
|
||||||
|
|
||||||
results = described_class.search_for('A?l\i:c e')
|
|
||||||
expect(results).to eq [match]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'finds accounts with matching display_name' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username',
|
|
||||||
domain: 'example.com'
|
|
||||||
)
|
|
||||||
|
|
||||||
results = described_class.search_for('display')
|
|
||||||
expect(results).to eq [match]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'finds accounts with matching username' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username',
|
|
||||||
domain: 'example.com'
|
|
||||||
)
|
|
||||||
|
|
||||||
results = described_class.search_for('username')
|
|
||||||
expect(results).to eq [match]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'finds accounts with matching domain' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username',
|
|
||||||
domain: 'example.com'
|
|
||||||
)
|
|
||||||
|
|
||||||
results = described_class.search_for('example')
|
|
||||||
expect(results).to eq [match]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'limits via constant by default' do
|
|
||||||
stub_const('Account::Search::DEFAULT_LIMIT', 1)
|
|
||||||
2.times.each { Fabricate(:account, display_name: 'Display Name') }
|
|
||||||
results = described_class.search_for('display')
|
|
||||||
expect(results.size).to eq 1
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'accepts arbitrary limits' do
|
|
||||||
2.times.each { Fabricate(:account, display_name: 'Display Name') }
|
|
||||||
results = described_class.search_for('display', limit: 1)
|
|
||||||
expect(results.size).to eq 1
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'ranks multiple matches higher' do
|
|
||||||
matches = [
|
|
||||||
{ username: 'username', display_name: 'username' },
|
|
||||||
{ display_name: 'Display Name', username: 'username', domain: 'example.com' },
|
|
||||||
].map(&method(:Fabricate).curry(2).call(:account))
|
|
||||||
|
|
||||||
results = described_class.search_for('username')
|
|
||||||
expect(results).to eq matches
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '.advanced_search_for' do
|
|
||||||
let(:account) { Fabricate(:account) }
|
|
||||||
|
|
||||||
context 'when limiting search to followed accounts' do
|
|
||||||
it 'accepts ?, \, : and space as delimiter' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'A & l & i & c & e',
|
|
||||||
username: 'username',
|
|
||||||
domain: 'example.com'
|
|
||||||
)
|
|
||||||
account.follow!(match)
|
|
||||||
|
|
||||||
results = described_class.advanced_search_for('A?l\i:c e', account, limit: 10, following: true)
|
|
||||||
expect(results).to eq [match]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not return non-followed accounts' do
|
|
||||||
Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'A & l & i & c & e',
|
|
||||||
username: 'username',
|
|
||||||
domain: 'example.com'
|
|
||||||
)
|
|
||||||
|
|
||||||
results = described_class.advanced_search_for('A?l\i:c e', account, limit: 10, following: true)
|
|
||||||
expect(results).to eq []
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not return suspended users' do
|
|
||||||
Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username',
|
|
||||||
domain: 'example.com',
|
|
||||||
suspended: true
|
|
||||||
)
|
|
||||||
|
|
||||||
results = described_class.advanced_search_for('username', account, limit: 10, following: true)
|
|
||||||
expect(results).to eq []
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not return unapproved users' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username'
|
|
||||||
)
|
|
||||||
|
|
||||||
match.user.update(approved: false)
|
|
||||||
|
|
||||||
results = described_class.advanced_search_for('username', account, limit: 10, following: true)
|
|
||||||
expect(results).to eq []
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not return unconfirmed users' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username'
|
|
||||||
)
|
|
||||||
|
|
||||||
match.user.update(confirmed_at: nil)
|
|
||||||
|
|
||||||
results = described_class.advanced_search_for('username', account, limit: 10, following: true)
|
|
||||||
expect(results).to eq []
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not return suspended users' do
|
|
||||||
Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username',
|
|
||||||
domain: 'example.com',
|
|
||||||
suspended: true
|
|
||||||
)
|
|
||||||
|
|
||||||
results = described_class.advanced_search_for('username', account)
|
|
||||||
expect(results).to eq []
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not return unapproved users' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username'
|
|
||||||
)
|
|
||||||
|
|
||||||
match.user.update(approved: false)
|
|
||||||
|
|
||||||
results = described_class.advanced_search_for('username', account)
|
|
||||||
expect(results).to eq []
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'does not return unconfirmed users' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'Display Name',
|
|
||||||
username: 'username'
|
|
||||||
)
|
|
||||||
|
|
||||||
match.user.update(confirmed_at: nil)
|
|
||||||
|
|
||||||
results = described_class.advanced_search_for('username', account)
|
|
||||||
expect(results).to eq []
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'accepts ?, \, : and space as delimiter' do
|
|
||||||
match = Fabricate(
|
|
||||||
:account,
|
|
||||||
display_name: 'A & l & i & c & e',
|
|
||||||
username: 'username',
|
|
||||||
domain: 'example.com'
|
|
||||||
)
|
|
||||||
|
|
||||||
results = described_class.advanced_search_for('A?l\i:c e', account)
|
|
||||||
expect(results).to eq [match]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'limits result count by default value' do
|
|
||||||
stub_const('Account::Search::DEFAULT_LIMIT', 1)
|
|
||||||
2.times { Fabricate(:account, display_name: 'Display Name') }
|
|
||||||
results = described_class.advanced_search_for('display', account)
|
|
||||||
expect(results.size).to eq 1
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'accepts arbitrary limits' do
|
|
||||||
2.times { Fabricate(:account, display_name: 'Display Name') }
|
|
||||||
results = described_class.advanced_search_for('display', account, limit: 1)
|
|
||||||
expect(results.size).to eq 1
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'ranks followed accounts higher' do
|
|
||||||
match = Fabricate(:account, username: 'Matching')
|
|
||||||
followed_match = Fabricate(:account, username: 'Matcher')
|
|
||||||
Fabricate(:follow, account: account, target_account: followed_match)
|
|
||||||
|
|
||||||
results = described_class.advanced_search_for('match', account)
|
|
||||||
expect(results).to eq [followed_match, match]
|
|
||||||
expect(results.first.rank).to be > results.last.rank
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#statuses_count' do
|
describe '#statuses_count' do
|
||||||
subject { Fabricate(:account) }
|
subject { Fabricate(:account) }
|
||||||
|
|
||||||
|
@ -824,8 +594,12 @@ RSpec.describe Account do
|
||||||
it { is_expected.to_not allow_values(account_note_over_limit).for(:note) }
|
it { is_expected.to_not allow_values(account_note_over_limit).for(:note) }
|
||||||
|
|
||||||
it { is_expected.to allow_value(fields_empty_name_value).for(:fields) }
|
it { is_expected.to allow_value(fields_empty_name_value).for(:fields) }
|
||||||
it { is_expected.to_not allow_value(fields_over_limit).for(:fields) }
|
it { is_expected.to_not allow_values(fields_over_limit, fields_empty_name).for(:fields) }
|
||||||
it { is_expected.to_not allow_value(fields_empty_name).for(:fields) }
|
|
||||||
|
it { is_expected.to validate_absence_of(:followers_url).on(:create) }
|
||||||
|
it { is_expected.to validate_absence_of(:inbox_url).on(:create) }
|
||||||
|
it { is_expected.to validate_absence_of(:shared_inbox_url).on(:create) }
|
||||||
|
it { is_expected.to validate_absence_of(:uri).on(:create) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when account is remote' do
|
context 'when account is remote' do
|
||||||
|
|
|
@ -8,4 +8,18 @@ RSpec.describe AccountWarning do
|
||||||
it { is_expected.to normalize(:text).from(nil).to('') }
|
it { is_expected.to normalize(:text).from(nil).to('') }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#appeal_eligible?' do
|
||||||
|
context 'when created too long ago' do
|
||||||
|
subject { Fabricate.build :account_warning, created_at: (described_class::APPEAL_WINDOW * 2).ago }
|
||||||
|
|
||||||
|
it { is_expected.to_not be_appeal_eligible }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when created recently' do
|
||||||
|
subject { Fabricate.build :account_warning, created_at: (described_class::APPEAL_WINDOW - 2.days).ago }
|
||||||
|
|
||||||
|
it { is_expected.to be_appeal_eligible }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue