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