From b7370ac8baa643d93ea727699b3b11f9d3a55bea Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 13 Aug 2017 00:44:41 +0200 Subject: ActivityPub delivery (#4566) * Deliver ActivityPub Like * Deliver ActivityPub Undo-Like * Deliver ActivityPub Create/Announce activities * Deliver ActivityPub creates from mentions * Deliver ActivityPub Block/Undo-Block * Deliver ActivityPub Accept/Reject-Follow * Deliver ActivityPub Undo-Follow * Deliver ActivityPub Follow * Deliver ActivityPub Delete activities Incidentally fix #889 * Adjust BatchedRemoveStatusService for ActivityPub * Add tests for ActivityPub workers * Add tests for FollowService * Add tests for FavouriteService, UnfollowService and PostStatusService * Add tests for ReblogService, BlockService, UnblockService, ProcessMentionsService * Add tests for AuthorizeFollowService, RejectFollowService, RemoveStatusService * Add tests for BatchedRemoveStatusService * Deliver updates to a local account to ActivityPub followers * Minor adjustments --- app/controllers/settings/profiles_controller.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'app/controllers/settings') diff --git a/app/controllers/settings/profiles_controller.rb b/app/controllers/settings/profiles_controller.rb index 0367e3593..c751c64ae 100644 --- a/app/controllers/settings/profiles_controller.rb +++ b/app/controllers/settings/profiles_controller.rb @@ -15,6 +15,7 @@ class Settings::ProfilesController < ApplicationController def update if @account.update(account_params) + ActivityPub::UpdateDistributionWorker.perform_async(@account.id) redirect_to settings_profile_path, notice: I18n.t('generic.changes_saved_msg') else render :show -- cgit From 871c0d251a6d27c4591785ae446738a8d6c553ab Mon Sep 17 00:00:00 2001 From: Colin Mitchell Date: Tue, 22 Aug 2017 12:33:57 -0400 Subject: Application prefs section (#2758) * Add code for creating/managing apps to settings section * Add specs for app changes * Fix controller spec * Fix view file I pasted over by mistake * Add locale strings. Add 'my apps' to nav * Add Client ID/Secret to App page. Add some visual separation * Fix rubocop warnings * Fix embarrassing typo I lost an `end` statement while fixing a merge conflict. * Add code for creating/managing apps to settings section - Add specs for app changes - Add locale strings. Add 'my apps' to nav - Add Client ID/Secret to App page. Add some visual separation - Fix some bugs/warnings * Update to match code standards * Trigger notification * Add warning about not sharing API secrets * Tweak spec a bit * Cleanup fixture creation by using let! * Remove unused key * Add foreign key for application<->user --- .../settings/applications_controller.rb | 65 ++++++++ app/models/user.rb | 13 ++ app/views/settings/applications/_fields.html.haml | 4 + app/views/settings/applications/index.html.haml | 20 +++ app/views/settings/applications/new.html.haml | 9 ++ app/views/settings/applications/show.html.haml | 28 ++++ config/initializers/doorkeeper.rb | 2 +- config/locales/doorkeeper.en.yml | 7 +- config/locales/en.yml | 11 ++ config/navigation.rb | 1 + config/routes.rb | 5 + .../20170427011934_re_add_owner_to_application.rb | 8 + db/schema.rb | 7 +- .../settings/applications_controller_spec.rb | 166 +++++++++++++++++++++ spec/models/user_spec.rb | 20 +++ 15 files changed, 362 insertions(+), 4 deletions(-) create mode 100644 app/controllers/settings/applications_controller.rb create mode 100644 app/views/settings/applications/_fields.html.haml create mode 100644 app/views/settings/applications/index.html.haml create mode 100644 app/views/settings/applications/new.html.haml create mode 100644 app/views/settings/applications/show.html.haml create mode 100644 db/migrate/20170427011934_re_add_owner_to_application.rb create mode 100644 spec/controllers/settings/applications_controller_spec.rb (limited to 'app/controllers/settings') diff --git a/app/controllers/settings/applications_controller.rb b/app/controllers/settings/applications_controller.rb new file mode 100644 index 000000000..b8f114455 --- /dev/null +++ b/app/controllers/settings/applications_controller.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +class Settings::ApplicationsController < ApplicationController + layout 'admin' + + before_action :authenticate_user! + + def index + @applications = current_user.applications.page(params[:page]) + end + + def new + @application = Doorkeeper::Application.new( + redirect_uri: Doorkeeper.configuration.native_redirect_uri, + scopes: 'read write follow' + ) + end + + def show + @application = current_user.applications.find(params[:id]) + end + + def create + @application = current_user.applications.build(application_params) + if @application.save + redirect_to settings_applications_path, notice: I18n.t('application.created') + else + render :new + end + end + + def update + @application = current_user.applications.find(params[:id]) + if @application.update_attributes(application_params) + redirect_to settings_applications_path, notice: I18n.t('generic.changes_saved_msg') + else + render :show + end + end + + def destroy + @application = current_user.applications.find(params[:id]) + @application.destroy + redirect_to settings_applications_path, notice: t('application.destroyed') + end + + def regenerate + @application = current_user.applications.find(params[:application_id]) + @access_token = current_user.token_for_app(@application) + @access_token.destroy + + redirect_to settings_application_path(@application), notice: t('access_token.regenerated') + end + + private + + def application_params + params.require(:doorkeeper_application).permit( + :name, + :redirect_uri, + :scopes, + :website + ) + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 96a2d09b7..02b1b26ee 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -46,6 +46,8 @@ class User < ApplicationRecord belongs_to :account, inverse_of: :user, required: true accepts_nested_attributes_for :account + has_many :applications, class_name: 'Doorkeeper::Application', as: :owner + validates :locale, inclusion: I18n.available_locales.map(&:to_s), if: :locale? validates_with BlacklistedEmailValidator, if: :email_changed? @@ -108,6 +110,17 @@ class User < ApplicationRecord settings.noindex end + def token_for_app(a) + return nil if a.nil? || a.owner != self + Doorkeeper::AccessToken + .find_or_create_by(application_id: a.id, resource_owner_id: id) do |t| + + t.scopes = a.scopes + t.expires_in = Doorkeeper.configuration.access_token_expires_in + t.use_refresh_token = Doorkeeper.configuration.refresh_token_enabled? + end + end + def activate_session(request) session_activations.activate(session_id: SecureRandom.hex, user_agent: request.user_agent, diff --git a/app/views/settings/applications/_fields.html.haml b/app/views/settings/applications/_fields.html.haml new file mode 100644 index 000000000..9dbe23466 --- /dev/null +++ b/app/views/settings/applications/_fields.html.haml @@ -0,0 +1,4 @@ += f.input :name, hint: t('activerecord.attributes.doorkeeper/application.name') += f.input :website, hint: t('activerecord.attributes.doorkeeper/application.website') += f.input :redirect_uri, hint: t('activerecord.attributes.doorkeeper/application.redirect_uri') += f.input :scopes, hint: t('activerecord.attributes.doorkeeper/application.scopes') diff --git a/app/views/settings/applications/index.html.haml b/app/views/settings/applications/index.html.haml new file mode 100644 index 000000000..17035f96c --- /dev/null +++ b/app/views/settings/applications/index.html.haml @@ -0,0 +1,20 @@ +- content_for :page_title do + = t('doorkeeper.applications.index.title') + +%table.table + %thead + %tr + %th= t('doorkeeper.applications.index.application') + %th= t('doorkeeper.applications.index.scopes') + %th= t('doorkeeper.applications.index.created_at') + %th + %tbody + - @applications.each do |application| + %tr + %td= link_to application.name, settings_application_path(application) + %th= application.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.join('
').html_safe + %td= l application.created_at + %td= table_link_to 'show', t('doorkeeper.applications.index.show'), settings_application_path(application) + %td= table_link_to 'times', t('doorkeeper.applications.index.delete'), settings_application_path(application), method: :delete, data: { confirm: t('doorkeeper.applications.confirmations.destroy') } += paginate @applications += link_to t('add_new'), new_settings_application_path, class: 'button' diff --git a/app/views/settings/applications/new.html.haml b/app/views/settings/applications/new.html.haml new file mode 100644 index 000000000..61406a31f --- /dev/null +++ b/app/views/settings/applications/new.html.haml @@ -0,0 +1,9 @@ +- content_for :page_title do + = t('doorkeeper.applications.new.title') + +.form-container + = simple_form_for @application, url: settings_applications_path do |f| + = render 'fields', f:f + + .actions + = f.button :button, t('.create'), type: :submit diff --git a/app/views/settings/applications/show.html.haml b/app/views/settings/applications/show.html.haml new file mode 100644 index 000000000..9f1a11986 --- /dev/null +++ b/app/views/settings/applications/show.html.haml @@ -0,0 +1,28 @@ +- content_for :page_title do + = t('doorkeeper.applications.show.title', name: @application.name) + + +%p.hint= t('application.warning') + +%div + %h3= t('application.uid') + %code= @application.uid + +%div + %h3= t('application.secret') + %code= @application.secret + +%div + %h3= t('access_token.your_token') + %code= current_user.token_for_app(@application).token + += link_to t('access_token.regenerate'), settings_application_regenerate_path(@application), method: :put, class: 'button' + +%hr + += simple_form_for @application, url: settings_application_path(@application), method: :put do |f| + = render 'fields', f:f + + .actions + = f.button :button, t('generic.save_changes'), type: :submit + diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 056a3651a..689e2ac4a 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -50,7 +50,7 @@ Doorkeeper.configure do # Optional parameter :confirmation => true (default false) if you want to enforce ownership of # a registered application # Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support - # enable_application_owner :confirmation => true + enable_application_owner # Define access token scopes for your provider # For more information go to diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml index 6412b8b48..fa0a7babf 100644 --- a/config/locales/doorkeeper.en.yml +++ b/config/locales/doorkeeper.en.yml @@ -3,8 +3,10 @@ en: activerecord: attributes: doorkeeper/application: - name: Name + name: Application Name + website: Application Website redirect_uri: Redirect URI + scopes: Scopes errors: models: doorkeeper/application: @@ -37,9 +39,12 @@ en: name: Name new: New Application title: Your applications + show: Show + delete: Delete new: title: New Application show: + title: 'Application: %{name}' actions: Actions application_id: Application Id callback_urls: Callback urls diff --git a/config/locales/en.yml b/config/locales/en.yml index 97f46c3af..fbcef03bd 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -33,6 +33,10 @@ en: user_count_after: users user_count_before: Home to what_is_mastodon: What is Mastodon? + access_token: + your_token: Your Access Token + regenerate: Regenerate Access Token + regenerated: Access Token Regenerated accounts: follow: Follow followers: Followers @@ -226,6 +230,12 @@ en: settings: 'Change e-mail preferences: %{link}' signature: Mastodon notifications from %{instance} view: 'View:' + application: + created: Application Created + destroyed: Application Destroyed + uid: Client ID + secret: Client Secret + warning: Be very careful with this data. Never share it with anyone other than authorized applications! applications: invalid_url: The provided URL is invalid auth: @@ -423,6 +433,7 @@ en: preferences: Preferences settings: Settings two_factor_authentication: Two-factor Authentication + your_apps: Your applications statuses: open_in_web: Open in web over_character_limit: character limit of %{max} exceeded diff --git a/config/navigation.rb b/config/navigation.rb index 535d033f5..6e04843ec 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -12,6 +12,7 @@ SimpleNavigation::Configuration.run do |navigation| settings.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_import_url settings.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_url settings.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url + settings.item :your_apps, safe_join([fa_icon('list fw'), t('settings.your_apps')]), settings_applications_url settings.item :follower_domains, safe_join([fa_icon('users fw'), t('settings.followers')]), settings_follower_domains_url end diff --git a/config/routes.rb b/config/routes.rb index 1a39dfeac..e8bc968f4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -79,6 +79,11 @@ Rails.application.routes.draw do end resource :follower_domains, only: [:show, :update] + + resources :applications do + put :regenerate + end + resource :delete, only: [:show, :destroy] resources :sessions, only: [:destroy] diff --git a/db/migrate/20170427011934_re_add_owner_to_application.rb b/db/migrate/20170427011934_re_add_owner_to_application.rb new file mode 100644 index 000000000..a41d71d2a --- /dev/null +++ b/db/migrate/20170427011934_re_add_owner_to_application.rb @@ -0,0 +1,8 @@ +class ReAddOwnerToApplication < ActiveRecord::Migration[5.0] + def change + add_column :oauth_applications, :owner_id, :integer, null: true + add_column :oauth_applications, :owner_type, :string, null: true + add_index :oauth_applications, [:owner_id, :owner_type] + add_foreign_key :oauth_applications, :users, column: :owner_id, on_delete: :cascade + end +end diff --git a/db/schema.rb b/db/schema.rb index 2501e451d..929a5fd01 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -216,8 +216,11 @@ ActiveRecord::Schema.define(version: 20170720000000) do t.string "scopes", default: "", null: false t.datetime "created_at" t.datetime "updated_at" - t.boolean "superapp", default: false, null: false - t.string "website" + t.boolean "superapp", default: false, null: false + t.string "website" + t.integer "owner_id" + t.string "owner_type" + t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true end diff --git a/spec/controllers/settings/applications_controller_spec.rb b/spec/controllers/settings/applications_controller_spec.rb new file mode 100644 index 000000000..fa27e6ec6 --- /dev/null +++ b/spec/controllers/settings/applications_controller_spec.rb @@ -0,0 +1,166 @@ +require 'rails_helper' + +describe Settings::ApplicationsController do + render_views + + let!(:user) { Fabricate(:user) } + let!(:app) { Fabricate(:application, owner: user) } + + before do + sign_in user, scope: :user + end + + describe 'GET #index' do + let!(:other_app) { Fabricate(:application) } + + it 'shows apps' do + get :index + expect(response).to have_http_status(:success) + expect(assigns(:applications)).to include(app) + expect(assigns(:applications)).to_not include(other_app) + end + end + + + describe 'GET #show' do + it 'returns http success' do + get :show, params: { id: app.id } + expect(response).to have_http_status(:success) + expect(assigns[:application]).to eql(app) + end + + it 'returns 404 if you dont own app' do + app.update!(owner: nil) + + get :show, params: { id: app.id } + expect(response.status).to eq 404 + end + end + + describe 'GET #new' do + it 'works' do + get :new + expect(response).to have_http_status(:success) + end + end + + describe 'POST #create' do + context 'success' do + def call_create + post :create, params: { + doorkeeper_application: { + name: 'My New App', + redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', + website: 'http://google.com', + scopes: 'read write follow' + } + } + response + end + + it 'creates an entry in the database' do + expect { call_create }.to change(Doorkeeper::Application, :count) + end + + it 'redirects back to applications page' do + expect(call_create).to redirect_to(settings_applications_path) + end + end + + context 'failure' do + before do + post :create, params: { + doorkeeper_application: { + name: '', + redirect_uri: '', + website: '', + scopes: '' + } + } + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'renders form again' do + expect(response).to render_template(:new) + end + end + end + + describe 'PATCH #update' do + context 'success' do + let(:opts) { + { + website: 'https://foo.bar/' + } + } + + def call_update + patch :update, params: { + id: app.id, + doorkeeper_application: opts + } + response + end + + it 'updates existing application' do + call_update + expect(app.reload.website).to eql(opts[:website]) + end + + it 'redirects back to applications page' do + expect(call_update).to redirect_to(settings_applications_path) + end + end + + context 'failure' do + before do + patch :update, params: { + id: app.id, + doorkeeper_application: { + name: '', + redirect_uri: '', + website: '', + scopes: '' + } + } + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + it 'renders form again' do + expect(response).to render_template(:show) + end + end + end + + describe 'destroy' do + before do + post :destroy, params: { id: app.id } + end + + it 'redirects back to applications page' do + expect(response).to redirect_to(settings_applications_path) + end + + it 'removes the app' do + expect(Doorkeeper::Application.find_by(id: app.id)).to be_nil + end + end + + describe 'regenerate' do + let(:token) { user.token_for_app(app) } + before do + expect(token).to_not be_nil + put :regenerate, params: { application_id: app.id } + end + + it 'should create new token' do + expect(user.token_for_app(app)).to_not eql(token) + end + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index ef45818b9..99aeca01b 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -286,4 +286,24 @@ RSpec.describe User, type: :model do Fabricate(:user) end end + + describe 'token_for_app' do + let(:user) { Fabricate(:user) } + let(:app) { Fabricate(:application, owner: user) } + + it 'returns a token' do + expect(user.token_for_app(app)).to be_a(Doorkeeper::AccessToken) + end + + it 'persists a token' do + t = user.token_for_app(app) + expect(user.token_for_app(app)).to eql(t) + end + + it 'is nil if user does not own app' do + app.update!(owner: nil) + + expect(user.token_for_app(app)).to be_nil + end + end end -- cgit From c1b086a538d128e9fbceab4fc6686611a4f2710f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 23 Aug 2017 00:59:35 +0200 Subject: Fix up the applications area (#4664) - Section it into "Development" area - Improve UI of application form, index, and details --- .../settings/applications_controller.rb | 21 ++++++------ app/views/settings/applications/_fields.html.haml | 15 +++++--- app/views/settings/applications/index.html.haml | 11 +++--- app/views/settings/applications/new.html.haml | 11 +++--- app/views/settings/applications/show.html.haml | 40 ++++++++++++---------- config/locales/doorkeeper.en.yml | 19 +++++----- config/locales/en.yml | 23 ++++++------- config/locales/ja.yml | 6 ++-- config/locales/oc.yml | 16 ++++----- config/locales/pl.yml | 8 ++--- config/navigation.rb | 5 ++- config/routes.rb | 6 ++-- db/schema.rb | 11 +++--- .../settings/applications_controller_spec.rb | 2 +- 14 files changed, 102 insertions(+), 92 deletions(-) (limited to 'app/controllers/settings') diff --git a/app/controllers/settings/applications_controller.rb b/app/controllers/settings/applications_controller.rb index b8f114455..894222c2a 100644 --- a/app/controllers/settings/applications_controller.rb +++ b/app/controllers/settings/applications_controller.rb @@ -4,6 +4,7 @@ class Settings::ApplicationsController < ApplicationController layout 'admin' before_action :authenticate_user! + before_action :set_application, only: [:show, :update, :destroy, :regenerate] def index @applications = current_user.applications.page(params[:page]) @@ -16,22 +17,20 @@ class Settings::ApplicationsController < ApplicationController ) end - def show - @application = current_user.applications.find(params[:id]) - end + def show; end def create @application = current_user.applications.build(application_params) + if @application.save - redirect_to settings_applications_path, notice: I18n.t('application.created') + redirect_to settings_applications_path, notice: I18n.t('applications.created') else render :new end end def update - @application = current_user.applications.find(params[:id]) - if @application.update_attributes(application_params) + if @application.update(application_params) redirect_to settings_applications_path, notice: I18n.t('generic.changes_saved_msg') else render :show @@ -39,21 +38,23 @@ class Settings::ApplicationsController < ApplicationController end def destroy - @application = current_user.applications.find(params[:id]) @application.destroy - redirect_to settings_applications_path, notice: t('application.destroyed') + redirect_to settings_applications_path, notice: I18n.t('applications.destroyed') end def regenerate - @application = current_user.applications.find(params[:application_id]) @access_token = current_user.token_for_app(@application) @access_token.destroy - redirect_to settings_application_path(@application), notice: t('access_token.regenerated') + redirect_to settings_application_path(@application), notice: I18n.t('applications.token_regenerated') end private + def set_application + @application = current_user.applications.find(params[:id]) + end + def application_params params.require(:doorkeeper_application).permit( :name, diff --git a/app/views/settings/applications/_fields.html.haml b/app/views/settings/applications/_fields.html.haml index 9dbe23466..536f69e04 100644 --- a/app/views/settings/applications/_fields.html.haml +++ b/app/views/settings/applications/_fields.html.haml @@ -1,4 +1,11 @@ -= f.input :name, hint: t('activerecord.attributes.doorkeeper/application.name') -= f.input :website, hint: t('activerecord.attributes.doorkeeper/application.website') -= f.input :redirect_uri, hint: t('activerecord.attributes.doorkeeper/application.redirect_uri') -= f.input :scopes, hint: t('activerecord.attributes.doorkeeper/application.scopes') +.fields-group + = f.input :name, placeholder: t('activerecord.attributes.doorkeeper/application.name') + = f.input :website, placeholder: t('activerecord.attributes.doorkeeper/application.website') + +.fields-group + = f.input :redirect_uri, wrapper: :with_block_label, label: t('activerecord.attributes.doorkeeper/application.redirect_uri'), hint: t('doorkeeper.applications.help.redirect_uri') + + %p.hint= t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: Doorkeeper.configuration.native_redirect_uri) + +.fields-group + = f.input :scopes, wrapper: :with_label, label: t('activerecord.attributes.doorkeeper/application.scopes'), hint: t('doorkeeper.applications.help.scopes') diff --git a/app/views/settings/applications/index.html.haml b/app/views/settings/applications/index.html.haml index 17035f96c..eea550388 100644 --- a/app/views/settings/applications/index.html.haml +++ b/app/views/settings/applications/index.html.haml @@ -6,15 +6,14 @@ %tr %th= t('doorkeeper.applications.index.application') %th= t('doorkeeper.applications.index.scopes') - %th= t('doorkeeper.applications.index.created_at') %th %tbody - @applications.each do |application| %tr %td= link_to application.name, settings_application_path(application) - %th= application.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.join('
').html_safe - %td= l application.created_at - %td= table_link_to 'show', t('doorkeeper.applications.index.show'), settings_application_path(application) - %td= table_link_to 'times', t('doorkeeper.applications.index.delete'), settings_application_path(application), method: :delete, data: { confirm: t('doorkeeper.applications.confirmations.destroy') } + %th= application.scopes + %td + = table_link_to 'times', t('doorkeeper.applications.index.delete'), settings_application_path(application), method: :delete, data: { confirm: t('doorkeeper.applications.confirmations.destroy') } + = paginate @applications -= link_to t('add_new'), new_settings_application_path, class: 'button' += link_to t('doorkeeper.applications.index.new'), new_settings_application_path, class: 'button' diff --git a/app/views/settings/applications/new.html.haml b/app/views/settings/applications/new.html.haml index 61406a31f..5274a430c 100644 --- a/app/views/settings/applications/new.html.haml +++ b/app/views/settings/applications/new.html.haml @@ -1,9 +1,8 @@ - content_for :page_title do = t('doorkeeper.applications.new.title') + += simple_form_for @application, url: settings_applications_path do |f| + = render 'fields', f: f -.form-container - = simple_form_for @application, url: settings_applications_path do |f| - = render 'fields', f:f - - .actions - = f.button :button, t('.create'), type: :submit + .actions + = f.button :button, t('doorkeeper.applications.buttons.submit'), type: :submit diff --git a/app/views/settings/applications/show.html.haml b/app/views/settings/applications/show.html.haml index 9f1a11986..4d8555111 100644 --- a/app/views/settings/applications/show.html.haml +++ b/app/views/settings/applications/show.html.haml @@ -1,27 +1,29 @@ - content_for :page_title do = t('doorkeeper.applications.show.title', name: @application.name) - -%p.hint= t('application.warning') - -%div - %h3= t('application.uid') - %code= @application.uid - -%div - %h3= t('application.secret') - %code= @application.secret - -%div - %h3= t('access_token.your_token') - %code= current_user.token_for_app(@application).token - -= link_to t('access_token.regenerate'), settings_application_regenerate_path(@application), method: :put, class: 'button' - -%hr +%p.hint= t('applications.warning') + +%table.table + %tbody + %tr + %th= t('doorkeeper.applications.show.application_id') + %td + %code= @application.uid + %tr + %th= t('doorkeeper.applications.show.secret') + %td + %code= @application.secret + %tr + %th{ rowspan: 2}= t('applications.your_token') + %td + %code= current_user.token_for_app(@application).token + %tr + %td= table_link_to 'refresh', t('applications.regenerate_token'), regenerate_settings_application_path(@application), method: :post + +%hr/ = simple_form_for @application, url: settings_application_path(@application), method: :put do |f| - = render 'fields', f:f + = render 'fields', f: f .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml index fa0a7babf..788d1bb40 100644 --- a/config/locales/doorkeeper.en.yml +++ b/config/locales/doorkeeper.en.yml @@ -3,10 +3,10 @@ en: activerecord: attributes: doorkeeper/application: - name: Application Name - website: Application Website + name: Application name redirect_uri: Redirect URI scopes: Scopes + website: Application website errors: models: doorkeeper/application: @@ -36,20 +36,19 @@ en: scopes: Separate scopes with spaces. Leave blank to use the default scopes. index: callback_url: Callback URL + delete: Delete name: Name - new: New Application - title: Your applications + new: New application show: Show - delete: Delete + title: Your applications new: - title: New Application + title: New application show: - title: 'Application: %{name}' actions: Actions - application_id: Application Id - callback_urls: Callback urls + application_id: Client key + callback_urls: Callback URLs scopes: Scopes - secret: Secret + secret: Client secret title: 'Application: %{name}' authorizations: buttons: diff --git a/config/locales/en.yml b/config/locales/en.yml index fbcef03bd..97bb14186 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -33,24 +33,20 @@ en: user_count_after: users user_count_before: Home to what_is_mastodon: What is Mastodon? - access_token: - your_token: Your Access Token - regenerate: Regenerate Access Token - regenerated: Access Token Regenerated accounts: follow: Follow followers: Followers following: Following + media: Media nothing_here: There is nothing here! people_followed_by: People whom %{name} follows people_who_follow: People who follow %{name} posts: Toots posts_with_replies: Toots with replies - media: Media - roles: - admin: Admin remote_follow: Remote follow reserved_username: The username is reserved + roles: + admin: Admin unfollow: Unfollow admin: accounts: @@ -230,14 +226,14 @@ en: settings: 'Change e-mail preferences: %{link}' signature: Mastodon notifications from %{instance} view: 'View:' - application: - created: Application Created - destroyed: Application Destroyed - uid: Client ID - secret: Client Secret - warning: Be very careful with this data. Never share it with anyone other than authorized applications! applications: + created: Application successfully created + destroyed: Application successfully deleted invalid_url: The provided URL is invalid + regenerate_token: Regenerate access token + token_regenerated: Access token successfully regenerated + warning: Be very careful with this data. Never share it with anyone! + your_token: Your access token auth: agreement_html: By signing up you agree to our terms of service and privacy policy. change_password: Security @@ -426,6 +422,7 @@ en: authorized_apps: Authorized apps back: Back to Mastodon delete: Account deletion + development: Development edit_profile: Edit profile export: Data export followers: Authorized followers diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 0f0b0ad4a..2ee99db45 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -37,16 +37,16 @@ ja: follow: フォロー followers: フォロワー following: フォロー中 + media: メディア nothing_here: 何もありません people_followed_by: "%{name} さんがフォロー中のアカウント" people_who_follow: "%{name} さんをフォロー中のアカウント" posts: トゥート posts_with_replies: トゥートと返信 - media: メディア - roles: - admin: Admin remote_follow: リモートフォロー reserved_username: このユーザー名は予約されています。 + roles: + admin: Admin unfollow: フォロー解除 admin: accounts: diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 9038d887a..65ea4525a 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -37,16 +37,16 @@ oc: follow: Sègre followers: Seguidors following: Abonaments + media: Mèdias nothing_here: I a pas res aquí ! people_followed_by: Lo mond que %{name} sèc people_who_follow: Lo mond que sègon %{name} posts: Tuts posts_with_replies: Tuts amb responsas - media: Mèdias - roles: - admin: Admin remote_follow: Sègre a distància reserved_username: Aqueste nom d’utilizaire es reservat + roles: + admin: Admin unfollow: Quitar de sègre admin: accounts: @@ -221,7 +221,7 @@ oc: body: "%{reporter} a senhalat %{target}" subject: Novèl senhalament per %{instance} (#%{id}) application_mailer: - salutation: '%{name},' + salutation: "%{name}," settings: 'Cambiar las preferéncias de corrièl : %{link}' signature: Notificacion de Mastodon sus %{instance} view: 'Veire :' @@ -234,13 +234,13 @@ oc: delete_account_html: Se volètz suprimir vòstre compte, podètz o far aquí. Vos demandarem que confirmetz. didnt_get_confirmation: Avètz pas recebut las instruccions de confirmacion ? forgot_password: Senhal oblidat ? + invalid_reset_password_token: Lo geton de reïnicializacion es invalid o acabat. Tornatz demandar un geton se vos plai. login: Se connectar logout: Se desconnectar register: Se marcar resend_confirmation: Tornar mandar las instruccions de confirmacion reset_password: Reïnicializar lo senhal set_new_password: Picar un nòu senhal - invalid_reset_password_token: Lo geton de reïnicializacion es invalid o acabat. Tornatz demandar un geton se vos plai. authorize_follow: error: O planhèm, i a agut una error al moment de cercar lo compte follow: Sègre @@ -337,12 +337,12 @@ oc: x_months: one: Fa un mes other: Fa %{count} meses - x_years: - one: Fa un an - other: Fa %{count} ans x_seconds: one: Fa una segonda other: Fa %{count} segondas + x_years: + one: Fa un an + other: Fa %{count} ans deletes: bad_password_msg: Ben ensajat pirata ! Senhal incorrècte confirm_password: Picatz vòstre senhal actual per verificar vòstra identitat diff --git a/config/locales/pl.yml b/config/locales/pl.yml index c005cdb01..b7f4898b0 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -37,16 +37,16 @@ pl: follow: Śledź followers: Śledzących following: Śledzi + media: Zawartość multimedialna nothing_here: Niczego tu nie ma! people_followed_by: Konta śledzone przez %{name} people_who_follow: Osoby, które śledzą konto %{name} posts: Wpisy posts_with_replies: Wpisy z odpowiedziami - media: Zawartość multimedialna - roles: - admin: Administrator remote_follow: Śledź zdalnie reserved_username: Ta nazwa użytkownika jest zarezerwowana. + roles: + admin: Administrator unfollow: Przestań śledzić admin: accounts: @@ -126,8 +126,8 @@ pl: severity: Priorytet show: affected_accounts: - one: Dotyczy jednego konta w bazie danych many: Dotyczy %{count} kont w bazie danych + one: Dotyczy jednego konta w bazie danych other: Dotyczy %{count} kont w bazie danych retroactive: silence: Odwołaj wyciszenie wszystkich kont w tej domenie diff --git a/config/navigation.rb b/config/navigation.rb index 6e04843ec..4b454b3fc 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -12,10 +12,13 @@ SimpleNavigation::Configuration.run do |navigation| settings.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_import_url settings.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_url settings.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url - settings.item :your_apps, safe_join([fa_icon('list fw'), t('settings.your_apps')]), settings_applications_url settings.item :follower_domains, safe_join([fa_icon('users fw'), t('settings.followers')]), settings_follower_domains_url end + primary.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_url do |development| + development.item :your_apps, safe_join([fa_icon('list fw'), t('settings.your_apps')]), settings_applications_url, highlights_on: %r{/settings/applications} + end + primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), admin_reports_url, if: proc { current_user.admin? } do |admin| admin.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_url, highlights_on: %r{/admin/reports} admin.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url, highlights_on: %r{/admin/accounts} diff --git a/config/routes.rb b/config/routes.rb index e8bc968f4..94a4ac88e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -80,8 +80,10 @@ Rails.application.routes.draw do resource :follower_domains, only: [:show, :update] - resources :applications do - put :regenerate + resources :applications, except: [:edit] do + member do + post :regenerate + end end resource :delete, only: [:show, :destroy] diff --git a/db/schema.rb b/db/schema.rb index 929a5fd01..98b07e282 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -216,11 +216,11 @@ ActiveRecord::Schema.define(version: 20170720000000) do t.string "scopes", default: "", null: false t.datetime "created_at" t.datetime "updated_at" - t.boolean "superapp", default: false, null: false - t.string "website" - t.integer "owner_id" - t.string "owner_type" - t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree + t.boolean "superapp", default: false, null: false + t.string "website" + t.integer "owner_id" + t.string "owner_type" + t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type" t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true end @@ -423,6 +423,7 @@ ActiveRecord::Schema.define(version: 20170720000000) do add_foreign_key "oauth_access_grants", "users", column: "resource_owner_id", on_delete: :cascade add_foreign_key "oauth_access_tokens", "oauth_applications", column: "application_id", on_delete: :cascade add_foreign_key "oauth_access_tokens", "users", column: "resource_owner_id", on_delete: :cascade + add_foreign_key "oauth_applications", "users", column: "owner_id", on_delete: :cascade add_foreign_key "preview_cards", "statuses", on_delete: :cascade add_foreign_key "reports", "accounts", column: "action_taken_by_account_id", on_delete: :nullify add_foreign_key "reports", "accounts", column: "target_account_id", on_delete: :cascade diff --git a/spec/controllers/settings/applications_controller_spec.rb b/spec/controllers/settings/applications_controller_spec.rb index fa27e6ec6..7902a4334 100644 --- a/spec/controllers/settings/applications_controller_spec.rb +++ b/spec/controllers/settings/applications_controller_spec.rb @@ -156,7 +156,7 @@ describe Settings::ApplicationsController do let(:token) { user.token_for_app(app) } before do expect(token).to_not be_nil - put :regenerate, params: { application_id: app.id } + post :regenerate, params: { id: app.id } end it 'should create new token' do -- cgit From 80393a23d0a0c296d4356a2a21cf8504435265bf Mon Sep 17 00:00:00 2001 From: nullkal Date: Wed, 23 Aug 2017 22:16:20 +0900 Subject: Use checkboxes for application scope setting (#4671) --- .../settings/applications_controller.rb | 6 +++++ app/views/settings/applications/_fields.html.haml | 14 ++++++++-- .../settings/applications_controller_spec.rb | 30 +++++++++++++++++++--- 3 files changed, 44 insertions(+), 6 deletions(-) (limited to 'app/controllers/settings') diff --git a/app/controllers/settings/applications_controller.rb b/app/controllers/settings/applications_controller.rb index 894222c2a..8fc9a0fa9 100644 --- a/app/controllers/settings/applications_controller.rb +++ b/app/controllers/settings/applications_controller.rb @@ -5,6 +5,7 @@ class Settings::ApplicationsController < ApplicationController before_action :authenticate_user! before_action :set_application, only: [:show, :update, :destroy, :regenerate] + before_action :prepare_scopes, only: [:create, :update] def index @applications = current_user.applications.page(params[:page]) @@ -63,4 +64,9 @@ class Settings::ApplicationsController < ApplicationController :website ) end + + def prepare_scopes + scopes = params.fetch(:doorkeeper_application, {}).fetch(:scopes, nil) + params[:doorkeeper_application][:scopes] = scopes.join(' ') if scopes.is_a? Array + end end diff --git a/app/views/settings/applications/_fields.html.haml b/app/views/settings/applications/_fields.html.haml index 536f69e04..83297a1ae 100644 --- a/app/views/settings/applications/_fields.html.haml +++ b/app/views/settings/applications/_fields.html.haml @@ -7,5 +7,15 @@ %p.hint= t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: Doorkeeper.configuration.native_redirect_uri) -.fields-group - = f.input :scopes, wrapper: :with_label, label: t('activerecord.attributes.doorkeeper/application.scopes'), hint: t('doorkeeper.applications.help.scopes') +.field-group + = f.input :scopes, + label: t('activerecord.attributes.doorkeeper/application.scopes'), + collection: Doorkeeper.configuration.scopes, + wrapper: :with_label, + include_blank: false, + selected: f.object.scopes.all, + required: false, + as: :check_boxes, + collection_wrapper_tag: 'ul', + item_wrapper_tag: 'li' + diff --git a/spec/controllers/settings/applications_controller_spec.rb b/spec/controllers/settings/applications_controller_spec.rb index 7902a4334..ca66f8d23 100644 --- a/spec/controllers/settings/applications_controller_spec.rb +++ b/spec/controllers/settings/applications_controller_spec.rb @@ -45,7 +45,7 @@ describe Settings::ApplicationsController do end describe 'POST #create' do - context 'success' do + context 'success (passed scopes as a String)' do def call_create post :create, params: { doorkeeper_application: { @@ -61,7 +61,29 @@ describe Settings::ApplicationsController do it 'creates an entry in the database' do expect { call_create }.to change(Doorkeeper::Application, :count) end - + + it 'redirects back to applications page' do + expect(call_create).to redirect_to(settings_applications_path) + end + end + + context 'success (passed scopes as an Array)' do + def call_create + post :create, params: { + doorkeeper_application: { + name: 'My New App', + redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', + website: 'http://google.com', + scopes: [ 'read', 'write', 'follow' ] + } + } + response + end + + it 'creates an entry in the database' do + expect { call_create }.to change(Doorkeeper::Application, :count) + end + it 'redirects back to applications page' do expect(call_create).to redirect_to(settings_applications_path) end @@ -74,7 +96,7 @@ describe Settings::ApplicationsController do name: '', redirect_uri: '', website: '', - scopes: '' + scopes: [] } } end @@ -123,7 +145,7 @@ describe Settings::ApplicationsController do name: '', redirect_uri: '', website: '', - scopes: '' + scopes: [] } } end -- cgit From 649a20ab46eadf9ae3bfc30782ae62379383bd72 Mon Sep 17 00:00:00 2001 From: masarakki Date: Sat, 26 Aug 2017 19:40:03 +0900 Subject: authorize-follow-requests-after-unlocking (#4658) --- .../api/v1/accounts/credentials_controller.rb | 2 +- app/controllers/settings/profiles_controller.rb | 2 +- app/services/update_account_service.rb | 21 +++++++++++++++++++++ app/workers/authorize_follow_worker.rb | 14 ++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 app/services/update_account_service.rb create mode 100644 app/workers/authorize_follow_worker.rb (limited to 'app/controllers/settings') diff --git a/app/controllers/api/v1/accounts/credentials_controller.rb b/app/controllers/api/v1/accounts/credentials_controller.rb index bea83cd2a..da534d960 100644 --- a/app/controllers/api/v1/accounts/credentials_controller.rb +++ b/app/controllers/api/v1/accounts/credentials_controller.rb @@ -12,7 +12,7 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController def update @account = current_account - @account.update!(account_params) + UpdateAccountService.new.call(@account, account_params, raise_error: true) ActivityPub::UpdateDistributionWorker.perform_async(@account.id) render json: @account, serializer: REST::CredentialAccountSerializer end diff --git a/app/controllers/settings/profiles_controller.rb b/app/controllers/settings/profiles_controller.rb index c751c64ae..28f78a4fb 100644 --- a/app/controllers/settings/profiles_controller.rb +++ b/app/controllers/settings/profiles_controller.rb @@ -14,7 +14,7 @@ class Settings::ProfilesController < ApplicationController def show; end def update - if @account.update(account_params) + if UpdateAccountService.new.call(@account, account_params) ActivityPub::UpdateDistributionWorker.perform_async(@account.id) redirect_to settings_profile_path, notice: I18n.t('generic.changes_saved_msg') else diff --git a/app/services/update_account_service.rb b/app/services/update_account_service.rb new file mode 100644 index 000000000..09ea377e7 --- /dev/null +++ b/app/services/update_account_service.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class UpdateAccountService < BaseService + def call(account, params, raise_error: false) + was_locked = account.locked + update_method = raise_error ? :update! : :update + account.send(update_method, params).tap do |ret| + next unless ret + authorize_all_follow_requests(account) if was_locked && !account.locked + end + end + + private + + def authorize_all_follow_requests(account) + follow_requests = FollowRequest.where(target_account: account) + AuthorizeFollowWorker.push_bulk(follow_requests) do |req| + [req.account_id, req.target_account_id] + end + end +end diff --git a/app/workers/authorize_follow_worker.rb b/app/workers/authorize_follow_worker.rb new file mode 100644 index 000000000..0d5014624 --- /dev/null +++ b/app/workers/authorize_follow_worker.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class AuthorizeFollowWorker + include Sidekiq::Worker + + def perform(source_account_id, target_account_id) + source_account = Account.find(source_account_id) + target_account = Account.find(target_account_id) + + AuthorizeFollowService.new.call(source_account, target_account) + rescue ActiveRecord::RecordNotFound + true + end +end -- cgit