From bf1bde5d6a8306284a0cce89eb8f492b8c9b7a67 Mon Sep 17 00:00:00 2001 From: Dachi Natsvlishvili Date: Fri, 17 Aug 2018 20:00:01 +0400 Subject: Add Georgian language translation (#8250) * Add Georgian language translation * i18n-tasks normalize --- config/application.rb | 1 + config/locales/activerecord.ka.yml | 13 + config/locales/devise.ka.yml | 82 ++++ config/locales/doorkeeper.ka.yml | 142 ++++++ config/locales/ka.yml | 893 +++++++++++++++++++++++++++++++++++++ config/locales/simple_form.ka.yml | 99 ++++ 6 files changed, 1230 insertions(+) create mode 100644 config/locales/activerecord.ka.yml create mode 100644 config/locales/devise.ka.yml create mode 100644 config/locales/doorkeeper.ka.yml create mode 100644 config/locales/ka.yml create mode 100644 config/locales/simple_form.ka.yml (limited to 'config') diff --git a/config/application.rb b/config/application.rb index df64f0256..ea4949bf2 100644 --- a/config/application.rb +++ b/config/application.rb @@ -60,6 +60,7 @@ module Mastodon :io, :it, :ja, + :ka, :ko, :nl, :no, diff --git a/config/locales/activerecord.ka.yml b/config/locales/activerecord.ka.yml new file mode 100644 index 000000000..cdd4f9c4c --- /dev/null +++ b/config/locales/activerecord.ka.yml @@ -0,0 +1,13 @@ +--- +ka: + activerecord: + errors: + models: + account: + attributes: + username: + invalid: მხოლოდ ასოები, ციფრები და "ქვედა-ტირე" + status: + attributes: + reblog: + taken: სტატუსის უკვე არსებობს diff --git a/config/locales/devise.ka.yml b/config/locales/devise.ka.yml new file mode 100644 index 000000000..3267eb22e --- /dev/null +++ b/config/locales/devise.ka.yml @@ -0,0 +1,82 @@ +--- +ka: + devise: + confirmations: + confirmed: თქვენი ელ-ფოსტის მისამართი წარმატებით დამოწმდა. + send_instructions: თქვენ მიიღებთ ელ-ფოსტას ინსტრუქციებით თუ როგორც დაამოწმოთ თქვენი ელ-ფოსტის მისამართი რამდენიმე წუთში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს. + send_paranoid_instructions: თუ თქვენი ელ-ფოსტა არსებობს ჩვენს მონაცემთა ბაზაში, თქვენ მიიღებთ ელ-ფოსტას ინსტრუქციებით თუ როგორც დაამოწმოთ თქვენი ელ-ფოსტის მისამართი რამდენიმე წუთში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს. + failure: + already_authenticated: უკვე შესული ხართ. + inactive: თქვენი ანგარიში ჯერ არაა აქტივირებული. + invalid: არასწორი %{authentication_keys} ან პაროლი. + last_attempt: თქვენი ანგარიშის ჩაკეტვამდე დაგრჩათ კიდევ ერთი მცდელობა. + locked: თქვენი ანგარიში ჩაიკეტა. + not_found_in_database: არასწორი %{authentication_keys} ან პაროლი. + timeout: თქვენს სესიას გაუვიდა ვადა. გთხოვთ შედით ახლიდან რომ გააგრძელოთ. + unauthenticated: გაგრძელებამდე საჭიროა შეხვიდეთ ან დარეგისტრირდეთ. + unconfirmed: გაგრძელებამდე საჭიროა დაამოწმოთ თქვენი ელ-ფოსტა. + mailer: + confirmation_instructions: + action: დაამოწმეთ ელ-ფოსტის მისამართი + explanation: თქვენ ამ ელ-ფოსტის მისამართი ანგარიში შექმენით %{host}-ზე. დარჩა ერთი დაწკაპუნება მის აქტივაციამდე. თუ ეს თქვენ არ იყავით, გთხოვთ არ მიაქციოთ ყურადღება ამ წერილს. + extra_html: გთხოვთ ასევე გაეცნოთ ინსტანციის წესებს და ჩვენს კონფინდენციალურობის პოლიტიკას. + subject: 'მასტოდონი: დამოწმების ინსტრუქციები %{instance}-თვის' + title: ელ-ფოსტის მისამართის დამოწმება + email_changed: + explanation: 'თქვენი ანგარიშის ელ-ფოსტის მისამართი იცვლება შემდეგზე:' + extra: თუ თქვენ არ შეგიცვლიათ თქვენი ელ-ფოსტის მისამართი, როგორც ჩანს სხვამ ხელთ იგდო თქვენი ანგარიში. გთოხვთ შეცვალოთ თქვენი პაროლი რაც შეიძლება მალე, ან დაუკავშირდეთ ინსტანციის ადმინისტრატორს თუ თქვენი ანგარიში ჩაიკეტა. + subject: 'მასტოდონი: ელ-ფოსტა შეიცვალა' + title: ახალი ელ-ფოსტის მისამართი + password_change: + explanation: თქვენი ანგარიშის პაროლი შეიცვალა. + extra: თუ თქვენ არ შეგიცვლიათ პაროლი, როგორც ჩანს სხვამ ხელთ იგდო თქვენი ანგარიში. გთოხვთ შეცვალოთ თქვენი პაროლი რაც შეიძლება მალე, ან დაუკავშირდეთ ინსტანციის ადმინისტრატორს თუ თქვენი ანგარიში ჩაიკეტა. + subject: 'მასტოდონი: პაროლი შეიცვალა' + title: პაროლი შეიცვალა + reconfirmation_instructions: + explanation: დაამოწმეთ ახალი ელ-ფოსტის მისამართი ცვლილებისთვის. + extra: თუ თქვენ არ გამოიწვიეთ ეს ცვლილება, გთხოვთ არ მიაქციოთ ყურადღება ამ წერილს. მასტოდონის ელ-ფოსტის მისამართი არ შეიცვლება სანამ არ გადახვალთ ზემოთ მოცემულ ბმულზე. + subject: 'მასტოდონი: დაამოწმეთ ელ-ფოსტის მისამართი %{instance}-თვის' + title: დაამოწმეთ ელ-ფოსტის მისამართი + reset_password_instructions: + action: შეცვალეთ პაროლი + explanation: თქვენ მოითხოვეთ ახალი პაროლი თქვენი ანგარიშისთვის. + extra: თუ ეს თქვენ არ მოგითხოვიათ, გთხოვთ არ მიაქციოთ ყურადღება ამ წერილს. თქვენი პაროლი არ შეიცვლება, სანამ არ გადახვალთ ზემოთ მოცემულ ბმულზე. + subject: 'მასტოდონი: პაროლის განახლების ინსტრუქცეიბი' + title: პაროლის განახლება + unlock_instructions: + subject: 'მასტოდონი: ჩაკეტვის მოხსნის ინსტრუქციები' + omniauth_callbacks: + failure: 'ვერ მოხდა აუტენტიფიკაცია %{kind}-თან. მიზეზი: "%{reason}".' + success: წარმატებით შედგა აუტენტიფიკაცია %{kind} ანგარიშთან. + passwords: + no_token: ამ გვერდზე წვდომა ვერ გექნებათ თუ არ მოდიხართ პაროლის აღდგენის ელ-ფოსტის წერილიდან. თუ მოდიხართ პაროლის აღგენის წერილიდან, დაამოწმეთ რომ გადადიხართ სრულ ურლ-ზე. + send_instructions: თუ თქვენი ელ-ფოსტა არსებობს ჩვენს მონაცემთა ბაზაში, თქვენ მიიღებთ ელ-ფოსტაზე წერილს პაროლის განახლების ბმულით, რამდენიმე წუთში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს. + send_paranoid_instructions: თუ თქვენი ელ-ფოსტა არსებობს ჩვენს მონაცემთა ბაზაში, თქვენ მიიღებთ ელ-ფოსტაზე წერილს პაროლის განახლების ბმულით, რამდენიმე წუთში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს. + updated: თქვენი პაროლი წარმატებით შეიცვალა. ახლა შესული ხართ. + updated_not_active: თქვენი პაროლი წარმატებით შეიცვალა. + registrations: + destroyed: ნახვამდის! თქვენი ანგარიში წარმატებით გაუქმდა. იმედი გვაქვს ისევ შევხვდებით. + signed_up: გამარჯობა! თქვენ წარმატებით დარეგისტრირდით. + signed_up_but_inactive: თქვენ წარმატებით დარეგისტრირდით. თუმცა, ავტორიზაცია ვერ შედგა, თქვენი ანგარიში ჯერ არაა გააქტიურებული. + signed_up_but_locked: თქვენ წარმატებით დარეგისტრირდით. თუმცა, აცტორიზაცია ვერ შედგა, თქვენი ანგარიში ჩაკეტილია. + signed_up_but_unconfirmed: წერილი დამოწმების ბმულით თქვენს ელ-ფოსტაზე გამოგზავნილია. გთხოვთ გაჰყევით ბმულს, რათა გაააქტიუროთ ანგარიში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს. + update_needs_confirmation: თქვენი ანგარიში წარმატებით განახლდა, მაგრამ გვესაჭიროება თქვენი ელ-ფოსტის მისამართის დამოწმება. შეამოწმეთ ელ-ფოსტა და დასამოწმებლად გადადით მიღებულ ბმულზე. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს. + updated: თქვენი ანგარიში წარმატებით განახლდა. + sessions: + already_signed_out: წარმატებით გახვედით. + signed_in: წარმატებით შეხვედით. + signed_out: წარმატებით გახვედით. + unlocks: + send_instructions: წერილს, ინსტრუქციებით თუ როგორ მოხსნათ ჩაკეტვა თქვენს ანგარიშს, მიიღებთ რამდენიმე წუთში. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს. + send_paranoid_instructions: თუ თქვენი ელ-ფოსტა არსებობს ჩვენს მონაცემთა ბაზაში, თქვენ მიიღებთ ელ-ფოსტაზე წერილს ჩაკეტვის მოხნის ინსტრუქციებით. გთხოვთ შეხედოთ თქვენი სპამის ფოლდერს თუ არ მიიღებთ ამ წერილს. + unlocked: თქვენს ანგარიშს ჩაკეტვა წარმატებით მოეხსნა. გაგრძელებისთვის, გთხოვთ გაიაროთ ავტორიზაცია. + errors: + messages: + already_confirmed: უკვე დამოწმდა, გთხოვთ სცადოთ ავტორიზაციის გავლა + confirmation_period_expired: საჭიროებს დამოწმებას პერიოდში %{period}, გთხოვთ მოითხოვოთ ახლიდან + expired: გაუვიდა ვადა, გთხოვთ მოითხოვოთ ახალი + not_found: ვერ იქნა ნაპოვნი + not_locked: არ ჩაკეტილა + not_saved: + one: "%{resource} ვერ დამახსოვრდა ერთი შეცდომის გამო:" + other: "%{resource} ვერ დამახსოვრდა %{count} შეცდომის გამო:" diff --git a/config/locales/doorkeeper.ka.yml b/config/locales/doorkeeper.ka.yml new file mode 100644 index 000000000..e462e66f1 --- /dev/null +++ b/config/locales/doorkeeper.ka.yml @@ -0,0 +1,142 @@ +--- +ka: + activerecord: + attributes: + doorkeeper/application: + name: აპლიკაციის სახელი + redirect_uri: გადამისამართების ური + scopes: ფარგლები + website: აპლიკაციის ვებ-საიტი + errors: + models: + doorkeeper/application: + attributes: + redirect_uri: + fragment_present: ვერ ექნება ფრაგმეტი. + invalid_uri: უნდა იყოს ვალიდური ური. + relative_uri: უნდა იყოს აბსოლუტური ური. + secured_uri: უნდა იყოს ჰტტპს/სსლ ური. + doorkeeper: + applications: + buttons: + authorize: ავტორიზაცია + cancel: უარყოფა + destroy: გაუქმება + edit: შეცვლა + submit: გაგრძელება + confirmations: + destroy: დარწმუნებული ხართ? + edit: + title: აპლიკაციის შეცვლა + form: + error: უპს! შესაძლო შეცდომებზე შეამოწმეთ თქვენი ფორმა + help: + native_redirect_uri: ლოკალური ტესტებისთვის მოიხმარეთ %{native_redirect_uri} + redirect_uri: გამოიყენეთ ერთი ხაზი თითო ური-სთვის + scopes: ფარგლები გამოჰყავით სიცარიელით. საწყისი ფარგლის გამოსაყენებლად დატოვეთ ცარიელი. + index: + application: აპლიკაცია + callback_url: ქოლბექ ურლ + delete: გაუქმება + name: სახელი + new: ახალი აპლიკაცია + scopes: ფარგლები + show: ჩვენება + title: თქვენი აპლიკაციები + new: + title: ახალი აპლიკაცია + show: + actions: მოქმედებები + application_id: კლიენტის გასაღები + callback_urls: ქოლბექ ურლები + scopes: ფარგლები + secret: კლიენტის სერვერი + title: 'აპლიკაცია: %{name}' + authorizations: + buttons: + authorize: ავტორიზაცია + deny: აკრძალვა + error: + title: წარმოიშვა შეცდომა + new: + able_to: ის შეძლებს + prompt: აპლიკაცია %{client_name} ითხოვს წვდომას თქვენს ანგარიშზე + title: საჭიროა ავტორიზაცია + show: + title: დააკოპირეთ ეს ავტორიზაციის კოდი და ჩასვით აპლიკაციაში. + authorized_applications: + buttons: + revoke: გაუქმება + confirmations: + revoke: დარწმუნებული ხართ? + index: + application: აპლიკაცია + created_at: ავტორიზებული + date_format: "%Y-%m-%d %H:%M:%S" + scopes: ფარგლები + title: თქვენი ავტორიზებული აპლიკაციები + errors: + messages: + access_denied: რესურსის მფლობელმა ან აუტორიზაციის სერვერმა აკრძალა ეს მოთხოვნა. + credential_flow_not_configured: რესურის მფლობელის პაროლის რწმუნებულებების ნაკადი ვერ შესრულდა არაკონფიგურირებული Doorkeeper.configure.resource_owner_from_credentials გამო. + invalid_client: ამოუცნობი კლიენტის გამო კლიენტ აუტენტიფიკაცია ვერ მოხერხდა, კლიენტის აუტენტიფიკაცია არ იყო თან დართული, ან მხარდაუჭერელი აუტენტიფიკაციის მეთოდი. + invalid_grant: მოწოდებული ავტორიზაციის გრანტი არასწორია, ვადაგასულია, გაუქმებულია არ ემთხვევა გადამისამართების ურის, რომელიც მოიხმარება ავტორიზაცის მოთხოვნაში, ან მიეცა სხვა კლიენტს. + invalid_redirect_uri: მითითებული გადამისამართების ური არაა ვალიდური. + invalid_request: მოთხოვნას აკლია აუცილებელი პარამეტრი, მოიცავს მხარდაუჭერელ პარამეტრის მნიშვნელობას, ან სხვაგვარად არაა გამართული. + invalid_resource_owner: მოწოდებული რესურსის მფლობელის რწმუნებულებები არაა ვალიდური, ან მფლობელის პონვა ვერ ხერხდება + invalid_scope: მოთხოვნილი ფარგალი არასწორია, ამოუცნობია ან არაა გამართული. + invalid_token: + expired: წვდომის ტოკენს გაუვიდა ვადა + revoked: წვდომის ტოკენი გაუქმდა + unknown: წვდომის ტოკენი არაა ვალიდური + resource_owner_authenticator_not_configured: რესურსის მფლობელის მოპოვება არ შედგა Doorkeeper.configure.resource_owner_authenticator კონფიგურაციის არ არსებობის გამო. + server_error: აუტორიზაციის სერვერს შეხვდა მოულოდნელი მდგომარეობა, რამაც ხელი შეუშალა მას აღესრულებინა მოთხონვა. + temporarily_unavailable: ავტორიზაციის სერვერი ამჟამად ვერ ახერხებს მოთხოვნის შემუშავებას დროებითი გადატვირთვის ან სერვერის შენარჩუნების გამო. + unauthorized_client: კლიენტი არაა ავტორიზებული შეასრულოს ეს მოთხოვნა ამ მეთოდით. + unsupported_grant_type: ავტორიზაციის გრანტის სახეობა არაა მხარდაჭერილი ავტორიზაციის სერვერის მიერ. + unsupported_response_type: ავტორიზაციის სერვერი არ უჭერს მხარს ამ პასუხის სახეობას. + flash: + applications: + create: + notice: აპლიკაცია შეიქმნა. + destroy: + notice: აპლიკაცია გაუქმდა. + update: + notice: აპლიკაცია განახლდა. + authorized_applications: + destroy: + notice: აპლიკაცია წაიშალა. + layouts: + admin: + nav: + applications: აპლიკაციები + oauth2_provider: ოუ-აუთ2 პროვაიდერი + application: + title: საჭიროა ოუ-აუთ ავტორიზაცია + scopes: + follow: შეცვალეთ ანგარიშის ურთიერთობები + push: მიიღეთ თქვენი ფუშ შეტყობინებები + read: წაიკითხოს მთელი თქვენი ანგარიშის მონაცემები + read:accounts: იხილოს ანგარიშის ინფორმაცია + read:blocks: იხილოს თქვენი ბლოკები + read:favourites: იხილოს თქვენი ფავორიტები + read:filters: იხილოს თქვენი ფილრები + read:follows: იხილოს თქვენი მიდევნებები + read:lists: იხილოს თქვენი სიები + read:mutes: იხილოს თქვენი გაჩუმებები + read:notifications: იხილოს თქვენი შეტყობინებები + read:reports: იხილოს თქვენი რეპორტები + read:search: მოძებნოს თქვენი სახელით + read:statuses: იხილოს ყველა სტატუსი + write: შეცვალოს მთელი თქვენი ანგარიშის მონაცემები + write:accounts: შეცვალოს თქვენი პროფილი + write:blocks: დაბლოკოს ანგარიშები და დომენები + write:favourites: ფავორიტი სტატუსები + write:filters: შექმნას ფილტრები + write:follows: გაყვეს ხალხს + write:lists: შექმნას სიები + write:media: ატვირთოს მედია ფაილები + write:mutes: გააგჩუმოს ადამიანები და საუბრები + write:notifications: გაასუფთავოს თქვენი შეტყობინებები + write:reports: დაარეპორტოს სხვა ადამიანები + write:statuses: გამოაქვეყნოს სტატუსები diff --git a/config/locales/ka.yml b/config/locales/ka.yml new file mode 100644 index 000000000..86d982665 --- /dev/null +++ b/config/locales/ka.yml @@ -0,0 +1,893 @@ +--- +ka: + about: + about_hashtag_html: ეს საჯარო ტუტებია, რომლებიც ატარებენ #%{hashtag} ტეგს. მათთან ინტერაქციას შეძლებთ, თუ ფედივერსში გაქვთ რაიმე ანგარიში. + about_mastodon_html: მასტოდონი ღია ვებ პროტოკოლებზე და უფასო, ღია პროგრამებზე დაფუძნებული სოციალური ქსელია. ის ისეთი დეცენტრალიზებულია როგორც ელ-ფოსტა. + about_this: შესახებ + administered_by: 'ადმინისტრატორი:' + api: აპი + closed_registrations: რეგისტრაციები ამჟამად ინსტანციაზე დახურულია. თუმცა! ანგარიშის შესაქმნელად შეგიძლიათ იპოვოთ სხვა ინსტანცია და იმავე ქსელზე იქონიოთ წვდომა იქიდან. + contact: კონტაქტი + contact_missing: არაა დაყენებული + contact_unavailable: მიუწ. + documentation: დოკუმენტაცია + extended_description_html: | +

კარგი ადგილი წესებისთვის

+

განვრცობილი აღწერილობა ჯერ არ შექმნილა.

+ features: + humane_approach_body: სხვა ქსელების შეცდომების გათვალისწინებით, მასტოდონი მიზნად ისახავს ეტიკური დიზაინის არჩევნების გაკეთებას, დაუპირისპირდეს სოციალური მედიის არასწორ მოხმარებას. + humane_approach_title: უფრო ადამიანური მიდგომა + not_a_product_body: მასტოდონი არ არის კომერციული ქსელი. არაა რეკლამა, არაა მაინინგი, არაა შემოღობილი ბაღები. არაა ცენტრალური ავტორიტეტი. + not_a_product_title: შენ ხარ პერსონა და არა პროდუქტი + real_conversation_body: 500 ნიშნის განკარგულებით, მარცვლოვანი კონტენტის და მედია გაფრთხილებების მხარდაჭერით, შეგიძლიათ გამოხატოთ ისე როგორც გსურთ. + real_conversation_title: შექმნილია ნამდვილი საუბრისთვის + within_reach_body: დეველოპერისთვის-მეგობრული აპი ექოსისტემის წყალობით, მრავალი აპლიკაცია აი-ოსისთვის, ანდროიდისთვის და სხვა პლატფორმებისთვის, საშალებას მოგცემთ ნებისმიერი ადგილიდან იქონიოთ კავშირი თქვენს მეგობრებთან. + within_reach_title: მუდამ წვდომის ქვეშ + generic_description: "%{domain} ერთი სერვერია ქსელში" + hosted_on: მასტოდონს მასპინძლობს %{domain} + learn_more: გაიგე მეტი + other_instances: ინსტანციების სია + privacy_policy: კონფიდენციალურობის პოლიტიკა + source_code: კოდი + status_count_after: სტატუსები + status_count_before: ვინც უავტორა + terms: მომსახურების პირობები + user_count_after: მომხმარებლისთვის + user_count_before: სახლი + what_is_mastodon: რა არის მასტოდონი? + accounts: + choices_html: "%{name}-ის არჩევნები:" + follow: გაყევი + followers: მიმდევრები + following: მიჰყვება + joined: გაწევრიანდა %{date} + media: მედია + moved_html: "%{name} გადავიდა %{new_profile_link}:" + network_hidden: ეს ინფორმაცია ხელმიუწვდომელია + nothing_here: აქ არაფერია! + people_followed_by: ხალხი ვისაც %{name} მიჰყვება + people_who_follow: ხალხი ვინც მიჰყვება %{name}-ს + pin_errors: + following: იმ ადამიანს, ვინც მოგწონთ, უკვე უნდა მიჰყვებოდეთ + posts: ტუტები + posts_with_replies: ტუტები და პასუხები + reserved_username: მომხმარებელი რეზერვირებულია + roles: + admin: ადმინისტრატორი + bot: ბოტი + moderator: მოდერატორი + unfollow: ნუღარ მიჰყვები + admin: + account_moderation_notes: + create: დატოვეთ ჩანაწერი + created_msg: მოდერაციის ჩანაწერი წარმატებით შეიქმნა! + delete: გაუქმება + destroyed_msg: მოდერაციის ჩანაწერი წარმატებით გაუქმდა! + accounts: + are_you_sure: დარწმუნებული ხარ? + avatar: ავატარი + by_domain: დომენი + change_email: + changed_msg: ანგარიშის ელ-ფოსტა წარმატებით შეიცვალა! + current_email: მიმდინარე ელ-ფოსტა + label: ელ-ფოსტის შეცვლა + new_email: ახალი ელ-ფოსტა + submit: ელ-ფოსტის შეცვლა + title: შეცვალეთ ელ-ფოსტა მომხმარებლისთვის %{username} + confirm: დადასტურება + confirmed: დადასტურებულია + confirming: დასტურდება + demote: დაქვეითება + disable: გამორთვა + disable_two_factor_authentication: გამორთე 2FA + disabled: გამორთულია + display_name: დისპლეი სახელი + domain: დომენი + edit: შეცვლა + email: ელ-ფოსტა + email_status: ელ-ფოსტის სტატუსი + enable: ჩართვა + enabled: ჩართულია + feed_url: ლენტის ურლ + followers: მიმდევრები + followers_url: მიმდევრების ურლ + follows: დადევნებები + inbox_url: ინბოქსის ურლ + ip: აი-პი + location: + all: ყველა + local: ლოკალური + remote: დისტანციური + title: ადგილმდებარეობა + login_status: ლოგინის სტატუსი + media_attachments: თან-დართული მედია + memorialize: აქციე მემორანდუმად + moderation: + all: ყველა + silenced: გაჩუმებული + suspended: შეჩერებული + title: მოდერაცია + moderation_notes: მოდერაციის ჩანაწერები + most_recent_activity: უახლესი აქტივობა + most_recent_ip: უახლესი აი-პი + not_subscribed: გამოუწერელი + order: + alphabetic: ანბანური + most_recent: უახლესი + title: წესრიგი + outbox_url: აუთბოქსის ურლ + perform_full_suspension: მოახდინეთ სრული შეჩერება + profile_url: პროფილის ურლ + promote: დაწინაურება + protocol: პროტოკოლი + public: საჯარო + push_subscription_expires: ფუშ გამოწერა უქმდება + redownload: განაახლე ავატარი + remove_avatar: გააუქმე ავატარი + resend_confirmation: + already_confirmed: ეს მომხმარებელი უკვე დამოწმებულია + send: დამოწმების ინსტრუქციების გადაგზავნა + success: დამოწმების ინსტრუქციები წარმატებით გაიგზავნა! + reset: გადატვირთვა + reset_password: პაროლის გადატვირთვა + resubscribe: ხელახალი გამოწერა + role: უფლებები + roles: + admin: ადმინისტრატორი + moderator: მოდერატორი + staff: სტაფი + user: მომხმარებელი + salmon_url: სალმონის ურლ + search: ძებნა + shared_inbox_url: გაზიარებული ინბოქსის ურლ + show: + created_reports: ამ ანგარიშის მიერ შექმნილი რეპორტები + report: რეპორტი + targeted_reports: ამ ანგარიშზე მიღებული რეპორტები + silence: სიჩუმე + statuses: სტატუსები + subscribe: გამოწერა + title: ანგარიშები + unconfirmed_email: დაუმოწმებელი ელ-ფოსტა + undo_silenced: გაჩუმების მოშორება + undo_suspension: შეჩერების მოშორება + unsubscribe: გამოწერის შეწყვეტა + username: მომხმარებლის სახელი + web: ვები + action_logs: + actions: + assigned_to_self_report: "%{name}-მა დანიშნა რეპორტი %{target} საკუთარ თავზე" + change_email_user: "%{name}-მა შეცვალა %{target} მომხმარებლის ელ-ფოსტის მისამართი" + confirm_user: "%{name}-მა დაამოწმა %{target} მომხმარებლის ელ-ფოსტის მისამართი" + create_custom_emoji: "%{name}-მა ატვირთა ახალი ემოჯი %{target}" + create_domain_block: "%{name}-მა დაბლოკა დომენი %{target}" + create_email_domain_block: "%{name}-მა შავ სიაში მოაქცია დომენი %{target}" + demote_user: "%{name}-მა დააქვეითა მომხმარებელი %{target}" + destroy_domain_block: "%{name}-მა ბლოკი მოხსნა დომენს %{target}" + destroy_email_domain_block: "%{name} თეთრ სიაში მოაქცია დომენი %{target}" + destroy_status: "%{name}-მა გააუქმა სტატუსი %{target}-ზე" + disable_2fa_user: "%{name} გათიშა მეორე ფაქტორის მოთხოვნილება მომხმარებელზე %{target}" + disable_custom_emoji: "%{name}-მა გათისა ემოჯი %{target}" + disable_user: "%{name}-მა გათიშა ლოგინი მომხმარებლისთვის %{target}" + enable_custom_emoji: "%{name}-მა ჩართო ემოჯი %{target}" + enable_user: "%{name}-მა ჩართო ლოგინი მომხმარებლისთვის %{target}" + memorialize_account: "%{name}-მა აქცია ანგარიში %{target} მემორანდუმის გვერდად" + promote_user: "%{name}-მა დააწინაურა მომხმარებელი %{target}" + remove_avatar_user: "%{name}-მა გააუქმა %{target} მომხმარებლის ავატარი" + reopen_report: "%{name}-მა ხელახლა გახსნა რეპორტი %{target}" + reset_password_user: "%{name} გადატვირთა მომხმარებლის %{target} პაროლი" + resolve_report: "%{name}-მა მოაგვარა %{target} მომხმარებლის რეპორტი" + silence_account: "%{name}-მა გააჩუმა %{target} ანგარიში" + suspend_account: "%{name} შეაჩერა %{target} ანგარიში" + unassigned_report: "%{name}-მა მოაშორა რეპორტი %{target}" + unsilence_account: "%{name}-მა მოაშორა გაჩუმება %{target} ანგარიშს" + unsuspend_account: "%{name}-მა მოაშორა შეჩერება %{target} ანგარიშს" + update_custom_emoji: "%{name}-მა განაახლა ემოჯი %{target}" + update_status: "%{name}-მა განაახლა სტატუსი %{target}-ით" + deleted_status: "(გაუქმებული სტატუსი)" + title: აუდიტის ლოგი + custom_emojis: + by_domain: დომენი + copied_msg: ემოჯის ლოკალური ასლი წარმატებით შეიქმნა + copy: კოპირება + copy_failed_msg: ამ ემოჯის ლოკალური ასლი ვერ შეიქმნა + created_msg: ემოჯი წარმატებით შეიქმნა! + delete: გაუქმება + destroyed_msg: ემოჯი წარმატებით გაუქმდა! + disable: გათიშვა + disabled_msg: ეს ემოჯი წარმატებით გაითიშა + emoji: ემოჯი + enable: ჩართვა + enabled_msg: წარმატებით ჩაირთო ეს ემოჯი + image_hint: PNG 50კბმდე + listed: ჩამოთვლილი + new: + title: ახალი პერსონალიზირებული ემოჯის დამატება + overwrite: გადაწერა + shortcode: მოკლე-კოდი + shortcode_hint: მინ. 2 ნიშანი, მხოლოდ ალფანუმერიკული ნიშნები და "ქვედა-ტირეები" + title: პერსონალიზირებული ემოჯიები + unlisted: ჩამოუთვლელი + update_failed_msg: ემოჯის განახლება ვერ მოხერხდა + updated_msg: ემოჯი წარმატებით განახლდა! + upload: ატვირთვა + dashboard: + backlog: დაუსრულებელი საქმეები + config: კონფიგურაცია + feature_deletions: ანგარიშის გაუქმებები + feature_invites: მოწვევის ბმულები + feature_registrations: რეგისტრაციები + feature_relay: ფედერაციის რილეი + features: ფუნქციები + hidden_service: ფედერაცია დამალულ სერვისებთან + open_reports: ღია რეპორტები + recent_users: ახალი მომხმარებლები + search: სრული-ტექსტის ძიება + single_user_mode: ერთ-მომხმარებლიანი რეჟიმი + software: პროგრამა + space: მოცულობის მოხმარება + title: დაფა + total_users: სულ მომხმარებლები + trends: ტრენდები + week_interactions: ამ კვირის ინტერაქციები + week_users_active: აქტიური ამ კვირას + week_users_new: ამ კვირის მომხმარებლები + domain_blocks: + add_new: ახლის დამატება + created_msg: დომენის ბლოკი ახლა პროცესირების ქვეშაა + destroyed_msg: დომენის ბლოკი გაუქმდა + domain: დომენი + new: + create: ბლოკის შექმნა + hint: დომენის ბლოკი არ შეაჩერებს ანგარიშების ჩაწერას მონაცემთა ბაზაში, მაგრამ ეს ამ ანგარიშებზე რეტროაქტიულად და ავტომატურად გაატარებს სპეციფიურ მოდერაციის მეთოდებს. + severity: + desc_html: "გაჩუმება გახდის ანგარიშის პოსტებს უჩინარს ყველასთვის, ვინც მას არ მიჰყვება. შეჩერება გააუქმებს ანგარიშის მთელ კონტენტს, მედიას და პროფილის მონაცემს. გამოიყენეთ არც ერთი თუ გსურთ უბრალოდ უარყოთ ფაილები." + noop: არც ერთი + silence: გაჩუმება + suspend: შეჩერება + title: ახალი დომენის ბლოკი + reject_media: მედია ფაილების უარყოფა + reject_media_hint: შლის ლოკალურად შენახულ მედია ფაილებს და უარყოფს სამომავლო გადმოტვირთებს. შეუსაბამო შეჩერებებისთვის + severities: + noop: არც ერთი + silence: გაჩუმება + suspend: შეჩერება + severity: სიმძიმე + show: + affected_accounts: + one: გავლენა იქონია მონაცემთა ბაზაში ერთ ანგარიშზე + other: გავლენა იქონიო მონაცემთა ბაზაში %{count} ანგარიშზე + retroactive: + silence: ამ დომენში ყველა არსებულ ანგარიშზე გაჩუმების მოშორება + suspend: ამ დომენში ყველა არსებულ ანგარიშზე შეჩერების მოშორება + title: უკუაქციეთ დომენის ბლოკი %{domain} დომენზე + undo: უკუქცევა + title: დომენის ბლოკები + undo: უკუქცევა + email_domain_blocks: + add_new: ახლის დამატება + created_msg: ელ-ფოსტის დომენი წარმატებით დაემატა შავ სიას + delete: გაუქმება + destroyed_msg: ელ-ფოსტის დომენი წარმატებით ამოიშალა შავი სიიდან + domain: დომენი + new: + create: დომენის დამატება + title: ელ-ფოსტის ახალი შენატანი შავ სიაში + title: ელ-ფოსტის შავი სია + instances: + account_count: ცნობილი ანგარიშები + domain_name: დომენი + reset: გადატვირთვა + search: ძებნა + title: ცნობილი ინსტანციები + invites: + filter: + all: ყველა + available: ხელმისაწვდომი + expired: ვადაგასული + title: ფილტრი + title: მოწვევები + relays: + add_new: ახელი რილეი + description_html: "ფედერაციის რილეი შუამავალი სერვერია, რომელიც ცვლის საჯარო ტუტების დიდ ოდენობას იმ სერვერებს შორის, რომლებიც გამოიწერენ და მასზე გამოაქვეყნებენ. ეს მცირე და საშუალო სერვერებს ეხმარება აღმოაჩინონ კონტენტი ფედივერსისგან, რომელიც სხვა შემთხვევაში მომხარებლებს აიძულებდა მექნიკურ რეჟიმში გაჰყოლოდნენ ხალხს სხვა დისტანციურ სერვერებზე." + enable_hint: ამოქმდების შემდეგ, თქვენი სერვერი გამოიწერს ყველა საჯარო ტუტს ამ რილეიდან და დაიწყებს სერვერის ღია ტუტების იქ გაგზავნას. + inbox_url: რილეი ურლ + setup: რილეი კავშირის დამყარება + status: სტატუსი + title: რილეი სია + report_notes: + created_msg: რეპორტის ჩანაწერი წარმატებით შეიქმნა! + destroyed_msg: რეპორტის ჩანაწერი წარმატებით გაუქმდა! + reports: + account: + note: ჩანაწერი + report: რეპორტი + action_taken_by: მოქმედება შეასრულა + are_you_sure: დარწმუნებული ხარ? + assign_to_self: დანიშნე ჩემზე + assigned: დაინიშნა მოდერატორი + comment: + none: არაფერი + created_at: რეპორტის დრო + id: იდ + mark_as_resolved: მონიშნე გადაწყვეტილად + mark_as_unresolved: მონიშნე გადაუწყვეტლად + notes: + create: ჩანაწერის დამატება + create_and_resolve: გადაწყვეტა ჩანაწერით + create_and_unresolve: ხელახალი გახსნა ჩანაწერით + delete: გაუქმება + placeholder: აღწერეთ თუ რა ნაბიჯები უნდა გადაიდგას, ან სხვა დაკავშირებული განახლებები... + reopen: რეპორტის ხელახალი გახსნა + report: 'რეპორტი #%{id}' + report_contents: მოცულობები + reported_account: დარეპორტებული ანგარიში + reported_by: დაარეპორტა + resolved: გადაწყვეტილი + resolved_msg: რეპორტი წარმატებით გადაწყდა! + silence_account: ანგარიშის გაჩუმება + status: სტატუსი + suspend_account: ანგარიშის შეჩერება + target: მიზანი + title: რეპორტები + unassign: გადაყენება + unresolved: გადაუწყვეტელი + updated_at: განახების დრო + view: ჩვენება + settings: + activity_api_enabled: + desc_html: ლოკალურად გამოქვეყნებული სტატუსების, აქტიური მომხმარებლების და ყოველკვირეული რეგისტრაციების მთვლელი + title: გამოაქვეყნე აგრეგატი სტატისტიკები მომხმარებლის აქტივობაზე + bootstrap_timeline_accounts: + desc_html: გამოჰყავი მომხმარებლები მძიმით. იმუშავებს მხოლოდ ლოკალური და "ბლოკ-მოხსნილ" ანგარიშები. საწყისი როდესაც ცარიელია ყველა ლოკალური ადმინი. + title: საწყისი მიდევნებები ახლა მომხმარებლებზე + contact_information: + email: ბიზნეს ელ-ფოსტა + username: საკონტაქტო მომხმარებლის სახელი + hero: + desc_html: წინა გვერდზე გამოჩენილი. მინ. 600/100პიქს. რეკომენდირებული. როდესაც არაა დაყენებული, ჩნდება ინსტანციის პიქტოგრამა + title: გმირი სურათი + peers_api_enabled: + desc_html: დომენების სახელები რომლებსაც შეხვდა ეს ინსტანცია ფედივერსში + title: გამოაქვეყნე აღმოჩენილი ინსტანციების სია + preview_sensitive_media: + desc_html: ბმულის პრევიუები სხვა ვებ-საიტებზე გამოაჩენენ პიქტოგრამას, მაშინაც კი თუ მედია მონიშნულია მგრძნობიარედ + title: გამოაჩინე მგრძნობიარე მედია ოუფენ-გრეფ პრევიუებში + registrations: + closed_message: + desc_html: გამოჩნდება წინა გვერდზე, როდესაც რეგისტრაციები დახურულია. შეგიძლიათ გამოიყენოთ ჰტმლ ტეგები + title: დახურული რეგისტრაციის წერილი + deletion: + desc_html: უფლება მიეცით ყველას, გააუქმონ თავიანთი ანგარიში + title: ღია ანგარიშის გაუქმება + min_invite_role: + disabled: არავინ + title: ნება დაერთოს მოწვეევებს + open: + desc_html: უფლება მიეცით ყველას, გახსნან ანგარიში + title: ღია რეგისტრაცია + show_known_fediverse_at_about_page: + desc_html: ჩართვისას, ეს გამოაჩენს ტუტებს ყველა ცნობილი ფედივერსისგან პრევიუზე. სხვა შემთხვევაში, გამოაჩენს მხოლოდ ლოკალურ ტუტებს. + title: გამოჩნდეს ცნობილი ვედივერსი თაიმლაინ პრევიუში + show_staff_badge: + desc_html: გამოჩნდეს სტაფის ნიშანი მომხმარებლის გვერდზე + title: სტაფის ნიშნის გამოჩენა + site_description: + desc_html: საშესავლო პარაგრაფი წინა გვერდზე. აღწერეთ თუ რა ხდის ამ მასტოდონის სერვერს განსაკუთრებულს და სხვა მნიშვნელოვანი. შეგიძლიათ გამოიყენოთ ჰტმლ ტეგები, კერძოდ <a> და <em>. + title: ინსტანციის აღწერილობა + site_description_extended: + desc_html: კარგი ადგილი მოქცევის კოდექსისთვის, წესები, სახელმძღვანელოები და სხვა რაც გამოარჩევს თქვენს ინსტანციას. შეგიძლიათ გამოიყენოთ ჰტმლ ტეგები + title: პერსონალიზირებული განვრცობილი ინფორმაცია + site_short_description: + desc_html: გამოჩნდება გვერდით ბარში და მეტა ტეგებში. აღწერეთ თუ რა არის მასტოდონი და რა ხდის ამ სერვერს უნიკალურს ერთ პარაგრაფში. თუ ცარიელია, გამოჩნდება ინსტანციის აღწერილობა. + title: აჩვენეთ ინსტანციის აღწერილობა + site_terms: + desc_html: შეგიძლიათ დაწეროთ საკუთარი კონფიდენციალურობის პოლიტიკა, მომსახურების პირობები ან სხვა იურიდიული დოკუმენტი. შეგიძლიათ გამოიყენოთ ჰტმლ ტეგები + title: პერსონალიზირებული მომსახურების პირობები + site_title: ინსტანციის სახელი + thumbnail: + desc_html: გამოიყენება პრევიუებისთვის ოუფენ-გრეფში და აპი-ში. 1200/630პიქს. რეკომენდირებული + title: ინსტანციის პიქტოგრამა + timeline_preview: + desc_html: აჩვენეთ საჯარო თაიმლაინი ლენდინგ გვერდზე + title: თაიმლაინ პრევიუ + title: საიტის პარამეტრები + statuses: + back_to_account: უკან ანგარიშის გვერდისკენ + batch: + delete: გაუქმება + nsfw_off: მონიშნე არა-მგრძნობიარედ + nsfw_on: მონიშნე მგრძნობიარედ + failed_to_execute: ვერ გაეშვა + media: + title: მედია + no_media: არაა მედია + no_status_selected: სატუსები არ შეცვლილა, რადგან არცერთი არ მონიშნულა + title: ანგარიშის სტატუსები + with_media: მედიით + subscriptions: + callback_url: ქოლბექ ურლ + confirmed: დამოწმდა + expires_in: ვადა გასდის + last_delivery: ბოლო მიღება + title: ვებ-საბი + topic: სათაური + title: ადმინისტრაცია + admin_mailer: + new_report: + body: "%{reporter}-მა დაარეპორტა %{target}" + body_remote: ვიღაცამ %{domain}-იდან დაარეპორტა %{target} + subject: ახალი რეპორტი %{instance} (#%{id})-ზე + application_mailer: + notification_preferences: შეცვალეთ ელ-ფოსტის პრეფერნსიები + salutation: "%{name}," + settings: 'შეცვალეთ ელ-ფოსტის პრეფერენსიები: %{link}' + view: 'ჩვენება:' + view_profile: პროფილის ჩვენება + view_status: სტატუსის ჩვენება + applications: + created: აპლიკაცია წარმატებით შეიქმნა + destroyed: აპლიკაცია წარმატებით გაუქმდა + invalid_url: მოწოდებული ურლ არასწორია + regenerate_token: წვდომის ტოკენის რეგენერაცია + token_regenerated: წვდომის ტოკენის რეგენერაცია მოხერხდა + warning: იყავით ძალიან ფრთხილად ამ მონაცემთან. არასდროს გააზიაროთ ეს! + your_token: თქვენი წვდომის ტოკენი + auth: + agreement_html: რეგისტრაციით თქვენ ეთანხმებით ინსტანციის წესებს და ჩვენ მომსახურების პირობებს. + change_password: პაროლი + confirm_email: ელ-ფოსტის დამოწმება + delete_account: ანგარიშის გაუქმება + delete_account_html: თუ გსურთ გააუქმოთ თქვენი ანგარიში, შეგიძლიათ გააგრძელოთ აქ. საჭირო იქნება დამოწმება. + didnt_get_confirmation: არ მოგსვლიათ დამოწმების ინსტრუქციები? + forgot_password: დაგავიწყდათ პაროლი? + invalid_reset_password_token: პაროლის გადატვირთვის ტოკენი არასწორია ან ვადაგასული. გთხოვთ მოითხოვეთ ახალი. + login: შესვლა + logout: გასვლა + migrate_account: სხვა ანგარიშზე გადასვლა + migrate_account_html: თუ გსურთ ამ ანგარიშის რედირექტის ხვაზე, შეგიძლიათ გაუწიოთ კონფიგურაცია აქ. + or: ან + or_log_in_with: ან გამოიყენეთ + providers: + cas: ქეს + saml: სამლ + register: რეგისტრაცია + register_elsewhere: რეგისტრაცია სხვა სერვერზე + resend_confirmation: დამოწმების ინსტრუქციების ხელახალი გამოგზავნა + reset_password: პაროლის გადატვირთვა + security: უსაფრთხოება + set_new_password: ახალი პაროლის დაყენება + authorize_follow: + already_following: უკვე მიჰყვებით ამ ანგარიშს + error: სამწუხაროთ, დისტანციური სერვერის წაკითხვამ გამოიწვია შეცდომა + follow: გაყევი + follow_request: 'დადევნების მოთხონვა გაეგზავნა:' + following: 'წარმატება! ახლა მიჰყვებით:' + post_follow: + close: ან შეგიძლიათ დახუროთ ეს ფანჯარა. + return: მომხმარებლის პროფილის ჩვენება + web: ვებზე გადასვლა + title: გაყევი %{acct}-ს + datetime: + distance_in_words: + about_x_hours: "%{count}სთ" + about_x_months: "%{count}თვე" + about_x_years: "%{count}წელი" + almost_x_years: "%{count}წელი" + half_a_minute: ამ წამს + less_than_x_minutes: "%{count}წთ" + less_than_x_seconds: ამ წამს + over_x_years: "%{count}წელი" + x_days: "%{count}დღე" + x_minutes: "%{count}წთ" + x_months: "%{count}თვე" + x_seconds: "%{count}წმ" + deletes: + bad_password_msg: კარგად სცადეთ, ჰაკერებო! არასწორი პაროლი + confirm_password: იდენტობის დასამოწმებლად შეიყვანეთ მიმდინარე პაროლი + description_html: ეს სამუდამოდ, დაუბრუნებლად გააუქმებს კონტენტს თქვენი ანგარიშიდან და მოახდენს მის დეაქტივაციას. მომხმარებლის სახელი კი, სამომავლო იმპერსონაციების შესაჩერებლად, გახდება რეზერვირებული + proceed: ანგარიშის გაუქმება + success_msg: თქვენი ანგარიში წარმატებით გაუქმდა + warning_html: მოცულობის გაუქმება გარანტირებულია მხოლოდ ამ ინსტანციაზე. კონტენტი რომელიც ფართო მასშტაბით გაზიარდა უფრო დატოვებს კვალს. ოფლაინ სერვერები და სერვერები, რომლებმაც შეწყვიტეს თქვენი განახლებების გამოწერა არ განაახლებენ მონაცემთა ბაზებს. + warning_title: წვდომა გავრცელებულ კონტენტზე + errors: + '403': ამ გვერდის ხილვის უფლება არ გაქვთ. + '404': გვერდი რომელსაც ეძებთ არ არსებობს. + '410': გვერდი რომელსაც ეძებდით აღარ არსებობს. + '422': + content: უსაფრთხოების ვერიფიკაცია ვერ მოხერხდა. ბლოკავთ ქუქის? + title: უსაფრთხოების ვერიფიკაცია არ შედგა + '429': დარტყმა + '500': + content: ბოდიში, ჩვენ მხარეს რაღაც არია. + title: გვერდი არაა სწორი + noscript_html: მასტოდონ ვებ-აპლიკაციის გამოყენებისთვის, გთხოვთ ჩართოთ ჯავასკრიპტი. სხვა შემთხვევაში, მასტოდონის თქვენი პატფორმისთვის სცადეთ გამოიყენოთ ერთ-ერთი მშობლიური აპლიკაცია. + exports: + archive_takeout: + date: თარიღი + download: ჩამოტვირთეთ თქვენი არქივი + hint_html: შეგიძლიათ მოითხოვოთ თქვენი აქივი ტუტებისა და ატვირთული მედიისა. ექსპორტირებული მონაცემები იქნება ექთივითი-ფაბ ფორმატში, წაკითხვადი ნებისმიერი თავსებადი პროგრამით. არქივის მოთხოვნა შეგიძლიათ 7 დღეში ერთხელ. + in_progress: მიმდინარეობს თქვენი არქივის შედგენა... + request: თქვენი არქივის მოთხოვნა + size: ზომა + blocks: თქვენ ბლოკავთ + csv: ცსვ + follows: თქვენ მიჰყვებით + mutes: თქვენ აჩუმებთ + storage: მედია საცავი + filters: + contexts: + home: სახლის თაიმლაინი + notifications: შეტყობინებები + public: საჯარო თაიმლაინი + thread: საუბრები + edit: + title: ფილტრის ცვლილება + errors: + invalid_context: მოწოდებულია არასწორი ან ცარიელი კონტექსტი + invalid_irreversible: დაუბრუნებელი ფილტრაცია მუშაობს მხოლოდ სახლის ან ნოტიფიკაციის კონტექსტში + index: + delete: გაუქმება + title: ფილტრები + new: + title: ახალი ფილტრის დამატება + followers: + domain: დომენი + explanation_html: თუ გსურთ უზრუნველყოთ თქვენი სტატუსების კონფიდენციალურობა, უნდა იცოდეთ თუ ვინ მოგყვებათ. კერძო სტატუსები მიეწოდება ყველა ინსტანციას, სადაც გყავთ მიმდევრები. შესაძლოა გსურდეთ განიხილოთ ისინი და ამოშალოთ მიმდევრები თუ არ ენდობით თქვენი კონფიდენციალურობის პატივისცემას სტაფისა თუ პროგრამისგან იმ ინსტანციებში. + followers_count: მიმდევრების რაოდენობა + lock_link: თქვენი ანგარიშის ჩაკეტვა + purge: მიმდევრებიდან ამოშლა + success: + one: მიმდევრების სოფტ-ბლოკირების პროცესი ერთი დომენზე... + other: მიმდევრების სოფტ-ბლოკირების პროცესი %{count} დომენზე... + true_privacy_html: გთხოვთ გაითვალისწინეთ, ჭეშმარიტი კონფიდენციალურობა მიღწევადია მხოლოდ ენდ-თუ-ენდ შიფრაციით. + unlocked_warning_html: ყველას შეუძლია გამოგყვეთ, რომ უცბად იხილოს თქვენი სტატუსები. %{lock_link} რომ შეძლოთ განიხილოთ და უარყოთ მიმდევრები. + unlocked_warning_title: თქვენი ანგარიში არაა ჩაკეტილი + footer: + developers: დეველოპერები + more: მეტი… + resources: რესურსები + generic: + changes_saved_msg: ცვლილებები წარმატებით დამახსოვრდა! + save_changes: ცვლილებების შენახვა + validation_errors: + one: რაღაც ჯერ არაა მთლად კარგად! გთხოვთ განიხილოთ ქვემოთ მოცემული შეცდომები + other: რაღაც ჯერ არაა მთლად კარგად! გთხოვთ განიხილოთ ქვემოთ მოცემული %{count} შეცდომა + imports: + preface: შეგიძლიათ დააიმპორტოთ მონაცემები, რომლებიც დააექსპორტეთ სხვა სერვერიდან, მაგალითად ადამიანების სია, რომლებსაც მიჰყვებით ან ბლოკავთ. + success: თქვენი მონაცემები წარმატებით აიტვირთა და მათი პროცესირება მოხდება გარკვეულ დროში + types: + blocking: ბლოკირების სია + following: დადევნების სია + muting: გაჩუმების სია + upload: ატვირთვა + in_memoriam_html: მემორანდუმში. + invites: + delete: დეაქტივაცია + expired: ვადა გაუვიდა + expires_in: + '1800': 30 წუთში + '21600': 6 საათში + '3600': 1 საათში + '43200': 12 საათში + '604800': 1 კვირაში + '86400': 1 დღეში + expires_in_prompt: არასდროს + generate: გენერირება + invited_by: 'თქვენ მოგიწვიათ:' + max_uses: + one: 1 მოხმარება + other: "%{count} მოხმარება" + max_uses_prompt: ლიმიტის გარეშე + prompt: ამ ინსტანციაზე წვდომის მისაცემად, დააგენერირეთ და გააზიარეთ ბმულები სხვებთან + table: + expires_at: ვადა გასდის + uses: მოხმარება + title: მოიწვიეთ ხალხი + lists: + errors: + limit: მიაღწიეთ სიების მაქსიმალურ ოდენობას + media_attachments: + validations: + images_and_video: ვიდეოს დართვა სტატუსზე, რომელიც უკვე მოიცავს სურათებს, ვერ მოხერხდება + too_many: თან ვერ დაურთავთ 4 ფაილზე მეტს + migrations: + acct: username@domain ახალი ანგარიშის + currently_redirecting: 'თქვენი პროფილი გამართულია მოახდინოს გადამისამართება მისამართზე:' + proceed: შენახვა + updated_msg: თქვენი ანგარიშის მიგრაციის პარამეტრები წარმატეებით დამახსოვრდა! + moderation: + title: მოდერაცია + notification_mailer: + digest: + action: ყველა შეტყობინების ჩვენება + body: 'აქ მოკლე შინაარსია წერილების, რომლებიც გამოგეპარათ წინა სტუმრობის შემდეგ: %{since}' + mention: "%{name}-მა დაგასახელათ:" + new_followers_summary: + one: ასევე, არყოფნისას შეგეძინათ ერთი ახალი მიმდევარი! იეი! + other: ასევე, არყოფნისას შეგეძინათ %{count} ახალი მიმდევარი! შესანიშნავია! + subject: + one: "1 ახალი შეტყობინება თქვენი ბოლო სტუმრობის შემდეგ \U0001F418" + other: "%{count} ახალი შეტყობინება თქვენი ბოლო სტუმრობის შემდეგ \U0001F418" + title: თქვენს არყოფნაში... + favourite: + body: 'თქვენი სტატუსი ფავორიტი გახადა %{name}-მა:' + subject: "%{name}-მა თქვენი სტატუსი გახადა ფავორიტი" + title: ახალი ფავორიტი + follow: + body: "%{name} ახლა მოგყვებათ!" + subject: "%{name} ახლა მოგყვებათ" + title: ახალი მიმდევარი + follow_request: + action: დადევნების მოთხოვნების მენეჯმენტი + body: "%{name}-მა მოითხოვა გამოგყვეთ" + subject: 'მიმდევარი მოლოდინში: %{name}' + title: ახალი დადევნების მოთხოვნა + mention: + action: პასუხი + body: 'თქვენ %{name}-მა გასახელათ:' + subject: თქვენ გასახელათ %{name}-მა + title: ახალი სახელობა + reblog: + body: 'თქვენი სტატუსი გაზარდა %{name}-მა:' + subject: "%{name}-მა გაზარდა თქვენი სტატუსი" + title: ახალი ბუსტი + number: + human: + decimal_units: + format: "%n%u" + units: + billion: ბილ. + million: მილ. + quadrillion: კუად. + thousand: ათას. + trillion: ტრილ. + unit: '' + pagination: + newer: უფრო ახალი + next: შემდეგი + older: ძველი + prev: წინა + truncate: "…" + preferences: + languages: ენები + other: სხვა + publishing: გამოქვეყნება + web: ვები + remote_follow: + acct: შეიყვანეთ თქვენი username@domain საიდანაც გსურთ გაჰყვეთ + missing_resource: საჭირო გადამისამართების ურლ თქვენი ანგარიშისთვის ვერ მოიძებნა + no_account_html: არ გაქვთ ანგარიში? შეგიძლიათ დარეგისტრირდეთ აქ + proceed: გააგრძელეთ გასაყოლად + prompt: 'თქვენ გაჰყვებით:' + remote_unfollow: + error: შეცდომა + title: სათაური + unfollowed: დადევნების შეწყვეტა + sessions: + activity: ბოლო აქტივობა + browser: ბრაუზერი + browsers: + alipay: ალიფეი + blackberry: ბლექბერი + chrome: ქრომი + edge: მაიკროსოფთ ედჯი + electron: ელექტრონი + firefox: ფაირფოქსი + generic: ამოუცნობი ბრაუზერი + ie: ინტერნეტ ექფლორერი + micro_messenger: მიკრო-მესინჯერი + nokia: ნოკია ს40 ოვი ბრაუზერი + opera: ოპერა + otter: ოტერი + phantom_js: ფანტომჯეიესი + qq: ქქ ბრაუზერი + safari: საფარი + uc_browser: იუსიბიბრაუზერი + weibo: ვეიბო + current_session: მიმდინარე სესია + description: "%{browser} %{platform}-ზე" + explanation: ეს ვებ-ბრაუზერებია, რომლებიც ამჟამად აუტენტიფიცირებულ არიან თქვენს მასტოდონ ანგარიშთან. + ip: აი-პი + platforms: + adobe_air: ედობ ეარი + android: ანდროიდი + blackberry: ბლექბერი + chrome_os: ქრომო-ოსი + firefox_os: ფაირფოქს-ოსი + ios: აი-ოსი + linux: ლინუქსი + mac: მაკი + other: ამოუცნობი პლატფორმა + windows: ვინდოუსი + windows_mobile: ვინდოუს მობაილი + windows_phone: ვინდოუს ფოუნი + revoke: გაუქმება + revoke_success: სესია წარმატებით გაუქმდა + title: სესიები + settings: + authorized_apps: ავტორიზირებული აპლიკაციები + back: უკან მასტოდონისკენ + delete: ანგარიშის გაუქმება + development: დეველოპმენტი + edit_profile: პროფილის ცვლილება + export: მონაცემის ექსპორტი + followers: ავტორიზირებული მიმდევრები + import: იმპორტი + migrate: ანგარიშის მიგრაცია + notifications: შეტყობინებები + preferences: პრეფერენციები + settings: პარამეტრები + two_factor_authentication: მეორე-ფაქტორის აუტენტიფიკაცია + your_apps: თქვენი აპლიკაციები + statuses: + attached: + description: 'თან დართული: %{attached}' + image: + one: "%{count} სურათი" + other: "%{count} სურათები" + video: + one: "%{count} ვიდეო" + other: "%{count} ვიდეოები" + boosted_from_html: გაიზარდა %{acct_link}-იდან + content_warning: 'გაფრთხილება კონტენტზე: %{warning}' + disallowed_hashtags: + one: 'მოიცავდა აკრძალულ ჰეშტეგს: %{tags}' + other: 'მოიცავს აკრძალულ ჰეშტეგს: %{tags}' + language_detection: ავტომატურად დადგინდეს ენა + open_in_web: ვებში გახნსა + over_character_limit: ნიშნების ლიმიტი გადასცდა %{max}-ს + pin_errors: + limit: ტუტების მაქსიმალური რაოდენობა უკვე აპინეთ + ownership: სხვისი ტუტი ვერ აიპინება + private: არა-საჯარო ტუტი ვერ აიპინება + reblog: ბუსტი ვერ აიპინება + show_more: მეტის ჩვენება + title: '%{name}: "%{quote}"' + visibilities: + private: მხოლოდ-მიმდევრები + private_long: აჩვენე მხოლოდ მიმდევრებს + public: საჯარო + public_long: ხედავს ყველა + unlisted: ჩამოუთვლელი + unlisted_long: ხედავს ყველა, მაგრამ არ ჩანს საჯარო თაიმლაინებში + stream_entries: + pinned: აპინული ტუტი + reblogged: გაზრდილი + sensitive_content: მგრძნობიარე კონტენტი + terms: + body_html: | +

კონფიდენციალურობის პოლიტიკა

+

რა ინფორმაციას ვაგროვებთ?

+ + + +
+ +

რაში ვიყენებთ ინფორმაციას?

+ +

ნებისმიერი სხვა ინფორმაცია, რომელსაც ვაგროვებთ თქვენგან შესაძლოა გამოყენებულ იქნას შემდეგი გზებით:

+ + + +
+ +

როგორ ვიცავთ თქვენს ინფორმაციას?

+ +

მიღებული გვაქვს სხვადასხვა ზომა, შევინარჩუნოთ თქვენი პირადი ინფორმაციის უსაფრთხოება, რომელსაც აგზავნით, შეგყავთ ან კითხულობთ. ამ ყველაფერთან ერთად თქვენი ბრაუზერის სესია, ტრეფიკი თქვენს აპლიკაციასა და აპის შორის დაცულია სსლ-ით, თქვენი პაროლი იშიფრება ძლიერი ალგორითმით. შეგიძლიათ ჩართოთ მეორე-ფაქტორის აუტენტიფიკაცია, რათა გააღმაოთ თქვენი ანგარიშის თავდაცვა.

+ +
+ +

რა არის ჩვენი მონაცემის უარყოფის პოლიტიკა?

+ +

ჩვენ არ დავიშურებთ ძალისხმევას რომ:

+ + + +

შეგიძლიათ მოითხოვოთ და ჩამოტვირთოთ თქვენი კონტენტის არქივი, რომელიც მოიცავს თქვენს პოსტებს, მედია ფაილებს, პროფილის და დასათაურების სურათს.

+ +

შეგიძლიათ დაუბრუნებლად გააუქმოთ თქვენი ანგარიში ნებისმიერ დროს.

+ +
+ +

ვიყენებთ თუ არა ქუქის?

+ +

დიახ. ქუქიები წარმოადგენენ პატარა ფაილებს, რომელთაც, საიტი ან სერვის-პროვაიდერი, ათავსებს თქვენი კომპიუტერის მყარ დისკზე, ვებ-ბრაუზერის (თუ ნებას რთავთ) მეშვეობით. ქუქიები საშუალებას აძლევს საიტს ამოიცნონ თქვენი ბრაუზზერი და თუ გაქვთ რეგისტრირებული ანგარიში მისი ასოციაცია მოახდინონ თქვენს ანგარიშთან.

+ +

ჩვენ ვიყენებთ ქუქის, ვიცოდეთ და შევინახოთ თქვენი პრეფერენსიები სამომავლო სტუმრობებისთვის.

+ +
+ +

ვამჟღავნებთ თუ არა ინფორმაციას გარე მხარეებისთვის?

+ +

ჩვენ არ ვყიდით, ვვაჭრობთ ან გადაქვაქ თქვენთვის პირადად იდენტიფიცირებადი ინფორმაცია სხვა მხარეებისთვის. ეს არ მოიცავს სანდო მხარეებს, რომლებიც გვეხმარება საიტის ოპერირებაში, ჩვენი საქმიანობის ჩატარებაში, ან თქვენთვის მომსახურების გაწევაში, წინაპირობით კონფიდენციალურად შეინახონ თქვენი ინფორმაცია. ჩვენ შესაძლოა გამოვაქვეყნოთ თქვენი ინფორმაცია, რომელიც შესაბამისად შეიძლება ჩავთვალოთ კანონმდებლობასთან შეთავსებისთვის, აღვასრულოთ პოლიტიკა ან დავიცვათ ჩვენი ან სხვისი უფლებები, კუთვნილება ან უსაფრთხოება.

+ +

თქვენი საჯარო ინფორმაცია შესაძლოა ჩამოტვირთულ იქნას სხვა სერვერების მიერ ქსელში. თქვენი ღია და მიმდევრებზე გათვლილი პოსტები მიეწოდება სერვერებს სადაც თქვენი მიმდევრები მოღვაწეობენ, იმ შემთხვევაში თუ მიმღებები მომდინარეობენ სხვა სერვერიდან, პირდაპირი წერილები მიეწოდებათ მიმღებების სერვერებს.

+ +

როდესაც უფლებას მისცემთ აპლიკაციას გამოიყენოს თქვენი ანგარიში, უფლებებისგან გამომდინარე, მან შესაძლოა მოიპოვოს თქვენი საჯარო ინფორმაცია, თქვენი დადევნების სიები, თქვენი მიმდევრები, თქვენი სიები, ყველა პოსტი და თქვენი ფავორიტები. აპლიკაციები ვერასდროს იქონიებენ წვდომას თქვენი ელ-ფოსტის მისამართზე ან პაროლზე.

+ +
+ +

საიტის მოხმარებს ბავშვების მიერ

+ +

თუ ეს სერვერი მდებარეობს ეუ-ში ან ეეა-ში: ჩვენი საიტი, პროდუქტები და სერვისები მიმართულია ადამიანებისთვის, რომელთაც შეუსრულდათ 16 წელი. თუ თქვენი ასაკი 16 წელიწადზე ნაკლებია, ჯიდიფიარის (ზოგადი მონაცემების დაცვის რეგულაცია/a>) მოთხოვნის მიხედვით არ გამოიყენოთ ეს საიტი.

+ +

თუ ეს სერვერი მდებარეობს ა.შ.შ.-ში: ჩვენი საიტი პროდუქტი და სერვისები მიმართულია ადამიანებისთვის, რომელთაც შეუსრულდათ 13 წელი. თუ თქვენი ასაკი 13 წელიწადზე ნაკლებია, კოპპას (ბავშვთა ონლაინ კონფიდენციალურობის დაცვის აქტი) მოთხოვნების მიხედვით არ გამოიყენოთ ეს საიტი.

+ +

იურიდიული მოთხოვნილებები შეიძლება განსხვავდებოდეს, თუ ეს სერვერი იმყოფება სხვა იურისდიქციის ქვეშ.

+ +
+ +

ცვლილებები კონფიდენციალურობის პოლიტიკაში

+ +

თუ გადავწყვეტთ შევცვალოთ კონფიდენციალურობის პოლიტიკა, გამოვაქვეყნებთ ამ გვერდზე.

+ +

ეს დოკუმენტი არის ცც-ბაი-სა. ეს ბოლოს განახლდა 2018 წლის, 17 აგვისტოს.

+ +

საწყისად ადაპტირებულია გამჟღავნების კონფიდენციალური პოლიტიკისგან.

+ title: "%{instance} მომსახურების პირობები და კონფიდენციალურობის პოლიტიკა" + themes: + contrast: მაღალი კონტრასტი + default: მასტოდონი + mastodon-light: მასტოდონი (ღია) + time: + formats: + default: "%b %d, %Y, %H:%M" + month: "%b %Y" + two_factor_authentication: + code_hint: დასამოწმებლად შეიყვანეთ თქვენი აუტენტიფიკატორ აპლიკაციისგან გენერირებული კოდი + description_html: თუ ჩართავთ მეორე-ფაქტორის აუტენტიფიკაციას, შესვლისას აუცილებელი იქნება ფლობდეთ ტელეფონს, რომელიც დააგენერირებს შესვლის ტოკენებს. + disable: გათიშვა + enable: ჩართვა + enabled: მეორე-ფაქტორის აუტენტიფიკაცია ჩართულია + enabled_success: მეორე-ფაქტორის აუტენტიფიკაცია წარმატებით ჩაირთო + generate_recovery_codes: აღდგენის კოდების გენერაცია + instructions_html: "დაასკანირეთ ეს ქრ კოდი გუგლ აუტენტიფიკატორში ან მსგავს ტოტპ აპლიკაციაში თქვენს ტელეფონზე. ამიერიდან, ეს აპლიკაცია დააგენერირებს ტოკენებს მაშინ როდესაც დაგჭირდებათ ავტორიზაცია." + lost_recovery_codes: აღდგენის კოდები უფლებას გაძლევთ მიიღოთ ხელმეორე წვდომა თქვენი ანგარიშისადმი თუ დაკარგავთ ტელეფონს. თუ დაკარგეთ აღდგენის კოდები, მათ რეგენერაცია შეგიძლიათ აქ. ძველი აღდგენის კოდები აღარ იქნება ვალიდური. + manual_instructions: 'თუ ვერ ასკანირებთ ქრ კოდს და საჭიროებთ მის მექანიკურ რეჟიმში შეყვანას, აქ არის ჩვეულებრივი ტექსტური საიდუმლო:' + recovery_codes: გაუწიეთ აღდგენის კოდებს რეზერვაცია + recovery_codes_regenerated: აღგენის კოდების რეგენერაცია წარმატებით შესრულდა + recovery_instructions_html: თუ როდესმე დაკარგავთ წვდომას თქვენს ტელეფონთან, შეგიძლიათ ქვემოთ მოცემული აღდგენის კოდები გამოიყენოთ, რათა მოიპოვოთ ხელმეორე წვდომა თქვენი ანგარიშისადმი. იქონიეთ აღდგენის კოდები დაცულად. მაგალითისთვის, შეგიძლიათ ამობეჭდოთ და შეინახოთ სხვა საბუთებთან ერთად. + setup: დაყენება + wrong_code: შეყვანილი კოდი არ იყო სწორი! სწორია სერვერის და მოწყობილობის დრო? + user_mailer: + backup_ready: + explanation: თქვენ მოითხოვეთ თქვენი მასტოდონის ანგარიშის სრული რეზერვაცია. ის ახლა უკვე მზადაა გადმოსაწერად! + subject: თქვენი არქივი გადმოსაწერად მზადაა + title: არქივის მიღება + welcome: + edit_profile_action: პროფილის მოწყობა + edit_profile_step: შეგიძლიათ მოაწყოთ თქვენი პროფილი ავატარის ატვირთვით, დასათაურების სურათით, თქვენი დისპლეი სახელის შეცვლით და სხვა. თუ გსურთ გაუწიოთ ახალ მიმდევრებს რევიუ, სანამ რეალურად გამოგყვებიან, შეგიძლიათ ჩაკეტოთ თქვენი ანგარიში. + explanation: აქ რამდენიმე რჩევაა დასაწყისისთვის + final_action: დაიწყე პოსტვა + final_step: 'დაიწყე პოსტვა! თქვენი ღია წერილები შესაძლოა ნახონ სხვებმა მიმდევრების გარეშეც კი, მაგალითად თქვენს ლოკალურ თაიმლაინზე ან ჰეშტეგებში. შეგიძლიათ წარადგინოთ თქვენი თავი #introductions ჰეშტეგით.' + full_handle: თქვენი სრული სახელური + full_handle_hint: ეს არის ის რასაც ეტყვით თქვენს მეგობრებს, რათა მოგწერონ ან გამოგყვნენ სხვა ინსტანციიდან. + review_preferences_action: შეცვალეთ პრეფერენსიები + review_preferences_step: დარწმუნდით რომ აყენებთ თქვენს პრეფერენსიებს, მაგალითად რა ელ-ფოსტის წერილების მიღება გსურთ, ან კონფიდენციალურობის რა დონე გსურთ ჰქონდეთ თქვენს პოსტებს საწყისად. თუ არ გაღიზიანებთ მოძრაობა, შეგიძლიათ ჩართოთ გიფის ავტო-დაკვრა. + subject: კეთილი იყოს თქვენი მობრძანება მასტოდონში + tip_bridge_html: თუ მოდიხართ ტვიტერიდან, შეგიძლიათ იპოვოთ მეგობრები მასტოდონში ხიდის აპლიკაციით. თუმცა, ეს მუშაობს მხოლოდ მაშინ თუ მათაც მოიხმარეს ხიდის აპლიკაცია! + tip_federated_timeline: ფედერალური თაიმლაინი მასტოდონის ქსელის ცეცხლოვანი ხედია. ის მოიცავს მხოლოდ იმ ადამიანებს, რომელთაგანაც გამოიწერეს თქვენმა მეზობლებმა, ასე რომ ეს არაა სრული. + tip_following: თქვენ საწყისად მიჰყვებით თქვენი სერვერის ადმინისტრატორ(ებ)ს. უფრო საინტერესო ადამიანების მოსაძებნად იხილეთ ლოკალური და ფედერალური თაიმლაინები. + tip_local_timeline: ლოკალური თაიმლაინი ცეცხლოვანი ხედია ადამიანებისთვის %{instance}-ზე. ისინი არიან თქვენი უსიტყვო მეზობლები! + tip_mobile_webapp: თუ თქვენი მობილური ბრაუზერი გთავაზობთ მასტოდონის სახლის-ეკრანზე დამატებას, შეძლებთ ფუშ შეტყობინებების მიღებას. ეს მრავალმხრივ მოქმედებს როგორც მშობლიური აპლიკაცია! + tips: რჩევები + title: კეთილი იყოს თქვენი მობრძანება, %{name}! + users: + invalid_email: ელ-ფოსტის მისამართი არაა მართებული + invalid_otp_token: არასწორი მეორე ფაქტორის კოდი + otp_lost_help_html: თუ დაკარგეთ წვდომა ორივეზე, შესაძლოა დაუკავშირდეთ %{email}-ს + seamless_external_login: შესული ხართ გარე სერვისით, აქედან გამომდინარე პაროლი და ელ-ფოსტის მისამართი არაა ხელმისაწვდომი. + signed_in_as: 'შესული ხართ როგორც:' diff --git a/config/locales/simple_form.ka.yml b/config/locales/simple_form.ka.yml new file mode 100644 index 000000000..eb6d82bb2 --- /dev/null +++ b/config/locales/simple_form.ka.yml @@ -0,0 +1,99 @@ +--- +ka: + simple_form: + hints: + defaults: + autofollow: ადამიანები რომლებიც დარეგისტრირდებიან მოწვევით, ავტომატურად გამოგყვებიან + avatar: პნგ, გიფ ან ჯპგ. მაქს. %{size}. ზომა დაპატარავდება %{dimensions}პიქს.-ზე + bot: ეს ანგარიში უმთავრესად ასრულებს ავტომატურ მოქმედებებს და შესაძლოა არ იყოს მონიტორინგის ქვეშ + context: ერთ ან მრავალი კონტექსტი სადაც ფილტრი უნდა შესრულდეს + digest: იგზავნება მხოლოდ ხანგრძლივი უაქტივობის პერიოდის შემდეგ და არყოფნისას თუ მიიღეთ ერთი წერილი მაინც + display_name: + one: დარჩა ერთი ნიშანი + other: დარჩა %{count} ნიშანი + fields: პროფილზე ტაბულის სახით შესაძლოა საჩვენებლად გაგაჩნდეთ მაქს. 4 პუნქტი + header: პნგ, გიფ ან ჯპგ. მაქს. %{size}. ზომა დაპატარავდება %{dimensions}პიქს.-ზე + inbox_url: ურლ დააკოირეთ გამოყენებისთვის სასურველი რილეის წინა გვერდიდან + irreversible: გაფილტრული ტუტები გაუქმდება აღუდგენლად, იმ შემთხვევაშიც კი თუ ფილტრი სამომავლოდ გაუქმდება + locale: მომხმარებლის ინტერფეისის, ელ-ფოსტის წერილების და ფუშ შეტყობინებების ენა + locked: საჭიროებს თქვენ მიერ მიმდევრების ხელით დადასტურებას + note: + one: დარჩა ერთი ნიშანი + other: დარჩა %{count} ნიშანი + phrase: დამთხვევა მოხდება დიდი და პატარა ასოების ან კონტენტის გაფრთხილების გათვალისწინების გარეშე + scopes: რომელი აპიებისადმი ექნება აპლიკაციას ცვდომა. თუ არიჩევთ უმთავრეს ფარგლებს, არ დაგჭირდებათ ინდივიდუალურების ამორჩევა. + setting_default_language: თქვენი ტუტების ენა შეიძლება დადგინდეს ავტომატურად, მაგრამ ეს არაა ყოველთვის ზუსტი + setting_hide_network: ვის მიყვებით და ვინ მოგყვებათ არ გამოჩნდება აქ + setting_noindex: გავლენას ახდენს თქვენს ღია პროფილისა და სტატუსის გვერდებზე + setting_theme: გავლენას ახდენს თუ როგორ გამოიყურება მასტოდონი, როდესაც შესული ხართ რომელიმე მოწყობილობიდან. + whole_word: როდესაც სიტყვა ან ფრაზა მხოლოდ ალფა-ნუმერიკულია, ის დაფიქსირდება თუ ემთხვევა სრულ სიტყვას + imports: + data: ცსვ ფაილის ექსპორტი მოხდა მასტოდონის სხვა ინსტანციიდან + sessions: + otp: 'შეიყვანეთ მეორე ფაქტორის კოდი, რომელიც დააგერირა თქვენმა ტელეფონმა ან მოიხმარეთ შემდეგი აღდგენის კოდებიდან ერთ-ერთი:' + user: + chosen_languages: როდესაც მოინიშნება, ღია თაიმლაინზე გამოჩნდება ტუტები მხოლოდ არჩეულ ენებზე + labels: + account: + fields: + name: ლეიბლი + value: მოცულობა + defaults: + autofollow: მოიწვიეთ რომ გამოჰყვნენ თქვენს ანგარიშს + avatar: ავატარი + bot: ეს ბოტის ანგარიშია + chosen_languages: ენების ფილტრი + confirm_new_password: დაადასტურეთ ახალი პაროლი + confirm_password: დაადასტურეთ პაროლი + context: კონტექსტის ფილტრი + current_password: მიმდინარე პაროლი + data: მონაცემები + display_name: დისპლეის სახელი + email: ელ-ფოსტის მისამართი + expires_in: ვადის გასვლის დრო + fields: პროფილის მეტა-მონაცემი + header: დასათაურება + inbox_url: რილეი ინბოქსის ურლ + irreversible: გაუქმდეს დამალვის მაგივრად + locale: ინტერფეისის ენა + locked: ანგარიშის ჩაკეტვა + max_uses: მოხმარების მაქს. ოდენობა + new_password: ახალი პაროლი + note: ბიო. + otp_attempt: მეორე-ფაქტორის კოდი + password: პაროლი + phrase: სიტყვა ან ფრაზა + setting_auto_play_gif: ანიმაციური გიფების ავტო-დაკვრა + setting_boost_modal: ბუსტამე მოხდეს დამოწმება + setting_default_language: პოსტინგის ენა + setting_default_privacy: პოსტის კონფიდენციალურობა + setting_default_sensitive: ყოველთვის მოინიშნოს მედია მგრძნობიარედ + setting_delete_modal: ტუტის გაუქმებამდე გამოჩნდეს დადასტურების ფანჯარა + setting_display_sensitive_media: ყოველთვის გამოჩნდეს მგრძნობიარე მედია + setting_hide_network: თქვენი ქსელის დამალვა + setting_noindex: საძოები სისტემების ინდექსაციის შეჩერება + setting_reduce_motion: მოძრაობის შემცირება ანიმაციებში + setting_system_font_ui: მოხდეს სისტემის საწყისი ფონტის მოხმარება + setting_theme: საიტის თემა + setting_unfollow_modal: გამოჩნდეს დადასტურების ფანჯარა, სანამ შეყვეტთ ვინმეს დადევნებას + severity: სიმძიმე + type: იმპორტის სახეობა + username: მომხმარებლის სახელი + username_or_email: მომხმარებლის სახელი ან ელ-ფოსტა + whole_word: მთელი სიტყვა + interactions: + must_be_follower: დაიბლოკოს შეტყობინებები არა მიმდევრებისგან + must_be_following: დაიბლოკოს შეტყობინებები ადამიანებისგან ვისაც არ მიჰყვებით + must_be_following_dm: დაიბლოკოს პირადი წერილები ადამიანბისგან ვისაც არ მიჰყვებით + notification_emails: + digest: გამოიგზავნოს დაიჯესტ წერილები + favourite: გამოიგზავნოს წერილი როდესაც ვინმე ფავორიტად აქცევს თქვენს სტატუსს + follow: გამოიგზავნოს წერილი როდესაც ვინმე გამოგყვებათ + follow_request: გამოიგზავნოს წერილი როდესაც ვინმე მოგთხოვთ გაჰყვეთ + mention: გამოიგზავნოს წერილი როდესაც ვინმე გასახელებთ + reblog: გამოიგზავნოს წერილი როდესაც ვინმე გაზრდის თქვენს სტატუსს + 'no': არა + required: + mark: "*" + text: აუცილებელი + 'yes': კი -- cgit From 78fa926ed560e6a9738144bec7e152fa42104139 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 18 Aug 2018 03:03:12 +0200 Subject: Add remote interaction dialog for toots (#8202) * Add remote interaction dialog for toots * Change AuthorizeFollow into AuthorizeInteraction, support statuses * Update brakeman.ignore * Adjust how interaction buttons are display on public pages * Fix tests --- app/controllers/authorize_follows_controller.rb | 66 -------- .../authorize_interactions_controller.rb | 66 ++++++++ app/controllers/intents_controller.rb | 2 +- app/controllers/remote_follow_controller.rb | 1 + app/controllers/remote_interaction_controller.rb | 48 ++++++ app/helpers/home_helper.rb | 10 ++ app/javascript/packs/public.js | 21 ++- app/javascript/styles/mastodon/components.scss | 1 + app/javascript/styles/mastodon/stream_entries.scss | 5 + app/models/remote_follow.rb | 4 + app/serializers/webfinger_serializer.rb | 2 +- .../_post_follow_actions.html.haml | 4 - app/views/authorize_follows/error.html.haml | 3 - app/views/authorize_follows/show.html.haml | 17 -- app/views/authorize_follows/success.html.haml | 13 -- .../_post_follow_actions.html.haml | 4 + app/views/authorize_interactions/error.html.haml | 3 + app/views/authorize_interactions/show.html.haml | 18 +++ app/views/authorize_interactions/success.html.haml | 13 ++ app/views/layouts/modal.html.haml | 2 +- app/views/remote_interaction/new.html.haml | 17 ++ .../stream_entries/_detailed_status.html.haml | 15 +- app/views/stream_entries/_simple_status.html.haml | 10 +- app/views/stream_entries/show.html.haml | 2 +- app/views/well_known/webfinger/show.xml.ruby | 2 +- config/brakeman.ignore | 180 +++++++++++++-------- config/locales/en.yml | 5 +- config/routes.rb | 5 +- .../authorize_follows_controller_spec.rb | 110 ------------- .../authorize_interactions_controller_spec.rb | 111 +++++++++++++ spec/controllers/intents_controller_spec.rb | 2 +- 31 files changed, 457 insertions(+), 305 deletions(-) delete mode 100644 app/controllers/authorize_follows_controller.rb create mode 100644 app/controllers/authorize_interactions_controller.rb create mode 100644 app/controllers/remote_interaction_controller.rb delete mode 100644 app/views/authorize_follows/_post_follow_actions.html.haml delete mode 100644 app/views/authorize_follows/error.html.haml delete mode 100644 app/views/authorize_follows/show.html.haml delete mode 100644 app/views/authorize_follows/success.html.haml create mode 100644 app/views/authorize_interactions/_post_follow_actions.html.haml create mode 100644 app/views/authorize_interactions/error.html.haml create mode 100644 app/views/authorize_interactions/show.html.haml create mode 100644 app/views/authorize_interactions/success.html.haml create mode 100644 app/views/remote_interaction/new.html.haml delete mode 100644 spec/controllers/authorize_follows_controller_spec.rb create mode 100644 spec/controllers/authorize_interactions_controller_spec.rb (limited to 'config') diff --git a/app/controllers/authorize_follows_controller.rb b/app/controllers/authorize_follows_controller.rb deleted file mode 100644 index 775d5f23f..000000000 --- a/app/controllers/authorize_follows_controller.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -class AuthorizeFollowsController < ApplicationController - layout 'modal' - - before_action :authenticate_user! - before_action :set_body_classes - - def show - @account = located_account || render(:error) - end - - def create - @account = follow_attempt.try(:target_account) - - if @account.nil? - render :error - else - render :success - end - rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError - render :error - end - - private - - def follow_attempt - FollowService.new.call(current_account, acct_without_prefix) - end - - def located_account - if acct_param_is_url? - account_from_remote_fetch - else - account_from_remote_follow - end - end - - def account_from_remote_fetch - FetchRemoteAccountService.new.call(acct_without_prefix) - end - - def account_from_remote_follow - ResolveAccountService.new.call(acct_without_prefix) - end - - def acct_param_is_url? - parsed_uri.path && %w(http https).include?(parsed_uri.scheme) - end - - def parsed_uri - Addressable::URI.parse(acct_without_prefix).normalize - end - - def acct_without_prefix - acct_params.gsub(/\Aacct:/, '') - end - - def acct_params - params.fetch(:acct, '') - end - - def set_body_classes - @body_classes = 'modal-layout' - end -end diff --git a/app/controllers/authorize_interactions_controller.rb b/app/controllers/authorize_interactions_controller.rb new file mode 100644 index 000000000..e27366ea3 --- /dev/null +++ b/app/controllers/authorize_interactions_controller.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +class AuthorizeInteractionsController < ApplicationController + include Authorization + + layout 'modal' + + before_action :authenticate_user! + before_action :set_body_classes + before_action :set_resource + + def show + if @resource.is_a?(Account) + render :show + elsif @resource.is_a?(Status) + redirect_to web_url("statuses/#{@resource.id}") + else + render :error + end + end + + def create + if @resource.is_a?(Account) && FollowService.new.call(current_account, @resource) + render :success + else + render :error + end + rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError + render :error + end + + private + + def set_resource + @resource = located_resource || render(:error) + authorize(@resource, :show?) if @resource.is_a?(Status) + end + + def located_resource + if uri_param_is_url? + ResolveURLService.new.call(uri_param) + else + account_from_remote_follow + end + end + + def account_from_remote_follow + ResolveAccountService.new.call(uri_param) + end + + def uri_param_is_url? + parsed_uri.path && %w(http https).include?(parsed_uri.scheme) + end + + def parsed_uri + Addressable::URI.parse(uri_param).normalize + end + + def uri_param + params[:uri] || params.fetch(:acct, '').gsub(/\Aacct:/, '') + end + + def set_body_classes + @body_classes = 'modal-layout' + end +end diff --git a/app/controllers/intents_controller.rb b/app/controllers/intents_controller.rb index 56129d69a..9f41cf48a 100644 --- a/app/controllers/intents_controller.rb +++ b/app/controllers/intents_controller.rb @@ -8,7 +8,7 @@ class IntentsController < ApplicationController if uri.scheme == 'web+mastodon' case uri.host when 'follow' - return redirect_to authorize_follow_path(acct: uri.query_values['uri'].gsub(/\Aacct:/, '')) + return redirect_to authorize_interaction_path(uri: uri.query_values['uri'].gsub(/\Aacct:/, '')) when 'share' return redirect_to share_path(text: uri.query_values['text']) end diff --git a/app/controllers/remote_follow_controller.rb b/app/controllers/remote_follow_controller.rb index cd61fd763..8ba331cd1 100644 --- a/app/controllers/remote_follow_controller.rb +++ b/app/controllers/remote_follow_controller.rb @@ -42,5 +42,6 @@ class RemoteFollowController < ApplicationController def set_body_classes @body_classes = 'modal-layout' + @hide_header = true end end diff --git a/app/controllers/remote_interaction_controller.rb b/app/controllers/remote_interaction_controller.rb new file mode 100644 index 000000000..6299a1e13 --- /dev/null +++ b/app/controllers/remote_interaction_controller.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +class RemoteInteractionController < ApplicationController + include Authorization + + layout 'modal' + + before_action :set_status + before_action :set_body_classes + + def new + @remote_follow = RemoteFollow.new(session_params) + end + + def create + @remote_follow = RemoteFollow.new(resource_params) + + if @remote_follow.valid? + session[:remote_follow] = @remote_follow.acct + redirect_to @remote_follow.interact_address_for(@status) + else + render :new + end + end + + private + + def resource_params + params.require(:remote_follow).permit(:acct) + end + + def session_params + { acct: session[:remote_follow] } + end + + def set_status + @status = Status.find(params[:id]) + authorize @status, :show? + rescue Mastodon::NotPermittedError + # Reraise in order to get a 404 + raise ActiveRecord::RecordNotFound + end + + def set_body_classes + @body_classes = 'modal-layout' + @hide_header = true + end +end diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb index 8449f6c8a..f5b501235 100644 --- a/app/helpers/home_helper.rb +++ b/app/helpers/home_helper.rb @@ -38,4 +38,14 @@ module HomeHelper end end end + + def obscured_counter(count) + if count <= 0 + 0 + elsif count == 1 + 1 + else + '1+' + end + end end diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js index 6b47eecf9..dc18da853 100644 --- a/app/javascript/packs/public.js +++ b/app/javascript/packs/public.js @@ -67,13 +67,6 @@ function main() { }, datetime, now, datetime.getFullYear()); }); - [].forEach.call(document.querySelectorAll('.modal-button'), (content) => { - content.addEventListener('click', (e) => { - e.preventDefault(); - window.open(e.target.href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes'); - }); - }); - const reactComponents = document.querySelectorAll('[data-component]'); if (reactComponents.length > 0) { import(/* webpackChunkName: "containers/media_container" */ '../mastodon/containers/media_container') @@ -119,6 +112,20 @@ function main() { return false; }); + delegate(document, '.modal-button', 'click', e => { + e.preventDefault(); + + let href; + + if (e.target.nodeName !== 'A') { + href = e.target.parentNode.href; + } else { + href = e.target.href; + } + + window.open(href, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes'); + }); + delegate(document, '#account_display_name', 'input', ({ target }) => { const nameCounter = document.querySelector('.name-counter'); const name = document.querySelector('.card .display-name strong'); diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 931f1aa0d..cfd8e5ad4 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -628,6 +628,7 @@ overflow: hidden; white-space: pre-wrap; padding-top: 2px; + color: $primary-text-color; &:focus { outline: 0; diff --git a/app/javascript/styles/mastodon/stream_entries.scss b/app/javascript/styles/mastodon/stream_entries.scss index 9e2aa720c..03bbd84db 100644 --- a/app/javascript/styles/mastodon/stream_entries.scss +++ b/app/javascript/styles/mastodon/stream_entries.scss @@ -3,6 +3,7 @@ border-radius: 4px; overflow: hidden; margin-bottom: 10px; + text-align: left; @media screen and (max-width: $no-gap-breakpoint) { margin-bottom: 0; @@ -63,6 +64,10 @@ } } } + + &--highlighted .entry { + background: lighten($ui-base-color, 8%); + } } .button.logo-button { diff --git a/app/models/remote_follow.rb b/app/models/remote_follow.rb index 070144e2d..2537de36c 100644 --- a/app/models/remote_follow.rb +++ b/app/models/remote_follow.rb @@ -22,6 +22,10 @@ class RemoteFollow addressable_template.expand(uri: account.local_username_and_domain).to_s end + def interact_address_for(status) + addressable_template.expand(uri: ActivityPub::TagManager.instance.uri_for(status)).to_s + end + private def populate_template diff --git a/app/serializers/webfinger_serializer.rb b/app/serializers/webfinger_serializer.rb index f80d12c02..8c0b07702 100644 --- a/app/serializers/webfinger_serializer.rb +++ b/app/serializers/webfinger_serializer.rb @@ -20,7 +20,7 @@ class WebfingerSerializer < ActiveModel::Serializer { rel: 'self', type: 'application/activity+json', href: account_url(object) }, { rel: 'salmon', href: api_salmon_url(object.id) }, { rel: 'magic-public-key', href: "data:application/magic-public-key,#{object.magic_key}" }, - { rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_follow_url}?acct={uri}" }, + { rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_interaction_url}?uri={uri}" }, ] end end diff --git a/app/views/authorize_follows/_post_follow_actions.html.haml b/app/views/authorize_follows/_post_follow_actions.html.haml deleted file mode 100644 index 2a9c062e9..000000000 --- a/app/views/authorize_follows/_post_follow_actions.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -.post-follow-actions - %div= link_to t('authorize_follow.post_follow.web'), web_url("accounts/#{@account.id}"), class: 'button button--block' - %div= link_to t('authorize_follow.post_follow.return'), TagManager.instance.url_for(@account), class: 'button button--block' - %div= t('authorize_follow.post_follow.close') diff --git a/app/views/authorize_follows/error.html.haml b/app/views/authorize_follows/error.html.haml deleted file mode 100644 index 88d33b68d..000000000 --- a/app/views/authorize_follows/error.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -.form-container - .flash-message#error_explanation - = t('authorize_follow.error') diff --git a/app/views/authorize_follows/show.html.haml b/app/views/authorize_follows/show.html.haml deleted file mode 100644 index 90e65b34f..000000000 --- a/app/views/authorize_follows/show.html.haml +++ /dev/null @@ -1,17 +0,0 @@ -- content_for :page_title do - = t('authorize_follow.title', acct: @account.acct) - -.form-container - .follow-prompt - = render 'application/card', account: @account - - - if current_account.following?(@account) - .flash-message - %strong - = t('authorize_follow.already_following') - = render 'post_follow_actions' - - - else - = form_tag authorize_follow_path, method: :post, class: 'simple_form' do - = hidden_field_tag :acct, @account.acct - = button_tag t('authorize_follow.follow'), type: :submit diff --git a/app/views/authorize_follows/success.html.haml b/app/views/authorize_follows/success.html.haml deleted file mode 100644 index cf9cb50ea..000000000 --- a/app/views/authorize_follows/success.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -- content_for :page_title do - = t('authorize_follow.title', acct: @account.acct) - -.form-container - .follow-prompt - - if @account.locked? - %h2= t('authorize_follow.follow_request') - - else - %h2= t('authorize_follow.following') - - = render 'application/card', account: @account - - = render 'post_follow_actions' diff --git a/app/views/authorize_interactions/_post_follow_actions.html.haml b/app/views/authorize_interactions/_post_follow_actions.html.haml new file mode 100644 index 000000000..561c60137 --- /dev/null +++ b/app/views/authorize_interactions/_post_follow_actions.html.haml @@ -0,0 +1,4 @@ +.post-follow-actions + %div= link_to t('authorize_follow.post_follow.web'), web_url("accounts/#{@resource.id}"), class: 'button button--block' + %div= link_to t('authorize_follow.post_follow.return'), TagManager.instance.url_for(@resource), class: 'button button--block' + %div= t('authorize_follow.post_follow.close') diff --git a/app/views/authorize_interactions/error.html.haml b/app/views/authorize_interactions/error.html.haml new file mode 100644 index 000000000..88d33b68d --- /dev/null +++ b/app/views/authorize_interactions/error.html.haml @@ -0,0 +1,3 @@ +.form-container + .flash-message#error_explanation + = t('authorize_follow.error') diff --git a/app/views/authorize_interactions/show.html.haml b/app/views/authorize_interactions/show.html.haml new file mode 100644 index 000000000..7ca9b98c1 --- /dev/null +++ b/app/views/authorize_interactions/show.html.haml @@ -0,0 +1,18 @@ +- content_for :page_title do + = t('authorize_follow.title', acct: @resource.acct) + +.form-container + .follow-prompt + = render 'application/card', account: @resource + + - if current_account.following?(@resource) + .flash-message + %strong + = t('authorize_follow.already_following') + + = render 'post_follow_actions' + - else + = form_tag authorize_interaction_path, method: :post, class: 'simple_form' do + = hidden_field_tag :action, :follow + = hidden_field_tag :acct, @resource.acct + = button_tag t('authorize_follow.follow'), type: :submit diff --git a/app/views/authorize_interactions/success.html.haml b/app/views/authorize_interactions/success.html.haml new file mode 100644 index 000000000..47fd09767 --- /dev/null +++ b/app/views/authorize_interactions/success.html.haml @@ -0,0 +1,13 @@ +- content_for :page_title do + = t('authorize_follow.title', acct: @resource.acct) + +.form-container + .follow-prompt + - if @resource.locked? + %h2= t('authorize_follow.follow_request') + - else + %h2= t('authorize_follow.following') + + = render 'application/card', account: @resource + + = render 'post_follow_actions' diff --git a/app/views/layouts/modal.html.haml b/app/views/layouts/modal.html.haml index 325b4ec72..b73068459 100644 --- a/app/views/layouts/modal.html.haml +++ b/app/views/layouts/modal.html.haml @@ -2,7 +2,7 @@ = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous' - content_for :content do - - if user_signed_in? + - if user_signed_in? && !@hide_header .account-header .avatar= image_tag current_account.avatar.url(:original) .name diff --git a/app/views/remote_interaction/new.html.haml b/app/views/remote_interaction/new.html.haml new file mode 100644 index 000000000..7357546b6 --- /dev/null +++ b/app/views/remote_interaction/new.html.haml @@ -0,0 +1,17 @@ +.form-container + .follow-prompt + %h2= t('remote_interaction.prompt') + + .public-layout + .activity-stream.activity-stream--highlighted + = render 'stream_entries/status', status: @status + + = simple_form_for @remote_follow, as: :remote_follow, url: remote_interaction_path(@status) do |f| + = render 'shared/error_messages', object: @remote_follow + + = f.input :acct, placeholder: t('remote_follow.acct'), input_html: { autocapitalize: 'none', autocorrect: 'off' } + + .actions + = f.button :button, t('remote_interaction.proceed'), type: :submit + + %p.hint.subtle-hint= t('remote_follow.no_account_html', sign_up_path: open_registrations? ? new_user_registration_path : 'https://joinmastodon.org/#getting-started') diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/stream_entries/_detailed_status.html.haml index aa160b979..a7c767816 100644 --- a/app/views/stream_entries/_detailed_status.html.haml +++ b/app/views/stream_entries/_detailed_status.html.haml @@ -39,6 +39,11 @@ - else = link_to status.application.name, status.application.website, class: 'detailed-status__application', target: '_blank', rel: 'noopener' · + = link_to remote_interaction_path(status), class: 'modal-button detailed-status__link' do + = fa_icon('reply') + %span.detailed-status__reblogs>= number_to_human status.replies_count, strip_insignificant_zeros: true + = " " + · - if status.direct_visibility? %span.detailed-status__link< = fa_icon('envelope') @@ -46,13 +51,15 @@ %span.detailed-status__link< = fa_icon('lock') - else - %span.detailed-status__link< + = link_to remote_interaction_path(status), class: 'modal-button detailed-status__link' do = fa_icon('retweet') - %span.detailed-status__reblogs= number_to_human status.reblogs_count, strip_insignificant_zeros: true + %span.detailed-status__reblogs>= number_to_human status.reblogs_count, strip_insignificant_zeros: true + = " " · - %span.detailed-status__link< + = link_to remote_interaction_path(status), class: 'modal-button detailed-status__link' do = fa_icon('star') - %span.detailed-status__favorites= number_to_human status.favourites_count, strip_insignificant_zeros: true + %span.detailed-status__favorites>= number_to_human status.favourites_count, strip_insignificant_zeros: true + = " " - if user_signed_in? · diff --git a/app/views/stream_entries/_simple_status.html.haml b/app/views/stream_entries/_simple_status.html.haml index 676d367ca..ec8b69bb6 100644 --- a/app/views/stream_entries/_simple_status.html.haml +++ b/app/views/stream_entries/_simple_status.html.haml @@ -29,14 +29,16 @@ = react_component :media_gallery, height: 343, sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } .status__action-bar - .status__action-bar-button.static-icon-button< + .status__action-bar__counter + = link_to remote_interaction_path(status), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do + = fa_icon 'reply fw' + .status__action-bar__counter__label= obscured_counter status.replies_count + = link_to remote_interaction_path(status), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do - if status.public_visibility? || status.unlisted_visibility? = fa_icon 'retweet fw' - %span.detailed-status__reblogs= number_to_human status.reblogs_count, strip_insignificant_zeros: true - elsif status.private_visibility? = fa_icon 'lock fw' - else = fa_icon 'envelope fw' - .status__action-bar-button.static-icon-button< + = link_to remote_interaction_path(status), class: 'status__action-bar-button icon-button modal-button', style: 'font-size: 18px; width: 23.1429px; height: 23.1429px; line-height: 23.15px;' do = fa_icon 'star fw' - %span.detailed-status__favorites= number_to_human status.favourites_count, strip_insignificant_zeros: true diff --git a/app/views/stream_entries/show.html.haml b/app/views/stream_entries/show.html.haml index 9da6245dc..2edc155bf 100644 --- a/app/views/stream_entries/show.html.haml +++ b/app/views/stream_entries/show.html.haml @@ -19,7 +19,7 @@ .grid .column-0 - .activity-stream.activity-stream-headless.h-entry + .activity-stream.h-entry = render partial: "stream_entries/#{@type}", locals: { @type.to_sym => @stream_entry.activity, include_threads: true } .column-1 = render 'application/sidebar' diff --git a/app/views/well_known/webfinger/show.xml.ruby b/app/views/well_known/webfinger/show.xml.ruby index 4352a24e9..968c8c138 100644 --- a/app/views/well_known/webfinger/show.xml.ruby +++ b/app/views/well_known/webfinger/show.xml.ruby @@ -37,7 +37,7 @@ doc << Ox::Element.new('XRD').tap do |xrd| xrd << Ox::Element.new('Link').tap do |link| link['rel'] = 'http://ostatus.org/schema/1.0/subscribe' - link['template'] = "#{authorize_follow_url}?acct={uri}" + link['template'] = "#{authorize_interaction_url}?acct={uri}" end end diff --git a/config/brakeman.ignore b/config/brakeman.ignore index e8956639c..40fef7283 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -1,5 +1,25 @@ { "ignored_warnings": [ + { + "warning_type": "SQL Injection", + "warning_code": 0, + "fingerprint": "04dbbc249b989db2e0119bbb0f59c9818e12889d2b97c529cdc0b1526002ba4b", + "check_name": "SQL", + "message": "Possible SQL injection", + "file": "app/models/report.rb", + "line": 86, + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", + "code": "Admin::ActionLog.from(\"(#{[Admin::ActionLog.where(:target_type => \"Report\", :target_id => id, :created_at => ((created_at..updated_at))).unscope(:order), Admin::ActionLog.where(:target_type => \"Account\", :target_id => target_account_id, :created_at => ((created_at..updated_at))).unscope(:order), Admin::ActionLog.where(:target_type => \"Status\", :target_id => status_ids, :created_at => ((created_at..updated_at))).unscope(:order)].map do\n \"(#{query.to_sql})\"\n end.join(\" UNION ALL \")}) AS admin_action_logs\")", + "render_path": null, + "location": { + "type": "method", + "class": "Report", + "method": "history" + }, + "user_input": "Admin::ActionLog.where(:target_type => \"Status\", :target_id => status_ids, :created_at => ((created_at..updated_at))).unscope(:order)", + "confidence": "High", + "note": "" + }, { "warning_type": "Cross-Site Scripting", "warning_code": 4, @@ -7,8 +27,8 @@ "check_name": "LinkToHref", "message": "Potentially unsafe model attribute in link_to href", "file": "app/views/admin/accounts/show.html.haml", - "line": 147, - "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", + "line": 167, + "link": "https://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).inbox_url, Account.find(params[:id]).inbox_url)", "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { @@ -26,8 +46,8 @@ "check_name": "LinkToHref", "message": "Potentially unsafe model attribute in link_to href", "file": "app/views/admin/accounts/show.html.haml", - "line": 153, - "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", + "line": 173, + "link": "https://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).shared_inbox_url, Account.find(params[:id]).shared_inbox_url)", "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { @@ -45,8 +65,8 @@ "check_name": "LinkToHref", "message": "Potentially unsafe model attribute in link_to href", "file": "app/views/admin/accounts/show.html.haml", - "line": 57, - "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", + "line": 75, + "link": "https://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).url, Account.find(params[:id]).url)", "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { @@ -57,6 +77,26 @@ "confidence": "Weak", "note": "" }, + { + "warning_type": "Mass Assignment", + "warning_code": 105, + "fingerprint": "28d81cc22580ef76e912b077b245f353499aa27b3826476667224c00227af2a9", + "check_name": "PermitAttributes", + "message": "Potentially dangerous key allowed for mass assignment", + "file": "app/controllers/admin/reports_controller.rb", + "line": 86, + "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/", + "code": "params.permit(:account_id, :resolved, :target_account_id)", + "render_path": null, + "location": { + "type": "method", + "class": "Admin::ReportsController", + "method": "filter_params" + }, + "user_input": ":account_id", + "confidence": "High", + "note": "" + }, { "warning_type": "Dynamic Render Path", "warning_code": 15, @@ -65,9 +105,9 @@ "message": "Render path contains parameter value", "file": "app/views/stream_entries/embed.html.haml", "line": 3, - "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", "code": "render(action => \"stream_entries/#{Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase}\", { Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase.to_sym => Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity, :centered => true })", - "render_path": [{"type":"controller","class":"StatusesController","method":"embed","line":45,"file":"app/controllers/statuses_controller.rb"}], + "render_path": [{"type":"controller","class":"StatusesController","method":"embed","line":58,"file":"app/controllers/statuses_controller.rb"}], "location": { "type": "template", "template": "stream_entries/embed" @@ -83,8 +123,8 @@ "check_name": "Render", "message": "Render path contains parameter value", "file": "app/views/admin/action_logs/index.html.haml", - "line": 5, - "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "line": 4, + "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", "code": "render(action => Admin::ActionLog.page(params[:page]), {})", "render_path": [{"type":"controller","class":"Admin::ActionLogsController","method":"index","line":7,"file":"app/controllers/admin/action_logs_controller.rb"}], "location": { @@ -95,6 +135,26 @@ "confidence": "Weak", "note": "" }, + { + "warning_type": "Redirect", + "warning_code": 18, + "fingerprint": "5fad11cd67f905fab9b1d5739d01384a1748ebe78c5af5ac31518201925265a7", + "check_name": "Redirect", + "message": "Possible unprotected redirect", + "file": "app/controllers/remote_interaction_controller.rb", + "line": 20, + "link": "https://brakemanscanner.org/docs/warning_types/redirect/", + "code": "redirect_to(RemoteFollow.new(resource_params).interact_address_for(Status.find(params[:id])))", + "render_path": null, + "location": { + "type": "method", + "class": "RemoteInteractionController", + "method": "create" + }, + "user_input": "RemoteFollow.new(resource_params).interact_address_for(Status.find(params[:id]))", + "confidence": "High", + "note": "" + }, { "warning_type": "Cross-Site Scripting", "warning_code": 4, @@ -102,8 +162,8 @@ "check_name": "LinkToHref", "message": "Potentially unsafe model attribute in link_to href", "file": "app/views/admin/accounts/show.html.haml", - "line": 156, - "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", + "line": 176, + "link": "https://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).followers_url, Account.find(params[:id]).followers_url)", "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { @@ -121,8 +181,8 @@ "check_name": "LinkToHref", "message": "Potentially unsafe model attribute in link_to href", "file": "app/views/admin/accounts/show.html.haml", - "line": 130, - "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", + "line": 149, + "link": "https://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).salmon_url, Account.find(params[:id]).salmon_url)", "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { @@ -141,7 +201,7 @@ "message": "Render path contains parameter value", "file": "app/views/admin/custom_emojis/index.html.haml", "line": 45, - "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", "code": "render(action => filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page]), {})", "render_path": [{"type":"controller","class":"Admin::CustomEmojisController","method":"index","line":11,"file":"app/controllers/admin/custom_emojis_controller.rb"}], "location": { @@ -160,7 +220,7 @@ "message": "Possible SQL injection", "file": "lib/mastodon/snowflake.rb", "line": 87, - "link": "http://brakemanscanner.org/docs/warning_types/sql_injection/", + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", "code": "connection.execute(\" CREATE OR REPLACE FUNCTION timestamp_id(table_name text)\\n RETURNS bigint AS\\n $$\\n DECLARE\\n time_part bigint;\\n sequence_base bigint;\\n tail bigint;\\n BEGIN\\n time_part := (\\n -- Get the time in milliseconds\\n ((date_part('epoch', now()) * 1000))::bigint\\n -- And shift it over two bytes\\n << 16);\\n\\n sequence_base := (\\n 'x' ||\\n -- Take the first two bytes (four hex characters)\\n substr(\\n -- Of the MD5 hash of the data we documented\\n md5(table_name ||\\n '#{SecureRandom.hex(16)}' ||\\n time_part::text\\n ),\\n 1, 4\\n )\\n -- And turn it into a bigint\\n )::bit(16)::bigint;\\n\\n -- Finally, add our sequence number to our base, and chop\\n -- it to the last two bytes\\n tail := (\\n (sequence_base + nextval(table_name || '_id_seq'))\\n & 65535);\\n\\n -- Return the time part and the sequence part. OR appears\\n -- faster here than addition, but they're equivalent:\\n -- time_part has no trailing two bytes, and tail is only\\n -- the last two bytes.\\n RETURN time_part | tail;\\n END\\n $$ LANGUAGE plpgsql VOLATILE;\\n\")", "render_path": null, "location": { @@ -180,7 +240,7 @@ "message": "Render path contains parameter value", "file": "app/views/admin/accounts/index.html.haml", "line": 67, - "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", "code": "render(action => filtered_accounts.page(params[:page]), {})", "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"index","line":12,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { @@ -191,25 +251,6 @@ "confidence": "Weak", "note": "" }, - { - "warning_type": "Cross-Site Request Forgery", - "warning_code": 7, - "fingerprint": "ab491f72606337a348482d006eb67a3b1616685fd48644d5ac909bbcd62a5000", - "check_name": "ForgerySetting", - "message": "'protect_from_forgery' should be called in WellKnown::HostMetaController", - "file": "app/controllers/well_known/host_meta_controller.rb", - "line": 4, - "link": "http://brakemanscanner.org/docs/warning_types/cross-site_request_forgery/", - "code": null, - "render_path": null, - "location": { - "type": "controller", - "controller": "WellKnown::HostMetaController" - }, - "user_input": null, - "confidence": "High", - "note": "" - }, { "warning_type": "Redirect", "warning_code": 18, @@ -218,7 +259,7 @@ "message": "Possible unprotected redirect", "file": "app/controllers/media_controller.rb", "line": 10, - "link": "http://brakemanscanner.org/docs/warning_types/redirect/", + "link": "https://brakemanscanner.org/docs/warning_types/redirect/", "code": "redirect_to(MediaAttachment.attached.find_by!(:shortcode => ((params[:id] or params[:medium_id]))).file.url(:original))", "render_path": null, "location": { @@ -237,8 +278,8 @@ "check_name": "LinkToHref", "message": "Potentially unsafe model attribute in link_to href", "file": "app/views/admin/accounts/show.html.haml", - "line": 119, - "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", + "line": 138, + "link": "https://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).remote_url, Account.find(params[:id]).remote_url)", "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { @@ -256,8 +297,8 @@ "check_name": "Redirect", "message": "Possible unprotected redirect", "file": "app/controllers/remote_follow_controller.rb", - "line": 18, - "link": "http://brakemanscanner.org/docs/warning_types/redirect/", + "line": 19, + "link": "https://brakemanscanner.org/docs/warning_types/redirect/", "code": "redirect_to(RemoteFollow.new(resource_params).subscribe_address_for(Account.find_local!(params[:account_username])))", "render_path": null, "location": { @@ -276,8 +317,8 @@ "check_name": "Render", "message": "Render path contains parameter value", "file": "app/views/admin/reports/index.html.haml", - "line": 25, - "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "line": 22, + "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", "code": "render(action => filtered_reports.page(params[:page]), {})", "render_path": [{"type":"controller","class":"Admin::ReportsController","method":"index","line":10,"file":"app/controllers/admin/reports_controller.rb"}], "location": { @@ -288,25 +329,6 @@ "confidence": "Weak", "note": "" }, - { - "warning_type": "Cross-Site Request Forgery", - "warning_code": 7, - "fingerprint": "d4278f04e807ec58a23925f8ab31fad5e84692f2fb9f2f57e7931aff05d57cf8", - "check_name": "ForgerySetting", - "message": "'protect_from_forgery' should be called in WellKnown::WebfingerController", - "file": "app/controllers/well_known/webfinger_controller.rb", - "line": 4, - "link": "http://brakemanscanner.org/docs/warning_types/cross-site_request_forgery/", - "code": null, - "render_path": null, - "location": { - "type": "controller", - "controller": "WellKnown::WebfingerController" - }, - "user_input": null, - "confidence": "High", - "note": "" - }, { "warning_type": "Cross-Site Scripting", "warning_code": 4, @@ -314,8 +336,8 @@ "check_name": "LinkToHref", "message": "Potentially unsafe model attribute in link_to href", "file": "app/views/admin/accounts/show.html.haml", - "line": 150, - "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", + "line": 170, + "link": "https://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).outbox_url, Account.find(params[:id]).outbox_url)", "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":18,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { @@ -326,6 +348,26 @@ "confidence": "Weak", "note": "" }, + { + "warning_type": "Mass Assignment", + "warning_code": 105, + "fingerprint": "e867661b2c9812bc8b75a5df12b28e2a53ab97015de0638b4e732fe442561b28", + "check_name": "PermitAttributes", + "message": "Potentially dangerous key allowed for mass assignment", + "file": "app/controllers/api/v1/reports_controller.rb", + "line": 42, + "link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/", + "code": "params.permit(:account_id, :comment, :forward, :status_ids => ([]))", + "render_path": null, + "location": { + "type": "method", + "class": "Api::V1::ReportsController", + "method": "report_params" + }, + "user_input": ":account_id", + "confidence": "High", + "note": "" + }, { "warning_type": "Dynamic Render Path", "warning_code": 15, @@ -333,10 +375,10 @@ "check_name": "Render", "message": "Render path contains parameter value", "file": "app/views/stream_entries/show.html.haml", - "line": 24, - "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "line": 23, + "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", "code": "render(partial => \"stream_entries/#{Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase}\", { :locals => ({ Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity_type.downcase.to_sym => Account.find_local!(params[:account_username]).statuses.find(params[:id]).stream_entry.activity, :include_threads => true }) })", - "render_path": [{"type":"controller","class":"StatusesController","method":"show","line":22,"file":"app/controllers/statuses_controller.rb"}], + "render_path": [{"type":"controller","class":"StatusesController","method":"show","line":30,"file":"app/controllers/statuses_controller.rb"}], "location": { "type": "template", "template": "stream_entries/show" @@ -346,6 +388,6 @@ "note": "" } ], - "updated": "2018-02-16 06:42:53 +0100", - "brakeman_version": "4.0.1" + "updated": "2018-08-18 00:49:25 +0200", + "brakeman_version": "4.2.1" } diff --git a/config/locales/en.yml b/config/locales/en.yml index cc24a02cf..90086103c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -655,11 +655,14 @@ en: publishing: Publishing web: Web remote_follow: - acct: Enter your username@domain you want to follow from + acct: Enter your username@domain you want to act from missing_resource: Could not find the required redirect URL for your account no_account_html: Don't have an account? You can sign up here proceed: Proceed to follow prompt: 'You are going to follow:' + remote_interaction: + proceed: Proceed to interact + prompt: 'You want to interact with this toot:' remote_unfollow: error: Error title: Title diff --git a/config/routes.rb b/config/routes.rb index 2983011d2..fd3b5fe4b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -74,6 +74,9 @@ Rails.application.routes.draw do get '/@:account_username/:id', to: 'statuses#show', as: :short_account_status get '/@:account_username/:id/embed', to: 'statuses#embed', as: :embed_short_account_status + get '/interact/:id', to: 'remote_interaction#new', as: :remote_interaction + post '/interact/:id', to: 'remote_interaction#create' + namespace :settings do resource :profile, only: [:show, :update] resource :preferences, only: [:show, :update] @@ -120,7 +123,7 @@ Rails.application.routes.draw do # Remote follow resource :remote_unfollow, only: [:create] - resource :authorize_follow, only: [:show, :create] + resource :authorize_interaction, only: [:show, :create] resource :share, only: [:show, :create] namespace :admin do diff --git a/spec/controllers/authorize_follows_controller_spec.rb b/spec/controllers/authorize_follows_controller_spec.rb deleted file mode 100644 index 52971c724..000000000 --- a/spec/controllers/authorize_follows_controller_spec.rb +++ /dev/null @@ -1,110 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AuthorizeFollowsController do - render_views - - describe 'GET #show' do - describe 'when signed out' do - it 'redirects to sign in page' do - get :show - - expect(response).to redirect_to(new_user_session_path) - end - end - - describe 'when signed in' do - let(:user) { Fabricate(:user) } - let(:account) { Fabricate(:account, user: user) } - - before do - sign_in(user) - end - - it 'renders error without acct param' do - get :show - - expect(response).to render_template(:error) - end - - it 'renders error when account cant be found' do - service = double - allow(ResolveAccountService).to receive(:new).and_return(service) - allow(service).to receive(:call).with('missing@hostname').and_return(nil) - - get :show, params: { acct: 'acct:missing@hostname' } - - expect(response).to render_template(:error) - expect(service).to have_received(:call).with('missing@hostname') - end - - it 'sets account from url' do - account = Account.new - service = double - allow(FetchRemoteAccountService).to receive(:new).and_return(service) - allow(service).to receive(:call).with('http://example.com').and_return(account) - - get :show, params: { acct: 'http://example.com' } - - expect(response).to have_http_status(200) - expect(assigns(:account)).to eq account - end - - it 'sets account from acct uri' do - account = Account.new - service = double - allow(ResolveAccountService).to receive(:new).and_return(service) - allow(service).to receive(:call).with('found@hostname').and_return(account) - - get :show, params: { acct: 'acct:found@hostname' } - - expect(response).to have_http_status(200) - expect(assigns(:account)).to eq account - end - end - end - - describe 'POST #create' do - describe 'when signed out' do - it 'redirects to sign in page' do - post :create - - expect(response).to redirect_to(new_user_session_path) - end - end - - describe 'when signed in' do - let(:user) { Fabricate(:user) } - let(:account) { Fabricate(:account, user: user) } - - before do - sign_in(user) - end - - it 'shows error when account not found' do - service = double - allow(FollowService).to receive(:new).and_return(service) - allow(service).to receive(:call).with(account, 'user@hostname').and_return(nil) - - post :create, params: { acct: 'acct:user@hostname' } - - expect(service).to have_received(:call).with(account, 'user@hostname') - expect(response).to render_template(:error) - end - - it 'follows account when found' do - target_account = Fabricate(:account) - result_account = double(target_account: target_account) - service = double - allow(FollowService).to receive(:new).and_return(service) - allow(service).to receive(:call).with(account, 'user@hostname').and_return(result_account) - - post :create, params: { acct: 'acct:user@hostname' } - - expect(service).to have_received(:call).with(account, 'user@hostname') - expect(response).to render_template(:success) - end - end - end -end diff --git a/spec/controllers/authorize_interactions_controller_spec.rb b/spec/controllers/authorize_interactions_controller_spec.rb new file mode 100644 index 000000000..81fd9ceb7 --- /dev/null +++ b/spec/controllers/authorize_interactions_controller_spec.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe AuthorizeInteractionsController do + render_views + + describe 'GET #show' do + describe 'when signed out' do + it 'redirects to sign in page' do + get :show + + expect(response).to redirect_to(new_user_session_path) + end + end + + describe 'when signed in' do + let(:user) { Fabricate(:user) } + let(:account) { Fabricate(:account, user: user) } + + before do + sign_in(user) + end + + it 'renders error without acct param' do + get :show + + expect(response).to render_template(:error) + end + + it 'renders error when account cant be found' do + service = double + allow(ResolveAccountService).to receive(:new).and_return(service) + allow(service).to receive(:call).with('missing@hostname').and_return(nil) + + get :show, params: { acct: 'acct:missing@hostname' } + + expect(response).to render_template(:error) + expect(service).to have_received(:call).with('missing@hostname') + end + + it 'sets resource from url' do + account = Account.new + service = double + allow(ResolveURLService).to receive(:new).and_return(service) + allow(service).to receive(:call).with('http://example.com').and_return(account) + + get :show, params: { acct: 'http://example.com' } + + expect(response).to have_http_status(200) + expect(assigns(:resource)).to eq account + end + + it 'sets resource from acct uri' do + account = Account.new + service = double + allow(ResolveAccountService).to receive(:new).and_return(service) + allow(service).to receive(:call).with('found@hostname').and_return(account) + + get :show, params: { acct: 'acct:found@hostname' } + + expect(response).to have_http_status(200) + expect(assigns(:resource)).to eq account + end + end + end + + describe 'POST #create' do + describe 'when signed out' do + it 'redirects to sign in page' do + post :create + + expect(response).to redirect_to(new_user_session_path) + end + end + + describe 'when signed in' do + let!(:user) { Fabricate(:user) } + let!(:account) { user.account } + + before do + sign_in(user) + end + + it 'shows error when account not found' do + service = double + + allow(ResolveAccountService).to receive(:new).and_return(service) + allow(service).to receive(:call).with('user@hostname').and_return(nil) + + post :create, params: { acct: 'acct:user@hostname' } + + expect(response).to render_template(:error) + end + + it 'follows account when found' do + target_account = Fabricate(:account) + service = double + + allow(ResolveAccountService).to receive(:new).and_return(service) + allow(service).to receive(:call).with('user@hostname').and_return(target_account) + + post :create, params: { acct: 'acct:user@hostname' } + + expect(service).to have_received(:call).with('user@hostname') + expect(account.following?(target_account)).to be true + expect(response).to render_template(:success) + end + end + end +end diff --git a/spec/controllers/intents_controller_spec.rb b/spec/controllers/intents_controller_spec.rb index 3dde7f835..ddfd5ea36 100644 --- a/spec/controllers/intents_controller_spec.rb +++ b/spec/controllers/intents_controller_spec.rb @@ -13,7 +13,7 @@ RSpec.describe IntentsController, type: :controller do context 'when host is follow' do let(:uri) { 'web+mastodon://follow?uri=test' } - it { is_expected.to redirect_to authorize_follow_path(acct: 'test') } + it { is_expected.to redirect_to authorize_interaction_path(uri: 'test') } end context 'when host is share' do -- cgit From 85bb32c410a975bf6154a78a82797f82713e2428 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 18 Aug 2018 12:48:27 +0200 Subject: Add "sign in to participate" message to public toot page (#8200) --- app/javascript/styles/mastodon/stream_entries.scss | 12 ++++++++---- app/views/stream_entries/_status.html.haml | 6 ++++++ config/locales/en.yml | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) (limited to 'config') diff --git a/app/javascript/styles/mastodon/stream_entries.scss b/app/javascript/styles/mastodon/stream_entries.scss index 03bbd84db..5aa809f76 100644 --- a/app/javascript/styles/mastodon/stream_entries.scss +++ b/app/javascript/styles/mastodon/stream_entries.scss @@ -37,7 +37,8 @@ &:last-child { .detailed-status, - .status { + .status, + .load-more { border-bottom: 0; border-radius: 0 0 4px 4px; } @@ -45,13 +46,15 @@ &:first-child { .detailed-status, - .status { + .status, + .load-more { border-radius: 4px 4px 0 0; } &:last-child { .detailed-status, - .status { + .status, + .load-more { border-radius: 4px; } } @@ -59,7 +62,8 @@ @media screen and (max-width: 740px) { .detailed-status, - .status { + .status, + .load-more { border-radius: 0 !important; } } diff --git a/app/views/stream_entries/_status.html.haml b/app/views/stream_entries/_status.html.haml index 320c9bc4f..92003a48f 100644 --- a/app/views/stream_entries/_status.html.haml +++ b/app/views/stream_entries/_status.html.haml @@ -53,3 +53,9 @@ - if @next_descendant_thread .entry{ class: entry_classes } = link_to_more short_account_status_url(status.account.username, status, since_descendant_thread_id: @max_descendant_thread_id - 1) + +- if include_threads && !embedded_view? && !user_signed_in? + .entry{ class: entry_classes } + = link_to new_user_session_path, class: 'load-more load-gap' do + = fa_icon 'comments' + = t('statuses.sign_in_to_participate') diff --git a/config/locales/en.yml b/config/locales/en.yml index 90086103c..66ab8f10a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -746,6 +746,7 @@ en: private: Non-public toot cannot be pinned reblog: A boost cannot be pinned show_more: Show more + sign_in_to_participate: Sign in to participate in the conversation title: '%{name}: "%{quote}"' visibilities: private: Followers-only -- cgit