summaryrefslogtreecommitdiffstats
path: root/app/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'app/controllers')
-rw-r--r--app/controllers/account_controller.rb3
-rw-r--r--app/controllers/admin_controller.rb4
-rw-r--r--app/controllers/application_controller.rb22
-rw-r--r--app/controllers/auto_completes_controller.rb2
-rw-r--r--app/controllers/context_menus_controller.rb2
-rw-r--r--app/controllers/issues_controller.rb27
-rw-r--r--app/controllers/messages_controller.rb4
-rw-r--r--app/controllers/my_controller.rb1
-rw-r--r--app/controllers/news_controller.rb4
-rw-r--r--app/controllers/oauth2_applications_controller.rb38
-rw-r--r--app/controllers/previews_controller.rb6
-rw-r--r--app/controllers/projects_controller.rb2
-rw-r--r--app/controllers/queries_controller.rb34
-rw-r--r--app/controllers/reactions_controller.rb65
-rw-r--r--app/controllers/repositories_controller.rb10
-rw-r--r--app/controllers/roles_controller.rb10
-rw-r--r--app/controllers/twofa_backup_codes_controller.rb4
-rw-r--r--app/controllers/twofa_controller.rb16
-rw-r--r--app/controllers/versions_controller.rb4
-rw-r--r--app/controllers/wiki_controller.rb1
20 files changed, 213 insertions, 46 deletions
diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb
index 5e615d17f..ea75d5de1 100644
--- a/app/controllers/account_controller.rb
+++ b/app/controllers/account_controller.rb
@@ -36,6 +36,7 @@ class AccountController < ApplicationController
redirect_back_or_default home_url, :referer => true
end
end
+ no_store
rescue AuthSourceException => e
logger.error "An error occurred when authenticating #{params[:username]}: #{e.message}"
render_error :message => e.message
@@ -95,6 +96,7 @@ class AccountController < ApplicationController
end
end
end
+ no_store
render :template => "account/password_recovery"
return
else
@@ -218,6 +220,7 @@ class AccountController < ApplicationController
def twofa_confirm
@twofa_view = @twofa.otp_confirm_view_variables
+ no_store
end
def twofa
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
index 892629af1..9b45f9553 100644
--- a/app/controllers/admin_controller.rb
+++ b/app/controllers/admin_controller.rb
@@ -36,9 +36,7 @@ class AdminController < ApplicationController
end
def projects
- retrieve_query(ProjectQuery, false, :defaults => @default_columns_names)
- @query.admin_projects = 1
-
+ retrieve_query(ProjectAdminQuery, false, :defaults => @default_columns_names)
@entry_count = @query.result_count
@entry_pages = Paginator.new @entry_count, per_page_option, params['page']
@projects = @query.results_scope(:limit => @entry_pages.per_page, :offset => @entry_pages.offset).to_a
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 111c85bc5..a01d5c75f 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -131,6 +131,14 @@ class ApplicationController < ActionController::Base
if (key = api_key_from_request)
# Use API key
user = User.find_by_api_key(key)
+ elsif access_token = Doorkeeper.authenticate(request)
+ # Oauth
+ if access_token.accessible?
+ user = User.active.find_by_id(access_token.resource_owner_id)
+ user.oauth_scope = access_token.scopes.all.map(&:to_sym)
+ else
+ doorkeeper_render_error
+ end
elsif /\ABasic /i.match?(request.authorization.to_s)
# HTTP Basic, either username/password or API key/random
authenticate_with_http_basic do |username, password|
@@ -482,15 +490,17 @@ class ApplicationController < ActionController::Base
end
helper_method :back_url
- def redirect_back_or_default(default, options={})
+ def redirect_back_or_default(default, options = {})
+ referer = options.delete(:referer)
+
if back_url = validate_back_url(params[:back_url].to_s)
redirect_to(back_url)
return
- elsif options[:referer]
+ elsif referer
redirect_to_referer_or default
return
end
- redirect_to default
+ redirect_to default, options
false
end
@@ -509,11 +519,9 @@ class ApplicationController < ActionController::Base
if uri.send(component).present? && uri.send(component) != request.send(component)
return false
end
-
- uri.send(:"#{component}=", nil)
end
- # Always ignore basic user:password in the URL
- uri.userinfo = nil
+ # Remove unnecessary components to convert the URL into a relative URL
+ uri.omit!(:scheme, :authority)
rescue Addressable::URI::InvalidURIError
return false
end
diff --git a/app/controllers/auto_completes_controller.rb b/app/controllers/auto_completes_controller.rb
index 2982447e9..77105c8e8 100644
--- a/app/controllers/auto_completes_controller.rb
+++ b/app/controllers/auto_completes_controller.rb
@@ -26,7 +26,7 @@ class AutoCompletesController < ApplicationController
status = params[:status].to_s
issue_id = params[:issue_id].to_s
- scope = Issue.cross_project_scope(@project, params[:scope]).visible
+ scope = Issue.cross_project_scope(@project, params[:scope]).includes(:tracker).visible
scope = scope.open(status == 'o') if status.present?
scope = scope.where.not(:id => issue_id.to_i) if issue_id.present?
if q.present?
diff --git a/app/controllers/context_menus_controller.rb b/app/controllers/context_menus_controller.rb
index 4c7305873..1e37f623b 100644
--- a/app/controllers/context_menus_controller.rb
+++ b/app/controllers/context_menus_controller.rb
@@ -33,7 +33,7 @@ class ContextMenusController < ApplicationController
@can = {
:edit => @issues.all?(&:attributes_editable?),
- :log_time => (@project && User.current.allowed_to?(:log_time, @project)),
+ :log_time => @issue&.time_loggable?,
:copy => User.current.allowed_to?(:copy_issues, @projects) && Issue.allowed_target_projects.any?,
:add_watchers => User.current.allowed_to?(:add_issue_watchers, @projects),
:delete => @issues.all?(&:deletable?),
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb
index c5af8658f..a9c3f6183 100644
--- a/app/controllers/issues_controller.rb
+++ b/app/controllers/issues_controller.rb
@@ -112,8 +112,13 @@ class IssuesController < ApplicationController
respond_to do |format|
format.html do
@priorities = IssuePriority.active
- @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
- @time_entries = @issue.time_entries.visible.preload(:activity, :user)
+ if @project.module_enabled?(:time_tracking)
+ @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
+ @time_entries = @issue.time_entries.visible.preload(:activity, :user)
+ else
+ @time_entry = nil
+ @time_entries = []
+ end
@relation = IssueRelation.new
@has_changesets = @issue.changesets.visible.preload(:repository, :user).exists?
retrieve_previous_and_next_issue_ids
@@ -224,9 +229,8 @@ class IssuesController < ApplicationController
end
respond_to do |format|
format.html do
- redirect_back_or_default(
- issue_path(@issue, previous_and_next_issue_ids_params)
- )
+ redirect_back_or_default issue_path(@issue),
+ flash: { previous_and_next_issue_ids: previous_and_next_issue_ids_params }
end
format.api {render_api_ok}
end
@@ -512,11 +516,14 @@ class IssuesController < ApplicationController
end
def retrieve_previous_and_next_issue_ids
- if params[:prev_issue_id].present? || params[:next_issue_id].present?
- @prev_issue_id = params[:prev_issue_id].presence.try(:to_i)
- @next_issue_id = params[:next_issue_id].presence.try(:to_i)
- @issue_position = params[:issue_position].presence.try(:to_i)
- @issue_count = params[:issue_count].presence.try(:to_i)
+ if flash.key?(:previous_and_next_issue_ids)
+ flash[:previous_and_next_issue_ids].then do |info|
+ @prev_issue_id = info[:prev_issue_id].presence.try(:to_i)
+ @next_issue_id = info[:next_issue_id].presence.try(:to_i)
+ @issue_position = info[:issue_position].presence.try(:to_i)
+ @issue_count = info[:issue_count].presence.try(:to_i)
+ end
+ flash.delete(:previous_and_next_issue_ids)
else
retrieve_query_from_session
if @query
diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb
index 5159bf540..8b26bee73 100644
--- a/app/controllers/messages_controller.rb
+++ b/app/controllers/messages_controller.rb
@@ -51,6 +51,8 @@ class MessagesController < ApplicationController
offset(@reply_pages.offset).
to_a
+ Message.preload_reaction_details(@replies)
+
@reply = Message.new(:subject => "RE: #{@message.subject}")
render :action => "show", :layout => false if request.xhr?
end
@@ -134,7 +136,7 @@ class MessagesController < ApplicationController
def preview
message = @board.messages.find_by_id(params[:id])
- @text = params[:text] ? params[:text] : nil
+ @text = params[:text] || nil
@previewed = message
render :partial => 'common/preview'
end
diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb
index 01fe3995c..35483c8ef 100644
--- a/app/controllers/my_controller.rb
+++ b/app/controllers/my_controller.rb
@@ -115,6 +115,7 @@ class MyController < ApplicationController
end
end
end
+ no_store
end
# Create a new feeds key
diff --git a/app/controllers/news_controller.rb b/app/controllers/news_controller.rb
index 06240e359..dd6bade24 100644
--- a/app/controllers/news_controller.rb
+++ b/app/controllers/news_controller.rb
@@ -67,8 +67,10 @@ class NewsController < ApplicationController
end
def show
- @comments = @news.comments.to_a
+ @comments = @news.comments.preload(:commented).to_a
@comments.reverse! if User.current.wants_comments_in_reverse_order?
+
+ Comment.preload_reaction_details(@comments)
end
def new
diff --git a/app/controllers/oauth2_applications_controller.rb b/app/controllers/oauth2_applications_controller.rb
new file mode 100644
index 000000000..107af2ec0
--- /dev/null
+++ b/app/controllers/oauth2_applications_controller.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+#
+# Redmine - project management software
+# Copyright (C) 2006- Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+class Oauth2ApplicationsController < Doorkeeper::ApplicationsController
+ private
+
+ def application_params
+ params[:doorkeeper_application] ||= {}
+ params[:doorkeeper_application][:scopes] ||= []
+
+ scopes = Redmine::AccessControl.public_permissions.map{|p| p.name.to_s}
+
+ if params[:doorkeeper_application][:scopes].is_a?(Array)
+ scopes |= params[:doorkeeper_application][:scopes]
+ else
+ scopes |= params[:doorkeeper_application][:scopes].split(/\s+/)
+ end
+ params[:doorkeeper_application][:scopes] = scopes.join(' ')
+ super
+ end
+end
diff --git a/app/controllers/previews_controller.rb b/app/controllers/previews_controller.rb
index 9dd228a3d..744daa7c8 100644
--- a/app/controllers/previews_controller.rb
+++ b/app/controllers/previews_controller.rb
@@ -26,7 +26,7 @@ class PreviewsController < ApplicationController
if @issue
@previewed = @issue
end
- @text = params[:text] ? params[:text] : nil
+ @text = params[:text] || nil
render :partial => 'common/preview'
end
@@ -34,12 +34,12 @@ class PreviewsController < ApplicationController
if params[:id].present? && news = News.visible.find_by_id(params[:id])
@previewed = news
end
- @text = params[:text] ? params[:text] : nil
+ @text = params[:text] || nil
render :partial => 'common/preview'
end
def text
- @text = params[:text] ? params[:text] : nil
+ @text = params[:text] || nil
render :partial => 'common/preview'
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index f9a390c58..2a42c99ed 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -176,7 +176,7 @@ class ProjectsController < ApplicationController
respond_to do |format|
format.html do
@principals_by_role = @project.principals_by_role
- @subprojects = @project.children.visible.to_a
+ @subprojects = @project.leaf? ? [] : @project.children.visible.to_a
@news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").to_a
with_subprojects = Setting.display_subprojects_issues?
@trackers = @project.rolled_up_trackers(with_subprojects).visible
diff --git a/app/controllers/queries_controller.rb b/app/controllers/queries_controller.rb
index 53ce029b9..24f37eda2 100644
--- a/app/controllers/queries_controller.rb
+++ b/app/controllers/queries_controller.rb
@@ -19,6 +19,8 @@
class QueriesController < ApplicationController
menu_item :issues
+ layout :query_layout
+
before_action :find_query, :only => [:edit, :update, :destroy]
before_action :find_optional_project, :only => [:new, :create]
@@ -52,7 +54,6 @@ class QueriesController < ApplicationController
@query.user = User.current
@query.project = @project
@query.build_from_params(params)
- render :layout => 'admin' if params[:admin_projects]
end
def create
@@ -63,14 +64,13 @@ class QueriesController < ApplicationController
if @query.save
flash[:notice] = l(:notice_successful_create)
- redirect_to_items(:query_id => @query, :admin_projects => params[:admin_projects])
+ redirect_to_items(:query_id => @query)
else
render :action => 'new', :layout => !request.xhr?
end
end
def edit
- render :layout => 'admin' if params[:admin_projects]
end
def update
@@ -78,7 +78,7 @@ class QueriesController < ApplicationController
if @query.save
flash[:notice] = l(:notice_successful_update)
- redirect_to_items(:query_id => @query, :admin_projects => params[:admin_projects])
+ redirect_to_items(:query_id => @query)
else
render :action => 'edit'
end
@@ -109,18 +109,20 @@ class QueriesController < ApplicationController
end
def current_menu_item
- @query ? @query.queried_class.to_s.underscore.pluralize.to_sym : nil
+ return unless @query
+ return if query_layout == 'admin'
+
+ @query.queried_class.to_s.underscore.pluralize.to_sym
end
def current_menu(project)
- super if params[:admin_projects].nil?
+ super unless query_layout == 'admin'
end
private
def find_query
@query = Query.find(params[:id])
- @query.admin_projects = params[:admin_projects] if @query.is_a?(ProjectQuery)
@project = @query.project
render_403 unless @query.editable_by?(User.current)
rescue ActiveRecord::RecordNotFound
@@ -171,17 +173,25 @@ class QueriesController < ApplicationController
end
def redirect_to_project_query(options)
- if params[:admin_projects]
- redirect_to admin_projects_path(options)
- else
- redirect_to projects_path(options)
- end
+ redirect_to projects_path(options)
+ end
+
+ def redirect_to_project_admin_query(options)
+ redirect_to admin_projects_path(options)
end
def redirect_to_user_query(options)
redirect_to users_path(options)
end
+ def query_layout
+ @query&.layout || 'base'
+ end
+
+ def menu_items
+ {self.controller_name.to_sym => {:actions => {}, :default => current_menu_item}}
+ end
+
# Returns the Query subclass, IssueQuery by default
# for compatibility with previous behaviour
def query_class
diff --git a/app/controllers/reactions_controller.rb b/app/controllers/reactions_controller.rb
new file mode 100644
index 000000000..71b37e5f8
--- /dev/null
+++ b/app/controllers/reactions_controller.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006- Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+class ReactionsController < ApplicationController
+ before_action :require_login
+
+ before_action :check_enabled
+ before_action :set_object, :authorize_reactable
+
+ def create
+ respond_to do |format|
+ format.js do
+ @object.reactions.find_or_create_by!(user: User.current)
+ end
+ format.any { head :not_found }
+ end
+ end
+
+ def destroy
+ respond_to do |format|
+ format.js do
+ reaction = @object.reactions.by(User.current).find_by(id: params[:id])
+ reaction&.destroy
+ end
+ format.any { head :not_found }
+ end
+ end
+
+ private
+
+ def check_enabled
+ render_403 unless Setting.reactions_enabled?
+ end
+
+ def set_object
+ object_type = params[:object_type]
+
+ unless Redmine::Reaction::REACTABLE_TYPES.include?(object_type)
+ render_403
+ return
+ end
+
+ @object = object_type.constantize.find(params[:object_id])
+ end
+
+ def authorize_reactable
+ render_403 unless Redmine::Reaction.editable?(@object, User.current)
+ end
+end
diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb
index 9be7878ce..d6a13daf2 100644
--- a/app/controllers/repositories_controller.rb
+++ b/app/controllers/repositories_controller.rb
@@ -160,7 +160,15 @@ class RepositoriesController < ApplicationController
# Force the download
send_opt = {:filename => filename_for_content_disposition(@path.split('/').last)}
send_type = Redmine::MimeType.of(@path)
- send_opt[:type] = send_type.to_s if send_type
+ case send_type
+ when nil
+ # No MIME type detected. Let Rails use the default type.
+ when 'application/javascript'
+ # Avoid ActionController::InvalidCrossOriginRequest exception by setting non-JS content type
+ send_opt[:type] = 'text/plain'
+ else
+ send_opt[:type] = send_type
+ end
send_opt[:disposition] = disposition(@path)
send_data @repository.cat(@path, @rev), send_opt
else
diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb
index dfe7c2b8f..89f9ee497 100644
--- a/app/controllers/roles_controller.rb
+++ b/app/controllers/roles_controller.rb
@@ -99,7 +99,15 @@ class RolesController < ApplicationController
begin
@role.destroy
rescue
- flash[:error] = l(:error_can_not_remove_role)
+ flash[:error] = l(:error_can_not_remove_role)
+
+ if @role.members.present?
+ projects = Project.joins(members: :member_roles).where(member_roles: { role_id: @role.id }).distinct.sorted
+ links = projects.map do |p|
+ view_context.link_to(p, settings_project_path(p, tab: 'members'))
+ end.join(', ')
+ flash[:error] += l(:error_can_not_remove_role_reason_members_html, projects: links)
+ end
end
redirect_to roles_path
end
diff --git a/app/controllers/twofa_backup_codes_controller.rb b/app/controllers/twofa_backup_codes_controller.rb
index 8e14247b0..923b9671b 100644
--- a/app/controllers/twofa_backup_codes_controller.rb
+++ b/app/controllers/twofa_backup_codes_controller.rb
@@ -26,7 +26,7 @@ class TwofaBackupCodesController < ApplicationController
before_action :twofa_setup
- require_sudo_mode :init
+ require_sudo_mode :init, :confirm, :create, :show
def init
if @twofa.send_code(controller: 'twofa_backup_codes', action: 'create')
@@ -37,6 +37,7 @@ class TwofaBackupCodesController < ApplicationController
def confirm
@twofa_view = @twofa.otp_confirm_view_variables
+ no_store
end
def create
@@ -64,6 +65,7 @@ class TwofaBackupCodesController < ApplicationController
if tokens.present? && (@created_at = tokens.collect(&:created_on).max) > 5.minutes.ago
@backup_codes = tokens.collect(&:value)
+ no_store
else
flash[:warning] = l('twofa_backup_codes_already_shown', bc_path: my_twofa_backup_codes_init_path)
redirect_to controller: 'my', action: 'account'
diff --git a/app/controllers/twofa_controller.rb b/app/controllers/twofa_controller.rb
index 446d2f105..3023caa9b 100644
--- a/app/controllers/twofa_controller.rb
+++ b/app/controllers/twofa_controller.rb
@@ -27,10 +27,14 @@ class TwofaController < ApplicationController
before_action :require_active_twofa
- require_sudo_mode :activate_init, :deactivate_init
+ require_sudo_mode :select_scheme,
+ :activate_init, :activate_confirm, :activate,
+ :deactivate_init, :deactivate_confirm, :deactivate
skip_before_action :check_twofa_activation, only: [:select_scheme, :activate_init, :activate_confirm, :activate]
+ before_action :ensure_user_has_no_twofa, only: [:select_scheme, :activate_init, :activate_confirm, :activate]
+
def select_scheme
@user = User.current
end
@@ -43,6 +47,7 @@ class TwofaController < ApplicationController
def activate_confirm
@twofa_view = @twofa.init_pairing_view_variables
+ no_store
end
def activate
@@ -114,4 +119,13 @@ class TwofaController < ApplicationController
redirect_to my_account_path
end
end
+
+ def ensure_user_has_no_twofa
+ # Allow activating a new 2FA scheme / showing twofa secret only if no other
+ # is already configured
+ return true if User.current.twofa_scheme.blank?
+
+ flash[:warning] = l('twofa_already_setup')
+ redirect_to controller: 'my', action: 'account'
+ end
end
diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb
index d52b43ba3..328d3e56e 100644
--- a/app/controllers/versions_controller.rb
+++ b/app/controllers/versions_controller.rb
@@ -51,7 +51,7 @@ class VersionsController < ApplicationController
if @selected_tracker_ids.any? && @versions.any?
issues = Issue.visible.
includes(:project, :tracker).
- preload(:status, :priority, :fixed_version).
+ preload(:status, :priority, :fixed_version, {:assigned_to => :email_address}).
where(:tracker_id => @selected_tracker_ids, :project_id => project_ids, :fixed_version_id => @versions.map(&:id)).
order("#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id")
@issues_by_version = issues.group_by(&:fixed_version)
@@ -69,7 +69,7 @@ class VersionsController < ApplicationController
format.html do
@issues = @version.fixed_issues.visible.
includes(:status, :tracker, :priority).
- preload(:project).
+ preload(:project, {:assigned_to => :email_address}).
reorder("#{Tracker.table_name}.position, #{Issue.table_name}.id").
to_a
end
diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb
index 36b90da77..bcb3b0891 100644
--- a/app/controllers/wiki_controller.rb
+++ b/app/controllers/wiki_controller.rb
@@ -240,6 +240,7 @@ class WikiController < ApplicationController
# don't load text
@versions = @page.content.versions.
select("id, author_id, comments, updated_on, version").
+ preload(:author).
reorder('version DESC').
limit(@version_pages.per_page + 1).
offset(@version_pages.offset).