forked from mirrors/catstodon
merge catstodon/main into main
This commit is contained in:
commit
380567f453
47 changed files with 786 additions and 105 deletions
.github/workflows
Vagrantfileapp
controllers
javascript
flavours
glitch
vanilla
mastodon/features/ui/components
skins
glitch
vanilla
styles/mastodon
lib
models
services
workers/scheduler
config
db
post_migrate
schema.rblib
spec
controllers
lib
models
2
.github/workflows/check-i18n.yml
vendored
2
.github/workflows/check-i18n.yml
vendored
|
@ -25,7 +25,7 @@ jobs:
|
|||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: '3.0'
|
||||
ruby-version: .ruby-version
|
||||
bundler-cache: true
|
||||
- name: Check locale file normalization
|
||||
run: bundle exec i18n-tasks check-normalized
|
||||
|
|
2
.github/workflows/linter.yml
vendored
2
.github/workflows/linter.yml
vendored
|
@ -53,7 +53,7 @@ jobs:
|
|||
- name: Set-up Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
node-version-file: .nvmrc
|
||||
cache: yarn
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
|
71
Vagrantfile
vendored
71
Vagrantfile
vendored
|
@ -3,16 +3,14 @@
|
|||
|
||||
ENV["PORT"] ||= "3000"
|
||||
|
||||
$provision = <<SCRIPT
|
||||
|
||||
cd /vagrant # This is where the host folder/repo is mounted
|
||||
$provisionA = <<SCRIPT
|
||||
|
||||
# Add the yarn repo + yarn repo keys
|
||||
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
||||
sudo apt-add-repository 'deb https://dl.yarnpkg.com/debian/ stable main'
|
||||
|
||||
# Add repo for NodeJS
|
||||
curl -sL https://deb.nodesource.com/setup_14.x | sudo bash -
|
||||
curl -sL https://deb.nodesource.com/setup_16.x | sudo bash -
|
||||
|
||||
# Add firewall rule to redirect 80 to PORT and save
|
||||
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{ENV["PORT"]}
|
||||
|
@ -33,32 +31,56 @@ sudo apt-get install \
|
|||
redis-tools \
|
||||
postgresql \
|
||||
postgresql-contrib \
|
||||
yarn \
|
||||
libicu-dev \
|
||||
libidn11-dev \
|
||||
libreadline-dev \
|
||||
libpam0g-dev \
|
||||
libreadline6-dev \
|
||||
autoconf \
|
||||
bison \
|
||||
build-essential \
|
||||
ffmpeg \
|
||||
file \
|
||||
gcc \
|
||||
libffi-dev \
|
||||
libgdbm-dev \
|
||||
libjemalloc-dev \
|
||||
libncurses5-dev \
|
||||
libprotobuf-dev \
|
||||
libssl-dev \
|
||||
libyaml-dev \
|
||||
pkg-config \
|
||||
protobuf-compiler \
|
||||
zlib1g-dev \
|
||||
-y
|
||||
|
||||
# Install rvm
|
||||
read RUBY_VERSION < .ruby-version
|
||||
sudo apt-add-repository -y ppa:rael-gc/rvm
|
||||
sudo apt-get install rvm -y
|
||||
|
||||
curl -sSL https://rvm.io/mpapis.asc | gpg --import
|
||||
curl -sSL https://rvm.io/pkuczynski.asc | gpg --import
|
||||
sudo usermod -a -G rvm $USER
|
||||
|
||||
curl -sSL https://raw.githubusercontent.com/rvm/rvm/stable/binscripts/rvm-installer | bash -s stable --ruby=$RUBY_VERSION
|
||||
source /home/vagrant/.rvm/scripts/rvm
|
||||
SCRIPT
|
||||
|
||||
$provisionB = <<SCRIPT
|
||||
|
||||
source "/etc/profile.d/rvm.sh"
|
||||
|
||||
# Install Ruby
|
||||
rvm reinstall ruby-$RUBY_VERSION --disable-binary
|
||||
read RUBY_VERSION < /vagrant/.ruby-version
|
||||
rvm install ruby-$RUBY_VERSION --disable-binary
|
||||
|
||||
# Configure database
|
||||
sudo -u postgres createuser -U postgres vagrant -s
|
||||
sudo -u postgres createdb -U postgres mastodon_development
|
||||
|
||||
# Install gems and node modules
|
||||
cd /vagrant # This is where the host folder/repo is mounted
|
||||
|
||||
# Install gems
|
||||
gem install bundler foreman
|
||||
bundle install
|
||||
|
||||
# Install node modules
|
||||
sudo corepack enable
|
||||
yarn set version classic
|
||||
yarn install
|
||||
|
||||
# Build Mastodon
|
||||
|
@ -72,18 +94,11 @@ echo 'export $(cat "/vagrant/.env.vagrant" | xargs)' >> ~/.bash_profile
|
|||
|
||||
SCRIPT
|
||||
|
||||
$start = <<SCRIPT
|
||||
|
||||
echo 'To start server'
|
||||
echo ' $ vagrant ssh -c "cd /vagrant && foreman start"'
|
||||
|
||||
SCRIPT
|
||||
|
||||
VAGRANTFILE_API_VERSION = "2"
|
||||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
|
||||
config.vm.box = "ubuntu/bionic64"
|
||||
config.vm.box = "ubuntu/focal64"
|
||||
|
||||
config.vm.provider :virtualbox do |vb|
|
||||
vb.name = "mastodon"
|
||||
|
@ -100,7 +115,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|||
# Use "virtio" network interfaces for better performance.
|
||||
vb.customize ["modifyvm", :id, "--nictype1", "virtio"]
|
||||
vb.customize ["modifyvm", :id, "--nictype2", "virtio"]
|
||||
|
||||
end
|
||||
|
||||
# This uses the vagrant-hostsupdater plugin, and lets you
|
||||
|
@ -118,7 +132,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|||
end
|
||||
|
||||
if config.vm.networks.any? { |type, options| type == :private_network }
|
||||
config.vm.synced_folder ".", "/vagrant", type: "nfs", mount_options: ['rw', 'vers=3', 'tcp', 'actimeo=1']
|
||||
config.vm.synced_folder ".", "/vagrant", type: "nfs", mount_options: ['rw', 'actimeo=1']
|
||||
else
|
||||
config.vm.synced_folder ".", "/vagrant"
|
||||
end
|
||||
|
@ -129,9 +143,12 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|||
config.vm.network :forwarded_port, guest: 8080, host: 8080
|
||||
|
||||
# Full provisioning script, only runs on first 'vagrant up' or with 'vagrant provision'
|
||||
config.vm.provision :shell, inline: $provision, privileged: false
|
||||
config.vm.provision :shell, inline: $provisionA, privileged: false, reset: true
|
||||
config.vm.provision :shell, inline: $provisionB, privileged: false
|
||||
|
||||
# Start up script, runs on every 'vagrant up'
|
||||
config.vm.provision :shell, inline: $start, run: 'always', privileged: false
|
||||
config.vm.post_up_message = <<MESSAGE
|
||||
To start server
|
||||
$ vagrant ssh -c "cd /vagrant && foreman start"
|
||||
MESSAGE
|
||||
|
||||
end
|
||||
|
|
|
@ -55,12 +55,14 @@ module Admin
|
|||
def approve
|
||||
authorize @account.user, :approve?
|
||||
@account.user.approve!
|
||||
log_action :approve, @account.user
|
||||
redirect_to admin_accounts_path(status: 'pending'), notice: I18n.t('admin.accounts.approved_msg', username: @account.acct)
|
||||
end
|
||||
|
||||
def reject
|
||||
authorize @account.user, :reject?
|
||||
DeleteAccountService.new.call(@account, reserve_email: false, reserve_username: false)
|
||||
log_action :reject, @account.user
|
||||
redirect_to admin_accounts_path(status: 'pending'), notice: I18n.t('admin.accounts.rejected_msg', username: @account.acct)
|
||||
end
|
||||
|
||||
|
|
|
@ -54,12 +54,14 @@ class Api::V1::Admin::AccountsController < Api::BaseController
|
|||
def approve
|
||||
authorize @account.user, :approve?
|
||||
@account.user.approve!
|
||||
log_action :approve, @account.user
|
||||
render json: @account, serializer: REST::Admin::AccountSerializer
|
||||
end
|
||||
|
||||
def reject
|
||||
authorize @account.user, :reject?
|
||||
DeleteAccountService.new.call(@account, reserve_email: false, reserve_username: false)
|
||||
log_action :reject, @account.user
|
||||
render_empty
|
||||
end
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class Api::V1::FiltersController < Api::BaseController
|
|||
|
||||
def create
|
||||
ApplicationRecord.transaction do
|
||||
filter_category = current_account.custom_filters.create!(resource_params)
|
||||
filter_category = current_account.custom_filters.create!(filter_params)
|
||||
@filter = filter_category.keywords.create!(keyword_params)
|
||||
end
|
||||
|
||||
|
@ -52,11 +52,11 @@ class Api::V1::FiltersController < Api::BaseController
|
|||
end
|
||||
|
||||
def resource_params
|
||||
params.permit(:phrase, :expires_in, :irreversible, context: [])
|
||||
params.permit(:phrase, :expires_in, :irreversible, :whole_word, context: [])
|
||||
end
|
||||
|
||||
def filter_params
|
||||
resource_params.slice(:expires_in, :irreversible, :context)
|
||||
resource_params.slice(:phrase, :expires_in, :irreversible, :context)
|
||||
end
|
||||
|
||||
def keyword_params
|
||||
|
|
|
@ -7,6 +7,7 @@ import Avatar from 'flavours/glitch/components/avatar';
|
|||
import Permalink from 'flavours/glitch/components/permalink';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
|
||||
const Account = connect(state => ({
|
||||
account: state.getIn(['accounts', me]),
|
||||
|
@ -16,7 +17,14 @@ const Account = connect(state => ({
|
|||
</Permalink>
|
||||
));
|
||||
|
||||
export default @withRouter
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
openClosedRegistrationsModal() {
|
||||
dispatch(openModal('CLOSED_REGISTRATIONS'));
|
||||
},
|
||||
});
|
||||
|
||||
export default @connect(null, mapDispatchToProps)
|
||||
@withRouter
|
||||
class Header extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
|
@ -24,12 +32,13 @@ class Header extends React.PureComponent {
|
|||
};
|
||||
|
||||
static propTypes = {
|
||||
openClosedRegistrationsModal: PropTypes.func,
|
||||
location: PropTypes.object,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { location } = this.props;
|
||||
const { location, openClosedRegistrationsModal } = this.props;
|
||||
|
||||
let content;
|
||||
|
||||
|
@ -41,10 +50,26 @@ class Header extends React.PureComponent {
|
|||
</>
|
||||
);
|
||||
} else {
|
||||
let signupButton;
|
||||
|
||||
if (registrationsOpen) {
|
||||
signupButton = (
|
||||
<a href='/auth/sign_up' className='button button-tertiary'>
|
||||
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
||||
</a>
|
||||
);
|
||||
} else {
|
||||
signupButton = (
|
||||
<button className='button button-tertiary' onClick={openClosedRegistrationsModal}>
|
||||
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
content = (
|
||||
<>
|
||||
<a href='/auth/sign_in' className='button'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a>
|
||||
<a href={registrationsOpen ? '/auth/sign_up' : 'https://joinmastodon.org/servers'} className='button button-tertiary'><FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /></a>
|
||||
{signupButton}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,180 @@
|
|||
import inherited from 'mastodon/locales/cs.json';
|
||||
|
||||
const messages = {
|
||||
// No translations available.
|
||||
'about.fork_disclaimer': 'Glitch-soc je svobodný software s otevřeným zdrojovým kódem založený na Mastodonu.',
|
||||
'settings.layout_opts': 'Možnosti rozvržení',
|
||||
'settings.layout': 'Rozložení:',
|
||||
'layout.current_is': 'Nastavené rozložení je:',
|
||||
'layout.auto': 'Automatické',
|
||||
'layout.desktop': 'Desktop',
|
||||
'layout.mobile': 'Mobil',
|
||||
'layout.hint.auto': 'Vybrat rozložení automaticky v závislosti na nastavení “Povolit pokročilé webové rozhraní” a velikosti obrazovky.',
|
||||
'layout.hint.desktop': 'Použít vícesloupcové rozložení nezávisle na nastavení “Povolit pokročilé webové rozhraní” a velikosti obrazovky.',
|
||||
'layout.hint.single': 'Použít jednosloupcové rozložení nezávisle na nastavení “Povolit pokročilé webové rozhraní” a velikosti obrazovky.',
|
||||
'navigation_bar.app_settings': 'Nastavení aplikace',
|
||||
'navigation_bar.featured_users': 'Vybraní uživatelé',
|
||||
'endorsed_accounts_editor.endorsed_accounts': 'Vybrané účty',
|
||||
'navigation_bar.info': 'Rozšířené informace',
|
||||
'navigation_bar.misc': 'Různé',
|
||||
'navigation_bar.keyboard_shortcuts': 'Klávesové zkratky',
|
||||
'getting_started.onboarding': 'Ukaž mi to tu',
|
||||
'onboarding.skip': 'Přeskočit',
|
||||
'onboarding.next': 'Další',
|
||||
'onboarding.done': 'Hotovo',
|
||||
'onboarding.page_one.federation': '{domain} je \'instance\' Mastodonu. Mastodon je síť nezávislých serverů, které jsou spolu propojené do jedné velké sociální sítě. Těmto serverům říkáme instance.',
|
||||
'onboarding.page_one.handle': 'Jste na instanci {domain}, takže celá adresa vašeho profilu je {handle}',
|
||||
'onboarding.page_one.welcome': 'Vítá vás {domain}!',
|
||||
'onboarding.page_two.compose': 'Příspěvky se píší v levém sloupci. Pomocí ikon pod příspěvkem k němu můžete připojit obrázky, změnit úroveň soukromí nebo přidat varování o obsahu.',
|
||||
'onboarding.page_three.search': 'Pomocí vyhledávací lišty můžete hledat lidi nebo hashtagy. Pokud hledáte někoho z jiné instance, musíte použít celou adresu jeho profilu.',
|
||||
'onboarding.page_three.profile': 'Upravte si svůj profil a nastavte si profilový obrázek, jméno, a krátký text o sobě. Naleznete tam i další možnosti nastavení.',
|
||||
'onboarding.page_four.home': 'Domovská časová osa zobrazuje příspěvky od lidí, které sledujete.',
|
||||
'onboarding.page_four.notifications': 'Notifikace se zobrazí, když s vámi někdo interaguje.',
|
||||
'onboarding.page_five.public_timelines': 'Místní časová osa zobrazuje veřejné příspěvky všech uživatelů instance {domain}. Federovaná časová osa zobrazí příspěvky od všech, koho uživatelé instance {domain} sledují. Tyto veřejné časové osy jsou skvělý způsob, jak objevit nové lidi.',
|
||||
'onboarding.page_six.almost_done': 'Skoro hotovo...',
|
||||
'onboarding.page_six.github': 'Na serveru {domain} běží Glitchsoc. Glitchsoc je přátelský {fork} programu {Mastodon}, a je kompatibilní s jakoukoliv jinou mastodoní instancí nebo aplikací. Glitchsoc je zcela svobodný a má otevřený zdrojový kód. Na stránce {github} můžete hlásit chyby, žádat o nové funkce, nebo ke kódu vlastnoručně přispět.',
|
||||
'onboarding.page_six.apps_available': 'Jsou dostupné {apps} pro iOS, Android i jiné platformy.',
|
||||
'onboarding.page_six.various_app': 'mobilní aplikace',
|
||||
'onboarding.page_six.appetoot': 'Veselé mastodonění!',
|
||||
'settings.auto_collapse': 'Automaticky sbalit',
|
||||
'settings.auto_collapse_all': 'Všechno',
|
||||
'settings.auto_collapse_lengthy': 'Dlouhé příspěvky',
|
||||
'settings.auto_collapse_media': 'Příspěvky s přílohami',
|
||||
'settings.auto_collapse_notifications': 'Oznámení',
|
||||
'settings.auto_collapse_reblogs': 'Boosty',
|
||||
'settings.auto_collapse_replies': 'Odpovědi',
|
||||
'settings.show_action_bar': 'Zobrazit ve sbalených příspěvcích tlačítka s akcemi',
|
||||
'settings.close': 'Zavřít',
|
||||
'settings.collapsed_statuses': 'Sbalené příspěvky',
|
||||
'settings.confirm_boost_missing_media_description': 'Zobrazit potvrzovací dialog před boostnutím příspěvku s chybějícími popisky obrázků',
|
||||
'boost_modal.missing_description': 'Příspěvek obsahuje obrázky bez popisků',
|
||||
'settings.enable_collapsed': 'Povolit sbalené příspěvky',
|
||||
'settings.enable_collapsed_hint': 'U sbalených příspěvků je část jejich obsahu skrytá, aby zabraly méně místa na obrazovce. (Tohle není stejná funkce jako varování o obsahu.)',
|
||||
'settings.general': 'Obecné',
|
||||
'settings.hicolor_privacy_icons': 'Barevné ikony soukromí',
|
||||
'settings.hicolor_privacy_icons.hint': 'Zobrazit ikony úrovně soukromí příspěvků v jasných, snadno rozlišitelných barvách',
|
||||
'settings.image_backgrounds': 'Obrázkové pozadí',
|
||||
'settings.image_backgrounds_media': 'Náhled médií ve sbalených příspěvcích',
|
||||
'settings.image_backgrounds_media_hint': 'Pokud jsou k příspěvku přiložena média, použije se první z nich jako pozadí',
|
||||
'settings.image_backgrounds_users': 'Nastavit sbaleným příspěvkům obrázkové pozadí',
|
||||
'settings.inline_preview_cards': 'Zobrazit v časové ose náhledy externích odkazů',
|
||||
'settings.media': 'Média',
|
||||
'settings.media_letterbox': 'Neořezávat obrázky',
|
||||
'settings.media_letterbox_hint': 'Místo výřezu obrázku zobrazit obrázek celý, doplněný podle potřeby o prázdné okraje',
|
||||
'settings.media_fullwidth': 'Zobrazit náhledy v plné šířce',
|
||||
'settings.notifications_opts': 'Možnosti oznámení',
|
||||
'settings.notifications.tab_badge': 'Zobrazit počet nepřečtených oznámení',
|
||||
'settings.notifications.tab_badge.hint': 'Počet nepřečtených oznámení se viditelně zobrazí na hlavní stránce (pokud není seznam oznámení viditelný)',
|
||||
'settings.notifications.favicon_badge': 'Zobrazit počet na ikoně serveru',
|
||||
'settings.notifications.favicon_badge.hint': 'Zobrazí počet nepřečtených oznámení na ikoně serveru',
|
||||
'settings.preferences': 'Předvolby',
|
||||
'settings.rewrite_mentions': 'Přepsat zmínky v zobrazených příspěvcích',
|
||||
'settings.rewrite_mentions_no': 'Nepřepisovat zmínky',
|
||||
'settings.rewrite_mentions_acct': 'Přepsat uživatelským jménem a doménou (pokud je účet na jiném serveru)',
|
||||
'settings.rewrite_mentions_username': 'Přepsat uživatelským jménem',
|
||||
'settings.show_reply_counter': 'Zobrazit odhad počtu odpovědí',
|
||||
'settings.status_icons': 'Ikony u příspěvků',
|
||||
'settings.status_icons_language': 'Indikace jazyk',
|
||||
'settings.status_icons_reply': 'Indikace odpovědi',
|
||||
'settings.status_icons_local_only': 'Indikace lokálního příspěvku',
|
||||
'settings.status_icons_media': 'Indikace obrázků a anket',
|
||||
'settings.status_icons_visibility': 'Indikace úrovně soukromí',
|
||||
'settings.tag_misleading_links': 'Označit zavádějící odkazy',
|
||||
'settings.tag_misleading_links.hint': 'Zobrazit skutečný cíl u každého odkazu, který ho explicitně nezmiňuje',
|
||||
'settings.wide_view': 'Široké sloupce (pouze v režimu Desktop)',
|
||||
'settings.wide_view_hint': 'Sloupce se roztáhnout, aby lépe vyplnily dostupný prostor.',
|
||||
'settings.navbar_under': 'Navigační lišta vespod (pouze v režimu Mobil)',
|
||||
'settings.compose_box_opts': 'Editační pole',
|
||||
'settings.always_show_spoilers_field': 'Vždy zobrazit pole pro varování o obsahu',
|
||||
'settings.prepend_cw_re': 'Při odpovídání přidat před varování o obsahu “re: ”',
|
||||
'settings.preselect_on_reply': 'Při odpovědi označit uživatelská jména',
|
||||
'settings.preselect_on_reply_hint': 'Při odpovídání na konverzaci s více účastníky se jména všech kromě prvního označí, aby šla jednoduše smazat',
|
||||
'settings.confirm_missing_media_description': 'Zobrazit potvrzovací dialog při odesílání příspěvku, ve kterém chybí popisky obrázků',
|
||||
'settings.confirm_before_clearing_draft': 'Zobrazit potvrzovací dialog před přepsáním právě vytvářené zprávy',
|
||||
'settings.show_content_type_choice': 'Zobrazit volbu formátu příspěvku',
|
||||
'settings.side_arm': 'Vedlejší odesílací tlačítko:',
|
||||
'settings.side_arm.none': 'Žádné',
|
||||
'settings.side_arm_reply_mode': 'Při odpovídání na příspěvek by vedlejší odesílací tlačítko mělo:',
|
||||
'settings.side_arm_reply_mode.keep': 'Použít svou nastavenou úroveň soukromí',
|
||||
'settings.side_arm_reply_mode.copy': 'Použít úroveň soukromí příspěvku, na který odpovídáte',
|
||||
'settings.side_arm_reply_mode.restrict': 'Zvýšit úroveň soukromí nejméně na úroveň příspěvku, na který odpovídáte',
|
||||
'settings.content_warnings': 'Varování o obsahu',
|
||||
'settings.content_warnings_shared_state': 'Zobrazit/schovat všechny kopie naráz',
|
||||
'settings.content_warnings_shared_state_hint': 'Tlačítko varování o obsahu bude mít efekt na všechny kopie příspěvku naráz, stejně jako na běžném Mastodonu. Nebude pak možné automaticky sbalit jakoukoliv kopii příspěvku, která má rozbalené varování o obsahu',
|
||||
'settings.content_warnings_media_outside': 'Zobrazit obrázky a videa mimo varování o obsahu',
|
||||
'settings.content_warnings_media_outside_hint': 'Obrázky a videa z příspěvku s varováním o obsahu se zobrazí se separátním přepínačem zobrazení, stejně jako na běžném Mastodonu.',
|
||||
'settings.content_warnings_unfold_opts': 'Možnosti automatického rozbalení',
|
||||
'settings.enable_content_warnings_auto_unfold': 'Vždy rozbalit příspěvky označené varováním o obsahu',
|
||||
'settings.deprecated_setting': 'Tato možnost se nyní nastavuje v {settings_page_link}',
|
||||
'settings.shared_settings_link': 'předvolbách Mastodonu',
|
||||
'settings.content_warnings_filter': 'Tato varování o obsahu automaticky nerozbalovat:',
|
||||
'settings.content_warnings.regexp': 'Regulární výraz',
|
||||
'settings.media_reveal_behind_cw': 'Automaticky zobrazit média označená varováním o obsahu',
|
||||
'settings.pop_in_player': 'Povolit plovoucí okno přehrávače',
|
||||
'settings.pop_in_position': 'Pozice plovoucího okna:',
|
||||
'settings.pop_in_left': 'Vlevo',
|
||||
'settings.pop_in_right': 'Vpravo',
|
||||
|
||||
|
||||
'status.collapse': 'Sbalit',
|
||||
'status.uncollapse': 'Rozbalit',
|
||||
'status.in_reply_to': 'Tento příspěvek je odpověď',
|
||||
'status.has_preview_card': 'Obsahuje náhled odkazu',
|
||||
'status.has_pictures': 'Obsahuje obrázky',
|
||||
'status.is_poll': 'Tento příspěvek je anketa',
|
||||
'status.has_video': 'Obsahuje video',
|
||||
'status.has_audio': 'Obsahuje audio',
|
||||
'status.local_only': 'Viditelné pouze z vaší instance',
|
||||
|
||||
'media_gallery.sensitive': 'Citlivý obsah',
|
||||
|
||||
'favourite_modal.combo': 'Příště můžete pro přeskočení stisknout {combo}',
|
||||
|
||||
'home.column_settings.show_direct': 'Zobrazit přímé zprávy',
|
||||
|
||||
'notification_purge.start': 'Čistící režim',
|
||||
'notifications.mark_as_read': 'Označit všechna oznámení jako přečtená',
|
||||
|
||||
'notification.markForDeletion': 'Označit pro smazání',
|
||||
'notifications.clear': 'Vymazat všechna oznámení',
|
||||
'notifications.marked_clear_confirmation': 'Určitě chcete trvale smazat všechna vybraná oznámení?',
|
||||
'notifications.marked_clear': 'Smazat vybraná oznámení',
|
||||
|
||||
'notification_purge.btn_all': 'Vybrat\nvše',
|
||||
'notification_purge.btn_none': 'Nevybrat\nnic',
|
||||
'notification_purge.btn_invert': 'Obrátit\nvýběr',
|
||||
'notification_purge.btn_apply': 'Smazat\nvybrané',
|
||||
|
||||
'compose.attach.upload': 'Nahrát soubor',
|
||||
'compose.attach.doodle': 'Něco namalovat',
|
||||
'compose.attach': 'Připojit...',
|
||||
|
||||
'advanced_options.local-only.short': 'Lokální příspěvek',
|
||||
'advanced_options.local-only.long': 'Neposílat na jiné servery',
|
||||
'advanced_options.local-only.tooltip': 'Tento příspěvek je pouze lokální',
|
||||
'advanced_options.icon_title': 'Pokročilá nastavení',
|
||||
'advanced_options.threaded_mode.short': 'Režim vlákna',
|
||||
'advanced_options.threaded_mode.long': 'Po odeslání automaticky otevře pole pro odpověď',
|
||||
'advanced_options.threaded_mode.tooltip': 'Režim vlákna je zapnutý',
|
||||
|
||||
'home.column_settings.advanced': 'Pokročilé',
|
||||
'home.column_settings.filter_regex': 'Filtrovat podle regulárních výrazů',
|
||||
|
||||
'compose_form.poll.single_choice': 'Povolit jednu odpověď',
|
||||
'compose_form.poll.multiple_choices': 'Povolit více odpovědí',
|
||||
|
||||
'compose.content-type.plain': 'Prostý text',
|
||||
'content-type.change': 'Formát příspěvku',
|
||||
'compose_form.spoiler': 'Přidat varování o obsahu',
|
||||
|
||||
'direct.group_by_conversations': 'Seskupit do konverzací',
|
||||
'column.toot': 'Příspěvky a odpovědi',
|
||||
'confirmation_modal.do_not_ask_again': 'Příště se už neptat',
|
||||
|
||||
'keyboard_shortcuts.bookmark': 'Přidat do záložek',
|
||||
'keyboard_shortcuts.toggle_collapse': 'Sbalit/rozbalit příspěvek',
|
||||
'keyboard_shortcuts.secondary_toot': 'Odeslat příspěvek s druhotným nastavením soukromí',
|
||||
|
||||
'column.subheading': 'Různé',
|
||||
};
|
||||
|
||||
export default Object.assign({}, inherited, messages);
|
||||
|
|
|
@ -6,6 +6,14 @@ en:
|
|||
skins:
|
||||
glitch:
|
||||
default: Default
|
||||
cs:
|
||||
flavours:
|
||||
glitch:
|
||||
description: Výchozí rozhraní instancí GlitchSoc.
|
||||
name: Glitch
|
||||
skins:
|
||||
glitch:
|
||||
default: Výchozí
|
||||
pl:
|
||||
flavours:
|
||||
glitch:
|
||||
|
|
|
@ -65,6 +65,7 @@ $ui-header-height: 55px;
|
|||
z-index: 2;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
|
||||
&__logo {
|
||||
display: inline-flex;
|
||||
|
@ -81,10 +82,15 @@ $ui-header-height: 55px;
|
|||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 0 10px;
|
||||
overflow: hidden;
|
||||
|
||||
.button {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.button-tertiary {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1306,7 +1306,8 @@ img.modal-warning {
|
|||
width: 600px;
|
||||
background: $ui-base-color;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 20px;
|
||||
|
|
|
@ -6,6 +6,14 @@ en:
|
|||
skins:
|
||||
vanilla:
|
||||
default: Default
|
||||
cs:
|
||||
flavours:
|
||||
vanilla:
|
||||
description: Standardní rozhraní Mastodonu. Některé funkce GlitchSoc v něm nejsou podporované.
|
||||
name: Standardní Mastodon
|
||||
skins:
|
||||
vanilla:
|
||||
default: Výchozí
|
||||
pl:
|
||||
flavours:
|
||||
vanilla:
|
||||
|
|
|
@ -6,6 +6,7 @@ import { registrationsOpen, me } from 'mastodon/initial_state';
|
|||
import Avatar from 'mastodon/components/avatar';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
|
||||
const Account = connect(state => ({
|
||||
account: state.getIn(['accounts', me]),
|
||||
|
@ -15,7 +16,14 @@ const Account = connect(state => ({
|
|||
</Link>
|
||||
));
|
||||
|
||||
export default @withRouter
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
openClosedRegistrationsModal() {
|
||||
dispatch(openModal('CLOSED_REGISTRATIONS'));
|
||||
},
|
||||
});
|
||||
|
||||
export default @connect(null, mapDispatchToProps)
|
||||
@withRouter
|
||||
class Header extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
|
@ -23,12 +31,13 @@ class Header extends React.PureComponent {
|
|||
};
|
||||
|
||||
static propTypes = {
|
||||
openClosedRegistrationsModal: PropTypes.func,
|
||||
location: PropTypes.object,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { location } = this.props;
|
||||
const { location, openClosedRegistrationsModal } = this.props;
|
||||
|
||||
let content;
|
||||
|
||||
|
@ -40,10 +49,26 @@ class Header extends React.PureComponent {
|
|||
</>
|
||||
);
|
||||
} else {
|
||||
let signupButton;
|
||||
|
||||
if (registrationsOpen) {
|
||||
signupButton = (
|
||||
<a href='/auth/sign_up' className='button button-tertiary'>
|
||||
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
||||
</a>
|
||||
);
|
||||
} else {
|
||||
signupButton = (
|
||||
<button className='button button-tertiary' onClick={openClosedRegistrationsModal}>
|
||||
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
content = (
|
||||
<>
|
||||
<a href='/auth/sign_in' className='button'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a>
|
||||
<a href={registrationsOpen ? '/auth/sign_up' : 'https://joinmastodon.org/servers'} className='button button-tertiary'><FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' /></a>
|
||||
{signupButton}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,10 @@ en:
|
|||
skins:
|
||||
glitch:
|
||||
contrast: High contrast
|
||||
cs:
|
||||
skins:
|
||||
glitch:
|
||||
contrast: Vysoký kontrast
|
||||
es:
|
||||
skins:
|
||||
glitch:
|
||||
|
|
|
@ -2,6 +2,10 @@ en:
|
|||
skins:
|
||||
glitch:
|
||||
mastodon-light: Mastodon (light)
|
||||
cs:
|
||||
skins:
|
||||
glitch:
|
||||
mastodon-light: Mastodon (světlý)
|
||||
es:
|
||||
skins:
|
||||
glitch:
|
||||
|
|
|
@ -2,6 +2,10 @@ en:
|
|||
skins:
|
||||
vanilla:
|
||||
contrast: High contrast
|
||||
cs:
|
||||
skins:
|
||||
vanilla:
|
||||
contrast: Vysoký kontrast
|
||||
es:
|
||||
skins:
|
||||
vanilla:
|
||||
|
|
|
@ -2,6 +2,10 @@ en:
|
|||
skins:
|
||||
vanilla:
|
||||
mastodon-light: Mastodon (light)
|
||||
cs:
|
||||
skins:
|
||||
vanilla:
|
||||
mastodon-light: Mastodon (světlý)
|
||||
es:
|
||||
skins:
|
||||
glitch:
|
||||
|
|
|
@ -2,3 +2,7 @@ en:
|
|||
skins:
|
||||
vanilla:
|
||||
win95: Masto95
|
||||
cs:
|
||||
skins:
|
||||
vanilla:
|
||||
win95: Windows 95
|
||||
|
|
|
@ -2231,6 +2231,7 @@ $ui-header-height: 55px;
|
|||
z-index: 2;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
|
||||
&__logo {
|
||||
display: inline-flex;
|
||||
|
@ -2247,10 +2248,15 @@ $ui-header-height: 55px;
|
|||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 0 10px;
|
||||
overflow: hidden;
|
||||
|
||||
.button {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.button-tertiary {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7156,10 +7162,12 @@ noscript {
|
|||
|
||||
.verified {
|
||||
border: 1px solid rgba($valid-value-color, 0.5);
|
||||
margin-top: -1px;
|
||||
|
||||
&:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
|
@ -7991,7 +7999,8 @@ noscript {
|
|||
width: 600px;
|
||||
background: $ui-base-color;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 20px;
|
||||
|
|
|
@ -10,7 +10,7 @@ class DeliveryFailureTracker
|
|||
end
|
||||
|
||||
def track_failure!
|
||||
redis.sadd(exhausted_deliveries_key, today)
|
||||
redis.sadd?(exhausted_deliveries_key, today)
|
||||
UnavailableDomain.create(domain: @host) if reached_failure_threshold?
|
||||
end
|
||||
|
||||
|
|
|
@ -322,24 +322,24 @@ class FeedManager
|
|||
def clean_feeds!(type, ids)
|
||||
reblogged_id_sets = {}
|
||||
|
||||
redis.pipelined do
|
||||
redis.pipelined do |pipeline|
|
||||
ids.each do |feed_id|
|
||||
redis.del(key(type, feed_id))
|
||||
pipeline.del(key(type, feed_id))
|
||||
reblog_key = key(type, feed_id, 'reblogs')
|
||||
# We collect a future for this: we don't block while getting
|
||||
# it, but we can iterate over it later.
|
||||
reblogged_id_sets[feed_id] = redis.zrange(reblog_key, 0, -1)
|
||||
redis.del(reblog_key)
|
||||
reblogged_id_sets[feed_id] = pipeline.zrange(reblog_key, 0, -1)
|
||||
pipeline.del(reblog_key)
|
||||
end
|
||||
end
|
||||
|
||||
# Remove all of the reblog tracking keys we just removed the
|
||||
# references to.
|
||||
redis.pipelined do
|
||||
redis.pipelined do |pipeline|
|
||||
reblogged_id_sets.each do |feed_id, future|
|
||||
future.value.each do |reblogged_id|
|
||||
reblog_set_key = key(type, feed_id, "reblogs:#{reblogged_id}")
|
||||
redis.del(reblog_set_key)
|
||||
pipeline.del(reblog_set_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -519,7 +519,7 @@ class FeedManager
|
|||
# REBLOG_FALLOFF most recent statuses, so we note that this
|
||||
# is an "extra" reblog, by storing it in reblog_set_key.
|
||||
reblog_set_key = key(timeline_type, account_id, "reblogs:#{status.reblog_of_id}")
|
||||
redis.sadd(reblog_set_key, status.id)
|
||||
redis.sadd?(reblog_set_key, status.id)
|
||||
return false
|
||||
end
|
||||
else
|
||||
|
@ -556,7 +556,7 @@ class FeedManager
|
|||
# 2. Remove reblog from set of this status's reblogs.
|
||||
reblog_set_key = key(timeline_type, account_id, "reblogs:#{status.reblog_of_id}")
|
||||
|
||||
redis.srem(reblog_set_key, status.id)
|
||||
redis.srem?(reblog_set_key, status.id)
|
||||
redis.zrem(reblog_key, status.reblog_of_id)
|
||||
# 3. Re-insert another reblog or original into the feed if one
|
||||
# remains in the set. We could pick a random element, but this
|
||||
|
|
|
@ -42,6 +42,6 @@ class Vacuum::StatusesVacuum
|
|||
end
|
||||
|
||||
def remove_from_search_index(status_ids)
|
||||
with_redis { |redis| redis.sadd('chewy:queue:StatusesIndex', status_ids) }
|
||||
with_redis { |redis| redis.sadd?('chewy:queue:StatusesIndex', status_ids) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -59,7 +59,7 @@ class AccountMigration < ApplicationRecord
|
|||
|
||||
def set_target_account
|
||||
self.target_account = ResolveAccountService.new.call(acct, skip_cache: true)
|
||||
rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error
|
||||
rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error, Addressable::URI::InvalidURIError
|
||||
# Validation will take care of it
|
||||
end
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ module DomainMaterializable
|
|||
|
||||
Instance.refresh
|
||||
count_unique_subdomains!
|
||||
|
||||
end
|
||||
|
||||
def count_unique_subdomains!
|
||||
|
|
|
@ -54,7 +54,7 @@ class CustomFilter < ApplicationRecord
|
|||
end
|
||||
|
||||
def irreversible=(value)
|
||||
self.action = value ? :hide : :warn
|
||||
self.action = ActiveModel::Type::Boolean.new.cast(value) ? :hide : :warn
|
||||
end
|
||||
|
||||
def irreversible?
|
||||
|
|
|
@ -19,9 +19,9 @@ class FollowRecommendationSuppression < ApplicationRecord
|
|||
private
|
||||
|
||||
def remove_follow_recommendations
|
||||
redis.pipelined do
|
||||
redis.pipelined do |pipeline|
|
||||
I18n.available_locales.each do |locale|
|
||||
redis.zrem("follow_recommendations:#{locale}", account_id)
|
||||
pipeline.zrem("follow_recommendations:#{locale}", account_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,7 +32,7 @@ class Form::Redirect
|
|||
|
||||
def set_target_account
|
||||
@target_account = ResolveAccountService.new.call(acct, skip_cache: true)
|
||||
rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error
|
||||
rescue Webfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error, Addressable::URI::InvalidURIError
|
||||
# Validation will take care of it
|
||||
end
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ class Trends::Base
|
|||
end
|
||||
|
||||
def record_used_id(id, at_time = Time.now.utc)
|
||||
redis.sadd(used_key(at_time), id)
|
||||
redis.sadd?(used_key(at_time), id)
|
||||
redis.expire(used_key(at_time), 1.day.seconds)
|
||||
end
|
||||
|
||||
|
|
|
@ -48,9 +48,9 @@ class BatchedRemoveStatusService < BaseService
|
|||
|
||||
# Cannot be batched
|
||||
@status_id_cutoff = Mastodon::Snowflake.id_at(2.weeks.ago)
|
||||
redis.pipelined do
|
||||
redis.pipelined do |pipeline|
|
||||
statuses.each do |status|
|
||||
unpush_from_public_timelines(status)
|
||||
unpush_from_public_timelines(pipeline, status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -73,22 +73,22 @@ class BatchedRemoveStatusService < BaseService
|
|||
end
|
||||
end
|
||||
|
||||
def unpush_from_public_timelines(status)
|
||||
def unpush_from_public_timelines(pipeline, status)
|
||||
return unless status.public_visibility? && status.id > @status_id_cutoff
|
||||
|
||||
payload = Oj.dump(event: :delete, payload: status.id.to_s)
|
||||
|
||||
redis.publish('timeline:public', payload)
|
||||
redis.publish(status.local? ? 'timeline:public:local' : 'timeline:public:remote', payload)
|
||||
pipeline.publish('timeline:public', payload)
|
||||
pipeline.publish(status.local? ? 'timeline:public:local' : 'timeline:public:remote', payload)
|
||||
|
||||
if status.media_attachments.any?
|
||||
redis.publish('timeline:public:media', payload)
|
||||
redis.publish(status.local? ? 'timeline:public:local:media' : 'timeline:public:remote:media', payload)
|
||||
pipeline.publish('timeline:public:media', payload)
|
||||
pipeline.publish(status.local? ? 'timeline:public:local:media' : 'timeline:public:remote:media', payload)
|
||||
end
|
||||
|
||||
status.tags.map { |tag| tag.name.mb_chars.downcase }.each do |hashtag|
|
||||
redis.publish("timeline:hashtag:#{hashtag}", payload)
|
||||
redis.publish("timeline:hashtag:#{hashtag}:local", payload) if status.local?
|
||||
pipeline.publish("timeline:hashtag:#{hashtag}", payload)
|
||||
pipeline.publish("timeline:hashtag:#{hashtag}:local", payload) if status.local?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ class Scheduler::IndexingScheduler
|
|||
type.import!(ids)
|
||||
|
||||
redis.pipelined do |pipeline|
|
||||
ids.each { |id| pipeline.srem("chewy:queue:#{type.name}", id) }
|
||||
ids.each { |id| pipeline.srem?("chewy:queue:#{type.name}", id) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -71,6 +71,7 @@ module Mastodon
|
|||
:af,
|
||||
:ar,
|
||||
:ast,
|
||||
:be,
|
||||
:bg,
|
||||
:bn,
|
||||
:br,
|
||||
|
|
|
@ -2,6 +2,7 @@ default: &default
|
|||
adapter: postgresql
|
||||
pool: <%= ENV["DB_POOL"] || ENV['MAX_THREADS'] || 5 %>
|
||||
timeout: 5000
|
||||
connect_timeout: 15
|
||||
encoding: unicode
|
||||
sslmode: <%= ENV['DB_SSLMODE'] || "prefer" %>
|
||||
|
||||
|
|
41
config/locales-glitch/cs.yml
Normal file
41
config/locales-glitch/cs.yml
Normal file
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
cs:
|
||||
admin:
|
||||
custom_emojis:
|
||||
batch_copy_error: 'Při kopírování některých emoji došlo k chybě: %{message}'
|
||||
batch_error: 'Došlo k chybě: %{message}'
|
||||
settings:
|
||||
captcha_enabled:
|
||||
desc_html: Tato funkce používá externí skripty služby hCaptcha, což může být problém z hlediska bezpečí a ochrany dat. Také to může <strong>některým (hlavně postiženým) lidem registrační proces výrazně zkomplikovat</strong>. Z tohoto důvodu prosím raději zvažte jiné možnosti, jako je schvalování registrací nebo registrace pouze pro zvané.<br>Uživatelům pozvaným skrze omezenou pozvánku se CAPTCHA nezobrazí.
|
||||
title: Vyžadovat po nových uživatelích opsání textu z obrázku (CAPTCHA)
|
||||
enable_keybase:
|
||||
desc_html: Uživatelé budou moci potvrdit svou identitu pomocí Keybase
|
||||
title: Zapnout potvrzování pomocí Keybase
|
||||
flavour_and_skin:
|
||||
title: Rozhraní a styl
|
||||
other:
|
||||
preamble: Různá nastavení glitch-soc, která se nevešla do jiných kategorií.
|
||||
title: Jiné
|
||||
outgoing_spoilers:
|
||||
desc_html: Při federování příspěvků se přidá toto varování o obsahu příspěvkům, které žádné nemají. To může být užitečné, pokud je váš server zaměřen na specifický obsah, pro který by jiné servery mohly varování o obsahu vyžadovat. Připojená média budou označena jako citlivá.
|
||||
title: Varování o obsahu pro odesílané příspěvky
|
||||
hide_followers_count:
|
||||
desc_html: Nezobrazovat na uživatelských profilech počet sledujících
|
||||
title: Schovat počet sledujících
|
||||
show_reblogs_in_public_timelines:
|
||||
desc_html: Veřejné boosty veřejných příspěvků se zobrazí na místní a federované časové ose.
|
||||
title: Zobrazovat ve veřejných časových osách boosty
|
||||
show_replies_in_public_timelines:
|
||||
desc_html: Na místní a federované časové ose se kromě odpovědí autora na vlastní příspěvky (vláken) zobrazí i ostatní veřejné odpovědi.
|
||||
title: Zobrazovat ve veřejných časových osách odpovědi
|
||||
trending_status_cw:
|
||||
desc_html: Zobrazovat v rámci trendů (pokud jsou zapnuté) i příspěvky s varováním o obsahu. Změny tohoto nastavení se neprojeví retroaktivně.
|
||||
title: Povolit v trendech příspěvky s varováním o obsahu
|
||||
auth:
|
||||
captcha_confirmation:
|
||||
hint_html: Už jen poslední krok! Pro potvrzení svého účtu opište prosím text z obrázku (CAPTCHA). Pokud máte dotazy nebo potřebujete s potvrzením pomoct, můžete <a href="/about/more">kontaktovat administrátora</a>.
|
||||
title: Ověření uživatele
|
||||
generic:
|
||||
use_this: Použít
|
||||
settings:
|
||||
flavours: Rozhraní
|
27
config/locales-glitch/simple_form.cs.yml
Normal file
27
config/locales-glitch/simple_form.cs.yml
Normal file
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
cs:
|
||||
simple_form:
|
||||
glitch_only: glitch-soc
|
||||
hints:
|
||||
defaults:
|
||||
fields: Na svém profilu můžete mít zobrazeno několik položek (max. %{count}) jako tabulku
|
||||
setting_default_content_type_html: Předpokládat, že nové příspěvky jsou napsané v HTML, pokud není uvedeno jinak
|
||||
setting_default_content_type_markdown: Předpokládat, že nové příspěvky používají pro formátování Markdown, pokud není uvedeno jinak
|
||||
setting_default_content_type_plain: Předpokládat, že nové příspěvky nejsou nijak formátované, pokud není uvedeno jinak (standardní chování Mastodonu)
|
||||
setting_default_language: Jazyk vašich příspěvků lze detekovat automaticky, ale není to vždycky přesné
|
||||
setting_hide_followers_count: Počet vašich sledujících se nebude nikomu zobrazovat, ani vám. Některé aplikace mohou zobrazit negativní počet sledujících.
|
||||
setting_skin: Aplikuje barevný styl na zvolené rozhraní Mastodonu
|
||||
labels:
|
||||
defaults:
|
||||
setting_default_content_type: Výchozí formát příspěvků
|
||||
setting_default_content_type_html: HTML
|
||||
setting_default_content_type_markdown: Markdown
|
||||
setting_default_content_type_plain: Prostý text
|
||||
setting_favourite_modal: Před oblíbením příspěvku zobrazit potvrzovací dialog (pouze pro rozhraní Glitch)
|
||||
setting_hide_followers_count: Skrýt počet vašich sledujících
|
||||
setting_skin: Styl
|
||||
setting_system_emoji_font: Použít výchozí emoji systému (pouze pro rozhraní Glitch)
|
||||
notification_emails:
|
||||
trending_tag: Nový populární hashtag vyžaduje schválení
|
||||
trending_link: Nový populární odkaz vyžaduje schválení
|
||||
trending_status: Nový populární příspěvek vyžaduje schválení
|
|
@ -79,69 +79,72 @@ class BackfillAdminActionLogs < ActiveRecord::Migration[6.1]
|
|||
safety_assured do
|
||||
AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log|
|
||||
next if log.account.nil?
|
||||
log.update(human_identifier: log.account.acct)
|
||||
log.update_attribute('human_identifier', log.account.acct)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(user: :account).where(target_type: 'User', human_identifier: nil).find_each do |log|
|
||||
next if log.user.nil?
|
||||
log.update(human_identifier: log.user.account.acct, route_param: log.user.account_id)
|
||||
log.update_attribute('human_identifier', log.user.account.acct)
|
||||
log.update_attribute('route_param', log.user.account_id)
|
||||
end
|
||||
|
||||
Admin::ActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text')
|
||||
|
||||
AdminActionLog.includes(:domain_block).where(target_type: 'DomainBlock').find_each do |log|
|
||||
next if log.domain_block.nil?
|
||||
log.update(human_identifier: log.domain_block.domain)
|
||||
log.update_attribute('human_identifier', log.domain_block.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:domain_allow).where(target_type: 'DomainAllow').find_each do |log|
|
||||
next if log.domain_allow.nil?
|
||||
log.update(human_identifier: log.domain_allow.domain)
|
||||
log.update_attribute('human_identifier', log.domain_allow.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:email_domain_block).where(target_type: 'EmailDomainBlock').find_each do |log|
|
||||
next if log.email_domain_block.nil?
|
||||
log.update(human_identifier: log.email_domain_block.domain)
|
||||
log.update_attribute('human_identifier', log.email_domain_block.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:unavailable_domain).where(target_type: 'UnavailableDomain').find_each do |log|
|
||||
next if log.unavailable_domain.nil?
|
||||
log.update(human_identifier: log.unavailable_domain.domain)
|
||||
log.update_attribute('human_identifier', log.unavailable_domain.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(status: :account).where(target_type: 'Status', human_identifier: nil).find_each do |log|
|
||||
next if log.status.nil?
|
||||
log.update(human_identifier: log.status.account.acct, permalink: log.status.uri)
|
||||
log.update_attribute('human_identifier', log.status.account.acct)
|
||||
log.update_attribute('permalink', log.status.uri)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(account_warning: :account).where(target_type: 'AccountWarning', human_identifier: nil).find_each do |log|
|
||||
next if log.account_warning.nil?
|
||||
log.update(human_identifier: log.account_warning.account.acct)
|
||||
log.update_attribute('human_identifier', log.account_warning.account.acct)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:announcement).where(target_type: 'Announcement', human_identifier: nil).find_each do |log|
|
||||
next if log.announcement.nil?
|
||||
log.update(human_identifier: log.announcement.text)
|
||||
log.update_attribute('human_identifier', log.announcement.text)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:ip_block).where(target_type: 'IpBlock', human_identifier: nil).find_each do |log|
|
||||
next if log.ip_block.nil?
|
||||
log.update(human_identifier: "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}")
|
||||
log.update_attribute('human_identifier', "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}")
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:custom_emoji).where(target_type: 'CustomEmoji', human_identifier: nil).find_each do |log|
|
||||
next if log.custom_emoji.nil?
|
||||
log.update(human_identifier: log.custom_emoji.shortcode)
|
||||
log.update_attribute('human_identifier', log.custom_emoji.shortcode)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:canonical_email_block).where(target_type: 'CanonicalEmailBlock', human_identifier: nil).find_each do |log|
|
||||
next if log.canonical_email_block.nil?
|
||||
log.update(human_identifier: log.canonical_email_block.canonical_email_hash)
|
||||
log.update_attribute('human_identifier', log.canonical_email_block.canonical_email_hash)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(appeal: :account).where(target_type: 'Appeal', human_identifier: nil).find_each do |log|
|
||||
next if log.appeal.nil?
|
||||
log.update(human_identifier: log.appeal.account.acct, route_param: log.appeal.account_warning_id)
|
||||
log.update_attribute('human_identifier', log.appeal.account.acct)
|
||||
log.update_attribute('route_param', log.appeal.account_warning_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class BackfillAdminActionLogsAgain < ActiveRecord::Migration[6.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
class Account < ApplicationRecord
|
||||
# Dummy class, to make migration possible across version changes
|
||||
has_one :user, inverse_of: :account
|
||||
|
||||
def local?
|
||||
domain.nil?
|
||||
end
|
||||
|
||||
def acct
|
||||
local? ? username : "#{username}@#{domain}"
|
||||
end
|
||||
end
|
||||
|
||||
class User < ApplicationRecord
|
||||
# Dummy class, to make migration possible across version changes
|
||||
belongs_to :account
|
||||
end
|
||||
|
||||
class Status < ApplicationRecord
|
||||
include RoutingHelper
|
||||
|
||||
# Dummy class, to make migration possible across version changes
|
||||
belongs_to :account
|
||||
|
||||
def local?
|
||||
attributes['local'] || attributes['uri'].nil?
|
||||
end
|
||||
|
||||
def uri
|
||||
local? ? activity_account_status_url(account, self) : attributes['uri']
|
||||
end
|
||||
end
|
||||
|
||||
class DomainBlock < ApplicationRecord; end
|
||||
class DomainAllow < ApplicationRecord; end
|
||||
class EmailDomainBlock < ApplicationRecord; end
|
||||
class UnavailableDomain < ApplicationRecord; end
|
||||
|
||||
class AccountWarning < ApplicationRecord
|
||||
# Dummy class, to make migration possible across version changes
|
||||
belongs_to :account
|
||||
end
|
||||
|
||||
class Announcement < ApplicationRecord; end
|
||||
class IpBlock < ApplicationRecord; end
|
||||
class CustomEmoji < ApplicationRecord; end
|
||||
class CanonicalEmailBlock < ApplicationRecord; end
|
||||
|
||||
class Appeal < ApplicationRecord
|
||||
# Dummy class, to make migration possible across version changes
|
||||
belongs_to :account
|
||||
end
|
||||
|
||||
class AdminActionLog < ApplicationRecord
|
||||
# Dummy class, to make migration possible across version changes
|
||||
|
||||
# Cannot use usual polymorphic support because of namespacing issues
|
||||
belongs_to :status, foreign_key: :target_id
|
||||
belongs_to :account, foreign_key: :target_id
|
||||
belongs_to :user, foreign_key: :user_id
|
||||
belongs_to :domain_block, foreign_key: :target_id
|
||||
belongs_to :domain_allow, foreign_key: :target_id
|
||||
belongs_to :email_domain_block, foreign_key: :target_id
|
||||
belongs_to :unavailable_domain, foreign_key: :target_id
|
||||
belongs_to :account_warning, foreign_key: :target_id
|
||||
belongs_to :announcement, foreign_key: :target_id
|
||||
belongs_to :ip_block, foreign_key: :target_id
|
||||
belongs_to :custom_emoji, foreign_key: :target_id
|
||||
belongs_to :canonical_email_block, foreign_key: :target_id
|
||||
belongs_to :appeal, foreign_key: :target_id
|
||||
end
|
||||
|
||||
def up
|
||||
safety_assured do
|
||||
AdminActionLog.includes(:account).where(target_type: 'Account', human_identifier: nil).find_each do |log|
|
||||
next if log.account.nil?
|
||||
log.update_attribute('human_identifier', log.account.acct)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(user: :account).where(target_type: 'User', human_identifier: nil).find_each do |log|
|
||||
next if log.user.nil?
|
||||
log.update_attribute('human_identifier', log.user.account.acct)
|
||||
log.update_attribute('route_param', log.user.account_id)
|
||||
end
|
||||
|
||||
Admin::ActionLog.where(target_type: 'Report', human_identifier: nil).in_batches.update_all('human_identifier = target_id::text')
|
||||
|
||||
AdminActionLog.includes(:domain_block).where(target_type: 'DomainBlock').find_each do |log|
|
||||
next if log.domain_block.nil?
|
||||
log.update_attribute('human_identifier', log.domain_block.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:domain_allow).where(target_type: 'DomainAllow').find_each do |log|
|
||||
next if log.domain_allow.nil?
|
||||
log.update_attribute('human_identifier', log.domain_allow.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:email_domain_block).where(target_type: 'EmailDomainBlock').find_each do |log|
|
||||
next if log.email_domain_block.nil?
|
||||
log.update_attribute('human_identifier', log.email_domain_block.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:unavailable_domain).where(target_type: 'UnavailableDomain').find_each do |log|
|
||||
next if log.unavailable_domain.nil?
|
||||
log.update_attribute('human_identifier', log.unavailable_domain.domain)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(status: :account).where(target_type: 'Status', human_identifier: nil).find_each do |log|
|
||||
next if log.status.nil?
|
||||
log.update_attribute('human_identifier', log.status.account.acct)
|
||||
log.update_attribute('permalink', log.status.uri)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(account_warning: :account).where(target_type: 'AccountWarning', human_identifier: nil).find_each do |log|
|
||||
next if log.account_warning.nil?
|
||||
log.update_attribute('human_identifier', log.account_warning.account.acct)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:announcement).where(target_type: 'Announcement', human_identifier: nil).find_each do |log|
|
||||
next if log.announcement.nil?
|
||||
log.update_attribute('human_identifier', log.announcement.text)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:ip_block).where(target_type: 'IpBlock', human_identifier: nil).find_each do |log|
|
||||
next if log.ip_block.nil?
|
||||
log.update_attribute('human_identifier', "#{log.ip_block.ip}/#{log.ip_block.ip.prefix}")
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:custom_emoji).where(target_type: 'CustomEmoji', human_identifier: nil).find_each do |log|
|
||||
next if log.custom_emoji.nil?
|
||||
log.update_attribute('human_identifier', log.custom_emoji.shortcode)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(:canonical_email_block).where(target_type: 'CanonicalEmailBlock', human_identifier: nil).find_each do |log|
|
||||
next if log.canonical_email_block.nil?
|
||||
log.update_attribute('human_identifier', log.canonical_email_block.canonical_email_hash)
|
||||
end
|
||||
|
||||
AdminActionLog.includes(appeal: :account).where(target_type: 'Appeal', human_identifier: nil).find_each do |log|
|
||||
next if log.appeal.nil?
|
||||
log.update_attribute('human_identifier', log.appeal.account.acct)
|
||||
log.update_attribute('route_param', log.appeal.account_warning_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def down; end
|
||||
end
|
14
db/schema.rb
14
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2022_11_24_114030) do
|
||||
ActiveRecord::Schema.define(version: 2022_12_06_114142) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -781,16 +781,6 @@ ActiveRecord::Schema.define(version: 2022_11_24_114030) do
|
|||
t.index ["status_id", "preview_card_id"], name: "index_preview_cards_statuses_on_status_id_and_preview_card_id"
|
||||
end
|
||||
|
||||
create_table "reactions", force: :cascade do |t|
|
||||
t.string "emoji"
|
||||
t.bigint "status_id", null: false
|
||||
t.bigint "account_id", null: false
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
t.index ["account_id"], name: "index_reactions_on_account_id"
|
||||
t.index ["status_id"], name: "index_reactions_on_status_id"
|
||||
end
|
||||
|
||||
create_table "relays", force: :cascade do |t|
|
||||
t.string "inbox_url", default: "", null: false
|
||||
t.string "follow_activity_id"
|
||||
|
@ -1221,8 +1211,6 @@ ActiveRecord::Schema.define(version: 2022_11_24_114030) do
|
|||
add_foreign_key "polls", "accounts", on_delete: :cascade
|
||||
add_foreign_key "polls", "statuses", on_delete: :cascade
|
||||
add_foreign_key "preview_card_trends", "preview_cards", on_delete: :cascade
|
||||
add_foreign_key "reactions", "accounts"
|
||||
add_foreign_key "reactions", "statuses"
|
||||
add_foreign_key "report_notes", "accounts", on_delete: :cascade
|
||||
add_foreign_key "report_notes", "reports", on_delete: :cascade
|
||||
add_foreign_key "reports", "accounts", column: "action_taken_by_account_id", name: "fk_bca45b75fd", on_delete: :nullify
|
||||
|
|
|
@ -17,7 +17,7 @@ module Chewy
|
|||
RedisConfiguration.with do |redis|
|
||||
redis.pipelined do |pipeline|
|
||||
@stash.each do |type, ids|
|
||||
pipeline.sadd("chewy:queue:#{type.name}", ids)
|
||||
pipeline.sadd?("chewy:queue:#{type.name}", ids)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -54,8 +54,8 @@ module Mastodon
|
|||
def clear
|
||||
keys = redis.keys('feed:*')
|
||||
|
||||
redis.pipelined do
|
||||
keys.each { |key| redis.del(key) }
|
||||
redis.pipelined do |pipeline|
|
||||
keys.each { |key| pipeline.del(key) }
|
||||
end
|
||||
|
||||
say('OK', :green)
|
||||
|
|
|
@ -25,7 +25,7 @@ module Mastodon
|
|||
end
|
||||
|
||||
def suffix_version
|
||||
'+1.0.10'
|
||||
'+1.0.11'
|
||||
end
|
||||
|
||||
def post_suffix
|
||||
|
|
|
@ -43,6 +43,16 @@ namespace :tests do
|
|||
puts 'CustomFilterKeyword records not created as expected'
|
||||
exit(1)
|
||||
end
|
||||
|
||||
unless Admin::ActionLog.find_by(target_type: 'DomainBlock', target_id: 1).human_identifier == 'example.org'
|
||||
puts 'Admin::ActionLog domain block records not updated as expected'
|
||||
exit(1)
|
||||
end
|
||||
|
||||
unless Admin::ActionLog.find_by(target_type: 'EmailDomainBlock', target_id: 1).human_identifier == 'example.org'
|
||||
puts 'Admin::ActionLog email domain block records not updated as expected'
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Populate the database with test data for 2.4.3'
|
||||
|
@ -84,8 +94,8 @@ namespace :tests do
|
|||
VALUES
|
||||
(1, 'destroy', 'Account', 1, now(), now()),
|
||||
(1, 'destroy', 'User', 1, now(), now()),
|
||||
(1, 'destroy', 'DomainBlock', 1312, now(), now()),
|
||||
(1, 'destroy', 'EmailDomainBlock', 1312, now(), now()),
|
||||
(1, 'destroy', 'DomainBlock', 1, now(), now()),
|
||||
(1, 'destroy', 'EmailDomainBlock', 1, now(), now()),
|
||||
(1, 'destroy', 'Status', 1, now(), now()),
|
||||
(1, 'destroy', 'CustomEmoji', 3, now(), now());
|
||||
SQL
|
||||
|
|
|
@ -147,6 +147,87 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'POST #approve' do
|
||||
subject { post :approve, params: { id: account.id } }
|
||||
|
||||
let(:current_user) { Fabricate(:user, role: role) }
|
||||
let(:account) { user.account }
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
account.user.update(approved: false)
|
||||
end
|
||||
|
||||
context 'when user is admin' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
|
||||
it 'succeeds in approving account' do
|
||||
is_expected.to redirect_to admin_accounts_path(status: 'pending')
|
||||
expect(user.reload).to be_approved
|
||||
end
|
||||
|
||||
it 'logs action' do
|
||||
is_expected.to have_http_status :found
|
||||
|
||||
log_item = Admin::ActionLog.last
|
||||
|
||||
expect(log_item).to_not be_nil
|
||||
expect(log_item.action).to eq :approve
|
||||
expect(log_item.account_id).to eq current_user.account_id
|
||||
expect(log_item.target_id).to eq account.user.id
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not admin' do
|
||||
let(:role) { UserRole.everyone }
|
||||
|
||||
it 'fails to approve account' do
|
||||
is_expected.to have_http_status :forbidden
|
||||
expect(user.reload).not_to be_approved
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #reject' do
|
||||
subject { post :reject, params: { id: account.id } }
|
||||
|
||||
let(:current_user) { Fabricate(:user, role: role) }
|
||||
let(:account) { user.account }
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
account.user.update(approved: false)
|
||||
end
|
||||
|
||||
context 'when user is admin' do
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
|
||||
it 'succeeds in rejecting account' do
|
||||
is_expected.to redirect_to admin_accounts_path(status: 'pending')
|
||||
end
|
||||
|
||||
it 'logs action' do
|
||||
is_expected.to have_http_status :found
|
||||
|
||||
log_item = Admin::ActionLog.last
|
||||
|
||||
expect(log_item).to_not be_nil
|
||||
expect(log_item.action).to eq :reject
|
||||
expect(log_item.account_id).to eq current_user.account_id
|
||||
expect(log_item.target_id).to eq account.user.id
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not admin' do
|
||||
let(:role) { UserRole.everyone }
|
||||
|
||||
it 'fails to reject account' do
|
||||
is_expected.to have_http_status :forbidden
|
||||
expect(user.reload).not_to be_approved
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #redownload' do
|
||||
subject { post :redownload, params: { id: account.id } }
|
||||
|
||||
|
|
|
@ -100,6 +100,15 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
|||
it 'approves user' do
|
||||
expect(account.reload.user_approved?).to be true
|
||||
end
|
||||
|
||||
it 'logs action' do
|
||||
log_item = Admin::ActionLog.last
|
||||
|
||||
expect(log_item).to_not be_nil
|
||||
expect(log_item.action).to eq :approve
|
||||
expect(log_item.account_id).to eq user.account_id
|
||||
expect(log_item.target_id).to eq account.user.id
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #reject' do
|
||||
|
@ -118,6 +127,15 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
|||
it 'removes user' do
|
||||
expect(User.where(id: account.user.id).count).to eq 0
|
||||
end
|
||||
|
||||
it 'logs action' do
|
||||
log_item = Admin::ActionLog.last
|
||||
|
||||
expect(log_item).to_not be_nil
|
||||
expect(log_item.action).to eq :reject
|
||||
expect(log_item.account_id).to eq user.account_id
|
||||
expect(log_item.target_id).to eq account.user.id
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #enable' do
|
||||
|
|
|
@ -22,9 +22,11 @@ RSpec.describe Api::V1::FiltersController, type: :controller do
|
|||
|
||||
describe 'POST #create' do
|
||||
let(:scopes) { 'write:filters' }
|
||||
let(:irreversible) { true }
|
||||
let(:whole_word) { false }
|
||||
|
||||
before do
|
||||
post :create, params: { phrase: 'magic', context: %w(home), irreversible: true }
|
||||
post :create, params: { phrase: 'magic', context: %w(home), irreversible: irreversible, whole_word: whole_word }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
|
@ -34,11 +36,29 @@ RSpec.describe Api::V1::FiltersController, type: :controller do
|
|||
it 'creates a filter' do
|
||||
filter = user.account.custom_filters.first
|
||||
expect(filter).to_not be_nil
|
||||
expect(filter.keywords.pluck(:keyword)).to eq ['magic']
|
||||
expect(filter.keywords.pluck(:keyword, :whole_word)).to eq [['magic', whole_word]]
|
||||
expect(filter.context).to eq %w(home)
|
||||
expect(filter.irreversible?).to be true
|
||||
expect(filter.irreversible?).to be irreversible
|
||||
expect(filter.expires_at).to be_nil
|
||||
end
|
||||
|
||||
context 'with different parameters' do
|
||||
let(:irreversible) { false }
|
||||
let(:whole_word) { true }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates a filter' do
|
||||
filter = user.account.custom_filters.first
|
||||
expect(filter).to_not be_nil
|
||||
expect(filter.keywords.pluck(:keyword, :whole_word)).to eq [['magic', whole_word]]
|
||||
expect(filter.context).to eq %w(home)
|
||||
expect(filter.irreversible?).to be irreversible
|
||||
expect(filter.expires_at).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
|
|
|
@ -22,7 +22,7 @@ describe DeliveryFailureTracker do
|
|||
|
||||
describe '#track_failure!' do
|
||||
it 'marks URL as unavailable after 7 days of being called' do
|
||||
6.times { |i| redis.sadd('exhausted_deliveries:example.com', i) }
|
||||
6.times { |i| redis.sadd?('exhausted_deliveries:example.com', i) }
|
||||
subject.track_failure!
|
||||
|
||||
expect(subject.days).to eq 7
|
||||
|
|
|
@ -11,7 +11,7 @@ RSpec.describe Vacuum::FeedsVacuum do
|
|||
redis.zadd(feed_key_for(inactive_user), 1, 1)
|
||||
redis.zadd(feed_key_for(active_user), 1, 1)
|
||||
redis.zadd(feed_key_for(inactive_user, 'reblogs'), 2, 2)
|
||||
redis.sadd(feed_key_for(inactive_user, 'reblogs:2'), 3)
|
||||
redis.sadd?(feed_key_for(inactive_user, 'reblogs:2'), 3)
|
||||
|
||||
subject.perform
|
||||
end
|
||||
|
|
|
@ -1,5 +1,48 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe AccountMigration, type: :model do
|
||||
describe 'validations' do
|
||||
let(:source_account) { Fabricate(:account) }
|
||||
let(:target_acct) { target_account.acct }
|
||||
|
||||
let(:subject) { AccountMigration.new(account: source_account, acct: target_acct) }
|
||||
|
||||
context 'with valid properties' do
|
||||
let(:target_account) { Fabricate(:account, username: 'target', domain: 'remote.org') }
|
||||
|
||||
before do
|
||||
target_account.aliases.create!(acct: source_account.acct)
|
||||
|
||||
service_double = double
|
||||
allow(ResolveAccountService).to receive(:new).and_return(service_double)
|
||||
allow(service_double).to receive(:call).with(target_acct, anything).and_return(target_account)
|
||||
end
|
||||
|
||||
it 'passes validations' do
|
||||
expect(subject).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context 'with unresolveable account' do
|
||||
let(:target_acct) { 'target@remote' }
|
||||
|
||||
before do
|
||||
service_double = double
|
||||
allow(ResolveAccountService).to receive(:new).and_return(service_double)
|
||||
allow(service_double).to receive(:call).with(target_acct, anything).and_return(nil)
|
||||
end
|
||||
|
||||
it 'has errors on acct field' do
|
||||
expect(subject).to model_have_error_on_field(:acct)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a space in the domain part' do
|
||||
let(:target_acct) { 'target@remote. org' }
|
||||
|
||||
it 'has errors on acct field' do
|
||||
expect(subject).to model_have_error_on_field(:acct)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue