diff options
author | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2017-03-21 14:22:56 +0100 |
---|---|---|
committer | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2017-03-21 14:22:56 +0100 |
commit | c5912ecd73560b730eda625c77d900ca23ab16d5 (patch) | |
tree | 8f7288b6209fb7e542e5d3bf867138ea6bde7faf /app/controllers | |
parent | 53d332d3c73f8a883fa54d8eaaf91f92da73c33f (diff) | |
parent | 1e5888d115df1973cd5af0aa95013dbbf29ddefd (diff) | |
download | gitlab-ce-c5912ecd73560b730eda625c77d900ca23ab16d5.tar.gz |
Merge branch 'master' into feature/multi-level-container-registry-images
* master: (1327 commits)
Merge branch 'render-json-leak' into 'security'
Merge branch 'ssrf' into 'security'
Merge branch 'ssrf' into 'security'
Merge branch 'fix-links-target-blank' into 'security'
Merge branch '28058-hide-emails-in-atom-feeds' into 'security'
Fix karma test
Reset filters after click
Handle Route#name being nil after an update
Only add frontend code coverage instrumentation when generating coverage report
fix recompile assets step in 9.0 upgrade guide to use yarn
Undo explicit conversion to Integer
Make level_value accept string integers
Make feature spec more robust
Removed d3.js from the main application.js bundle
Extend compound status for manual actions specs
Update css to be nice and tidy.
Fix pipeline status for transition between stages
add an index to the ghost column
Return 404 in project issues API endpoint when project cannot be found
Improve rename projects migration
...
Conflicts:
doc/ci/docker/using_docker_build.md
spec/lib/gitlab/import_export/all_models.yml
Diffstat (limited to 'app/controllers')
63 files changed, 651 insertions, 457 deletions
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index fb6df1a06d2..1d0bd6e0b81 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -89,6 +89,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :akismet_api_key, :akismet_enabled, :container_registry_token_expire_delay, + :default_artifacts_expire_in, :default_branch_protection, :default_group_visibility, :default_project_visibility, @@ -143,6 +144,9 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :two_factor_grace_period, :user_default_external, :user_oauth_applications, + :unique_ips_limit_per_user, + :unique_ips_limit_time_window, + :unique_ips_limit_enabled, :version_check_enabled, :terminal_max_session_time, diff --git a/app/controllers/admin/applications_controller.rb b/app/controllers/admin/applications_controller.rb index 62f62e99a97..9c9f420c1e0 100644 --- a/app/controllers/admin/applications_controller.rb +++ b/app/controllers/admin/applications_controller.rb @@ -2,7 +2,7 @@ class Admin::ApplicationsController < Admin::ApplicationController include OauthApplications before_action :set_application, only: [:show, :edit, :update, :destroy] - before_action :load_scopes, only: [:new, :edit] + before_action :load_scopes, only: [:new, :create, :edit, :update] def index @applications = Doorkeeper::Application.where("owner_id IS NULL") diff --git a/app/controllers/admin/health_check_controller.rb b/app/controllers/admin/health_check_controller.rb index 241c7be0ea1..caf4c138da8 100644 --- a/app/controllers/admin/health_check_controller.rb +++ b/app/controllers/admin/health_check_controller.rb @@ -1,5 +1,5 @@ class Admin::HealthCheckController < Admin::ApplicationController def show - @errors = HealthCheck::Utils.process_checks('standard') + @errors = HealthCheck::Utils.process_checks(['standard']) end end diff --git a/app/controllers/admin/impersonation_tokens_controller.rb b/app/controllers/admin/impersonation_tokens_controller.rb new file mode 100644 index 00000000000..07c8bf714fc --- /dev/null +++ b/app/controllers/admin/impersonation_tokens_controller.rb @@ -0,0 +1,53 @@ +class Admin::ImpersonationTokensController < Admin::ApplicationController + before_action :user + + def index + set_index_vars + end + + def create + @impersonation_token = finder.build(impersonation_token_params) + + if @impersonation_token.save + flash[:impersonation_token] = @impersonation_token.token + redirect_to admin_user_impersonation_tokens_path, notice: "A new impersonation token has been created." + else + set_index_vars + render :index + end + end + + def revoke + @impersonation_token = finder.find(params[:id]) + + if @impersonation_token.revoke! + flash[:notice] = "Revoked impersonation token #{@impersonation_token.name}!" + else + flash[:alert] = "Could not revoke impersonation token #{@impersonation_token.name}." + end + + redirect_to admin_user_impersonation_tokens_path + end + + private + + def user + @user ||= User.find_by!(username: params[:user_id]) + end + + def finder(options = {}) + PersonalAccessTokensFinder.new({ user: user, impersonation: true }.merge(options)) + end + + def impersonation_token_params + params.require(:personal_access_token).permit(:name, :expires_at, :impersonation, scopes: []) + end + + def set_index_vars + @scopes = Gitlab::Auth::API_SCOPES + + @impersonation_token ||= finder.build + @inactive_impersonation_tokens = finder(state: 'inactive').execute + @active_impersonation_tokens = finder(state: 'active').execute.order(:expires_at) + end +end diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index 39c8c6d8a0c..daecfc832bf 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -14,6 +14,15 @@ class Admin::ProjectsController < Admin::ApplicationController @projects = @projects.search(params[:name]) if params[:name].present? @projects = @projects.sort(@sort = params[:sort]) @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]) + + respond_to do |format| + format.html + format.json do + render json: { + html: view_to_html_string("admin/projects/_projects", locals: { projects: @projects }) + } + end + end end def show diff --git a/app/controllers/admin/system_info_controller.rb b/app/controllers/admin/system_info_controller.rb index 1330399a836..99039724521 100644 --- a/app/controllers/admin/system_info_controller.rb +++ b/app/controllers/admin/system_info_controller.rb @@ -3,7 +3,7 @@ class Admin::SystemInfoController < Admin::ApplicationController 'nobrowse', 'read-only', 'ro' - ] + ].freeze EXCLUDED_MOUNT_TYPES = [ 'autofs', @@ -27,7 +27,7 @@ class Admin::SystemInfoController < Admin::ApplicationController 'tmpfs', 'tracefs', 'vfat' - ] + ].freeze def show @cpus = Vmstat.cpu rescue nil diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 7ffde71c3b1..24504685e48 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -29,11 +29,7 @@ class Admin::UsersController < Admin::ApplicationController end def impersonate - if user.blocked? - flash[:alert] = "You cannot impersonate a blocked user" - - redirect_to admin_user_path(user) - else + if can?(user, :log_in) session[:impersonator_id] = current_user.id warden.set_user(user, scope: :user) @@ -43,6 +39,17 @@ class Admin::UsersController < Admin::ApplicationController flash[:alert] = "You are now impersonating #{user.username}" redirect_to root_path + else + flash[:alert] = + if user.blocked? + "You cannot impersonate a blocked user" + elsif user.internal? + "You cannot impersonate an internal user" + else + "You cannot impersonate a user who cannot log in" + end + + redirect_to admin_user_path(user) end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5e7af3bff0d..b7ce081a5cd 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -40,6 +40,10 @@ class ApplicationController < ActionController::Base render_403 end + rescue_from Gitlab::Auth::TooManyIps do |e| + head :forbidden, retry_after: Gitlab::Auth::UniqueIpsLimiter.config.unique_ips_limit_time_window + end + def redirect_back_or_default(default: root_path, options: {}) redirect_to request.referer.present? ? :back : default, options end @@ -63,7 +67,7 @@ class ApplicationController < ActionController::Base token_string = params[:private_token].presence || request.headers['PRIVATE-TOKEN'].presence user = User.find_by_authentication_token(token_string) || User.find_by_personal_access_token(token_string) - if user + if user && can?(user, :log_in) # Notice we are passing store false, so the user is not # actually stored in the session and a token is needed # for every request. If you want the token to work as a @@ -72,14 +76,6 @@ class ApplicationController < ActionController::Base end end - def authenticate_user!(*args) - if redirect_to_home_page_url? - return redirect_to current_application_settings.home_page_url - end - - super(*args) - end - def log_exception(exception) application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace application_trace.map!{ |t| " #{t}\n" } @@ -94,7 +90,7 @@ class ApplicationController < ActionController::Base current_application_settings.after_sign_out_path.presence || new_user_session_path end - def can?(object, action, subject) + def can?(object, action, subject = :global) Ability.allowed?(object, action, subject) end @@ -130,10 +126,6 @@ class ApplicationController < ActionController::Base headers['X-XSS-Protection'] = '1; mode=block' headers['X-UA-Compatible'] = 'IE=edge' headers['X-Content-Type-Options'] = 'nosniff' - # Enabling HSTS for non-standard ports would send clients to the wrong port - if Gitlab.config.gitlab.https && Gitlab.config.gitlab.port == 443 - headers['Strict-Transport-Security'] = 'max-age=31536000' - end end def validate_user_service_ticket! @@ -181,7 +173,7 @@ class ApplicationController < ActionController::Base end def gitlab_ldap_access(&block) - Gitlab::LDAP::Access.open { |access| block.call(access) } + Gitlab::LDAP::Access.open { |access| yield(access) } end # JSON for infinite scroll via Pager object @@ -287,19 +279,6 @@ class ApplicationController < ActionController::Base session[:skip_tfa] && session[:skip_tfa] > Time.current end - def redirect_to_home_page_url? - # If user is not signed-in and tries to access root_path - redirect him to landing page - # Don't redirect to the default URL to prevent endless redirections - return false unless current_application_settings.home_page_url.present? - - home_page_url = current_application_settings.home_page_url.chomp('/') - root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')] - - return false if root_urls.include?(home_page_url) - - current_user.nil? && root_path == request.path - end - # U2F (universal 2nd factor) devices need a unique identifier for the application # to perform authentication. # https://developers.yubico.com/U2F/App_ID.html diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb index d7a45bacd35..b79ca034c5b 100644 --- a/app/controllers/autocomplete_controller.rb +++ b/app/controllers/autocomplete_controller.rb @@ -18,8 +18,7 @@ class AutocompleteController < ApplicationController if params[:search].blank? # Include current user if available to filter by "Me" if params[:current_user].present? && current_user - @users = @users.where.not(id: current_user.id) - @users = [current_user, *@users] + @users = [current_user, *@users].uniq end if params[:author_id].present? diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb deleted file mode 100644 index ff297d6ff13..00000000000 --- a/app/controllers/ci/projects_controller.rb +++ /dev/null @@ -1,47 +0,0 @@ -module Ci - class ProjectsController < ::ApplicationController - before_action :project - before_action :no_cache, only: [:badge] - before_action :authorize_read_project!, except: [:badge, :index] - skip_before_action :authenticate_user!, only: [:badge] - protect_from_forgery - - def index - redirect_to root_path - end - - def show - # Temporary compatibility with CI badges pointing to CI project page - redirect_to namespace_project_path(project.namespace, project) - end - - # Project status badge - # Image with build status for sha or ref - # - # This action in DEPRECATED, this is here only for backwards compatibility - # with projects migrated from GitLab CI. - # - def badge - return render_404 unless @project - - image = Ci::ImageForBuildService.new.execute(@project, params) - send_file image.path, filename: image.name, disposition: 'inline', type: "image/svg+xml" - end - - protected - - def project - @project ||= Project.find_by(ci_id: params[:id].to_i) - end - - def no_cache - response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate" - response.headers["Pragma"] = "no-cache" - response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT" - end - - def authorize_read_project! - return access_denied! unless can?(current_user, :read_project, project) - end - end -end diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index 4c497711fc0..ea441b1736b 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -23,7 +23,7 @@ module AuthenticatesWithTwoFactor # # Returns nil def prompt_for_two_factor(user) - return locked_user_redirect(user) if user.access_locked? + return locked_user_redirect(user) unless user.can?(:log_in) session[:otp_user_id] = user.id setup_u2f_authentication(user) @@ -37,10 +37,9 @@ module AuthenticatesWithTwoFactor def authenticate_with_two_factor user = self.resource = find_user + return locked_user_redirect(user) unless user.can?(:log_in) - if user.access_locked? - locked_user_redirect(user) - elsif user_params[:otp_attempt].present? && session[:otp_user_id] + if user_params[:otp_attempt].present? && session[:otp_user_id] authenticate_with_two_factor_via_otp(user) elsif user_params[:device_response].present? && session[:otp_user_id] authenticate_with_two_factor_via_u2f(user) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 88d180fcc2e..9ac8197e45a 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,10 +4,9 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables - start_branch = @mr_target_branch unless initial_commit? commit_params = @commit_params.merge( start_project: @mr_target_project, - start_branch: start_branch, + start_branch: @mr_target_branch, target_branch: @mr_source_branch ) @@ -17,12 +16,16 @@ module CreatesCommit if result[:status] == :success update_flash_notice(success_notice) + success_path = final_success_path(success_path) + respond_to do |format| - format.html { redirect_to final_success_path(success_path) } - format.json { render json: { message: "success", filePath: final_success_path(success_path) } } + format.html { redirect_to success_path } + format.json { render json: { message: "success", filePath: success_path } } end else flash[:alert] = result[:message] + failure_path = failure_path.call if failure_path.respond_to?(:call) + respond_to do |format| format.html do if failure_view @@ -58,9 +61,13 @@ module CreatesCommit end def final_success_path(success_path) - return success_path unless create_merge_request? + if create_merge_request? + merge_request_exists? ? existing_merge_request_path : new_merge_request_path + else + success_path = success_path.call if success_path.respond_to?(:call) - merge_request_exists? ? existing_merge_request_path : new_merge_request_path + success_path + end end def new_merge_request_path @@ -92,46 +99,26 @@ module CreatesCommit end def create_merge_request? - # XXX: Even if the field is set, if we're checking the same branch + # Even if the field is set, if we're checking the same branch # as the target branch in the same project, # we don't want to create a merge request. params[:create_merge_request].present? && - (different_project? || @ref != @target_branch) + (different_project? || @mr_target_branch != @mr_source_branch) end - # TODO: We should really clean this up def set_commit_variables if can?(current_user, :push_code, @project) - # Edit file in this project @mr_source_project = @project + @target_branch ||= @ref else - # Merge request from fork to this project @mr_source_project = current_user.fork_of(@project) + @target_branch ||= @mr_source_project.repository.next_branch('patch') end # Merge request to this project @mr_target_project = @project - @mr_target_branch = @ref || @target_branch - - @mr_source_branch = guess_mr_source_branch - end - - def initial_commit? - @mr_target_branch.nil? || - !@mr_target_project.repository.branch_exists?(@mr_target_branch) - end + @mr_target_branch ||= @ref || @target_branch - def guess_mr_source_branch - # XXX: Happens when viewing a commit without a branch. In this case, - # @target_branch would be the default branch for @mr_source_project, - # however we want a generated new branch here. Thus we can't use - # @target_branch, but should pass nil to indicate that we want a new - # branch instead of @target_branch. - return if - create_merge_request? && - # XXX: Don't understand why rubocop prefers this indention - @mr_source_project.repository.branch_exists?(@target_branch) - - @target_branch + @mr_source_branch = @target_branch end end diff --git a/app/controllers/concerns/filter_projects.rb b/app/controllers/concerns/filter_projects.rb index 586f97c5eb4..6014112256a 100644 --- a/app/controllers/concerns/filter_projects.rb +++ b/app/controllers/concerns/filter_projects.rb @@ -8,7 +8,7 @@ module FilterProjects extend ActiveSupport::Concern def filter_projects(projects) - projects = projects.search(params[:filter_projects]) if params[:filter_projects].present? + projects = projects.search(params[:name]) if params[:name].present? projects = projects.non_archived if params[:archived].blank? projects = projects.personal(current_user) if params[:personal].present? && current_user diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb index 0821974aa93..3ccf2a9ce33 100644 --- a/app/controllers/concerns/issuable_actions.rb +++ b/app/controllers/concerns/issuable_actions.rb @@ -26,6 +26,23 @@ module IssuableActions private + def render_conflict_response + respond_to do |format| + format.html do + @conflict = true + render :edit + end + + format.json do + render json: { + errors: [ + "Someone edited this #{issuable.human_class_name} at the same time you did. Please refresh your browser and make sure your changes will not unintentionally remove theirs." + ] + }, status: 409 + end + end + end + def labels @labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute end diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index a6e158ebae6..85ae4985e58 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -9,24 +9,32 @@ module IssuableCollections private - def issuable_meta_data(issuable_collection) + def issuable_meta_data(issuable_collection, collection_type) # map has to be used here since using pluck or select will # throw an error when ordering issuables by priority which inserts # a new order into the collection. # We cannot use reorder to not mess up the paginated collection. - issuable_ids = issuable_collection.map(&:id) - issuable_note_count = Note.count_for_collection(issuable_ids, @collection_type) + issuable_ids = issuable_collection.map(&:id) + issuable_note_count = Note.count_for_collection(issuable_ids, @collection_type) issuable_votes_count = AwardEmoji.votes_for_collection(issuable_ids, @collection_type) + issuable_merge_requests_count = + if collection_type == 'Issue' + MergeRequestsClosingIssues.count_for_collection(issuable_ids) + else + [] + end issuable_ids.each_with_object({}) do |id, issuable_meta| downvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.downvote? } - upvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.upvote? } - notes = issuable_note_count.find { |notes| notes.noteable_id == id } + upvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.upvote? } + notes = issuable_note_count.find { |notes| notes.noteable_id == id } + merge_requests = issuable_merge_requests_count.find { |mr| mr.first == id } issuable_meta[id] = Issuable::IssuableMeta.new( upvotes.try(:count).to_i, downvotes.try(:count).to_i, - notes.try(:count).to_i + notes.try(:count).to_i, + merge_requests.try(:last).to_i ) end end diff --git a/app/controllers/concerns/issues_action.rb b/app/controllers/concerns/issues_action.rb index fb5edb34370..b17c138d5c7 100644 --- a/app/controllers/concerns/issues_action.rb +++ b/app/controllers/concerns/issues_action.rb @@ -10,7 +10,7 @@ module IssuesAction .page(params[:page]) @collection_type = "Issue" - @issuable_meta_data = issuable_meta_data(@issues) + @issuable_meta_data = issuable_meta_data(@issues, @collection_type) respond_to do |format| format.html diff --git a/app/controllers/concerns/merge_requests_action.rb b/app/controllers/concerns/merge_requests_action.rb index 6229759dcf1..d3c8e4888bc 100644 --- a/app/controllers/concerns/merge_requests_action.rb +++ b/app/controllers/concerns/merge_requests_action.rb @@ -9,7 +9,7 @@ module MergeRequestsAction .page(params[:page]) @collection_type = "MergeRequest" - @issuable_meta_data = issuable_meta_data(@merge_requests) + @issuable_meta_data = issuable_meta_data(@merge_requests, @collection_type) end private diff --git a/app/controllers/concerns/repository_settings_redirect.rb b/app/controllers/concerns/repository_settings_redirect.rb new file mode 100644 index 00000000000..0854c73a02f --- /dev/null +++ b/app/controllers/concerns/repository_settings_redirect.rb @@ -0,0 +1,7 @@ +module RepositorySettingsRedirect + extend ActiveSupport::Concern + + def redirect_to_repository_settings(project) + redirect_to namespace_project_settings_repository_path(project.namespace, project) + end +end diff --git a/app/controllers/concerns/service_params.rb b/app/controllers/concerns/service_params.rb index d7f5a4e4682..a8c0937569c 100644 --- a/app/controllers/concerns/service_params.rb +++ b/app/controllers/concerns/service_params.rb @@ -33,10 +33,10 @@ module ServiceParams :issues_url, :jira_issue_transition_id, :merge_requests_events, + :mock_service_url, :namespace, :new_issue_url, :notify, - :notify_only_broken_builds, :notify_only_broken_pipelines, :password, :priority, @@ -59,10 +59,10 @@ module ServiceParams :user_key, :username, :webhook - ] + ].freeze # Parameters to ignore if no value is specified - FILTER_BLANK_PARAMS = [:password] + FILTER_BLANK_PARAMS = [:password].freeze def service_params dynamic_params = @service.event_channel_names + @service.event_names diff --git a/app/controllers/concerns/spammable_actions.rb b/app/controllers/concerns/spammable_actions.rb index da225d8f1c7..d0a692070d9 100644 --- a/app/controllers/concerns/spammable_actions.rb +++ b/app/controllers/concerns/spammable_actions.rb @@ -27,7 +27,7 @@ module SpammableActions render :verify else - fallback.call + yield end end diff --git a/app/controllers/dashboard/groups_controller.rb b/app/controllers/dashboard/groups_controller.rb index 0b7cf8167f0..d03265e9f20 100644 --- a/app/controllers/dashboard/groups_controller.rb +++ b/app/controllers/dashboard/groups_controller.rb @@ -1,5 +1,17 @@ class Dashboard::GroupsController < Dashboard::ApplicationController def index - @group_members = current_user.group_members.includes(source: :route).page(params[:page]) + @group_members = current_user.group_members.includes(source: :route).joins(:group) + @group_members = @group_members.merge(Group.search(params[:filter_groups])) if params[:filter_groups].present? + @group_members = @group_members.merge(Group.sort(@sort = params[:sort])) + @group_members = @group_members.page(params[:page]) + + respond_to do |format| + format.html + format.json do + render json: { + html: view_to_html_string("dashboard/groups/_groups", locals: { group_members: @group_members }) + } + end + end end end diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb index 7f506db583f..df528d10f6e 100644 --- a/app/controllers/dashboard/milestones_controller.rb +++ b/app/controllers/dashboard/milestones_controller.rb @@ -5,6 +5,7 @@ class Dashboard::MilestonesController < Dashboard::ApplicationController def index respond_to do |format| format.html do + @milestone_states = GlobalMilestone.states_count(@projects) @milestones = Kaminari.paginate_array(milestones).page(params[:page]) end format.json do diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb index 325ae565537..be00d765f73 100644 --- a/app/controllers/dashboard/projects_controller.rb +++ b/app/controllers/dashboard/projects_controller.rb @@ -42,7 +42,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController private def load_projects(base_scope) - projects = base_scope.sorted_by_activity.includes(:namespace) + projects = base_scope.sorted_by_activity.includes(:route, namespace: :route) filter_projects(projects) end diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb index 5848ca62777..096de8032ae 100644 --- a/app/controllers/dashboard/todos_controller.rb +++ b/app/controllers/dashboard/todos_controller.rb @@ -22,12 +22,12 @@ class Dashboard::TodosController < Dashboard::ApplicationController end def destroy_all - TodoService.new.mark_todos_as_done(@todos, current_user) + updated_ids = TodoService.new.mark_todos_as_done(@todos, current_user) respond_to do |format| format.html { redirect_to dashboard_todos_path, notice: 'All todos were marked as done.' } format.js { head :ok } - format.json { render json: todos_counts } + format.json { render json: todos_counts.merge(updated_ids: updated_ids) } end end @@ -37,6 +37,12 @@ class Dashboard::TodosController < Dashboard::ApplicationController render json: todos_counts end + def bulk_restore + TodoService.new.mark_todos_as_pending_by_ids(params[:ids], current_user) + + render json: todos_counts + end + # Used in TodosHelper also def self.todos_count_format(count) count >= 100 ? '99+' : count @@ -45,7 +51,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController private def find_todos - @todos ||= TodosFinder.new(current_user, params).execute + @todos ||= TodosFinder.new(current_user, params.merge(include_associations: true)).execute end def todos_counts diff --git a/app/controllers/emojis_controller.rb b/app/controllers/emojis_controller.rb deleted file mode 100644 index 1bec5a7d27f..00000000000 --- a/app/controllers/emojis_controller.rb +++ /dev/null @@ -1,6 +0,0 @@ -class EmojisController < ApplicationController - layout false - - def index - end -end diff --git a/app/controllers/explore/groups_controller.rb b/app/controllers/explore/groups_controller.rb index a962f9a0937..68228c095da 100644 --- a/app/controllers/explore/groups_controller.rb +++ b/app/controllers/explore/groups_controller.rb @@ -1,8 +1,17 @@ class Explore::GroupsController < Explore::ApplicationController def index @groups = GroupsFinder.new.execute(current_user) - @groups = @groups.search(params[:search]) if params[:search].present? + @groups = @groups.search(params[:filter_groups]) if params[:filter_groups].present? @groups = @groups.sort(@sort = params[:sort]) @groups = @groups.page(params[:page]) + + respond_to do |format| + format.html + format.json do + render json: { + html: view_to_html_string("explore/groups/_groups", locals: { groups: @groups }) + } + end + end end end diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb index 26e17a7553e..6167f9bd335 100644 --- a/app/controllers/explore/projects_controller.rb +++ b/app/controllers/explore/projects_controller.rb @@ -2,7 +2,7 @@ class Explore::ProjectsController < Explore::ApplicationController include FilterProjects def index - @projects = ProjectsFinder.new.execute(current_user) + @projects = load_projects @tags = @projects.tags_on(:tags) @projects = @projects.tagged_with(params[:tag]) if params[:tag].present? @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present? @@ -21,7 +21,8 @@ class Explore::ProjectsController < Explore::ApplicationController end def trending - @projects = filter_projects(Project.trending) + @projects = load_projects(Project.trending) + @projects = filter_projects(@projects) @projects = @projects.sort(@sort = params[:sort]) @projects = @projects.page(params[:page]) @@ -36,7 +37,7 @@ class Explore::ProjectsController < Explore::ApplicationController end def starred - @projects = ProjectsFinder.new.execute(current_user) + @projects = load_projects @projects = filter_projects(@projects) @projects = @projects.reorder('star_count DESC') @projects = @projects.page(params[:page]) @@ -50,4 +51,11 @@ class Explore::ProjectsController < Explore::ApplicationController end end end + + protected + + def load_projects(base_scope = nil) + base_scope ||= ProjectsFinder.new.execute(current_user) + base_scope.includes(:route, namespace: :route) + end end diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index 0d872c86c8a..43102596201 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -6,6 +6,7 @@ class Groups::MilestonesController < Groups::ApplicationController def index respond_to do |format| format.html do + @milestone_states = GlobalMilestone.states_count(@projects) @milestones = Kaminari.paginate_array(milestones).page(params[:page]) end end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 7ed54479599..05f9ee1ee90 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -32,7 +32,13 @@ class GroupsController < Groups::ApplicationController @group = Groups::CreateService.new(current_user, group_params).execute if @group.persisted? - redirect_to @group, notice: "Group '#{@group.name}' was successfully created." + notice = if @group.chat_team.present? + "Group '#{@group.name}' and its Mattermost team were successfully created." + else + "Group '#{@group.name}' was successfully created." + end + + redirect_to @group, notice: notice else render action: "new" end @@ -108,11 +114,11 @@ class GroupsController < Groups::ApplicationController @projects = @projects.sorted_by_activity @projects = filter_projects(@projects) @projects = @projects.sort(@sort = params[:sort]) - @projects = @projects.page(params[:page]) if params[:filter_projects].blank? + @projects = @projects.page(params[:page]) if params[:name].blank? end def authorize_create_group! - unless can?(current_user, :create_group, nil) + unless can?(current_user, :create_group) return render_404 end end @@ -142,7 +148,9 @@ class GroupsController < Groups::ApplicationController :request_access_enabled, :share_with_group_lock, :visibility_level, - :parent_id + :parent_id, + :create_chat_team, + :chat_team_name ] end diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb index c2e4d62b50b..3109439b2ff 100644 --- a/app/controllers/jwt_controller.rb +++ b/app/controllers/jwt_controller.rb @@ -5,7 +5,7 @@ class JwtController < ApplicationController SERVICES = { Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService, - } + }.freeze def auth service = SERVICES[params[:service]] @@ -39,7 +39,8 @@ class JwtController < ApplicationController message: "HTTP Basic: Access denied\n" \ "You have 2FA enabled, please use a personal access token for Git over HTTP.\n" \ "You can generate one at #{profile_personal_access_tokens_url}" } - ] }, status: 401 + ] + }, status: 401 end def render_unauthorized @@ -47,7 +48,8 @@ class JwtController < ApplicationController errors: [ { code: 'UNAUTHORIZED', message: 'HTTP Basic: Access denied' } - ] }, status: 401 + ] + }, status: 401 end def auth_params diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb index c721dca58d9..05190103767 100644 --- a/app/controllers/oauth/authorizations_controller.rb +++ b/app/controllers/oauth/authorizations_controller.rb @@ -1,8 +1,8 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController - before_action :authenticate_resource_owner! - layout 'profile' + # Overriden from Doorkeeper::AuthorizationsController to + # include the call to session.delete def new if pre_auth.authorizable? if skip_authorization? || matching_token? @@ -16,44 +16,4 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController render "doorkeeper/authorizations/error" end end - - # TODO: Handle raise invalid authorization - def create - redirect_or_render authorization.authorize - end - - def destroy - redirect_or_render authorization.deny - end - - private - - def matching_token? - Doorkeeper::AccessToken.matching_token_for(pre_auth.client, - current_resource_owner.id, - pre_auth.scopes) - end - - def redirect_or_render(auth) - if auth.redirectable? - redirect_to auth.redirect_uri - else - render json: auth.body, status: auth.status - end - end - - def pre_auth - @pre_auth ||= - Doorkeeper::OAuth::PreAuthorization.new(Doorkeeper.configuration, - server.client_via_uid, - params) - end - - def authorization - @authorization ||= strategy.request - end - - def strategy - @strategy ||= server.authorization_request(pre_auth.response_type) - end end diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb index c8663a3c38e..e4452f46056 100644 --- a/app/controllers/profiles/keys_controller.rb +++ b/app/controllers/profiles/keys_controller.rb @@ -10,11 +10,6 @@ class Profiles::KeysController < Profiles::ApplicationController @key = current_user.keys.find(params[:id]) end - # Back-compat: We need to support this URL since git-annex webapp points to it - def new - redirect_to profile_keys_path - end - def create @key = current_user.keys.new(key_params) diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb index a271e2dfc4b..b8b71d295f6 100644 --- a/app/controllers/profiles/notifications_controller.rb +++ b/app/controllers/profiles/notifications_controller.rb @@ -17,6 +17,6 @@ class Profiles::NotificationsController < Profiles::ApplicationController end def user_params - params.require(:user).permit(:notification_email, :notified_of_own_activity) + params.require(:user).permit(:notification_email) end end diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb index 6e007f17913..0abe7ea3c9b 100644 --- a/app/controllers/profiles/personal_access_tokens_controller.rb +++ b/app/controllers/profiles/personal_access_tokens_controller.rb @@ -4,7 +4,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController end def create - @personal_access_token = current_user.personal_access_tokens.generate(personal_access_token_params) + @personal_access_token = finder.build(personal_access_token_params) if @personal_access_token.save flash[:personal_access_token] = @personal_access_token.token @@ -16,7 +16,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController end def revoke - @personal_access_token = current_user.personal_access_tokens.find(params[:id]) + @personal_access_token = finder.find(params[:id]) if @personal_access_token.revoke! flash[:notice] = "Revoked personal access token #{@personal_access_token.name}!" @@ -29,14 +29,19 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController private + def finder(options = {}) + PersonalAccessTokensFinder.new({ user: current_user, impersonation: false }.merge(options)) + end + def personal_access_token_params params.require(:personal_access_token).permit(:name, :expires_at, scopes: []) end def set_index_vars - @personal_access_token ||= current_user.personal_access_tokens.build - @scopes = Gitlab::Auth::SCOPES - @active_personal_access_tokens = current_user.personal_access_tokens.active.order(:expires_at) - @inactive_personal_access_tokens = current_user.personal_access_tokens.inactive + @scopes = Gitlab::Auth::API_SCOPES + + @personal_access_token = finder.build + @inactive_personal_access_tokens = finder(state: 'inactive').execute + @active_personal_access_tokens = finder(state: 'active').execute.order(:expires_at) end end diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb index 18044ca78e2..26e7e93533e 100644 --- a/app/controllers/profiles/two_factor_auths_controller.rb +++ b/app/controllers/profiles/two_factor_auths_controller.rb @@ -80,7 +80,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController def build_qr_code uri = current_user.otp_provisioning_uri(account_string, issuer: issuer_host) - RQRCode::render_qrcode(uri, :svg, level: :m, unit: 3) + RQRCode.render_qrcode(uri, :svg, level: :m, unit: 3) end def account_string diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index f0c71725ea8..987b95e89b9 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -47,11 +47,14 @@ class ProfilesController < Profiles::ApplicationController end def update_username - @user.update_attributes(username: user_params[:username]) - - respond_to do |format| - format.js + if @user.update_attributes(username: user_params[:username]) + options = { notice: "Username successfully changed" } + else + message = @user.errors.full_messages.uniq.join('. ') + options = { alert: "Username change failed - #{message}" } end + + redirect_back_or_default(default: { action: 'show' }, options: options) end private diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb index d9dfa534669..ffb54390965 100644 --- a/app/controllers/projects/autocomplete_sources_controller.rb +++ b/app/controllers/projects/autocomplete_sources_controller.rb @@ -1,9 +1,5 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController - before_action :load_autocomplete_service, except: [:emojis, :members] - - def emojis - render json: Gitlab::AwardEmoji.urls - end + before_action :load_autocomplete_service, except: [:members] def members render json: ::Projects::ParticipantsService.new(@project, current_user).execute(noteable) diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb index 863a766a255..6461eeac11c 100644 --- a/app/controllers/projects/blame_controller.rb +++ b/app/controllers/projects/blame_controller.rb @@ -8,9 +8,12 @@ class Projects::BlameController < Projects::ApplicationController def show @blob = @repository.blob_at(@commit.id, @path) - + return render_404 unless @blob + environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit } + @environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last + @blame_groups = Gitlab::Blame.new(@blob, @commit).groups end end diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 39ba815cfca..52fc67d162c 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -5,7 +5,7 @@ class Projects::BlobController < Projects::ApplicationController include ActionView::Helpers::SanitizeHelper # Raised when given an invalid file path - class InvalidPathError < StandardError; end + InvalidPathError = Class.new(StandardError) before_action :require_non_empty_project, except: [:new, :create] before_action :authorize_download_code! @@ -23,8 +23,10 @@ class Projects::BlobController < Projects::ApplicationController end def create + update_ref + create_commit(Files::CreateService, success_notice: "The file has been successfully created.", - success_path: namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)), + success_path: -> { namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) }, failure_view: :new, failure_path: namespace_project_new_blob_path(@project.namespace, @project, @ref)) end @@ -40,7 +42,7 @@ class Projects::BlobController < Projects::ApplicationController def update @path = params[:file_path] if params[:file_path].present? - create_commit(Files::UpdateService, success_path: after_edit_path, + create_commit(Files::UpdateService, success_path: -> { after_edit_path }, failure_view: :edit, failure_path: namespace_project_blob_path(@project.namespace, @project, @id)) @@ -62,7 +64,7 @@ class Projects::BlobController < Projects::ApplicationController def destroy create_commit(Files::DestroyService, success_notice: "The file has been successfully deleted.", - success_path: namespace_project_tree_path(@project.namespace, @project, @target_branch), + success_path: -> { namespace_project_tree_path(@project.namespace, @project, @target_branch) }, failure_view: :show, failure_path: namespace_project_blob_path(@project.namespace, @project, @id)) end @@ -87,6 +89,11 @@ class Projects::BlobController < Projects::ApplicationController private + def update_ref + branch_exists = @repository.find_branch(@target_branch) + @ref = @target_branch if branch_exists + end + def blob @blob ||= Blob.decorate(@repository.blob_at(@commit.id, @path)) diff --git a/app/controllers/projects/boards/issues_controller.rb b/app/controllers/projects/boards/issues_controller.rb index 61fef4dc133..28c9646910d 100644 --- a/app/controllers/projects/boards/issues_controller.rb +++ b/app/controllers/projects/boards/issues_controller.rb @@ -8,6 +8,7 @@ module Projects def index issues = ::Boards::Issues::ListService.new(project, current_user, filter_params).execute issues = issues.page(params[:page]).per(params[:per] || 20) + make_sure_position_is_set(issues) render json: { issues: serialize_as_json(issues), @@ -38,6 +39,12 @@ module Projects private + def make_sure_position_is_set(issues) + issues.each do |issue| + issue.move_to_end && issue.save unless issue.relative_position + end + end + def issue @issue ||= IssuesFinder.new(current_user, project_id: project.id) @@ -63,7 +70,7 @@ module Projects end def move_params - params.permit(:board_id, :id, :from_list_id, :to_list_id) + params.permit(:board_id, :id, :from_list_id, :to_list_id, :move_before_iid, :move_after_iid) end def issue_params @@ -73,7 +80,7 @@ module Projects def serialize_as_json(resource) resource.as_json( labels: true, - only: [:id, :iid, :title, :confidential, :due_date], + only: [:id, :iid, :title, :confidential, :due_date, :relative_position], include: { assignee: { only: [:id, :name, :username], methods: [:avatar_url] }, milestone: { only: [:id, :title] } diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index 89d84809e3a..840405f38cb 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -1,25 +1,29 @@ class Projects::BranchesController < Projects::ApplicationController include ActionView::Helpers::SanitizeHelper include SortingHelper + # Authorize - before_action :require_non_empty_project + before_action :require_non_empty_project, except: :create before_action :authorize_download_code! before_action :authorize_push_code!, only: [:new, :create, :destroy, :destroy_all_merged] def index @sort = params[:sort].presence || sort_value_name @branches = BranchesFinder.new(@repository, params).execute - @branches = Kaminari.paginate_array(@branches).page(params[:page]) - - @max_commits = @branches.reduce(0) do |memo, branch| - diverging_commit_counts = repository.diverging_commit_counts(branch) - [memo, diverging_commit_counts[:behind], diverging_commit_counts[:ahead]].max - end respond_to do |format| - format.html + format.html do + paginate_branches + @refs_pipelines = @project.pipelines.latest_successful_for_refs(@branches.map(&:name)) + + @max_commits = @branches.reduce(0) do |memo, branch| + diverging_commit_counts = repository.diverging_commit_counts(branch) + [memo, diverging_commit_counts[:behind], diverging_commit_counts[:ahead]].max + end + end format.json do - render json: @repository.branch_names + paginate_branches unless params[:show_all] + render json: @branches.map(&:name) end end end @@ -32,6 +36,8 @@ class Projects::BranchesController < Projects::ApplicationController branch_name = sanitize(strip_tags(params[:branch_name])) branch_name = Addressable::URI.unescape(branch_name) + redirect_to_autodeploy = project.empty_repo? && project.deployment_services.present? + result = CreateBranchService.new(project, current_user). execute(branch_name, ref) @@ -42,8 +48,15 @@ class Projects::BranchesController < Projects::ApplicationController if result[:status] == :success @branch = result[:branch] - redirect_to namespace_project_tree_path(@project.namespace, @project, - @branch.name) + + if redirect_to_autodeploy + redirect_to( + url_to_autodeploy_setup(project, branch_name), + notice: view_context.autodeploy_flash_notice(branch_name)) + else + redirect_to namespace_project_tree_path(@project.namespace, @project, + @branch.name) + end else @error = result[:message] render action: 'new' @@ -76,7 +89,23 @@ class Projects::BranchesController < Projects::ApplicationController ref_escaped = sanitize(strip_tags(params[:ref])) Addressable::URI.unescape(ref_escaped) else - @project.default_branch + @project.default_branch || 'master' end end + + def paginate_branches + @branches = Kaminari.paginate_array(@branches).page(params[:page]) + end + + def url_to_autodeploy_setup(project, branch_name) + namespace_project_new_blob_path( + project.namespace, + project, + branch_name, + file_name: '.gitlab-ci.yml', + commit_message: 'Set up auto deploy', + target_branch: branch_name, + context: 'autodeploy' + ) + end end diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index e10d7992db7..cc67f688d51 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -51,23 +51,35 @@ class Projects::CommitController < Projects::ApplicationController def revert assign_change_commit_vars - return render_404 if @target_branch.blank? + return render_404 if @start_branch.blank? + + @target_branch = create_new_branch? ? @commit.revert_branch_name : @start_branch + + @mr_target_branch = @start_branch create_commit(Commits::RevertService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully reverted.", - success_path: successful_change_path, failure_path: failed_change_path) + success_path: -> { successful_change_path }, failure_path: failed_change_path) end def cherry_pick assign_change_commit_vars - return render_404 if @target_branch.blank? + return render_404 if @start_branch.blank? + + @target_branch = create_new_branch? ? @commit.cherry_pick_branch_name : @start_branch + + @mr_target_branch = @start_branch create_commit(Commits::CherryPickService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully cherry-picked.", - success_path: successful_change_path, failure_path: failed_change_path) + success_path: -> { successful_change_path }, failure_path: failed_change_path) end private + def create_new_branch? + params[:create_merge_request].present? || !can?(current_user, :push_code, @project) + end + def successful_change_path referenced_merge_request_url || namespace_project_commits_url(@project.namespace, @project, @target_branch) end @@ -78,7 +90,7 @@ class Projects::CommitController < Projects::ApplicationController def referenced_merge_request_url if merge_request = @commit.merged_merge_request(current_user) - namespace_project_merge_request_url(@project.namespace, @project, merge_request) + namespace_project_merge_request_url(merge_request.target_project.namespace, merge_request.target_project, merge_request) end end @@ -94,7 +106,7 @@ class Projects::CommitController < Projects::ApplicationController @diffs = commit.diffs(opts) @notes_count = commit.notes.count - + @environment = EnvironmentsFinder.new(@project, current_user, commit: @commit).execute.last end @@ -118,11 +130,7 @@ class Projects::CommitController < Projects::ApplicationController end def assign_change_commit_vars - @commit = project.commit(params[:id]) - @target_branch = params[:target_branch] - @commit_params = { - commit: @commit, - create_merge_request: params[:create_merge_request].present? || different_project? - } + @start_branch = params[:start_branch] + @commit_params = { commit: @commit } end end diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb index b094491e006..1502b734f37 100644 --- a/app/controllers/projects/deploy_keys_controller.rb +++ b/app/controllers/projects/deploy_keys_controller.rb @@ -1,4 +1,5 @@ class Projects::DeployKeysController < Projects::ApplicationController + include RepositorySettingsRedirect respond_to :html # Authorize @@ -7,51 +8,36 @@ class Projects::DeployKeysController < Projects::ApplicationController layout "project_settings" def index - @key = DeployKey.new - set_index_vars + redirect_to_repository_settings(@project) end def new - redirect_to namespace_project_deploy_keys_path(@project.namespace, @project) + redirect_to_repository_settings(@project) end def create @key = DeployKey.new(deploy_key_params.merge(user: current_user)) - set_index_vars - if @key.valid? && @project.deploy_keys << @key - redirect_to namespace_project_deploy_keys_path(@project.namespace, @project) - else - render "index" + unless @key.valid? && @project.deploy_keys << @key + flash[:alert] = @key.errors.full_messages.join(', ').html_safe end + redirect_to_repository_settings(@project) end def enable Projects::EnableDeployKeyService.new(@project, current_user, params).execute - redirect_to namespace_project_deploy_keys_path(@project.namespace, @project) + redirect_to_repository_settings(@project) end def disable @project.deploy_keys_projects.find_by(deploy_key_id: params[:id]).destroy - redirect_back_or_default(default: { action: 'index' }) + redirect_to_repository_settings(@project) end protected - def set_index_vars - @enabled_keys ||= @project.deploy_keys - - @available_keys ||= current_user.accessible_deploy_keys - @enabled_keys - @available_project_keys ||= current_user.project_deploy_keys - @enabled_keys - @available_public_keys ||= DeployKey.are_public - @enabled_keys - - # Public keys that are already used by another accessible project are already - # in @available_project_keys. - @available_public_keys -= @available_project_keys - end - def deploy_key_params params.require(:deploy_key).permit(:key, :title, :can_push) end diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index fed75396d6e..fa37963dfd4 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -5,7 +5,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController before_action :authorize_create_deployment!, only: [:stop] before_action :authorize_update_environment!, only: [:edit, :update] before_action :authorize_admin_environment!, only: [:terminal, :terminal_websocket_authorize] - before_action :environment, only: [:show, :edit, :update, :stop, :terminal, :terminal_websocket_authorize] + before_action :environment, only: [:show, :edit, :update, :stop, :terminal, :terminal_websocket_authorize, :metrics] before_action :verify_api_request!, only: :terminal_websocket_authorize def index @@ -109,6 +109,19 @@ class Projects::EnvironmentsController < Projects::ApplicationController end end + def metrics + # Currently, this acts as a hint to load the metrics details into the cache + # if they aren't there already + @metrics = environment.metrics || {} + + respond_to do |format| + format.html + format.json do + render json: @metrics, status: @metrics.any? ? :ok : :no_content + end + end + end + private def verify_api_request! diff --git a/app/controllers/projects/git_http_client_controller.rb b/app/controllers/projects/git_http_client_controller.rb index 216c158e41e..9a1bf037a95 100644 --- a/app/controllers/projects/git_http_client_controller.rb +++ b/app/controllers/projects/git_http_client_controller.rb @@ -76,11 +76,12 @@ class Projects::GitHttpClientController < Projects::ApplicationController return @project if defined?(@project) project_id, _ = project_id_with_suffix - if project_id.blank? - @project = nil - else - @project = Project.find_by_full_path("#{params[:namespace_id]}/#{project_id}") - end + @project = + if project_id.blank? + nil + else + Project.find_by_full_path("#{params[:namespace_id]}/#{project_id}") + end end # This method returns two values so that we can parse diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb index 923e7340e69..43fc0c39801 100644 --- a/app/controllers/projects/graphs_controller.rb +++ b/app/controllers/projects/graphs_controller.rb @@ -17,6 +17,25 @@ class Projects::GraphsController < Projects::ApplicationController end def commits + redirect_to action: 'charts' + end + + def languages + redirect_to action: 'charts' + end + + def charts + get_commits + get_languages + end + + def ci + redirect_to charts_namespace_project_pipelines_path(@project.namespace, @project) + end + + private + + def get_commits @commits = @project.repository.commits(@ref, limit: 2000, skip_merges: true) @commits_graph = Gitlab::Graphs::Commits.new(@commits) @commits_per_week_days = @commits_graph.commits_per_week_days @@ -24,15 +43,7 @@ class Projects::GraphsController < Projects::ApplicationController @commits_per_month = @commits_graph.commits_per_month end - def ci - @charts = {} - @charts[:week] = Ci::Charts::WeekChart.new(project) - @charts[:month] = Ci::Charts::MonthChart.new(project) - @charts[:year] = Ci::Charts::YearChart.new(project) - @charts[:build_times] = Ci::Charts::BuildTime.new(project) - end - - def languages + def get_languages @languages = Linguist::Repository.new(@repository.rugged, @repository.rugged.head.target_id).languages total = @languages.map(&:last).sum @@ -52,8 +63,6 @@ class Projects::GraphsController < Projects::ApplicationController end end - private - def fetch_graph @commits = @project.repository.commits(@ref, limit: 6000, skip_merges: true) @log = [] diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 6ef36771ac1..cdb5b4173d3 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -6,6 +6,8 @@ class Projects::IssuesController < Projects::ApplicationController include IssuableCollections include SpammableActions + prepend_before_action :authenticate_user!, only: [:new] + before_action :redirect_to_external_issue_tracker, only: [:index, :new] before_action :module_enabled before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests, @@ -26,7 +28,7 @@ class Projects::IssuesController < Projects::ApplicationController @collection_type = "Issue" @issues = issues_collection @issues = @issues.page(params[:page]) - @issuable_meta_data = issuable_meta_data(@issues) + @issuable_meta_data = issuable_meta_data(@issues, @collection_type) if @issues.out_of_range? && @issues.total_pages != 0 return redirect_to url_for(params.merge(page: @issues.total_pages)) @@ -64,8 +66,15 @@ class Projects::IssuesController < Projects::ApplicationController params[:issue] ||= ActionController::Parameters.new( assignee_id: "" ) - build_params = issue_params.merge(merge_request_for_resolving_discussions: merge_request_for_resolving_discussions) - @issue = @noteable = Issues::BuildService.new(project, current_user, build_params).execute + build_params = issue_params.merge( + merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of], + discussion_to_resolve: params[:discussion_to_resolve] + ) + service = Issues::BuildService.new(project, current_user, build_params) + + @issue = @noteable = service.execute + @merge_request_to_resolve_discussions_of = service.merge_request_to_resolve_discussions_of + @discussion_to_resolve = service.discussions_to_resolve.first if params[:discussion_to_resolve] respond_with(@issue) end @@ -94,11 +103,21 @@ class Projects::IssuesController < Projects::ApplicationController end def create - create_params = issue_params - .merge(merge_request_for_resolving_discussions: merge_request_for_resolving_discussions) - .merge(spammable_params) + create_params = issue_params.merge(spammable_params).merge( + merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of], + discussion_to_resolve: params[:discussion_to_resolve] + ) - @issue = Issues::CreateService.new(project, current_user, create_params).execute + service = Issues::CreateService.new(project, current_user, create_params) + @issue = service.execute + + if service.discussions_to_resolve.count(&:resolved?) > 0 + flash[:notice] = if service.discussion_to_resolve_id + "Resolved 1 discussion." + else + "Resolved all discussions." + end + end respond_to do |format| format.html do @@ -129,13 +148,12 @@ class Projects::IssuesController < Projects::ApplicationController end format.json do - render json: @issue.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } }, methods: [:task_status, :task_status_short]) + render json: @issue.to_json(include: { milestone: {}, assignee: { only: [:name, :username], methods: [:avatar_url] }, labels: { methods: :text_color } }, methods: [:task_status, :task_status_short]) end end rescue ActiveRecord::StaleObjectError - @conflict = true - render :edit + render_conflict_response end def referenced_merge_requests @@ -186,14 +204,6 @@ class Projects::IssuesController < Projects::ApplicationController alias_method :awardable, :issue alias_method :spammable, :issue - def merge_request_for_resolving_discussions - return unless merge_request_iid = params[:merge_request_for_resolving_discussions] - - @merge_request_for_resolving_discussions ||= MergeRequestsFinder.new(current_user, project_id: project.id). - execute. - find_by(iid: merge_request_iid) - end - def authorize_read_issue! return render_404 unless can?(current_user, :read_issue, @issue) end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 75971faa93e..677a8a1a73a 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -10,11 +10,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController before_action :module_enabled before_action :merge_request, only: [ :edit, :update, :show, :diffs, :commits, :conflicts, :conflict_for_path, :pipelines, :merge, :merge_check, - :ci_status, :ci_environments_status, :toggle_subscription, :cancel_merge_when_build_succeeds, :remove_wip, :resolve_conflicts, :assign_related_issues + :ci_status, :ci_environments_status, :toggle_subscription, :cancel_merge_when_pipeline_succeeds, :remove_wip, :resolve_conflicts, :assign_related_issues ] before_action :validates_merge_request, only: [:show, :diffs, :commits, :pipelines] before_action :define_show_vars, only: [:show, :diffs, :commits, :conflicts, :conflict_for_path, :builds, :pipelines] - before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds, :merge_check] + before_action :define_widget_vars, only: [:merge, :cancel_merge_when_pipeline_succeeds, :merge_check] before_action :define_commit_vars, only: [:diffs] before_action :define_diff_comment_vars, only: [:diffs] before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds, :conflicts, :conflict_for_path, :pipelines] @@ -39,7 +39,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @collection_type = "MergeRequest" @merge_requests = merge_requests_collection @merge_requests = @merge_requests.page(params[:page]) - @issuable_meta_data = issuable_meta_data(@merge_requests) + @issuable_meta_data = issuable_meta_data(@merge_requests, @collection_type) if @merge_requests.out_of_range? && @merge_requests.total_pages != 0 return redirect_to url_for(params.merge(page: @merge_requests.total_pages)) @@ -245,9 +245,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController format.json do define_pipelines_vars - render json: PipelineSerializer + render json: { + pipelines: PipelineSerializer .new(project: @project, user: @current_user) .represent(@pipelines) + } end end end @@ -296,22 +298,21 @@ class Projects::MergeRequestsController < Projects::ApplicationController def update @merge_request = MergeRequests::UpdateService.new(project, current_user, merge_request_params).execute(@merge_request) - if @merge_request.valid? - respond_to do |format| - format.html do - redirect_to([@merge_request.target_project.namespace.becomes(Namespace), - @merge_request.target_project, @merge_request]) - end - format.json do - render json: @merge_request.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } }, methods: [:task_status, :task_status_short]) + respond_to do |format| + format.html do + if @merge_request.valid? + redirect_to([@merge_request.target_project.namespace.becomes(Namespace), @merge_request.target_project, @merge_request]) + else + render :edit end end - else - render "edit" + + format.json do + render json: @merge_request.to_json(include: { milestone: {}, assignee: { only: [:name, :username], methods: [:avatar_url] }, labels: { methods: :text_color } }, methods: [:task_status, :task_status_short]) + end end rescue ActiveRecord::StaleObjectError - @conflict = true - render :edit + render_conflict_response end def remove_wip @@ -323,12 +324,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController def merge_check @merge_request.check_if_can_be_merged + @pipelines = @merge_request.all_pipelines render partial: "projects/merge_requests/widget/show.html.haml", layout: false end - def cancel_merge_when_build_succeeds - unless @merge_request.can_cancel_merge_when_build_succeeds?(current_user) + def cancel_merge_when_pipeline_succeeds + unless @merge_request.can_cancel_merge_when_pipeline_succeeds?(current_user) return access_denied! end @@ -340,9 +342,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController def merge return access_denied! unless @merge_request.can_be_merged_by?(current_user) - # Disable the CI check if merge_when_build_succeeds is enabled since we have + # Disable the CI check if merge_when_pipeline_succeeds is enabled since we have # to wait until CI completes to know - unless @merge_request.mergeable?(skip_ci_check: merge_when_build_succeeds_active?) + unless @merge_request.mergeable?(skip_ci_check: merge_when_pipeline_succeeds_active?) @status = :failed return end @@ -354,7 +356,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.update(merge_error: nil) - if params[:merge_when_build_succeeds].present? + if params[:merge_when_pipeline_succeeds].present? unless @merge_request.head_pipeline @status = :failed return @@ -365,7 +367,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController .new(@project, current_user, merge_params) .execute(@merge_request) - @status = :merge_when_build_succeeds + @status = :merge_when_pipeline_succeeds elsif @merge_request.head_pipeline.success? # This can be triggered when a user clicks the auto merge button while # the tests finish at about the same time @@ -381,14 +383,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController end def merge_widget_refresh - if merge_request.merge_when_build_succeeds - @status = :merge_when_build_succeeds - else - # Only MRs that can be merged end in this action - # MR can be already picked up for merge / merged already or can be waiting for worker to be picked up - # in last case it does not have any special status. Possible error is handled inside widget js function - @status = :success - end + @status = + if merge_request.merge_when_pipeline_succeeds + :merge_when_pipeline_succeeds + else + # Only MRs that can be merged end in this action + # MR can be already picked up for merge / merged already or can be waiting for worker to be picked up + # in last case it does not have any special status. Possible error is handled inside widget js function + :success + end render 'merge' end @@ -444,6 +447,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController def ci_status pipeline = @merge_request.head_pipeline + @pipelines = @merge_request.all_pipelines if pipeline status = pipeline.status @@ -462,7 +466,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController sha: (merge_request.diff_head_commit.short_id if merge_request.diff_head_sha), status: status, coverage: coverage, - pipeline: pipeline.try(:id) + pipeline: pipeline.try(:id), + has_ci: @merge_request.has_ci? } render json: response @@ -672,8 +677,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.ensure_ref_fetched end - def merge_when_build_succeeds_active? - params[:merge_when_build_succeeds].present? && + def merge_when_pipeline_succeeds_active? + params[:merge_when_pipeline_succeeds].present? && @merge_request.head_pipeline && @merge_request.head_pipeline.active? end diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb index b033f7b5ea9..d00177e7612 100644 --- a/app/controllers/projects/notes_controller.rb +++ b/app/controllers/projects/notes_controller.rb @@ -148,17 +148,10 @@ class Projects::NotesController < Projects::ApplicationController def note_json(note) attrs = { - award: false, id: note.id } - if note.is_a?(AwardEmoji) - attrs.merge!( - valid: note.valid?, - award: true, - name: note.name - ) - elsif note.persisted? + if note.persisted? Banzai::NoteRenderer.render([note], @project, current_user) attrs.merge!( @@ -198,7 +191,7 @@ class Projects::NotesController < Projects::ApplicationController ) end - attrs[:commands_changes] = note.commands_changes unless attrs[:award] + attrs[:commands_changes] = note.commands_changes attrs end @@ -218,6 +211,11 @@ class Projects::NotesController < Projects::ApplicationController end def find_current_user_notes - @notes = NotesFinder.new(project, current_user, params).execute.inc_author + @notes = NotesFinder.new(project, current_user, params.merge(last_fetched_at: last_fetched_at)) + .execute.inc_author + end + + def last_fetched_at + request.headers['X-Last-Fetched-At'] end end diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index 84451257b98..718d9e86bea 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -1,9 +1,10 @@ class Projects::PipelinesController < Projects::ApplicationController - before_action :pipeline, except: [:index, :new, :create] + before_action :pipeline, except: [:index, :new, :create, :charts] before_action :commit, only: [:show, :builds] before_action :authorize_read_pipeline! before_action :authorize_create_pipeline!, only: [:new, :create] before_action :authorize_update_pipeline!, only: [:retry, :cancel] + before_action :builds_enabled, only: :charts def index @scope = params[:scope] @@ -13,9 +14,15 @@ class Projects::PipelinesController < Projects::ApplicationController .page(params[:page]) .per(30) - @running_or_pending_count = PipelinesFinder + @running_count = PipelinesFinder .new(project).execute(scope: 'running').count + @pending_count = PipelinesFinder + .new(project).execute(scope: 'pending').count + + @finished_count = PipelinesFinder + .new(project).execute(scope: 'finished').count + @pipelines_count = PipelinesFinder .new(project).execute.count @@ -29,7 +36,9 @@ class Projects::PipelinesController < Projects::ApplicationController .represent(@pipelines), count: { all: @pipelines_count, - running_or_pending: @running_or_pending_count + running: @running_count, + pending: @pending_count, + finished: @finished_count, } } end @@ -84,6 +93,14 @@ class Projects::PipelinesController < Projects::ApplicationController redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project) end + def charts + @charts = {} + @charts[:week] = Ci::Charts::WeekChart.new(project) + @charts[:month] = Ci::Charts::MonthChart.new(project) + @charts[:year] = Ci::Charts::YearChart.new(project) + @charts[:build_times] = Ci::Charts::BuildTime.new(project) + end + private def create_params diff --git a/app/controllers/projects/protected_branches_controller.rb b/app/controllers/projects/protected_branches_controller.rb index 2f422d352ed..a8cb07eb67a 100644 --- a/app/controllers/projects/protected_branches_controller.rb +++ b/app/controllers/projects/protected_branches_controller.rb @@ -1,26 +1,22 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController + include RepositorySettingsRedirect # Authorize before_action :require_non_empty_project before_action :authorize_admin_project! before_action :load_protected_branch, only: [:show, :update, :destroy] - before_action :load_protected_branches, only: [:index] layout "project_settings" def index - @protected_branch = @project.protected_branches.new - load_gon_index + redirect_to_repository_settings(@project) end def create @protected_branch = ::ProtectedBranches::CreateService.new(@project, current_user, protected_branch_params).execute - if @protected_branch.persisted? - redirect_to namespace_project_protected_branches_path(@project.namespace, @project) - else - load_protected_branches - load_gon_index - render :index + unless @protected_branch.persisted? + flash[:alert] = @protected_branches.errors.full_messages.join(', ').html_safe end + redirect_to_repository_settings(@project) end def show @@ -45,7 +41,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController @protected_branch.destroy respond_to do |format| - format.html { redirect_to namespace_project_protected_branches_path } + format.html { redirect_to_repository_settings(@project) } format.js { head :ok } end end @@ -61,24 +57,4 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController merge_access_levels_attributes: [:access_level, :id], push_access_levels_attributes: [:access_level, :id]) end - - def load_protected_branches - @protected_branches = @project.protected_branches.order(:name).page(params[:page]) - end - - def access_levels_options - { - push_access_levels: { - "Roles" => ProtectedBranch::PushAccessLevel.human_access_levels.map { |id, text| { id: id, text: text, before_divider: true } }, - }, - merge_access_levels: { - "Roles" => ProtectedBranch::MergeAccessLevel.human_access_levels.map { |id, text| { id: id, text: text, before_divider: true } } - } - } - end - - def load_gon_index - params = { open_branches: @project.open_branches.map { |br| { text: br.name, id: br.name, title: br.name } } } - gon.push(params.merge(access_levels_options)) - end end diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index 10d24da16d7..c55b37ae0dd 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -15,7 +15,7 @@ class Projects::RawController < Projects::ApplicationController return if cached_blob? - if @blob.lfs_pointer? + if @blob.lfs_pointer? && project.lfs_enabled? send_lfs_object else send_git_blob @repository, @blob diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index 17cb1d5be24..f9d798d0455 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -13,7 +13,8 @@ class Projects::ServicesController < Projects::ApplicationController end def update - if @service.update_attributes(service_params[:service]) + @service.assign_attributes(service_params[:service]) + if @service.save(context: :manual_change) redirect_to( edit_namespace_project_service_path(@project.namespace, @project, @service.to_param), notice: 'Successfully updated.' diff --git a/app/controllers/projects/settings/members_controller.rb b/app/controllers/projects/settings/members_controller.rb index 5735e281f66..cbfa2afa959 100644 --- a/app/controllers/projects/settings/members_controller.rb +++ b/app/controllers/projects/settings/members_controller.rb @@ -7,47 +7,18 @@ module Projects @sort = params[:sort].presence || sort_value_name @group_links = @project.project_group_links - @project_members = @project.project_members - @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) - - group = @project.group - - # group links - @group_links = @project.project_group_links.all - @skip_groups = @group_links.pluck(:group_id) @skip_groups << @project.namespace_id unless @project.personal? - if group - # We need `.where.not(user_id: nil)` here otherwise when a group has an - # invitee, it would make the following query return 0 rows since a NULL - # user_id would be present in the subquery - # See http://stackoverflow.com/questions/129077/not-in-clause-and-null-values - group_members = MembersFinder.new(@project_members, group).execute(current_user) - end + @project_members = MembersFinder.new(@project, current_user).execute if params[:search].present? - user_ids = @project.users.search(params[:search]).select(:id) - @project_members = @project_members.where(user_id: user_ids) - - if group_members - user_ids = group.users.search(params[:search]).select(:id) - group_members = group_members.where(user_id: user_ids) - end - - @group_links = @project.project_group_links.where(group_id: @project.invited_groups.search(params[:search]).select(:id)) + @project_members = @project_members.joins(:user).merge(User.search(params[:search])) + @group_links = @group_links.where(group_id: @project.invited_groups.search(params[:search]).select(:id)) end - wheres = ["members.id IN (#{@project_members.select(:id).to_sql})"] - wheres << "members.id IN (#{group_members.select(:id).to_sql})" if group_members - - @project_members = Member. - where(wheres.join(' OR ')). - sort(@sort). - page(params[:page]) - + @project_members = @project_members.sort(@sort).page(params[:page]) @requesters = AccessRequestsFinder.new(@project).execute(current_user) - @project_member = @project.project_members.new end end diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb new file mode 100644 index 00000000000..b6ce4abca45 --- /dev/null +++ b/app/controllers/projects/settings/repository_controller.rb @@ -0,0 +1,50 @@ +module Projects + module Settings + class RepositoryController < Projects::ApplicationController + before_action :authorize_admin_project! + + def show + @deploy_keys = DeployKeysPresenter + .new(@project, current_user: current_user) + + define_protected_branches + end + + private + + def define_protected_branches + load_protected_branches + @protected_branch = @project.protected_branches.new + load_gon_index + end + + def load_protected_branches + @protected_branches = @project.protected_branches.order(:name).page(params[:page]) + end + + def access_levels_options + { + push_access_levels: { + roles: ProtectedBranch::PushAccessLevel.human_access_levels.map do |id, text| + { id: id, text: text, before_divider: true } + end + }, + merge_access_levels: { + roles: ProtectedBranch::MergeAccessLevel.human_access_levels.map do |id, text| + { id: id, text: text, before_divider: true } + end + } + } + end + + def open_branches + branches = @project.open_branches.map { |br| { text: br.name, id: br.name, title: br.name } } + { open_branches: branches } + end + + def load_gon_index + gon.push(open_branches.merge(access_levels_options)) + end + end + end +end diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index 33379659d73..e13f0bde315 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -14,7 +14,9 @@ class Projects::TagsController < Projects::ApplicationController @tags = TagsFinder.new(@repository, params).execute @tags = Kaminari.paginate_array(@tags).page(params[:page]) - @releases = project.releases.where(tag: @tags.map(&:name)) + tag_names = @tags.map(&:name) + @tags_pipelines = @project.pipelines.latest_successful_for_refs(tag_names) + @releases = project.releases.where(tag: tag_names) end def show @@ -41,13 +43,27 @@ class Projects::TagsController < Projects::ApplicationController end def destroy - Tags::DestroyService.new(project, current_user).execute(params[:id]) + result = Tags::DestroyService.new(project, current_user).execute(params[:id]) respond_to do |format| - format.html do - redirect_to namespace_project_tags_path(@project.namespace, @project) + if result[:status] == :success + format.html do + redirect_to namespace_project_tags_path(@project.namespace, @project) + end + + format.js + else + @error = result[:message] + + format.html do + redirect_to namespace_project_tags_path(@project.namespace, @project), + alert: @error + end + + format.js do + render status: :unprocessable_entity + end end - format.js end end end diff --git a/app/controllers/projects/triggers_controller.rb b/app/controllers/projects/triggers_controller.rb index b2c11ea4156..c47198c5eb6 100644 --- a/app/controllers/projects/triggers_controller.rb +++ b/app/controllers/projects/triggers_controller.rb @@ -1,5 +1,8 @@ class Projects::TriggersController < Projects::ApplicationController before_action :authorize_admin_build! + before_action :authorize_manage_trigger!, except: [:index, :create] + before_action :authorize_admin_trigger!, only: [:edit, :update] + before_action :trigger, only: [:take_ownership, :edit, :update, :destroy] layout 'project_settings' @@ -8,27 +11,67 @@ class Projects::TriggersController < Projects::ApplicationController end def create - @trigger = project.triggers.new - @trigger.save + @trigger = project.triggers.create(create_params.merge(owner: current_user)) if @trigger.valid? - redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Trigger was created successfully.' + flash[:notice] = 'Trigger was created successfully.' else - @triggers = project.triggers.select(&:persisted?) - render action: "show" + flash[:alert] = 'You could not create a new trigger.' + end + + redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project) + end + + def take_ownership + if trigger.update(owner: current_user) + flash[:notice] = 'Trigger was re-assigned.' + else + flash[:alert] = 'You could not take ownership of trigger.' + end + + redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project) + end + + def edit + end + + def update + if trigger.update(update_params) + redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project), notice: 'Trigger was successfully updated.' + else + render action: "edit" end end def destroy - trigger.destroy - flash[:alert] = "Trigger removed" + if trigger.destroy + flash[:notice] = "Trigger removed." + else + flash[:alert] = "Could not remove the trigger." + end redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project) end private + def authorize_manage_trigger! + access_denied! unless can?(current_user, :manage_trigger, trigger) + end + + def authorize_admin_trigger! + access_denied! unless can?(current_user, :admin_trigger, trigger) + end + def trigger - @trigger ||= project.triggers.find(params[:id]) + @trigger ||= project.triggers.find(params[:id]) || render_404 + end + + def create_params + params.require(:trigger).permit(:description) + end + + def update_params + params.require(:trigger).permit(:description) end end diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb index 2d8064c9878..f210f7e61d2 100644 --- a/app/controllers/projects/wikis_controller.rb +++ b/app/controllers/projects/wikis_controller.rb @@ -1,5 +1,3 @@ -require 'project_wiki' - class Projects::WikisController < Projects::ApplicationController before_action :authorize_read_wiki! before_action :authorize_create_wiki!, only: [:edit, :create, :history] @@ -47,8 +45,9 @@ class Projects::WikisController < Projects::ApplicationController return render('empty') unless can?(current_user, :create_wiki, @project) @page = @project_wiki.find_page(params[:id]) + @page = WikiPages::UpdateService.new(@project, current_user, wiki_params).execute(@page) - if @page = WikiPages::UpdateService.new(@project, current_user, wiki_params).execute(@page) + if @page.valid? redirect_to( namespace_project_wiki_path(@project.namespace, @project, @page), notice: 'Wiki was successfully updated.' diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index acca821782c..47f7e0b1b28 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -117,7 +117,7 @@ class ProjectsController < Projects::ApplicationController return access_denied! unless can?(current_user, :remove_project, @project) ::Projects::DestroyService.new(@project, current_user, {}).async_execute - flash[:alert] = "Project '#{@project.name}' will be deleted." + flash[:alert] = "Project '#{@project.name_with_namespace}' will be deleted." redirect_to dashboard_projects_path rescue Projects::DestroyService::DestroyError => ex @@ -267,8 +267,9 @@ class ProjectsController < Projects::ApplicationController @project_wiki = @project.wiki @wiki_home = @project_wiki.find_page('home', params[:version_id]) elsif @project.feature_available?(:issues, current_user) - @issues = issues_collection - @issues = @issues.page(params[:page]) + @issues = issues_collection.page(params[:page]) + @collection_type = 'Issue' + @issuable_meta_data = issuable_meta_data(@issues, @collection_type) end render :show @@ -314,7 +315,8 @@ class ProjectsController < Projects::ApplicationController :name, :namespace_id, :only_allow_merge_if_all_discussions_are_resolved, - :only_allow_merge_if_build_succeeds, + :only_allow_merge_if_pipeline_succeeds, + :printing_merge_request_link_enabled, :path, :public_builds, :request_access_enabled, diff --git a/app/controllers/root_controller.rb b/app/controllers/root_controller.rb index db2817fadf6..1b4545e4a49 100644 --- a/app/controllers/root_controller.rb +++ b/app/controllers/root_controller.rb @@ -8,7 +8,9 @@ # `DashboardController#show`, which is the default. class RootController < Dashboard::ProjectsController skip_before_action :authenticate_user!, only: [:index] - before_action :redirect_to_custom_dashboard, only: [:index] + + before_action :redirect_unlogged_user, if: -> { current_user.nil? } + before_action :redirect_logged_user, if: -> { current_user.present? } def index super @@ -16,23 +18,38 @@ class RootController < Dashboard::ProjectsController private - def redirect_to_custom_dashboard - return redirect_to new_user_session_path unless current_user + def redirect_unlogged_user + if redirect_to_home_page_url? + redirect_to(current_application_settings.home_page_url) + else + redirect_to(new_user_session_path) + end + end + def redirect_logged_user case current_user.dashboard when 'stars' flash.keep - redirect_to starred_dashboard_projects_path + redirect_to(starred_dashboard_projects_path) when 'project_activity' - redirect_to activity_dashboard_path + redirect_to(activity_dashboard_path) when 'starred_project_activity' - redirect_to activity_dashboard_path(filter: 'starred') + redirect_to(activity_dashboard_path(filter: 'starred')) when 'groups' - redirect_to dashboard_groups_path + redirect_to(dashboard_groups_path) when 'todos' - redirect_to dashboard_todos_path - else - return + redirect_to(dashboard_todos_path) end end + + def redirect_to_home_page_url? + # If user is not signed-in and tries to access root_path - redirect him to landing page + # Don't redirect to the default URL to prevent endless redirections + return false unless current_application_settings.home_page_url.present? + + home_page_url = current_application_settings.home_page_url.chomp('/') + root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')] + + root_urls.exclude?(home_page_url) + end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 93a180b9036..7d81c96262f 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -15,11 +15,12 @@ class SessionsController < Devise::SessionsController def new set_minimum_password_length - if Gitlab.config.ldap.enabled - @ldap_servers = Gitlab::LDAP::Config.servers - else - @ldap_servers = [] - end + @ldap_servers = + if Gitlab.config.ldap.enabled + Gitlab::LDAP::Config.servers + else + [] + end super end diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index 2d26718873f..f3fd3da8b20 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -28,8 +28,9 @@ class SnippetsController < ApplicationController @snippets = SnippetsFinder.new.execute(current_user, { filter: :by_user, user: @user, - scope: params[:scope] }). - page(params[:page]) + scope: params[:scope] + }) + .page(params[:page]) render 'index' else diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 509f4f412ca..f1bfd574f04 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -14,6 +14,8 @@ class UploadsController < ApplicationController end disposition = uploader.image? ? 'inline' : 'attachment' + + expires_in 0.seconds, must_revalidate: true, private: true send_file uploader.file.path, disposition: disposition end |