Merge remote-tracking branch 'parent/main' into upstream-20240507
This commit is contained in:
commit
89b71363ae
70 changed files with 1739 additions and 445 deletions
|
@ -9,7 +9,7 @@ module Admin
|
|||
|
||||
@site_upload.destroy!
|
||||
|
||||
redirect_to admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
|
||||
redirect_back fallback_location: admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -9,16 +9,22 @@ class Api::V1::AccountsController < Api::BaseController
|
|||
before_action -> { doorkeeper_authorize! :follow, :write, :'write:blocks' }, only: [:block, :unblock]
|
||||
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:create]
|
||||
|
||||
before_action :require_user!, except: [:show, :create]
|
||||
before_action :set_account, except: [:create]
|
||||
before_action :check_account_approval, except: [:create]
|
||||
before_action :check_account_confirmation, except: [:create]
|
||||
before_action :require_user!, except: [:index, :show, :create]
|
||||
before_action :set_account, except: [:index, :create]
|
||||
before_action :set_accounts, only: [:index]
|
||||
before_action :check_account_approval, except: [:index, :create]
|
||||
before_action :check_account_confirmation, except: [:index, :create]
|
||||
before_action :check_enabled_registrations, only: [:create]
|
||||
before_action :check_accounts_limit, only: [:index]
|
||||
|
||||
skip_before_action :require_authenticated_user!, only: :create
|
||||
|
||||
override_rate_limit_headers :follow, family: :follows
|
||||
|
||||
def index
|
||||
render json: @accounts, each_serializer: REST::AccountSerializer
|
||||
end
|
||||
|
||||
def show
|
||||
cache_if_unauthenticated!
|
||||
render json: @account, serializer: REST::AccountSerializer
|
||||
|
@ -84,6 +90,10 @@ class Api::V1::AccountsController < Api::BaseController
|
|||
@account = Account.find(params[:id])
|
||||
end
|
||||
|
||||
def set_accounts
|
||||
@accounts = Account.where(id: account_ids).without_unapproved
|
||||
end
|
||||
|
||||
def check_account_approval
|
||||
raise(ActiveRecord::RecordNotFound) if @account.local? && @account.user_pending?
|
||||
end
|
||||
|
@ -92,10 +102,22 @@ class Api::V1::AccountsController < Api::BaseController
|
|||
raise(ActiveRecord::RecordNotFound) if @account.local? && !@account.user_confirmed?
|
||||
end
|
||||
|
||||
def check_accounts_limit
|
||||
raise(Mastodon::ValidationError) if account_ids.size > DEFAULT_ACCOUNTS_LIMIT
|
||||
end
|
||||
|
||||
def relationships(**options)
|
||||
AccountRelationshipsPresenter.new([@account], current_user.account_id, **options)
|
||||
end
|
||||
|
||||
def account_ids
|
||||
Array(accounts_params[:ids]).uniq.map(&:to_i)
|
||||
end
|
||||
|
||||
def accounts_params
|
||||
params.permit(ids: [])
|
||||
end
|
||||
|
||||
def account_params
|
||||
params.permit(:username, :email, :password, :agreement, :locale, :reason, :time_zone, :invite_code)
|
||||
end
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Push::SubscriptionsController < Api::BaseController
|
||||
include Redisable
|
||||
include Lockable
|
||||
|
||||
before_action -> { doorkeeper_authorize! :push }
|
||||
before_action :require_user!
|
||||
before_action :set_push_subscription
|
||||
before_action :set_push_subscription, only: [:show, :update]
|
||||
before_action :check_push_subscription, only: [:show, :update]
|
||||
|
||||
def show
|
||||
|
@ -11,16 +14,18 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
|
|||
end
|
||||
|
||||
def create
|
||||
@push_subscription&.destroy!
|
||||
with_redis_lock("push_subscription:#{current_user.id}") do
|
||||
destroy_web_push_subscriptions!
|
||||
|
||||
@push_subscription = Web::PushSubscription.create!(
|
||||
endpoint: subscription_params[:endpoint],
|
||||
key_p256dh: subscription_params[:keys][:p256dh],
|
||||
key_auth: subscription_params[:keys][:auth],
|
||||
data: data_params,
|
||||
user_id: current_user.id,
|
||||
access_token_id: doorkeeper_token.id
|
||||
)
|
||||
@push_subscription = Web::PushSubscription.create!(
|
||||
endpoint: subscription_params[:endpoint],
|
||||
key_p256dh: subscription_params[:keys][:p256dh],
|
||||
key_auth: subscription_params[:keys][:auth],
|
||||
data: data_params,
|
||||
user_id: current_user.id,
|
||||
access_token_id: doorkeeper_token.id
|
||||
)
|
||||
end
|
||||
|
||||
render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer
|
||||
end
|
||||
|
@ -31,14 +36,18 @@ class Api::V1::Push::SubscriptionsController < Api::BaseController
|
|||
end
|
||||
|
||||
def destroy
|
||||
@push_subscription&.destroy!
|
||||
destroy_web_push_subscriptions!
|
||||
render_empty
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def destroy_web_push_subscriptions!
|
||||
doorkeeper_token.web_push_subscriptions.destroy_all
|
||||
end
|
||||
|
||||
def set_push_subscription
|
||||
@push_subscription = Web::PushSubscription.find_by(access_token_id: doorkeeper_token.id)
|
||||
@push_subscription = doorkeeper_token.web_push_subscriptions.first
|
||||
end
|
||||
|
||||
def check_push_subscription
|
||||
|
|
|
@ -5,9 +5,11 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
|
||||
before_action -> { authorize_if_got_token! :read, :'read:statuses' }, except: [:create, :update, :destroy]
|
||||
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:create, :update, :destroy]
|
||||
before_action :require_user!, except: [:show, :context]
|
||||
before_action :set_status, only: [:show, :context]
|
||||
before_action :set_thread, only: [:create]
|
||||
before_action :require_user!, except: [:index, :show, :context]
|
||||
before_action :set_statuses, only: [:index]
|
||||
before_action :set_status, only: [:show, :context]
|
||||
before_action :set_thread, only: [:create]
|
||||
before_action :check_statuses_limit, only: [:index]
|
||||
|
||||
override_rate_limit_headers :create, family: :statuses
|
||||
override_rate_limit_headers :update, family: :statuses
|
||||
|
@ -23,6 +25,11 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
DESCENDANTS_LIMIT = 60
|
||||
DESCENDANTS_DEPTH_LIMIT = 20
|
||||
|
||||
def index
|
||||
@statuses = cache_collection(@statuses, Status)
|
||||
render json: @statuses, each_serializer: REST::StatusSerializer
|
||||
end
|
||||
|
||||
def show
|
||||
cache_if_unauthenticated!
|
||||
@status = cache_collection([@status], Status).first
|
||||
|
@ -125,6 +132,10 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
|
||||
private
|
||||
|
||||
def set_statuses
|
||||
@statuses = Status.permitted_statuses_from_ids(status_ids, current_account)
|
||||
end
|
||||
|
||||
def set_status
|
||||
@status = Status.find(params[:id])
|
||||
authorize @status, :show?
|
||||
|
@ -139,6 +150,18 @@ class Api::V1::StatusesController < Api::BaseController
|
|||
render json: { error: I18n.t('statuses.errors.in_reply_not_found') }, status: 404
|
||||
end
|
||||
|
||||
def check_statuses_limit
|
||||
raise(Mastodon::ValidationError) if status_ids.size > DEFAULT_STATUSES_LIMIT
|
||||
end
|
||||
|
||||
def status_ids
|
||||
Array(statuses_params[:ids]).uniq.map(&:to_i)
|
||||
end
|
||||
|
||||
def statuses_params
|
||||
params.permit(ids: [])
|
||||
end
|
||||
|
||||
def status_params
|
||||
params.permit(
|
||||
:status,
|
||||
|
|
23
app/controllers/well_known/oauth_metadata_controller.rb
Normal file
23
app/controllers/well_known/oauth_metadata_controller.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module WellKnown
|
||||
class OauthMetadataController < ActionController::Base # rubocop:disable Rails/ApplicationController
|
||||
include CacheConcern
|
||||
|
||||
# Prevent `active_model_serializer`'s `ActionController::Serialization` from calling `current_user`
|
||||
# and thus re-issuing session cookies
|
||||
serialization_scope nil
|
||||
|
||||
def show
|
||||
# Due to this document potentially changing between Mastodon versions (as
|
||||
# new OAuth scopes are added), we don't use expires_in to cache upstream,
|
||||
# instead just caching in the rails cache:
|
||||
render_with_cache(
|
||||
json: ::OauthMetadataPresenter.new,
|
||||
serializer: ::OauthMetadataSerializer,
|
||||
content_type: 'application/json',
|
||||
expires_in: 15.minutes
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -251,9 +251,14 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def prerender_custom_emojis_from_hash(html, custom_emojis_hash)
|
||||
# rubocop:disable Style/OpenStructUse
|
||||
prerender_custom_emojis(html, JSON.parse([custom_emojis_hash].to_json, object_class: OpenStruct))
|
||||
# rubocop:enable Style/OpenStructUse
|
||||
prerender_custom_emojis(html, JSON.parse([custom_emojis_hash].to_json, object_class: OpenStruct)) # rubocop:disable Style/OpenStructUse
|
||||
end
|
||||
|
||||
def site_icon_path(type, size = '48')
|
||||
icon = SiteUpload.find_by(var: type)
|
||||
return nil unless icon
|
||||
|
||||
icon.file.url(size)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"about.domain_blocks.no_reason_available": "السبب غير متوفر",
|
||||
"about.domain_blocks.preamble": "يسمح لك ماستدون عموماً بعرض المحتوى من المستخدمين من أي خادم آخر في الفدرالية والتفاعل معهم. وهذه هي الاستثناءات التي وضعت على هذا الخادم بالذات.",
|
||||
"about.domain_blocks.silenced.explanation": "عموماً، لن ترى ملفات التعريف والمحتوى من هذا الخادم، إلا إذا كنت تبحث عنه بشكل صريح أو تختار أن تتابعه.",
|
||||
"about.domain_blocks.silenced.title": "تم كتمه",
|
||||
"about.domain_blocks.silenced.title": "محدود",
|
||||
"about.domain_blocks.suspended.explanation": "لن يتم معالجة أي بيانات من هذا الخادم أو تخزينها أو تبادلها، مما يجعل أي تفاعل أو اتصال مع المستخدمين من هذا الخادم مستحيلا.",
|
||||
"about.domain_blocks.suspended.title": "مُعلّق",
|
||||
"about.not_available": "لم يتم توفير هذه المعلومات على هذا الخادم.",
|
||||
|
@ -21,7 +21,7 @@
|
|||
"account.blocked": "محظور",
|
||||
"account.browse_more_on_origin_server": "تصفح المزيد في الملف الشخصي الأصلي",
|
||||
"account.cancel_follow_request": "إلغاء طلب المتابعة",
|
||||
"account.copy": "نسخ الرابط إلى الملف الشخصي",
|
||||
"account.copy": "نسخ الرابط إلى الحساب",
|
||||
"account.direct": "إشارة خاصة لـ @{name}",
|
||||
"account.disable_notifications": "توقف عن إشعاري عندما ينشر @{name}",
|
||||
"account.domain_blocked": "اسم النِّطاق محظور",
|
||||
|
@ -32,7 +32,7 @@
|
|||
"account.featured_tags.last_status_never": "لا توجد رسائل",
|
||||
"account.featured_tags.title": "وسوم {name} المميَّزة",
|
||||
"account.follow": "متابعة",
|
||||
"account.follow_back": "تابعه بدورك",
|
||||
"account.follow_back": "رد المتابعة",
|
||||
"account.followers": "مُتابِعون",
|
||||
"account.followers.empty": "لا أحدَ يُتابع هذا المُستخدم إلى حد الآن.",
|
||||
"account.followers_counter": "{count, plural, zero{لا مُتابع} one {مُتابعٌ واحِد} two {مُتابعانِ اِثنان} few {{counter} مُتابِعين} many {{counter} مُتابِعًا} other {{counter} مُتابع}}",
|
||||
|
@ -89,12 +89,12 @@
|
|||
"announcement.announcement": "إعلان",
|
||||
"attachments_list.unprocessed": "(غير معالَج)",
|
||||
"audio.hide": "إخفاء المقطع الصوتي",
|
||||
"block_modal.remote_users_caveat": "Do t’i kërkojmë shërbyesit {domain} të respektojë vendimin tuaj. Por, pajtimi s’është i garantuar, ngaqë disa shërbyes mund t’i trajtojnë ndryshe bllokimet. Psotimet publike mundet të jenë ende të dukshme për përdorues pa bërë hyrje në llogari.",
|
||||
"block_modal.show_less": "اعرض أقلّ",
|
||||
"block_modal.remote_users_caveat": "سوف نطلب من الخادم {domain} أن يحترم قرارك، لكن الالتزام غير مضمون لأن بعض الخواديم قد تتعامل مع نصوص الكتل بشكل مختلف. قد تظل المنشورات العامة مرئية للمستخدمين غير المسجلين الدخول.",
|
||||
"block_modal.show_less": "أظهر الأقل",
|
||||
"block_modal.show_more": "أظهر المزيد",
|
||||
"block_modal.they_cant_mention": "لن يستطيع ذِكرك أو متابعتك.",
|
||||
"block_modal.they_cant_see_posts": "لن يستطيع رؤية منشوراتك ولن ترى منشوراته.",
|
||||
"block_modal.they_will_know": "يمكنه أن يرى أنه قد تم حجبه.",
|
||||
"block_modal.they_will_know": "يمكنه أن يرى أنه قد تم حظره.",
|
||||
"block_modal.title": "أتريد حظر المستخدم؟",
|
||||
"block_modal.you_wont_see_mentions": "لن تر المنشورات التي يُشار فيهم إليه.",
|
||||
"boost_modal.combo": "يُمكنك الضّغط على {combo} لتخطي هذا في المرة المُقبلة",
|
||||
|
@ -220,7 +220,7 @@
|
|||
"domain_pill.activitypub_lets_connect": "يتيح لك التواصل والتفاعل مع الناس ليس فقط على ماستدون، ولكن عبر تطبيقات اجتماعية مختلفة أيضا.",
|
||||
"domain_pill.activitypub_like_language": "إنّ ActivityPub مثل لغة ماستدون التي يتحدث بها مع شبكات اجتماعية أخرى.",
|
||||
"domain_pill.server": "الخادِم",
|
||||
"domain_pill.their_handle": "مُعرِّفُه:",
|
||||
"domain_pill.their_handle": "مُعرفه:",
|
||||
"domain_pill.their_server": "بيتهم الرقمي، حيث تُستضاف كافة منشوراتهم.",
|
||||
"domain_pill.their_username": "مُعرّفُهم الفريد على الخادم. من الممكن العثور على مستخدمين بنفس اسم المستخدم على خوادم مختلفة.",
|
||||
"domain_pill.username": "اسم المستخدم",
|
||||
|
@ -308,6 +308,8 @@
|
|||
"follow_suggestions.hints.similar_to_recently_followed": "هذا الملف الشخصي مشابه للملفات الشخصية التي تابعتها مؤخرا.",
|
||||
"follow_suggestions.personalized_suggestion": "توصية مخصصة",
|
||||
"follow_suggestions.popular_suggestion": "توصية رائجة",
|
||||
"follow_suggestions.popular_suggestion_longer": "رائج على {domain}",
|
||||
"follow_suggestions.similar_to_recently_followed_longer": "مشابهة لمواصفات الملفات الشخصية التي تابعتَها حديثًا",
|
||||
"follow_suggestions.view_all": "عرض الكل",
|
||||
"follow_suggestions.who_to_follow": "حسابات للمُتابَعة",
|
||||
"followed_tags": "الوسوم المتابَعة",
|
||||
|
@ -360,8 +362,8 @@
|
|||
"interaction_modal.title.reply": "الرد على منشور {name}",
|
||||
"intervals.full.days": "{number, plural, one {# يوم} other {# أيام}}",
|
||||
"intervals.full.hours": "{number, plural, one {# ساعة} other {# ساعات}}",
|
||||
"intervals.full.minutes": "{number, plural, one {# دقيقة} other {# دقائق}}",
|
||||
"keyboard_shortcuts.back": "للعودة",
|
||||
"intervals.full.minutes": "{number, plural, one {دقيقة واحدة}two {دقيقتان} other {# دقائق}}",
|
||||
"keyboard_shortcuts.back": "للرجوع",
|
||||
"keyboard_shortcuts.blocked": "لفتح قائمة المستخدمين المحظورين",
|
||||
"keyboard_shortcuts.boost": "لإعادة النشر",
|
||||
"keyboard_shortcuts.column": "للتركيز على منشور على أحد الأعمدة",
|
||||
|
@ -421,7 +423,9 @@
|
|||
"loading_indicator.label": "جاري التحميل…",
|
||||
"media_gallery.toggle_visible": "{number, plural, zero {} one {اخف الصورة} two {اخف الصورتين} few {اخف الصور} many {اخف الصور} other {اخف الصور}}",
|
||||
"moved_to_account_banner.text": "حسابك {disabledAccount} معطل حاليًا لأنك انتقلت إلى {movedToAccount}.",
|
||||
"mute_modal.hide_from_notifications": "إخفاء من قائمة الإشعارات",
|
||||
"mute_modal.hide_options": "إخفاء الخيارات",
|
||||
"mute_modal.indefinite": "إلى أن أفسخ كتمها",
|
||||
"mute_modal.show_options": "إظهار الخيارات",
|
||||
"mute_modal.they_can_mention_and_follow": "سيكون بإمكانه الإشارة إليك ومتابعتك، لكنك لن تره.",
|
||||
"mute_modal.they_wont_know": "لن يَعرف أنه قد تم كتمه.",
|
||||
|
@ -460,10 +464,20 @@
|
|||
"notification.follow": "يتابعك {name}",
|
||||
"notification.follow_request": "لقد طلب {name} متابعتك",
|
||||
"notification.mention": "{name} ذكرك",
|
||||
"notification.moderation-warning.learn_more": "اعرف المزيد",
|
||||
"notification.moderation_warning.action_disable": "تم تعطيل حسابك.",
|
||||
"notification.moderation_warning.action_mark_statuses_as_sensitive": "بعض من منشوراتك تم تصنيفها على أنها حساسة.",
|
||||
"notification.moderation_warning.action_none": "لقد تلقى حسابك تحذيرا بالإشراف.",
|
||||
"notification.moderation_warning.action_sensitive": "سيتم وضع علامة على منشوراتك على أنها حساسة من الآن فصاعدا.",
|
||||
"notification.moderation_warning.action_suspend": "لقد تم تعليق حسابك.",
|
||||
"notification.own_poll": "انتهى استطلاعك للرأي",
|
||||
"notification.poll": "لقد انتهى استطلاع رأي شاركتَ فيه",
|
||||
"notification.reblog": "قام {name} بمشاركة منشورك",
|
||||
"notification.relationships_severance_event": "فقدت الاتصالات مع {name}",
|
||||
"notification.relationships_severance_event.account_suspension": "قام مشرف من {from} بتعليق {target}، مما يعني أنك لم يعد بإمكانك تلقي التحديثات منهم أو التفاعل معهم.",
|
||||
"notification.relationships_severance_event.domain_block": "قام مشرف من {from} بحظر {target}، بما في ذلك {followersCount} من متابعينك و {followingCount, plural, one {# حساب} other {# حسابات}} تتابعها.",
|
||||
"notification.relationships_severance_event.learn_more": "اعرف المزيد",
|
||||
"notification.relationships_severance_event.user_domain_block": "لقد قمت بحظر {target}، مما أدى إلى إزالة {followersCount} من متابعينك و {followingCount, plural, one {# حساب} other {# حسابات}} تتابعها.",
|
||||
"notification.status": "{name} نشر للتو",
|
||||
"notification.update": "عدّلَ {name} منشورًا",
|
||||
"notification_requests.accept": "موافقة",
|
||||
|
@ -503,10 +517,15 @@
|
|||
"notifications.permission_denied": "تنبيهات سطح المكتب غير متوفرة بسبب رفض أذونات المتصفح مسبقاً",
|
||||
"notifications.permission_denied_alert": "لا يمكن تفعيل إشعارات سطح المكتب، لأن إذن المتصفح قد تم رفضه سابقاً",
|
||||
"notifications.permission_required": "إشعارات سطح المكتب غير متوفرة لأنه لم يتم منح الإذن المطلوب.",
|
||||
"notifications.policy.filter_new_accounts.hint": "تم إنشاؤها منذ {days, plural, zero {}one {يوم واحد} two {يومان} few {# أيام} many {# أيام} other {# أيام}}",
|
||||
"notifications.policy.filter_new_accounts_title": "حسابات جديدة",
|
||||
"notifications.policy.filter_not_followers_hint": "بما في ذلك الأشخاص الذين يتابعونك أقل من {days, plural, zero {}one {يوم واحد} two {يومان} few {# أيام} many {# أيام} other {# أيام}}",
|
||||
"notifications.policy.filter_not_followers_title": "أشخاص لا يتابعونك",
|
||||
"notifications.policy.filter_not_following_hint": "حتى توافق عليهم يدويا",
|
||||
"notifications.policy.filter_not_following_title": "أشخاص لا تتابعهم",
|
||||
"notifications.policy.filter_private_mentions_hint": "تمت تصفيته إلا إذا أن يكون ردًا على ذكرك أو إذا كنت تتابع الحساب",
|
||||
"notifications.policy.filter_private_mentions_title": "إشارات خاصة غير مرغوب فيها",
|
||||
"notifications.policy.title": "تصفية الإشعارات من…",
|
||||
"notifications_permission_banner.enable": "تفعيل إشعارات سطح المكتب",
|
||||
"notifications_permission_banner.how_to_control": "لتلقي الإشعارات عندما لا يكون ماستدون مفتوح، قم بتفعيل إشعارات سطح المكتب، يمكنك التحكم بدقة في أنواع التفاعلات التي تولد إشعارات سطح المكتب من خلال زر الـ{icon} أعلاه بمجرد تفعيلها.",
|
||||
"notifications_permission_banner.title": "لا تفوت شيئاً أبداً",
|
||||
|
@ -687,6 +706,7 @@
|
|||
"status.edited_x_times": "عُدّل {count, plural, zero {} one {مرةً واحدة} two {مرّتان} few {{count} مرات} many {{count} مرة} other {{count} مرة}}",
|
||||
"status.embed": "إدماج",
|
||||
"status.favourite": "فضّل",
|
||||
"status.favourites": "{count, plural, zero {}one {مفضلة واحدة} two {مفضلتان} few {# مفضلات} many {# مفضلات} other {# مفضلات}}",
|
||||
"status.filter": "تصفية هذه الرسالة",
|
||||
"status.filtered": "مُصفّى",
|
||||
"status.hide": "إخفاء المنشور",
|
||||
|
@ -707,6 +727,7 @@
|
|||
"status.reblog": "إعادة النشر",
|
||||
"status.reblog_private": "إعادة النشر إلى الجمهور الأصلي",
|
||||
"status.reblogged_by": "شارَكَه {name}",
|
||||
"status.reblogs": "{count, plural, one {تعزيز واحد} two {تعزيزتان} few {# تعزيزات} many {# تعزيزات} other {# تعزيزات}}",
|
||||
"status.reblogs.empty": "لم يقم أي أحد بمشاركة هذا المنشور بعد. عندما يقوم أحدهم بذلك سوف يظهر هنا.",
|
||||
"status.redraft": "إزالة وإعادة الصياغة",
|
||||
"status.remove_bookmark": "احذفه مِن الفواصل المرجعية",
|
||||
|
|
|
@ -331,7 +331,7 @@
|
|||
"footer.source_code": "Quellcode anzeigen",
|
||||
"footer.status": "Status",
|
||||
"generic.saved": "Gespeichert",
|
||||
"getting_started.heading": "Auf geht’s!",
|
||||
"getting_started.heading": "Auf gehts!",
|
||||
"hashtag.column_header.tag_mode.all": "und {additional}",
|
||||
"hashtag.column_header.tag_mode.any": "oder {additional}",
|
||||
"hashtag.column_header.tag_mode.none": "ohne {additional}",
|
||||
|
@ -400,7 +400,7 @@
|
|||
"keyboard_shortcuts.requests": "Liste der Follower-Anfragen aufrufen",
|
||||
"keyboard_shortcuts.search": "Suchleiste fokussieren",
|
||||
"keyboard_shortcuts.spoilers": "Feld für Inhaltswarnung anzeigen/ausblenden",
|
||||
"keyboard_shortcuts.start": "„Auf geht’s!“ öffnen",
|
||||
"keyboard_shortcuts.start": "„Auf gehts!“ öffnen",
|
||||
"keyboard_shortcuts.toggle_hidden": "Beitragstext hinter der Inhaltswarnung anzeigen/ausblenden",
|
||||
"keyboard_shortcuts.toggle_sensitivity": "Medien anzeigen/ausblenden",
|
||||
"keyboard_shortcuts.toot": "Neuen Beitrag erstellen",
|
||||
|
|
|
@ -578,6 +578,15 @@
|
|||
"notification.follow_request": "{name}さんがあなたにフォローリクエストしました",
|
||||
"notification.list_status": "{name}さんの投稿が{listName}に追加されました",
|
||||
"notification.mention": "{name}さんがあなたに返信しました",
|
||||
"notification.moderation-warning.learn_more": "さらに詳しく",
|
||||
"notification.moderation_warning": "あなたは管理者からの警告を受けています。",
|
||||
"notification.moderation_warning.action_delete_statuses": "あなたによるいくつかの投稿が削除されました。",
|
||||
"notification.moderation_warning.action_disable": "あなたのアカウントは無効になりました。",
|
||||
"notification.moderation_warning.action_mark_statuses_as_sensitive": "あなたの投稿のいくつかは閲覧注意として判定されています。",
|
||||
"notification.moderation_warning.action_none": "あなたのアカウントは管理者からの警告を受けています。",
|
||||
"notification.moderation_warning.action_sensitive": "あなたの投稿はこれから閲覧注意としてマークされます。",
|
||||
"notification.moderation_warning.action_silence": "あなたのアカウントは制限されています。",
|
||||
"notification.moderation_warning.action_suspend": "あなたのアカウントは停止されました。",
|
||||
"notification.own_poll": "アンケートが終了しました",
|
||||
"notification.poll": "アンケートが終了しました",
|
||||
"notification.reblog": "{name}さんがあなたの投稿をブーストしました",
|
||||
|
|
|
@ -308,6 +308,8 @@
|
|||
"follow_requests.unlocked_explanation": "Čeprav vaš račun ni zaklenjen, zaposleni pri {domain} menijo, da bi morda želeli pregledati zahteve za sledenje teh računov ročno.",
|
||||
"follow_suggestions.curated_suggestion": "Izbor osebja",
|
||||
"follow_suggestions.dismiss": "Ne pokaži več",
|
||||
"follow_suggestions.featured_longer": "Osebno izbrala ekipa {domain}",
|
||||
"follow_suggestions.friends_of_friends_longer": "Priljubljeno med osebami, ki jim sledite",
|
||||
"follow_suggestions.hints.featured": "Ta profil so izbrali skrbniki strežnika {domain}.",
|
||||
"follow_suggestions.hints.friends_of_friends": "Ta profil je priljubljen med osebami, ki jim sledite.",
|
||||
"follow_suggestions.hints.most_followed": "Ta profil na strežniku {domain} je en izmed najbolj sledenih.",
|
||||
|
@ -315,6 +317,8 @@
|
|||
"follow_suggestions.hints.similar_to_recently_followed": "Ta profil je podoben profilom, ki ste jim nedavno začeli slediti.",
|
||||
"follow_suggestions.personalized_suggestion": "Osebno prilagojen predlog",
|
||||
"follow_suggestions.popular_suggestion": "Priljubljen predlog",
|
||||
"follow_suggestions.popular_suggestion_longer": "Priljubljeno na {domain}",
|
||||
"follow_suggestions.similar_to_recently_followed_longer": "Podobno profilom, ki ste jim pred kratkim sledili",
|
||||
"follow_suggestions.view_all": "Pokaži vse",
|
||||
"follow_suggestions.who_to_follow": "Komu slediti",
|
||||
"followed_tags": "Sledeni ključniki",
|
||||
|
@ -469,6 +473,15 @@
|
|||
"notification.follow": "{name} vam sledi",
|
||||
"notification.follow_request": "{name} vam želi slediti",
|
||||
"notification.mention": "{name} vas je omenil/a",
|
||||
"notification.moderation-warning.learn_more": "Več o tem",
|
||||
"notification.moderation_warning": "Prejeli ste opozorilo moderatorjev",
|
||||
"notification.moderation_warning.action_delete_statuses": "Nekatere vaše objave so odstranjene.",
|
||||
"notification.moderation_warning.action_disable": "Vaš račun je bil onemogočen.",
|
||||
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Nekatere vaše objave so bile označene kot občutljive.",
|
||||
"notification.moderation_warning.action_none": "Vaš račun je prejel opozorilo moderatorjev.",
|
||||
"notification.moderation_warning.action_sensitive": "Vaše objave bodo odslej označene kot občutljive.",
|
||||
"notification.moderation_warning.action_silence": "Vaš račun je bil omejen.",
|
||||
"notification.moderation_warning.action_suspend": "Vaš račun je bil suspendiran.",
|
||||
"notification.own_poll": "Vaša anketa je zaključena",
|
||||
"notification.poll": "Anketa, v kateri ste sodelovali, je zaključena",
|
||||
"notification.reblog": "{name} je izpostavila/a vašo objavo",
|
||||
|
|
|
@ -297,6 +297,7 @@
|
|||
"filter_modal.select_filter.subtitle": "Përdorni një kategori ekzistuese, ose krijoni një të re",
|
||||
"filter_modal.select_filter.title": "Filtroje këtë postim",
|
||||
"filter_modal.title.status": "Filtroni një postim",
|
||||
"filtered_notifications_banner.mentions": "{count, plural, one {përmendje} other {përmendje}}",
|
||||
"filtered_notifications_banner.pending_requests": "Njoftime prej {count, plural, =0 {askujt} one {një personi} other {# vetësh}} që mund të njihni",
|
||||
"filtered_notifications_banner.title": "Njoftime të filtruar",
|
||||
"firehose.all": "Krejt",
|
||||
|
@ -307,6 +308,8 @@
|
|||
"follow_requests.unlocked_explanation": "Edhe pse llogaria juaj s’është e kyçur, ekipi i {domain} mendoi se mund të donit të shqyrtonit dorazi kërkesa ndjekjeje prej këtyre llogarive.",
|
||||
"follow_suggestions.curated_suggestion": "Zgjedhur nga ekipi",
|
||||
"follow_suggestions.dismiss": "Mos shfaq më",
|
||||
"follow_suggestions.featured_longer": "Zgjedhur enkas nga ekipi {domain}",
|
||||
"follow_suggestions.friends_of_friends_longer": "Popullore mes personash që ndiqni",
|
||||
"follow_suggestions.hints.featured": "Ky profil është zgjedhur nga ekipi {domain}.",
|
||||
"follow_suggestions.hints.friends_of_friends": "Ky profil është popullor mes personave që ndiqni.",
|
||||
"follow_suggestions.hints.most_followed": "Ky profil është një nga më të ndjekur në {domain}.",
|
||||
|
@ -314,6 +317,8 @@
|
|||
"follow_suggestions.hints.similar_to_recently_followed": "Ky profil është i ngjashëm me profile që keni ndjekur tani afër.",
|
||||
"follow_suggestions.personalized_suggestion": "Sugjerim i personalizuar",
|
||||
"follow_suggestions.popular_suggestion": "Sugjerim popullor",
|
||||
"follow_suggestions.popular_suggestion_longer": "Popullore në {domain}",
|
||||
"follow_suggestions.similar_to_recently_followed_longer": "I ngjashëm me profile që keni zënë të ndiqni së fundi",
|
||||
"follow_suggestions.view_all": "Shihni krejt",
|
||||
"follow_suggestions.who_to_follow": "Cilët të ndiqen",
|
||||
"followed_tags": "Hashtag-ë të ndjekur",
|
||||
|
@ -468,6 +473,15 @@
|
|||
"notification.follow": "{name} zuri t’ju ndjekë",
|
||||
"notification.follow_request": "{name} ka kërkuar t’ju ndjekë",
|
||||
"notification.mention": "{name} ju ka përmendur",
|
||||
"notification.moderation-warning.learn_more": "Mësoni më tepër",
|
||||
"notification.moderation_warning": "Keni marrë një sinjalizim moderimi",
|
||||
"notification.moderation_warning.action_delete_statuses": "Disa nga postimet tuaja janë hequr.",
|
||||
"notification.moderation_warning.action_disable": "Llogaria juaj është çaktivizuar.",
|
||||
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Disa prej postimeve tuaja u është vënë shenjë si me spec.",
|
||||
"notification.moderation_warning.action_none": "Llogaria juaj ka marrë një sinjalizim moderimi.",
|
||||
"notification.moderation_warning.action_sensitive": "Postimeve tuaja do t’u vihet shenjë si me spec, nga tani e tutje.",
|
||||
"notification.moderation_warning.action_silence": "Llogaria juaj është kufizuar.",
|
||||
"notification.moderation_warning.action_suspend": "Llogaria juaj është pezulluar.",
|
||||
"notification.own_poll": "Pyetësori juaj ka përfunduar",
|
||||
"notification.poll": "Ka përfunduar një pyetësor ku keni votuar",
|
||||
"notification.reblog": "{name} përforcoi mesazhin tuaj",
|
||||
|
|
|
@ -6,6 +6,8 @@ module AccessTokenExtension
|
|||
included do
|
||||
include Redisable
|
||||
|
||||
has_many :web_push_subscriptions, class_name: 'Web::PushSubscription', inverse_of: :access_token
|
||||
|
||||
after_commit :push_to_streaming_api
|
||||
end
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ class Admin::Metrics::Measure::InstanceMediaAttachmentsMeasure < Admin::Metrics:
|
|||
WHERE date_trunc('day', media_attachments.created_at)::date = axis.period
|
||||
AND #{account_domain_sql(params[:include_subdomains])}
|
||||
)
|
||||
SELECT COALESCE(SUM(size), 0) FROM new_media_attachments
|
||||
SELECT COALESCE(SUM(size), 0)::bigint FROM new_media_attachments
|
||||
) AS value
|
||||
FROM (
|
||||
SELECT generate_series(date_trunc('day', :start_at::timestamp)::date, date_trunc('day', :end_at::timestamp)::date, interval '1 day') AS period
|
||||
|
|
|
@ -282,6 +282,6 @@ class LinkDetailsExtractor
|
|||
end
|
||||
|
||||
def html_entities
|
||||
@html_entities ||= HTMLEntities.new
|
||||
@html_entities ||= HTMLEntities.new(:expanded)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,11 +17,9 @@
|
|||
# url :string
|
||||
# avatar_file_name :string
|
||||
# avatar_content_type :string
|
||||
# avatar_file_size :integer
|
||||
# avatar_updated_at :datetime
|
||||
# header_file_name :string
|
||||
# header_content_type :string
|
||||
# header_file_size :integer
|
||||
# header_updated_at :datetime
|
||||
# avatar_remote_url :string
|
||||
# locked :boolean default(FALSE), not null
|
||||
|
@ -55,6 +53,8 @@
|
|||
# indexable :boolean default(FALSE), not null
|
||||
# master_settings :jsonb
|
||||
# remote_pending :boolean default(FALSE), not null
|
||||
# avatar_file_size :bigint(8)
|
||||
# header_file_size :bigint(8)
|
||||
#
|
||||
|
||||
class Account < ApplicationRecord
|
||||
|
|
|
@ -3,6 +3,23 @@
|
|||
module Status::ThreadingConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
def permitted_statuses_from_ids(ids, account, stable: false)
|
||||
statuses = Status.with_accounts(ids).to_a
|
||||
account_ids = statuses.map(&:account_id).uniq
|
||||
domains = statuses.filter_map(&:account_domain).uniq
|
||||
relations = account&.relations_map(account_ids, domains) || {}
|
||||
|
||||
statuses.reject! { |status| StatusFilter.new(status, account, relations).filtered? }
|
||||
|
||||
if stable
|
||||
statuses.sort_by! { |status| ids.index(status.id) }
|
||||
else
|
||||
statuses
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ancestors(limit, account = nil)
|
||||
find_statuses_from_tree_path(ancestor_ids(limit), account)
|
||||
end
|
||||
|
@ -85,15 +102,7 @@ module Status::ThreadingConcern
|
|||
end
|
||||
|
||||
def find_statuses_from_tree_path(ids, account, promote: false)
|
||||
statuses = Status.with_accounts(ids).to_a
|
||||
account_ids = statuses.map(&:account_id).uniq
|
||||
domains = statuses.filter_map(&:account_domain).uniq
|
||||
relations = account&.relations_map(account_ids, domains) || {}
|
||||
|
||||
statuses.reject! { |status| StatusFilter.new(status, account, relations).filtered? }
|
||||
|
||||
# Order ancestors/descendants by tree path
|
||||
statuses.sort_by! { |status| ids.index(status.id) }
|
||||
statuses = Status.permitted_statuses_from_ids(ids, account, stable: true)
|
||||
|
||||
# Bring self-replies to the top
|
||||
if promote
|
||||
|
|
|
@ -22,7 +22,7 @@ module User::LdapAuthenticable
|
|||
safe_username = safe_username.gsub(keys, replacement)
|
||||
end
|
||||
|
||||
resource = joins(:account).find_by(accounts: { username: safe_username })
|
||||
resource = joins(:account).merge(Account.where(Account.arel_table[:username].lower.eq safe_username.downcase)).take
|
||||
|
||||
if resource.blank?
|
||||
resource = new(
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
# domain :string
|
||||
# image_file_name :string
|
||||
# image_content_type :string
|
||||
# image_file_size :integer
|
||||
# image_updated_at :datetime
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
|
@ -24,6 +23,7 @@
|
|||
# aliases :jsonb
|
||||
# is_sensitive :boolean default(FALSE), not null
|
||||
# license :string
|
||||
# image_file_size :bigint(8)
|
||||
#
|
||||
|
||||
class CustomEmoji < ApplicationRecord
|
||||
|
|
|
@ -65,6 +65,8 @@ class Form::AdminSettings
|
|||
hold_remote_new_accounts
|
||||
stop_fetch_activity_domains
|
||||
stop_link_preview_domains
|
||||
app_icon
|
||||
favicon
|
||||
).freeze
|
||||
|
||||
INTEGER_KEYS = %i(
|
||||
|
@ -114,6 +116,8 @@ class Form::AdminSettings
|
|||
UPLOAD_KEYS = %i(
|
||||
thumbnail
|
||||
mascot
|
||||
app_icon
|
||||
favicon
|
||||
).freeze
|
||||
|
||||
OVERRIDEN_SETTINGS = {
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
# updated_at :datetime not null
|
||||
# data_file_name :string
|
||||
# data_content_type :string
|
||||
# data_file_size :integer
|
||||
# data_updated_at :datetime
|
||||
# account_id :bigint(8) not null
|
||||
# overwrite :boolean default(FALSE), not null
|
||||
# data_file_size :bigint(8)
|
||||
#
|
||||
|
||||
# NOTE: This is a deprecated model, only kept to not break ongoing imports
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
# status_id :bigint(8)
|
||||
# file_file_name :string
|
||||
# file_content_type :string
|
||||
# file_file_size :integer
|
||||
# file_updated_at :datetime
|
||||
# remote_url :string default(""), not null
|
||||
# created_at :datetime not null
|
||||
|
@ -24,9 +23,10 @@
|
|||
# file_storage_schema_version :integer
|
||||
# thumbnail_file_name :string
|
||||
# thumbnail_content_type :string
|
||||
# thumbnail_file_size :integer
|
||||
# thumbnail_updated_at :datetime
|
||||
# thumbnail_remote_url :string
|
||||
# file_file_size :bigint(8)
|
||||
# thumbnail_file_size :bigint(8)
|
||||
#
|
||||
|
||||
class MediaAttachment < ApplicationRecord
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
# description :string default(""), not null
|
||||
# image_file_name :string
|
||||
# image_content_type :string
|
||||
# image_file_size :integer
|
||||
# image_updated_at :datetime
|
||||
# type :integer default("link"), not null
|
||||
# html :text default(""), not null
|
||||
|
@ -32,6 +31,7 @@
|
|||
# link_type :integer
|
||||
# published_at :datetime
|
||||
# image_description :string default(""), not null
|
||||
# image_file_size :bigint(8)
|
||||
#
|
||||
|
||||
class PreviewCard < ApplicationRecord
|
||||
|
|
|
@ -8,18 +8,26 @@
|
|||
# var :string default(""), not null
|
||||
# file_file_name :string
|
||||
# file_content_type :string
|
||||
# file_file_size :integer
|
||||
# file_updated_at :datetime
|
||||
# meta :json
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# blurhash :string
|
||||
# file_file_size :bigint(8)
|
||||
#
|
||||
|
||||
class SiteUpload < ApplicationRecord
|
||||
include Attachmentable
|
||||
|
||||
FAVICON_SIZES = [16, 32, 48].freeze
|
||||
APPLE_ICON_SIZES = [57, 60, 72, 76, 114, 120, 144, 152, 167, 180, 1024].freeze
|
||||
ANDROID_ICON_SIZES = [36, 48, 72, 96, 144, 192, 256, 384, 512].freeze
|
||||
|
||||
APP_ICON_SIZES = (APPLE_ICON_SIZES + ANDROID_ICON_SIZES).uniq.freeze
|
||||
|
||||
STYLES = {
|
||||
app_icon: APP_ICON_SIZES.each_with_object({}) { |size, hash| hash[size.to_s.to_sym] = "#{size}x#{size}#" }.freeze,
|
||||
favicon: FAVICON_SIZES.each_with_object({}) { |size, hash| hash[size.to_s.to_sym] = "#{size}x#{size}#" }.freeze,
|
||||
thumbnail: {
|
||||
'@1x': {
|
||||
format: 'png',
|
||||
|
|
|
@ -336,7 +336,7 @@ class Status < ApplicationRecord
|
|||
end
|
||||
|
||||
def reported?
|
||||
@reported ||= Report.where(target_account: account).unresolved.exists?(['? = ANY(status_ids)', id])
|
||||
@reported ||= account.targeted_reports.unresolved.exists?(['? = ANY(status_ids)', id]) || account.strikes.exists?(['? = ANY(status_ids)', id.to_s])
|
||||
end
|
||||
|
||||
def dtl?
|
||||
|
|
|
@ -39,7 +39,7 @@ class Tag < ApplicationRecord
|
|||
HASHTAG_LAST_SEQUENCE = '([[:word:]_]*[[:alpha:]][[:word:]_]*)'
|
||||
HASHTAG_NAME_PAT = "#{HASHTAG_FIRST_SEQUENCE}|#{HASHTAG_LAST_SEQUENCE}"
|
||||
|
||||
HASHTAG_RE = %r{(?<![=/)\w])#(#{HASHTAG_NAME_PAT})}i
|
||||
HASHTAG_RE = %r{(?<![=/)\p{Alnum}])#(#{HASHTAG_NAME_PAT})}i
|
||||
HASHTAG_NAME_RE = /\A(#{HASHTAG_NAME_PAT})\z/i
|
||||
HASHTAG_INVALID_CHARS_RE = /[^[:alnum:]\u0E47-\u0E4E#{HASHTAG_SEPARATORS}]/
|
||||
|
||||
|
|
67
app/presenters/oauth_metadata_presenter.rb
Normal file
67
app/presenters/oauth_metadata_presenter.rb
Normal file
|
@ -0,0 +1,67 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class OauthMetadataPresenter < ActiveModelSerializers::Model
|
||||
include RoutingHelper
|
||||
|
||||
attributes :issuer, :authorization_endpoint, :token_endpoint,
|
||||
:revocation_endpoint, :scopes_supported,
|
||||
:response_types_supported, :response_modes_supported,
|
||||
:grant_types_supported, :token_endpoint_auth_methods_supported,
|
||||
:service_documentation, :app_registration_endpoint
|
||||
|
||||
def issuer
|
||||
root_url
|
||||
end
|
||||
|
||||
def service_documentation
|
||||
'https://docs.joinmastodon.org/'
|
||||
end
|
||||
|
||||
def authorization_endpoint
|
||||
oauth_authorization_url
|
||||
end
|
||||
|
||||
def token_endpoint
|
||||
oauth_token_url
|
||||
end
|
||||
|
||||
# As the api_v1_apps route doesn't technically conform to the specification
|
||||
# for OAuth 2.0 Dynamic Client Registration defined in RFC 7591 we use a
|
||||
# non-standard property for now to indicate the mastodon specific registration
|
||||
# endpoint. See: https://datatracker.ietf.org/doc/html/rfc7591
|
||||
def app_registration_endpoint
|
||||
api_v1_apps_url
|
||||
end
|
||||
|
||||
def revocation_endpoint
|
||||
oauth_revoke_url
|
||||
end
|
||||
|
||||
def scopes_supported
|
||||
doorkeeper.scopes
|
||||
end
|
||||
|
||||
def response_types_supported
|
||||
doorkeeper.authorization_response_types
|
||||
end
|
||||
|
||||
def response_modes_supported
|
||||
doorkeeper.authorization_response_flows.flat_map(&:response_mode_matches).uniq
|
||||
end
|
||||
|
||||
def grant_types_supported
|
||||
grant_types_supported = doorkeeper.grant_flows.dup
|
||||
grant_types_supported << 'refresh_token' if doorkeeper.refresh_token_enabled?
|
||||
grant_types_supported
|
||||
end
|
||||
|
||||
def token_endpoint_auth_methods_supported
|
||||
%w(client_secret_basic client_secret_post)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def doorkeeper
|
||||
@doorkeeper ||= Doorkeeper.configuration
|
||||
end
|
||||
end
|
|
@ -1,21 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ManifestSerializer < ActiveModel::Serializer
|
||||
include ApplicationHelper
|
||||
include RoutingHelper
|
||||
include ActionView::Helpers::TextHelper
|
||||
|
||||
ICON_SIZES = %w(
|
||||
36
|
||||
48
|
||||
72
|
||||
96
|
||||
144
|
||||
192
|
||||
256
|
||||
384
|
||||
512
|
||||
).freeze
|
||||
|
||||
attributes :id, :name, :short_name,
|
||||
:icons, :theme_color, :background_color,
|
||||
:display, :start_url, :scope,
|
||||
|
@ -37,9 +26,12 @@ class ManifestSerializer < ActiveModel::Serializer
|
|||
end
|
||||
|
||||
def icons
|
||||
ICON_SIZES.map do |size|
|
||||
SiteUpload::ANDROID_ICON_SIZES.map do |size|
|
||||
src = site_icon_path('app_icon', size.to_i)
|
||||
src = URI.join(root_url, src).to_s if src.present?
|
||||
|
||||
{
|
||||
src: frontend_asset_url("icons/android-chrome-#{size}x#{size}.png"),
|
||||
src: src || frontend_asset_url("icons/android-chrome-#{size}x#{size}.png"),
|
||||
sizes: "#{size}x#{size}",
|
||||
type: 'image/png',
|
||||
purpose: 'any maskable',
|
||||
|
|
9
app/serializers/oauth_metadata_serializer.rb
Normal file
9
app/serializers/oauth_metadata_serializer.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class OauthMetadataSerializer < ActiveModel::Serializer
|
||||
attributes :issuer, :authorization_endpoint, :token_endpoint,
|
||||
:revocation_endpoint, :scopes_supported,
|
||||
:response_types_supported, :response_modes_supported,
|
||||
:grant_types_supported, :token_endpoint_auth_methods_supported,
|
||||
:service_documentation, :app_registration_endpoint
|
||||
end
|
|
@ -40,5 +40,33 @@
|
|||
= fa_icon 'trash fw'
|
||||
= t('admin.site_uploads.delete')
|
||||
|
||||
.fields-row
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :favicon,
|
||||
as: :file,
|
||||
input_html: { accept: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].join(',') },
|
||||
wrapper: :with_block_label
|
||||
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
- if @admin_settings.favicon.persisted?
|
||||
= image_tag @admin_settings.favicon.file.url('48'), class: 'fields-group__thumbnail'
|
||||
= link_to admin_site_upload_path(@admin_settings.favicon), data: { method: :delete }, class: 'link-button link-button--destructive' do
|
||||
= fa_icon 'trash fw'
|
||||
= t('admin.site_uploads.delete')
|
||||
|
||||
.fields-row
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :app_icon,
|
||||
as: :file,
|
||||
input_html: { accept: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].join(',') },
|
||||
wrapper: :with_block_label
|
||||
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
- if @admin_settings.app_icon.persisted?
|
||||
= image_tag @admin_settings.app_icon.file.url('48'), class: 'fields-group__thumbnail'
|
||||
= link_to admin_site_upload_path(@admin_settings.app_icon), data: { method: :delete }, class: 'link-button link-button--destructive' do
|
||||
= fa_icon 'trash fw'
|
||||
= t('admin.site_uploads.delete')
|
||||
|
||||
.actions
|
||||
= f.button :button, t('generic.save_changes'), type: :submit
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
- if storage_host?
|
||||
%link{ rel: 'dns-prefetch', href: storage_host }/
|
||||
|
||||
%link{ rel: 'icon', href: '/favicon.ico', type: 'image/x-icon' }/
|
||||
%link{ rel: 'icon', href: site_icon_path('favicon') || '/favicon.ico', type: 'image/x-icon' }/
|
||||
|
||||
- %w(16 32 48).each do |size|
|
||||
%link{ rel: 'icon', sizes: "#{size}x#{size}", href: frontend_asset_path("icons/favicon-#{size}x#{size}.png"), type: 'image/png' }/
|
||||
- SiteUpload::FAVICON_SIZES.each do |size|
|
||||
%link{ rel: 'icon', sizes: "#{size}x#{size}", href: site_icon_path('favicon', size.to_i) || frontend_asset_path("icons/favicon-#{size}x#{size}.png"), type: 'image/png' }/
|
||||
|
||||
- %w(57 60 72 76 114 120 144 152 167 180 1024).each do |size|
|
||||
%link{ rel: 'apple-touch-icon', sizes: "#{size}x#{size}", href: frontend_asset_path("icons/apple-touch-icon-#{size}x#{size}.png") }/
|
||||
- SiteUpload::APPLE_ICON_SIZES.each do |size|
|
||||
%link{ rel: 'apple-touch-icon', sizes: "#{size}x#{size}", href: site_icon_path('app_icon', size.to_i) || frontend_asset_path("icons/apple-touch-icon-#{size}x#{size}.png") }/
|
||||
|
||||
%link{ rel: 'mask-icon', href: frontend_asset_path('images/logo-symbol-icon.svg'), color: '#6364FF' }/
|
||||
%link{ rel: 'manifest', href: manifest_path(format: :json) }/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue