merge nyastodon-specific changes back in

This was caused by an accidental rebase that i
"fixed" by force-pushing, which caused nyastodon
to be even with glitch-soc/main.  oops.
This commit is contained in:
anna 2022-12-01 23:23:12 +00:00
commit 57b7968504
Signed by: fef
GPG key ID: EC22E476DC2D3D84
83 changed files with 1153 additions and 230 deletions

View file

@ -68,7 +68,9 @@ jobs:
cache-version: v1
pkg-manager: yarn
- run:
command: ./bin/rails assets:precompile
command: |
export NODE_OPTIONS=--openssl-legacy-provider
./bin/rails assets:precompile
name: Precompile assets
- persist_to_workspace:
paths:

44
.env.production.catcatnya Normal file
View file

@ -0,0 +1,44 @@
LOCAL_DOMAIN=catcatnya.com
ALTERNATE_DOMAINS=0.catcatnya.com,1.catcatnya.com,2.catcatnya.com,3.catcatnya.com,4.catcatnya.com,5.catcatnya.com,6.catcatnya.com,7.catcatnya.com,8.catcatnya.com,9.catcatnya.com
SINGLE_USER_MODE=false
SECRET_KEY_BASE=[REDACTED]
OTP_SECRET=[REDACTED]
VAPID_PRIVATE_KEY=[REDACTED]
VAPID_PUBLIC_KEY=[REDACTED]
DB_HOST=[REDACTED]
DB_PORT=[REDACTED]
DB_NAME=[REDACTED]
DB_USER=[REDACTED]
DB_PASS=[REDACTED]
REDIS_HOST=[REDACTED]
REDIS_PORT=[REDACTED]
REDIS_PASSWORD=[REDACTED]
S3_ENABLED=false
PAPERCLIP_ROOT_PATH=[REDACTED]
PAPERCLIP_ROOT_URL=https://cdn.catcatnya.com
SMTP_SERVER=smtp.kescher.at
SMTP_PORT=[REDACTED]
SMTP_LOGIN=[REDACTED]
SMTP_PASSWORD=[REDACTED]
SMTP_AUTH_METHOD=[REDACTED]
SMTP_OPENSSL_VERIFY_MODE=[REDACTED]
SMTP_FROM_ADDRESS='Mastodon <no-reply@catcatnya.com>'
ES_ENABLED=true
ES_HOST=[REDACTED]
ES_PORT=[REDACTED]
ES_PREFIX=[REDACTED]
AUTHORIZED_FETCH=true
RAILS_SERVE_STATIC_FILES=false
RAILS_LOG_LEVEL=error
MAX_TOOT_CHARS=6942
MAX_DESCRIPTION_CHARS=6942
MAX_BIO_CHARS=6942
MAX_PROFILE_FIELDS=10
MAX_PINNED_TOOTS=10
MAX_DISPLAY_NAME_CHARS=50
MIN_POLL_OPTIONS=1
MAX_POLL_OPTIONS=20
MAX_SEARCH_RESULTS=1000
MAX_REMOTE_EMOJI_SIZE=1048576
IP_RETENTION_PERIOD=86400

View file

@ -263,6 +263,9 @@ MAX_PROFILE_FIELDS=4
# Maximum allowed display name characters
MAX_DISPLAY_NAME_CHARS=30
# Minimum allowed poll options. (Minimum of 1)
MIN_POLL_OPTIONS=2
# Maximum allowed poll options
MAX_POLL_OPTIONS=5

View file

@ -1,44 +0,0 @@
name: Build container image
on:
workflow_dispatch:
push:
branches:
- 'main'
pull_request:
paths:
- .github/workflows/build-image.yml
- Dockerfile
permissions:
contents: read
packages: write
jobs:
build-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
if: github.event_name != 'pull_request'
- uses: docker/metadata-action@v4
id: meta
with:
images: ghcr.io/${{ github.repository_owner }}/mastodon
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=edge,branch=main
type=sha,prefix=,format=long
- uses: docker/build-push-action@v3
with:
context: .
platforms: linux/amd64,linux/arm64
builder: ${{ steps.buildx.outputs.name }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max

View file

@ -1 +1 @@
3.0.4
3.0.5

View file

@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at glitch-abuse@sitedethib.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at jeremy@kescher.at. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

View file

@ -1,25 +1,24 @@
# Contributing to Mastodon Glitch Edition #
# Contributing to Catstodon #
Thank you for your interest in contributing to the `glitch-soc` project!
Here are some guidelines, and ways you can help.
Thank you for your interest in contributing to a fork of the `glitch-soc` project!
Before you do anything here, please check if you can contribute to either the [vanilla Mastodon project](https://github.com/mastodon/mastodon) or [glitch-soc](https://github.com/glitch-soc/mastodon) first.
If you still decide to contribute here instead, here are some guidelines, and ways you can help.
> (This document is a bit of a work-in-progress, so please bear with us.
> If you don't see what you're looking for here, please don't hesitate to reach out!)
## Planning ##
Right now a lot of the planning for this project takes place in our development Discord, or through GitHub Issues and Projects.
We're working on ways to improve the planning structure and better solicit feedback, and if you feel like you can help in this respect, feel free to give us a holler.
Right now a lot of the planning for this project takes place... in my head. Actually, just contact me via Matrix - contact info can be found on [my personal website](https://kescher.at). You can also contribute via GitHub or kescherGit, if you have an account at either.
## Documentation ##
The documentation for this repository is available at [`glitch-soc/docs`](https://github.com/glitch-soc/docs) (online at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/)).
Right now, we've mostly focused on the features that make this fork different from upstream in some manner.
Adding screenshots, improving descriptions, and so forth are all ways to help contribute to the project even if you don't know any code.
Unlike glitch-soc, which has [`glitch-soc/docs`](https://github.com/glitch-soc/docs) (online at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/)), this repo only documents things in a README. Sorry.
Right now, we've mostly focused on the features that make this fork different from upstream, which, may I remind you, is already a fork.
## Frontend Development ##
Check out [the documentation here](https://glitch-soc.github.io/docs/contributing/frontend/) for more information.
Check out [the documentation here](https://glitch-soc.github.io/docs/contributing/frontend/) for more information on this topic. We'll be following that a bit.
## Backend Development ##

View file

@ -90,22 +90,22 @@ GEM
attr_required (1.0.1)
awrence (1.2.1)
aws-eventstream (1.2.0)
aws-partitions (1.587.0)
aws-sdk-core (3.130.2)
aws-partitions (1.668.0)
aws-sdk-core (3.168.2)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.60.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.56.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.114.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-s3 (1.117.1)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.0)
aws-sigv4 (1.5.2)
aws-eventstream (~> 1, >= 1.0.2)
bcrypt (3.1.17)
bcrypt (3.1.18)
better_errors (2.9.1)
coderay (>= 1.0.0)
erubi (>= 1.0.0)
@ -117,7 +117,7 @@ GEM
erubi (~> 1.4)
parser (>= 2.4)
smart_properties
bindata (2.4.10)
bindata (2.4.14)
binding_of_caller (1.0.0)
debug_inspector (>= 0.0.1)
blurhash (0.1.6)
@ -125,12 +125,12 @@ GEM
bootsnap (1.14.0)
msgpack (~> 1.2)
brakeman (5.4.0)
browser (4.2.0)
brpoplpush-redis_script (0.1.2)
browser (5.3.1)
brpoplpush-redis_script (0.1.3)
concurrent-ruby (~> 1.0, >= 1.0.5)
redis (>= 1.0, <= 5.0)
redis (>= 1.0, < 6)
builder (3.2.4)
bullet (7.0.3)
bullet (7.0.4)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
bundler-audit (0.9.1)
@ -142,7 +142,7 @@ GEM
i18n
rake (>= 10.0.0)
sshkit (>= 1.9.0)
capistrano-bundler (2.0.1)
capistrano-bundler (2.1.0)
capistrano (~> 3.1)
capistrano-rails (1.6.2)
capistrano (~> 3.1)
@ -165,7 +165,7 @@ GEM
activesupport
cbor (0.5.9.6)
charlock_holmes (0.7.7)
chewy (7.2.4)
chewy (7.2.7)
activesupport (>= 5.2)
elasticsearch (>= 7.12.0, < 7.14.0)
elasticsearch-dsl
@ -176,15 +176,15 @@ GEM
color_diff (0.1)
concurrent-ruby (1.1.10)
connection_pool (2.3.0)
cose (1.2.1)
cose (1.3.0)
cbor (~> 0.5.9)
openssl-signature_algorithm (~> 1.0)
crack (0.4.5)
rexml
crass (1.0.6)
css_parser (1.7.1)
css_parser (1.12.0)
addressable
debug_inspector (1.0.0)
debug_inspector (1.1.0)
devise (4.8.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
@ -203,10 +203,10 @@ GEM
diff-lcs (1.5.0)
discard (1.2.1)
activerecord (>= 4.2, < 8)
docile (1.3.4)
docile (1.4.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (5.6.0)
doorkeeper (5.6.2)
railties (>= 5)
dotenv (2.8.1)
dotenv-rails (2.8.1)
@ -226,11 +226,11 @@ GEM
erubi (1.11.0)
et-orbi (1.2.7)
tzinfo
excon (0.76.0)
excon (0.94.0)
fabrication (2.30.0)
faker (2.23.0)
i18n (>= 1.8.11, < 2)
faraday (1.9.3)
faraday (1.10.2)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@ -246,8 +246,8 @@ GEM
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.3)
multipart-post (>= 1.2, < 3)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
@ -271,8 +271,8 @@ GEM
fog-core (>= 1.45, <= 2.1.0)
fog-json (>= 1.0)
ipaddress (>= 0.8)
formatador (0.2.5)
fugit (1.7.1)
formatador (0.3.0)
fugit (1.7.2)
et-orbi (~> 1, >= 1.2.7)
raabro (~> 1.4)
fuubar (2.5.1)
@ -284,7 +284,7 @@ GEM
openid_connect (~> 1.2)
globalid (1.0.0)
activesupport (>= 5.0)
hamlit (2.13.0)
hamlit (3.0.3)
temple (>= 0.8.2)
thor
tilt
@ -329,13 +329,14 @@ GEM
terminal-table (>= 1.5.1)
idn-ruby (0.1.5)
ipaddress (0.8.3)
jmespath (1.6.1)
jmespath (1.6.2)
json (2.6.2)
json-canonicalization (0.3.0)
json-jwt (1.13.0)
json-canonicalization (0.3.1)
json-jwt (1.15.3)
activesupport (>= 4.2)
aes_key_wrap
bindata
httpclient
json-ld (3.2.3)
htmlentities (~> 4.3)
json-canonicalization (~> 0.3)
@ -347,7 +348,7 @@ GEM
json-ld (~> 3.2)
rdf (~> 3.2)
jsonapi-renderer (0.2.2)
jwt (2.4.1)
jwt (2.5.0)
kaminari (1.2.2)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.2)
@ -404,18 +405,20 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2022.0105)
mini_mime (1.1.2)
mini_portile2 (2.8.0)
minitest (5.16.3)
msgpack (1.6.0)
multi_json (1.15.0)
multipart-post (2.1.1)
multipart-post (2.2.3)
net-ldap (0.17.1)
net-scp (4.0.0.rc1)
net-protocol (0.1.3)
timeout
net-scp (4.0.0)
net-ssh (>= 2.6.5, < 8.0.0)
net-smtp (0.3.3)
net-protocol
net-ssh (7.0.1)
nio4r (2.5.8)
nokogiri (1.13.9)
mini_portile2 (~> 2.8.0)
nokogiri (1.13.9-x86_64-linux)
racc (~> 1.4)
nsa (0.2.8)
activesupport (>= 4.2, < 7)
@ -436,23 +439,24 @@ GEM
omniauth-saml (1.10.3)
omniauth (~> 1.3, >= 1.3.2)
ruby-saml (~> 1.9)
openid_connect (1.3.0)
openid_connect (1.4.2)
activemodel
attr_required (>= 1.0.0)
json-jwt (>= 1.5.0)
rack-oauth2 (>= 1.6.1)
swd (>= 1.0.0)
json-jwt (>= 1.15.0)
net-smtp
rack-oauth2 (~> 1.21)
swd (~> 1.3)
tzinfo
validate_email
validate_url
webfinger (>= 1.0.1)
openssl (3.0.0)
webfinger (~> 1.2)
openssl (3.0.1)
openssl-signature_algorithm (1.2.1)
openssl (> 2.0, < 3.1)
orm_adapter (0.5.0)
ox (2.14.11)
parallel (1.22.1)
parser (3.1.2.1)
parser (3.1.3.0)
ast (~> 2.4.1)
parslet (2.0.0)
pastel (0.8.0)
@ -460,14 +464,15 @@ GEM
pg (1.4.5)
pghero (2.8.3)
activerecord (>= 5)
pkg-config (1.4.9)
pkg-config (1.5.1)
posix-spawn (0.3.15)
premailer (1.14.2)
premailer (1.18.0)
addressable
css_parser (>= 1.6.0)
css_parser (>= 1.12.0)
htmlentities (>= 4.0.0)
premailer-rails (1.11.1)
premailer-rails (1.12.0)
actionmailer (>= 3)
net-smtp
premailer (~> 1.7, >= 1.7.9)
private_address_check (0.5.0)
pry (0.14.1)
@ -490,13 +495,13 @@ GEM
rack (>= 1.0, < 3)
rack-cors (1.1.1)
rack (>= 2.0.0)
rack-oauth2 (1.19.0)
rack-oauth2 (1.21.3)
activesupport
attr_required
httpclient
json-jwt (>= 1.11.0)
rack (>= 2.1.0)
rack-proxy (0.7.0)
rack-proxy (0.7.4)
rack
rack-test (2.0.2)
rack (>= 1.3)
@ -527,7 +532,7 @@ GEM
rails-i18n (6.0.0)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 7)
rails-settings-cached (0.6.6)
rails-settings-cached (0.7.2)
rails (>= 4.2.0)
railties (6.1.7)
actionpack (= 6.1.7)
@ -539,33 +544,33 @@ GEM
rake (13.0.6)
rdf (3.2.9)
link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.5.0)
rdf-normalize (0.5.1)
rdf (~> 3.2)
redcarpet (3.5.1)
redis (4.5.1)
redis (4.8.0)
redis-namespace (1.9.0)
redis (>= 4)
regexp_parser (2.6.0)
regexp_parser (2.6.1)
request_store (1.5.1)
rack (>= 1.4)
responders (3.0.1)
actionpack (>= 5.0)
railties (>= 5.0)
rexml (3.2.5)
rotp (6.2.0)
rotp (6.2.1)
rpam2 (4.0.2)
rqrcode (2.1.2)
chunky_png (~> 1.0)
rqrcode_core (~> 1.0)
rqrcode_core (1.2.0)
rspec-core (3.11.0)
rspec-support (~> 3.11.0)
rspec-expectations (3.11.0)
rspec-core (3.12.0)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-mocks (3.11.1)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-support (~> 3.12.0)
rspec-rails (5.1.2)
actionpack (>= 5.2)
activesupport (>= 5.2)
@ -577,26 +582,27 @@ GEM
rspec-sidekiq (3.1.0)
rspec-core (~> 3.0, >= 3.0.0)
sidekiq (>= 2.4.0)
rspec-support (3.11.1)
rspec-support (3.12.0)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.30.1)
rubocop (1.39.0)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.1.0.0)
parser (>= 3.1.2.1)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.18.0, < 2.0)
rubocop-ast (>= 1.23.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.18.0)
rubocop-ast (1.23.0)
parser (>= 3.1.1.0)
rubocop-rails (2.15.0)
rubocop-rails (2.17.3)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.7.0, < 2.0)
rubocop (>= 1.33.0, < 2.0)
ruby-progressbar (1.11.0)
ruby-saml (1.13.0)
ruby-saml (1.14.0)
nokogiri (>= 1.10.5)
rexml
ruby2_keywords (0.0.5)
@ -637,7 +643,7 @@ GEM
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.2)
simplecov_json_formatter (0.1.4)
smart_properties (1.17.0)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
@ -646,25 +652,26 @@ GEM
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
sshkit (1.21.2)
sshkit (1.21.3)
net-scp (>= 1.1.2)
net-ssh (>= 2.8.0)
stackprof (0.2.22)
stackprof (0.2.23)
statsd-ruby (1.5.0)
stoplight (3.0.0)
strong_migrations (0.7.9)
activerecord (>= 5)
strong_migrations (0.8.0)
activerecord (>= 5.2)
swd (1.3.0)
activesupport (>= 3)
attr_required (>= 0.0.5)
httpclient (>= 2.4)
temple (0.8.2)
temple (0.9.1)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
terrapin (0.6.0)
climate_control (>= 0.0.3, < 1.0)
thor (1.2.1)
tilt (2.0.11)
timeout (0.3.0)
tpm-key_attestation (0.11.0)
bindata (~> 2.4)
openssl (> 2.0, < 3.1)
@ -684,7 +691,7 @@ GEM
unf (~> 0.1.0)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
tzinfo-data (1.2022.6)
tzinfo-data (1.2022.7)
tzinfo (>= 1.0.0)
unf (0.1.4)
unf_ext
@ -727,7 +734,7 @@ GEM
xorcist (1.1.3)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.6.0)
zeitwerk (2.6.6)
PLATFORMS
ruby

View file

@ -1,14 +1,35 @@
# Mastodon Glitch Edition #
# Catstodon
## Introduction
This Mastodon fork is based on the [glitch-soc Fork of Mastodon](https://github.com/glitch-soc/mastodon), with changes made to suit [CatCatNya~](https://catcatnya.com).
The aforementioned instance is running the `develop` branch.
I intend to contribute some useful differences back to [glitch-soc](https://github.com/glitch-soc/mastodon) and [vanilla Mastodon](https://github.com/mastodon/mastodon).
> Now with automated deploys!
To install, take a look at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/). The instructions and features are the same, except for the differences outlined below.
[![Build Status](https://img.shields.io/circleci/project/github/glitch-soc/mastodon.svg)][circleci]
[![Code Climate](https://img.shields.io/codeclimate/maintainability/glitch-soc/mastodon.svg)][code_climate]
Contributing guidelines are available [here](CONTRIBUTING.md).
[circleci]: https://circleci.com/gh/glitch-soc/mastodon
[code_climate]: https://codeclimate.com/github/glitch-soc/mastodon
Note: [CatCatNya~](https://catcatnya.com) runs on the `develop` branch.
That branch may, at times, be force-pushed to (mostly for undoing cherry-picking of vanilla commits when upstream adopts them).
I highly suggest only ever running the `main` branch in production!
So here's the deal: we all work on this code, and anyone who uses that does so absolutely at their own risk. can you dig it?
## Differences
- Some files are adjusted specifically for the CatCatNya~ instance. Specifically, these:
- sounds/boop.mp3
- sounds/boop.ogg
<br>You might want to revert these to the upstream files (or your own versions!) if you decide to use this fork for your own instance.
- The web frontend emoji picker is a blobcat instead of the joy emoji.
- The rate limits for authenticated users have been relaxed a bit.
- The API endpoint `/api/v1/custom_emojis` is no longer affected by AUTHORIZED_FETCH, allowing anyone to copy custom emojis.
- Allow higher resolution images. (4096x4096 instead of the previous limit of 1920x1080)
- Allow posting polls with only one poll option (if `MIN_POLL_OPTIONS` is set to 1 on your instance).
- Added oatstodon flavour (taken from [types.pl fork](https://github.com/ralsei/types.pl), by [@oat@hellsite.site](https://hellsite.site/@oat))
- RSS feeds have titles again.
- Account RSS feeds show the CW (if applicable).
- Tag RSS feeds show the handle (username if local, username@domain if remote) and the CW (if applicable).
- You can view documentation for this project at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/).
- And contributing guidelines are available [here](CONTRIBUTING.md) and [here](https://glitch-soc.github.io/docs/contributing/).
## Previous differences now merged into glitch-soc
- Fixed incorrect upload size limit display when adding new a new custom emoji. ([Pull request](https://github.com/glitch-soc/mastodon/pull/1763))
- Everything merged into vanilla Mastodon
## Previous differences now merged into vanilla Mastodon
- The period of retention of IP addresses and sessions was made configurable. ([Pull request](https://github.com/mastodon/mastodon/pull/18757))

View file

@ -2,6 +2,7 @@
class Api::V1::CustomEmojisController < Api::BaseController
skip_before_action :set_cache_headers
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
def index
expires_in 3.minutes, public: true

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true
class Api::V1::Trends::StatusesController < Api::BaseController
before_action :require_user!, only: [:index], if: :require_auth?
before_action :set_statuses
after_action :insert_pagination_headers
@ -54,4 +55,8 @@ class Api::V1::Trends::StatusesController < Api::BaseController
def records_continue?
@statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)
end
def require_auth?
!Setting.timeline_preview
end
end

View file

@ -34,6 +34,11 @@ export const STATUS_FETCH_SOURCE_REQUEST = 'STATUS_FETCH_SOURCE_REQUEST';
export const STATUS_FETCH_SOURCE_SUCCESS = 'STATUS_FETCH_SOURCE_SUCCESS';
export const STATUS_FETCH_SOURCE_FAIL = 'STATUS_FETCH_SOURCE_FAIL';
export const STATUS_TRANSLATE_REQUEST = 'STATUS_TRANSLATE_REQUEST';
export const STATUS_TRANSLATE_SUCCESS = 'STATUS_TRANSLATE_SUCCESS';
export const STATUS_TRANSLATE_FAIL = 'STATUS_TRANSLATE_FAIL';
export const STATUS_TRANSLATE_UNDO = 'STATUS_TRANSLATE_UNDO';
export function fetchStatusRequest(id, skipLoading) {
return {
type: STATUS_FETCH_REQUEST,
@ -310,4 +315,36 @@ export function toggleStatusCollapse(id, isCollapsed) {
id,
isCollapsed,
};
}
};
export const translateStatus = id => (dispatch, getState) => {
dispatch(translateStatusRequest(id));
api(getState).post(`/api/v1/statuses/${id}/translate`).then(response => {
dispatch(translateStatusSuccess(id, response.data));
}).catch(error => {
dispatch(translateStatusFail(id, error));
});
};
export const translateStatusRequest = id => ({
type: STATUS_TRANSLATE_REQUEST,
id,
});
export const translateStatusSuccess = (id, translation) => ({
type: STATUS_TRANSLATE_SUCCESS,
id,
translation,
});
export const translateStatusFail = (id, error) => ({
type: STATUS_TRANSLATE_FAIL,
id,
error,
});
export const undoStatusTranslation = id => ({
type: STATUS_TRANSLATE_UNDO,
id,
});

View file

@ -86,6 +86,7 @@ class Status extends ImmutablePureComponent {
onEmbed: PropTypes.func,
onHeightChange: PropTypes.func,
onToggleHidden: PropTypes.func,
onTranslate: PropTypes.func,
onInteractionModal: PropTypes.func,
muted: PropTypes.bool,
hidden: PropTypes.bool,
@ -476,6 +477,10 @@ class Status extends ImmutablePureComponent {
this.node = c;
}
handleTranslate = () => {
this.props.onTranslate(this.props.status);
}
renderLoadingMediaGallery () {
return <div className='media-gallery' style={{ height: '110px' }} />;
}
@ -793,6 +798,7 @@ class Status extends ImmutablePureComponent {
mediaIcons={contentMediaIcons}
expanded={isExpanded}
onExpandedToggle={this.handleExpandedToggle}
onTranslate={this.handleTranslate}
parseClick={parseClick}
disabled={!router}
tagLinks={settings.get('tag_misleading_links')}

View file

@ -1,11 +1,11 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, injectIntl } from 'react-intl';
import Permalink from './permalink';
import classnames from 'classnames';
import Icon from 'flavours/glitch/components/icon';
import { autoPlayGif } from 'flavours/glitch/initial_state';
import { autoPlayGif, languages as preloadedLanguages, translationEnabled } from 'flavours/glitch/initial_state';
import { decode as decodeIDNA } from 'flavours/glitch/utils/idna';
const textMatchesTarget = (text, origin, host) => {
@ -62,13 +62,56 @@ const isLinkMisleading = (link) => {
return !(textMatchesTarget(text, origin, host) || textMatchesTarget(text.toLowerCase(), origin, host));
};
export default class StatusContent extends React.PureComponent {
class TranslateButton extends React.PureComponent {
static propTypes = {
translation: ImmutablePropTypes.map,
onClick: PropTypes.func,
};
render () {
const { translation, onClick } = this.props;
if (translation) {
const language = preloadedLanguages.find(lang => lang[0] === translation.get('detected_source_language'));
const languageName = language ? language[2] : translation.get('detected_source_language');
const provider = translation.get('provider');
return (
<div className='translate-button'>
<div className='translate-button__meta'>
<FormattedMessage id='status.translated_from_with' defaultMessage='Translated from {lang} using {provider}' values={{ lang: languageName, provider }} />
</div>
<button className='link-button' onClick={onClick}>
<FormattedMessage id='status.show_original' defaultMessage='Show original' />
</button>
</div>
);
}
return (
<button className='status__content__read-more-button' onClick={onClick}>
<FormattedMessage id='status.translate' defaultMessage='Translate' />
</button>
);
}
}
export default @injectIntl
class StatusContent extends React.PureComponent {
static contextTypes = {
identity: PropTypes.object,
};
static propTypes = {
status: ImmutablePropTypes.map.isRequired,
expanded: PropTypes.bool,
collapsed: PropTypes.bool,
onExpandedToggle: PropTypes.func,
onTranslate: PropTypes.func,
media: PropTypes.node,
extraMedia: PropTypes.node,
mediaIcons: PropTypes.arrayOf(PropTypes.string),
@ -77,6 +120,7 @@ export default class StatusContent extends React.PureComponent {
onUpdate: PropTypes.func,
tagLinks: PropTypes.bool,
rewriteMentions: PropTypes.string,
intl: PropTypes.object,
};
static defaultProps = {
@ -249,6 +293,10 @@ export default class StatusContent extends React.PureComponent {
}
}
handleTranslate = () => {
this.props.onTranslate();
}
setContentsRef = (c) => {
this.contentsNode = c;
}
@ -263,18 +311,24 @@ export default class StatusContent extends React.PureComponent {
disabled,
tagLinks,
rewriteMentions,
intl,
} = this.props;
const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden;
const renderTranslate = translationEnabled && this.context.identity.signedIn && this.props.onTranslate && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('contentHtml').length > 0 && status.get('language') !== null && intl.locale !== status.get('language');
const content = { __html: status.get('contentHtml') };
const content = { __html: status.get('translation') ? status.getIn(['translation', 'content']) : status.get('contentHtml') };
const spoilerContent = { __html: status.get('spoilerHtml') };
const lang = status.get('language');
const lang = status.get('translation') ? intl.locale : status.get('language');
const classNames = classnames('status__content', {
'status__content--with-action': parseClick && !disabled,
'status__content--with-spoiler': status.get('spoiler_text').length > 0,
});
const translateButton = renderTranslate && (
<TranslateButton onClick={this.handleTranslate} translation={status.get('translation')} />
);
if (status.get('spoiler_text').length > 0) {
let mentionsPlaceholder = '';
@ -350,11 +404,11 @@ export default class StatusContent extends React.PureComponent {
onMouseLeave={this.handleMouseLeave}
lang={lang}
/>
{!hidden && translateButton}
{media}
</div>
{extraMedia}
</div>
);
} else if (parseClick) {
@ -375,6 +429,7 @@ export default class StatusContent extends React.PureComponent {
onMouseLeave={this.handleMouseLeave}
lang={lang}
/>
{translateButton}
{media}
{extraMedia}
</div>
@ -395,6 +450,7 @@ export default class StatusContent extends React.PureComponent {
onMouseLeave={this.handleMouseLeave}
lang={lang}
/>
{translateButton}
{media}
{extraMedia}
</div>

View file

@ -24,7 +24,9 @@ import {
deleteStatus,
hideStatus,
revealStatus,
editStatus
editStatus,
translateStatus,
undoStatusTranslation,
} from 'flavours/glitch/actions/statuses';
import {
initAddFilter,
@ -198,6 +200,14 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
dispatch(editStatus(status.get('id'), history));
},
onTranslate (status) {
if (status.get('translation')) {
dispatch(undoStatusTranslation(status.get('id')));
} else {
dispatch(translateStatus(status.get('id')));
}
},
onDirect (account, router) {
dispatch(directCompose(account, router));
},

View file

@ -392,8 +392,8 @@ class EmojiPickerDropdown extends React.PureComponent {
<div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
{button || <img
className={classNames('emojione', { 'pulse-loading': active && loading })}
alt='🙂'
src={`${assetHost}/emoji/1f602.svg`}
alt='blobCat emoji'
src={`${assetHost}/blobCat.png`}
/>}
</div>

View file

@ -81,7 +81,7 @@ class Option extends React.PureComponent {
</label>
<div className='poll__cancel'>
<IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
<IconButton disabled={index < pollLimits.min_options} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
</div>
</li>
);

View file

@ -35,7 +35,6 @@ const messages = defineMessages({
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
keyboard_shortcuts: { id: 'navigation_bar.keyboard_shortcuts', defaultMessage: 'Keyboard shortcuts' },
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
lists_subheading: { id: 'column_subheading.lists', defaultMessage: 'Lists' },
misc: { id: 'navigation_bar.misc', defaultMessage: 'Misc' },
menu: { id: 'getting_started.heading', defaultMessage: 'Getting started' },

View file

@ -19,7 +19,6 @@ const messages = defineMessages({
info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' },
show_me_around: { id: 'getting_started.onboarding', defaultMessage: 'Show me around' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' },
info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' },
keyboard_shortcuts: { id: 'navigation_bar.keyboard_shortcuts', defaultMessage: 'Keyboard shortcuts' },
featured_users: { id: 'navigation_bar.featured_users', defaultMessage: 'Featured users' },
});

View file

@ -29,6 +29,7 @@ const messages = defineMessages({
rewrite_mentions_username: { id: 'settings.rewrite_mentions_username', defaultMessage: 'Rewrite with username' },
pop_in_left: { id: 'settings.pop_in_left', defaultMessage: 'Left' },
pop_in_right: { id: 'settings.pop_in_right', defaultMessage: 'Right' },
enter_amount_prompt: { id: 'settings.enter_amount_prompt', defaultMessage: 'Enter an amount' },
});
export default @injectIntl

View file

@ -21,20 +21,21 @@ export default class LocalSettingsPageItem extends React.PureComponent {
})),
settings: ImmutablePropTypes.map.isRequired,
placeholder: PropTypes.string,
number: PropTypes.bool,
disabled: PropTypes.bool,
};
handleChange = e => {
const { target } = e;
const { item, onChange, options, placeholder } = this.props;
const { item, onChange, options, placeholder, number } = this.props;
if (options && options.length > 0) onChange(item, target.value);
else if (placeholder) onChange(item, target.value);
else if (placeholder) onChange(item, number ? parseInt(target.value) : target.value);
else onChange(item, target.checked);
}
render () {
const { handleChange } = this;
const { settings, item, id, options, children, dependsOn, dependsOnNot, placeholder, disabled } = this.props;
const { settings, item, id, options, children, dependsOn, dependsOnNot, placeholder, number, disabled } = this.props;
let enabled = !disabled;
if (dependsOn) {
@ -76,7 +77,7 @@ export default class LocalSettingsPageItem extends React.PureComponent {
</fieldset>
</div>
);
} else if (placeholder) {
} else if (placeholder || number) {
return (
<div className='glitch local-settings__page__item string'>
<label htmlFor={id}>
@ -84,7 +85,7 @@ export default class LocalSettingsPageItem extends React.PureComponent {
<p>
<input
id={id}
type='text'
type={number ? 'number' : 'text'}
value={settings.getIn(item)}
placeholder={placeholder}
onChange={handleChange}

View file

@ -35,6 +35,7 @@ class DetailedStatus extends ImmutablePureComponent {
onOpenMedia: PropTypes.func.isRequired,
onOpenVideo: PropTypes.func.isRequired,
onToggleHidden: PropTypes.func,
onTranslate: PropTypes.func.isRequired,
expanded: PropTypes.bool,
measureHeight: PropTypes.bool,
onHeightChange: PropTypes.func,
@ -116,6 +117,11 @@ class DetailedStatus extends ImmutablePureComponent {
window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
}
handleTranslate = () => {
const { onTranslate, status } = this.props;
onTranslate(status);
}
render () {
const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status;
const { expanded, onToggleHidden, settings, usingPiP, intl } = this.props;
@ -309,6 +315,7 @@ class DetailedStatus extends ImmutablePureComponent {
expanded={expanded}
collapsed={false}
onExpandedToggle={onToggleHidden}
onTranslate={this.handleTranslate}
parseClick={this.parseClick}
onUpdate={this.handleChildUpdate}
tagLinks={settings.get('tag_misleading_links')}

View file

@ -35,7 +35,9 @@ import {
deleteStatus,
editStatus,
hideStatus,
revealStatus
revealStatus,
translateStatus,
undoStatusTranslation,
} from 'flavours/glitch/actions/statuses';
import { initMuteModal } from 'flavours/glitch/actions/mutes';
import { initBlockModal } from 'flavours/glitch/actions/blocks';
@ -56,6 +58,7 @@ import { autoUnfoldCW } from 'flavours/glitch/utils/content_warning';
import { textForScreenReader, defaultMediaVisibility } from 'flavours/glitch/components/status';
import Icon from 'flavours/glitch/components/icon';
import { Helmet } from 'react-helmet';
import { makeCustomEmojiMap } from '../../selectors';
const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
@ -459,6 +462,16 @@ class Status extends ImmutablePureComponent {
this.setState({ isExpanded: !isExpanded, threadExpanded: !isExpanded });
}
handleTranslate = status => {
const { dispatch } = this.props;
if (status.get('translation')) {
dispatch(undoStatusTranslation(status.get('id')));
} else {
dispatch(translateStatus(status.get('id')));
}
}
handleBlockClick = (status) => {
const { dispatch } = this.props;
const account = status.get('account');
@ -690,6 +703,7 @@ class Status extends ImmutablePureComponent {
onReactionRemove={this.handleReactionRemove}
expanded={isExpanded}
onToggleHidden={this.handleToggleHidden}
onTranslate={this.handleTranslate}
domain={domain}
showMedia={this.state.showMedia}
onToggleMediaVisibility={this.handleToggleMediaVisibility}

View file

@ -75,11 +75,9 @@ class LinkFooter extends React.PureComponent {
</p>
<p>
<strong>Mastodon</strong>:
<strong>nyastodon</strong>:
{' '}
<a href='https://joinmastodon.org' target='_blank'><FormattedMessage id='footer.about' defaultMessage='About' /></a>
{' · '}
<a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='footer.get_app' defaultMessage='Get the app' /></a>
<a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='footer.about' defaultMessage='About' /></a>
{' · '}
<Link to='/keyboard-shortcuts'><FormattedMessage id='footer.keyboard_shortcuts' defaultMessage='Keyboard shortcuts' /></Link>
{' · '}
@ -87,6 +85,8 @@ class LinkFooter extends React.PureComponent {
{' · '}
v{version}
</p>
<p>be gay do crime uwu</p>
</div>
);
}

View file

@ -56,7 +56,7 @@ class NavigationPanel extends React.Component {
)}
{showTrends ? (
<ColumnLink transparent to='/explore' icon='hashtag' text={intl.formatMessage(messages.explore)} />
<ColumnLink transparent to={(signedIn || timelinePreview) ? '/explore' : '/explore/tags'} icon='hashtag' text={intl.formatMessage(messages.explore)} />
) : (
<ColumnLink transparent to='/search' icon='search' text={intl.formatMessage(messages.search)} />
)}

View file

@ -144,10 +144,11 @@ const PageSix = ({ admin, domain }) => {
<p>
<FormattedMessage
id='onboarding.page_six.github'
defaultMessage='{domain} runs on Glitchsoc. Glitchsoc is a friendly {fork} of {Mastodon}. Glitchsoc is fully compatible with all Mastodon apps and instances. Glitchsoc is free open-source software. You can report bugs, request features, or contribute to the code on {github}.'
defaultMessage='{domain} runs on Catstodon, which is a {fork} of {glitchsoc}, which, in turn, is a friendly {fork} of {Mastodon}. It is fully compatible with all Mastodon apps and instances. Catstodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.'
values={{
domain,
fork: <a href='https://en.wikipedia.org/wiki/Fork_(software_development)' target='_blank' rel='noopener'>fork</a>,
glitchsoc: <a href='https://github.com/glitch-soc/mastodon' target='_blank' rel='noopener'>Glitchsoc</a>,
Mastodon: <a href='https://github.com/mastodon/mastodon' target='_blank' rel='noopener'>Mastodon</a>,
github: <a href={source_url} target='_blank' rel='noopener'>GitHub</a>,
}}

View file

@ -65,6 +65,7 @@ import Header from './components/header';
// Dummy import, to make sure that <Status /> ends up in the application bundle.
// Without this it ends up in ~8 very commonly used bundles.
import '../../../glitch/components/status';
import { timelinePreview } from 'flavours/glitch/initial_state';
const messages = defineMessages({
beforeUnload: { id: 'ui.beforeunload', defaultMessage: 'Your draft will be lost if you leave Mastodon.' },
@ -75,7 +76,6 @@ const mapStateToProps = state => ({
hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0,
hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) && state.getIn(['compose', 'media_attachments']).size < 4,
layout: state.getIn(['meta', 'layout']),
layout_local_setting: state.getIn(['local_settings', 'layout']),
isWide: state.getIn(['local_settings', 'stretch']),
navbarUnder: state.getIn(['local_settings', 'navbar_under']),
@ -177,7 +177,7 @@ class SwitchingColumnsArea extends React.PureComponent {
}
} else if (singleUserMode && owner && initialState?.accounts[owner]) {
redirect = <Redirect from='/' to={`/@${initialState.accounts[owner].username}`} exact />;
} else if (showTrends) {
} else if (showTrends && (signedIn || timelinePreview)) {
redirect = <Redirect from='/' to='/explore' exact />;
} else {
redirect = <Redirect from='/' to='/about' exact />;

View file

@ -81,6 +81,7 @@
* @property {boolean=} use_pending_items
* @property {string} version
* @property {number} visible_reactions
* @property {boolean} translation_enabled
* @property {object} local_settings
*/
@ -125,6 +126,7 @@ export const mascot = getMeta('mascot');
export const maxReactions = (initialState && initialState.max_reactions) || 1;
export const me = getMeta('me');
export const movedToAccountId = getMeta('moved_to_account_id');
export const visibleReactions = getMeta('visible_reactions');
export const owner = getMeta('owner');
export const profile_directory = getMeta('profile_directory');
export const reduceMotion = getMeta('reduce_motion');
@ -141,6 +143,7 @@ export const useBlurhash = getMeta('use_blurhash');
export const usePendingItems = getMeta('use_pending_items');
export const version = getMeta('version');
export const visibleReactions = getMeta('visible_reactions');
export const translationEnabled = getMeta('translation_enabled');
export const languages = initialState?.languages;
// Glitch-soc-specific settings

View file

@ -1,6 +1,9 @@
import inherited from 'mastodon/locales/de.json';
const messages = {
'getting_started.open_source_notice': 'Catstodon ist quelloffene Software, zudem ein Fork von {glitchsoc}, was wiederum ein Fork von {Mastodon} ist. Du kannst auf GitHub unter {github} dazu beitragen oder Probleme melden.',
'onboarding.page_six.github': '{domain} läuft auf Catstodon, was ein Fork ({fork}) von {glitchsoc} ist, welches wiederum ein Fork ({fork}) von {Mastodon} ist. It is fully compatible with all Mastodon apps and instances. Catstodon ist quelloffene Software. Du kannst auf GitHub unter {github} Probleme melden, nach neuen Funktionen fragen oder zum Code beitragen.',
'notification.reaction': '{name} hat auf deinen Beitrag reagiert',
'notifications.column_settings.reaction': 'Reaktionen:',

View file

@ -1,7 +1,7 @@
import inherited from 'mastodon/locales/en.json';
const messages = {
'getting_started.open_source_notice': 'Glitchsoc is free open source software forked from {Mastodon}. You can contribute or report issues on GitHub at {github}.',
'getting_started.open_source_notice': 'Catstodon is open source software, a friendly fork of {glitchsoc}, which in turn is a fork of {Mastodon}. You can contribute or report issues on GitHub at {github}.',
'layout.auto': 'Auto',
'layout.current_is': 'Your current layout is:',
'layout.desktop': 'Desktop',
@ -10,7 +10,7 @@ const messages = {
'getting_started.onboarding': 'Show me around',
'onboarding.page_one.federation': '{domain} is an \'instance\' of Mastodon. Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.',
'onboarding.page_one.welcome': 'Welcome to {domain}!',
'onboarding.page_six.github': '{domain} runs on Glitchsoc. Glitchsoc is a friendly {fork} of {Mastodon}, and is compatible with any Mastodon instance or app. Glitchsoc is entirely free and open-source. You can report bugs, request features, or contribute to the code on {github}.',
'onboarding.page_six.github': '{domain} runs on Catstodon, which is a {fork} of {glitchsoc}, which, in turn, is a friendly {fork} of {Mastodon}. It is fully compatible with all Mastodon apps and instances. Catstodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.',
'settings.auto_collapse': 'Automatic collapsing',
'settings.auto_collapse_all': 'Everything',
'settings.auto_collapse_lengthy': 'Lengthy toots',

View file

@ -13,7 +13,6 @@ const messages = {
'compose.attach': 'Adjuntar...',
'favourite_modal.combo': 'Puedes presionar {combo} para omitir esto la próxima vez',
'getting_started.onboarding': 'Paseo inicial',
'getting_started.open_source_notice': 'Glitchsoc es software libre y gratuito bifurcado de {Mastodon}. Puedes contribuir o reportar errores en GitHub en {github}.',
'home.column_settings.show_direct': 'Mostrar mensajes directos',
'layout.auto': 'Automático',
'layout.current_is': 'Tu diseño actual es:',
@ -34,7 +33,6 @@ const messages = {
'notifications.marked_clear': 'Limpiar notificaciones seleccionadas',
'onboarding.page_one.federation': '{domain} es una "instancia" de Mastodon. Mastodon es una red de servidores independientes que se unen para crear una red social más grande. A estos servidores los llamamos instancias.',
'onboarding.page_one.welcome': '¡Bienvenidx a {domain}!',
'onboarding.page_six.github': '{domain} usa Glitchsoc. Glitchsoc es una bifurcación {fork} amigable de {Mastodon}, y es compatible con cualquier instancia o aplicación de Mastodon. Glitchsoc es completamente gratuito y de código abierto. Puedes reportar errores, solicitar funciones o contribuir al código en {github}.',
'settings.always_show_spoilers_field': 'Siempre mostrar el campo de advertencia de contenido',
'settings.auto_collapse_all': 'Todo',
'settings.auto_collapse_lengthy': 'Toots largos',

View file

@ -1,7 +1,6 @@
import inherited from 'mastodon/locales/ja.json';
const messages = {
'getting_started.open_source_notice': 'Glitchsocは{Mastodon}によるフリーなオープンソースソフトウェアです。誰でもGitHub{github})から開発に參加したり、問題を報告したりできます。',
'layout.auto': '自動',
'layout.current_is': 'あなたの現在のレイアウト:',
'layout.desktop': 'デスクトップ',
@ -12,7 +11,6 @@ const messages = {
'getting_started.onboarding': '解説を表示',
'onboarding.page_one.federation': '{domain}はMastodonのインスタンスです。Mastodonとは、独立したサーバが連携して作るソーシャルネットワークです。これらのサーバーをインスタンスと呼びます。',
'onboarding.page_one.welcome': '{domain}へようこそ!',
'onboarding.page_six.github': '{domain}はGlitchsocを使用しています。Glitchsocは{Mastodon}のフレンドリーな{fork}で、どんなMastodonアプリやインスタンスとも互換性があります。Glitchsocは完全に無料で、オープンソースです。{github}でバグ報告や機能要望あるいは貢獻をすることが可能です。',
'settings.always_show_spoilers_field': '常にコンテンツワーニング設定を表示する(指定がない場合は通常投稿)',
'settings.auto_collapse': '自動折りたたみ',
'settings.auto_collapse_all': 'すべて',

View file

@ -52,7 +52,6 @@ const messages = {
'endorsed_accounts_editor.endorsed_accounts': '추천하는 계정들',
'favourite_modal.combo': '다음엔 {combo}를 눌러 건너뛸 수 있습니다',
'getting_started.onboarding': '둘러보기',
'getting_started.open_source_notice': '글리치는 {Mastodon}의 자유 오픈소스 포크버전입니다. {github}에서 문제를 리포팅 하거나 기여를 할 수 있습니다.',
'home.column_settings.advanced': '고급',
'home.column_settings.filter_regex': '정규표현식으로 필터',
'home.column_settings.show_direct': 'DM 보여주기',
@ -93,7 +92,6 @@ const messages = {
'onboarding.page_six.almost_done': '거의 다 되었습니다…',
'onboarding.page_six.appetoot': '본 아페툿!',
'onboarding.page_six.apps_available': 'iOS, 안드로이드, 그리고 다른 플랫폼들을 위한 {apps}이 존재합니다.',
'onboarding.page_six.github': '{domain}은 글리치를 통해 구동 됩니다. 글리치는 {Mastodon}의 {fork}입니다, 그리고 어떤 마스토돈 인스턴스나 앱과도 호환 됩니다. 글리치는 완전한 자유 오픈소스입니다. {github}에서 버그를 리포팅 하거나, 기능을 제안하거나, 코드를 기여할 수 있습니다.',
'onboarding.page_six.guidelines': '커뮤니티 가이드라인',
'onboarding.page_six.read_guidelines': '{domain}의 {guidelines}을 읽어주세요!',
'onboarding.page_six.various_app': '모바일 앱',

View file

@ -1,7 +1,6 @@
import inherited from 'mastodon/locales/pl.json';
const messages = {
'getting_started.open_source_notice': 'Glitchsoc jest wolnym i otwartoźródłowym forkiem oprogramowania {Mastodon}. Możesz współtworzyć projekt lub zgłaszać błędy na GitHubie pod adresem {github}.',
'layout.auto': 'Automatyczny',
'layout.current_is': 'Twój obecny układ to:',
'layout.desktop': 'Desktopowy',
@ -11,7 +10,6 @@ const messages = {
'getting_started.onboarding': 'Rozejrzyj się',
'onboarding.page_one.federation': '{domain} jest \'instancją\' Mastodona. Mastodon to sieć działających niezależnie serwerów tworzących jedną sieć społecznościową. Te serwery nazywane są instancjami.',
'onboarding.page_one.welcome': 'Witamy na {domain}!',
'onboarding.page_six.github': '{domain} jest oparty na Glitchsoc. Glitchsoc jest {forkiem} {Mastodon}a kompatybilnym z każdym klientem i aplikacją Mastodona. Glitchsoc jest całkowicie wolnym i otwartoźródłowym oprogramowaniem. Możesz zgłaszać błędy i sugestie funkcji oraz współtworzyć projekt na {github}.',
'settings.auto_collapse': 'Automatyczne zwijanie',
'settings.auto_collapse_all': 'Wszystko',
'settings.auto_collapse_lengthy': 'Długie wpisy',

View file

@ -53,7 +53,6 @@ const messages = {
'endorsed_accounts_editor.endorsed_accounts': '推荐用户',
'favourite_modal.combo': '下次你可以按 {combo} 跳过这个',
'getting_started.onboarding': '参观一下',
'getting_started.open_source_notice': 'Glitchsoc 是由 {Mastodon} 分叉出来的免费开源软件。你可以在 GitHub 上贡献或报告问题,地址是 {github}。',
'home.column_settings.advanced': '高级',
'home.column_settings.filter_regex': '按正则表达式过滤',
'home.column_settings.show_direct': '显示私信',
@ -94,7 +93,6 @@ const messages = {
'onboarding.page_six.almost_done': '就快完成了...',
'onboarding.page_six.appetoot': '尽情享用吧!',
'onboarding.page_six.apps_available': '有适用于 iOS、Android 和其他平台的应用程序。',
'onboarding.page_six.github': '{domain} 在 Glitchsoc 上运行。Glitchsoc 是 {Mastodon} 的一个友好 {fork},与任何 Mastodon 实例或应用兼容。Glitchsoc 是完全免费和开源的。你可以在 {github} 上报告错误、请求功能或贡献代码。',
'onboarding.page_six.guidelines': '社区准则',
'onboarding.page_six.read_guidelines': '请阅读 {domain} 的 {guidelines}',
'onboarding.page_six.various_app': '应用程序',
@ -198,4 +196,4 @@ const messages = {
'web_app_crash.title': '抱歉Mastodon 出了点问题。',
};
export default Object.assign({}, inherited, messages);
export default Object.assign({}, inherited, messages);

View file

@ -60,6 +60,7 @@ import { me, defaultContentType } from 'flavours/glitch/initial_state';
import { overwrite } from 'flavours/glitch/utils/js_helpers';
import { unescapeHTML } from 'flavours/glitch/utils/html';
import { recoverHashtags } from 'flavours/glitch/utils/hashtag';
import { pollLimits } from 'flavours/glitch/initial_state';
const totalElefriends = 3;
@ -127,7 +128,7 @@ const initialState = ImmutableMap({
});
const initialPoll = ImmutableMap({
options: ImmutableList(['', '']),
options: ImmutableList(new Array(pollLimits.min_options).fill('')),
expires_in: 24 * 3600,
multiple: false,
});

View file

@ -18,6 +18,8 @@ import {
STATUS_REVEAL,
STATUS_HIDE,
STATUS_COLLAPSE,
STATUS_TRANSLATE_SUCCESS,
STATUS_TRANSLATE_UNDO,
STATUS_FETCH_REQUEST,
STATUS_FETCH_FAIL,
} from 'flavours/glitch/actions/statuses';
@ -129,6 +131,10 @@ export default function statuses(state = initialState, action) {
return state.setIn([action.id, 'collapsed'], action.isCollapsed);
case TIMELINE_DELETE:
return deleteStatus(state, action.id, action.references);
case STATUS_TRANSLATE_SUCCESS:
return state.setIn([action.id, 'translation'], fromJS(action.translation));
case STATUS_TRANSLATE_UNDO:
return state.deleteIn([action.id, 'translation']);
default:
return state;
}

View file

@ -15,7 +15,7 @@
display: block;
font-size: 15px;
line-height: 20px;
color: $ui-highlight-color;
color: $highlight-text-color;
border: 0;
background: transparent;
padding: 0;

View file

@ -206,15 +206,13 @@
}
}
.status__content__edited-label {
display: block;
cursor: default;
.translate-button {
margin-top: 16px;
font-size: 15px;
line-height: 20px;
padding: 0;
padding-top: 8px;
display: flex;
justify-content: space-between;
color: $dark-text-color;
font-weight: 500;
}
.status__content__spoiler-link {

View file

@ -0,0 +1,4 @@
@import 'homogay/variables';
@import 'index';
@import 'homogay/diff';

View file

@ -0,0 +1,109 @@
// turn the timed line into a highly addictive dopamine slot machine
// fav button
.no-reduce-motion .icon-button.star-icon {
&.deactivate {
& > .fa-star {
animation: none;
}
}
&.activate {
& > .fa-star {
animation: spring-rotate-in 1s cubic-bezier(.2, 0, .4, 1);
}
}
}
@keyframes spring-rotate-in {
0% {
transform: rotate(0deg);
}
20% {
transform: rotate(20deg);
}
60% {
transform: rotate(-380deg);
}
85% {
transform: rotate(-355deg);
}
100% {
transform: rotate(-360deg);
}
}
@keyframes spring-rotate-out {
0% {
transform: rotate(-360deg);
}
60% {
transform: rotate(20deg);
}
85% {
transform: rotate(-5deg);
}
100% {
transform: rotate(0deg);
}
}
// bookmark button
.no-reduce-motion .icon-button {
& > .fa-bookmark {
transform: translateY(0);
animation: none;
}
&.active > .fa-bookmark {
animation: bookmark-save .6s cubic-bezier(.2, 0, .4, 1);
}
}
@keyframes bookmark-save {
0% {
transform: translateY(0);
}
40% {
transform: translateY(-3px);
}
60% {
transform: translateY(4px);
}
100% {
transform: translateY(0);
}
}
// collapse button at the top right of all posts
.no-reduce-motion .status__collapse-button {
&.activate > .fa-angle-double-up {
animation: spring-flip-in .5s cubic-bezier(.2, 0, .4, 1);
}
&.deactivate > .fa-angle-double-up {
animation: spring-flip-out .5s cubic-bezier(.2, 0, .4, 1);
}
}
@keyframes spring-flip-in {
0% {
transform: rotate(0deg);
}
60% {
transform: rotate(-190deg);
}
85% {
transform: rotate(-175deg);
}
100% {
transform: rotate(-180deg);
}
}
@keyframes spring-flip-out {
0% {
transform: rotate(-180deg);
}
60% {
transform: rotate(10deg);
}
85% {
transform: rotate(-5deg)
}
100% {
transform: rotate(0deg);
}
}

View file

@ -0,0 +1,161 @@
body {
background: darken($ui-base-color, 5%);
}
// hashtags in primary color
.status__content a {
color: $highlight-text-color;
}
// compose panel
.compose-panel .autosuggest-textarea label .autosuggest-textarea__textarea,
.compose-form .autosuggest-input label .autosuggest-textarea__textarea,
.compose-form__buttons-wrapper,
.compose-form__warning,
.spoiler-input input,
.compose-form__modifiers,
.reply-indicator {
background: lighten($ui-base-color, 4%);
color: $primary-text-color;
}
.compose-form .autosuggest-textarea label .autosuggest-textarea__textarea {
border-top-left-radius: $border-radius;
border-top-right-radius: $border-radius;
}
.compose-form__buttons-wrapper {
border-bottom-left-radius: $border-radius;
border-bottom-right-radius: $border-radius;
}
.compose-panel .compose-form__autosuggest-wrapper {
background-color: #fff0; // transparent background so it doesn't mess with border-radius
}
.poll__option input[type="text"],
.compose-form__poll-wrapper select {
border-color: $ui-base-lighter-color;
}
.autosuggest-textarea__suggestions {
background: lighten($ui-base-color, 4%);
}
.autosuggest-textarea__suggestions__item.selected,
.autosuggest-textarea__suggestions__item:hover {
background: $ui-highlight-color;
}
.emoji-mart-bar:first-child {
background: lighten($ui-base-color, 7%);
border-bottom-color: #fff0;
border-top-left-radius: $border-radius;
border-top-right-radius: $border-radius;
}
.emoji-mart-anchor:not(.emoji-mart-anchor-selected) {
color: $ui-base-lighter-color;
}
.search__input {
background: lighten($ui-base-color, 4%);
}
// dropdowns
.dropdown-menu,
.dropdown-menu__item a,
.dropdown-menu__item button {
background: $ui-base-lighter-color;
}
.dropdown-menu__arrow.top {
border-top-color: $ui-base-lighter-color;
}
.dropdown-menu__arrow.bottom {
border-bottom-color: $ui-base-lighter-color;
}
// general modals
.modal-root__modal {
background: $ui-base-color;
}
.report-modal__container {
border-top-color: $ui-base-lighter-color;
}
.report-modal__comment {
border-right-color: $ui-base-lighter-color;
}
.report-modal__comment .setting-text {
background: $ui-base-color;
}
.boost-modal__action-bar,
.doodle-modal__action-bar,
.confirmation-modal__action-bar,
.mute-modal__action-bar,
.block-modal__action-bar {
background: lighten($ui-base-color, 5%);
}
.confirmation-modal__secondary-button,
.confirmation-modal__cancel-button,
.mute-modal__cancel-button,
.block-modal__cancel-button {
color: $primary-text-color;
&:hover {
color: $ui-highlight-color;
}
}
// app settings modal
.glitch.local-settings {
background: $ui-base-color;
}
.glitch.local-settings__navigation,
.glitch.local-settings__navigation__item {
background: lighten($ui-base-color, 4%);
}
.glitch.local-settings__navigation__item {
border-bottom-color: $ui-base-lighter-color;
}
// border radius
.button,
.dropdown-menu,
.account__avatar,
.search__input,
.spoiler-input input,
.status-card,
.language-dropdown__dropdown,
.privacy-dropdown__dropdown,
.poll__option input[type="text"],
.compose-form__poll-wrapper select,
.account__header__tabs__buttons .icon-button,
.emoji-picker-dropdown__menu,
.emoji-mart-search input,
.boost-modal,
.report-modal,
.block-modal,
.confirmation-modal,
.actions-modal,
.mute-modal,
.compare-history-modal {
border-radius: $border-radius;
}
.dropdown-menu {
padding-top: $border-radius;
padding-bottom: $border-radius;
}
.emoji-mart-scroll {
margin-bottom: $border-radius;
padding-bottom: 0;
}
.column-header {
border-top-left-radius: $border-radius;
border-top-right-radius: $border-radius;
}
.column > .scrollable {
border-bottom-left-radius: $border-radius;
border-bottom-right-radius: $border-radius;
}
// timed line
.status {
border-bottom: 0; // no separators between posts
}
.media-gallery__item.letterbox {
background: none; // remove the black background from letterbox images
}
@import 'animations';

View file

@ -0,0 +1,53 @@
// Commonly used web colors
$black: #000000;
$white: #ffffff;
$success-green: #5fe43d;
$error-red: #c9343b;
$warning-red: #c96932;
$gold-star: #e4ba3d;
$red-bookmark: $success-green;
// Values from the classic Mastodon UI
$classic-base-color: #150f21;
$classic-primary-color: #d4b6cb;
$classic-secondary-color: #eaddf4;
$classic-highlight-color: #de18a3;
// Variables for defaults in UI
$base-shadow-color: $black !default;
$base-overlay-background: $black !default;
$base-border-color: $white !default;
$simple-background-color: lighten($classic-base-color, 7%) !default;
$valid-value-color: $success-green !default;
$error-value-color: $error-red !default;
// Tell UI to use selected colors
$ui-base-color: $classic-base-color !default;
$ui-base-lighter-color: #5f4a6e !default;
$ui-primary-color: $classic-primary-color !default;
$ui-secondary-color: $classic-secondary-color !default;
$ui-highlight-color: $classic-highlight-color !default;
// Variables for texts
$primary-text-color: $classic-secondary-color !default;
$darker-text-color: $ui-primary-color !default;
$dark-text-color: $ui-base-lighter-color !default;
$secondary-text-color: $ui-secondary-color !default;
$highlight-text-color: lighten($ui-highlight-color, 8%) !default;
$action-button-color: $ui-base-lighter-color !default;
$passive-text-color: $gold-star !default;
$active-passive-text-color: $success-green !default;
// For texts on inverted backgrounds
$inverted-text-color: $primary-text-color !default; // we don't do inverted backgrounds
$lighter-text-color: $ui-base-lighter-color !default;
$light-text-color: $ui-primary-color !default;
// Variables for components
$media-modal-media-max-width: 100%;
// put margins on top and bottom of image to avoid the screen covered by image.
$media-modal-media-max-height: 80%;
$border-radius: 8px;

View file

@ -0,0 +1,332 @@
@import 'index';
/* customize ya stuff */
:root {
--border-radius: 5px;
/* rgb for transparency to work */
--text-color: 217, 225, 232;
--text-color-secondary: 96, 105, 132; /* less bright, for unimportant bits */
--background-color: 18, 18, 37;
--background-color-brighter: 22, 22, 47;
--app-background-color: 8, 8, 17; /* used only for the VERY background in the back */
--accent-color: 39, 183, 145;
--accent-color-secondary: 62, 91, 84; /* less saturated ver of --accent-color */
--accent-color-bright: 92, 193, 162;
}
.account__avatar-overlay-base, .account__avatar-overlay-overlay, .account__avatar {
border-radius: var(--border-radius);
}
/* roundening shenanigans */
.drawer > div, nav, .search, .drawer__header a, .drawer--header a, .search__input {
border-radius: var(--border-radius) !important;
}
.column-header, .column-back-button, .navigation-panel .column-link:nth-child(1), .navigation-panel .column-link:nth-child(10), .navigation-bar {
border-radius: var(--border-radius) var(--border-radius) 0px 0px;
}
.column > .scrollable, .getting-started, .navigation-panel .column-link:nth-child(8), .navigation-panel .column-link:nth-child(11) {
border-radius: 0px 0px var(--border-radius) var(--border-radius);
}
/* standard fg/bg color changes */
.drawer__inner, .drawer__inner__mastodon, .drawer__header, .drawer--header, .actions-modal, .block-modal, .boost-modal, .confirmation-modal, .mute-modal, .report-modal, article, .getting-started, .column-subheading, .column-link, .column-subheading, .column-link, .emoji-mart-scroll, .emoji-mart-search, .emoji-mart-category-label > span, .emoji-picker-dropdown__menu, .scrollable, .empty-column-indicator, .column-inline-form, .dropdown-menu, .dropdown-menu__item a, .account__header__fields dt, .search-popout, .confirmation-modal__action-bar, .reactions-bar__item, .emoji-picker-dropdown__modifiers__menu, .content-wrapper, .sidebar-wrapper--empty, .regeneration-indicator, .tabs-bar, .navigation-bar, .trends__header, .modal-layout {
background-color: rgb(var(--background-color)) !important;
color: rgb(var(--text-color)) !important;
}
.glitch.local-settings__navigation, .glitch.local-settings__navigation__item, .glitch.local-settings__page, .glitch.local-settings {
background-color: rgb(var(--background-color));
color: rgb(var(--text-color));
}
.modal-layout, .modal-layout__mastodon > * {
background-image: none;
}
.account__section-headline a.active::after, .account__section-headline button.active::after, .notification__filter-bar a.active::after, .notification__filter-bar button.active::after, .account__section-headline a.active::after, .account__section-headline a.active::before, .account__section-headline button.active::after, .account__section-headline button.active::before, .notification__filter-bar a.active::after, .notification__filter-bar a.active::before, .notification__filter-bar button.active::after, .notification__filter-bar button.active::before {
border-color: transparent transparent rgb(var(--background-color));
}
.dropdown-menu__arrow {
border-bottom-color: rgb(var(--background-color)) !important;
}
.dropdown-menu__arrow.top {
border-top-color: rgb(var(--background-color)) !important;
}
.reply-indicator__content, .status__content, .reply-indicator__display-name, .privacy-dropdown__option__icon, .composer--options--dropdown--content--item .icon, .composer--reply > .content {
color: rgb(var(--text-color)) !important;
}
html {
scrollbar-color: rgb(var(--background-color-brighter)) rgba(0,0,0,0.1);
}
.tabs-bar__wrapper {
background: rgb(var(--app-background-color));
}
.column-header, .column-header__button, .account__section-headline, .notification__filter-bar > button, .emoji-mart-bar, .column-back-button, .column-header__back-button, .announcements, .column-header__collapsible-inner, .status.status-direct:not(.read), .notification__filter-bar, .glitch.local-settings__page {
background-color: rgb(var(--background-color-brighter)) !important;
border-bottom: none;
}
.reply-indicator, .emoji-picker-dropdown__modifiers__menu button:hover, .compose-form .compose-form__buttons-wrapper, .composer--options-wrapper, .compose-form__poll-wrapper select, .flash-message, .card__bar, .card > a:hover .card__bar, .glitch.local-settings__navigation__item:hover {
background-color: rgb(var(--background-color-brighter));
}
.columns-area, .app-body, .getting-started__wrapper {
background-color: rgb(var(--app-background-color));
}
.privacy-dropdown__option__content strong, .composer--options--dropdown--content strong, .character-counter, .report-modal__comment .setting-text-label, .compose-form__poll-wrapper select {
color: rgb(var(--text-color)) !important;
}
input, textarea, .compose-form__modifiers, .privacy-dropdown__dropdown, .composer--options--dropdown--content, .privacy-dropdown__value {
background-color: rgb(var(--background-color-brighter)) !important;
color: rgb(var(--text-color)) !important;
}
.compose-form__buttons-wrapper, .admin-wrapper .sidebar-wrapper__inner, .admin-wrapper .sidebar ul a:hover, .admin-wrapper .sidebar ul a, .admin-wrapper .sidebar ul a.selected, .account__disclaimer, .account__action-bar-links {
background-color: rgb(var(--background-color-brighter));
}
.detailed-status, .detailed-status__action-bar, .account__header__bar, .focusable:focus {
background-color: rgb(var(--background-color-brighter)) !important;
border-bottom: none;
border-top: none;
}
.status.collapsed .status__content::after {
background: linear-gradient(rgba(var(--background-color),0), rgba(var(--background-color),0)) !important;
}
/* accent color changes */
.button, .react-toggle--checked .react-toggle-track, .react-toggle--checked:hover .react-toggle-track, .react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track, .button.logo-button, .emoji-mart-anchor-bar, .loading-bar, .icon-with-badge__badge, .video-player__volume__current, .video-player__volume__handle, .upload-progress__tracker, .video-player__seek__buffer, .video-player__seek__progress, .floating-action-button {
background-color: rgb(var(--accent-color));
}
.react-toggle--checked .react-toggle-thumb, .compose-form__sensitive-button .checkbox, .filters .filter-subset a.selected, .account__action-bar__tab.active, .tabs-bar__link.active, .notification.unread::before, .status.unread::before {
border-color: rgb(var(--accent-color));
}
.text-icon-button, .icon-button.inverted, button.inverted:hover, .icon-button, .icon-button:hover, .status__action-bar__counter__label, .text-icon-button:active, .text-icon-button:focus, .text-icon-button:hover, .icon-button.disabled, .composer--options--dropdown.open > .value {
color: rgb(var(--accent-color-secondary));
}
.status__info__icons i {
color: rgb(var(--accent-color-secondary)) !important;
}
.status__content__spoiler-link {
background-color: rgb(var(--accent-color-secondary)) !important;
}
.column-header__wrapper.active::before {
background: radial-gradient(ellipse, rgba(var(--accent-color),.23) 0%, rgba(var(--accent-color),0) 60%);
}
.column-header__wrapper.active {
box-shadow: 0 1px 0 rgba(var(--accent-color),.3);
}
.compose-form__sensitive-button .checkbox.active, .poll__chart.leading {
border-color: rgb(var(--accent-color));
background-color: rgb(var(--accent-color));
}
.poll__chart {
background-color: rgb(var(--accent-color-secondary));
}
.column-header.active .column-header__icon {
text-shadow: 0 0 10px rgba(var(--accent-color),.4);
}
.text-icon-button:active, .text-icon-button:focus, .text-icon-button:hover, .drawer__header a:hover, .drawer--header a:hover, .drawer--header a:focus, .icon-button:hover, .reactions-bar__item:hover {
background-color: rgba(var(--accent-color-secondary), .1);
}
.icon-button.inverted:active, .icon-button.inverted:focus, .icon-button.inverted:hover, .reactions-bar__item.active {
background-color: rgba(var(--accent-color-secondary), .25);
color: rgb(var(--accent-color-secondary));
}
.button:active, .button:focus, .button:hover, .admin-wrapper .sidebar ul .simple-navigation-active-leaf a:hover, .simple_form .block-button:hover, .simple_form .button:hover, .simple_form button:hover, .button.logo-button:active, .button.logo-button:focus, .button.logo-button:hover, .floating-action-button:hover, .glitch.local-settings__navigation__item.active:hover {
background-color: rgb(var(--accent-color-bright));
}
.privacy-dropdown__option.active, .composer--options--dropdown--content--item.active, .privacy-dropdown__option:hover, .composer--options--dropdown--content--item:hover, .privacy-dropdown__option.active:hover, .composer--options--dropdown--content.active:hover, .admin-wrapper .sidebar ul .simple-navigation-active-leaf a, .simple_form .block-button, .simple_form .button, .simple_form button, .simple_form .block-button:active, .simple_form .block-button:focus, .simple_form .button:active, .simple_form .button:focus, .simple_form button:active, .simple_form button:focus, .composer--options--dropdown.open > .value, .glitch.local-settings__navigation__item.active {
background-color: rgb(var(--accent-color));
}
.status__info__icons .icon-button.active i, .tabs-bar__link.active, .status__content a {
color: rgb(var(--accent-color)) !important;
}
.trends__item__sparkline path:last-child {
stroke: rgb(var(--accent-color)) !important;
}
.trends__item__sparkline path:first-child {
fill: rgb(var(--accent-color-secondary)) !important;
}
a.u-url, .status-link, .column-header__back-button, .status__content__read-more-button, .column-header.active .column-header__icon, .column-link.active, .account__section-headline a.active, .account__section-headline button.active, .notification__filter-bar a.active, .notification__filter-bar button.active, .account__header__content a, .account__header__bio .account__header__fields a, .reactions-bar__item.active .reactions-bar__item__count, .emoji-mart-anchor-selected, .reply-indicator__content a, .compose-form .compose-form__warning a, .text-icon-button.active, .icon-button.inverted.active, .drawer__tab:hover, .icon-button.active, .column-back-button, .filters .filter-subset a.selected, .admin-wrapper .content .muted-hint a, body .muted-hint a, .table a, .notification__message .fa, .drawer--header a:hover, .drawer--header a:focus {
color: rgb(var(--accent-color)) !important;
}
/* fixes */
/* boost hack, v2 */
/* https://codepen.io/sosuke/pen/Pjoqqp */
button.icon-button i.fa-retweet {
filter: brightness(0) saturate(100%) invert(31%) sepia(28%) saturate(388%) hue-rotate(115deg) brightness(94%) contrast(90%); /* accent-color-secondary */
color: transparent !important;
}
button.icon-button.active i.fa-retweet {
filter: brightness(0) saturate(100%) invert(57%) sepia(61%) saturate(481%) hue-rotate(114deg) brightness(93%) contrast(91%); /* accent-color */
}
button.icon-button.disabled i.fa-retweet, button.icon-button.disabled i.fa-lock {
filter: brightness(0) saturate(100%) invert(31%) sepia(28%) saturate(388%) hue-rotate(115deg) brightness(60%) contrast(90%); /* accent-color-secondary with brightness set to 50% */
}
.load-more:hover, .mbstobon-2 .drawer__inner__mastodon, .mbstobon-1 .drawer__inner__mastodon, .mbstobon-0 .drawer__inner__mastodon {
background: inherit;
}
.account__action-bar__tab, .account__action-bar {
border: none;
}
.notification__filter-bar, .account__header__bar, .admin-wrapper .content-heading, .admin-wrapper .content h4, .tabs-bar__link:not(.active) {
border-bottom: none;
}
.dropdown-menu__separator, hr {
opacity: 0;
}
.compose-form .autosuggest-textarea__textarea, .compose-form .spoiler-input__input, .compose-panel .compose-form__autosuggest-wrapper, .mbstobon-3 .drawer__inner__mastodon {
background: transparent;
}
.status, .account, .account__header__fields dl, .account__header__fields, .account__header__bio .account__header__fields, .glitch.local-settings__navigation__item {
border-top: none;
border-bottom: none;
}
.report-modal__container, .report-modal__comment, .report-modal__comment .setting-text__wrapper {
border-color: rgba(0, 0, 0, 0) !important;
}
.drawer__inner__mastodon {
background: inherit;
}
/* misc */
.column-link:hover, .dropdown-menu__item a:active, .dropdown-menu__item a:focus, .dropdown-menu__item a:hover, header strong.display-name__html {
color: #fff !important;
}
.notification__filter-bar button.active, .account__section-headline .active {
border-bottom: 3px solid rgb(var(--accent-color));
}
.notification__filter-bar button:not(.active):hover {
top: -3px;
}
.account__section-headline a.active::after, .account__section-headline a.active::before {
display: none;
}
.account__header__extra__links a:hover {
text-decoration: underline;
}
.account__section-headline a:hover, .confirmation-modal__cancel-button span {
color: #fff;
}
.notification__filter-bar button.active::after {
opacity: 0;
}
.notification__filter-bar button.active::before {
opacity: 0;
}
.column-link__badge, .column-subheading {
background-color: rgb(var(--accent-color));
animation-name: flash;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-direction: alternate-reverse;
}
@keyframes flash {
from {background-color: rgb(var(--accent-color));}
to {background-color: rgb(var(--accent-color-secondary));}
}
.reply-indicator {
max-height: 38px;
overflow-y: hidden;
transition: max-height 1s;
}
.reply-indicator:hover {
max-height: 100%;
}
.reply-indicator:before {
content: 'Replying to:';
font-size: 12px;
color: rgb(var(--text-color-secondary));
}
.getting-started__footer p:after {
content: ' Oat was here';
}
/* public/static css */
/* for pages like /@username */
.public-layout .public-account-header__tabs__tabs .counter.active::after {
border-bottom-color: rgb(var(--accent-color));
}
.public-layout .public-account-bio .account__header__fields a {
color: rgb(var(--accent-color));
}
.public-layout .header .nav-button {
color: #fff;
background-color: rgb(var(--accent-color));
}
.public-layout .header .nav-button:active, .public-layout .header .nav-button:focus, .public-layout .header .nav-button:hover {
background-color: rgb(var(--accent-color-bright))
}
.public-layout .activity-stream .entry, .hero-widget__text, .table-of-contents {
background-color: rgb(var(--background-color));
}
body {
background-color: rgb(var(--app-background-color));
}
.public-layout .public-account-header__tabs__tabs .counter {
border-right: none;
}
.public-layout .public-account-bio, .public-layout .public-account-header__bar::before, .public-layout .header, .directory__tag > a, .directory__tag > div, .directory__tag > a:active, .directory__tag > a:focus, .directory__tag > a:hover, .public-layout .header .brand:hover, .landing-page__call-to-action, .box-widget {
background-color: rgb(var(--background-color-brighter));
}
.public-layout .display-name, .status__relative-time time, .status__relative-time {
color: rgb(var(--text-color-secondary));
}
.rich-formatting, .rich-formatting p {
color: rgb(var(--text-color));
}
.rich-formatting table tbody tr, .rich-formatting table thead tr, .notification-follow, .notification-follow-request {
border-bottom: none;
}
// https://types.pl/@haskal/106569437674907815
.search-popout em {
color: rgb(var(--accent-color)) !important;
}

View file

@ -268,7 +268,7 @@ a.button.logo-button {
border: 0;
background: transparent;
padding: 0;
padding-top: 8px;
padding-top: 16px;
text-decoration: none;
&:hover,

View file

@ -1,12 +1,12 @@
// Commonly used web colors
$black: #000000; // Black
$white: #ffffff; // White
$success-green: #79bd9a; // Padua
$error-red: #df405a; // Cerise
$warning-red: #ff5050; // Sunset Orange
$gold-star: #ca8f04; // Dark Goldenrod
$success-green: #79bd9a !default; // Padua
$error-red: #df405a !default; // Cerise
$warning-red: #ff5050 !default; // Sunset Orange
$gold-star: #ca8f04 !default; // Dark Goldenrod
$red-bookmark: $warning-red;
$red-bookmark: $warning-red !default;
// Values from the classic Mastodon UI
$classic-base-color: #282c37; // Midnight Express

View file

@ -1,6 +1,6 @@
import EXIF from 'exif-js';
const MAX_IMAGE_PIXELS = 2073600; // 1920x1080px
const MAX_IMAGE_PIXELS = 16777216; // 4096x4096px
const _browser_quirks = {};

View file

@ -22,6 +22,7 @@ import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_
// We use the component (and not the container) since we do not want
// to use the progress bar to show download progress
import Bundle from '../features/ui/components/bundle';
import { visibleReactions } from '../initial_state';
export const textForScreenReader = (intl, status, rebloggedByText = false) => {
const displayName = status.getIn(['account', 'display_name']);

View file

@ -390,8 +390,8 @@ class EmojiPickerDropdown extends React.PureComponent {
<div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
{button || <img
className={classNames('emojione', { 'pulse-loading': active && loading })}
alt='🙂'
src={`${assetHost}/emoji/1f602.svg`}
alt='blobCat emoji'
src={`${assetHost}/blobCat.png`}
/>}
</div>

View file

@ -7,6 +7,7 @@ import IconButton from 'mastodon/components/icon_button';
import Icon from 'mastodon/components/icon';
import AutosuggestInput from 'mastodon/components/autosuggest_input';
import classNames from 'classnames';
import { pollMinOptions } from 'mastodon/initial_state';
const messages = defineMessages({
option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Choice {number}' },
@ -102,7 +103,7 @@ class Option extends React.PureComponent {
</label>
<div className='poll__cancel'>
<IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
<IconButton disabled={index < pollMinOptions} title={intl.formatMessage(messages.remove_option)} icon='times' onClick={this.handleOptionRemove} />
</div>
</li>
);

View file

@ -64,6 +64,7 @@ import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
import Icon from 'mastodon/components/icon';
import { Helmet } from 'react-helmet';
import { makeCustomEmojiMap } from '../../selectors';
const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
@ -225,6 +226,10 @@ class Status extends ImmutablePureComponent {
this.props.dispatch(fetchStatus(nextProps.params.statusId));
}
if (nextProps.params.statusId && nextProps.ancestorsIds.size > this.props.ancestorsIds.size) {
this._scrolledIntoView = false;
}
if (nextProps.status && nextProps.status.get('id') !== this.state.loadedStatusId) {
this.setState({ showMedia: defaultMediaVisibility(nextProps.status), loadedStatusId: nextProps.status.get('id') });
}

View file

@ -60,7 +60,7 @@ class NavigationPanel extends React.Component {
)}
{showTrends ? (
<ColumnLink transparent to='/explore' icon='hashtag' text={intl.formatMessage(messages.explore)} />
<ColumnLink transparent to={(signedIn || timelinePreview) ? '/explore' : '/explore/tags'} icon='hashtag' text={intl.formatMessage(messages.explore)} />
) : (
<ColumnLink transparent to='/search' icon='search' text={intl.formatMessage(messages.search)} />
)}

View file

@ -54,7 +54,7 @@ import {
About,
PrivacyPolicy,
} from './util/async-components';
import initialState, { me, owner, singleUserMode, showTrends } from '../../initial_state';
import initialState, { me, owner, singleUserMode, showTrends, timelinePreview } from '../../initial_state';
import { closeOnboarding, INTRODUCTION_VERSION } from 'mastodon/actions/onboarding';
import Header from './components/header';
@ -163,7 +163,7 @@ class SwitchingColumnsArea extends React.PureComponent {
}
} else if (singleUserMode && owner && initialState?.accounts[owner]) {
redirect = <Redirect from='/' to={`/@${initialState.accounts[owner].username}`} exact />;
} else if (showTrends) {
} else if (showTrends && (signedIn || timelinePreview)) {
redirect = <Redirect from='/' to='/explore' exact />;
} else {
redirect = <Redirect from='/' to='/about' exact />;

View file

@ -118,6 +118,7 @@ export const mascot = getMeta('mascot');
export const maxReactions = (initialState && initialState.max_reactions) || 1;
export const me = getMeta('me');
export const movedToAccountId = getMeta('moved_to_account_id');
export const visibleReactions = getMeta('visible_reactions');
export const owner = getMeta('owner');
export const profile_directory = getMeta('profile_directory');
export const reduceMotion = getMeta('reduce_motion');
@ -140,4 +141,7 @@ export const languages = initialState?.languages;
// Glitch-soc-specific settings
export const maxChars = (initialState && initialState.max_toot_chars) || 500;
// CatCatNya~ specific settings
export const pollMinOptions = (initialState && initialState.poll_limits && initialState.poll_limits.min_options) || 2;
export default initialState;

View file

@ -137,8 +137,8 @@
"compose_form.poll.remove_option": "Auswahlfeld entfernen",
"compose_form.poll.switch_to_multiple": "Mehrfachauswahl erlauben",
"compose_form.poll.switch_to_single": "Nur Einzelauswahl erlauben",
"compose_form.publish": "Veröffentlichen",
"compose_form.publish_form": "Veröffentlichen",
"compose_form.publish": "Boop",
"compose_form.publish_form": "Boop",
"compose_form.publish_loud": "{publish}!",
"compose_form.save_changes": "Änderungen speichern",
"compose_form.sensitive.hide": "{count, plural, one {Mit einer Inhaltswarnung versehen} other {Mit einer Inhaltswarnung versehen}}",

View file

@ -17,6 +17,7 @@
"account.badges.group": "Group",
"account.block": "Block @{name}",
"account.block_domain": "Block domain {domain}",
"account.block_domain": "Block domain {domain}",
"account.blocked": "Blocked",
"account.browse_more_on_origin_server": "Browse more on the original profile",
"account.cancel_follow_request": "Withdraw follow request",
@ -137,8 +138,8 @@
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Publish",
"compose_form.publish_form": "Publish",
"compose_form.publish": "Boop",
"compose_form.publish_form": "Boop",
"compose_form.publish_loud": "{publish}!",
"compose_form.save_changes": "Save changes",
"compose_form.sensitive.hide": "{count, plural, one {Mark media as sensitive} other {Mark media as sensitive}}",

View file

@ -141,8 +141,8 @@
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Publish",
"compose_form.publish_form": "Publish",
"compose_form.publish": "Boop",
"compose_form.publish_form": "Boop",
"compose_form.publish_loud": "{publish}!",
"compose_form.save_changes": "Save changes",
"compose_form.sensitive.hide": "{count, plural, one {Mark media as sensitive} other {Mark media as sensitive}}",

View file

@ -387,7 +387,8 @@
"not_signed_in_indicator.not_signed_in": "Vous devez vous connecter pour accéder à cette ressource.",
"notification.admin.report": "{name} a signalé {target}",
"notification.admin.sign_up": "{name} s'est inscrit·e",
"notification.favourite": "{name} a ajouté le message à ses favoris",
"notification.favourite": "{name} a aimé votre publication",
"notification.reaction": "{name} a réagi·e à votre publication",
"notification.follow": "{name} vous suit",
"notification.follow_request": "{name} a demandé à vous suivre",
"notification.mention": "{name} vous a mentionné·e:",
@ -402,6 +403,7 @@
"notifications.column_settings.admin.sign_up": "Nouvelles inscriptions :",
"notifications.column_settings.alert": "Notifications du navigateur",
"notifications.column_settings.favourite": "Favoris:",
"notifications.column_settings.reaction": "Réactions:",
"notifications.column_settings.filter_bar.advanced": "Afficher toutes les catégories",
"notifications.column_settings.filter_bar.category": "Barre de filtrage rapide",
"notifications.column_settings.filter_bar.show_bar": "Afficher la barre de filtre",
@ -551,6 +553,7 @@
"status.edited_x_times": "Edité {count, plural, one {{count} fois} other {{count} fois}}",
"status.embed": "Intégrer",
"status.favourite": "Ajouter aux favoris",
"status.react": "Réagir",
"status.filter": "Filtrer ce message",
"status.filtered": "Filtré",
"status.hide": "Cacher le pouet",
@ -609,6 +612,7 @@
"timeline_hint.resources.statuses": "Les messages plus anciens",
"trends.counter_by_accounts": "{count, plural, one {{counter} personne} other {{counter} personnes}} au cours {days, plural, one {des dernières 24h} other {des {days} derniers jours}}",
"trends.trending_now": "Tendance en ce moment",
"tooltips.reactions": "Réactions",
"ui.beforeunload": "Votre brouillon sera perdu si vous quittez Mastodon.",
"units.short.billion": "{count}Md",
"units.short.million": "{count}M",

View file

@ -52,7 +52,7 @@ import { STORE_HYDRATE } from '../actions/store';
import { REDRAFT } from '../actions/statuses';
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
import uuid from '../uuid';
import { me } from '../initial_state';
import { me, pollMinOptions } from '../initial_state';
import { unescapeHTML } from '../utils/html';
const initialState = ImmutableMap({
@ -95,7 +95,7 @@ const initialState = ImmutableMap({
});
const initialPoll = ImmutableMap({
options: ImmutableList(['', '']),
options: ImmutableList(new Array(pollMinOptions).fill('')),
expires_in: 24 * 3600,
multiple: false,
});

View file

@ -1,6 +1,6 @@
import EXIF from 'exif-js';
const MAX_IMAGE_PIXELS = 2073600; // 1920x1080px
const MAX_IMAGE_PIXELS = 16777216; // 4096x4096px
const _browser_quirks = {};

View file

@ -0,0 +1 @@
@import 'flavours/glitch/styles/homogay';

View file

@ -0,0 +1,16 @@
de:
skins:
glitch:
homogay: homogay (von @anna@girldick.gay)
en:
skins:
glitch:
homogay: homogay (by @anna@girldick.gay)
es:
skins:
glitch:
homogay: homogay (por @anna@girldick.gay)
fr:
skins:
glitch:
homogay: homogay (par @anna@girldick.gay)

View file

@ -0,0 +1 @@
@import 'flavours/glitch/styles/oatstodon';

View file

@ -0,0 +1,8 @@
en:
skins:
glitch:
oatstodon: oatstodon (by @oat@hellsite.site)
es:
skins:
glitch:
oatstodon: oatstodon (por @oat@hellsite.site)

View file

@ -6,12 +6,12 @@ class RateLimiter
FAMILIES = {
follows: {
limit: 400,
period: 24.hours.freeze,
period: 12.hours.freeze,
}.freeze,
statuses: {
limit: 300,
period: 3.hours.freeze,
period: 1.hour.freeze,
}.freeze,
reports: {

View file

@ -68,7 +68,7 @@ class MediaAttachment < ApplicationRecord
IMAGE_STYLES = {
original: {
pixels: 2_073_600, # 1920x1080px
pixels: 16_777_216, # 4096x4096px
file_geometry_parser: FastGeometryParser,
}.freeze,

View file

@ -21,6 +21,7 @@ class InitialStateSerializer < ActiveModel::Serializer
def poll_limits
{
min_options: PollValidator::MIN_OPTIONS,
max_options: PollValidator::MAX_OPTIONS,
max_option_chars: PollValidator::MAX_OPTION_CHARS,
min_expiration: PollValidator::MIN_EXPIRATION,

View file

@ -67,6 +67,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
},
polls: {
min_options: PollValidator::MIN_OPTIONS,
max_options: PollValidator::MAX_OPTIONS,
max_characters_per_option: PollValidator::MAX_OPTION_CHARS,
min_expiration: PollValidator::MIN_EXPIRATION,

View file

@ -42,6 +42,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer
def poll_limits
{
min_options: PollValidator::MIN_OPTIONS,
max_options: PollValidator::MAX_OPTIONS,
max_option_chars: PollValidator::MAX_OPTION_CHARS,
min_expiration: PollValidator::MIN_EXPIRATION,
@ -91,6 +92,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer
},
polls: {
min_options: PollValidator::MIN_OPTIONS,
max_options: PollValidator::MAX_OPTIONS,
max_characters_per_option: PollValidator::MAX_OPTION_CHARS,
min_expiration: PollValidator::MIN_EXPIRATION,

View file

@ -1,7 +1,8 @@
# frozen_string_literal: true
class PollValidator < ActiveModel::Validator
MAX_OPTIONS = (ENV['MAX_POLL_OPTIONS'] || 5).to_i
MIN_OPTIONS = [1, (ENV['MIN_POLL_OPTIONS'] || 2).to_i].max
MAX_OPTIONS = [MIN_OPTIONS, (ENV['MAX_POLL_OPTIONS'] || 5).to_i].max
MAX_OPTION_CHARS = (ENV['MAX_POLL_OPTION_CHARS'] || 100).to_i
MAX_EXPIRATION = 1.month.freeze
MIN_EXPIRATION = 5.minutes.freeze
@ -9,7 +10,7 @@ class PollValidator < ActiveModel::Validator
def validate(poll)
current_time = Time.now.utc
poll.errors.add(:options, I18n.t('polls.errors.too_few_options')) unless poll.options.size > 1
poll.errors.add(:options, I18n.t('polls.errors.too_few_options')) unless poll.options.size >= MIN_OPTIONS
poll.errors.add(:options, I18n.t('polls.errors.too_many_options', max: MAX_OPTIONS)) if poll.options.size > MAX_OPTIONS
poll.errors.add(:options, I18n.t('polls.errors.over_character_limit', max: MAX_OPTION_CHARS)) if poll.options.any? { |option| option.mb_chars.grapheme_length > MAX_OPTION_CHARS }
poll.errors.add(:options, I18n.t('polls.errors.duplicate_options')) unless poll.options.uniq.size == poll.options.size

View file

@ -9,6 +9,7 @@ RSS::Builder.build do |doc|
@statuses.each do |status|
doc.item do |item|
item.title("New post#{" (CW: #{status.spoiler_text})" unless status.spoiler_text.empty?}")
item.link(ActivityPub::TagManager.instance.url_for(status))
item.pub_date(status.created_at)
item.description(rss_status_content_format(status))

View file

@ -7,6 +7,7 @@ RSS::Builder.build do |doc|
@statuses.each do |status|
doc.item do |item|
item.title("New post by #{status.account.pretty_acct}#{" (CW: #{status.spoiler_text})" unless status.spoiler_text.empty?}")
item.link(ActivityPub::TagManager.instance.url_for(status))
item.pub_date(status.created_at)
item.description(rss_status_content_format(status))

View file

@ -62,7 +62,7 @@ class Rack::Attack
IpBlock.blocked?(req.remote_ip)
end
throttle('throttle_authenticated_api', limit: 300, period: 5.minutes) do |req|
throttle('throttle_authenticated_api', limit: 600, period: 5.minutes) do |req|
req.authenticated_user_id if req.api_request?
end
@ -70,11 +70,11 @@ class Rack::Attack
req.throttleable_remote_ip if req.api_request? && req.unauthenticated?
end
throttle('throttle_api_media', limit: 30, period: 30.minutes) do |req|
throttle('throttle_api_media', limit: 100, period: 30.minutes) do |req|
req.authenticated_user_id if req.post? && req.path.match?(/\A\/api\/v\d+\/media\z/i)
end
throttle('throttle_media_proxy', limit: 30, period: 10.minutes) do |req|
throttle('throttle_media_proxy', limit: 200, period: 10.minutes) do |req|
req.throttleable_remote_ip if req.path.start_with?('/media_proxy')
end
@ -82,7 +82,7 @@ class Rack::Attack
req.throttleable_remote_ip if req.post? && req.path == '/api/v1/accounts'
end
throttle('throttle_authenticated_paging', limit: 300, period: 15.minutes) do |req|
throttle('throttle_authenticated_paging', limit: 1000, period: 15.minutes) do |req|
req.authenticated_user_id if req.paging_request?
end
@ -93,7 +93,7 @@ class Rack::Attack
API_DELETE_REBLOG_REGEX = /\A\/api\/v1\/statuses\/[\d]+\/unreblog\z/.freeze
API_DELETE_STATUS_REGEX = /\A\/api\/v1\/statuses\/[\d]+\z/.freeze
throttle('throttle_api_delete', limit: 30, period: 30.minutes) do |req|
throttle('throttle_api_delete', limit: 60, period: 5.minutes) do |req|
req.authenticated_user_id if (req.post? && req.path.match?(API_DELETE_REBLOG_REGEX)) || (req.delete? && req.path.match?(API_DELETE_STATUS_REGEX))
end

View file

@ -2,7 +2,7 @@
# important settings can be changed from the admin interface.
defaults: &defaults
site_title: 'Mastodon Glitch Edition'
site_title: 'nyastodon'
site_short_description: ''
site_description: ''
site_extended_description: ''

View file

@ -39,7 +39,7 @@
class: Scheduler::UserCleanupScheduler
queue: scheduler
ip_cleanup_scheduler:
cron: '<%= Random.rand(0..59) %> <%= Random.rand(3..5) %> * * *'
every: '1h'
class: Scheduler::IpCleanupScheduler
queue: scheduler
pghero_scheduler:

View file

@ -47,6 +47,11 @@ SystemCallFilter=~@cpu-emulation @debug @keyring @ipc @mount @obsolete @privileg
SystemCallFilter=@chown
SystemCallFilter=pipe
SystemCallFilter=pipe2
Nice=19
CPUSchedulingPolicy=idle
CPUSchedulingPriority=1
IOSchedulingClass=idle
IOSchedulingPriority=7
ReadWritePaths=/home/mastodon/live
[Install]

View file

@ -9,6 +9,7 @@ WorkingDirectory=/home/mastodon/live
Environment="NODE_ENV=production"
Environment="PORT=4000"
Environment="STREAMING_CLUSTER_NUM=1"
Environment="LD_PRELOAD=libjemalloc.so"
ExecStart=/usr/bin/node ./streaming
TimeoutSec=15
Restart=always

View file

@ -21,7 +21,19 @@ module Mastodon
end
def suffix
'+glitch'
'+cat'
end
def suffix_version
'+1.0.7'
end
def post_suffix
'+nya'
end
def post_suffix_version
'-1.1.5'
end
def to_a
@ -29,11 +41,11 @@ module Mastodon
end
def to_s
[to_a.join('.'), flags, suffix].join
[to_a.join('.'), flags, suffix, suffix_version, post_suffix, post_suffix_version].join
end
def repository
ENV.fetch('GITHUB_REPOSITORY', 'glitch-soc/mastodon')
ENV.fetch('GITHUB_REPOSITORY', 'CatCatNya/catstodon')
end
def source_base_url

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

BIN
public/blobCat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Binary file not shown.

27
redact-env.bash Executable file
View file

@ -0,0 +1,27 @@
#!/usr/bin/env bash
if [[ -f "$1" ]]; then
sed -e '/^#.*$/d' \
-e 's/^SECRET_KEY_BASE=.*/SECRET_KEY_BASE=[REDACTED]/gi' \
-e 's/^OTP_SECRET=.*/OTP_SECRET=[REDACTED]/gi' \
-e 's/^VAPID_PRIVATE_KEY=.*/VAPID_PRIVATE_KEY=[REDACTED]/gi' \
-e 's/^VAPID_PUBLIC_KEY=.*/VAPID_PUBLIC_KEY=[REDACTED]/gi' \
-e 's/^DB_HOST=.*/DB_HOST=[REDACTED]/gi' \
-e 's/^DB_PORT=.*/DB_PORT=[REDACTED]/gi' \
-e 's/^DB_NAME=.*/DB_NAME=[REDACTED]/gi' \
-e 's/^DB_USER=.*/DB_USER=[REDACTED]/gi' \
-e 's/^DB_PASS=.*/DB_PASS=[REDACTED]/gi' \
-e 's/^REDIS_HOST=.*/REDIS_HOST=[REDACTED]/gi' \
-e 's/^REDIS_PORT=.*/REDIS_PORT=[REDACTED]/gi' \
-e 's/^REDIS_PASSWORD=.*/REDIS_PASSWORD=[REDACTED]/gi' \
-e 's/^PAPERCLIP_ROOT_PATH=.*/PAPERCLIP_ROOT_PATH=[REDACTED]/gi' \
-e 's/^SMTP_PORT=.*/SMTP_PORT=[REDACTED]/gi' \
-e 's/^SMTP_LOGIN=.*/SMTP_LOGIN=[REDACTED]/gi' \
-e 's/^SMTP_PASSWORD=.*/SMTP_PASSWORD=[REDACTED]/gi' \
-e 's/^SMTP_AUTH_METHOD=.*/SMTP_AUTH_METHOD=[REDACTED]/gi' \
-e 's/^SMTP_OPENSSL_VERIFY_MODE=.*/SMTP_OPENSSL_VERIFY_MODE=[REDACTED]/gi' \
-e 's/^ES_HOST=.*/ES_HOST=[REDACTED]/gi' \
-e 's/^ES_PORT=.*/ES_PORT=[REDACTED]/gi' \
-e 's/^ES_PREFIX=.*/ES_PREFIX=[REDACTED]/gi' \
"$1"
fi