diff --git a/.dockerignore b/.dockerignore index 2ddfa9b953..5cd3b179a5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,7 +4,6 @@ public/system public/assets public/packs node_modules -storybook neo4j vendor/bundle .DS_Store diff --git a/.env.production.sample b/.env.production.sample index eb1c5a48f5..1d8a177aa2 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -69,7 +69,7 @@ SMTP_FROM_ADDRESS=notifications@example.com #SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt #SMTP_OPENSSL_VERIFY_MODE=peer #SMTP_ENABLE_STARTTLS_AUTO=true - +#SMTP_TLS=true # Optional user upload path and URL (images, avatars). Default is :rails_root/public/system. If you set this variable, you are responsible for making your HTTP server (eg. nginx) serve these files. # PAPERCLIP_ROOT_PATH=/var/lib/mastodon/public-system diff --git a/.eslintrc.yml b/.eslintrc.yml index a816bffeff..fd2ba46dd0 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -112,7 +112,7 @@ rules: jsx-a11y/iframe-has-title: warn jsx-a11y/img-has-alt: warn jsx-a11y/img-redundant-alt: warn - jsx-a11y/label-has-for: warn + jsx-a11y/label-has-for: off jsx-a11y/mouse-events-have-key-events: warn jsx-a11y/no-access-key: warn jsx-a11y/no-distracting-elements: warn @@ -121,6 +121,6 @@ rules: jsx-a11y/onclick-has-focus: warn jsx-a11y/onclick-has-role: warn jsx-a11y/role-has-required-aria-props: warn - jsx-a11y/role-supports-aria-props: warn + jsx-a11y/role-supports-aria-props: off jsx-a11y/scope: warn jsx-a11y/tabindex-no-positive: warn diff --git a/.gitignore b/.gitignore index 868a843682..38ebc934f2 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,6 @@ public/system public/assets public/packs public/packs-test -public/sw.js .env .env.production node_modules/ diff --git a/.nanoignore b/.nanoignore index f02c0a68ac..80e9397035 100644 --- a/.nanoignore +++ b/.nanoignore @@ -14,7 +14,6 @@ node_modules/ public/assets/ public/system/ spec/ -storybook/ tmp/ .vagrant/ vendor/bundle/ diff --git a/.rubocop.yml b/.rubocop.yml index 1cbdadd49f..ae36971747 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -27,6 +27,7 @@ Metrics/AbcSize: Max: 100 Metrics/BlockLength: + Max: 35 Exclude: - 'lib/tasks/**/*' @@ -35,10 +36,10 @@ Metrics/BlockNesting: Metrics/ClassLength: CountComments: false - Max: 200 + Max: 300 Metrics/CyclomaticComplexity: - Max: 15 + Max: 25 Metrics/LineLength: AllowURI: true @@ -53,11 +54,11 @@ Metrics/ModuleLength: Max: 200 Metrics/ParameterLists: - Max: 4 + Max: 5 CountKeywordArgs: true Metrics/PerceivedComplexity: - Max: 10 + Max: 20 Rails: Enabled: true diff --git a/.slugignore b/.slugignore index b0141b0e2b..5470f6e3f3 100644 --- a/.slugignore +++ b/.slugignore @@ -2,4 +2,3 @@ node_modules/ .cache/ docs/ spec/ -storybook/ diff --git a/Aptfile b/Aptfile index f89f74bd4e..48dff1a770 100644 --- a/Aptfile +++ b/Aptfile @@ -1,7 +1,9 @@ -protobuf-compiler -libprotobuf-dev ffmpeg -libxdamage1 -libxfixes3 libicu-dev +libidn11 libidn11-dev +libpq-dev +libprotobuf-dev +libxdamage1 +libxfixes3 +protobuf-compiler diff --git a/README.md b/README.md index 7d9b6e4ab1..998d570053 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,3 @@ So here's the deal: we all work on this code, and then it runs on dev.glitch.soc - You can view documentation for this project at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/). - And contributing guidelines are available [here](CONTRIBUTING.md) and [here](https://glitch-soc.github.io/docs/contributing/). - diff --git a/app.json b/app.json index a935b8232b..09adaac2c9 100644 --- a/app.json +++ b/app.json @@ -2,7 +2,7 @@ "name": "Mastodon", "description": "A GNU Social-compatible microblogging server", "repository": "https://github.com/tootsuite/mastodon", - "logo": "https://github.com/tootsuite/mastodon/raw/master/app/javascript/images/logo.svg", + "logo": "https://github.com/tootsuite.png", "env": { "HEROKU": { "description": "Leave this as true", diff --git a/app/controllers/settings/two_factor_authentications_controller.rb b/app/controllers/settings/two_factor_authentications_controller.rb index 9834838817..863cc7351b 100644 --- a/app/controllers/settings/two_factor_authentications_controller.rb +++ b/app/controllers/settings/two_factor_authentications_controller.rb @@ -18,7 +18,7 @@ module Settings end def destroy - if current_user.validate_and_consume_otp!(confirmation_params[:code]) + if acceptable_code? current_user.otp_required_for_login = false current_user.save! redirect_to settings_two_factor_authentication_path @@ -38,5 +38,10 @@ module Settings def verify_otp_required redirect_to settings_two_factor_authentication_path if current_user.otp_required_for_login? end + + def acceptable_code? + current_user.validate_and_consume_otp!(confirmation_params[:code]) || + current_user.invalidate_otp_backup_code!(confirmation_params[:code]) + end end end diff --git a/app/helpers/instance_helper.rb b/app/helpers/instance_helper.rb index a1c3c3521f..70027cca91 100644 --- a/app/helpers/instance_helper.rb +++ b/app/helpers/instance_helper.rb @@ -2,7 +2,7 @@ module InstanceHelper def site_title - Setting.site_title.to_s + Setting.site_title.presence || site_hostname end def site_hostname diff --git a/app/javascript/mastodon/components/autosuggest_textarea.js b/app/javascript/mastodon/components/autosuggest_textarea.js index fa41e59e1f..35b37600fe 100644 --- a/app/javascript/mastodon/components/autosuggest_textarea.js +++ b/app/javascript/mastodon/components/autosuggest_textarea.js @@ -162,20 +162,23 @@ export default class AutosuggestTextarea extends ImmutablePureComponent { return (
{' '} @@ -158,13 +158,15 @@ export default class StatusContent extends React.PureComponent { {mentionsPlaceholder} -
+,
, etc.)
// and replacing valid unicode strings
@@ -19,7 +21,7 @@ function emojify(str) {
insideTag = true;
} else if (!insideTag && (match = trie.search(str.substring(i)))) {
const unicodeStr = match;
- if (unicodeStr in unicodeMapping) {
+ if (unicodeStr in unicodeMapping && excluded.indexOf(unicodeStr) === -1) {
const [filename, shortCode] = unicodeMapping[unicodeStr];
const alt = unicodeStr;
const replacement = ``;
diff --git a/app/javascript/mastodon/features/account/components/action_bar.js b/app/javascript/mastodon/features/account/components/action_bar.js
index b8df724c67..c12c0889e4 100644
--- a/app/javascript/mastodon/features/account/components/action_bar.js
+++ b/app/javascript/mastodon/features/account/components/action_bar.js
@@ -1,7 +1,7 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
-import DropdownMenu from '../../../components/dropdown_menu';
+import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
import Link from 'react-router-dom/Link';
import { defineMessages, injectIntl, FormattedMessage, FormattedNumber } from 'react-intl';
@@ -15,6 +15,7 @@ const messages = defineMessages({
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
follow: { id: 'account.follow', defaultMessage: 'Follow' },
report: { id: 'account.report', defaultMessage: 'Report @{name}' },
+ share: { id: 'account.share', defaultMessage: 'Share @{name}\'s profile' },
media: { id: 'account.media', defaultMessage: 'Media' },
blockDomain: { id: 'account.block_domain', defaultMessage: 'Hide everything from {domain}' },
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
@@ -36,6 +37,12 @@ export default class ActionBar extends React.PureComponent {
intl: PropTypes.object.isRequired,
};
+ handleShare = () => {
+ navigator.share({
+ url: this.props.account.get('url'),
+ });
+ }
+
render () {
const { account, me, intl } = this.props;
@@ -43,6 +50,9 @@ export default class ActionBar extends React.PureComponent {
let extraInfo = '';
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.props.onMention });
+ if ('share' in navigator) {
+ menu.push({ text: intl.formatMessage(messages.share, { name: account.get('username') }), action: this.handleShare });
+ }
menu.push(null);
menu.push({ text: intl.formatMessage(messages.media), to: `/accounts/${account.get('id')}/media` });
menu.push(null);
@@ -96,7 +106,7 @@ export default class ActionBar extends React.PureComponent {
با احترام,
-
گردانندگان سرور <%= @instance %>
+گردانندگان سرور <%= @instance %>
\ No newline at end of file diff --git a/app/views/user_mailer/confirmation_instructions.fa.text.erb b/app/views/user_mailer/confirmation_instructions.fa.text.erb index 904bd5bfe7..76727b3bef 100644 --- a/app/views/user_mailer/confirmation_instructions.fa.text.erb +++ b/app/views/user_mailer/confirmation_instructions.fa.text.erb @@ -9,4 +9,4 @@ با احترام، -گردانندگان سرور <%= @instance %> +گردانندگان سرور <%= @instance %> \ No newline at end of file diff --git a/app/workers/pubsubhubbub/delivery_worker.rb b/app/workers/pubsubhubbub/delivery_worker.rb index 035a590481..88645cf338 100644 --- a/app/workers/pubsubhubbub/delivery_worker.rb +++ b/app/workers/pubsubhubbub/delivery_worker.rb @@ -16,6 +16,8 @@ class Pubsubhubbub::DeliveryWorker @subscription = Subscription.find(subscription_id) @payload = payload process_delivery unless blocked_domain? + rescue => e + raise e.class, "Delivery failed for #{subscription&.callback_url}: #{e.message}" end private diff --git a/app/workers/pubsubhubbub/distribution_worker.rb b/app/workers/pubsubhubbub/distribution_worker.rb index ce467d18b1..ea246128d2 100644 --- a/app/workers/pubsubhubbub/distribution_worker.rb +++ b/app/workers/pubsubhubbub/distribution_worker.rb @@ -14,7 +14,7 @@ class Pubsubhubbub::DistributionWorker @subscriptions = active_subscriptions.to_a distribute_public!(stream_entries.reject(&:hidden?)) - distribute_hidden!(stream_entries.reject { |s| !s.hidden? }) + distribute_hidden!(stream_entries.select(&:hidden?)) end private @@ -35,7 +35,7 @@ class Pubsubhubbub::DistributionWorker @payload = OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, stream_entries)) @domains = @account.followers.domains - Pubsubhubbub::DeliveryWorker.push_bulk(@subscriptions.reject { |s| !allowed_to_receive?(s.callback_url, s.domain) }) do |subscription| + Pubsubhubbub::DeliveryWorker.push_bulk(@subscriptions.select { |s| allowed_to_receive?(s.callback_url, s.domain) }) do |subscription| [subscription.id, @payload] end end diff --git a/app/workers/pubsubhubbub/subscribe_worker.rb b/app/workers/pubsubhubbub/subscribe_worker.rb index 6865e71360..7560c2671f 100644 --- a/app/workers/pubsubhubbub/subscribe_worker.rb +++ b/app/workers/pubsubhubbub/subscribe_worker.rb @@ -3,7 +3,7 @@ class Pubsubhubbub::SubscribeWorker include Sidekiq::Worker - sidekiq_options queue: 'push', retry: 10, unique: :until_executed + sidekiq_options queue: 'push', retry: 10, unique: :until_executed, dead: false sidekiq_retry_in do |count| case count @@ -18,9 +18,17 @@ class Pubsubhubbub::SubscribeWorker end end + sidekiq_retries_exhausted do |msg, _e| + account = Account.find(msg['args'].first) + logger.error "PuSH subscription attempts for #{account.acct} exhausted. Unsubscribing" + ::UnsubscribeService.new.call(account) + end + def perform(account_id) account = Account.find(account_id) logger.debug "PuSH re-subscribing to #{account.acct}" ::SubscribeService.new.call(account) + rescue => e + raise e.class, "Subscribe failed for #{account&.acct}: #{e.message}" end end diff --git a/app/workers/web_push_notification_worker.rb b/app/workers/web_push_notification_worker.rb index da4043ddbd..eacea04c34 100644 --- a/app/workers/web_push_notification_worker.rb +++ b/app/workers/web_push_notification_worker.rb @@ -7,16 +7,19 @@ class WebPushNotificationWorker def perform(session_activation_id, notification_id) session_activation = SessionActivation.find(session_activation_id) - notification = Notification.find(notification_id) + notification = Notification.find(notification_id) - begin - session_activation.web_push_subscription.push(notification) - rescue Webpush::InvalidSubscription, Webpush::ExpiredSubscription => e - # Subscription expiration is not currently implemented in any browser - session_activation.web_push_subscription.destroy! - session_activation.update!(web_push_subscription: nil) + return if session_activation.web_push_subscription.nil? || notification.activity.nil? - raise e - end + session_activation.web_push_subscription.push(notification) + rescue Webpush::InvalidSubscription, Webpush::ExpiredSubscription + # Subscription expiration is not currently implemented in any browser + + session_activation.web_push_subscription.destroy! + session_activation.update!(web_push_subscription: nil) + + true + rescue ActiveRecord::RecordNotFound + true end end diff --git a/boxfile.yml b/boxfile.yml index 3302231109..59a66d87bc 100644 --- a/boxfile.yml +++ b/boxfile.yml @@ -1,7 +1,7 @@ run.config: engine: ruby engine.config: - runtime: ruby-2.4.1 + runtime: ruby-2.4 extra_packages: # basic servers: @@ -20,6 +20,9 @@ run.config: # for node-gyp, used in the asset compilation process: - python-2 + # i18n: + - libidn + cache_dirs: - node_modules @@ -35,10 +38,6 @@ run.config: extra_steps: - envsubst < .env.nanobox > .env - - gem install bundler - - bundle config build.nokogiri --with-iconv-dir=/data/ --with-zlib-dir=/data/ - - bundle config build.nokogumbo --with-iconv-dir=/data/ --with-zlib-dir=/data/ - - bundle install --clean - yarn fs_watch: true diff --git a/config/locales/ca.yml b/config/locales/ca.yml index ce4831ac2b..725b120ec3 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -161,7 +161,7 @@ ca: confirmed: Confirmat expires_in: Expira en last_delivery: Últim lliurament - title: PubSubHubbub + title: WebSub topic: Tòpic title: Administració application_mailer: diff --git a/config/locales/de.yml b/config/locales/de.yml index 04d3fd0b89..87c5fa67a0 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -144,7 +144,7 @@ de: confirmed: Bestätigt expires_in: Verfällt in last_delivery: Letzte Zustellung - title: PubSubHubbub + title: WebSub topic: Thema title: Administration application_mailer: diff --git a/config/locales/en.yml b/config/locales/en.yml index 8fa1ac0e38..90b4fe82bc 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -207,7 +207,7 @@ en: confirmed: Confirmed expires_in: Expires in last_delivery: Last delivery - title: PubSubHubbub + title: WebSub topic: Topic title: Administration admin_mailer: @@ -215,6 +215,7 @@ en: body: "%{reporter} has reported %{target}" subject: New report for %{instance} (#%{id}) application_mailer: + salutation: '%{name},' settings: 'Change e-mail preferences: %{link}' signature: Mastodon notifications from %{instance} view: 'View:' @@ -348,6 +349,8 @@ en: title: "%{name} favourited your status" follow: title: "%{name} is now following you" + group: + title: "%{count} notifications" mention: action_boost: Boost action_expand: Show more diff --git a/config/locales/fa.yml b/config/locales/fa.yml index c42016eb3e..eb66a9c410 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -1,19 +1,38 @@ --- fa: about: - about_mastodon_html: ماستدون (Mastodon) یک شبکهٔ اجتماعی آزاد و کدباز است. یک جایگزین غیرمتمرکز برای شبکههای تجاری، که نمیگذارد ارتباطهای شما را یک شرکت در انحصار خود بگیرد. یک سرور مورد اعتماد را انتخاب کنید — هر سروری که باشد، همچنان میتوانید با سرورهای دیگر ارتباط داشته باشید. هر کسی میتواند سرور ماستدون خود را راه بیندازد و در شبکهٔ اجتماعی سهیم شود. - about_this: دربارهٔ این سرور - closed_registrations: امکان ثبت نام روی این سرور هماینک فعال نیست. + about_mastodon_html: ماستدون (Mastodon) یک شبکهٔ اجتماعی است که بر اساس پروتکلهای آزاد وب و نرمافزارهای آزاد و کدباز ساخته شده است. این شبکه مانند ایمیل غیرمتمرکز است. + about_this: درباره. + closed_registrations: ثبتنام روی این سرور هماینک فعال نیست. اما شما میتوانید سرور دیگری بیابید و با حسابی که آنجا میسازید دقیقاً به همین شبکه دسترسی داشته باشید. contact: تماس + contact_missing: تعیین نشده + contact_unavailable: موجود نیست description_headline: "%{domain} چیست؟" domain_count_after: سرور دیگر domain_count_before: متصل به - other_instances: سرورهای دیگر + extended_description_html: | +توضیحات تکمیلی نوشته نشده است.
+ features: + humane_approach_body: با آموختن از کاستیهای شبکههای دیگر، ماستدون میخواهد به کمک انتخابهای اخلاقیتر در طراحی خودش با آسیبهای شبکههای اجتماعی مبارزه کند. + humane_approach_title: رویکردی انسانیتر + not_a_product_body: ماستدون یک شبکهٔ تجاری نیست. بدون تبلیغات، بدون دادهکاوی، بدون حصارکشی. هیچ قدرت مرکزیای وجود ندارد. + not_a_product_title: شما یک انسان هستید، نه یک محصول + real_conversation_body: با ۵۰۰ نویسه برای هر نوشته و با پشتیبانی از هشدارهای موردی برای نوشتهها و تصاویر، میتوانید خود را همان گونه که میخواهید ابراز کنید. + real_conversation_title: برای گفتگوهای واقعی + within_reach_body: اپهای متنوع برای iOS، اندروید، و سیستمهای دیگر به خاطر وحود یک اکوسیستم API دوستانه برای برنامهنویسان. از همه جا با دوستان خود ارتباط داشته باشید. + within_reach_title: همیشه در دسترس + find_another_instance: یافتن سرورهای دیگر + generic_description: "%{domain} یک سرور روی شبکه است" + hosted_on: ماستدون میزبانیشده روی %{domain} + learn_more: بیشتر بدانید + other_instances: فهرست سرورها source_code: کدهای منبع status_count_after: چیز نوشتهاند status_count_before: که جمعاً user_count_after: کاربر user_count_before: دارای + what_is_mastodon: ماستدون چیست؟ accounts: follow: پی بگیرید followers: پیگیران @@ -23,12 +42,14 @@ fa: people_who_follow: کسانی که %{name} را پی میگیرند posts: نوشته remote_follow: پیگیری غیرمستقیم + reserved_username: این نام کاربری در دسترس نیست unfollow: پایان پیگیری admin: accounts: are_you_sure: آیا مطمئن هستید؟ confirm: تأیید confirmed: تأیید شد + disable_two_factor_authentication: غیرفعالسازی ورود دومرحلهای display_name: نمایش به نام domain: دامین edit: ویرایش @@ -36,6 +57,7 @@ fa: feed_url: نشانی فید followers: پیگیران follows: پی میگیرد + ip: IP location: all: همه local: محلی @@ -58,17 +80,23 @@ fa: profile_url: نشانی نمایه public: عمومی push_subscription_expires: عضویت از راه PuSH منقضی شد + redownload: بهروزرسانی تصویر نمایه + reset: بازنشانی reset_password: بازنشانی رمز + resubscribe: اشتراک دوباره salmon_url: نشانی Salmon + search: جستجو show: created_reports: گزارشها از طرف این حساب report: گزارش targeted_reports: گزارشها دربارهٔ این حساب silence: بیصدا statuses: نوشتهها + subscribe: اشتراک title: حسابها undo_silenced: واگردانی بیصداکردن undo_suspension: واگردانی تعلیق + unsubscribe: لغو اشتراک username: نام کاربری web: وب domain_blocks: @@ -81,12 +109,14 @@ fa: hint: مسدودسازی دامین جلوی فهرستشدن حسابها در پایگاه داده را نمیگیرد، بلکه به طور خودکار روشهای مدیریتی را روی فعالیتهای فعلی و گذشتهٔ آن حسابها اعمال میکند. severity: desc_html: "بیصداکردن یک حساب نوشتههای آن را برای همه (به جز پیگیرانش) ناپدید میکند. معلقکردن حساب همهٔ نوشتهها، تصویرها، و اطلاعات حساب را پاک میکند." + noop: هیچ silence: بیصداکردن suspend: معلقکردن title: مسدودسازی دامین دیگر reject_media: نپذیرفتن پروندههای تصویری reject_media_hint: تصویرهای ذخیرهشده در اینجا را پاک میکند و جلوی دریافت تصویرها را در آینده میگیرد. بیتأثیر برای معلقشدهها severities: + noop: هیچ silence: بیصداکردن suspend: معلقکردن severity: شدت @@ -106,12 +136,17 @@ fa: domain_name: دامین title: سرورهای شناختهشده reports: + action_taken_by: انجامدهنده + are_you_sure: آیا مطمئن هستید؟ comment: label: توضیح none: خالی delete: پاککردن id: شناسه mark_as_resolved: علامتگذاری به عنوان حلشده + nsfw: + 'false': نمایش پیوستهای تصویری + 'true': نهفتن پیوستهای تصویری report: 'گزارش #%{id}' report_contents: محتوا reported_account: حساب گزارششده @@ -126,38 +161,71 @@ fa: view: نمایش settings: contact_information: - email: یک نشانی ایمیل عمومی وارد کنید - username: یک نام کاربری وارد کنید + email: ایمیل کاری + username: نام کاربری registrations: closed_message: desc_html: وقتی امکان ثبت نام روی سرور فعال نباشد در صفحهٔ اصلی نمایش مییابد<a>
و <em>
.
title: دربارهٔ سایت
site_description_extended:
- desc_html: در صفحهٔ اطلاعات تکمیلی نشان داده میشوداین سایت برخی از اطلاعات مربوط به شما را ثبت میکند. این موارد شامل اطلاعات ثبتنامی شماست، و نیز شامل نوشتههایی است که اینجا میخوانید، مینویسید، یا واکنشهایی که به نوشتههای دیگران نشان میدهید.
+ +وقتی که در این سایت ثبتنام میکنید، ممکن است از شما بخواهیم که نام و نشانی ایمیل خود را وارد کنید. البته بدون ثبتنام نیز میتوان از این سایت بازدید کرد. برای تأیید ایمیل شما، ما یک نشانی اینترنتی یکتا را به آن میفرستیم. اگر آن نشانی را کسی باز کند، ما میفهمیم که آن شما بودهاید و بنابراین نشانی ایمیل متعلق به شماست.
+ +وقتی که عضو باشید و چیزی بنویسید، ما نشانی اینترنتیای (IP) را که نوشته از آن آمده است ثبت میکنیم. سیاههٔ کاری (log) سرور شامل نشانی IP همهٔ درخواستها به سرور است که ما شاید آن را هم ثبت کنیم.
+ +اطلاعاتی را که ما از شما ثبت میکنیم، ممکن است در موارد زیر به کار بروند:
+ +ما روشهای امنیتی گوناگونی را پیاده کردهایم تا امنیت اطلاعات شخصی شما هنگام ثبت، فرستادهشدن، و بازیابی آنها حفظ شود.
+ +ما با حسن نیت تلاش میکنیم تا:
+ +بله. کوکیها پروندههای کوچکی هستند که یک سایت یا خدماتدهندهاش (اگر شما اجازه بدهید) از راه مرورگر در کامپیوتر شما ذخیره میکنند. به کمک این کوکیها سایت میتواند مرورگر شما را بشناسد و اگر شما ثبتنام کرده باشید، حساب شما را به مرورگرتان مرتبط کند.
+ +ما به کمک کوکیها ترجیحات شما را برای بازدیدهای آینده میفهمیم و ذخیره میکنیم و دادههای جامعی دربارهٔ بازدیدها از سایت و برهمکنشها با آن را تهیه میکنیم. به این ترتیب میتوانیم در آینده تجربهٔ کاربری سایت و ابزارهای مربوط به آن را بهتر کنیم. برای داشتن درک بهتری از بازدیدکنندگان این سایت، ما گاهی از خدماتدهندههای دیگر نیز کمک میگیریم. این خدماتدهندهها اجازه ندارند تا از اطلاعاتی که به جای ما جمع میکنند برای کاری به جز بهترکردن کار ما استفاده کنند.
+ +ما اطلاعاتی را که بتواند شما را شناسایی کند به نهادهای دیگر نمیفروشیم، معامله نمیکنیم، یا به هر روش دیگری منتقل نمیکنیم. این شامل نهادهای مورد اعتمادی نمیشود که به ما در گرداندن این سایت یا انجام کارهایمان کمک میکنند، یا به شما خدمات میرسانند، تا جایی که آنها این دادهها را محرمانه نگه دارند. ما همچنین ممکن است اطلاعات شما را به حکم قانون یا برای اِعمال سیاستهای سایت، یا به خاطر حفظ حقوق، داراییها، یا امنیت خودمان یا دیگران منتشر کنیم. ما ممکن است اطلاعات بازدیدکنندگان سایت را که با آن نمیتوان شما را شناسایی کرد برای بازاریابی، تبلیغات، یا هدفهای دیگر به نهادهای دیگر ارائه دهیم.
+ +ما گاهی ممکن است به صلاحدید خودمان محصولات یا خدمات دیگران را در این سایت بگنجانیم یا پیشنهاد دهیم. سایتهای مرتبط با این محصولات و خدمات دارای سیاستهای رازداری جداگانه و مستقل خودشان هستند. بنابراین ما مسئولیتی دربارهٔ محتوا و کنشهای این سایتها به عهده نمیگیریم. با این وجود، ما تلاش میکنیم که این سایت به درستی کار کند و از بازخورد شما برای چنین محصولات و خدماتی استقبال میکنیم.
+ +سایت ما، محصولات و خدماتش همه برای کسانی است که دستکم ۱۳ سال سن داشته باشند. اگر این سرور در خاک ایالات متحدهٔ امریکا قرار دارد و سن شما کمتر از ۱۳ سال است، به خاطر رعایت قانون COPPA (Children's Online Privacy Protection Act) لطفاً این سایت را به کار نبرید.
+ +این سیاست رازداری آنلاین تنها مربوط به اطلاعاتی است که از راه سایت ما گردآوری میشود و شامل اطلاعاتی که به طور آفلاین گردآوری شده نیست.
+ +با استفاده از این سایت، شما موافقت خود را با سیاست رازداری ما اعلام میکنید.
+ +اگر ما سیاست رازداری خود را تغییر دهیم، این تغییرات را در این صفحه خواهیم نوشت.
+ +این نوشته تحت اجازهنامهٔ CC-BY-SA قرار دارد. تاریخ آخرین بهروزرسانی آن ۱۰ خرداد ۱۳۹۲ است.
+ +این نوشته اقتباسی است از سیاست رازداری Discourse.
+ title: "شرایط استفاده و سیاست رازداری %{instance}" time: formats: default: "%d %b %Y, %H:%M" @@ -299,11 +509,13 @@ fa: description_html: اگر ورود دومرحلهای را فعال کنید، برای ورود به سیستم به تلفن خود نیاز خواهید داشت تا برایتان یک کد موقتی بسازد disable: غیرفعالکردن enable: فعالکردن + enabled: ورود دومرحلهای فعال است enabled_success: ورود دومرحلهای با موفقیت فعال شد generate_recovery_codes: ساخت کدهای بازیابی instructions_html: "این کد QR را با برنامهٔ Google Authenticator یا برنامههای TOTP مشابه اسکن کنید. از این به بعد، آن برنامه کدهایی موقتی خواهد ساخت که برای ورود باید آنها را وارد کنید." lost_recovery_codes: با کدهای بازیابی میتوانید اگر تلفن خود را گم کردید به حساب خود دسترسی داشته باشید. اگر کدهای بازیابی خود را گم کردید، آنها را اینجا دوباره بسازید. کدهای بازیابی قبلی شما نامعتبر خواهند شد. manual_instructions: 'اگر نمیتوانید کدها را اسکن کنید و باید آنها را دستی وارد کنید، متن کد امنیتی اینجاست:' + recovery_codes: پشتیبانگیری از کدهای بازیابی recovery_codes_regenerated: کدهای بازیابی با موفقیت ساخته شدند recovery_instructions_html: اگر تلفن خود را گم کردید، میتوانید با یکی از کدهای بازیابی زیر کنترل حساب خود را به دست بگیرید. این کدها را در جای امنی نگه دارید، مثلاً آنها را چاپ کنید و کنار سایر مدارک مهم خود قرار دهید setup: راه اندازی diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 13514bfc3e..7fde60a2be 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -200,7 +200,7 @@ fr: confirmed: Confirmé expires_in: Expire dans last_delivery: Dernière livraison - title: PubSubHubbub + title: WebSub topic: Sujet title: Administration admin_mailer: diff --git a/config/locales/he.yml b/config/locales/he.yml index dc6caf87ac..7772e6a76e 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -155,7 +155,7 @@ he: confirmed: מאושר expires_in: פג תוקף ב- last_delivery: משלוח אחרון - title: PubSubHubbub + title: WebSub topic: נושא title: ניהול application_mailer: diff --git a/config/locales/id.yml b/config/locales/id.yml index e0e82d378e..0d5937cfbb 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -146,7 +146,7 @@ id: confirmed: Dikonfirmasi expires_in: Kadaluarsa dalam last_delivery: Terakhir dikirim - title: PubSubHubbub + title: WebSub topic: Topik title: Administrasi application_mailer: diff --git a/config/locales/io.yml b/config/locales/io.yml index 4f7323a6f2..c9abd57110 100644 --- a/config/locales/io.yml +++ b/config/locales/io.yml @@ -144,7 +144,7 @@ io: confirmed: Confirmed expires_in: Expires in last_delivery: Last delivery - title: PubSubHubbub + title: WebSub topic: Topic title: Administration application_mailer: diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 6763ed301a..fa8f4566c9 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -5,9 +5,14 @@ ja: about_this: 詳細情報 closed_registrations: 現在このインスタンスでの新規登録は受け付けていません。しかし、他のインスタンスにアカウントを作成しても全く同じネットワークに参加することができます。 contact: 連絡先 + contact_missing: 未設定 + contact_unavailable: N/A description_headline: "%{domain} とは?" domain_count_after: 個のインスタンス domain_count_before: 接続中 + extended_description_html: | +詳細説明が設定されていません。
features: humane_approach_body: 他の SNS の失敗から学び、Mastodon はソーシャルメディアが誤った使い方をされることの無いように倫理的な設計を目指しています。 humane_approach_title: より思いやりのある設計 @@ -104,12 +109,14 @@ ja: hint: ドメインブロックはデータベース中のアカウント項目の作成を妨げませんが、遡って自動的に指定されたモデレーションをそれらのアカウントに適用します。 severity: desc_html: "サイレンスはアカウントのトゥートをフォローしていない人から隠します。停止はそのアカウントのコンテンツ、メディア、プロフィールデータをすべて削除します。" + noop: なし silence: サイレンス suspend: 停止 title: 新規ドメインブロック reject_media: メディアファイルを拒否 reject_media_hint: ローカルに保存されたメディアファイルを削除し、今後のダウンロードを拒否します。停止とは無関係です。 severities: + noop: なし silence: サイレンス suspend: 停止 severity: 深刻度 @@ -200,7 +207,7 @@ ja: confirmed: 確認済み expires_in: 期限 last_delivery: 最終配送 - title: PubSubHubbub + title: WebSub topic: トピック title: 管理 admin_mailer: @@ -341,6 +348,8 @@ ja: title: あなたのトゥートが %{name} さんにお気に入り登録されました follow: title: "%{name} さんにフォローされました" + group: + title: "%{count} 件の通知" mention: action_boost: ブースト action_expand: もっと見る @@ -392,6 +401,8 @@ ja: windows: Windows windows_mobile: Windows Mobile windows_phone: Windows Phone + revoke: 削除 + revoke_success: セッションを削除しました title: セッション settings: authorized_apps: 認証済みアプリ diff --git a/config/locales/ko.yml b/config/locales/ko.yml index a081de38da..aae0e62e72 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -161,7 +161,7 @@ ko: confirmed: 확인됨 expires_in: 기한 last_delivery: 최종 발송 - title: PubSubHubbub + title: WebSub topic: 토픽 title: 관리 admin_mailer: diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 58282259d1..e65658d8b6 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -206,7 +206,7 @@ nl: confirmed: Bevestigd expires_in: Verloopt over last_delivery: Laatste bezorging - title: PubSubHubbub + title: WebSub topic: Account title: Beheer admin_mailer: diff --git a/config/locales/no.yml b/config/locales/no.yml index 122ad56758..b2e5773de0 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -148,7 +148,7 @@ confirmed: Bekreftet expires_in: Utløper om last_delivery: Siste levering - title: PubSubHubbub + title: WebSub topic: Emne title: Administrasjon application_mailer: diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 6d9996dbcc..d9a5892876 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -1,19 +1,38 @@ --- oc: about: - about_mastodon_html: Mastodon es un malhum social liure e open-source. Una alternativa descentralizada a las plat-formas comercialas, aquò evita qu’una sola companhiá monopolize vòstra comunicacion. Causissètz un servidor que vos fisatz, quina que siasque vòstra causida, podètz interagir amb tot lo mond. Qual que siasque pòt aver son instància Mastodon e participar al malhum social sens cap de problèmas. + about_mastodon_html: Mastodon es un malhum social bastit amb de protocòls liures e gratuits. Es descentralizat coma los corrièls. about_this: A prepaus d’aquesta instància closed_registrations: Las inscripcions son clavadas pel moment sus aquesta instància. contact: Contacte + contact_missing: Pas parametrat + contact_unavailable: Pas disponible description_headline: Qué es %{domain} ? domain_count_after: autras instàncias domain_count_before: Connectat a - other_instances: Autras instàncias + extended_description_html: | +La descripcion longa es pas estada causida pel moment.
+ features: + humane_approach_body: Amb l’experiéncia dels fracasses d’autres malhums, Mastodon ten per objectiu de lutar contra los abuses dels malhums socials en far de causidas eticas. + humane_approach_title: Un biais mai uman + not_a_product_body: Mastodon es pas un malhum comercial. Pas cap de reclama, d’utilizacion de vòstras donadas o d’òrt daurat clavat. I a pas cap d’autoritat centrala. + not_a_product_title: Sètz una persona, non pas un produit + real_conversation_body: Amb 500 caractèrs a vòstra disposicion e un nivèl de confidencialitat per cada publicacion, podètz vos exprimir coma volètz. + real_conversation_title: Fach per de conversacions vertadièras + within_reach_body: Multiplas aplicacion per iOS, Android, e autras plataformas mercés a un entorn API de bon utilizar, vos permet de gardar lo contacte pertot. + within_reach_title: Totjorn al costat + find_another_instance: Trobar mai instàncias + generic_description: "%{domain} es un dels servidors del malhum" + hosted_on: Mastodon albergat sus %{domain} + learn_more: Ne saber mai + other_instances: Lista d’instàncias source_code: Còdi font status_count_after: estatuts status_count_before: qu’an escrich user_count_after: personas - user_count_before: Ostal de + user_count_before: Ostal de + what_is_mastodon: Qu’es Mastodon ? accounts: follow: Sègre followers: Seguidors @@ -23,6 +42,7 @@ oc: people_who_follow: Lo mond que sègon %{name} posts: Estatuts remote_follow: Sègre a distància + reserved_username: Aqueste nom d’utilizaire es reservat unfollow: Quitar de sègre admin: accounts: @@ -60,8 +80,10 @@ oc: profile_url: URL del perfil public: Public push_subscription_expires: Fin de l’abonament PuSH + redownload: Actualizar los avatars reset: Reïnicializar reset_password: Reïnicializar lo senhal + resubscribe: Se tornar abonar salmon_url: URL Salmon search: Cercar show: @@ -70,13 +92,14 @@ oc: targeted_reports: Rapòrts faches tocant aqueste compte silence: Silenci statuses: Estatuts + subscribe: S’abonar title: Comptes undo_silenced: Levar lo silenci undo_suspension: Levar la suspension username: Nom d’utilizaire web: Web domain_blocks: - add_new: Ajustar un nòu + add_new: N’ajustar un nòu created_msg: Domeni blocat es a èsser tractat destroyed_msg: Lo blocatge del domeni es estat levat domain: Domeni @@ -85,12 +108,14 @@ oc: hint: Lo blocatge empacharà pas la creacion de compte dins la basa de donadas, mai aplicarà la moderacion sus aquestes comptes. severity: desc_html: "Silenci farà venir invisibles los estatuts del compte al mond que son pas de seguidors. Suspendre levarà tot lo contengut del compte, los mèdias e las donadas de perfil." + noop: Cap silence: Silenci suspend: Suspendre title: Nòu blocatge domeni reject_media: Regetar los fichièrs mèdias reject_media_hint: Lèva los fichièrs gardats localament e regèta las demandas de telecargament dins lo futur. Servís pas a res per las suspensions severities: + noop: Cap silence: Silenci suspend: Suspendre severity: Severitat @@ -110,6 +135,7 @@ oc: domain_name: Domeni title: Instàncias conegudas reports: + action_taken_by: Accion menada per are_you_sure: Es segur ? comment: label: Comentari @@ -147,7 +173,7 @@ oc: desc_html: Autorizar lo monde a se marcar title: Inscripcions site_description: - desc_html: Afichada jos la forma de paragrafe sus la pagina d’acuèlh e utilizada coma balisa meta.<a>
e <em>
.
+ desc_html: Afichada jos la forma de paragraf sus la pagina d’acuèlh e utilizada coma balisa meta.<a>
e <em>
.
title: Descripcion del site
site_description_extended:
desc_html: Afichada sus la pagina d’informacion complementària del siteCollectem informacions sus vos quand vos marcatz sus nòstre site e juntem las donadas quand participatz a nòstre forum ne legissent, escrivent e notant lo contengut partejat aquí.
+Collectem informacions sus vos quand vos marcatz sus nòstre site e juntem las donadas quand participatz a nòstre forum en legissent, escrivent e notant lo contengut partejat aquí.
Pendent l’inscripcion podèm vos demandar vòstre nom e adreça de corrièl. Podètz çaquelà visitar nòstre site sens vos marcar. Verificarem vòstra adreça amb un messatge donant un ligam unic. Se clicatz sul ligam sauprem qu’avètz lo contraròtle de l’adreça.
@@ -472,13 +528,13 @@ oc:Òc-ben. Los cookies son de pichons fichièrs qu’un site o sos forneires de servicis plaçan dins lo disc dur de vòstre ordenador via lo navigator Web (Se los acceptatz). Aqueles cookies permeton al site de reconéisser vòstre navigator e se tenètz un compte enregistrat de l’associar a vòstre compte.
-Empleguem de cookies per comprendre e enregistrar vòstras preferéncias per vòstras visitas venentas, per recampar de donadas sul trafic del site e las interaccions per fin que posquem ofrir una melhora experiéncia del site e de las aisinas pel futur. Pòt arribar que contractèssem amb de forneires de servicis tèrces per nos ajudar a comprendre melhor nòstres visitors. Aqueles forneires an pas lo drech que d’utilizar las donadas collectadas per nos ajudar a menar e melhorar nòstre afar.
+Empleguem de cookies per comprendre e enregistrar vòstras preferéncias per vòstras visitas venentas, per recampar de donadas sul trafic del site e las interaccions per dire que posquem ofrir una melhora experiéncia del site e de las aisinas pel futur. Pòt arribar que contractèssem amb de forneires de servicis tèrces per nos ajudar a comprendre melhor nòstres visitors. Aqueles forneires an pas lo drech que d’utilizar las donadas collectadas per nos ajudar a menar e melhorar nòstre afar.
-Vendèm pas, comercem o qualque transferiment que siasque a de partits exteriors vòstras informacions personalas identificablas. Aquò inclutz pas los tèrces partits de confisança que nos assiston a menar nòstre site, menar nòstre afar o vos servir, baste que son d’acòrd per gardar aquelas informacions confidencialas. Pòt tanben arribar que liberèssem vòstras informacions quand cresèm qu’es apropriat d’o far per se sometre a la lei, per refortir nòstras politicas, o per protegir los dreches, proprietats o seguritat de qualqu’un o de nosautres. Pasmens es possible que mandèssem d’informacions non-personalas e identificablas de nòstres visitors a d’autres partits per d’utilizacion en marketing, publicitat o un emplec mai.
+Vendèm pas, comercem o qualque transferiment que siasque a de tèrces vòstras informacions personalas identificablas. Aquò inclutz pas los tèrces partits de confisança que nos assiston a menar nòstre site, menar nòstre afar o vos servir, baste que son d’acòrd per gardar aquelas informacions confidencialas. Pòt tanben arribar que liberèssem vòstras informacions quand cresèm qu’es apropriat d’o far per se sometre a la lei, per refortir nòstras politicas, o per protegir los dreches, proprietats o seguritat de qualqu’un o de nosautres. Pasmens es possible que mandèssem d’informacions non-personalas e identificablas de nòstres visitors a d’autres partits per d’utilizacion en marketing, publicitat o un emplec mai.
-Pòt arribar, a nòstra discrecion, qu’incluguèssem o ofriguèssem de produches o servicis de tèrces partits sus nòstre site. Aqueles sites tèrces an de politicas de confidencialitats separadas e independentas. En consequéncia avèm pas cap de responsabilitat pel contengut e las activitats d’aqueles sites ligats. Pasmens cerquem de protegir l’integritat de nòstre site e aculhèm los comentaris tocant aqueles sites.
@@ -515,6 +571,7 @@ oc: instructions_html: "Escanatz aqueste còdi QR amb Google Authenticator o una aplicacion similària sus vòstre mobil. A partir d’ara, aquesta aplicacion generarà un geton que vos caldrà picar per vos connectar." lost_recovery_codes: Los còdi de recuperacion vos permeton d’accedir a vòstre compte se perdètz vòstre mobil. S’avètz perdut vòstres còdis de recuperacion los podètz tornar generar aquí. Los ancians còdis seràn pas mai valides. manual_instructions: 'Se podètz pas numerizar lo còdi QR e que vos cal picar lo còdi a la man, vaquí lo còdi en clar :' + recovery_codes: Salvar los còdis de recuperacion recovery_codes_regenerated: Los còdis de recuperacion son ben estats tornats generar recovery_instructions_html: Se vos arriba de perdre vòstre mobil, podètz utilizar un dels còdis de recuperacion cai-jos per poder tornar accedir a vòstre compte. Gardatz los còdis en seguretat, per exemple, imprimissètz los e gardatz los amb vòstres documents importants. setup: Paramètres diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 02c97e955d..a30092d505 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -205,7 +205,7 @@ pl: confirmed: Potwierdzono expires_in: Wygasa last_delivery: Ostatnio doręczono - title: PubSubHubbub + title: WebSub topic: Temat title: Administracja admin_mailer: @@ -350,6 +350,8 @@ pl: title: "%{name} dodał Twój status do ulubionych" follow: title: "%{name} zaczął Cię śledzić" + group: + title: "%{count} powiadomień" mention: action_boost: Podbij action_expand: Pokaż więcej diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 9bd1b0d282..68b1c549ce 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -147,7 +147,7 @@ pt-BR: confirmed: Confirmado expires_in: Expira em last_delivery: Última entrega - title: PubSubHubbub + title: WebSub topic: Tópico title: Administração application_mailer: diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 6bf592d1cb..f6dd322005 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -142,7 +142,7 @@ pt: confirmed: Confirmado expires_in: Expira em last_delivery: Última entrega - title: PubSubHubbub + title: WebSub topic: Tópico title: Administração application_mailer: diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 141017f40f..348f670b57 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -138,7 +138,7 @@ ru: confirmed: Подтверждено expires_in: Истекает через last_delivery: Последняя доставка - title: PubSubHubbub + title: WebSub topic: Тема title: Администрирование application_mailer: @@ -267,6 +267,21 @@ ru: next: След prev: Пред truncate: "…" + push_notifications: + favourite: + title: "Ваш статус понравился %{name}" + follow: + title: "%{name} теперь подписан(а) на Вас" + mention: + action_boost: Продвинуть + action_expand: Развернуть + action_favourite: Нравится + title: "Вас упомянул(а) %{name}" + reblog: + title: "%{name} продвинул(а) Ваш статус" + subscribed: + body: Теперь Вы можете получать push-уведомления. + title: Подписка зарегистрирована! remote_follow: acct: Введите username@domain, откуда Вы хотите подписаться missing_resource: Поиск требуемого перенаправления URL для Вашего аккаунта завершился неудачей @@ -335,6 +350,8 @@ ru: click_to_show: Показать reblogged: продвинул(а) sensitive_content: Чувствительный контент + terms: + title: "Условия обслуживания и политика конфиденциальности %{instance}" time: formats: default: "%b %d, %Y, %H:%M" diff --git a/config/locales/simple_form.fa.yml b/config/locales/simple_form.fa.yml index 3de1fe9719..71a9d6e1fc 100644 --- a/config/locales/simple_form.fa.yml +++ b/config/locales/simple_form.fa.yml @@ -12,6 +12,7 @@ fa: note: one: '1 حرف باقی مانده' other: '%{count} حرف باقی مانده' + setting_noindex: روی نمایهٔ عمومی و صفحهٔ نوشتههای شما تأثیر میگذارد imports: data: پروندهٔ CSV که از سرور ماستدون دیگری برونسپاری شده sessions: @@ -27,6 +28,7 @@ fa: data: دادهها display_name: نمایش به نام email: نشانی ایمیل + filtered_languages: زبانهای فیلترشده header: تصویر زمینه locale: زبان locked: خصوصیکردن حساب @@ -37,6 +39,11 @@ fa: setting_auto_play_gif: پخش خودکار تصویرهای متحرک setting_boost_modal: نمایش پیغام تأیید پیش از بازبوقیدن setting_default_privacy: حریم خصوصی نوشتهها + setting_default_sensitive: همیشه تصاویر را به عنوان حساس علامت بزن + setting_delete_modal: پیش از پاک کردن یک بوق پیغام تأیید نشان بده + setting_noindex: درخواست از موتورهای جستجو برای لغو فهرستسازی + setting_system_font_ui: بهکاربردن قلم پیشفرض سیستم + setting_unfollow_modal: نمایش پیغام تأیید پیش از لغو پیگیری دیگران severity: شدت type: نوع درونریزی username: نام کاربری (تنها حروف انگلیسی) diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml index d52d531099..351d1800c1 100644 --- a/config/locales/simple_form.nl.yml +++ b/config/locales/simple_form.nl.yml @@ -37,8 +37,8 @@ nl: type: Importtype username: gebruikersnaam interactions: - must_be_follower: Blokkeermeldingen van mensen die jou niet volgen - must_be_following: Blokkeermeldingen van mensen die jij niet volgt + must_be_follower: Blokkeer meldingen van mensen die jou niet volgen + must_be_following: Blokkeer meldingen van mensen die jij niet volgt notification_emails: digest: Verstuur periodiek e-mails met een samenvatting favourite: Verstuur een e-mail wanneer iemand jouw toot als favoriet markeert diff --git a/config/locales/simple_form.ru.yml b/config/locales/simple_form.ru.yml index c4e6ad8a86..3bdb7870f4 100644 --- a/config/locales/simple_form.ru.yml +++ b/config/locales/simple_form.ru.yml @@ -16,6 +16,7 @@ ru: many: Осталось %{count} символов one: Остался 1 символ other: Осталось %{count} символов + setting_noindex: Относится к Вашему публичному профилю и страницам статусов imports: data: Файл CSV, экспортированный с другого узла Mastodon sessions: @@ -42,7 +43,11 @@ ru: setting_auto_play_gif: Автоматически проигрывать анимированные GIF setting_boost_modal: Показывать диалог подтверждения перед продвижением setting_default_privacy: Видимость постов + setting_default_sensitive: Всегда отмечать медиаконтент как чувствительный setting_delete_modal: Показывать диалог подтверждения перед удалением + setting_noindex: Отказаться от индексации в поисковых машинах + setting_system_font_ui: Использовать шрифт системы по умолчанию + setting_unfollow_modal: Показывать диалог подтверждения перед тем, как отписаться от аккаунта severity: Строгость type: Тип импорта username: Имя пользователя diff --git a/config/locales/th.yml b/config/locales/th.yml index 89782209e7..801f4886fa 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -148,7 +148,7 @@ th: confirmed: ยืนยัน expires_in: หมดอายุภายใน last_delivery: จัดส่งครั้งล่าสุด - title: PubSubHubbub + title: WebSub topic: ชื่อเรื่อง title: แอดมิน application_mailer: diff --git a/config/locales/tr.yml b/config/locales/tr.yml index a1f2d2078a..ac378090c7 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -147,7 +147,7 @@ tr: confirmed: Onaylandı expires_in: Bitiş Tarihi last_delivery: Son gönderim - title: PubSubHubbub + title: WebSub topic: Konu title: Yönetim application_mailer: diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 3237ea1db7..22fff6961d 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -138,7 +138,7 @@ uk: confirmed: Підтверджено expires_in: Спливає через last_delivery: Остання доставка - title: PubSubHubbub + title: WebSub topic: Тема title: Адміністрування application_mailer: diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 0b02632945..5018b48b80 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -154,7 +154,7 @@ zh-CN: confirmed: 确定 expires_in: 期限 last_delivery: 数据最后送抵时间 - title: PubSubHubbub 订阅 + title: WebSub 订阅 topic: 所订阅资源 title: 管理 application_mailer: diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index e25edc8905..0ea3457c7e 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -118,7 +118,7 @@ zh-TW: confirmed: 已確認 expires_in: 期限 last_delivery: 最後遞送 - title: PubSubHubbub + title: WebSub topic: 主題 title: 管理介面 application_mailer: diff --git a/config/routes.rb b/config/routes.rb index 71729fee5e..c60a8b1313 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,6 +3,8 @@ require 'sidekiq/web' require 'sidekiq-scheduler/web' +Sidekiq::Web.set :session_secret, Rails.application.secrets[:secret_key_base] + Rails.application.routes.draw do mount LetterOpenerWeb::Engine, at: 'letter_opener' if Rails.env.development? diff --git a/config/settings.yml b/config/settings.yml index 38871c7729..acaab31667 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -17,9 +17,11 @@ defaults: &defaults closed_registrations_message: '' open_deletion: true timeline_preview: false + default_sensitive: false + unfollow_modal: false boost_modal: false - auto_play_gif: false delete_modal: true + auto_play_gif: false system_font_ui: false noindex: false notification_emails: diff --git a/config/webpack/production.js b/config/webpack/production.js index 4592db89e6..cd1dd91dc7 100644 --- a/config/webpack/production.js +++ b/config/webpack/production.js @@ -10,7 +10,11 @@ const { publicPath } = require('./configuration.js'); const path = require('path'); module.exports = merge(sharedConfig, { - output: { filename: '[name]-[chunkhash].js' }, + output: { + filename: '[name]-[chunkhash].js', + chunkFilename: '[name]-[chunkhash].js', + }, + devtool: 'source-map', // separate sourcemap file, suitable for production stats: 'normal', @@ -48,7 +52,7 @@ module.exports = merge(sharedConfig, { ServiceWorker: { entry: path.join(__dirname, '../../app/javascript/mastodon/service_worker/entry.js'), cacheName: 'mastodon', - output: '../sw.js', + output: '../assets/sw.js', publicPath: '/sw.js', minify: true, }, diff --git a/config/webpack/shared.js b/config/webpack/shared.js index 425918d66f..be1b494217 100644 --- a/config/webpack/shared.js +++ b/config/webpack/shared.js @@ -33,7 +33,7 @@ module.exports = { output: { filename: '[name].js', - chunkFilename: '[name]-[chunkhash].js', + chunkFilename: '[name].js', path: output.path, publicPath: output.publicPath, }, diff --git a/db/migrate/20170720000000_add_index_favourites_on_account_id_and_id.rb b/db/migrate/20170720000000_add_index_favourites_on_account_id_and_id.rb new file mode 100644 index 0000000000..99903584c9 --- /dev/null +++ b/db/migrate/20170720000000_add_index_favourites_on_account_id_and_id.rb @@ -0,0 +1,6 @@ +class AddIndexFavouritesOnAccountIdAndId < ActiveRecord::Migration[5.1] + def change + # Used to query favourites of an account ordered by id. + add_index :favourites, [:account_id, :id] + end +end diff --git a/db/schema.rb b/db/schema.rb index cf7b0722fc..2501e451d0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170718211102) do +ActiveRecord::Schema.define(version: 20170720000000) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -103,6 +103,7 @@ ActiveRecord::Schema.define(version: 20170718211102) do t.integer "status_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["account_id", "id"], name: "index_favourites_on_account_id_and_id" t.index ["account_id", "status_id"], name: "index_favourites_on_account_id_and_status_id", unique: true t.index ["status_id"], name: "index_favourites_on_status_id" end diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index 07969aff4b..aeb5492dc6 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -21,7 +21,7 @@ module Mastodon end def flags - 'rc1' + '' end def to_a diff --git a/package.json b/package.json index 132d7017d5..5fdd491ee7 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,9 @@ "build:production": "cross-env RAILS_ENV=production ./bin/webpack", "manage:translations": "node ./config/webpack/translationRunner.js", "start": "node ./streaming/index.js", - "storybook": "cross-env NODE_ENV=test start-storybook -s ./public -p 9001 -c storybook", "test": "npm run test:lint && npm run test:mocha", - "test:lint": "eslint -c .eslintrc.yml --ext=js app/javascript/ config/webpack/ spec/javascript/ storybook/ streaming/", - "test:mocha": "cross-env NODE_ENV=test mocha --require ./spec/javascript/setup.js --compilers js:babel-register ./spec/javascript/components/*.test.js", + "test:lint": "eslint -c .eslintrc.yml --ext=js app/javascript/ config/webpack/ spec/javascript/ streaming/", + "test:mocha": "cross-env NODE_ENV=test mocha --require ./spec/javascript/setup.js --compilers js:babel-register ./spec/javascript/components/**/*.test.js", "postinstall": "npm rebuild node-sass" }, "repository": { @@ -57,7 +56,7 @@ "glob": "^7.1.1", "http-link-header": "^0.8.0", "immutable": "^3.8.1", - "intersection-observer": "^0.3.2", + "intersection-observer": "^0.4.0", "intl": "^1.2.5", "intl-relativeformat": "^2.0.0", "is-nan": "^1.2.1", @@ -113,15 +112,13 @@ "tiny-queue": "^0.2.1", "uuid": "^3.1.0", "uws": "^8.14.0", - "webpack": "^3.0.0", - "webpack-bundle-analyzer": "^2.8.2", - "webpack-manifest-plugin": "^1.1.2", + "webpack": "^3.4.1", + "webpack-bundle-analyzer": "^2.8.3", + "webpack-manifest-plugin": "^1.2.1", "webpack-merge": "^4.1.0", "websocket.js": "^0.1.12" }, "devDependencies": { - "@storybook/addon-actions": "^3.1.8", - "@storybook/react": "^3.1.8", "babel-eslint": "^7.2.3", "chai": "^4.1.0", "chai-enzyme": "^0.8.0", @@ -134,7 +131,7 @@ "react-intl-translations-manager": "^5.0.0", "react-test-renderer": "^15.6.1", "sinon": "^2.3.7", - "webpack-dev-server": "^2.5.1", + "webpack-dev-server": "^2.6.1", "yargs": "^8.0.2" }, "optionalDependencies": { diff --git a/public/sw.js b/public/sw.js new file mode 120000 index 0000000000..1471a9e640 --- /dev/null +++ b/public/sw.js @@ -0,0 +1 @@ +assets/sw.js \ No newline at end of file diff --git a/public/web-push-icon_expand.png b/public/web-push-icon_expand.png new file mode 100644 index 0000000000..972c288864 Binary files /dev/null and b/public/web-push-icon_expand.png differ diff --git a/public/web-push-icon_favourite.png b/public/web-push-icon_favourite.png new file mode 100644 index 0000000000..ef36b8898c Binary files /dev/null and b/public/web-push-icon_favourite.png differ diff --git a/public/web-push-icon_reblog.png b/public/web-push-icon_reblog.png new file mode 100644 index 0000000000..0f555ed09f Binary files /dev/null and b/public/web-push-icon_reblog.png differ diff --git a/scalingo.json b/scalingo.json index 8df2caba16..426698b9cc 100644 --- a/scalingo.json +++ b/scalingo.json @@ -2,7 +2,7 @@ "name": "Mastodon", "description": "A GNU Social-compatible microblogging server", "repository": "https://github.com/tootsuite/mastodon", - "logo": "https://github.com/tootsuite/mastodon/raw/master/app/javascript/images/logo.svg", + "logo": "https://github.com/tootsuite.png", "env": { "LOCAL_DOMAIN": { "description": "The domain that your Mastodon instance will run on (this can be appname.scalingo.io or a custom domain)", diff --git a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb index 7bcf9fe0e9..3f655c7b23 100644 --- a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Accounts::CredentialsController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb b/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb index 171852c755..33982cb8f6 100644 --- a/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Accounts::FollowerAccountsController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } before do Fabricate(:follow, target_account: user.account) diff --git a/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb b/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb index a4cad9163e..e22f54a31d 100644 --- a/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Accounts::FollowingAccountsController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } before do Fabricate(:follow, account: user.account) diff --git a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb index e281afcb92..3a9607317c 100644 --- a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Accounts::RelationshipsController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/accounts/search_controller_spec.rb b/spec/controllers/api/v1/accounts/search_controller_spec.rb index 40c82437dd..42cc3f64de 100644 --- a/spec/controllers/api/v1/accounts/search_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/search_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::Accounts::SearchController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb index 55cb5bcc24..8b4fd6a5bc 100644 --- a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Accounts::StatusesController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/accounts_controller_spec.rb b/spec/controllers/api/v1/accounts_controller_spec.rb index 216a9cb3b6..c13509e7bb 100644 --- a/spec/controllers/api/v1/accounts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::AccountsController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow read') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/blocks_controller_spec.rb b/spec/controllers/api/v1/blocks_controller_spec.rb index 4fd968b27c..f25a7e8788 100644 --- a/spec/controllers/api/v1/blocks_controller_spec.rb +++ b/spec/controllers/api/v1/blocks_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::BlocksController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') } before do Fabricate(:block, account: user.account) diff --git a/spec/controllers/api/v1/domain_blocks_controller_spec.rb b/spec/controllers/api/v1/domain_blocks_controller_spec.rb index ff5c5f3302..3713931dc6 100644 --- a/spec/controllers/api/v1/domain_blocks_controller_spec.rb +++ b/spec/controllers/api/v1/domain_blocks_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::DomainBlocksController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') } before do user.account.block_domain!('example.com') diff --git a/spec/controllers/api/v1/favourites_controller_spec.rb b/spec/controllers/api/v1/favourites_controller_spec.rb index 062e91adcc..3de045377f 100644 --- a/spec/controllers/api/v1/favourites_controller_spec.rb +++ b/spec/controllers/api/v1/favourites_controller_spec.rb @@ -3,19 +3,77 @@ require 'rails_helper' RSpec.describe Api::V1::FavouritesController, type: :controller do render_views - let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } - - before do - Fabricate(:favourite, account: user.account) - allow(controller).to receive(:doorkeeper_token) { token } - end + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } describe 'GET #index' do - it 'returns http success' do - get :index, params: { limit: 1 } + context 'without token' do + it 'returns http unauthorized' do + get :index + expect(response).to have_http_status :unauthorized + end + end + + context 'with token' do + context 'without read scope' do + before do + allow(controller).to receive(:doorkeeper_token) do + Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: '') + end + end + + it 'returns http forbidden' do + get :index + expect(response).to have_http_status :forbidden + end + end + + context 'without valid resource owner' do + before do + token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') + user.destroy! + + allow(controller).to receive(:doorkeeper_token) { token } + end + + it 'returns http unprocessable entity' do + get :index + expect(response).to have_http_status :unprocessable_entity + end + end + + context 'with read scope and valid resource owner' do + before do + allow(controller).to receive(:doorkeeper_token) do + Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') + end + end + + it 'shows favourites owned by the user' do + favourite_by_user = Fabricate(:favourite, account: user.account) + favourite_by_others = Fabricate(:favourite) + + get :index + + expect(assigns(:statuses)).to match_array [favourite_by_user.status] + end + + it 'adds pagination headers if necessary' do + favourite = Fabricate(:favourite, account: user.account) + + get :index, params: { limit: 1 } + + expect(response.headers['Link'].find_link(['rel', 'next']).href).to eq "http://test.host/api/v1/favourites?limit=1&max_id=#{favourite.id}" + expect(response.headers['Link'].find_link(['rel', 'prev']).href).to eq "http://test.host/api/v1/favourites?limit=1&since_id=#{favourite.id}" + end + + it 'does not add pagination headers if not necessary' do + get :index - expect(response).to have_http_status(:success) + expect(response.headers['Link'].find_link(['rel', 'next'])).to eq nil + expect(response.headers['Link'].find_link(['rel', 'prev'])).to eq nil + end + end end end end diff --git a/spec/controllers/api/v1/follow_requests_controller_spec.rb b/spec/controllers/api/v1/follow_requests_controller_spec.rb index d455a0255d..51df006a22 100644 --- a/spec/controllers/api/v1/follow_requests_controller_spec.rb +++ b/spec/controllers/api/v1/follow_requests_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::FollowRequestsController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice', locked: true)) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') } let(:follower) { Fabricate(:account, username: 'bob') } before do diff --git a/spec/controllers/api/v1/follows_controller_spec.rb b/spec/controllers/api/v1/follows_controller_spec.rb index cc4958ab59..b5e1d16dd7 100644 --- a/spec/controllers/api/v1/follows_controller_spec.rb +++ b/spec/controllers/api/v1/follows_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::FollowsController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/instances_controller_spec.rb b/spec/controllers/api/v1/instances_controller_spec.rb index 544f3d28f8..eba233b053 100644 --- a/spec/controllers/api/v1/instances_controller_spec.rb +++ b/spec/controllers/api/v1/instances_controller_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Api::V1::InstancesController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/media_controller_spec.rb b/spec/controllers/api/v1/media_controller_spec.rb index 00dcac95dc..6bad3f05d8 100644 --- a/spec/controllers/api/v1/media_controller_spec.rb +++ b/spec/controllers/api/v1/media_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/mutes_controller_spec.rb b/spec/controllers/api/v1/mutes_controller_spec.rb index 85aad43841..3e6fa887b2 100644 --- a/spec/controllers/api/v1/mutes_controller_spec.rb +++ b/spec/controllers/api/v1/mutes_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::MutesController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') } before do Fabricate(:mute, account: user.account) diff --git a/spec/controllers/api/v1/notifications_controller_spec.rb b/spec/controllers/api/v1/notifications_controller_spec.rb index e06230913a..f493d0d38e 100644 --- a/spec/controllers/api/v1/notifications_controller_spec.rb +++ b/spec/controllers/api/v1/notifications_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } let(:other) { Fabricate(:user, account: Fabricate(:account, username: 'bob')) } before do diff --git a/spec/controllers/api/v1/reports_controller_spec.rb b/spec/controllers/api/v1/reports_controller_spec.rb index 471ea4e0bc..1eb5a43534 100644 --- a/spec/controllers/api/v1/reports_controller_spec.rb +++ b/spec/controllers/api/v1/reports_controller_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Api::V1::ReportsController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read write') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/search_controller_spec.rb b/spec/controllers/api/v1/search_controller_spec.rb index 4d22ddc98f..ff0c254b1f 100644 --- a/spec/controllers/api/v1/search_controller_spec.rb +++ b/spec/controllers/api/v1/search_controller_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Api::V1::SearchController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb b/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb index 1acb990a00..556731d578 100644 --- a/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb @@ -5,7 +5,7 @@ RSpec.describe Api::V1::Statuses::FavouritedByAccountsController, type: :control let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { double acceptable?: true, resource_owner_id: user.id, application: app } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app) } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/statuses/favourites_controller_spec.rb b/spec/controllers/api/v1/statuses/favourites_controller_spec.rb index eb77072d25..2a029230d7 100644 --- a/spec/controllers/api/v1/statuses/favourites_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/favourites_controller_spec.rb @@ -7,7 +7,7 @@ describe Api::V1::Statuses::FavouritesController do let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { double acceptable?: true, resource_owner_id: user.id, application: app } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write', application: app) } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/statuses/mutes_controller_spec.rb b/spec/controllers/api/v1/statuses/mutes_controller_spec.rb index 1f8c29e3d8..54c594e92c 100644 --- a/spec/controllers/api/v1/statuses/mutes_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/mutes_controller_spec.rb @@ -7,7 +7,7 @@ describe Api::V1::Statuses::MutesController do let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { double acceptable?: true, resource_owner_id: user.id, application: app } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write', application: app) } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb b/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb index c5624023f1..ba022a96e0 100644 --- a/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb @@ -5,7 +5,7 @@ RSpec.describe Api::V1::Statuses::RebloggedByAccountsController, type: :controll let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { double acceptable?: true, resource_owner_id: user.id, application: app } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app) } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb index 36c323736b..d6d36c1b2f 100644 --- a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb @@ -7,7 +7,7 @@ describe Api::V1::Statuses::ReblogsController do let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { double acceptable?: true, resource_owner_id: user.id, application: app } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write', application: app) } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/statuses_controller_spec.rb b/spec/controllers/api/v1/statuses_controller_spec.rb index 3d65180ab3..a36265395b 100644 --- a/spec/controllers/api/v1/statuses_controller_spec.rb +++ b/spec/controllers/api/v1/statuses_controller_spec.rb @@ -5,7 +5,7 @@ RSpec.describe Api::V1::StatusesController, type: :controller do let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { double acceptable?: true, resource_owner_id: user.id, application: app } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'write') } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/timelines/home_controller_spec.rb b/spec/controllers/api/v1/timelines/home_controller_spec.rb index faa6c60ce2..4d45235209 100644 --- a/spec/controllers/api/v1/timelines/home_controller_spec.rb +++ b/spec/controllers/api/v1/timelines/home_controller_spec.rb @@ -12,7 +12,7 @@ describe Api::V1::Timelines::HomeController do end context 'with a user context' do - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } describe 'GET #show' do before do @@ -30,7 +30,7 @@ describe Api::V1::Timelines::HomeController do end context 'without a user context' do - let(:token) { double acceptable?: true, resource_owner_id: nil } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: 'read') } describe 'GET #show' do it 'returns http unprocessable entity' do diff --git a/spec/controllers/api/v1/timelines/public_controller_spec.rb b/spec/controllers/api/v1/timelines/public_controller_spec.rb index 353ab9bc2d..3acf2e2678 100644 --- a/spec/controllers/api/v1/timelines/public_controller_spec.rb +++ b/spec/controllers/api/v1/timelines/public_controller_spec.rb @@ -12,7 +12,7 @@ describe Api::V1::Timelines::PublicController do end context 'with a user context' do - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) } describe 'GET #show' do before do @@ -42,7 +42,7 @@ describe Api::V1::Timelines::PublicController do end context 'without a user context' do - let(:token) { double acceptable?: true, resource_owner_id: nil } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil) } describe 'GET #show' do it 'returns http success' do diff --git a/spec/controllers/api/v1/timelines/tag_controller_spec.rb b/spec/controllers/api/v1/timelines/tag_controller_spec.rb index f743f0cde1..74de1e81f2 100644 --- a/spec/controllers/api/v1/timelines/tag_controller_spec.rb +++ b/spec/controllers/api/v1/timelines/tag_controller_spec.rb @@ -12,7 +12,7 @@ describe Api::V1::Timelines::TagController do end context 'with a user context' do - let(:token) { double acceptable?: true, resource_owner_id: user.id } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) } describe 'GET #show' do before do @@ -28,7 +28,7 @@ describe Api::V1::Timelines::TagController do end context 'without a user context' do - let(:token) { double acceptable?: true, resource_owner_id: nil } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil) } describe 'GET #show' do it 'returns http success' do diff --git a/spec/fabricators/access_token_fabricator.rb b/spec/fabricators/access_token_fabricator.rb new file mode 100644 index 0000000000..1856a8eb3b --- /dev/null +++ b/spec/fabricators/access_token_fabricator.rb @@ -0,0 +1,2 @@ +Fabricator :access_token, from: 'Doorkeeper::AccessToken' do +end diff --git a/spec/fabricators/accessible_access_token_fabricator.rb b/spec/fabricators/accessible_access_token_fabricator.rb new file mode 100644 index 0000000000..4b7e99b207 --- /dev/null +++ b/spec/fabricators/accessible_access_token_fabricator.rb @@ -0,0 +1,4 @@ +Fabricator :accessible_access_token, from: :access_token do + expires_in { nil } + revoked_at { nil } +end diff --git a/spec/helpers/emoji_helper_spec.rb b/spec/helpers/emoji_helper_spec.rb index 1eedfb7194..6edf7672f7 100644 --- a/spec/helpers/emoji_helper_spec.rb +++ b/spec/helpers/emoji_helper_spec.rb @@ -7,6 +7,11 @@ RSpec.describe EmojiHelper, type: :helper do expect(emojify(text)).to eq '📖 Book' end + it 'converts composite emoji shortcodes to unicode' do + text = ':couple_ww:' + expect(emojify(text)).to eq '👩❤👩' + end + it 'does not convert shortcodes that are part of a string into unicode' do text = ':see_no_evil::hear_no_evil::speak_no_evil:' expect(emojify(text)).to eq text diff --git a/spec/helpers/instance_helper_spec.rb b/spec/helpers/instance_helper_spec.rb index c3d28544f2..bc5950d91c 100644 --- a/spec/helpers/instance_helper_spec.rb +++ b/spec/helpers/instance_helper_spec.rb @@ -19,7 +19,7 @@ describe InstanceHelper do it 'returns empty string when Setting.site_title is nil' do Setting.site_title = nil - expect(helper.site_title).to eq '' + expect(helper.site_title).to eq 'cb6e6126.ngrok.io' end end diff --git a/spec/javascript/components/dropdown_menu.test.js b/spec/javascript/components/dropdown_menu.test.js index 54cdcabf06..a5af730efe 100644 --- a/spec/javascript/components/dropdown_menu.test.js +++ b/spec/javascript/components/dropdown_menu.test.js @@ -5,16 +5,24 @@ import React from 'react'; import DropdownMenu from '../../../app/javascript/mastodon/components/dropdown_menu'; import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown'; +const isTrue = () => true; + describe('