Merge commit 'b87bfb8c96c8491f1228e0258d05119f3420db05' into glitch-soc/merge-upstream
This commit is contained in:
commit
46ddaffd40
|
@ -15,6 +15,6 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
RUN gem install foreman
|
RUN gem install foreman
|
||||||
|
|
||||||
# [Optional] Uncomment this line to install global node packages.
|
# [Optional] Uncomment this line to install global node packages.
|
||||||
RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g yarn" 2>&1
|
RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && corepack enable" 2>&1
|
||||||
|
|
||||||
COPY welcome-message.txt /usr/local/etc/vscode-dev-containers/first-run-notice.txt
|
COPY welcome-message.txt /usr/local/etc/vscode-dev-containers/first-run-notice.txt
|
||||||
|
|
|
@ -11,6 +11,7 @@ bundle install
|
||||||
git checkout -- Gemfile.lock
|
git checkout -- Gemfile.lock
|
||||||
|
|
||||||
# Fetch Javascript dependencies
|
# Fetch Javascript dependencies
|
||||||
|
corepack prepare
|
||||||
yarn install --immutable
|
yarn install --immutable
|
||||||
|
|
||||||
# [re]create, migrate, and seed the test database
|
# [re]create, migrate, and seed the test database
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// If we do not want a package to be grouped with others, we need to set its groupName
|
// If we do not want a package to be grouped with others, we need to set its groupName
|
||||||
// to `null` after any other rule set it to something.
|
// to `null` after any other rule set it to something.
|
||||||
dependencyDashboardHeader: 'This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more. Before approving any upgrade: read the description and comments in the [`renovate.json5` file](https://github.com/mastodon/mastodon/blob/main/.github/renovate.json5).',
|
dependencyDashboardHeader: 'This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more. Before approving any upgrade: read the description and comments in the [`renovate.json5` file](https://github.com/mastodon/mastodon/blob/main/.github/renovate.json5).',
|
||||||
|
postUpdateOptions: ['yarnDedupeHighest'],
|
||||||
packageRules: [
|
packageRules: [
|
||||||
{
|
{
|
||||||
// Require Dependency Dashboard Approval for major version bumps of these node packages
|
// Require Dependency Dashboard Approval for major version bumps of these node packages
|
||||||
|
|
|
@ -31,4 +31,3 @@ linters:
|
||||||
- 'app/views/admin/accounts/_buttons.html.haml'
|
- 'app/views/admin/accounts/_buttons.html.haml'
|
||||||
- 'app/views/admin/accounts/_local_account.html.haml'
|
- 'app/views/admin/accounts/_local_account.html.haml'
|
||||||
- 'app/views/admin/roles/_form.html.haml'
|
- 'app/views/admin/roles/_form.html.haml'
|
||||||
- 'app/views/layouts/application.html.haml'
|
|
||||||
|
|
|
@ -24,15 +24,6 @@ Lint/NonLocalExitFromIterator:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/helpers/jsonld_helper.rb'
|
- 'app/helpers/jsonld_helper.rb'
|
||||||
|
|
||||||
# This cop supports safe autocorrection (--autocorrect).
|
|
||||||
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
|
|
||||||
Lint/UnusedBlockArgument:
|
|
||||||
Exclude:
|
|
||||||
- 'config/initializers/content_security_policy.rb'
|
|
||||||
- 'config/initializers/doorkeeper.rb'
|
|
||||||
- 'config/initializers/paperclip.rb'
|
|
||||||
- 'config/initializers/simple_form.rb'
|
|
||||||
|
|
||||||
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
Max: 144
|
Max: 144
|
||||||
|
@ -73,26 +64,6 @@ RSpec/AnyInstance:
|
||||||
RSpec/ExampleLength:
|
RSpec/ExampleLength:
|
||||||
Max: 22
|
Max: 22
|
||||||
|
|
||||||
# Configuration parameters: AssignmentOnly.
|
|
||||||
RSpec/InstanceVariable:
|
|
||||||
Exclude:
|
|
||||||
- 'spec/controllers/api/v1/streaming_controller_spec.rb'
|
|
||||||
- 'spec/controllers/auth/confirmations_controller_spec.rb'
|
|
||||||
- 'spec/controllers/auth/passwords_controller_spec.rb'
|
|
||||||
- 'spec/controllers/auth/sessions_controller_spec.rb'
|
|
||||||
- 'spec/controllers/concerns/export_controller_concern_spec.rb'
|
|
||||||
- 'spec/controllers/home_controller_spec.rb'
|
|
||||||
- 'spec/controllers/settings/two_factor_authentication/webauthn_credentials_controller_spec.rb'
|
|
||||||
- 'spec/controllers/statuses_cleanup_controller_spec.rb'
|
|
||||||
- 'spec/models/concerns/account_finder_concern_spec.rb'
|
|
||||||
- 'spec/models/concerns/account_interactions_spec.rb'
|
|
||||||
- 'spec/models/public_feed_spec.rb'
|
|
||||||
- 'spec/serializers/activitypub/note_serializer_spec.rb'
|
|
||||||
- 'spec/serializers/activitypub/update_poll_serializer_spec.rb'
|
|
||||||
- 'spec/services/remove_status_service_spec.rb'
|
|
||||||
- 'spec/services/search_service_spec.rb'
|
|
||||||
- 'spec/services/unblock_domain_service_spec.rb'
|
|
||||||
|
|
||||||
RSpec/LetSetup:
|
RSpec/LetSetup:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'spec/controllers/api/v1/accounts/statuses_controller_spec.rb'
|
- 'spec/controllers/api/v1/accounts/statuses_controller_spec.rb'
|
||||||
|
@ -135,12 +106,6 @@ RSpec/LetSetup:
|
||||||
- 'spec/services/unsuspend_account_service_spec.rb'
|
- 'spec/services/unsuspend_account_service_spec.rb'
|
||||||
- 'spec/workers/scheduler/user_cleanup_scheduler_spec.rb'
|
- 'spec/workers/scheduler/user_cleanup_scheduler_spec.rb'
|
||||||
|
|
||||||
RSpec/MessageChain:
|
|
||||||
Exclude:
|
|
||||||
- 'spec/models/concerns/remotable_spec.rb'
|
|
||||||
- 'spec/models/session_activation_spec.rb'
|
|
||||||
- 'spec/models/setting_spec.rb'
|
|
||||||
|
|
||||||
RSpec/MultipleExpectations:
|
RSpec/MultipleExpectations:
|
||||||
Max: 8
|
Max: 8
|
||||||
|
|
||||||
|
@ -180,11 +145,6 @@ Rails/HasManyOrHasOneDependent:
|
||||||
- 'app/models/user.rb'
|
- 'app/models/user.rb'
|
||||||
- 'app/models/web/push_subscription.rb'
|
- 'app/models/web/push_subscription.rb'
|
||||||
|
|
||||||
Rails/I18nLocaleTexts:
|
|
||||||
Exclude:
|
|
||||||
- 'lib/tasks/mastodon.rake'
|
|
||||||
- 'spec/helpers/flashes_helper_spec.rb'
|
|
||||||
|
|
||||||
# Configuration parameters: Include.
|
# Configuration parameters: Include.
|
||||||
# Include: app/controllers/**/*.rb, app/mailers/**/*.rb
|
# Include: app/controllers/**/*.rb, app/mailers/**/*.rb
|
||||||
Rails/LexicallyScopedActionFilter:
|
Rails/LexicallyScopedActionFilter:
|
||||||
|
@ -560,14 +520,6 @@ Style/SingleArgumentDig:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'lib/webpacker/manifest_extensions.rb'
|
- 'lib/webpacker/manifest_extensions.rb'
|
||||||
|
|
||||||
# This cop supports safe autocorrection (--autocorrect).
|
|
||||||
# Configuration parameters: EnforcedStyle.
|
|
||||||
# SupportedStyles: require_parentheses, require_no_parentheses
|
|
||||||
Style/StabbyLambdaParentheses:
|
|
||||||
Exclude:
|
|
||||||
- 'config/environments/production.rb'
|
|
||||||
- 'config/initializers/content_security_policy.rb'
|
|
||||||
|
|
||||||
# This cop supports safe autocorrection (--autocorrect).
|
# This cop supports safe autocorrection (--autocorrect).
|
||||||
Style/StderrPuts:
|
Style/StderrPuts:
|
||||||
Exclude:
|
Exclude:
|
||||||
|
@ -626,5 +578,3 @@ Style/TrailingCommaInHashLiteral:
|
||||||
Style/WordArray:
|
Style/WordArray:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/helpers/languages_helper.rb'
|
- 'app/helpers/languages_helper.rb'
|
||||||
- 'spec/controllers/settings/imports_controller_spec.rb'
|
|
||||||
- 'spec/models/form/import_spec.rb'
|
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -16,7 +16,7 @@ gem 'dotenv-rails', '~> 2.8'
|
||||||
|
|
||||||
gem 'aws-sdk-s3', '~> 1.123', require: false
|
gem 'aws-sdk-s3', '~> 1.123', require: false
|
||||||
gem 'fog-core', '<= 2.4.0'
|
gem 'fog-core', '<= 2.4.0'
|
||||||
gem 'fog-openstack', '~> 0.3', require: false
|
gem 'fog-openstack', '~> 1.0', require: false
|
||||||
gem 'kt-paperclip', '~> 7.2'
|
gem 'kt-paperclip', '~> 7.2'
|
||||||
gem 'md-paperclip-azure', '~> 2.2', require: false
|
gem 'md-paperclip-azure', '~> 2.2', require: false
|
||||||
gem 'blurhash', '~> 0.1'
|
gem 'blurhash', '~> 0.1'
|
||||||
|
|
20
Gemfile.lock
20
Gemfile.lock
|
@ -263,7 +263,7 @@ GEM
|
||||||
erubi (1.12.0)
|
erubi (1.12.0)
|
||||||
et-orbi (1.2.7)
|
et-orbi (1.2.7)
|
||||||
tzinfo
|
tzinfo
|
||||||
excon (0.100.0)
|
excon (0.104.0)
|
||||||
fabrication (2.30.0)
|
fabrication (2.30.0)
|
||||||
faker (3.2.2)
|
faker (3.2.2)
|
||||||
i18n (>= 1.8.11, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
|
@ -298,19 +298,18 @@ GEM
|
||||||
ffi-compiler (1.0.1)
|
ffi-compiler (1.0.1)
|
||||||
ffi (>= 1.0.0)
|
ffi (>= 1.0.0)
|
||||||
rake
|
rake
|
||||||
fog-core (2.1.0)
|
fog-core (2.3.0)
|
||||||
builder
|
builder
|
||||||
excon (~> 0.58)
|
excon (~> 0.71)
|
||||||
formatador (~> 0.2)
|
formatador (>= 0.2, < 2.0)
|
||||||
mime-types
|
mime-types
|
||||||
fog-json (1.2.0)
|
fog-json (1.2.0)
|
||||||
fog-core
|
fog-core
|
||||||
multi_json (~> 1.10)
|
multi_json (~> 1.10)
|
||||||
fog-openstack (0.3.10)
|
fog-openstack (1.1.0)
|
||||||
fog-core (>= 1.45, <= 2.1.0)
|
fog-core (~> 2.1)
|
||||||
fog-json (>= 1.0)
|
fog-json (>= 1.0)
|
||||||
ipaddress (>= 0.8)
|
formatador (1.1.0)
|
||||||
formatador (0.3.0)
|
|
||||||
fugit (1.8.1)
|
fugit (1.8.1)
|
||||||
et-orbi (~> 1, >= 1.2.7)
|
et-orbi (~> 1, >= 1.2.7)
|
||||||
raabro (~> 1.4)
|
raabro (~> 1.4)
|
||||||
|
@ -370,7 +369,6 @@ GEM
|
||||||
terminal-table (>= 1.5.1)
|
terminal-table (>= 1.5.1)
|
||||||
idn-ruby (0.1.5)
|
idn-ruby (0.1.5)
|
||||||
io-console (0.6.0)
|
io-console (0.6.0)
|
||||||
ipaddress (0.8.3)
|
|
||||||
irb (1.8.1)
|
irb (1.8.1)
|
||||||
rdoc
|
rdoc
|
||||||
reline (>= 0.3.8)
|
reline (>= 0.3.8)
|
||||||
|
@ -452,7 +450,7 @@ GEM
|
||||||
memory_profiler (1.0.1)
|
memory_profiler (1.0.1)
|
||||||
mime-types (3.5.1)
|
mime-types (3.5.1)
|
||||||
mime-types-data (~> 3.2015)
|
mime-types-data (~> 3.2015)
|
||||||
mime-types-data (3.2023.0808)
|
mime-types-data (3.2023.1003)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.5)
|
mini_portile2 (2.8.5)
|
||||||
minitest (5.20.0)
|
minitest (5.20.0)
|
||||||
|
@ -858,7 +856,7 @@ DEPENDENCIES
|
||||||
fast_blank (~> 1.0)
|
fast_blank (~> 1.0)
|
||||||
fastimage
|
fastimage
|
||||||
fog-core (<= 2.4.0)
|
fog-core (<= 2.4.0)
|
||||||
fog-openstack (~> 0.3)
|
fog-openstack (~> 1.0)
|
||||||
fuubar (~> 2.5)
|
fuubar (~> 2.5)
|
||||||
haml-rails (~> 2.0)
|
haml-rails (~> 2.0)
|
||||||
haml_lint
|
haml_lint
|
||||||
|
|
|
@ -31,6 +31,11 @@ module Admin
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def batched_ordered_status_edits
|
||||||
|
@status.edits.reorder(nil).includes(:account, status: [:account]).find_each(order: :asc)
|
||||||
|
end
|
||||||
|
helper_method :batched_ordered_status_edits
|
||||||
|
|
||||||
def admin_status_batch_action_params
|
def admin_status_batch_action_params
|
||||||
params.require(:admin_status_batch_action).permit(status_ids: [])
|
params.require(:admin_status_batch_action).permit(status_ids: [])
|
||||||
end
|
end
|
||||||
|
|
|
@ -91,6 +91,14 @@ module ApplicationHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def html_title
|
||||||
|
safe_join(
|
||||||
|
[content_for(:page_title).to_s.chomp, title]
|
||||||
|
.select(&:present?),
|
||||||
|
' - '
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def title
|
def title
|
||||||
Rails.env.production? ? site_title : "#{site_title} (Dev)"
|
Rails.env.production? ? site_title : "#{site_title} (Dev)"
|
||||||
end
|
end
|
||||||
|
|
|
@ -298,5 +298,3 @@ module LanguagesHelper
|
||||||
locale_name.to_sym if locale_name.present? && I18n.available_locales.include?(locale_name.to_sym)
|
locale_name.to_sym if locale_name.present? && I18n.available_locales.include?(locale_name.to_sym)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:enable Metrics/ModuleLength
|
|
||||||
|
|
|
@ -42,4 +42,5 @@ export interface ApiAccountJSON {
|
||||||
suspended?: boolean;
|
suspended?: boolean;
|
||||||
limited?: boolean;
|
limited?: boolean;
|
||||||
memorial?: boolean;
|
memorial?: boolean;
|
||||||
|
hide_collections: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ const mapStateToProps = (state, { params: { acct, id } }) => {
|
||||||
hasMore: !!state.getIn(['user_lists', 'followers', accountId, 'next']),
|
hasMore: !!state.getIn(['user_lists', 'followers', accountId, 'next']),
|
||||||
isLoading: state.getIn(['user_lists', 'followers', accountId, 'isLoading'], true),
|
isLoading: state.getIn(['user_lists', 'followers', accountId, 'isLoading'], true),
|
||||||
suspended: state.getIn(['accounts', accountId, 'suspended'], false),
|
suspended: state.getIn(['accounts', accountId, 'suspended'], false),
|
||||||
|
hideCollections: state.getIn(['accounts', accountId, 'hide_collections'], false),
|
||||||
hidden: getAccountHidden(state, accountId),
|
hidden: getAccountHidden(state, accountId),
|
||||||
blockedBy: state.getIn(['relationships', accountId, 'blocked_by'], false),
|
blockedBy: state.getIn(['relationships', accountId, 'blocked_by'], false),
|
||||||
};
|
};
|
||||||
|
@ -111,7 +112,7 @@ class Followers extends ImmutablePureComponent {
|
||||||
}, 300, { leading: true });
|
}, 300, { leading: true });
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { accountId, accountIds, hasMore, blockedBy, isAccount, multiColumn, isLoading, suspended, hidden, remote, remoteUrl } = this.props;
|
const { accountId, accountIds, hasMore, blockedBy, isAccount, multiColumn, isLoading, suspended, hidden, remote, remoteUrl, hideCollections } = this.props;
|
||||||
|
|
||||||
if (!isAccount) {
|
if (!isAccount) {
|
||||||
return (
|
return (
|
||||||
|
@ -137,6 +138,8 @@ class Followers extends ImmutablePureComponent {
|
||||||
emptyMessage = <LimitedAccountHint accountId={accountId} />;
|
emptyMessage = <LimitedAccountHint accountId={accountId} />;
|
||||||
} else if (blockedBy) {
|
} else if (blockedBy) {
|
||||||
emptyMessage = <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />;
|
emptyMessage = <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />;
|
||||||
|
} else if (hideCollections && accountIds.isEmpty()) {
|
||||||
|
emptyMessage = <FormattedMessage id='empty_column.account_hides_collections' defaultMessage='This user has chosen to not make this information available' />;
|
||||||
} else if (remote && accountIds.isEmpty()) {
|
} else if (remote && accountIds.isEmpty()) {
|
||||||
emptyMessage = <RemoteHint url={remoteUrl} />;
|
emptyMessage = <RemoteHint url={remoteUrl} />;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -45,6 +45,7 @@ const mapStateToProps = (state, { params: { acct, id } }) => {
|
||||||
hasMore: !!state.getIn(['user_lists', 'following', accountId, 'next']),
|
hasMore: !!state.getIn(['user_lists', 'following', accountId, 'next']),
|
||||||
isLoading: state.getIn(['user_lists', 'following', accountId, 'isLoading'], true),
|
isLoading: state.getIn(['user_lists', 'following', accountId, 'isLoading'], true),
|
||||||
suspended: state.getIn(['accounts', accountId, 'suspended'], false),
|
suspended: state.getIn(['accounts', accountId, 'suspended'], false),
|
||||||
|
hideCollections: state.getIn(['accounts', accountId, 'hide_collections'], false),
|
||||||
hidden: getAccountHidden(state, accountId),
|
hidden: getAccountHidden(state, accountId),
|
||||||
blockedBy: state.getIn(['relationships', accountId, 'blocked_by'], false),
|
blockedBy: state.getIn(['relationships', accountId, 'blocked_by'], false),
|
||||||
};
|
};
|
||||||
|
@ -111,7 +112,7 @@ class Following extends ImmutablePureComponent {
|
||||||
}, 300, { leading: true });
|
}, 300, { leading: true });
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { accountId, accountIds, hasMore, blockedBy, isAccount, multiColumn, isLoading, suspended, hidden, remote, remoteUrl } = this.props;
|
const { accountId, accountIds, hasMore, blockedBy, isAccount, multiColumn, isLoading, suspended, hidden, remote, remoteUrl, hideCollections } = this.props;
|
||||||
|
|
||||||
if (!isAccount) {
|
if (!isAccount) {
|
||||||
return (
|
return (
|
||||||
|
@ -137,6 +138,8 @@ class Following extends ImmutablePureComponent {
|
||||||
emptyMessage = <LimitedAccountHint accountId={accountId} />;
|
emptyMessage = <LimitedAccountHint accountId={accountId} />;
|
||||||
} else if (blockedBy) {
|
} else if (blockedBy) {
|
||||||
emptyMessage = <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />;
|
emptyMessage = <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />;
|
||||||
|
} else if (hideCollections && accountIds.isEmpty()) {
|
||||||
|
emptyMessage = <FormattedMessage id='empty_column.account_hides_collections' defaultMessage='This user has chosen to not make this information available' />;
|
||||||
} else if (remote && accountIds.isEmpty()) {
|
} else if (remote && accountIds.isEmpty()) {
|
||||||
emptyMessage = <RemoteHint url={remoteUrl} />;
|
emptyMessage = <RemoteHint url={remoteUrl} />;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
"attachments_list.unprocessed": "(ausstehend)",
|
"attachments_list.unprocessed": "(ausstehend)",
|
||||||
"audio.hide": "Audio ausblenden",
|
"audio.hide": "Audio ausblenden",
|
||||||
"autosuggest_hashtag.per_week": "{count} pro Woche",
|
"autosuggest_hashtag.per_week": "{count} pro Woche",
|
||||||
"boost_modal.combo": "Drücke {combo}, um das beim nächsten Mal zu überspringen",
|
"boost_modal.combo": "Mit {combo} wird dieses Fenster beim nächsten Mal nicht mehr angezeigt",
|
||||||
"bundle_column_error.copy_stacktrace": "Fehlerbericht kopieren",
|
"bundle_column_error.copy_stacktrace": "Fehlerbericht kopieren",
|
||||||
"bundle_column_error.error.body": "Die angeforderte Seite konnte nicht dargestellt werden. Dies könnte auf einen Fehler in unserem Code oder auf ein Browser-Kompatibilitätsproblem zurückzuführen sein.",
|
"bundle_column_error.error.body": "Die angeforderte Seite konnte nicht dargestellt werden. Dies könnte auf einen Fehler in unserem Code oder auf ein Browser-Kompatibilitätsproblem zurückzuführen sein.",
|
||||||
"bundle_column_error.error.title": "Oh nein!",
|
"bundle_column_error.error.title": "Oh nein!",
|
||||||
|
|
|
@ -222,6 +222,7 @@
|
||||||
"emoji_button.search_results": "Search results",
|
"emoji_button.search_results": "Search results",
|
||||||
"emoji_button.symbols": "Symbols",
|
"emoji_button.symbols": "Symbols",
|
||||||
"emoji_button.travel": "Travel & Places",
|
"emoji_button.travel": "Travel & Places",
|
||||||
|
"empty_column.account_hides_collections": "This user has chosen to not make this information available",
|
||||||
"empty_column.account_suspended": "Account suspended",
|
"empty_column.account_suspended": "Account suspended",
|
||||||
"empty_column.account_timeline": "No posts here!",
|
"empty_column.account_timeline": "No posts here!",
|
||||||
"empty_column.account_unavailable": "Profile unavailable",
|
"empty_column.account_unavailable": "Profile unavailable",
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
"account.share": "שתף את הפרופיל של @{name}",
|
"account.share": "שתף את הפרופיל של @{name}",
|
||||||
"account.show_reblogs": "הצג הדהודים מאת @{name}",
|
"account.show_reblogs": "הצג הדהודים מאת @{name}",
|
||||||
"account.statuses_counter": "{count, plural, one {הודעה} two {הודעותיים} many {{count} הודעות} other {{count} הודעות}}",
|
"account.statuses_counter": "{count, plural, one {הודעה} two {הודעותיים} many {{count} הודעות} other {{count} הודעות}}",
|
||||||
"account.unblock": "הסר את החסימה של @{name}",
|
"account.unblock": "להסיר חסימה ל- @{name}",
|
||||||
"account.unblock_domain": "הסירי את החסימה של קהילת {domain}",
|
"account.unblock_domain": "הסירי את החסימה של קהילת {domain}",
|
||||||
"account.unblock_short": "הסר חסימה",
|
"account.unblock_short": "הסר חסימה",
|
||||||
"account.unendorse": "אל תקדם בפרופיל",
|
"account.unendorse": "אל תקדם בפרופיל",
|
||||||
|
|
|
@ -222,7 +222,7 @@
|
||||||
"emoji_button.search_results": "Výsledky hľadania",
|
"emoji_button.search_results": "Výsledky hľadania",
|
||||||
"emoji_button.symbols": "Symboly",
|
"emoji_button.symbols": "Symboly",
|
||||||
"emoji_button.travel": "Cestovanie a miesta",
|
"emoji_button.travel": "Cestovanie a miesta",
|
||||||
"empty_column.account_suspended": "Účet bol vylúčený",
|
"empty_column.account_suspended": "Účet bol pozastavený",
|
||||||
"empty_column.account_timeline": "Nie sú tu žiadne príspevky!",
|
"empty_column.account_timeline": "Nie sú tu žiadne príspevky!",
|
||||||
"empty_column.account_unavailable": "Profil nedostupný",
|
"empty_column.account_unavailable": "Profil nedostupný",
|
||||||
"empty_column.blocks": "Ešte si nikoho nezablokoval/a.",
|
"empty_column.blocks": "Ešte si nikoho nezablokoval/a.",
|
||||||
|
|
|
@ -93,6 +93,7 @@ export const accountDefaultValues: AccountShape = {
|
||||||
memorial: false,
|
memorial: false,
|
||||||
limited: false,
|
limited: false,
|
||||||
moved: null,
|
moved: null,
|
||||||
|
hide_collections: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const AccountFactory = ImmutableRecord<AccountShape>(accountDefaultValues);
|
const AccountFactory = ImmutableRecord<AccountShape>(accountDefaultValues);
|
||||||
|
|
|
@ -16,12 +16,36 @@ class StatusCacheHydrator
|
||||||
# We take advantage of the fact that some relationships can only occur with an original status, not
|
# We take advantage of the fact that some relationships can only occur with an original status, not
|
||||||
# the reblog that wraps it, so we can assume that some values are always false
|
# the reblog that wraps it, so we can assume that some values are always false
|
||||||
if payload[:reblog]
|
if payload[:reblog]
|
||||||
|
hydrate_reblog_payload(payload, account_id)
|
||||||
|
else
|
||||||
|
hydrate_non_reblog_payload(payload, account_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def hydrate_non_reblog_payload(empty_payload, account_id)
|
||||||
|
empty_payload.tap do |payload|
|
||||||
|
payload[:favourited] = Favourite.where(account_id: account_id, status_id: @status.id).exists?
|
||||||
|
payload[:reblogged] = Status.where(account_id: account_id, reblog_of_id: @status.id).exists?
|
||||||
|
payload[:muted] = ConversationMute.where(account_id: account_id, conversation_id: @status.conversation_id).exists?
|
||||||
|
payload[:bookmarked] = Bookmark.where(account_id: account_id, status_id: @status.id).exists?
|
||||||
|
payload[:pinned] = StatusPin.where(account_id: account_id, status_id: @status.id).exists? if @status.account_id == account_id
|
||||||
|
payload[:filtered] = mapped_applied_custom_filter(account_id, @status)
|
||||||
|
|
||||||
|
if payload[:poll]
|
||||||
|
payload[:poll][:voted] = @status.account_id == account_id
|
||||||
|
payload[:poll][:own_votes] = []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def hydrate_reblog_payload(empty_payload, account_id)
|
||||||
|
empty_payload.tap do |payload|
|
||||||
payload[:muted] = false
|
payload[:muted] = false
|
||||||
payload[:bookmarked] = false
|
payload[:bookmarked] = false
|
||||||
payload[:pinned] = false if @status.account_id == account_id
|
payload[:pinned] = false if @status.account_id == account_id
|
||||||
payload[:filtered] = CustomFilter
|
payload[:filtered] = mapped_applied_custom_filter(account_id, @status.reblog)
|
||||||
.apply_cached_filters(CustomFilter.cached_filters_for(account_id), @status.reblog)
|
|
||||||
.map { |filter| serialized_filter(filter) }
|
|
||||||
|
|
||||||
# If the reblogged status is being delivered to the author who disabled the display of the application
|
# If the reblogged status is being delivered to the author who disabled the display of the application
|
||||||
# used to create the status, we need to hydrate it here too
|
# used to create the status, we need to hydrate it here too
|
||||||
|
@ -47,26 +71,14 @@ class StatusCacheHydrator
|
||||||
|
|
||||||
payload[:favourited] = payload[:reblog][:favourited]
|
payload[:favourited] = payload[:reblog][:favourited]
|
||||||
payload[:reblogged] = payload[:reblog][:reblogged]
|
payload[:reblogged] = payload[:reblog][:reblogged]
|
||||||
else
|
|
||||||
payload[:favourited] = Favourite.where(account_id: account_id, status_id: @status.id).exists?
|
|
||||||
payload[:reblogged] = Status.where(account_id: account_id, reblog_of_id: @status.id).exists?
|
|
||||||
payload[:muted] = ConversationMute.where(account_id: account_id, conversation_id: @status.conversation_id).exists?
|
|
||||||
payload[:bookmarked] = Bookmark.where(account_id: account_id, status_id: @status.id).exists?
|
|
||||||
payload[:pinned] = StatusPin.where(account_id: account_id, status_id: @status.id).exists? if @status.account_id == account_id
|
|
||||||
payload[:filtered] = CustomFilter
|
|
||||||
.apply_cached_filters(CustomFilter.cached_filters_for(account_id), @status)
|
|
||||||
.map { |filter| serialized_filter(filter) }
|
|
||||||
|
|
||||||
if payload[:poll]
|
|
||||||
payload[:poll][:voted] = @status.account_id == account_id
|
|
||||||
payload[:poll][:own_votes] = []
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
payload
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def mapped_applied_custom_filter(account_id, status)
|
||||||
|
CustomFilter
|
||||||
|
.apply_cached_filters(CustomFilter.cached_filters_for(account_id), status)
|
||||||
|
.map { |filter| serialized_filter(filter) }
|
||||||
|
end
|
||||||
|
|
||||||
def serialized_filter(filter)
|
def serialized_filter(filter)
|
||||||
ActiveModelSerializers::SerializableResource.new(
|
ActiveModelSerializers::SerializableResource.new(
|
||||||
|
|
|
@ -8,7 +8,7 @@ class REST::AccountSerializer < ActiveModel::Serializer
|
||||||
|
|
||||||
attributes :id, :username, :acct, :display_name, :locked, :bot, :discoverable, :group, :created_at,
|
attributes :id, :username, :acct, :display_name, :locked, :bot, :discoverable, :group, :created_at,
|
||||||
:note, :url, :uri, :avatar, :avatar_static, :header, :header_static,
|
:note, :url, :uri, :avatar, :avatar_static, :header, :header_static,
|
||||||
:followers_count, :following_count, :statuses_count, :last_status_at
|
:followers_count, :following_count, :statuses_count, :last_status_at, :hide_collections
|
||||||
|
|
||||||
has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested?
|
has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested?
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
%h3= t('admin.statuses.history')
|
%h3= t('admin.statuses.history')
|
||||||
|
|
||||||
%ol.history
|
%ol.history
|
||||||
- @status.edits.reorder(nil).includes(:account, status: [:account]).find_each(order: :asc).with_index do |status_edit, i|
|
- batched_ordered_status_edits.with_index do |status_edit, i|
|
||||||
%li
|
%li
|
||||||
.history__entry
|
.history__entry
|
||||||
%h5
|
%h5
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
%meta{ name: 'theme-color', content: '#191b22' }/
|
%meta{ name: 'theme-color', content: '#191b22' }/
|
||||||
%meta{ name: 'apple-mobile-web-app-capable', content: 'yes' }/
|
%meta{ name: 'apple-mobile-web-app-capable', content: 'yes' }/
|
||||||
|
|
||||||
%title= content_for?(:page_title) ? safe_join([yield(:page_title).chomp.html_safe, title], ' - ') : title
|
%title= html_title
|
||||||
|
|
||||||
= javascript_pack_tag "common", crossorigin: 'anonymous'
|
= javascript_pack_tag "common", crossorigin: 'anonymous'
|
||||||
- if @theme
|
- if @theme
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
default: &default
|
default: &default
|
||||||
adapter: postgresql
|
adapter: postgresql
|
||||||
pool: <%= ENV["DB_POOL"] || ENV['MAX_THREADS'] || 5 %>
|
pool: <%= ENV["DB_POOL"] || (if Sidekiq.server? then Sidekiq[:concurrency] else ENV['MAX_THREADS'] end) || 5 %>
|
||||||
timeout: 5000
|
timeout: 5000
|
||||||
connect_timeout: 15
|
connect_timeout: 15
|
||||||
encoding: unicode
|
encoding: unicode
|
||||||
|
|
|
@ -44,7 +44,7 @@ Rails.application.configure do
|
||||||
config.force_ssl = true
|
config.force_ssl = true
|
||||||
config.ssl_options = {
|
config.ssl_options = {
|
||||||
redirect: {
|
redirect: {
|
||||||
exclude: ->request { request.path.start_with?('/health') || request.headers["Host"].end_with?('.onion') || request.headers["Host"].end_with?('.i2p') }
|
exclude: ->(request) { request.path.start_with?('/health') || request.headers["Host"].end_with?('.onion') || request.headers["Host"].end_with?('.i2p') }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ end
|
||||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
|
||||||
# Rails.application.config.content_security_policy_report_only = true
|
# Rails.application.config.content_security_policy_report_only = true
|
||||||
|
|
||||||
Rails.application.config.content_security_policy_nonce_generator = ->request { SecureRandom.base64(16) }
|
Rails.application.config.content_security_policy_nonce_generator = ->(_request) { SecureRandom.base64(16) }
|
||||||
|
|
||||||
Rails.application.config.content_security_policy_nonce_directives = %w(style-src)
|
Rails.application.config.content_security_policy_nonce_directives = %w(style-src)
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ Rails.application.reloader.to_prepare do
|
||||||
p.worker_src :none
|
p.worker_src :none
|
||||||
end
|
end
|
||||||
|
|
||||||
LetterOpenerWeb::LettersController.after_action do |p|
|
LetterOpenerWeb::LettersController.after_action do
|
||||||
request.content_security_policy_nonce_directives = %w(script-src)
|
request.content_security_policy_nonce_directives = %w(script-src)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -169,7 +169,7 @@ Doorkeeper.configure do
|
||||||
# Under some circumstances you might want to have applications auto-approved,
|
# Under some circumstances you might want to have applications auto-approved,
|
||||||
# so that the user skips the authorization step.
|
# so that the user skips the authorization step.
|
||||||
# For example if dealing with a trusted application.
|
# For example if dealing with a trusted application.
|
||||||
skip_authorization do |resource_owner, client|
|
skip_authorization do |_resource_owner, client|
|
||||||
client.application.superapp?
|
client.application.superapp?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ Paperclip.interpolates :filename do |attachment, style|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Paperclip.interpolates :prefix_path do |attachment, style|
|
Paperclip.interpolates :prefix_path do |attachment, _style|
|
||||||
if attachment.storage_schema_version >= 1 && attachment.instance.respond_to?(:local?) && !attachment.instance.local?
|
if attachment.storage_schema_version >= 1 && attachment.instance.respond_to?(:local?) && !attachment.instance.local?
|
||||||
'cache' + File::SEPARATOR
|
'cache' + File::SEPARATOR
|
||||||
else
|
else
|
||||||
|
@ -19,7 +19,7 @@ Paperclip.interpolates :prefix_path do |attachment, style|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Paperclip.interpolates :prefix_url do |attachment, style|
|
Paperclip.interpolates :prefix_url do |attachment, _style|
|
||||||
if attachment.storage_schema_version >= 1 && attachment.instance.respond_to?(:local?) && !attachment.instance.local?
|
if attachment.storage_schema_version >= 1 && attachment.instance.respond_to?(:local?) && !attachment.instance.local?
|
||||||
'cache/'
|
'cache/'
|
||||||
else
|
else
|
||||||
|
|
|
@ -175,7 +175,7 @@ SimpleForm.setup do |config|
|
||||||
# config.item_wrapper_class = nil
|
# config.item_wrapper_class = nil
|
||||||
|
|
||||||
# How the label text should be generated altogether with the required text.
|
# How the label text should be generated altogether with the required text.
|
||||||
config.label_text = lambda { |label, required, explicit_label| "#{label} #{required}" }
|
config.label_text = lambda { |label, required, _explicit_label| "#{label} #{required}" }
|
||||||
|
|
||||||
# You can define the class to use on all labels. Default is nil.
|
# You can define the class to use on all labels. Default is nil.
|
||||||
# config.label_class = nil
|
# config.label_class = nil
|
||||||
|
|
|
@ -1 +1,14 @@
|
||||||
|
---
|
||||||
lt:
|
lt:
|
||||||
|
activerecord:
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
account:
|
||||||
|
attributes:
|
||||||
|
username:
|
||||||
|
invalid: turi būti tik raidės, skaičiai ir pabraukimai.
|
||||||
|
reserved: užimtas.
|
||||||
|
admin/webhook:
|
||||||
|
attributes:
|
||||||
|
url:
|
||||||
|
invalid: nėra tinkamas URL adresas.
|
||||||
|
|
|
@ -556,6 +556,7 @@ be:
|
||||||
total_reported: Скаргі на іх
|
total_reported: Скаргі на іх
|
||||||
total_storage: Медыя дадаткі
|
total_storage: Медыя дадаткі
|
||||||
totals_time_period_hint_html: Паказаныя агульныя значэнні ніжэй уключаюць даныя за ўвесь час.
|
totals_time_period_hint_html: Паказаныя агульныя значэнні ніжэй уключаюць даныя за ўвесь час.
|
||||||
|
unknown_instance: На дадзены момант няма запісаў аб гэтым дамене на гэтым серверы.
|
||||||
invites:
|
invites:
|
||||||
deactivate_all: Дэактываваць усё
|
deactivate_all: Дэактываваць усё
|
||||||
filter:
|
filter:
|
||||||
|
@ -1076,6 +1077,14 @@ be:
|
||||||
hint_html: Засталася яшчэ адна рэч! Каб не дапусціць спаму, нам трэба пацвердзіць, што вы чалавек. Разгадайце CAPTCHA ніжэй і націсніце «Працягнуць».
|
hint_html: Засталася яшчэ адна рэч! Каб не дапусціць спаму, нам трэба пацвердзіць, што вы чалавек. Разгадайце CAPTCHA ніжэй і націсніце «Працягнуць».
|
||||||
title: Праверка бяспекі
|
title: Праверка бяспекі
|
||||||
confirmations:
|
confirmations:
|
||||||
|
awaiting_review: Ваш электронны адрас пацверджаны! Адміністрацыя %{domain} зараз разглядае вашу рэгістрацыю. Вы атрымаеце паведамленне па электроннай пошце, калі ваш уліковы запіс будзе ўхвалены!
|
||||||
|
awaiting_review_title: Ваша рэгістрацыя разглядаецца
|
||||||
|
clicking_this_link: націснуць на гэту спасылку
|
||||||
|
login_link: увайсці
|
||||||
|
proceed_to_login_html: Цяпер вы можаце перайсці да %{login_link}.
|
||||||
|
redirect_to_app_html: Вы павінны былі быць перанакіраваны ў праграму <strong>%{app_name}</strong>. Калі гэтага не адбылося, паспрабуйце %{clicking_this_link} або вярніцеся да праграмы ўручную.
|
||||||
|
registration_complete: Ваша рэгістрацыя на %{domain} завершана!
|
||||||
|
welcome_title: Вітаем, %{name}!
|
||||||
wrong_email_hint: Калі гэты адрас электроннай пошты памылковы, вы можаце змяніць яго ў наладах уліковага запісу.
|
wrong_email_hint: Калі гэты адрас электроннай пошты памылковы, вы можаце змяніць яго ў наладах уліковага запісу.
|
||||||
delete_account: Выдаліць уліковы запіс
|
delete_account: Выдаліць уліковы запіс
|
||||||
delete_account_html: Калі вы жадаеце выдаліць ваш уліковы запіс, можаце <a href="%{path}">працягнуць тут</a>. Ад вас будзе запатрабавана пацвярджэнне.
|
delete_account_html: Калі вы жадаеце выдаліць ваш уліковы запіс, можаце <a href="%{path}">працягнуць тут</a>. Ад вас будзе запатрабавана пацвярджэнне.
|
||||||
|
@ -1137,6 +1146,7 @@ be:
|
||||||
functional: Ваш уліковы запіс поўнасцю працуе.
|
functional: Ваш уліковы запіс поўнасцю працуе.
|
||||||
pending: Ваша заяўка разглядаецца нашым супрацоўнікам. Гэта можа заняць некаторы час. Вы атрымаеце электронны ліст, калі заяўка будзе ўхвалена.
|
pending: Ваша заяўка разглядаецца нашым супрацоўнікам. Гэта можа заняць некаторы час. Вы атрымаеце электронны ліст, калі заяўка будзе ўхвалена.
|
||||||
redirecting_to: Ваш уліковы запіс неактыўны, бо ў цяперашні час ён перанакіроўваецца на %{acct}.
|
redirecting_to: Ваш уліковы запіс неактыўны, бо ў цяперашні час ён перанакіроўваецца на %{acct}.
|
||||||
|
self_destruct: Паколькі %{domain} зачыняецца, вы атрымаеце толькі абмежаваны доступ да свайго уліковага запісу.
|
||||||
view_strikes: Праглядзець мінулыя папярэджанні для вашага ўліковага запісу
|
view_strikes: Праглядзець мінулыя папярэджанні для вашага ўліковага запісу
|
||||||
too_fast: Форма адпраўлена занадта хутка, паспрабуйце яшчэ раз.
|
too_fast: Форма адпраўлена занадта хутка, паспрабуйце яшчэ раз.
|
||||||
use_security_key: Выкарыстаеце ключ бяспекі
|
use_security_key: Выкарыстаеце ключ бяспекі
|
||||||
|
@ -1622,6 +1632,9 @@ be:
|
||||||
over_daily_limit: Вы перавысілі ліміт ў %{limit} запланаваных на сёння допісаў
|
over_daily_limit: Вы перавысілі ліміт ў %{limit} запланаваных на сёння допісаў
|
||||||
over_total_limit: Вы перавысілі ліміт ў %{limit} запланаваных допісаў
|
over_total_limit: Вы перавысілі ліміт ў %{limit} запланаваных допісаў
|
||||||
too_soon: Запланаваная дата мусіць быць у будучыні
|
too_soon: Запланаваная дата мусіць быць у будучыні
|
||||||
|
self_destruct:
|
||||||
|
lead_html: На жаль, дамен <strong>%{domain}</strong> зачыняецца назаўсёды. Калі ў вас быў уліковы запіс, вы не зможаце працягваць выкарыстоўваць яго, але вы ўсё яшчэ можаце запытаць рэзервовае капіраванне вашых даных.
|
||||||
|
title: Гэты сервер зачыняецца
|
||||||
sessions:
|
sessions:
|
||||||
activity: Апошняя актыўнасць
|
activity: Апошняя актыўнасць
|
||||||
browser: Браўзер
|
browser: Браўзер
|
||||||
|
|
|
@ -1600,7 +1600,7 @@ ko:
|
||||||
windows: 윈도우
|
windows: 윈도우
|
||||||
windows_mobile: 윈도우 모바일
|
windows_mobile: 윈도우 모바일
|
||||||
windows_phone: 윈도우 폰
|
windows_phone: 윈도우 폰
|
||||||
revoke: 삭제
|
revoke: 취소
|
||||||
revoke_success: 세션을 성공적으로 취소하였습니다
|
revoke_success: 세션을 성공적으로 취소하였습니다
|
||||||
title: 세션
|
title: 세션
|
||||||
view_authentication_history: 내 계정에 대한 인증 이력 보기
|
view_authentication_history: 내 계정에 대한 인증 이력 보기
|
||||||
|
|
|
@ -232,6 +232,12 @@ lt:
|
||||||
unassign: Nepriskirti
|
unassign: Nepriskirti
|
||||||
unresolved: Neišspręsti
|
unresolved: Neišspręsti
|
||||||
updated_at: Atnaujinti
|
updated_at: Atnaujinti
|
||||||
|
roles:
|
||||||
|
everyone: Numatytieji leidimai
|
||||||
|
everyone_full_description_html: Tai – <strong>bazinis vaidmuo</strong>, turintis įtakos <strong>visiems naudotojams</strong>, net ir tiems, kurie neturi priskirto vaidmens. Visi kiti vaidmenys iš jo paveldi teises.
|
||||||
|
settings:
|
||||||
|
domain_blocks:
|
||||||
|
all: Visiems
|
||||||
statuses:
|
statuses:
|
||||||
back_to_account: Atgal į paskyros puslapį
|
back_to_account: Atgal į paskyros puslapį
|
||||||
media:
|
media:
|
||||||
|
@ -250,6 +256,10 @@ lt:
|
||||||
body: "%{reporter} parašė skundą apie %{target}"
|
body: "%{reporter} parašė skundą apie %{target}"
|
||||||
body_remote: Kažkas iš %{domain} parašė skundą apie %{target}
|
body_remote: Kažkas iš %{domain} parašė skundą apie %{target}
|
||||||
subject: Naujas skundas %{instance} (#%{id})
|
subject: Naujas skundas %{instance} (#%{id})
|
||||||
|
appearance:
|
||||||
|
localization:
|
||||||
|
body: Mastodon verčia savanoriai.
|
||||||
|
guide_link_text: Visi gali prisidėti.
|
||||||
application_mailer:
|
application_mailer:
|
||||||
notification_preferences: Keisti el pašto parinktis
|
notification_preferences: Keisti el pašto parinktis
|
||||||
settings: 'Keisti el pašto parinktis: %{link}'
|
settings: 'Keisti el pašto parinktis: %{link}'
|
||||||
|
@ -458,9 +468,9 @@ lt:
|
||||||
private: Tik sekėjams
|
private: Tik sekėjams
|
||||||
private_long: Rodyti tik sekėjams
|
private_long: Rodyti tik sekėjams
|
||||||
public: Viešas
|
public: Viešas
|
||||||
public_long: Matyti gali visi
|
public_long: Visi gali matyti
|
||||||
unlisted: Neįtrauktas į sąrašus
|
unlisted: Neįtrauktas į sąrašus
|
||||||
unlisted_long: Matyti gali visi, tačiau nėra įtraukta į viešas laiko juostas
|
unlisted_long: Matyti gali visi, tačiau nėra įtraukti į viešąsias laiko skales
|
||||||
stream_entries:
|
stream_entries:
|
||||||
sensitive_content: Jautrus turinys
|
sensitive_content: Jautrus turinys
|
||||||
themes:
|
themes:
|
||||||
|
@ -507,4 +517,5 @@ lt:
|
||||||
seamless_external_login: Jūs esate prisijungę per išorini įrenginį, todėl slaptąžodis ir el pašto nustatymai neprieinami.
|
seamless_external_login: Jūs esate prisijungę per išorini įrenginį, todėl slaptąžodis ir el pašto nustatymai neprieinami.
|
||||||
signed_in_as: 'Prisijungta kaip:'
|
signed_in_as: 'Prisijungta kaip:'
|
||||||
verification:
|
verification:
|
||||||
|
hint_html: "<strong>Savo tapatybės patvirtinimas Mastodon skirtas visiems.</strong> Remiantis atviraisiais žiniatinklio standartais, dabar ir visam laikui nemokamas. Viskas, ko tau reikia, yra asmeninė svetainė, pagal kurią žmonės tave atpažįsta. Kai iš savo profilio pateiksi nuorodą į šią svetainę, patikrinsime, ar svetainėje yra nuoroda į tavo profilį, ir parodysime vizualinį indikatorių."
|
||||||
verification: Patvirtinimas
|
verification: Patvirtinimas
|
||||||
|
|
|
@ -1079,6 +1079,7 @@ ru:
|
||||||
confirmations:
|
confirmations:
|
||||||
awaiting_review: Ваш адрес электронной почты подтвержден! Сотрудники %{domain} проверяют вашу регистрацию. Вы получите письмо, если они подтвердят вашу учетную запись!
|
awaiting_review: Ваш адрес электронной почты подтвержден! Сотрудники %{domain} проверяют вашу регистрацию. Вы получите письмо, если они подтвердят вашу учетную запись!
|
||||||
awaiting_review_title: Ваша регистрация проверяется
|
awaiting_review_title: Ваша регистрация проверяется
|
||||||
|
clicking_this_link: нажатие на эту ссылку
|
||||||
login_link: войти
|
login_link: войти
|
||||||
proceed_to_login_html: Теперь вы можете перейти к %{login_link}.
|
proceed_to_login_html: Теперь вы можете перейти к %{login_link}.
|
||||||
registration_complete: Ваша регистрация на %{domain} завершена!
|
registration_complete: Ваша регистрация на %{domain} завершена!
|
||||||
|
@ -1536,7 +1537,7 @@ ru:
|
||||||
update:
|
update:
|
||||||
subject: "%{name} изменил(а) пост"
|
subject: "%{name} изменил(а) пост"
|
||||||
notifications:
|
notifications:
|
||||||
administration_emails: E-mail уведомления администратора
|
administration_emails: Уведомления администратора по электронной почте
|
||||||
email_events: События для e-mail уведомлений
|
email_events: События для e-mail уведомлений
|
||||||
email_events_hint: 'Выберите события, для которых вы хотели бы получать уведомления:'
|
email_events_hint: 'Выберите события, для которых вы хотели бы получать уведомления:'
|
||||||
other_settings: Остальные настройки уведомлений
|
other_settings: Остальные настройки уведомлений
|
||||||
|
@ -1631,6 +1632,7 @@ ru:
|
||||||
over_total_limit: Вы превысили лимит на %{limit} запланированных постов
|
over_total_limit: Вы превысили лимит на %{limit} запланированных постов
|
||||||
too_soon: Запланированная дата должна быть в будущем
|
too_soon: Запланированная дата должна быть в будущем
|
||||||
self_destruct:
|
self_destruct:
|
||||||
|
lead_html: К сожалению, <strong>%{domain}</strong> закрывается навсегда. Если вас учётная запись находиться здесь вы не сможете продолжить использовать его, но вы можете запросить резервную копию ваших данных.
|
||||||
title: Этот сервер закрывается
|
title: Этот сервер закрывается
|
||||||
sessions:
|
sessions:
|
||||||
activity: Последняя активность
|
activity: Последняя активность
|
||||||
|
|
|
@ -1 +1,45 @@
|
||||||
|
---
|
||||||
lt:
|
lt:
|
||||||
|
simple_form:
|
||||||
|
hints:
|
||||||
|
account:
|
||||||
|
discoverable: Tavo vieši įrašai ir profilis gali būti rodomi arba rekomenduojami įvairiose Mastodon vietose, o profilis gali būti siūlomas kitiems naudotojams.
|
||||||
|
display_name: Tavo pilnas vardas arba smagus vardas.
|
||||||
|
fields: Tavo pagrindinis puslapis, įvardžiai, amžius, bet kas, ko tik nori.
|
||||||
|
indexable: Tavo vieši įrašai gali būti rodomi Mastodon paieškos rezultatuose. Žmonės, kurie bendravo su tavo įrašais, gali jų ieškoti nepriklausomai nuo to.
|
||||||
|
note: 'Gali @paminėti kitus žmones arba #saitažodžius.'
|
||||||
|
show_collections: Žmonės galės peržiūrėti tavo sekimus ir sekėjus. Žmonės, kuriuos seki, matys, kad juos seki, nepaisant to.
|
||||||
|
unlocked: Žmonės galės tave sekti nepaprašę patvirtinimo. Panaikink žymėjimą, jei nori peržiūrėti sekimo prašymus ir pasirinkti, ar priimti, ar atmesti naujus sekėjus.
|
||||||
|
account_warning_preset:
|
||||||
|
text: Gali naudoti įrašų sintaksę, pavyzdžiui, URL adresus, saitažodus ir paminėjimus
|
||||||
|
defaults:
|
||||||
|
header: PNG, GIF arba JPG. Ne daugiau kaip %{size}. Bus sumažintas iki %{dimensions}tšk.
|
||||||
|
inbox_url: Nukopijuok URL adresą iš pradinio puslapio perdavėjo, kurį nori naudoti
|
||||||
|
irreversible: Filtruoti įrašai išnyks negrįžtamai, net jei vėliau filtras bus pašalintas
|
||||||
|
locale: Naudotojo sąsajos kalba, el. laiškai ir stumiamieji pranešimai
|
||||||
|
password: Naudok bent 8 simbolius
|
||||||
|
phrase: Bus suderinta, neatsižvelgiant į teksto korpusą arba įrašo turinio įspėjimą
|
||||||
|
setting_display_media_hide_all: Visada slėpti žiniasklaidą
|
||||||
|
setting_display_media_show_all: Visada rodyti žiniasklaidą
|
||||||
|
setting_use_blurhash: Gradientai pagrįsti paslėptų vaizdų spalvomis, tačiau užgožia bet kokias detales
|
||||||
|
setting_use_pending_items: Slėpti laiko skalės naujienas po paspaudimo, vietoj automatinio kanalo slinkimo
|
||||||
|
featured_tag:
|
||||||
|
name: 'Štai keletas pastaruoju metu dažniausiai saitažodžių, kurių tu naudojai:'
|
||||||
|
form_admin_settings:
|
||||||
|
peers_api_enabled: Domenų pavadinimų sąrašas, su kuriais šis serveris susidūrė fediverse. Čia nėra duomenų apie tai, ar tu bendrauji su tam tikru serveriu, tik apie tai, kad tavo serveris apie jį žino. Tai naudojama tarnybose, kurios renka federacijos statistiką bendrąja prasme.
|
||||||
|
site_contact_email: Kaip žmonės gali su tavimi susisiekti teisiniais ar pagalbos užklausimais.
|
||||||
|
site_contact_username: Kaip žmonės gali tave pasiekti Mastodon.
|
||||||
|
site_extended_description: Bet kokia papildoma informacija, kuri gali būti naudinga lankytojams ir naudotojams. Gali būti struktūrizuota naudojant Markdown sintaksę.
|
||||||
|
trends: Trendai rodo, kurios įrašai, saitažodžiai ir naujienų istorijos tavo serveryje sulaukia didžiausio susidomėjimo.
|
||||||
|
sessions:
|
||||||
|
webauthn: Jei tai USB raktas, būtinai jį įkišk ir, jei reikia, paliesk.
|
||||||
|
settings:
|
||||||
|
indexable: Tavo profilio puslapis gali būti rodomas paieškos rezultatuose Google, Bing ir kituose.
|
||||||
|
labels:
|
||||||
|
featured_tag:
|
||||||
|
name: Saitažodis
|
||||||
|
tag:
|
||||||
|
listable: Leisti šį saitažodį rodyti paieškose ir pasiūlymuose
|
||||||
|
name: Saitažodis
|
||||||
|
trendable: Leisti šį saitažodį rodyti pagal trendus
|
||||||
|
usable: Leisti įrašams naudoti šį saitažodį
|
||||||
|
|
|
@ -98,7 +98,7 @@ sk:
|
||||||
disabled: Blokovaný
|
disabled: Blokovaný
|
||||||
pending: Čakajúci
|
pending: Čakajúci
|
||||||
silenced: Obmedzený
|
silenced: Obmedzený
|
||||||
suspended: Vylúčený/á
|
suspended: Pozastavený/á
|
||||||
title: Moderácia
|
title: Moderácia
|
||||||
moderation_notes: Moderátorské poznámky
|
moderation_notes: Moderátorské poznámky
|
||||||
most_recent_activity: Posledná aktivita
|
most_recent_activity: Posledná aktivita
|
||||||
|
@ -149,8 +149,8 @@ sk:
|
||||||
statuses: Príspevkov
|
statuses: Príspevkov
|
||||||
strikes: Predchádzajúce údery
|
strikes: Predchádzajúce údery
|
||||||
subscribe: Odoberaj
|
subscribe: Odoberaj
|
||||||
suspend: Vylúč
|
suspend: Pozastav
|
||||||
suspended: Vylúčený/á
|
suspended: Pozastavený/á
|
||||||
suspension_irreversible: Údaje tohto účtu boli nenávratne vymazané. Účet môžete zrušiť, aby sa dal používať, ale neobnovia sa žiadne údaje, ktoré predtým mal.
|
suspension_irreversible: Údaje tohto účtu boli nenávratne vymazané. Účet môžete zrušiť, aby sa dal používať, ale neobnovia sa žiadne údaje, ktoré predtým mal.
|
||||||
suspension_reversible_hint_html: Účet bol pozastavený a údaje budú úplne odstránené dňa %{date}. Dovtedy je možné účet obnoviť bez akýchkoľvek nepriaznivých účinkov. Ak chcete okamžite odstrániť všetky údaje účtu, môžete tak urobiť nižšie.
|
suspension_reversible_hint_html: Účet bol pozastavený a údaje budú úplne odstránené dňa %{date}. Dovtedy je možné účet obnoviť bez akýchkoľvek nepriaznivých účinkov. Ak chcete okamžite odstrániť všetky údaje účtu, môžete tak urobiť nižšie.
|
||||||
title: Účty
|
title: Účty
|
||||||
|
@ -162,6 +162,7 @@ sk:
|
||||||
undo_suspension: Zruš blokovanie
|
undo_suspension: Zruš blokovanie
|
||||||
unsilenced_msg: Úspešne zrušené obmedzenie účtu %{username}
|
unsilenced_msg: Úspešne zrušené obmedzenie účtu %{username}
|
||||||
unsubscribe: Prestaň odoberať
|
unsubscribe: Prestaň odoberať
|
||||||
|
unsuspended_msg: "%{username} ov/in účet úspešne spojazdnený"
|
||||||
username: Prezývka
|
username: Prezývka
|
||||||
view_domain: Ukáž súhrn pre doménu
|
view_domain: Ukáž súhrn pre doménu
|
||||||
warn: Varuj
|
warn: Varuj
|
||||||
|
@ -209,7 +210,7 @@ sk:
|
||||||
resolve_report: Vyrieš nahlásený problém
|
resolve_report: Vyrieš nahlásený problém
|
||||||
sensitive_account: Vynúť všetky médiá na účte ako chúlostivé
|
sensitive_account: Vynúť všetky médiá na účte ako chúlostivé
|
||||||
silence_account: Utíš účet
|
silence_account: Utíš účet
|
||||||
suspend_account: Vylúč účet
|
suspend_account: Pozastav účet
|
||||||
unassigned_report: Odober priradenie nahlásenia
|
unassigned_report: Odober priradenie nahlásenia
|
||||||
unblock_email_account: Odblokuj emailovú adresu
|
unblock_email_account: Odblokuj emailovú adresu
|
||||||
unsilence_account: Zvráť obmedzenie účtu
|
unsilence_account: Zvráť obmedzenie účtu
|
||||||
|
@ -255,6 +256,7 @@ sk:
|
||||||
silence_account_html: "%{name} obmedzil/a účet %{target}"
|
silence_account_html: "%{name} obmedzil/a účet %{target}"
|
||||||
suspend_account_html: "%{name} zablokoval/a účet používateľa %{target}"
|
suspend_account_html: "%{name} zablokoval/a účet používateľa %{target}"
|
||||||
unassigned_report_html: "%{name} odobral/a report od %{target}"
|
unassigned_report_html: "%{name} odobral/a report od %{target}"
|
||||||
|
unsuspend_account_html: "%{name} spojazdnil/a účet %{target}"
|
||||||
update_user_role_html: "%{name} zmenil/a rolu pre %{target}"
|
update_user_role_html: "%{name} zmenil/a rolu pre %{target}"
|
||||||
deleted_account: zmazaný účet
|
deleted_account: zmazaný účet
|
||||||
empty: Žiadne záznamy nenájdené.
|
empty: Žiadne záznamy nenájdené.
|
||||||
|
@ -341,6 +343,7 @@ sk:
|
||||||
confirm_suspension:
|
confirm_suspension:
|
||||||
cancel: Zruš
|
cancel: Zruš
|
||||||
confirm: Vylúč
|
confirm: Vylúč
|
||||||
|
preamble_html: Chystáš sa vylúčiť <strong>%{domain}</strong> a jej poddomény.
|
||||||
title: Potvrď blokovanie domény %{domain}
|
title: Potvrď blokovanie domény %{domain}
|
||||||
created_msg: Doména je v štádiu blokovania
|
created_msg: Doména je v štádiu blokovania
|
||||||
destroyed_msg: Blokovanie domény bolo zrušené
|
destroyed_msg: Blokovanie domény bolo zrušené
|
||||||
|
@ -355,7 +358,7 @@ sk:
|
||||||
severity:
|
severity:
|
||||||
noop: Nič
|
noop: Nič
|
||||||
silence: Obmedz
|
silence: Obmedz
|
||||||
suspend: Vylúč
|
suspend: Pozastav
|
||||||
title: Nové blokovanie domény
|
title: Nové blokovanie domény
|
||||||
not_permitted: Nemáš povolenie na vykonanie tohto kroku
|
not_permitted: Nemáš povolenie na vykonanie tohto kroku
|
||||||
obfuscate: Zatemniť názov domény
|
obfuscate: Zatemniť názov domény
|
||||||
|
@ -416,7 +419,7 @@ sk:
|
||||||
reject_media: Zamietni médiá
|
reject_media: Zamietni médiá
|
||||||
reject_reports: Zamietni hlásenia
|
reject_reports: Zamietni hlásenia
|
||||||
silence: Obmedzená
|
silence: Obmedzená
|
||||||
suspend: Vylúč
|
suspend: Pozastav
|
||||||
policy: Zásady
|
policy: Zásady
|
||||||
reason: Verejné odôvodnenie
|
reason: Verejné odôvodnenie
|
||||||
title: Zásady o obsahu
|
title: Zásady o obsahu
|
||||||
|
@ -537,7 +540,7 @@ sk:
|
||||||
statuses: Nahlásený obsah
|
statuses: Nahlásený obsah
|
||||||
summary:
|
summary:
|
||||||
action_preambles:
|
action_preambles:
|
||||||
suspend_html: 'Chystáš sa <strong>vylúčiť</strong> účet <strong>@%{acct}</strong>. To urobí:'
|
suspend_html: 'Chystáš sa <strong>pozastaviť</strong> účet <strong>@%{acct}</strong>. To urobí:'
|
||||||
actions:
|
actions:
|
||||||
delete_html: Vymaž pohoršujúce príspevky
|
delete_html: Vymaž pohoršujúce príspevky
|
||||||
mark_as_sensitive_html: Označ médiá pohoršujúcich príspevkov za chúlostivé
|
mark_as_sensitive_html: Označ médiá pohoršujúcich príspevkov za chúlostivé
|
||||||
|
|
|
@ -427,7 +427,11 @@ namespace :mastodon do
|
||||||
from: env['SMTP_FROM_ADDRESS'],
|
from: env['SMTP_FROM_ADDRESS'],
|
||||||
}
|
}
|
||||||
|
|
||||||
mail = ActionMailer::Base.new.mail to: send_to, subject: 'Test', body: 'Mastodon SMTP configuration works!'
|
mail = ActionMailer::Base.new.mail(
|
||||||
|
to: send_to,
|
||||||
|
subject: 'Test', # rubocop:disable Rails/I18nLocaleTexts
|
||||||
|
body: 'Mastodon SMTP configuration works!'
|
||||||
|
)
|
||||||
mail.deliver
|
mail.deliver
|
||||||
break
|
break
|
||||||
rescue => e
|
rescue => e
|
||||||
|
|
|
@ -211,7 +211,7 @@
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.5.0",
|
||||||
"jest-environment-jsdom": "^29.5.0",
|
"jest-environment-jsdom": "^29.5.0",
|
||||||
"lint-staged": "^13.2.2",
|
"lint-staged": "^15.0.0",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"react-test-renderer": "^18.2.0",
|
"react-test-renderer": "^18.2.0",
|
||||||
"stylelint": "^15.10.1",
|
"stylelint": "^15.10.1",
|
||||||
|
|
|
@ -26,7 +26,6 @@ describe Api::V1::StreamingController do
|
||||||
context 'with streaming api on different host' do
|
context 'with streaming api on different host' do
|
||||||
before do
|
before do
|
||||||
Rails.configuration.x.streaming_api_base_url = "wss://streaming-#{Rails.configuration.x.web_domain}"
|
Rails.configuration.x.streaming_api_base_url = "wss://streaming-#{Rails.configuration.x.web_domain}"
|
||||||
@streaming_host = URI.parse(Rails.configuration.x.streaming_api_base_url).host
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #index' do
|
describe 'GET #index' do
|
||||||
|
@ -38,7 +37,13 @@ describe Api::V1::StreamingController do
|
||||||
[:scheme, :path, :query, :fragment].each do |part|
|
[:scheme, :path, :query, :fragment].each do |part|
|
||||||
expect(redirect_to_uri.send(part)).to eq(request_uri.send(part)), "redirect target #{part}"
|
expect(redirect_to_uri.send(part)).to eq(request_uri.send(part)), "redirect target #{part}"
|
||||||
end
|
end
|
||||||
expect(redirect_to_uri.host).to eq(@streaming_host), 'redirect target host'
|
expect(redirect_to_uri.host).to eq(streaming_host), 'redirect target host'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def streaming_host
|
||||||
|
URI.parse(Rails.configuration.x.streaming_api_base_url).host
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,12 +18,14 @@ describe Auth::PasswordsController do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
request.env['devise.mapping'] = Devise.mappings[:user]
|
request.env['devise.mapping'] = Devise.mappings[:user]
|
||||||
@token = user.send_reset_password_instructions
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with valid reset_password_token' do
|
context 'with valid reset_password_token' do
|
||||||
it 'returns http success' do
|
it 'returns http success' do
|
||||||
get :edit, params: { reset_password_token: @token }
|
token = user.send_reset_password_instructions
|
||||||
|
|
||||||
|
get :edit, params: { reset_password_token: token }
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -38,9 +40,9 @@ describe Auth::PasswordsController do
|
||||||
|
|
||||||
describe 'POST #update' do
|
describe 'POST #update' do
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
|
let(:password) { 'reset0password' }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@password = 'reset0password'
|
|
||||||
request.env['devise.mapping'] = Devise.mappings[:user]
|
request.env['devise.mapping'] = Devise.mappings[:user]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -50,9 +52,9 @@ describe Auth::PasswordsController do
|
||||||
let!(:web_push_subscription) { Fabricate(:web_push_subscription, access_token: access_token) }
|
let!(:web_push_subscription) { Fabricate(:web_push_subscription, access_token: access_token) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@token = user.send_reset_password_instructions
|
token = user.send_reset_password_instructions
|
||||||
|
|
||||||
post :update, params: { user: { password: @password, password_confirmation: @password, reset_password_token: @token } }
|
post :update, params: { user: { password: password, password_confirmation: password, reset_password_token: token } }
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'redirect to sign in' do
|
it 'redirect to sign in' do
|
||||||
|
@ -63,7 +65,7 @@ describe Auth::PasswordsController do
|
||||||
this_user = User.find(user.id)
|
this_user = User.find(user.id)
|
||||||
|
|
||||||
expect(this_user).to_not be_nil
|
expect(this_user).to_not be_nil
|
||||||
expect(this_user.valid_password?(@password)).to be true
|
expect(this_user.valid_password?(password)).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'deactivates all sessions' do
|
it 'deactivates all sessions' do
|
||||||
|
@ -81,7 +83,7 @@ describe Auth::PasswordsController do
|
||||||
|
|
||||||
context 'with invalid reset_password_token' do
|
context 'with invalid reset_password_token' do
|
||||||
before do
|
before do
|
||||||
post :update, params: { user: { password: @password, password_confirmation: @password, reset_password_token: 'some_invalid_value' } }
|
post :update, params: { user: { password: password, password_confirmation: password, reset_password_token: 'some_invalid_value' } }
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders reset password' do
|
it 'renders reset password' do
|
||||||
|
|
|
@ -11,7 +11,7 @@ describe ExportControllerConcern do
|
||||||
end
|
end
|
||||||
|
|
||||||
def export_data
|
def export_data
|
||||||
@export.account.username
|
'body data value'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ describe ExportControllerConcern do
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
expect(response.media_type).to eq 'text/csv'
|
expect(response.media_type).to eq 'text/csv'
|
||||||
expect(response.headers['Content-Disposition']).to start_with 'attachment; filename="anonymous.csv"'
|
expect(response.headers['Content-Disposition']).to start_with 'attachment; filename="anonymous.csv"'
|
||||||
expect(response.body).to eq user.account.username
|
expect(response.body).to eq 'body data value'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns unauthorized when not signed in' do
|
it 'returns unauthorized when not signed in' do
|
||||||
|
|
|
@ -194,7 +194,7 @@ RSpec.describe Settings::ImportsController do
|
||||||
let!(:rows) do
|
let!(:rows) do
|
||||||
[
|
[
|
||||||
{ 'acct' => 'foo@bar' },
|
{ 'acct' => 'foo@bar' },
|
||||||
{ 'acct' => 'user@bar', 'show_reblogs' => false, 'notify' => true, 'languages' => ['fr', 'de'] },
|
{ 'acct' => 'user@bar', 'show_reblogs' => false, 'notify' => true, 'languages' => %w(fr de) },
|
||||||
].map { |data| Fabricate(:bulk_import_row, bulk_import: bulk_import, data: data) }
|
].map { |data| Fabricate(:bulk_import_row, bulk_import: bulk_import, data: data) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,10 @@ require 'rails_helper'
|
||||||
RSpec.describe StatusesCleanupController do
|
RSpec.describe StatusesCleanupController do
|
||||||
render_views
|
render_views
|
||||||
|
|
||||||
|
let!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@user = Fabricate(:user)
|
sign_in user, scope: :user
|
||||||
sign_in @user, scope: :user
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #show' do
|
describe 'GET #show' do
|
||||||
|
@ -30,9 +31,9 @@ RSpec.describe StatusesCleanupController do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'updates the account status cleanup policy' do
|
it 'updates the account status cleanup policy' do
|
||||||
expect(@user.account.statuses_cleanup_policy.enabled).to be true
|
expect(user.account.statuses_cleanup_policy.enabled).to be true
|
||||||
expect(@user.account.statuses_cleanup_policy.keep_direct).to be false
|
expect(user.account.statuses_cleanup_policy.keep_direct).to be false
|
||||||
expect(@user.account.statuses_cleanup_policy.keep_polls).to be true
|
expect(user.account.statuses_cleanup_policy.keep_polls).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'redirects' do
|
it 'redirects' do
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
|
|
||||||
Fabricator(:session_activation) do
|
Fabricator(:session_activation) do
|
||||||
user { Fabricate.build(:user) }
|
user { Fabricate.build(:user) }
|
||||||
session_id 'MyString'
|
session_id { sequence(:session_id) { |i| "session_id_#{i}" } }
|
||||||
end
|
end
|
||||||
|
|
|
@ -296,5 +296,51 @@ describe ApplicationHelper do
|
||||||
expect(helper.title).to eq 'site title'
|
expect(helper.title).to eq 'site title'
|
||||||
expect(Rails.env).to have_received(:production?)
|
expect(Rails.env).to have_received(:production?)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns site title with note on non-production environment' do
|
||||||
|
Setting.site_title = 'site title'
|
||||||
|
allow(Rails.env).to receive(:production?).and_return(false)
|
||||||
|
expect(helper.title).to eq 'site title (Dev)'
|
||||||
|
expect(Rails.env).to have_received(:production?)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'html_title' do
|
||||||
|
before do
|
||||||
|
allow(Rails.env).to receive(:production?).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
around do |example|
|
||||||
|
site_title = Setting.site_title
|
||||||
|
example.run
|
||||||
|
Setting.site_title = site_title
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a page_title content_for value' do
|
||||||
|
it 'uses the value in the html title' do
|
||||||
|
Setting.site_title = 'Site Title'
|
||||||
|
helper.content_for(:page_title, 'Test Value')
|
||||||
|
|
||||||
|
expect(helper.html_title).to eq 'Test Value - Site Title'
|
||||||
|
expect(helper.html_title).to be_html_safe
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'removes extra new lines' do
|
||||||
|
Setting.site_title = 'Site Title'
|
||||||
|
helper.content_for(:page_title, "Test Value\n")
|
||||||
|
|
||||||
|
expect(helper.html_title).to eq 'Test Value - Site Title'
|
||||||
|
expect(helper.html_title).to be_html_safe
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without any page_title content_for value' do
|
||||||
|
it 'returns the site title' do
|
||||||
|
Setting.site_title = 'Site Title'
|
||||||
|
|
||||||
|
expect(helper.html_title).to eq 'Site Title'
|
||||||
|
expect(helper.html_title).to be_html_safe
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,16 +4,23 @@ require 'rails_helper'
|
||||||
|
|
||||||
describe FlashesHelper do
|
describe FlashesHelper do
|
||||||
describe 'user_facing_flashes' do
|
describe 'user_facing_flashes' do
|
||||||
it 'returns user facing flashes' do
|
before do
|
||||||
|
# rubocop:disable Rails/I18nLocaleTexts
|
||||||
flash[:alert] = 'an alert'
|
flash[:alert] = 'an alert'
|
||||||
flash[:error] = 'an error'
|
flash[:error] = 'an error'
|
||||||
flash[:notice] = 'a notice'
|
flash[:notice] = 'a notice'
|
||||||
flash[:success] = 'a success'
|
flash[:success] = 'a success'
|
||||||
flash[:not_user_facing] = 'a not user facing flash'
|
flash[:not_user_facing] = 'a not user facing flash'
|
||||||
expect(helper.user_facing_flashes).to eq 'alert' => 'an alert',
|
# rubocop:enable Rails/I18nLocaleTexts
|
||||||
'error' => 'an error',
|
end
|
||||||
'notice' => 'a notice',
|
|
||||||
'success' => 'a success'
|
it 'returns user facing flashes' do
|
||||||
|
expect(helper.user_facing_flashes).to eq(
|
||||||
|
'alert' => 'an alert',
|
||||||
|
'error' => 'an error',
|
||||||
|
'notice' => 'a notice',
|
||||||
|
'success' => 'a success'
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,12 +8,14 @@ RSpec.describe TranslationService::DeepL do
|
||||||
let(:plan) { 'advanced' }
|
let(:plan) { 'advanced' }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://api.deepl.com/v2/languages?type=source').to_return(
|
%w(api-free.deepl.com api.deepl.com).each do |host|
|
||||||
body: '[{"language":"EN","name":"English"},{"language":"UK","name":"Ukrainian"}]'
|
stub_request(:get, "https://#{host}/v2/languages?type=source").to_return(
|
||||||
)
|
body: '[{"language":"EN","name":"English"},{"language":"UK","name":"Ukrainian"}]'
|
||||||
stub_request(:get, 'https://api.deepl.com/v2/languages?type=target').to_return(
|
)
|
||||||
body: '[{"language":"EN-GB","name":"English (British)"},{"language":"ZH","name":"Chinese"}]'
|
stub_request(:get, "https://#{host}/v2/languages?type=target").to_return(
|
||||||
)
|
body: '[{"language":"EN-GB","name":"English (British)"},{"language":"ZH","name":"Chinese"}]'
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#translate' do
|
describe '#translate' do
|
||||||
|
@ -73,28 +75,25 @@ RSpec.describe TranslationService::DeepL do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#request' do
|
describe 'the paid and free plan api hostnames' do
|
||||||
before do
|
before do
|
||||||
stub_request(:any, //)
|
service.languages
|
||||||
# rubocop:disable Lint/EmptyBlock
|
|
||||||
service.send(:request, :get, '/v2/languages') { |res| }
|
|
||||||
# rubocop:enable Lint/EmptyBlock
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'uses paid plan base URL' do
|
context 'without a plan set' do
|
||||||
expect(a_request(:get, 'https://api.deepl.com/v2/languages')).to have_been_made.once
|
it 'uses paid plan base URL and sends an API key' do
|
||||||
end
|
expect(a_request(:get, 'https://api.deepl.com/v2/languages?type=source').with(headers: { Authorization: 'DeepL-Auth-Key my-api-key' })).to have_been_made.once
|
||||||
|
expect(a_request(:get, 'https://api.deepl.com/v2/languages?type=target').with(headers: { Authorization: 'DeepL-Auth-Key my-api-key' })).to have_been_made.once
|
||||||
context 'with free plan' do
|
|
||||||
let(:plan) { 'free' }
|
|
||||||
|
|
||||||
it 'uses free plan base URL' do
|
|
||||||
expect(a_request(:get, 'https://api-free.deepl.com/v2/languages')).to have_been_made.once
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'sends API key' do
|
context 'with the free plan' do
|
||||||
expect(a_request(:get, 'https://api.deepl.com/v2/languages').with(headers: { Authorization: 'DeepL-Auth-Key my-api-key' })).to have_been_made.once
|
let(:plan) { 'free' }
|
||||||
|
|
||||||
|
it 'uses free plan base URL and sends an API key' do
|
||||||
|
expect(a_request(:get, 'https://api-free.deepl.com/v2/languages?type=source').with(headers: { Authorization: 'DeepL-Auth-Key my-api-key' })).to have_been_made.once
|
||||||
|
expect(a_request(:get, 'https://api-free.deepl.com/v2/languages?type=target').with(headers: { Authorization: 'DeepL-Auth-Key my-api-key' })).to have_been_made.once
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,17 +4,15 @@ require 'rails_helper'
|
||||||
|
|
||||||
describe AccountFinderConcern do
|
describe AccountFinderConcern do
|
||||||
describe 'local finders' do
|
describe 'local finders' do
|
||||||
before do
|
let!(:account) { Fabricate(:account, username: 'Alice') }
|
||||||
@account = Fabricate(:account, username: 'Alice')
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '.find_local' do
|
describe '.find_local' do
|
||||||
it 'returns case-insensitive result' do
|
it 'returns case-insensitive result' do
|
||||||
expect(Account.find_local('alice')).to eq(@account)
|
expect(Account.find_local('alice')).to eq(account)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns correctly cased result' do
|
it 'returns correctly cased result' do
|
||||||
expect(Account.find_local('Alice')).to eq(@account)
|
expect(Account.find_local('Alice')).to eq(account)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns nil without a match' do
|
it 'returns nil without a match' do
|
||||||
|
@ -36,7 +34,7 @@ describe AccountFinderConcern do
|
||||||
|
|
||||||
describe '.find_local!' do
|
describe '.find_local!' do
|
||||||
it 'returns matching result' do
|
it 'returns matching result' do
|
||||||
expect(Account.find_local!('alice')).to eq(@account)
|
expect(Account.find_local!('alice')).to eq(account)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises on non-matching result' do
|
it 'raises on non-matching result' do
|
||||||
|
@ -54,17 +52,15 @@ describe AccountFinderConcern do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'remote finders' do
|
describe 'remote finders' do
|
||||||
before do
|
let!(:account) { Fabricate(:account, username: 'Alice', domain: 'mastodon.social') }
|
||||||
@account = Fabricate(:account, username: 'Alice', domain: 'mastodon.social')
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '.find_remote' do
|
describe '.find_remote' do
|
||||||
it 'returns exact match result' do
|
it 'returns exact match result' do
|
||||||
expect(Account.find_remote('alice', 'mastodon.social')).to eq(@account)
|
expect(Account.find_remote('alice', 'mastodon.social')).to eq(account)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns case-insensitive result' do
|
it 'returns case-insensitive result' do
|
||||||
expect(Account.find_remote('ALICE', 'MASTODON.SOCIAL')).to eq(@account)
|
expect(Account.find_remote('ALICE', 'MASTODON.SOCIAL')).to eq(account)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns nil when username does not match' do
|
it 'returns nil when username does not match' do
|
||||||
|
@ -90,7 +86,7 @@ describe AccountFinderConcern do
|
||||||
|
|
||||||
describe '.find_remote!' do
|
describe '.find_remote!' do
|
||||||
it 'returns matching result' do
|
it 'returns matching result' do
|
||||||
expect(Account.find_remote!('alice', 'mastodon.social')).to eq(@account)
|
expect(Account.find_remote!('alice', 'mastodon.social')).to eq(account)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises on non-matching result' do
|
it 'raises on non-matching result' do
|
||||||
|
|
|
@ -655,38 +655,36 @@ describe AccountInteractions do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'ignoring reblogs from an account' do
|
describe 'ignoring reblogs from an account' do
|
||||||
before do
|
let!(:me) { Fabricate(:account, username: 'Me') }
|
||||||
@me = Fabricate(:account, username: 'Me')
|
let!(:you) { Fabricate(:account, username: 'You') }
|
||||||
@you = Fabricate(:account, username: 'You')
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with the reblogs option unspecified' do
|
context 'with the reblogs option unspecified' do
|
||||||
before do
|
before do
|
||||||
@me.follow!(@you)
|
me.follow!(you)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'defaults to showing reblogs' do
|
it 'defaults to showing reblogs' do
|
||||||
expect(@me.muting_reblogs?(@you)).to be(false)
|
expect(me.muting_reblogs?(you)).to be(false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with the reblogs option set to false' do
|
context 'with the reblogs option set to false' do
|
||||||
before do
|
before do
|
||||||
@me.follow!(@you, reblogs: false)
|
me.follow!(you, reblogs: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does mute reblogs' do
|
it 'does mute reblogs' do
|
||||||
expect(@me.muting_reblogs?(@you)).to be(true)
|
expect(me.muting_reblogs?(you)).to be(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with the reblogs option set to true' do
|
context 'with the reblogs option set to true' do
|
||||||
before do
|
before do
|
||||||
@me.follow!(@you, reblogs: true)
|
me.follow!(you, reblogs: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not mute reblogs' do
|
it 'does not mute reblogs' do
|
||||||
expect(@me.muting_reblogs?(@you)).to be(false)
|
expect(me.muting_reblogs?(you)).to be(false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -69,7 +69,9 @@ RSpec.describe Remotable do
|
||||||
|
|
||||||
context 'with an invalid URL' do
|
context 'with an invalid URL' do
|
||||||
before do
|
before do
|
||||||
allow(Addressable::URI).to receive_message_chain(:parse, :normalize).with(url).with(no_args).and_raise(Addressable::URI::InvalidURIError)
|
parsed = instance_double(Addressable::URI)
|
||||||
|
allow(parsed).to receive(:normalize).with(no_args).and_raise(Addressable::URI::InvalidURIError)
|
||||||
|
allow(Addressable::URI).to receive(:parse).with(url).and_return(parsed)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'makes no request' do
|
it 'makes no request' do
|
||||||
|
|
|
@ -296,7 +296,7 @@ RSpec.describe Form::Import do
|
||||||
|
|
||||||
it_behaves_like 'on successful import', 'following', 'merge', 'following_accounts.csv', [
|
it_behaves_like 'on successful import', 'following', 'merge', 'following_accounts.csv', [
|
||||||
{ 'acct' => 'user@example.com', 'show_reblogs' => true, 'notify' => false, 'languages' => nil },
|
{ 'acct' => 'user@example.com', 'show_reblogs' => true, 'notify' => false, 'languages' => nil },
|
||||||
{ 'acct' => 'user@test.com', 'show_reblogs' => true, 'notify' => true, 'languages' => ['en', 'fr'] },
|
{ 'acct' => 'user@test.com', 'show_reblogs' => true, 'notify' => true, 'languages' => %w(en fr) },
|
||||||
]
|
]
|
||||||
|
|
||||||
it_behaves_like 'on successful import', 'muting', 'merge', 'muted_accounts.csv', [
|
it_behaves_like 'on successful import', 'muting', 'merge', 'muted_accounts.csv', [
|
||||||
|
|
|
@ -199,15 +199,13 @@ RSpec.describe PublicFeed do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with an account passed in' do
|
describe 'with an account passed in' do
|
||||||
subject { described_class.new(@account).get(20).map(&:id) }
|
subject { described_class.new(account).get(20).map(&:id) }
|
||||||
|
|
||||||
before do
|
let!(:account) { Fabricate(:account) }
|
||||||
@account = Fabricate(:account)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'excludes statuses from accounts blocked by the account' do
|
it 'excludes statuses from accounts blocked by the account' do
|
||||||
blocked = Fabricate(:account)
|
blocked = Fabricate(:account)
|
||||||
@account.block!(blocked)
|
account.block!(blocked)
|
||||||
blocked_status = Fabricate(:status, account: blocked)
|
blocked_status = Fabricate(:status, account: blocked)
|
||||||
|
|
||||||
expect(subject).to_not include(blocked_status.id)
|
expect(subject).to_not include(blocked_status.id)
|
||||||
|
@ -215,7 +213,7 @@ RSpec.describe PublicFeed do
|
||||||
|
|
||||||
it 'excludes statuses from accounts who have blocked the account' do
|
it 'excludes statuses from accounts who have blocked the account' do
|
||||||
blocker = Fabricate(:account)
|
blocker = Fabricate(:account)
|
||||||
blocker.block!(@account)
|
blocker.block!(account)
|
||||||
blocked_status = Fabricate(:status, account: blocker)
|
blocked_status = Fabricate(:status, account: blocker)
|
||||||
|
|
||||||
expect(subject).to_not include(blocked_status.id)
|
expect(subject).to_not include(blocked_status.id)
|
||||||
|
@ -223,7 +221,7 @@ RSpec.describe PublicFeed do
|
||||||
|
|
||||||
it 'excludes statuses from accounts muted by the account' do
|
it 'excludes statuses from accounts muted by the account' do
|
||||||
muted = Fabricate(:account)
|
muted = Fabricate(:account)
|
||||||
@account.mute!(muted)
|
account.mute!(muted)
|
||||||
muted_status = Fabricate(:status, account: muted)
|
muted_status = Fabricate(:status, account: muted)
|
||||||
|
|
||||||
expect(subject).to_not include(muted_status.id)
|
expect(subject).to_not include(muted_status.id)
|
||||||
|
@ -231,7 +229,7 @@ RSpec.describe PublicFeed do
|
||||||
|
|
||||||
it 'excludes statuses from accounts from personally blocked domains' do
|
it 'excludes statuses from accounts from personally blocked domains' do
|
||||||
blocked = Fabricate(:account, domain: 'example.com')
|
blocked = Fabricate(:account, domain: 'example.com')
|
||||||
@account.block_domain!(blocked.domain)
|
account.block_domain!(blocked.domain)
|
||||||
blocked_status = Fabricate(:status, account: blocked)
|
blocked_status = Fabricate(:status, account: blocked)
|
||||||
|
|
||||||
expect(subject).to_not include(blocked_status.id)
|
expect(subject).to_not include(blocked_status.id)
|
||||||
|
@ -239,7 +237,7 @@ RSpec.describe PublicFeed do
|
||||||
|
|
||||||
context 'with language preferences' do
|
context 'with language preferences' do
|
||||||
it 'excludes statuses in languages not allowed by the account user' do
|
it 'excludes statuses in languages not allowed by the account user' do
|
||||||
@account.user.update(chosen_languages: [:en, :es])
|
account.user.update(chosen_languages: [:en, :es])
|
||||||
en_status = Fabricate(:status, language: 'en')
|
en_status = Fabricate(:status, language: 'en')
|
||||||
es_status = Fabricate(:status, language: 'es')
|
es_status = Fabricate(:status, language: 'es')
|
||||||
fr_status = Fabricate(:status, language: 'fr')
|
fr_status = Fabricate(:status, language: 'fr')
|
||||||
|
@ -250,7 +248,7 @@ RSpec.describe PublicFeed do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'includes all languages when user does not have a setting' do
|
it 'includes all languages when user does not have a setting' do
|
||||||
@account.user.update(chosen_languages: nil)
|
account.user.update(chosen_languages: nil)
|
||||||
|
|
||||||
en_status = Fabricate(:status, language: 'en')
|
en_status = Fabricate(:status, language: 'en')
|
||||||
es_status = Fabricate(:status, language: 'es')
|
es_status = Fabricate(:status, language: 'es')
|
||||||
|
@ -260,7 +258,7 @@ RSpec.describe PublicFeed do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'includes all languages when account does not have a user' do
|
it 'includes all languages when account does not have a user' do
|
||||||
@account.update(user: nil)
|
account.update(user: nil)
|
||||||
|
|
||||||
en_status = Fabricate(:status, language: 'en')
|
en_status = Fabricate(:status, language: 'en')
|
||||||
es_status = Fabricate(:status, language: 'es')
|
es_status = Fabricate(:status, language: 'es')
|
||||||
|
|
|
@ -98,34 +98,44 @@ RSpec.describe SessionActivation do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when id exists' do
|
context 'when id exists' do
|
||||||
let(:id) { '1' }
|
let!(:session_activation) { Fabricate(:session_activation) }
|
||||||
|
|
||||||
it 'calls where.destroy_all' do
|
it 'destroys the record' do
|
||||||
expect(described_class).to receive_message_chain(:where, :destroy_all)
|
described_class.deactivate(session_activation.session_id)
|
||||||
.with(session_id: id).with(no_args)
|
|
||||||
|
|
||||||
described_class.deactivate(id)
|
expect { session_activation.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.purge_old' do
|
describe '.purge_old' do
|
||||||
it 'calls order.offset.destroy_all' do
|
around do |example|
|
||||||
expect(described_class).to receive_message_chain(:order, :offset, :destroy_all)
|
before = Rails.configuration.x.max_session_activations
|
||||||
.with('created_at desc').with(Rails.configuration.x.max_session_activations).with(no_args)
|
Rails.configuration.x.max_session_activations = 1
|
||||||
|
example.run
|
||||||
|
Rails.configuration.x.max_session_activations = before
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:oldest_session_activation) { Fabricate(:session_activation, created_at: 10.days.ago) }
|
||||||
|
let!(:newest_session_activation) { Fabricate(:session_activation, created_at: 5.days.ago) }
|
||||||
|
|
||||||
|
it 'preserves the newest X records based on config' do
|
||||||
described_class.purge_old
|
described_class.purge_old
|
||||||
|
|
||||||
|
expect { oldest_session_activation.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
expect { newest_session_activation.reload }.to_not raise_error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.exclusive' do
|
describe '.exclusive' do
|
||||||
let(:id) { '1' }
|
let!(:unwanted_session_activation) { Fabricate(:session_activation) }
|
||||||
|
let!(:wanted_session_activation) { Fabricate(:session_activation) }
|
||||||
|
|
||||||
it 'calls where.destroy_all' do
|
it 'preserves supplied record and destroys all others' do
|
||||||
expect(described_class).to receive_message_chain(:where, :not, :destroy_all)
|
described_class.exclusive(wanted_session_activation.session_id)
|
||||||
.with(session_id: id).with(no_args)
|
|
||||||
|
|
||||||
described_class.exclusive(id)
|
expect { unwanted_session_activation.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
expect { wanted_session_activation.reload }.to_not raise_error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -77,10 +77,13 @@ RSpec.describe Setting do
|
||||||
let(:default_value) { { default_value: 'default_value' } }
|
let(:default_value) { { default_value: 'default_value' } }
|
||||||
|
|
||||||
it 'calls default_value.with_indifferent_access.merge!' do
|
it 'calls default_value.with_indifferent_access.merge!' do
|
||||||
expect(default_value).to receive_message_chain(:with_indifferent_access, :merge!)
|
indifferent_hash = instance_double(Hash, merge!: nil)
|
||||||
.with(db_val.value)
|
allow(default_value).to receive(:with_indifferent_access).and_return(indifferent_hash)
|
||||||
|
|
||||||
described_class[key]
|
described_class[key]
|
||||||
|
|
||||||
|
expect(default_value).to have_received(:with_indifferent_access)
|
||||||
|
expect(indifferent_hash).to have_received(:merge!).with(db_val.value)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,6 @@ if RUN_SYSTEM_SPECS
|
||||||
ENV['STREAMING_API_BASE_URL'] = "http://localhost:#{STREAMING_PORT}"
|
ENV['STREAMING_API_BASE_URL'] = "http://localhost:#{STREAMING_PORT}"
|
||||||
end
|
end
|
||||||
|
|
||||||
if RUN_SEARCH_SPECS
|
|
||||||
# Include any configuration or setups specific to search tests here
|
|
||||||
end
|
|
||||||
|
|
||||||
require File.expand_path('../config/environment', __dir__)
|
require File.expand_path('../config/environment', __dir__)
|
||||||
|
|
||||||
abort('The Rails environment is running in production mode!') if Rails.env.production?
|
abort('The Rails environment is running in production mode!') if Rails.env.production?
|
||||||
|
@ -35,8 +31,6 @@ Sidekiq.logger = nil
|
||||||
|
|
||||||
# System tests config
|
# System tests config
|
||||||
DatabaseCleaner.strategy = [:deletion]
|
DatabaseCleaner.strategy = [:deletion]
|
||||||
streaming_server_manager = StreamingServerManager.new
|
|
||||||
search_data_manager = SearchDataManager.new
|
|
||||||
|
|
||||||
Devise::Test::ControllerHelpers.module_eval do
|
Devise::Test::ControllerHelpers.module_eval do
|
||||||
alias_method :original_sign_in, :sign_in
|
alias_method :original_sign_in, :sign_in
|
||||||
|
@ -100,26 +94,7 @@ RSpec.configure do |config|
|
||||||
Capybara.current_driver = :rack_test
|
Capybara.current_driver = :rack_test
|
||||||
end
|
end
|
||||||
|
|
||||||
config.before :suite do
|
|
||||||
if RUN_SYSTEM_SPECS
|
|
||||||
Webpacker.compile
|
|
||||||
streaming_server_manager.start(port: STREAMING_PORT)
|
|
||||||
end
|
|
||||||
|
|
||||||
if RUN_SEARCH_SPECS
|
|
||||||
Chewy.strategy(:urgent)
|
|
||||||
search_data_manager.prepare_test_data
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
config.after :suite do
|
|
||||||
streaming_server_manager.stop
|
|
||||||
|
|
||||||
search_data_manager.cleanup_test_data if RUN_SEARCH_SPECS
|
|
||||||
end
|
|
||||||
|
|
||||||
config.around :each, type: :system do |example|
|
config.around :each, type: :system do |example|
|
||||||
# driven_by :selenium, using: :chrome, screen_size: [1600, 1200]
|
|
||||||
driven_by :selenium, using: :headless_chrome, screen_size: [1600, 1200]
|
driven_by :selenium, using: :headless_chrome, screen_size: [1600, 1200]
|
||||||
|
|
||||||
# The streaming server needs access to the database
|
# The streaming server needs access to the database
|
||||||
|
@ -136,12 +111,6 @@ RSpec.configure do |config|
|
||||||
self.use_transactional_tests = true
|
self.use_transactional_tests = true
|
||||||
end
|
end
|
||||||
|
|
||||||
config.around :each, type: :search do |example|
|
|
||||||
search_data_manager.populate_indexes
|
|
||||||
example.run
|
|
||||||
search_data_manager.remove_indexes
|
|
||||||
end
|
|
||||||
|
|
||||||
config.before do |example|
|
config.before do |example|
|
||||||
unless example.metadata[:paperclip_processing]
|
unless example.metadata[:paperclip_processing]
|
||||||
allow_any_instance_of(Paperclip::Attachment).to receive(:post_process).and_return(true) # rubocop:disable RSpec/AnyInstance
|
allow_any_instance_of(Paperclip::Attachment).to receive(:post_process).and_return(true) # rubocop:disable RSpec/AnyInstance
|
||||||
|
|
|
@ -119,24 +119,26 @@ module TestEndpoints
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'Caching behavior' do
|
describe 'Caching behavior' do
|
||||||
shared_examples 'cachable response' do
|
shared_examples 'cachable response' do |http_success: false|
|
||||||
it 'does not set cookies' do
|
it 'does not set cookies or set public cache control', :aggregate_failures do
|
||||||
expect(response.cookies).to be_empty
|
expect(response.cookies).to be_empty
|
||||||
end
|
|
||||||
|
|
||||||
it 'sets public cache control', :aggregate_failures do
|
|
||||||
# expect(response.cache_control[:max_age]&.to_i).to be_positive
|
# expect(response.cache_control[:max_age]&.to_i).to be_positive
|
||||||
expect(response.cache_control[:public]).to be_truthy
|
expect(response.cache_control[:public]).to be_truthy
|
||||||
expect(response.cache_control[:private]).to be_falsy
|
expect(response.cache_control[:private]).to be_falsy
|
||||||
expect(response.cache_control[:no_store]).to be_falsy
|
expect(response.cache_control[:no_store]).to be_falsy
|
||||||
expect(response.cache_control[:no_cache]).to be_falsy
|
expect(response.cache_control[:no_cache]).to be_falsy
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200) if http_success
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
shared_examples 'non-cacheable response' do
|
shared_examples 'non-cacheable response' do |http_success: false|
|
||||||
it 'sets private cache control' do
|
it 'sets private cache control' do
|
||||||
expect(response.cache_control[:private]).to be_truthy
|
expect(response.cache_control[:private]).to be_truthy
|
||||||
expect(response.cache_control[:no_store]).to be_truthy
|
expect(response.cache_control[:no_store]).to be_truthy
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200) if http_success
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -149,7 +151,7 @@ describe 'Caching behavior' do
|
||||||
|
|
||||||
shared_examples 'language-dependent' do
|
shared_examples 'language-dependent' do
|
||||||
it 'has a Vary on Accept-Language' do
|
it 'has a Vary on Accept-Language' do
|
||||||
expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('accept-language')
|
expect(response_vary_headers).to include('accept-language')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -202,7 +204,7 @@ describe 'Caching behavior' do
|
||||||
it_behaves_like 'cachable response'
|
it_behaves_like 'cachable response'
|
||||||
|
|
||||||
it 'has a Vary on Cookie' do
|
it 'has a Vary on Cookie' do
|
||||||
expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('cookie')
|
expect(response_vary_headers).to include('cookie')
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'language-dependent' if TestEndpoints::LANGUAGE_DEPENDENT.include?(endpoint)
|
it_behaves_like 'language-dependent' if TestEndpoints::LANGUAGE_DEPENDENT.include?(endpoint)
|
||||||
|
@ -216,7 +218,7 @@ describe 'Caching behavior' do
|
||||||
it_behaves_like 'cachable response'
|
it_behaves_like 'cachable response'
|
||||||
|
|
||||||
it 'has a Vary on Authorization' do
|
it 'has a Vary on Authorization' do
|
||||||
expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('authorization')
|
expect(response_vary_headers).to include('authorization')
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'language-dependent' if TestEndpoints::LANGUAGE_DEPENDENT.include?(endpoint)
|
it_behaves_like 'language-dependent' if TestEndpoints::LANGUAGE_DEPENDENT.include?(endpoint)
|
||||||
|
@ -302,7 +304,7 @@ describe 'Caching behavior' do
|
||||||
it_behaves_like 'non-cacheable response'
|
it_behaves_like 'non-cacheable response'
|
||||||
|
|
||||||
it 'has a Vary on Cookie' do
|
it 'has a Vary on Cookie' do
|
||||||
expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('cookie')
|
expect(response_vary_headers).to include('cookie')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -311,11 +313,7 @@ describe 'Caching behavior' do
|
||||||
describe endpoint do
|
describe endpoint do
|
||||||
before { get endpoint }
|
before { get endpoint }
|
||||||
|
|
||||||
it_behaves_like 'non-cacheable response'
|
it_behaves_like 'non-cacheable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -351,7 +349,7 @@ describe 'Caching behavior' do
|
||||||
it_behaves_like 'non-cacheable response'
|
it_behaves_like 'non-cacheable response'
|
||||||
|
|
||||||
it 'has a Vary on Authorization' do
|
it 'has a Vary on Authorization' do
|
||||||
expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('authorization')
|
expect(response_vary_headers).to include('authorization')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -362,11 +360,7 @@ describe 'Caching behavior' do
|
||||||
get endpoint, headers: { 'Authorization' => "Bearer #{token.token}" }
|
get endpoint, headers: { 'Authorization' => "Bearer #{token.token}" }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'non-cacheable response'
|
it_behaves_like 'non-cacheable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -393,11 +387,7 @@ describe 'Caching behavior' do
|
||||||
context 'when allowed for local users only' do
|
context 'when allowed for local users only' do
|
||||||
let(:show_domain_blocks) { 'users' }
|
let(:show_domain_blocks) { 'users' }
|
||||||
|
|
||||||
it_behaves_like 'non-cacheable response'
|
it_behaves_like 'non-cacheable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when disabled' do
|
context 'when disabled' do
|
||||||
|
@ -421,11 +411,7 @@ describe 'Caching behavior' do
|
||||||
get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'cachable response'
|
it_behaves_like 'cachable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
TestEndpoints::REQUIRE_SIGNATURE.each do |endpoint|
|
TestEndpoints::REQUIRE_SIGNATURE.each do |endpoint|
|
||||||
|
@ -434,11 +420,7 @@ describe 'Caching behavior' do
|
||||||
get endpoint, sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
get endpoint, sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'non-cacheable response'
|
it_behaves_like 'non-cacheable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -456,11 +438,7 @@ describe 'Caching behavior' do
|
||||||
get '/actor', headers: { 'Accept' => 'application/activity+json' }
|
get '/actor', headers: { 'Accept' => 'application/activity+json' }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'cachable response'
|
it_behaves_like 'cachable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
(TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint|
|
(TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint|
|
||||||
|
@ -487,11 +465,7 @@ describe 'Caching behavior' do
|
||||||
get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'cachable response'
|
it_behaves_like 'cachable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
(TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint|
|
(TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint|
|
||||||
|
@ -500,11 +474,7 @@ describe 'Caching behavior' do
|
||||||
get endpoint, sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
get endpoint, sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'non-cacheable response'
|
it_behaves_like 'non-cacheable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -528,11 +498,7 @@ describe 'Caching behavior' do
|
||||||
get '/actor', headers: { 'Accept' => 'application/activity+json' }
|
get '/actor', headers: { 'Accept' => 'application/activity+json' }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'cachable response'
|
it_behaves_like 'cachable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
(TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint|
|
(TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint|
|
||||||
|
@ -560,11 +526,7 @@ describe 'Caching behavior' do
|
||||||
get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'cachable response'
|
it_behaves_like 'cachable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
(TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint|
|
(TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint|
|
||||||
|
@ -573,11 +535,7 @@ describe 'Caching behavior' do
|
||||||
get endpoint, sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
get endpoint, sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'non-cacheable response'
|
it_behaves_like 'non-cacheable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -591,11 +549,7 @@ describe 'Caching behavior' do
|
||||||
get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'cachable response'
|
it_behaves_like 'cachable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
(TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint|
|
(TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint|
|
||||||
|
@ -667,7 +621,7 @@ describe 'Caching behavior' do
|
||||||
it_behaves_like 'non-cacheable response'
|
it_behaves_like 'non-cacheable response'
|
||||||
|
|
||||||
it 'has a Vary on Authorization' do
|
it 'has a Vary on Authorization' do
|
||||||
expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('authorization')
|
expect(response_vary_headers).to include('authorization')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -678,13 +632,15 @@ describe 'Caching behavior' do
|
||||||
get endpoint, headers: { 'Authorization' => "Bearer #{token.token}" }
|
get endpoint, headers: { 'Authorization' => "Bearer #{token.token}" }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'non-cacheable response'
|
it_behaves_like 'non-cacheable response', http_success: true
|
||||||
|
|
||||||
it 'returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def response_vary_headers
|
||||||
|
response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,71 +20,70 @@ RSpec.describe RemoveStatusService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when removed status is not a reblog' do
|
context 'when removed status is not a reblog' do
|
||||||
|
let!(:status) { PostStatusService.new.call(alice, text: 'Hello @bob@example.com ThisIsASecret') }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@status = PostStatusService.new.call(alice, text: 'Hello @bob@example.com ThisIsASecret')
|
FavouriteService.new.call(jeff, status)
|
||||||
FavouriteService.new.call(jeff, @status)
|
Fabricate(:status, account: bill, reblog: status, uri: 'hoge')
|
||||||
Fabricate(:status, account: bill, reblog: @status, uri: 'hoge')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'removes status from author\'s home feed' do
|
it 'removes status from author\'s home feed' do
|
||||||
subject.call(@status)
|
subject.call(status)
|
||||||
expect(HomeFeed.new(alice).get(10).pluck(:id)).to_not include(@status.id)
|
expect(HomeFeed.new(alice).get(10).pluck(:id)).to_not include(status.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'removes status from local follower\'s home feed' do
|
it 'removes status from local follower\'s home feed' do
|
||||||
subject.call(@status)
|
subject.call(status)
|
||||||
expect(HomeFeed.new(jeff).get(10).pluck(:id)).to_not include(@status.id)
|
expect(HomeFeed.new(jeff).get(10).pluck(:id)).to_not include(status.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'sends Delete activity to followers' do
|
it 'sends Delete activity to followers' do
|
||||||
subject.call(@status)
|
subject.call(status)
|
||||||
expect(a_request(:post, 'http://example.com/inbox').with(
|
expect(a_request(:post, 'http://example.com/inbox').with(
|
||||||
body: hash_including({
|
body: hash_including({
|
||||||
'type' => 'Delete',
|
'type' => 'Delete',
|
||||||
'object' => {
|
'object' => {
|
||||||
'type' => 'Tombstone',
|
'type' => 'Tombstone',
|
||||||
'id' => ActivityPub::TagManager.instance.uri_for(@status),
|
'id' => ActivityPub::TagManager.instance.uri_for(status),
|
||||||
'atomUri' => OStatus::TagManager.instance.uri_for(@status),
|
'atomUri' => OStatus::TagManager.instance.uri_for(status),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)).to have_been_made.once
|
)).to have_been_made.once
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'sends Delete activity to rebloggers' do
|
it 'sends Delete activity to rebloggers' do
|
||||||
subject.call(@status)
|
subject.call(status)
|
||||||
expect(a_request(:post, 'http://example2.com/inbox').with(
|
expect(a_request(:post, 'http://example2.com/inbox').with(
|
||||||
body: hash_including({
|
body: hash_including({
|
||||||
'type' => 'Delete',
|
'type' => 'Delete',
|
||||||
'object' => {
|
'object' => {
|
||||||
'type' => 'Tombstone',
|
'type' => 'Tombstone',
|
||||||
'id' => ActivityPub::TagManager.instance.uri_for(@status),
|
'id' => ActivityPub::TagManager.instance.uri_for(status),
|
||||||
'atomUri' => OStatus::TagManager.instance.uri_for(@status),
|
'atomUri' => OStatus::TagManager.instance.uri_for(status),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)).to have_been_made.once
|
)).to have_been_made.once
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'remove status from notifications' do
|
it 'remove status from notifications' do
|
||||||
expect { subject.call(@status) }.to change {
|
expect { subject.call(status) }.to change {
|
||||||
Notification.where(activity_type: 'Favourite', from_account: jeff, account: alice).count
|
Notification.where(activity_type: 'Favourite', from_account: jeff, account: alice).count
|
||||||
}.from(1).to(0)
|
}.from(1).to(0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when removed status is a private self-reblog' do
|
context 'when removed status is a private self-reblog' do
|
||||||
before do
|
let!(:original_status) { Fabricate(:status, account: alice, text: 'Hello ThisIsASecret', visibility: :private) }
|
||||||
@original_status = Fabricate(:status, account: alice, text: 'Hello ThisIsASecret', visibility: :private)
|
let!(:status) { ReblogService.new.call(alice, original_status) }
|
||||||
@status = ReblogService.new.call(alice, @original_status)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'sends Undo activity to followers' do
|
it 'sends Undo activity to followers' do
|
||||||
subject.call(@status)
|
subject.call(status)
|
||||||
expect(a_request(:post, 'http://example.com/inbox').with(
|
expect(a_request(:post, 'http://example.com/inbox').with(
|
||||||
body: hash_including({
|
body: hash_including({
|
||||||
'type' => 'Undo',
|
'type' => 'Undo',
|
||||||
'object' => hash_including({
|
'object' => hash_including({
|
||||||
'type' => 'Announce',
|
'type' => 'Announce',
|
||||||
'object' => ActivityPub::TagManager.instance.uri_for(@original_status),
|
'object' => ActivityPub::TagManager.instance.uri_for(original_status),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
)).to have_been_made.once
|
)).to have_been_made.once
|
||||||
|
@ -92,19 +91,17 @@ RSpec.describe RemoveStatusService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when removed status is public self-reblog' do
|
context 'when removed status is public self-reblog' do
|
||||||
before do
|
let!(:original_status) { Fabricate(:status, account: alice, text: 'Hello ThisIsASecret', visibility: :public) }
|
||||||
@original_status = Fabricate(:status, account: alice, text: 'Hello ThisIsASecret', visibility: :public)
|
let!(:status) { ReblogService.new.call(alice, original_status) }
|
||||||
@status = ReblogService.new.call(alice, @original_status)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'sends Undo activity to followers' do
|
it 'sends Undo activity to followers' do
|
||||||
subject.call(@status)
|
subject.call(status)
|
||||||
expect(a_request(:post, 'http://example.com/inbox').with(
|
expect(a_request(:post, 'http://example.com/inbox').with(
|
||||||
body: hash_including({
|
body: hash_including({
|
||||||
'type' => 'Undo',
|
'type' => 'Undo',
|
||||||
'object' => hash_including({
|
'object' => hash_including({
|
||||||
'type' => 'Announce',
|
'type' => 'Announce',
|
||||||
'object' => ActivityPub::TagManager.instance.uri_for(@original_status),
|
'object' => ActivityPub::TagManager.instance.uri_for(original_status),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
)).to have_been_made.once
|
)).to have_been_made.once
|
||||||
|
|
|
@ -19,17 +19,15 @@ describe SearchService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with an url query' do
|
describe 'with an url query' do
|
||||||
before do
|
let(:query) { 'http://test.host/query' }
|
||||||
@query = 'http://test.host/query'
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when it does not find anything' do
|
context 'when it does not find anything' do
|
||||||
it 'returns the empty results' do
|
it 'returns the empty results' do
|
||||||
service = instance_double(ResolveURLService, call: nil)
|
service = instance_double(ResolveURLService, call: nil)
|
||||||
allow(ResolveURLService).to receive(:new).and_return(service)
|
allow(ResolveURLService).to receive(:new).and_return(service)
|
||||||
results = subject.call(@query, nil, 10, resolve: true)
|
results = subject.call(query, nil, 10, resolve: true)
|
||||||
|
|
||||||
expect(service).to have_received(:call).with(@query, on_behalf_of: nil)
|
expect(service).to have_received(:call).with(query, on_behalf_of: nil)
|
||||||
expect(results).to eq empty_results
|
expect(results).to eq empty_results
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -40,8 +38,8 @@ describe SearchService, type: :service do
|
||||||
service = instance_double(ResolveURLService, call: account)
|
service = instance_double(ResolveURLService, call: account)
|
||||||
allow(ResolveURLService).to receive(:new).and_return(service)
|
allow(ResolveURLService).to receive(:new).and_return(service)
|
||||||
|
|
||||||
results = subject.call(@query, nil, 10, resolve: true)
|
results = subject.call(query, nil, 10, resolve: true)
|
||||||
expect(service).to have_received(:call).with(@query, on_behalf_of: nil)
|
expect(service).to have_received(:call).with(query, on_behalf_of: nil)
|
||||||
expect(results).to eq empty_results.merge(accounts: [account])
|
expect(results).to eq empty_results.merge(accounts: [account])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -52,8 +50,8 @@ describe SearchService, type: :service do
|
||||||
service = instance_double(ResolveURLService, call: status)
|
service = instance_double(ResolveURLService, call: status)
|
||||||
allow(ResolveURLService).to receive(:new).and_return(service)
|
allow(ResolveURLService).to receive(:new).and_return(service)
|
||||||
|
|
||||||
results = subject.call(@query, nil, 10, resolve: true)
|
results = subject.call(query, nil, 10, resolve: true)
|
||||||
expect(service).to have_received(:call).with(@query, on_behalf_of: nil)
|
expect(service).to have_received(:call).with(query, on_behalf_of: nil)
|
||||||
expect(results).to eq empty_results.merge(statuses: [status])
|
expect(results).to eq empty_results.merge(statuses: [status])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,38 +6,36 @@ describe UnblockDomainService, type: :service do
|
||||||
subject { described_class.new }
|
subject { described_class.new }
|
||||||
|
|
||||||
describe 'call' do
|
describe 'call' do
|
||||||
before do
|
let!(:independently_suspended) { Fabricate(:account, domain: 'example.com', suspended_at: 1.hour.ago) }
|
||||||
@independently_suspended = Fabricate(:account, domain: 'example.com', suspended_at: 1.hour.ago)
|
let!(:independently_silenced) { Fabricate(:account, domain: 'example.com', silenced_at: 1.hour.ago) }
|
||||||
@independently_silenced = Fabricate(:account, domain: 'example.com', silenced_at: 1.hour.ago)
|
let!(:domain_block) { Fabricate(:domain_block, domain: 'example.com') }
|
||||||
@domain_block = Fabricate(:domain_block, domain: 'example.com')
|
let!(:silenced) { Fabricate(:account, domain: 'example.com', silenced_at: domain_block.created_at) }
|
||||||
@silenced = Fabricate(:account, domain: 'example.com', silenced_at: @domain_block.created_at)
|
let!(:suspended) { Fabricate(:account, domain: 'example.com', suspended_at: domain_block.created_at) }
|
||||||
@suspended = Fabricate(:account, domain: 'example.com', suspended_at: @domain_block.created_at)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'unsilences accounts and removes block' do
|
it 'unsilences accounts and removes block' do
|
||||||
@domain_block.update(severity: :silence)
|
domain_block.update(severity: :silence)
|
||||||
|
|
||||||
subject.call(@domain_block)
|
subject.call(domain_block)
|
||||||
expect_deleted_domain_block
|
expect_deleted_domain_block
|
||||||
expect(@silenced.reload.silenced?).to be false
|
expect(silenced.reload.silenced?).to be false
|
||||||
expect(@suspended.reload.suspended?).to be true
|
expect(suspended.reload.suspended?).to be true
|
||||||
expect(@independently_suspended.reload.suspended?).to be true
|
expect(independently_suspended.reload.suspended?).to be true
|
||||||
expect(@independently_silenced.reload.silenced?).to be true
|
expect(independently_silenced.reload.silenced?).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'unsuspends accounts and removes block' do
|
it 'unsuspends accounts and removes block' do
|
||||||
@domain_block.update(severity: :suspend)
|
domain_block.update(severity: :suspend)
|
||||||
|
|
||||||
subject.call(@domain_block)
|
subject.call(domain_block)
|
||||||
expect_deleted_domain_block
|
expect_deleted_domain_block
|
||||||
expect(@suspended.reload.suspended?).to be false
|
expect(suspended.reload.suspended?).to be false
|
||||||
expect(@silenced.reload.silenced?).to be false
|
expect(silenced.reload.silenced?).to be false
|
||||||
expect(@independently_suspended.reload.suspended?).to be true
|
expect(independently_suspended.reload.suspended?).to be true
|
||||||
expect(@independently_silenced.reload.silenced?).to be true
|
expect(independently_silenced.reload.silenced?).to be true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def expect_deleted_domain_block
|
def expect_deleted_domain_block
|
||||||
expect { @domain_block.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
expect { domain_block.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,3 +41,38 @@ class SearchDataManager
|
||||||
Tag.destroy_all
|
Tag.destroy_all
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
RSpec.configure do |config|
|
||||||
|
config.before :suite do
|
||||||
|
if search_examples_present?
|
||||||
|
# Configure chewy to use `urgent` strategy to index documents
|
||||||
|
Chewy.strategy(:urgent)
|
||||||
|
|
||||||
|
# Create search data
|
||||||
|
search_data_manager.prepare_test_data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
config.after :suite do
|
||||||
|
if search_examples_present?
|
||||||
|
# Clean up after search data
|
||||||
|
search_data_manager.cleanup_test_data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
config.around :each, type: :search do |example|
|
||||||
|
search_data_manager.populate_indexes
|
||||||
|
example.run
|
||||||
|
search_data_manager.remove_indexes
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def search_data_manager
|
||||||
|
@search_data_manager ||= SearchDataManager.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def search_examples_present?
|
||||||
|
RUN_SEARCH_SPECS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -76,3 +76,32 @@ class StreamingServerManager
|
||||||
@running_thread.join
|
@running_thread.join
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
RSpec.configure do |config|
|
||||||
|
config.before :suite do
|
||||||
|
if streaming_examples_present?
|
||||||
|
# Compile assets
|
||||||
|
Webpacker.compile
|
||||||
|
|
||||||
|
# Start the node streaming server
|
||||||
|
streaming_server_manager.start(port: STREAMING_PORT)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
config.after :suite do
|
||||||
|
if streaming_examples_present?
|
||||||
|
# Stop the node streaming server
|
||||||
|
streaming_server_manager.stop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def streaming_server_manager
|
||||||
|
@streaming_server_manager ||= StreamingServerManager.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def streaming_examples_present?
|
||||||
|
RUN_SYSTEM_SPECS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe BlacklistedEmailValidator, type: :validator do
|
RSpec.describe BlacklistedEmailValidator do
|
||||||
describe '#validate' do
|
describe '#validate' do
|
||||||
subject { described_class.new.validate(user); errors }
|
subject { described_class.new.validate(user); errors }
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe DisallowedHashtagsValidator, type: :validator do
|
RSpec.describe DisallowedHashtagsValidator do
|
||||||
let(:disallowed_tags) { [] }
|
let(:disallowed_tags) { [] }
|
||||||
|
|
||||||
describe '#validate' do
|
describe '#validate' do
|
||||||
|
|
|
@ -2,48 +2,76 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe FollowLimitValidator, type: :validator do
|
RSpec.describe FollowLimitValidator do
|
||||||
describe '#validate' do
|
describe '#validate' do
|
||||||
before do
|
context 'with a nil account' do
|
||||||
allow_any_instance_of(described_class).to receive(:limit_reached?).with(account) do
|
it 'does not add validation errors to base' do
|
||||||
limit_reached
|
follow = Fabricate.build(:follow, account: nil)
|
||||||
end
|
|
||||||
|
|
||||||
described_class.new.validate(follow)
|
follow.valid?
|
||||||
end
|
|
||||||
|
|
||||||
let(:follow) { instance_double(Follow, account: account, errors: errors) }
|
expect(follow.errors[:base]).to be_empty
|
||||||
let(:errors) { instance_double(ActiveModel::Errors, add: nil) }
|
|
||||||
let(:account) { instance_double(Account, nil?: _nil, local?: local, following_count: 0, followers_count: 0) }
|
|
||||||
let(:_nil) { true }
|
|
||||||
let(:local) { false }
|
|
||||||
|
|
||||||
context 'with follow.account.nil? || !follow.account.local?' do
|
|
||||||
let(:_nil) { true }
|
|
||||||
|
|
||||||
it 'not calls errors.add' do
|
|
||||||
expect(errors).to_not have_received(:add).with(:base, any_args)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with !(follow.account.nil? || !follow.account.local?)' do
|
context 'with a non-local account' do
|
||||||
let(:_nil) { false }
|
it 'does not add validation errors to base' do
|
||||||
let(:local) { true }
|
follow = Fabricate.build(:follow, account: Account.new(domain: 'host.example'))
|
||||||
|
|
||||||
context 'when limit_reached?' do
|
follow.valid?
|
||||||
let(:limit_reached) { true }
|
|
||||||
|
|
||||||
it 'calls errors.add' do
|
expect(follow.errors[:base]).to be_empty
|
||||||
expect(errors).to have_received(:add)
|
end
|
||||||
.with(:base, I18n.t('users.follow_limit_reached', limit: FollowLimitValidator::LIMIT))
|
end
|
||||||
|
|
||||||
|
context 'with a local account' do
|
||||||
|
let(:account) { Account.new }
|
||||||
|
|
||||||
|
context 'when the followers count is under the limit' do
|
||||||
|
before do
|
||||||
|
allow(account).to receive(:following_count).and_return(described_class::LIMIT - 100)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not add validation errors to base' do
|
||||||
|
follow = Fabricate.build(:follow, account: account)
|
||||||
|
|
||||||
|
follow.valid?
|
||||||
|
|
||||||
|
expect(follow.errors[:base]).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with !limit_reached?' do
|
context 'when the following count is over the limit' do
|
||||||
let(:limit_reached) { false }
|
before do
|
||||||
|
allow(account).to receive(:following_count).and_return(described_class::LIMIT + 100)
|
||||||
|
end
|
||||||
|
|
||||||
it 'not calls errors.add' do
|
context 'when the followers count is low' do
|
||||||
expect(errors).to_not have_received(:add).with(:base, any_args)
|
before do
|
||||||
|
allow(account).to receive(:followers_count).and_return(10)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds validation errors to base' do
|
||||||
|
follow = Fabricate.build(:follow, account: account)
|
||||||
|
|
||||||
|
follow.valid?
|
||||||
|
|
||||||
|
expect(follow.errors[:base]).to include(I18n.t('users.follow_limit_reached', limit: FollowLimitValidator::LIMIT))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the followers count is high' do
|
||||||
|
before do
|
||||||
|
allow(account).to receive(:followers_count).and_return(100_000)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not add validation errors to base' do
|
||||||
|
follow = Fabricate.build(:follow, account: account)
|
||||||
|
|
||||||
|
follow.valid?
|
||||||
|
|
||||||
|
expect(follow.errors[:base]).to be_empty
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe PollValidator, type: :validator do
|
RSpec.describe PollValidator do
|
||||||
describe '#validate' do
|
describe '#validate' do
|
||||||
before do
|
before do
|
||||||
validator.validate(poll)
|
validator.validate(poll)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe StatusPinValidator, type: :validator do
|
RSpec.describe StatusPinValidator do
|
||||||
describe '#validate' do
|
describe '#validate' do
|
||||||
before do
|
before do
|
||||||
subject.validate(pin)
|
subject.validate(pin)
|
||||||
|
|
Loading…
Reference in New Issue