Compare commits

...

5 Commits

Author SHA1 Message Date
Matt Jankowski
8021229257
Merge 4393bd395a into 94bceb8683 2025-07-11 14:05:42 +00:00
Echo
94bceb8683
Expose enabled features to the frontend (#35348)
Some checks are pending
Check i18n / check-i18n (push) Waiting to run
Chromatic / Run Chromatic (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (ruby) (push) Waiting to run
Check formatting / lint (push) Waiting to run
JavaScript Linting / lint (push) Waiting to run
Ruby Linting / lint (push) Waiting to run
JavaScript Testing / test (push) Waiting to run
Historical data migration test / test (14-alpine) (push) Waiting to run
Historical data migration test / test (15-alpine) (push) Waiting to run
Historical data migration test / test (16-alpine) (push) Waiting to run
Historical data migration test / test (17-alpine) (push) Waiting to run
Ruby Testing / build (production) (push) Waiting to run
Ruby Testing / build (test) (push) Waiting to run
Ruby Testing / test (.ruby-version) (push) Blocked by required conditions
Ruby Testing / test (3.2) (push) Blocked by required conditions
Ruby Testing / test (3.3) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (.ruby-version) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.2) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.3) (push) Blocked by required conditions
Ruby Testing / End to End testing (.ruby-version) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.2) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.3) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:8.10.2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, opensearchproject/opensearch:2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.2, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.3, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
2025-07-11 13:15:22 +00:00
Claire
88b0f3a172
Simplify DatabaseViewRecord.refresh (#35252) 2025-07-11 08:36:05 +00:00
github-actions[bot]
b69b5ba775
New Crowdin Translations (automated) (#35344)
Co-authored-by: GitHub Actions <noreply@github.com>
2025-07-11 08:14:39 +00:00
Matt Jankowski
4393bd395a Convert to doorkeeper ORM mixin style for OAuth models 2025-07-03 18:28:24 -04:00
49 changed files with 202 additions and 174 deletions

View File

@ -4,7 +4,7 @@ class Api::V1::AppsController < Api::BaseController
skip_before_action :require_authenticated_user!
def create
@app = Doorkeeper::Application.create!(application_options)
@app = OAuth::Application.create!(application_options)
render json: @app, serializer: REST::CredentialApplicationSerializer
end

View File

@ -17,7 +17,7 @@ class OAuth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio
def destroy
Web::PushSubscription.unsubscribe_for(params[:id], current_resource_owner)
Doorkeeper::Application.find_by(id: params[:id])&.close_streaming_sessions(current_resource_owner)
OAuth::Application.find_by(id: params[:id])&.close_streaming_sessions(current_resource_owner)
super
end

View File

@ -10,7 +10,7 @@ class Settings::ApplicationsController < Settings::BaseController
def show; end
def new
@application = Doorkeeper::Application.new(
@application = OAuth::Application.new(
redirect_uri: Doorkeeper.configuration.native_redirect_uri,
scopes: 'profile'
)
@ -59,6 +59,6 @@ class Settings::ApplicationsController < Settings::BaseController
end
def application_params
params.expect(doorkeeper_application: [:name, :redirect_uri, :website, scopes: []])
params.expect(oauth_application: [:name, :redirect_uri, :website, scopes: []])
end
end

View File

@ -1,6 +1,5 @@
// @ts-check
/**
* @typedef {[code: string, name: string, localName: string]} InitialStateLanguage
*/
@ -64,6 +63,7 @@
* @property {boolean=} critical_updates_pending
* @property {InitialStateMeta} meta
* @property {Role?} role
* @property {string[]} features
*/
const element = document.getElementById('initial-state');
@ -140,4 +140,12 @@ export function getAccessToken() {
return getMeta('access_token');
}
/**
* @param {string} feature
* @returns {boolean}
*/
export function isFeatureEnabled(feature) {
return initialState?.features?.includes(feature) || false;
}
export default initialState;

View File

@ -219,6 +219,9 @@
"confirmations.delete_list.confirm": "Elimina",
"confirmations.delete_list.message": "Segur que vols suprimir permanentment aquesta llista?",
"confirmations.delete_list.title": "Eliminar la llista?",
"confirmations.discard_draft.confirm": "Descarta i continua",
"confirmations.discard_draft.edit.cancel": "Continua l'edició",
"confirmations.discard_draft.post.cancel": "Reprendre l'esborrany",
"confirmations.discard_edit_media.confirm": "Descarta",
"confirmations.discard_edit_media.message": "Tens canvis no desats en la descripció del contingut o en la previsualització, els vols descartar?",
"confirmations.follow_to_list.confirm": "Seguir i afegir a una llista",
@ -792,6 +795,7 @@
"report_notification.categories.violation": "Violació de norma",
"report_notification.categories.violation_sentence": "violació de normes",
"report_notification.open": "Obre l'informe",
"search.clear": "Esborra la cerca",
"search.no_recent_searches": "No hi ha cerques recents",
"search.placeholder": "Cerca",
"search.quick_action.account_search": "Perfils coincidint amb {x}",

View File

@ -572,7 +572,7 @@
"navigation_bar.mutes": "Skjulte brugere",
"navigation_bar.opened_in_classic_interface": "Indlæg, konti og visse andre sider åbnes som standard i den klassiske webgrænseflade.",
"navigation_bar.preferences": "Præferencer",
"navigation_bar.privacy_and_reach": "Fortrolighed og udbredelse",
"navigation_bar.privacy_and_reach": "Fortrolighed og rækkevidde",
"navigation_bar.search": "Søg",
"navigation_bar.search_trends": "Søg/Trender",
"navigation_panel.collapse_followed_tags": "Sammenfold menuen Fulgte hashtags",

View File

@ -1,10 +0,0 @@
# frozen_string_literal: true
module AccessGrantExtension
extend ActiveSupport::Concern
included do
scope :expired, -> { where.not(expires_in: nil).where('created_at + MAKE_INTERVAL(secs => expires_in) < NOW()') }
scope :revoked, -> { where.not(revoked_at: nil).where(revoked_at: ...Time.now.utc) }
end
end

View File

@ -1,29 +0,0 @@
# frozen_string_literal: true
module AccessTokenExtension
extend ActiveSupport::Concern
included do
include Redisable
has_many :web_push_subscriptions, class_name: 'Web::PushSubscription', inverse_of: :access_token
after_commit :push_to_streaming_api
scope :expired, -> { where.not(expires_in: nil).where('created_at + MAKE_INTERVAL(secs => expires_in) < NOW()') }
scope :not_revoked, -> { where(revoked_at: nil) }
scope :revoked, -> { where.not(revoked_at: nil).where(revoked_at: ...Time.now.utc) }
end
def revoke(clock = Time)
update(revoked_at: clock.now.utc)
end
def update_last_used(request, clock = Time)
update(last_used_at: clock.now.utc, last_used_ip: request.remote_ip)
end
def push_to_streaming_api
redis.publish("timeline:access_token:#{id}", Oj.dump(event: :kill)) if revoked? || destroyed?
end
end

View File

@ -1,49 +0,0 @@
# frozen_string_literal: true
module ApplicationExtension
extend ActiveSupport::Concern
APP_NAME_LIMIT = 60
APP_REDIRECT_URI_LIMIT = 2_000
APP_WEBSITE_LIMIT = 2_000
included do
include Redisable
has_many :created_users, class_name: 'User', foreign_key: 'created_by_application_id', inverse_of: :created_by_application
validates :name, length: { maximum: APP_NAME_LIMIT }
validates :redirect_uri, length: { maximum: APP_REDIRECT_URI_LIMIT }
validates :website, url: true, length: { maximum: APP_WEBSITE_LIMIT }, if: :website?
# The relationship used between Applications and AccessTokens is using
# dependent: delete_all, which means the ActiveRecord callback in
# AccessTokenExtension is not run, so instead we manually announce to
# streaming that these tokens are being deleted.
before_destroy :close_streaming_sessions, prepend: true
end
def confirmation_redirect_uri
redirect_uri.lines.first.strip
end
def redirect_uris
# Doorkeeper stores the redirect_uri value as a newline delimeted list in
# the database:
redirect_uri.split
end
def close_streaming_sessions(resource_owner = nil)
# TODO: #28793 Combine into a single topic
payload = Oj.dump(event: :kill)
scope = access_tokens
scope = scope.where(resource_owner_id: resource_owner.id) unless resource_owner.nil?
scope.in_batches do |tokens|
redis.pipelined do |pipeline|
tokens.ids.each do |id|
pipeline.publish("timeline:access_token:#{id}", payload)
end
end
end
end
end

View File

@ -9,12 +9,12 @@ class Vacuum::AccessTokensVacuum
private
def vacuum_revoked_access_tokens!
Doorkeeper::AccessToken.expired.in_batches.delete_all
Doorkeeper::AccessToken.revoked.in_batches.delete_all
OAuth::AccessToken.expired.in_batches.delete_all
OAuth::AccessToken.revoked.in_batches.delete_all
end
def vacuum_revoked_access_grants!
Doorkeeper::AccessGrant.expired.in_batches.delete_all
Doorkeeper::AccessGrant.revoked.in_batches.delete_all
OAuth::AccessGrant.expired.in_batches.delete_all
OAuth::AccessGrant.revoked.in_batches.delete_all
end
end

View File

@ -10,12 +10,6 @@ module DatabaseViewRecord
concurrently: true,
cascade: false
)
rescue ActiveRecord::StatementInvalid
Scenic.database.refresh_materialized_view(
table_name,
concurrently: false,
cascade: false
)
end
end

7
app/models/oauth.rb Normal file
View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
module OAuth
def self.table_name_prefix
'oauth_'
end
end

View File

@ -0,0 +1,8 @@
# frozen_string_literal: true
class OAuth::AccessGrant < ApplicationRecord
include ::Doorkeeper::Orm::ActiveRecord::Mixins::AccessGrant
scope :expired, -> { where.not(expires_in: nil).where('created_at + MAKE_INTERVAL(secs => expires_in) < NOW()') }
scope :revoked, -> { where.not(revoked_at: nil).where(revoked_at: ...Time.now.utc) }
end

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
class OAuth::AccessToken < ApplicationRecord
include ::Doorkeeper::Orm::ActiveRecord::Mixins::AccessToken
include Redisable
has_many :web_push_subscriptions, class_name: 'Web::PushSubscription', inverse_of: :access_token, dependent: nil
scope :expired, -> { where.not(expires_in: nil).where('created_at + MAKE_INTERVAL(secs => expires_in) < NOW()') }
scope :not_revoked, -> { where(revoked_at: nil) }
scope :revoked, -> { where.not(revoked_at: nil).where(revoked_at: ...Time.now.utc) }
after_commit :push_to_streaming_api
def revoke(clock = Time)
update(revoked_at: clock.now.utc)
end
def update_last_used(request, clock = Time)
update(last_used_at: clock.now.utc, last_used_ip: request.remote_ip)
end
private
def push_to_streaming_api
redis.publish("timeline:access_token:#{id}", Oj.dump(event: :kill)) if revoked? || destroyed?
end
end

View File

@ -0,0 +1,44 @@
# frozen_string_literal: true
class OAuth::Application < ApplicationRecord
include ::Doorkeeper::Orm::ActiveRecord::Mixins::Application
APP_NAME_LIMIT = 60
APP_REDIRECT_URI_LIMIT = 2_000
APP_WEBSITE_LIMIT = 2_000
include Redisable
has_many :created_users, class_name: 'User', foreign_key: :created_by_application_id, inverse_of: :created_by_application, dependent: nil
validates :name, length: { maximum: APP_NAME_LIMIT }
validates :redirect_uri, length: { maximum: APP_REDIRECT_URI_LIMIT }
validates :website, url: true, length: { maximum: APP_WEBSITE_LIMIT }, if: :website?
before_destroy :close_streaming_sessions, prepend: true
def confirmation_redirect_uri
redirect_uri.lines.first.strip
end
def redirect_uris
# The redirect_uri value is stored as a newline delimited list
redirect_uri.split
end
# The association between `Application` and `AccessToken` uses a setting of
# `dependent: delete_all` which means the callbacks in `AccessToken` are not
# run. Instead, announce to streaming that these tokens are being deleted.
def close_streaming_sessions(resource_owner = nil)
payload = Oj.dump(event: :kill)
scope = access_tokens
scope = scope.where(resource_owner_id: resource_owner.id) unless resource_owner.nil?
scope.in_batches do |tokens|
redis.pipelined do |pipeline|
tokens.ids.each do |id|
pipeline.publish("timeline:access_token:#{id}", payload)
end
end
end
end
end

View File

@ -32,7 +32,7 @@ class Report < ApplicationRecord
rate_limit by: :account, family: :reports
belongs_to :account
belongs_to :application, class_name: 'Doorkeeper::Application', optional: true
belongs_to :application, class_name: 'OAuth::Application', optional: true
with_options class_name: 'Account' do
belongs_to :target_account

View File

@ -19,7 +19,7 @@ class SessionActivation < ApplicationRecord
include BrowserDetection
belongs_to :user, inverse_of: :session_activations
belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', dependent: :destroy, optional: true
belongs_to :access_token, class_name: 'OAuth::AccessToken', dependent: :destroy, optional: true
belongs_to :web_push_subscription, class_name: 'Web::PushSubscription', dependent: :destroy, optional: true
delegate :token,
@ -61,12 +61,12 @@ class SessionActivation < ApplicationRecord
private
def assign_access_token
self.access_token = Doorkeeper::AccessToken.create!(access_token_attributes)
self.access_token = OAuth::AccessToken.create!(access_token_attributes)
end
def access_token_attributes
{
application_id: Doorkeeper::Application.find_by(superapp: true)&.id,
application_id: OAuth::Application.find_by(superapp: true)&.id,
resource_owner_id: user_id,
scopes: DEFAULT_SCOPES.join(' '),
expires_in: Doorkeeper.configuration.access_token_expires_in,

View File

@ -64,7 +64,7 @@ class Status < ApplicationRecord
update_index('statuses', :proper)
update_index('public_statuses', :proper)
belongs_to :application, class_name: 'Doorkeeper::Application', optional: true
belongs_to :application, class_name: 'OAuth::Application', optional: true
belongs_to :account, inverse_of: :statuses
belongs_to :in_reply_to_account, class_name: 'Account', optional: true

View File

@ -83,11 +83,11 @@ class User < ApplicationRecord
belongs_to :account, inverse_of: :user
belongs_to :invite, counter_cache: :uses, optional: true
belongs_to :created_by_application, class_name: 'Doorkeeper::Application', optional: true
belongs_to :created_by_application, class_name: 'OAuth::Application', optional: true
belongs_to :role, class_name: 'UserRole', optional: true
accepts_nested_attributes_for :account
has_many :applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: nil
has_many :applications, class_name: 'OAuth::Application', as: :owner, dependent: nil
has_many :backups, inverse_of: :user, dependent: nil
has_many :invites, inverse_of: :user, dependent: nil
has_many :markers, inverse_of: :user, dependent: :destroy
@ -303,7 +303,7 @@ class User < ApplicationRecord
end
def applications_last_used
Doorkeeper::AccessToken
OAuth::AccessToken
.where(resource_owner_id: id)
.where.not(last_used_at: nil)
.group(:application_id)
@ -314,7 +314,7 @@ class User < ApplicationRecord
def token_for_app(app)
return nil if app.nil? || app.owner != self
Doorkeeper::AccessToken.find_or_create_by(application_id: app.id, resource_owner_id: id) do |t|
OAuth::AccessToken.find_or_create_by(application_id: app.id, resource_owner_id: id) do |t|
t.scopes = app.scopes
t.expires_in = Doorkeeper.configuration.access_token_expires_in
t.use_refresh_token = Doorkeeper.configuration.refresh_token_enabled?
@ -368,9 +368,9 @@ class User < ApplicationRecord
end
def revoke_access!
Doorkeeper::AccessGrant.by_resource_owner(self).touch_all(:revoked_at)
OAuth::AccessGrant.by_resource_owner(self).touch_all(:revoked_at)
Doorkeeper::AccessToken.by_resource_owner(self).in_batches do |batch|
OAuth::AccessToken.by_resource_owner(self).in_batches do |batch|
batch.touch_all(:revoked_at)
Web::PushSubscription.where(access_token_id: batch).delete_all

View File

@ -18,7 +18,7 @@
class Web::PushSubscription < ApplicationRecord
belongs_to :user
belongs_to :access_token, class_name: 'Doorkeeper::AccessToken'
belongs_to :access_token, class_name: 'OAuth::AccessToken'
has_one :session_activation, foreign_key: 'web_push_subscription_id', inverse_of: :web_push_subscription, dependent: nil
@ -42,7 +42,7 @@ class Web::PushSubscription < ApplicationRecord
class << self
def unsubscribe_for(application_id, resource_owner)
access_token_ids = Doorkeeper::AccessToken.where(application_id: application_id, resource_owner_id: resource_owner.id).not_revoked.pluck(:id)
access_token_ids = OAuth::AccessToken.where(application_id: application_id, resource_owner_id: resource_owner.id).not_revoked.pluck(:id)
where(access_token_id: access_token_ids).delete_all
end
end

View File

@ -5,7 +5,7 @@ class InitialStateSerializer < ActiveModel::Serializer
attributes :meta, :compose, :accounts,
:media_attachments, :settings,
:languages
:languages, :features
attribute :critical_updates_pending, if: -> { object&.role&.can?(:view_devops) && SoftwareUpdate.check_enabled? }
@ -85,6 +85,10 @@ class InitialStateSerializer < ActiveModel::Serializer
LanguagesHelper::SUPPORTED_LOCALES.map { |(key, value)| [key, value[0], value[1]] }
end
def features
Mastodon::Feature.enabled_features
end
private
def default_meta_store

View File

@ -27,7 +27,7 @@ class AppSignUpService < BaseService
end
def create_access_token!
@access_token = Doorkeeper::AccessToken.create!(
@access_token = OAuth::AccessToken.create!(
application: @app,
resource_owner_id: @user.id,
scopes: @app.scopes,

View File

@ -26,7 +26,7 @@ class PostStatusService < BaseService
# @option [String] :scheduled_at
# @option [Hash] :poll Optional poll to attach
# @option [Enumerable] :media_ids Optional array of media IDs to attach
# @option [Doorkeeper::Application] :application
# @option [OAuth::Application] :application
# @option [String] :idempotency Optional idempotency key
# @option [Boolean] :with_rate_limit
# @option [Enumerable] :allowed_mentions Optional array of expected mentioned account IDs, raises `UnexpectedMentionsError` if unexpected accounts end up in mentions

View File

@ -21,7 +21,7 @@ class PublishScheduledStatusWorker
def options_with_objects(options)
options.tap do |options_hash|
options_hash[:application] = Doorkeeper::Application.find(options_hash.delete(:application_id)) if options[:application_id]
options_hash[:application] = OAuth::Application.find(options_hash.delete(:application_id)) if options[:application_id]
options_hash[:thread] = Status.find(options_hash.delete(:in_reply_to_id)) if options_hash[:in_reply_to_id]
end
end

View File

@ -20,7 +20,7 @@ class Scheduler::IpCleanupScheduler
SessionActivation.where(updated_at: ...IP_RETENTION_PERIOD.ago).in_batches.update_all(ip: nil)
User.where(current_sign_in_at: ...IP_RETENTION_PERIOD.ago).in_batches.update_all(sign_up_ip: nil)
LoginActivity.where(created_at: ...IP_RETENTION_PERIOD.ago).in_batches.destroy_all
Doorkeeper::AccessToken.where(last_used_at: ...IP_RETENTION_PERIOD.ago).in_batches.update_all(last_used_ip: nil)
OAuth::AccessToken.where(last_used_at: ...IP_RETENTION_PERIOD.ago).in_batches.update_all(last_used_ip: nil)
end
def clean_expired_ip_blocks!

View File

@ -117,9 +117,6 @@ module Mastodon
end
config.to_prepare do
Doorkeeper::Application.include ApplicationExtension
Doorkeeper::AccessGrant.include AccessGrantExtension
Doorkeeper::AccessToken.include AccessTokenExtension
Devise::FailureApp.include AbstractController::Callbacks
Devise::FailureApp.include Localized
end

View File

@ -4,6 +4,10 @@ Doorkeeper.configure do
# Change the ORM that doorkeeper will use (needs plugins)
orm :active_record
access_grant_class 'OAuth::AccessGrant'
access_token_class 'OAuth::AccessToken'
application_class 'OAuth::Application'
# This block will be called to check whether the resource owner is authenticated or not.
resource_owner_authenticator do
current_user || redirect_to(new_user_session_url)

View File

@ -578,6 +578,11 @@ ca:
all: Totes
limited: Limitades
title: Moderació
moderation_notes:
create: Afegeix una nota de moderació
created_msg: S'ha creat la nota de moderació d'instància.
destroyed_msg: S'ha esborrat la nota de moderació d'instància.
title: Notes de moderació
private_comment: Comentari privat
public_comment: Comentari públic
purge: Purga
@ -1339,6 +1344,10 @@ ca:
basic_information: Informació bàsica
hint_html: "<strong>Personalitza el que la gent veu en el teu perfil públic i a prop dels teus tuts..</strong> És més probable que altres persones et segueixin i interaccionin amb tu quan tens emplenat el teu perfil i amb la teva imatge."
other: Altres
emoji_styles:
auto: Automàtic
native: Nadiu
twemoji: Twemoji
errors:
'400': La sol·licitud que vas emetre no era vàlida o no era correcta.
'403': No tens permís per a veure aquesta pàgina.

View File

@ -653,7 +653,7 @@ da:
mark_as_sensitive_description_html: Medierne i det anmeldte indlæg markeres som sensitive, og en advarsel (strike) registreres mhp. eskalering ved evt. fremtidige overtrædelser fra samme konto.
other_description_html: Se flere muligheder for at kontrollere kontoens adfærd og tilpasse kommunikationen til den anmeldte konto.
resolve_description_html: Ingen foranstaltninger træffes mod den anmeldte konto, ingen advarsel (strike) registreres og anmeldelsen lukkes.
silence_description_html: Kontoen vil kun være synlig for følgerene eller dem, som manuelt slå den op, hvilket markant begrænser dens udbredelse. Kan altid omgøres. Lukker alle indrapporteringer af kontoen.
silence_description_html: Kontoen vil kun være synlig for dem, der allerede følger den eller manuelt slår den op, hvilket alvorligt begrænser dens rækkevidde. Kan altid omgøres. Lukker alle indrapporteringer af denne konto.
suspend_description_html: Kontoen inkl. alt indhold utilgængeliggøres og interaktion umuliggøres, og den slettes på et tidspunkt. Kan omgøres inden for 30 dage. Lukker alle indrapporteringer af kontoen.
actions_description_html: Afgør, hvilke foranstaltning, der skal træffes for at løse denne anmeldelse. Ved en straffende foranstaltning mod den anmeldte konto, fremsendes en e-mailnotifikation, undtagen når kategorien <strong>Spam</strong> er valgt.
actions_description_remote_html: Fastslå en nødvendig handling mhp. at løse denne anmeldelse. Dette vil kun påvirke <strong>din</strong> servers kommunikation med, og indholdshåndtering for, fjernkontoen.
@ -1266,8 +1266,8 @@ da:
user_privacy_agreement_html: Jeg accepterer <a href="%{privacy_policy_path}" target="_blank">fortrolighedspolitikken</a>
author_attribution:
example_title: Eksempeltekst
hint_html: Skriver du nyheder eller blogartikler uden for Mastodon? Styr, hvordan man bliver krediteret, når disse deles på Mastodon.
instructions: 'Sørg for, at denne kode er i artikelens HTML:'
hint_html: Skriver du nyheder eller blogartikler uden for Mastodon? Styr, hvordan du bliver krediteret, når de bliver delt på Mastodon.
instructions: 'Sørg for, at denne kode er i din artikels HTML:'
more_from_html: Flere fra %{name}
s_blog: "%{name}s blog"
then_instructions: Tilføj dernæst publikationsdomænenavnet i feltet nedenfor.
@ -1718,11 +1718,11 @@ da:
hint_html: "<strong>Tilpas hvordan din profil og dine indlæg kan findes.</strong> En række funktioner i Mastodon kan hjælpe dig med at nå ud til et bredere publikum, hvis du aktiverer dem. Tjek indstillingerne herunder for at sikre, at de passer til dit brugsscenarie."
privacy: Privatliv
privacy_hint_html: Styr, hvor meget der ønskes synliggjort til gavn for andre. Folk finder interessante profiler og apps ved at tjekke andres følgere ud, samt se hvilke apps de sender fra, men dine præferencer ønskes muligvis ikke synliggjort.
reach: Udbredelse
reach: Rækkevidde
reach_hint_html: Indstil om du vil blive opdaget og fulgt af nye mennesker. Ønsker du, at dine indlæg skal vises på Udforsk-siden? Ønsker du, at andre skal se dig i deres følg-anbefalinger? Ønsker du at acceptere alle nye følgere automatisk, eller vil du have detaljeret kontrol over hver og en?
search: Søg
search: Søgning
search_hint_html: Indstil hvordan du vil findes. Ønsker du, at folk skal finde dig gennem hvad du har skrevet offentligt? Vil du have folk udenfor Mastodon til at finde din profil, når de søger på nettet? Vær opmærksom på, at det ikke kan garanteres at dine offentlige indlæg er udelukket fra alle søgemaskiner.
title: Fortrolighed og udbredelse
title: Fortrolighed og rækkevidde
privacy_policy:
title: Privatlivspolitik
reactions:
@ -1923,7 +1923,7 @@ da:
'7889238': 3 måneder
min_age_label: Alderstærskel
min_favs: Behold indlæg favoritmarkeret mindst
min_favs_hint: Sletter ingen dine egne indlæg, som har modtaget minimum dette antal favoritmarkeringer. Lad stå tomt for at slette indlæg uanset antal favoritmarkeringer
min_favs_hint: Sletter ingen af dine egne indlæg, som har modtaget minimum dette antal favoritmarkeringer. Lad stå tom for at slette indlæg uanset antal favoritmarkeringer
min_reblogs: Behold indlæg fremhævet mindst
min_reblogs_hint: Sletter ingen af dine egne indlæg, som er fremhævet flere end dette antal gange. Lad stå tom for at slette indlæg uanset antallet af fremhævelser
stream_entries:
@ -2095,7 +2095,7 @@ da:
verification:
extra_instructions_html: <strong>Tip:</strong> Linket på din hjemmeside kan være usynligt. Den vigtige del er <code>rel="me"</code> , som forhindrer impersonation på websteder med brugergenereret indhold. Du kan endda bruge et <code>link</code> tag i overskriften på siden i stedet for <code>a</code>, men HTML skal være tilgængelig uden at udføre JavaScript.
here_is_how: Sådan gør du
hint_html: "<strong>Bekræftelse af din identitet på Mastodon er for alle.</strong> Baseret på åbne webstandarder, nu og for evigt gratis. Alt du behøver er en personlig hjemmeside, som folk genkende dig ved. Når du linker til denne hjemmeside fra din profil, vi vil kontrollere, at hjemmesiden linker tilbage til din profil og vise en visuel indikator på det."
hint_html: "<strong>Verificering af din identitet på Mastodon er for alle.</strong> Baseret på åbne webstandarder, nu og for altid gratis. Alt, hvad du behøver, er en personlig hjemmeside, som folk kender dig fra. Når du linker til denne hjemmeside fra din profil, kontrollerer vi, at hjemmesiden linker tilbage til din profil, og viser en visuel indikator på den."
instructions_html: Kopier og indsæt koden nedenfor i HTML på din hjemmeside. Tilføj derefter adressen på din hjemmeside i et af de ekstra felter på din profil på fanen "Redigér profil" og gem ændringer.
verification: Bekræftelse
verified_links: Dine bekræftede links

View File

@ -1349,6 +1349,10 @@ hu:
basic_information: Általános információk
hint_html: "<strong>Tedd egyedivé, mi látnak mások a profilodon és a bejegyzéseid mellett.</strong> Mások nagyobb eséllyel követnek vissza és lépnek veled kapcsolatba, ha van kitöltött profilod és profilképed."
other: Egyéb
emoji_styles:
auto: Automatikus
native: Natív
twemoji: Twemoji
errors:
'400': A küldött kérés érvénytelen vagy hibás volt.
'403': Nincs jogosultságod az oldal megtekintéséhez.

View File

@ -61,6 +61,7 @@ ca:
setting_display_media_default: Amaga el contingut gràfic marcat com a sensible
setting_display_media_hide_all: Oculta sempre tot el contingut multimèdia
setting_display_media_show_all: Mostra sempre el contingut gràfic
setting_emoji_style: Com mostrar els emojis. "Automàtic" provarà de fer servir els emojis nadius, però revertirà a twemojis en els navegadors antics.
setting_system_scrollbars_ui: S'aplica només als navegadors d'escriptori basats en Safari i Chrome
setting_use_blurhash: Els degradats es basen en els colors de les imatges ocultes, però n'enfosqueixen els detalls
setting_use_pending_items: Amaga les actualitzacions de la línia de temps després de fer un clic, en lloc de desplaçar-les automàticament
@ -240,6 +241,7 @@ ca:
setting_display_media_default: Per defecte
setting_display_media_hide_all: Amaga-ho tot
setting_display_media_show_all: Mostra-ho tot
setting_emoji_style: Estil d'emojis
setting_expand_spoilers: Desplega sempre els tuts marcats amb advertències de contingut
setting_hide_network: Amaga la teva xarxa
setting_missing_alt_text_modal: Mostra un diàleg de confirmació abans de publicar contingut sense text alternatiu

View File

@ -61,6 +61,7 @@ hu:
setting_display_media_default: Kényes tartalomnak jelölt média elrejtése
setting_display_media_hide_all: Média elrejtése mindig
setting_display_media_show_all: Média megjelenítése mindig
setting_emoji_style: Az emodzsik megjelenítési módja. Az „Automatikus” megpróbálja a natív emodzsikat használni, de az örökölt böngészők esetén a Twemojira vált vissza.
setting_system_scrollbars_ui: Csak Chrome és Safari alapú asztali böngészőkre vonatkozik
setting_use_blurhash: A kihomályosítás az eredeti képből történik, de minden részletet elrejt
setting_use_pending_items: Idővonal frissítése csak kattintásra automatikus görgetés helyett
@ -241,6 +242,7 @@ hu:
setting_display_media_default: Alapértelmezés
setting_display_media_hide_all: Mindent elrejt
setting_display_media_show_all: Mindent mutat
setting_emoji_style: Emodzsistílus
setting_expand_spoilers: Tartalmi figyelmeztetéssel ellátott bejegyzések automatikus kinyitása
setting_hide_network: Hálózatod elrejtése
setting_missing_alt_text_modal: Megerősítési párbeszédablak megjelenítése a helyettesítő szöveg nélküli média közzététele előtt

View File

@ -1,3 +1,3 @@
# frozen_string_literal: true
Doorkeeper::Application.create_with(name: 'Web', redirect_uri: Doorkeeper.configuration.native_redirect_uri, scopes: 'read write follow push').find_or_create_by(superapp: true)
OAuth::Application.create_with(name: 'Web', redirect_uri: Doorkeeper.configuration.native_redirect_uri, scopes: 'read write follow push').find_or_create_by(superapp: true)

View File

@ -134,12 +134,12 @@ namespace :tests do
exit(1)
end
unless Doorkeeper::Application.find(2)[:scopes] == 'write:accounts profile'
unless OAuth::Application.find(2)[:scopes] == 'write:accounts profile'
puts 'Application OAuth scopes not rewritten as expected'
exit(1)
end
unless Doorkeeper::Application.find(2).access_tokens.first[:scopes] == 'write:accounts profile'
unless OAuth::Application.find(2).access_tokens.first[:scopes] == 'write:accounts profile'
puts 'OAuth access token scopes not rewritten as expected'
exit(1)
end

View File

@ -5,7 +5,7 @@ require 'rails_helper'
RSpec.describe OAuth::AuthorizationsController do
render_views
let(:app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/', scopes: 'read') }
let(:app) { OAuth::Application.create!(name: 'test', redirect_uri: 'http://localhost/', scopes: 'read') }
describe 'GET #new' do
subject do
@ -34,7 +34,7 @@ RSpec.describe OAuth::AuthorizationsController do
context 'when app is already authorized' do
before do
Doorkeeper::AccessToken.find_or_create_for(
OAuth::AccessToken.find_or_create_for(
application: app,
resource_owner: user.id,
scopes: app.scopes,

View File

@ -55,7 +55,7 @@ RSpec.describe OAuth::AuthorizedApplicationsController do
it 'revokes access tokens for the application and removes subscriptions and sends kill payload to streaming' do
post :destroy, params: { id: application.id }
expect(Doorkeeper::AccessToken.where(application: application).first.revoked_at)
expect(OAuth::AccessToken.where(application: application).first.revoked_at)
.to_not be_nil
expect(Web::PushSubscription.where(user: user).count)
.to eq(0)

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator :access_grant, from: 'Doorkeeper::AccessGrant' do
Fabricator :access_grant, from: OAuth::AccessGrant do
application
resource_owner_id { Fabricate(:user).id }
expires_in 3_600

View File

@ -1,3 +1,3 @@
# frozen_string_literal: true
Fabricator :access_token, from: 'Doorkeeper::AccessToken'
Fabricator :access_token, from: OAuth::AccessToken

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
Fabricator(:application, from: Doorkeeper::Application) do
Fabricator(:application, from: OAuth::Application) do
name 'Example'
website 'http://example.com'
redirect_uri 'http://example.com/callback'

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Doorkeeper::AccessGrant do
RSpec.describe OAuth::AccessGrant do
describe 'Validations' do
subject { Fabricate :access_grant }

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Doorkeeper::AccessToken do
RSpec.describe OAuth::AccessToken do
describe 'Associations' do
it { is_expected.to have_many(:web_push_subscriptions).class_name('Web::PushSubscription').inverse_of(:access_token) }
end

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe Doorkeeper::Application do
RSpec.describe OAuth::Application do
describe 'Associations' do
it { is_expected.to have_many(:created_users).class_name('User').inverse_of(:created_by_application).with_foreign_key(:created_by_application_id) }
end

View File

@ -439,7 +439,7 @@ RSpec.describe User do
it 'creates and returns a persisted token' do
expect { user.token_for_app(app) }
.to change(Doorkeeper::AccessToken.where(resource_owner_id: user.id, application: app), :count).by(1)
.to change(OAuth::AccessToken.where(resource_owner_id: user.id, application: app), :count).by(1)
end
end
@ -449,7 +449,7 @@ RSpec.describe User do
it 'returns a persisted token' do
expect(user.token_for_app(app))
.to be_a(Doorkeeper::AccessToken)
.to be_a(OAuth::AccessToken)
.and eq(token)
end
end
@ -531,7 +531,7 @@ RSpec.describe User do
end
def remove_active_user_tokens
change { Doorkeeper::AccessToken.active_for(user).count }.to(0)
change { OAuth::AccessToken.active_for(user).count }.to(0)
end
def remove_user_web_subscriptions

View File

@ -31,7 +31,7 @@ RSpec.describe 'Apps' do
expect(response.content_type)
.to start_with('application/json')
app = Doorkeeper::Application.find_by(name: client_name)
app = OAuth::Application.find_by(name: client_name)
expect(app).to be_present
expect(app.scopes.to_s).to eq scopes
@ -64,7 +64,7 @@ RSpec.describe 'Apps' do
expect(response).to have_http_status(200)
expect(response.content_type)
.to start_with('application/json')
expect(Doorkeeper::Application.find_by(name: client_name)).to be_present
expect(OAuth::Application.find_by(name: client_name)).to be_present
expect(response.parsed_body)
.to include(
@ -84,7 +84,7 @@ RSpec.describe 'Apps' do
expect(response.content_type)
.to start_with('application/json')
app = Doorkeeper::Application.find_by(name: client_name)
app = OAuth::Application.find_by(name: client_name)
expect(app).to be_present
expect(app.scopes.to_s).to eq 'read'
@ -117,12 +117,12 @@ RSpec.describe 'Apps' do
expect(response).to have_http_status(200)
expect(response.content_type)
.to start_with('application/json')
expect(Doorkeeper::Application.find_by(name: client_name).scopes.to_s).to eq 'read'
expect(OAuth::Application.find_by(name: client_name).scopes.to_s).to eq 'read'
end
end
context 'with a too-long name' do
let(:client_name) { 'a' * Doorkeeper::Application::APP_NAME_LIMIT * 2 }
let(:client_name) { 'a' * OAuth::Application::APP_NAME_LIMIT * 2 }
it 'returns http unprocessable entity' do
subject
@ -134,7 +134,7 @@ RSpec.describe 'Apps' do
end
context 'with a too-long website' do
let(:website) { "https://foo.bar/#{'a' * Doorkeeper::Application::APP_WEBSITE_LIMIT * 2}" }
let(:website) { "https://foo.bar/#{'a' * OAuth::Application::APP_WEBSITE_LIMIT * 2}" }
it 'returns http unprocessable entity' do
subject
@ -146,7 +146,7 @@ RSpec.describe 'Apps' do
end
context 'with a too-long redirect_uri' do
let(:redirect_uris) { "https://app.example/#{'a' * Doorkeeper::Application::APP_REDIRECT_URI_LIMIT * 2}" }
let(:redirect_uris) { "https://app.example/#{'a' * OAuth::Application::APP_REDIRECT_URI_LIMIT * 2}" }
it 'returns http unprocessable entity' do
subject
@ -180,7 +180,7 @@ RSpec.describe 'Apps' do
expect(response.content_type)
.to start_with('application/json')
app = Doorkeeper::Application.find_by(name: client_name)
app = OAuth::Application.find_by(name: client_name)
expect(app).to be_present
expect(app.redirect_uri).to eq redirect_uris
@ -204,7 +204,7 @@ RSpec.describe 'Apps' do
expect(response.content_type)
.to start_with('application/json')
app = Doorkeeper::Application.find_by(name: client_name)
app = OAuth::Application.find_by(name: client_name)
expect(app).to be_present
expect(app.redirect_uri).to eq redirect_uris.join "\n"
@ -276,7 +276,7 @@ RSpec.describe 'Apps' do
expect(response.content_type)
.to start_with('application/json')
app = Doorkeeper::Application.find_by(name: client_name)
app = OAuth::Application.find_by(name: client_name)
expect(app).to be_present
expect(app.website).to eq website

View File

@ -169,7 +169,7 @@ RSpec.describe 'Caching behavior' do
let(:alice) { Account.find_by(username: 'alice') }
let(:user) { User.find_by(email: 'user@host.example') }
let(:token) { Doorkeeper::AccessToken.find_by(resource_owner_id: user.id) }
let(:token) { OAuth::AccessToken.find_by(resource_owner_id: user.id) }
before_all do
alice = Fabricate(:account, username: 'alice')

View File

@ -25,7 +25,7 @@ RSpec.describe 'Settings / Exports' do
let(:params) do
{
doorkeeper_application: {
oauth_application: {
name: 'My New App',
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
website: 'http://google.com',
@ -36,13 +36,13 @@ RSpec.describe 'Settings / Exports' do
it 'supports passing scope values as string' do
expect { subject }
.to change(Doorkeeper::Application, :count).by(1)
.to change(OAuth::Application, :count).by(1)
expect(response)
.to redirect_to(settings_applications_path)
end
it 'gracefully handles invalid nested params' do
post settings_applications_path(doorkeeper_application: 'invalid')
post settings_applications_path(oauth_application: 'invalid')
expect(response)
.to have_http_status(400)
@ -53,7 +53,7 @@ RSpec.describe 'Settings / Exports' do
let(:application) { Fabricate :application, owner: user }
it 'gracefully handles invalid nested params' do
put settings_application_path(application.id, doorkeeper_application: 'invalid')
put settings_application_path(application.id, oauth_application: 'invalid')
expect(response)
.to have_http_status(400)

View File

@ -68,7 +68,7 @@ RSpec.describe 'Auth Passwords' do
end
def user_token_count
Doorkeeper::AccessToken
OAuth::AccessToken
.active_for(user)
.count
end

View File

@ -7,7 +7,7 @@ RSpec.describe 'Using OAuth from an external app' do
subject { visit "/oauth/authorize?#{params.to_query}" }
let(:client_app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: about_url(host: Rails.application.config.x.local_domain), scopes: 'read') }
let(:client_app) { OAuth::Application.create!(name: 'test', redirect_uri: about_url(host: Rails.application.config.x.local_domain), scopes: 'read') }
let(:params) do
{ client_id: client_app.uid, response_type: 'code', redirect_uri: client_app.redirect_uri, scope: 'read' }
end
@ -264,7 +264,7 @@ RSpec.describe 'Using OAuth from an external app' do
end
def user_has_grant_with_client_app?
Doorkeeper::AccessGrant
OAuth::AccessGrant
.exists?(
application: client_app,
resource_owner_id: user.id

View File

@ -34,7 +34,7 @@ RSpec.describe 'Settings applications page' do
fill_in_form
expect { submit_form }
.to change(Doorkeeper::Application, :count).by(1)
.to change(OAuth::Application, :count).by(1)
expect(page)
.to have_content(I18n.t('doorkeeper.applications.index.title'))
.and have_content('My new app')
@ -47,7 +47,7 @@ RSpec.describe 'Settings applications page' do
visit new_settings_application_path
expect { submit_form }
.to not_change(Doorkeeper::Application, :count)
.to not_change(OAuth::Application, :count)
expect(page)
.to have_content("can't be blank")
end
@ -60,9 +60,9 @@ RSpec.describe 'Settings applications page' do
fill_in I18n.t('activerecord.attributes.doorkeeper/application.redirect_uri'),
with: 'urn:ietf:wg:oauth:2.0:oob'
check 'read', id: :doorkeeper_application_scopes_read
check 'write', id: :doorkeeper_application_scopes_write
check 'follow', id: :doorkeeper_application_scopes_follow
check 'read', id: :oauth_application_scopes_read
check 'write', id: :oauth_application_scopes_write
check 'follow', id: :oauth_application_scopes_follow
end
def submit_form
@ -76,12 +76,12 @@ RSpec.describe 'Settings applications page' do
fill_in form_app_name_label,
with: 'My new app name with a new value'
check 'push', id: :doorkeeper_application_scopes_push
check 'push', id: :oauth_application_scopes_push
submit_form
expect(page)
.to have_content('My new app name with a new value')
.and have_checked_field('push', id: :doorkeeper_application_scopes_push)
.and have_checked_field('push', id: :oauth_application_scopes_push)
end
it 'does not update with wrong values' do
@ -110,7 +110,7 @@ RSpec.describe 'Settings applications page' do
visit settings_applications_path
expect { destroy_application }
.to change(Doorkeeper::Application, :count).by(-1)
.to change(OAuth::Application, :count).by(-1)
expect(page)
.to have_no_content(application.name)
expect(redis_pipeline_stub)