diff options
Diffstat (limited to 'app/controllers')
51 files changed, 589 insertions, 234 deletions
diff --git a/app/controllers/admin/appearances_controller.rb b/app/controllers/admin/appearances_controller.rb index 26cf74e4849..4b0ec54b3f4 100644 --- a/app/controllers/admin/appearances_controller.rb +++ b/app/controllers/admin/appearances_controller.rb @@ -5,6 +5,7 @@ class Admin::AppearancesController < Admin::ApplicationController end def preview + render 'preview', layout: 'devise' end def create diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index f4eda864aac..23ba83aba0e 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -87,6 +87,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :version_check_enabled, :admin_notification_email, :user_oauth_applications, + :user_default_external, :shared_runners_enabled, :shared_runners_text, :max_artifacts_size, @@ -109,6 +110,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :metrics_packet_size, :send_user_confirmation_email, :container_registry_token_expire_delay, + :repository_storage, + :enabled_git_access_protocol, restricted_visibility_levels: [], import_sources: [], disabled_oauth_sign_in_sources: [] diff --git a/app/controllers/admin/builds_controller.rb b/app/controllers/admin/builds_controller.rb index 0db91eaaf2e..88f3c0e2fd4 100644 --- a/app/controllers/admin/builds_controller.rb +++ b/app/controllers/admin/builds_controller.rb @@ -5,8 +5,10 @@ class Admin::BuildsController < Admin::ApplicationController @builds = @all_builds.order('created_at DESC') @builds = case @scope + when 'pending' + @builds.pending.reverse_order when 'running' - @builds.running_or_pending.reverse_order + @builds.running.reverse_order when 'finished' @builds.finished else diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index a6db4690df0..94b5aaa71d0 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -10,6 +10,7 @@ class Admin::GroupsController < Admin::ApplicationController def show @members = @group.members.order("access_level DESC").page(params[:members_page]) + @requesters = @group.requesters @projects = @group.projects.page(params[:projects_page]) end diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb index 4e85b6b4cf2..cbfc4581411 100644 --- a/app/controllers/admin/hooks_controller.rb +++ b/app/controllers/admin/hooks_controller.rb @@ -22,7 +22,6 @@ class Admin::HooksController < Admin::ApplicationController redirect_to admin_hooks_path end - def test @hook = SystemHook.find(params[:hook_id]) data = { diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index 87986fdf8b1..0d2f4f6eb38 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -5,11 +5,12 @@ class Admin::ProjectsController < Admin::ApplicationController def index @projects = Project.all @projects = @projects.in_namespace(params[:namespace_id]) if params[:namespace_id].present? - @projects = @projects.where("projects.visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present? + @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present? @projects = @projects.with_push if params[:with_push].present? @projects = @projects.abandoned if params[:abandoned].present? @projects = @projects.where(last_repository_check_failed: true) if params[:last_repository_check_failed].present? - @projects = @projects.non_archived unless params[:with_archived].present? + @projects = @projects.non_archived unless params[:archived].present? + @projects = @projects.personal(current_user) if params[:personal].present? @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]) @@ -20,7 +21,8 @@ class Admin::ProjectsController < Admin::ApplicationController @group_members = @group.members.order("access_level DESC").page(params[:group_members_page]) end - @project_members = @project.project_members.page(params[:project_members_page]) + @project_members = @project.members.page(params[:project_members_page]) + @requesters = @project.requesters end def transfer diff --git a/app/controllers/admin/runner_projects_controller.rb b/app/controllers/admin/runner_projects_controller.rb index d25619d94e0..bc65dcc33d3 100644 --- a/app/controllers/admin/runner_projects_controller.rb +++ b/app/controllers/admin/runner_projects_controller.rb @@ -1,15 +1,12 @@ class Admin::RunnerProjectsController < Admin::ApplicationController before_action :project, only: [:create] - def index - @runner_projects = project.runner_projects.all - @runner_project = project.runner_projects.new - end - def create @runner = Ci::Runner.find(params[:runner_project][:runner_id]) - if @runner.assign_to(@project, current_user) + runner_project = @runner.assign_to(@project, current_user) + + if runner_project.persisted? redirect_to admin_runner_path(@runner) else redirect_to admin_runner_path(@runner), alert: 'Failed adding runner to project' diff --git a/app/controllers/admin/system_info_controller.rb b/app/controllers/admin/system_info_controller.rb new file mode 100644 index 00000000000..e4c73008826 --- /dev/null +++ b/app/controllers/admin/system_info_controller.rb @@ -0,0 +1,59 @@ +class Admin::SystemInfoController < Admin::ApplicationController + EXCLUDED_MOUNT_OPTIONS = [ + 'nobrowse', + 'read-only', + 'ro' + ] + + EXCLUDED_MOUNT_TYPES = [ + 'autofs', + 'binfmt_misc', + 'cgroup', + 'debugfs', + 'devfs', + 'devpts', + 'devtmpfs', + 'efivarfs', + 'fuse.gvfsd-fuse', + 'fuseblk', + 'fusectl', + 'hugetlbfs', + 'mqueue', + 'proc', + 'pstore', + 'securityfs', + 'sysfs', + 'tmpfs', + 'tracefs', + 'vfat' + ] + + def show + system_info = Vmstat.snapshot + mounts = Sys::Filesystem.mounts + + @disks = [] + mounts.each do |mount| + mount_options = mount.options.split(',') + + next if (EXCLUDED_MOUNT_OPTIONS & mount_options).any? + next if (EXCLUDED_MOUNT_TYPES & [mount.mount_type]).any? + + begin + disk = Sys::Filesystem.stat(mount.mount_point) + @disks.push({ + bytes_total: disk.bytes_total, + bytes_used: disk.bytes_used, + disk_name: mount.name, + mount_path: disk.path + }) + rescue Sys::Filesystem::Error + end + end + + @cpus = system_info.cpus.length + + @mem_used = system_info.memory.active_bytes + @mem_total = system_info.memory.total_bytes + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index dd1bc6f5d52..a1004d9bcea 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -36,6 +36,10 @@ class ApplicationController < ActionController::Base render_404 end + rescue_from Gitlab::Access::AccessDeniedError do |exception| + render_403 + end + def redirect_back_or_default(default: root_path, options: {}) redirect_to request.referer.present? ? :back : default, options end @@ -340,10 +344,6 @@ class ApplicationController < ActionController::Base session[:skip_tfa] && session[:skip_tfa] > Time.current end - def browser_supports_u2f? - browser.chrome? && browser.version.to_i >= 41 && !browser.device.mobile? - 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 diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb index 8bf71a1adbb..aa894fde36b 100644 --- a/app/controllers/ci/projects_controller.rb +++ b/app/controllers/ci/projects_controller.rb @@ -25,7 +25,7 @@ module Ci 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" + send_file image.path, filename: image.name, disposition: 'inline', type: "image/svg+xml" end protected diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index 998b8adc411..ba07cea569c 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -57,7 +57,7 @@ module AuthenticatesWithTwoFactor # Authenticate using the response from a U2F (universal 2nd factor) device def authenticate_with_two_factor_via_u2f(user) - if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenges]) + if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge]) # Remove any lingering user data from login session.delete(:otp_user_id) session.delete(:challenges) @@ -77,11 +77,9 @@ module AuthenticatesWithTwoFactor if key_handles.present? sign_requests = u2f.authentication_requests(key_handles) - challenges = sign_requests.map(&:challenge) - session[:challenges] = challenges - gon.push(u2f: { challenges: challenges, app_id: u2f_app_id, - sign_requests: sign_requests, - browser_supports_u2f: browser_supports_u2f? }) + session[:challenge] ||= u2f.challenge + gon.push(u2f: { challenge: session[:challenge], app_id: u2f_app_id, + sign_requests: sign_requests }) end end end diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index dacb5679dd3..f2b8f297bc2 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -7,7 +7,8 @@ module CreatesCommit commit_params = @commit_params.merge( source_project: @project, source_branch: @ref, - target_branch: @target_branch + target_branch: @target_branch, + previous_path: @previous_path ) result = service.new(@tree_edit_project, current_user, commit_params).execute diff --git a/app/controllers/concerns/diff_for_path.rb b/app/controllers/concerns/diff_for_path.rb new file mode 100644 index 00000000000..026d8b2e1e0 --- /dev/null +++ b/app/controllers/concerns/diff_for_path.rb @@ -0,0 +1,24 @@ +module DiffForPath + extend ActiveSupport::Concern + + def render_diff_for_path(diffs, diff_refs, project) + diff_file = safe_diff_files(diffs, diff_refs: diff_refs, repository: project.repository).find do |diff| + diff.old_path == params[:old_path] && diff.new_path == params[:new_path] + end + + return render_404 unless diff_file + + diff_commit = commit_for_diff(diff_file) + blob = diff_file.blob(diff_commit) + + locals = { + diff_file: diff_file, + diff_commit: diff_commit, + diff_refs: diff_refs, + blob: blob, + project: project + } + + render json: { html: view_to_html_string('projects/diffs/_content', locals) } + end +end diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb index a24273fad0b..52682ef9dc9 100644 --- a/app/controllers/concerns/membership_actions.rb +++ b/app/controllers/concerns/membership_actions.rb @@ -10,7 +10,7 @@ module MembershipActions end def approve_access_request - @member = membershipable.members.request.find(params[:id]) + @member = membershipable.requesters.find(params[:id]) return render_403 unless can?(current_user, action_member_permission(:update, @member), @member) @@ -20,30 +20,20 @@ module MembershipActions end def leave - @member = membershipable.members.find_by(user_id: current_user) - return render_403 unless @member + @member = membershipable.members.find_by(user_id: current_user) || + membershipable.requesters.find_by(user_id: current_user) + Members::DestroyService.new(@member, current_user).execute source_type = @member.real_source_type.humanize(capitalize: false) - - if can?(current_user, action_member_permission(:destroy, @member), @member) - notice = - if @member.request? - "Your access request to the #{source_type} has been withdrawn." - else - "You left the \"#{@member.source.human_name}\" #{source_type}." - end - @member.destroy - - redirect_to [:dashboard, @member.real_source_type.tableize], notice: notice - else - if cannot_leave? - alert = "You can not leave the \"#{@member.source.human_name}\" #{source_type}." - alert << " Transfer or delete the #{source_type}." - redirect_to polymorphic_url(membershipable), alert: alert + notice = + if @member.request? + "Your access request to the #{source_type} has been withdrawn." else - render_403 + "You left the \"#{@member.source.human_name}\" #{source_type}." end - end + redirect_path = @member.request? ? @member.source : [:dashboard, @member.real_source_type.tableize] + + redirect_to redirect_path, notice: notice end protected @@ -51,8 +41,4 @@ module MembershipActions def membershipable raise NotImplementedError end - - def cannot_leave? - raise NotImplementedError - end end diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index 7b66ad3f92c..3da44b9b888 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -1,5 +1,4 @@ class ConfirmationsController < Devise::ConfirmationsController - def almost_there flash[:notice] = nil render layout: "devise_empty" diff --git a/app/controllers/dashboard/groups_controller.rb b/app/controllers/dashboard/groups_controller.rb index 71ba6153021..de6bc689bb7 100644 --- a/app/controllers/dashboard/groups_controller.rb +++ b/app/controllers/dashboard/groups_controller.rb @@ -1,5 +1,5 @@ class Dashboard::GroupsController < Dashboard::ApplicationController def index - @group_members = current_user.group_members.page(params[:page]) + @group_members = current_user.group_members.includes(:source).page(params[:page]) end end diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb index 3a2db3e6eeb..19a76a5b5d8 100644 --- a/app/controllers/dashboard/todos_controller.rb +++ b/app/controllers/dashboard/todos_controller.rb @@ -1,6 +1,4 @@ class Dashboard::TodosController < Dashboard::ApplicationController - include TodosHelper - before_action :find_todos, only: [:index, :destroy_all] def index @@ -13,7 +11,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController respond_to do |format| format.html { redirect_to dashboard_todos_path, notice: 'Todo was successfully marked as done.' } format.js { head :ok } - format.json { render json: { count: todos_pending_count, done_count: todos_done_count } } + format.json { render json: todos_counts } end end @@ -23,7 +21,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController 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: { count: todos_pending_count, done_count: todos_done_count } } + format.json { render json: todos_counts } end end @@ -36,4 +34,11 @@ class Dashboard::TodosController < Dashboard::ApplicationController def find_todos @todos ||= TodosFinder.new(current_user, params).execute end + + def todos_counts + { + count: TodosFinder.new(current_user, state: :pending).execute.count, + done_count: TodosFinder.new(current_user, state: :done).execute.count + } + end end diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index d0f2e2949f0..9fc41a12536 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -7,7 +7,7 @@ class Groups::GroupMembersController < Groups::ApplicationController def index @project = @group.projects.find(params[:project_id]) if params[:project_id] @members = @group.group_members - @members = @members.non_pending unless can?(current_user, :admin_group, @group) + @members = @members.non_invite unless can?(current_user, :admin_group, @group) if params[:search].present? users = @group.users.search(params[:search]).to_a @@ -15,6 +15,7 @@ class Groups::GroupMembersController < Groups::ApplicationController end @members = @members.order('access_level DESC').page(params[:page]).per(50) + @requesters = @group.requesters if can?(current_user, :admin_group, @group) @group_member = @group.group_members.new end @@ -34,11 +35,10 @@ class Groups::GroupMembersController < Groups::ApplicationController end def destroy - @group_member = @group.group_members.find(params[:id]) - - return render_403 unless can?(current_user, :destroy_group_member, @group_member) + @group_member = @group.members.find_by(id: params[:id]) || + @group.requesters.find_by(id: params[:id]) - @group_member.destroy + Members::DestroyService.new(@group_member, current_user).execute respond_to do |format| format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' } @@ -68,8 +68,4 @@ class Groups::GroupMembersController < Groups::ApplicationController # MembershipActions concern alias_method :membershipable, :group - - def cannot_leave? - @group.last_owner?(current_user) - end end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index ee4fcc4e360..a04bf7df722 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -37,15 +37,12 @@ class GroupsController < Groups::ApplicationController end def show - @last_push = current_user.recent_push if current_user - - @projects = @projects.includes(:namespace) - @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? + if current_user + @last_push = current_user.recent_push + @notification_setting = current_user.notification_settings_for(group) + end - @shared_projects = GroupProjectsFinder.new(group, only_shared: true).execute(current_user) + setup_projects respond_to do |format| format.html @@ -97,6 +94,16 @@ class GroupsController < Groups::ApplicationController protected + def setup_projects + @projects = @projects.includes(:namespace) + @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? + + @shared_projects = GroupProjectsFinder.new(group, only_shared: true).execute(current_user) + end + def authorize_create_group! unless can?(current_user, :create_group, nil) return render_404 diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index 9b5c43b17e2..d3dd98c8a4e 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -12,13 +12,12 @@ class HelpController < ApplicationController end def show - @category = clean_path_info(path_params[:category]) - @file = path_params[:file] + @path = clean_path_info(path_params[:path]) respond_to do |format| format.any(:markdown, :md, :html) do # Note: We are purposefully NOT using `Rails.root.join` - path = File.join(Rails.root, 'doc', @category, "#{@file}.md") + path = File.join(Rails.root, 'doc', "#{@path}.md") if File.exist?(path) @markdown = File.read(path) @@ -33,7 +32,7 @@ class HelpController < ApplicationController # Allow access to images in the doc folder format.any(:png, :gif, :jpeg) do # Note: We are purposefully NOT using `Rails.root.join` - path = File.join(Rails.root, 'doc', @category, "#{@file}.#{params[:format]}") + path = File.join(Rails.root, 'doc', "#{@path}.#{params[:format]}") if File.exist?(path) send_file(path, disposition: 'inline') @@ -57,8 +56,7 @@ class HelpController < ApplicationController private def path_params - params.require(:category) - params.require(:file) + params.require(:path) params end diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb index 93a7ace3530..7e8597a5eb3 100644 --- a/app/controllers/import/base_controller.rb +++ b/app/controllers/import/base_controller.rb @@ -1,5 +1,4 @@ class Import::BaseController < ApplicationController - private def get_or_create_namespace diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb index 18300390851..99b10b2f9b3 100644 --- a/app/controllers/import/fogbugz_controller.rb +++ b/app/controllers/import/fogbugz_controller.rb @@ -5,7 +5,6 @@ class Import::FogbugzController < Import::BaseController rescue_from Fogbugz::AuthenticationException, with: :fogbugz_unauthorized def new - end def callback @@ -22,7 +21,6 @@ class Import::FogbugzController < Import::BaseController end def new_user_map - end def create_user_map diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb index 67bf4190e7e..9c1b0eb20f4 100644 --- a/app/controllers/import/github_controller.rb +++ b/app/controllers/import/github_controller.rb @@ -1,14 +1,29 @@ class Import::GithubController < Import::BaseController before_action :verify_github_import_enabled - before_action :github_auth, except: :callback + before_action :github_auth, only: [:status, :jobs, :create] rescue_from Octokit::Unauthorized, with: :github_unauthorized + helper_method :logged_in_with_github? + + def new + if logged_in_with_github? + go_to_github_for_permissions + elsif session[:github_access_token] + redirect_to status_import_github_url + end + end + def callback session[:github_access_token] = client.get_token(params[:code]) redirect_to status_import_github_url end + def personal_access_token + session[:github_access_token] = params[:personal_access_token] + redirect_to status_import_github_url + end + def status @repos = client.repos @already_added_projects = current_user.created_projects.where(import_type: "github") @@ -57,10 +72,14 @@ class Import::GithubController < Import::BaseController end def github_unauthorized - go_to_github_for_permissions + session[:github_access_token] = nil + redirect_to new_import_github_url, + alert: 'Access denied to your GitHub account.' end - private + def logged_in_with_github? + current_user.identities.exists?(provider: 'github') + end def access_params { github_access_token: session[:github_access_token] } diff --git a/app/controllers/import/gitlab_projects_controller.rb b/app/controllers/import/gitlab_projects_controller.rb index f99aa490d3e..30df1fb2fec 100644 --- a/app/controllers/import/gitlab_projects_controller.rb +++ b/app/controllers/import/gitlab_projects_controller.rb @@ -12,9 +12,13 @@ class Import::GitlabProjectsController < Import::BaseController return redirect_back_or_default(options: { alert: "You need to upload a GitLab project export archive." }) end + imported_file = project_params[:file].path + "-import" + + FileUtils.copy_entry(project_params[:file].path, imported_file) + @project = Gitlab::ImportExport::ProjectCreator.new(project_params[:namespace_id], current_user, - File.expand_path(project_params[:file].path), + File.expand_path(imported_file), project_params[:path]).execute if @project.saved? @@ -23,10 +27,7 @@ class Import::GitlabProjectsController < Import::BaseController notice: "Project '#{@project.name}' is being imported." ) else - redirect_to( - new_import_gitlab_project_path, - alert: "Project could not be imported: #{@project.errors.full_messages.join(', ')}" - ) + redirect_back_or_default(options: { alert: "Project could not be imported: #{@project.errors.full_messages.join(', ')}" }) end end diff --git a/app/controllers/import/gitorious_controller.rb b/app/controllers/import/gitorious_controller.rb index eecbe380c9e..a4c4ad23027 100644 --- a/app/controllers/import/gitorious_controller.rb +++ b/app/controllers/import/gitorious_controller.rb @@ -44,5 +44,4 @@ class Import::GitoriousController < Import::BaseController def verify_gitorious_import_enabled render_404 unless gitorious_import_enabled? end - end diff --git a/app/controllers/import/google_code_controller.rb b/app/controllers/import/google_code_controller.rb index e0de31f2251..8d0de158f98 100644 --- a/app/controllers/import/google_code_controller.rb +++ b/app/controllers/import/google_code_controller.rb @@ -3,7 +3,6 @@ class Import::GoogleCodeController < Import::BaseController before_action :user_map, only: [:new_user_map, :create_user_map] def new - end def callback @@ -34,7 +33,6 @@ class Import::GoogleCodeController < Import::BaseController end def new_user_map - end def create_user_map diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 94bb108c5f5..58964a0e65d 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -5,7 +5,6 @@ class InvitesController < ApplicationController respond_to :html def show - end def accept diff --git a/app/controllers/notification_settings_controller.rb b/app/controllers/notification_settings_controller.rb index eddd03cc229..8ec4bb1233f 100644 --- a/app/controllers/notification_settings_controller.rb +++ b/app/controllers/notification_settings_controller.rb @@ -2,11 +2,9 @@ class NotificationSettingsController < ApplicationController before_action :authenticate_user! def create - project = Project.find(params[:project][:id]) + return render_404 unless can_read?(resource) - return render_404 unless can?(current_user, :read_project, project) - - @notification_setting = current_user.notification_settings_for(project) + @notification_setting = current_user.notification_settings_for(resource) @saved = @notification_setting.update_attributes(notification_setting_params) render_response @@ -21,6 +19,22 @@ class NotificationSettingsController < ApplicationController private + def resource + @resource ||= + if params[:project_id].present? + Project.find(params[:project_id]) + elsif params[:namespace_id].present? + Group.find(params[:namespace_id]) + end + end + + def can_read?(resource) + ability_name = resource.class.name.downcase + ability_name = "read_#{ability_name}".to_sym + + can?(current_user, ability_name, resource) + end + def render_response render json: { html: view_to_html_string("shared/notifications/_button", notification_setting: @notification_setting), diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index f35d631df0c..f54c79c2e37 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -107,7 +107,11 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController # Only allow properly saved users to login. if @user.persisted? && @user.valid? log_audit_event(@user, with: oauth['provider']) - sign_in_and_redirect(@user) + if @user.two_factor_enabled? + prompt_for_two_factor(@user) + else + sign_in_and_redirect(@user) + end else error_message = @user.errors.full_messages.to_sentence diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb index 6a358fdcc05..e37e9e136db 100644 --- a/app/controllers/profiles/two_factor_auths_controller.rb +++ b/app/controllers/profiles/two_factor_auths_controller.rb @@ -100,7 +100,6 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController gon.push(u2f: { challenges: session[:challenges], app_id: u2f_app_id, register_requests: registration_requests, - sign_requests: sign_requests, - browser_supports_u2f: browser_supports_u2f? }) + sign_requests: sign_requests }) end end diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb index 776ba92c9ab..996909a28c6 100644 --- a/app/controllers/projects/application_controller.rb +++ b/app/controllers/projects/application_controller.rb @@ -74,7 +74,7 @@ class Projects::ApplicationController < ApplicationController end def require_branch_head - unless @repository.branch_names.include?(@ref) + unless @repository.branch_exists?(@ref) redirect_to( namespace_project_tree_path(@project.namespace, @project, @ref), notice: "This action is not allowed unless you are on a branch" diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb index f11c8321464..7241949393b 100644 --- a/app/controllers/projects/artifacts_controller.rb +++ b/app/controllers/projects/artifacts_controller.rb @@ -23,10 +23,9 @@ class Projects::ArtifactsController < Projects::ApplicationController entry = build.artifacts_metadata_entry(params[:path]) if entry.exists? - render json: { archive: build.artifacts_file.path, - entry: Base64.encode64(entry.path) } + send_artifacts_entry(build, entry) else - render json: {}, status: 404 + render_404 end end diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index cd8b2911674..eda3727a28d 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -16,6 +16,7 @@ class Projects::BlobController < Projects::ApplicationController before_action :from_merge_request, only: [:edit, :update] before_action :require_branch_head, only: [:edit, :update] before_action :editor_variables, except: [:show, :preview, :diff] + before_action :validate_diff_params, only: :diff def new commit unless @repository.empty? @@ -37,6 +38,12 @@ class Projects::BlobController < Projects::ApplicationController end def update + if params[:file_path].present? + @previous_path = @path + @path = params[:file_path] + @commit_params[:file_path] = @path + end + after_edit_path = if from_merge_request && @target_branch == @ref diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) + @@ -56,7 +63,7 @@ class Projects::BlobController < Projects::ApplicationController diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true) diff_lines = diffy.diff.scan(/.*\n/)[2..-1] diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines) - @diff_lines = Gitlab::Diff::Highlight.new(diff_lines).highlight + @diff_lines = Gitlab::Diff::Highlight.new(diff_lines, repository: @repository).highlight render layout: false end @@ -146,4 +153,10 @@ class Projects::BlobController < Projects::ApplicationController file_content_encoding: params[:encoding] } end + + def validate_diff_params + if [:since, :to, :offset].any? { |key| params[key].blank? } + render nothing: true + end + end end diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb index ef3051d7519..553b62741a5 100644 --- a/app/controllers/projects/builds_controller.rb +++ b/app/controllers/projects/builds_controller.rb @@ -1,6 +1,6 @@ class Projects::BuildsController < Projects::ApplicationController before_action :build, except: [:index, :cancel_all] - before_action :authorize_read_build!, except: [:cancel, :cancel_all, :retry] + before_action :authorize_read_build!, except: [:cancel, :cancel_all, :retry, :play] before_action :authorize_update_build!, except: [:index, :show, :status, :raw] layout 'project' @@ -10,8 +10,10 @@ class Projects::BuildsController < Projects::ApplicationController @builds = @all_builds.order('created_at DESC') @builds = case @scope + when 'pending' + @builds.pending.reverse_order when 'running' - @builds.running_or_pending.reverse_order + @builds.running.reverse_order when 'finished' @builds.finished else @@ -47,14 +49,19 @@ class Projects::BuildsController < Projects::ApplicationController end def retry - unless @build.retryable? - return render_404 - end + return render_404 unless @build.retryable? build = Ci::Build.retry(@build, current_user) redirect_to build_path(build) end + def play + return render_404 unless @build.playable? + + build = @build.play(current_user) + redirect_to build_path(build) + end + def cancel @build.cancel redirect_to build_path(@build) diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index 6751737d15e..727e84b40a1 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -3,6 +3,7 @@ # Not to be confused with CommitsController, plural. class Projects::CommitController < Projects::ApplicationController include CreatesCommit + include DiffForPath include DiffHelper # Authorize @@ -11,22 +12,14 @@ class Projects::CommitController < Projects::ApplicationController before_action :authorize_update_build!, only: [:cancel_builds, :retry_builds] before_action :authorize_read_commit_status!, only: [:builds] before_action :commit - before_action :define_show_vars, only: [:show, :builds] + before_action :define_commit_vars, only: [:show, :diff_for_path, :builds] + before_action :define_status_vars, only: [:show, :builds] + before_action :define_note_vars, only: [:show, :diff_for_path] before_action :authorize_edit_tree!, only: [:revert, :cherry_pick] def show apply_diff_view_cookie! - @grouped_diff_notes = commit.notes.grouped_diff_notes - - @note = @project.build_commit_note(commit) - @notes = commit.notes.non_diff_notes.fresh - @noteable = @commit - @comments_target = { - noteable_type: 'Commit', - commit_id: @commit.id - } - respond_to do |format| format.html format.diff { render text: @commit.to_diff } @@ -34,6 +27,10 @@ class Projects::CommitController < Projects::ApplicationController end end + def diff_for_path + render_diff_for_path(@diffs, @commit.diff_refs, @project) + end + def builds end @@ -107,16 +104,36 @@ class Projects::CommitController < Projects::ApplicationController @ci_builds ||= Ci::Build.where(pipeline: pipelines) end - def define_show_vars + def define_commit_vars return git_not_found! unless commit opts = diff_options opts[:ignore_whitespace_change] = true if params[:format] == 'diff' @diffs = commit.diffs(opts) - @diff_refs = [commit.parent || commit, commit] @notes_count = commit.notes.count + end + + def define_note_vars + @grouped_diff_notes = commit.notes.grouped_diff_notes + @notes = commit.notes.non_diff_notes.fresh + + Banzai::NoteRenderer.render( + @grouped_diff_notes.values.flatten + @notes, + @project, + current_user, + ) + + @note = @project.build_commit_note(commit) + + @noteable = @commit + @comments_target = { + noteable_type: 'Commit', + commit_id: @commit.id + } + end + def define_status_vars @statuses = CommitStatus.where(pipeline: pipelines) @builds = Ci::Build.where(pipeline: pipelines) end diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index af0b69a2442..5f3ee71444d 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -1,30 +1,26 @@ require 'addressable/uri' class Projects::CompareController < Projects::ApplicationController + include DiffForPath include DiffHelper # Authorize before_action :require_non_empty_project before_action :authorize_download_code! - before_action :assign_ref_vars, only: [:index, :show] + before_action :define_ref_vars, only: [:index, :show, :diff_for_path] + before_action :define_diff_vars, only: [:show, :diff_for_path] before_action :merge_request, only: [:index, :show] def index end def show - compare = CompareService.new. - execute(@project, @head_ref, @project, @base_ref, diff_options) + end - if compare - @commits = Commit.decorate(compare.commits, @project) - @commit = @project.commit(@head_ref) - @base_commit = @project.merge_base_commit(@base_ref, @head_ref) - @diffs = compare.diffs(diff_options) - @diff_refs = [@base_commit, @commit] - @diff_notes_disabled = true - @grouped_diff_notes = {} - end + def diff_for_path + return render_404 unless @compare + + render_diff_for_path(@diffs, @diff_refs, @project) end def create @@ -34,13 +30,35 @@ class Projects::CompareController < Projects::ApplicationController private - def assign_ref_vars - @base_ref = Addressable::URI.unescape(params[:from]) + def define_ref_vars + @start_ref = Addressable::URI.unescape(params[:from]) @ref = @head_ref = Addressable::URI.unescape(params[:to]) end + def define_diff_vars + @compare = CompareService.new.execute(@project, @head_ref, @project, @start_ref) + + if @compare + @commits = Commit.decorate(@compare.commits, @project) + + @start_commit = @project.commit(@start_ref) + @commit = @project.commit(@head_ref) + @base_commit = @project.merge_base_commit(@start_ref, @head_ref) + + @diffs = @compare.diffs(diff_options) + @diff_refs = Gitlab::Diff::DiffRefs.new( + base_sha: @base_commit.try(:sha), + start_sha: @start_commit.try(:sha), + head_sha: @commit.try(:sha) + ) + + @diff_notes_disabled = true + @grouped_diff_notes = {} + end + end + def merge_request @merge_request ||= @project.merge_requests.opened. - find_by(source_project: @project, source_branch: @head_ref, target_branch: @base_ref) + find_by(source_project: @project, source_branch: @head_ref, target_branch: @start_ref) end end diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb index f907d63258b..40a8b7940d9 100644 --- a/app/controllers/projects/git_http_controller.rb +++ b/app/controllers/projects/git_http_controller.rb @@ -1,4 +1,9 @@ +# This file should be identical in GitLab Community Edition and Enterprise Edition + class Projects::GitHttpController < Projects::ApplicationController + include ActionController::HttpAuthentication::Basic + include KerberosSpnegoHelper + attr_reader :user # Git clients will not know what authenticity token to send along @@ -14,6 +19,8 @@ class Projects::GitHttpController < Projects::ApplicationController render_ok elsif receive_pack? && receive_pack_allowed? render_ok + elsif http_blocked? + render_not_allowed else render_not_found end @@ -40,9 +47,12 @@ class Projects::GitHttpController < Projects::ApplicationController private def authenticate_user - return if project && project.public? && upload_pack? + if project && project.public? && upload_pack? + return # Allow access + end - authenticate_or_request_with_http_basic do |login, password| + if allow_basic_auth? && basic_auth_provided? + login, password = user_name_and_password(request) auth_result = Gitlab::Auth.find_for_git_client(login, password, project: project, ip: request.ip) if auth_result.type == :ci && upload_pack? @@ -53,8 +63,31 @@ class Projects::GitHttpController < Projects::ApplicationController @user = auth_result.user end - ci? || user + if ci? || user + return # Allow access + end + elsif allow_kerberos_spnego_auth? && spnego_provided? + @user = find_kerberos_user + + if user + send_final_spnego_response + return # Allow access + end end + + send_challenges + render plain: "HTTP Basic: Access denied\n", status: 401 + end + + def basic_auth_provided? + has_basic_credentials?(request) + end + + def send_challenges + challenges = [] + challenges << 'Basic realm="GitLab"' if allow_basic_auth? + challenges << spnego_challenge if allow_kerberos_spnego_auth? + headers['Www-Authenticate'] = challenges.join("\n") if challenges.any? end def ensure_project_found! @@ -120,7 +153,11 @@ class Projects::GitHttpController < Projects::ApplicationController end def render_not_found - render text: 'Not Found', status: :not_found + render plain: 'Not Found', status: :not_found + end + + def render_not_allowed + render plain: download_access.message, status: :forbidden end def ci? @@ -131,12 +168,28 @@ class Projects::GitHttpController < Projects::ApplicationController return false unless Gitlab.config.gitlab_shell.upload_pack if user - Gitlab::GitAccess.new(user, project).download_access_check.allowed? + download_access.allowed? else ci? || project.public? end end + def access + return @access if defined?(@access) + + @access = Gitlab::GitAccess.new(user, project, 'http') + end + + def download_access + return @download_access if defined?(@download_access) + + @download_access = access.check('git-upload-pack') + end + + def http_blocked? + !access.protocol_allowed? + end + def receive_pack_allowed? return false unless Gitlab.config.gitlab_shell.receive_pack diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 4e2d3bebb2e..fa663c9bda4 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -62,8 +62,12 @@ class Projects::IssuesController < Projects::ApplicationController end def show + raw_notes = @issue.notes_with_associations.fresh + + @notes = Banzai::NoteRenderer. + render(raw_notes, @project, current_user, @path, @project_wiki, @ref) + @note = @project.notes.new(noteable: @issue) - @notes = @issue.notes.with_associations.fresh @noteable = @issue respond_to do |format| @@ -72,7 +76,6 @@ class Projects::IssuesController < Projects::ApplicationController render json: @issue.to_json(include: [:milestone, :labels]) end end - end def create @@ -111,6 +114,7 @@ class Projects::IssuesController < Projects::ApplicationController render :edit end end + format.json do render json: @issue.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } }) end @@ -222,6 +226,7 @@ class Projects::IssuesController < Projects::ApplicationController :assignee_id, :milestone_id, :state_event, + :subscription_event, label_ids: [], add_label_ids: [], remove_label_ids: [] diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 851822d805a..df659bb8c3b 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -1,5 +1,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController include ToggleSubscriptionAction + include DiffForPath include DiffHelper include IssuableActions include ToggleAwardEmoji @@ -9,10 +10,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController :edit, :update, :show, :diffs, :commits, :builds, :merge, :merge_check, :ci_status, :toggle_subscription, :cancel_merge_when_build_succeeds, :remove_wip ] - before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits, :builds] before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds] before_action :define_show_vars, only: [:show, :diffs, :commits, :builds] before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_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] # Allow read any merge_request @@ -53,13 +55,19 @@ class Projects::MergeRequestsController < Projects::ApplicationController end def show - @note_counts = Note.where(commit_id: @merge_request.commits.map(&:id)). - group(:commit_id).count - respond_to do |format| - format.html - format.json { render json: @merge_request } - format.patch { render text: @merge_request.to_patch } + format.html { define_discussion_vars } + + format.json do + render json: @merge_request + end + + format.patch do + return render_404 unless @merge_request.diff_refs + + send_git_patch @project.repository, @merge_request.diff_refs + end + format.diff do return render_404 unless @merge_request.diff_refs @@ -71,43 +79,65 @@ class Projects::MergeRequestsController < Projects::ApplicationController def diffs apply_diff_view_cookie! - @commit = @merge_request.last_commit - @base_commit = @merge_request.diff_base_commit - - # MRs created before 8.4 don't have a diff_base_commit, - # but we need it for the "View file @ ..." link by deleted files - @base_commit ||= @merge_request.first_commit.parent || @merge_request.first_commit - - @comments_target = { - noteable_type: 'MergeRequest', - noteable_id: @merge_request.id - } - - @grouped_diff_notes = @merge_request.notes.grouped_diff_notes + @merge_request_diff = @merge_request.merge_request_diff respond_to do |format| - format.html + format.html { define_discussion_vars } format.json { render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") } } end end + # With an ID param, loads the MR at that ID. Otherwise, accepts the same params as #new + # and uses that (unsaved) MR. + # + def diff_for_path + if params[:id] + merge_request + define_diff_comment_vars + else + build_merge_request + @diff_notes_disabled = true + @grouped_diff_notes = {} + end + + define_commit_vars + diffs = @merge_request.diffs(diff_options) + + render_diff_for_path(diffs, @merge_request.diff_refs, @merge_request.project) + end + def commits respond_to do |format| - format.html { render 'show' } - format.json { render json: { html: view_to_html_string('projects/merge_requests/show/_commits') } } + format.html do + define_discussion_vars + + render 'show' + end + format.json do + # Get commits from repository + # or from cache if already merged + @commits = @merge_request.commits + @note_counts = Note.where(commit_id: @commits.map(&:id)). + group(:commit_id).count + + render json: { html: view_to_html_string('projects/merge_requests/show/_commits') } + end end end def builds respond_to do |format| - format.html { render 'show' } + format.html do + define_discussion_vars + + render 'show' + end format.json { render json: { html: view_to_html_string('projects/merge_requests/show/_builds') } } end end def new - params[:merge_request] ||= ActionController::Parameters.new(source_project: @project) - @merge_request = MergeRequests::BuildService.new(project, current_user, merge_request_params).execute + build_merge_request @noteable = @merge_request @target_branches = if @merge_request.target_project @@ -119,7 +149,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @target_project = merge_request.target_project @source_project = merge_request.source_project @commits = @merge_request.compare_commits.reverse - @commit = @merge_request.last_commit + @commit = @merge_request.diff_head_commit @base_commit = @merge_request.diff_base_commit @diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare @diff_notes_disabled = true @@ -190,12 +220,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController def merge return access_denied! unless @merge_request.can_be_merged_by?(current_user) - unless @merge_request.mergeable? + # Disable the CI check if merge_when_build_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?) @status = :failed return end - if params[:sha] != @merge_request.source_sha + if params[:sha] != @merge_request.diff_head_sha @status = :sha_mismatch return end @@ -204,8 +236,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.update(merge_error: nil) - if params[:merge_when_build_succeeds].present? - if @merge_request.pipeline && @merge_request.pipeline.active? + if params[:merge_when_build_succeeds].present? + unless @merge_request.pipeline + @status = :failed + return + end + + if @merge_request.pipeline.active? MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params) .execute(@merge_request) @status = :merge_when_build_succeeds @@ -252,16 +289,16 @@ class Projects::MergeRequestsController < Projects::ApplicationController status ||= "preparing" else ci_service = @merge_request.source_project.ci_service - status = ci_service.commit_status(merge_request.last_commit.sha, merge_request.source_branch) if ci_service + status = ci_service.commit_status(merge_request.diff_head_sha, merge_request.source_branch) if ci_service if ci_service.respond_to?(:commit_coverage) - coverage = ci_service.commit_coverage(merge_request.last_commit.sha, merge_request.source_branch) + coverage = ci_service.commit_coverage(merge_request.diff_head_sha, merge_request.source_branch) end end response = { title: merge_request.title, - sha: merge_request.last_commit_short_sha, + sha: merge_request.diff_head_commit.short_id, status: status, coverage: coverage } @@ -286,10 +323,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController alias_method :issuable, :merge_request alias_method :awardable, :merge_request - def closes_issues - @closes_issues ||= @merge_request.closes_issues - end - def authorize_update_merge_request! return render_404 unless can?(current_user, :update_merge_request, @merge_request) end @@ -318,17 +351,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController end def define_show_vars - # Build a note object for comment form - @note = @project.notes.new(noteable: @merge_request) - @notes = @merge_request.mr_and_commit_notes.inc_author.fresh - @discussions = @notes.discussions @noteable = @merge_request - - # Get commits from repository - # or from cache if already merged - @commits = @merge_request.commits - - @merge_request_diff = @merge_request.merge_request_diff + @commits_count = @merge_request.commits.count @pipeline = @merge_request.pipeline @statuses = @pipeline.statuses if @pipeline @@ -339,10 +363,55 @@ class Projects::MergeRequestsController < Projects::ApplicationController end end + # Discussion tab data is rendered on html responses of actions + # :show, :diff, :commits, :builds. but not when request the data through AJAX + def define_discussion_vars + # Build a note object for comment form + @note = @project.notes.new(noteable: @noteable) + + @discussions = @noteable.mr_and_commit_notes. + inc_author_project_award_emoji. + fresh. + discussions + + # This is not executed lazily + @notes = Banzai::NoteRenderer.render( + @discussions.flatten, + @project, + current_user, + @path, + @project_wiki, + @ref + ) + end + def define_widget_vars @pipeline = @merge_request.pipeline @pipelines = [@pipeline].compact - closes_issues + end + + def define_commit_vars + @commit = @merge_request.diff_head_commit + @base_commit = @merge_request.diff_base_commit || @merge_request.likely_diff_base_commit + end + + def define_diff_comment_vars + @comments_target = { + noteable_type: 'MergeRequest', + noteable_id: @merge_request.id + } + + @use_legacy_diff_notes = !@merge_request.support_new_diff_notes? + @grouped_diff_notes = @merge_request.notes.grouped_diff_notes + + Banzai::NoteRenderer.render( + @grouped_diff_notes.values.flatten, + @project, + current_user, + @path, + @project_wiki, + @ref + ) end def invalid_mr @@ -368,4 +437,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController def ensure_ref_fetched @merge_request.ensure_ref_fetched end + + def merge_when_build_succeeds_active? + params[:merge_when_build_succeeds].present? && + @merge_request.pipeline && @merge_request.pipeline.active? + end + + def build_merge_request + params[:merge_request] ||= ActionController::Parameters.new(source_project: @project) + @merge_request = MergeRequests::BuildService.new(project, current_user, merge_request_params).execute + end end diff --git a/app/controllers/projects/network_controller.rb b/app/controllers/projects/network_controller.rb index b181c47baec..34318391dd9 100644 --- a/app/controllers/projects/network_controller.rb +++ b/app/controllers/projects/network_controller.rb @@ -7,7 +7,6 @@ class Projects::NetworkController < Projects::ApplicationController before_action :authorize_download_code! def show - @url = namespace_project_network_path(@project.namespace, @project, @ref, @options.merge(format: :json)) @commit_url = namespace_project_commit_path(@project.namespace, @project, 'ae45ca32').gsub("ae45ca32", "%s") diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb index 836f79ff080..3eacdbbd067 100644 --- a/app/controllers/projects/notes_controller.rb +++ b/app/controllers/projects/notes_controller.rb @@ -24,6 +24,10 @@ class Projects::NotesController < Projects::ApplicationController def create @note = Notes::CreateService.new(project, current_user, note_params).execute + if @note.is_a?(Note) + Banzai::NoteRenderer.render([@note], @project, current_user) + end + respond_to do |format| format.json { render json: note_json(@note) } format.html { redirect_back_or_default } @@ -33,6 +37,10 @@ class Projects::NotesController < Projects::ApplicationController def update @note = Notes::UpdateService.new(project, current_user, note_params).execute(note) + if @note.is_a?(Note) + Banzai::NoteRenderer.render([@note], @project, current_user) + end + respond_to do |format| format.json { render json: note_json(@note) } format.html { redirect_back_or_default } @@ -118,7 +126,9 @@ class Projects::NotesController < Projects::ApplicationController name: note.name } elsif note.valid? - { + Banzai::NoteRenderer.render([note], @project, current_user) + + attrs = { valid: true, id: note.id, discussion_id: note.discussion_id, @@ -128,6 +138,23 @@ class Projects::NotesController < Projects::ApplicationController discussion_html: note_to_discussion_html(note), discussion_with_diff_html: note_to_discussion_with_diff_html(note) } + + # The discussion_id is used to add the comment to the correct discussion + # element on the merge request page. Among other things, the discussion_id + # contains the sha of head commit of the merge request. + # When new commits are pushed into the merge request after the initial + # load of the merge request page, the discussion elements will still have + # the old discussion_ids, with the old head commit sha. The new comment, + # however, will have the new discussion_id with the new commit sha. + # To ensure that these new comments will still end up in the correct + # discussion element, we also send the original discussion_id, with the + # old commit sha, along, and fall back on this value when no discussion + # element with the new discussion_id could be found. + if note.new_diff_note? && note.position != note.original_position + attrs[:original_discussion_id] = note.original_discussion_id + end + + attrs else { valid: false, @@ -144,7 +171,7 @@ class Projects::NotesController < Projects::ApplicationController def note_params params.require(:note).permit( :note, :noteable, :noteable_id, :noteable_type, :project_id, - :attachment, :line_code, :commit_id, :type + :attachment, :line_code, :commit_id, :type, :position ) end diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index 127bd1a4318..487963fdcd7 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -54,6 +54,6 @@ class Projects::PipelinesController < Projects::ApplicationController end def commit - @commit ||= @pipeline.commit_data + @commit ||= @pipeline.commit end end diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 35d067cd029..3435a118964 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -6,7 +6,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController def index @project_members = @project.project_members - @project_members = @project_members.non_pending unless can?(current_user, :admin_project, @project) + @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) if params[:search].present? users = @project.users.search(params[:search]).to_a @@ -19,7 +19,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController if @group @group_members = @group.group_members - @group_members = @group_members.non_pending unless can?(current_user, :admin_group, @group) + @group_members = @group_members.non_invite unless can?(current_user, :admin_group, @group) if params[:search].present? users = @group.users.search(params[:search]).to_a @@ -29,6 +29,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController @group_members = @group_members.order('access_level DESC') end + @requesters = @project.requesters if can?(current_user, :admin_project, @project) + @project_member = @project.project_members.new @project_group_links = @project.project_group_links end @@ -48,11 +50,10 @@ class Projects::ProjectMembersController < Projects::ApplicationController end def destroy - @project_member = @project.project_members.find(params[:id]) - - return render_403 unless can?(current_user, :destroy_project_member, @project_member) + @project_member = @project.members.find_by(id: params[:id]) || + @project.requesters.find_by(id: params[:id]) - @project_member.destroy + Members::DestroyService.new(@project_member, current_user).execute respond_to do |format| format.html do @@ -98,8 +99,4 @@ class Projects::ProjectMembersController < Projects::ApplicationController # MembershipActions concern alias_method :membershipable, :project - - def cannot_leave? - current_user == @project.owner - end end diff --git a/app/controllers/projects/protected_branches_controller.rb b/app/controllers/projects/protected_branches_controller.rb index efa7bf14d0f..10dca47fded 100644 --- a/app/controllers/projects/protected_branches_controller.rb +++ b/app/controllers/projects/protected_branches_controller.rb @@ -2,12 +2,14 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController # Authorize before_action :require_non_empty_project before_action :authorize_admin_project! + before_action :load_protected_branch, only: [:show, :update, :destroy] layout "project_settings" def index - @branches = @project.protected_branches.to_a + @protected_branches = @project.protected_branches.order(:name).page(params[:page]) @protected_branch = @project.protected_branches.new + gon.push({ open_branches: @project.open_branches.map { |br| { text: br.name, id: br.name, title: br.name } } }) end def create @@ -16,26 +18,24 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController @project) end - def update - protected_branch = @project.protected_branches.find(params[:id]) - - if protected_branch && - protected_branch.update_attributes( - developers_can_push: params[:developers_can_push] - ) + def show + @matching_branches = @protected_branch.matching(@project.repository.branches) + end + def update + if @protected_branch && @protected_branch.update_attributes(protected_branch_params) respond_to do |format| - format.json { render json: protected_branch, status: :ok } + format.json { render json: @protected_branch, status: :ok } end else respond_to do |format| - format.json { render json: protected_branch.errors, status: :unprocessable_entity } + format.json { render json: @protected_branch.errors, status: :unprocessable_entity } end end end def destroy - @project.protected_branches.find(params[:id]).destroy + @protected_branch.destroy respond_to do |format| format.html { redirect_to namespace_project_protected_branches_path } @@ -45,7 +45,11 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController private + def load_protected_branch + @protected_branch = @project.protected_branches.find(params[:id]) + end + def protected_branch_params - params.require(:protected_branch).permit(:name, :developers_can_push) + params.require(:protected_branch).permit(:name, :developers_can_push, :developers_can_merge) end end diff --git a/app/controllers/projects/runner_projects_controller.rb b/app/controllers/projects/runner_projects_controller.rb index bedeb4a295c..8267b14941d 100644 --- a/app/controllers/projects/runner_projects_controller.rb +++ b/app/controllers/projects/runner_projects_controller.rb @@ -6,11 +6,12 @@ class Projects::RunnerProjectsController < Projects::ApplicationController def create @runner = Ci::Runner.find(params[:runner_project][:runner_id]) - return head(403) unless current_user.ci_authorized_runners.include?(@runner) + return head(403) unless can?(current_user, :assign_runner, @runner) path = runners_path(project) + runner_project = @runner.assign_to(project, current_user) - if @runner.assign_to(project, current_user) + if runner_project.persisted? redirect_to path else redirect_to path, alert: 'Failed adding runner to project' diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb index 0b4fa572501..53c36635efe 100644 --- a/app/controllers/projects/runners_controller.rb +++ b/app/controllers/projects/runners_controller.rb @@ -5,10 +5,9 @@ class Projects::RunnersController < Projects::ApplicationController layout 'project_settings' def index - @runners = project.runners.ordered - @specific_runners = current_user.ci_authorized_runners. - where.not(id: project.runners). - ordered.page(params[:page]).per(20) + @project_runners = project.runners.ordered + @assignable_runners = current_user.ci_authorized_runners. + assignable_for(project).ordered.page(params[:page]).per(20) @shared_runners = Ci::Runner.shared.active @shared_runners_count = @shared_runners.count(:all) end diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index 739681f4085..1b91882048e 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -45,8 +45,9 @@ class Projects::ServicesController < Projects::ApplicationController end def test - data = Gitlab::PushDataBuilder.build_sample(project, current_user) + data = @service.test_data(project, current_user) outcome = @service.test(data) + if outcome[:success] message = { notice: 'We sent a request to the provided URL' } else diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb index 6d2901a24a4..6d0a7ee1031 100644 --- a/app/controllers/projects/snippets_controller.rb +++ b/app/controllers/projects/snippets_controller.rb @@ -54,7 +54,7 @@ class Projects::SnippetsController < Projects::ApplicationController def show @note = @project.notes.new(noteable: @snippet) - @notes = @snippet.notes.fresh + @notes = Banzai::NoteRenderer.render(@snippet.notes.fresh, @project, current_user) @noteable = @snippet end diff --git a/app/controllers/projects/todos_controller.rb b/app/controllers/projects/todos_controller.rb index 23868d986e9..5685d0f4e7c 100644 --- a/app/controllers/projects/todos_controller.rb +++ b/app/controllers/projects/todos_controller.rb @@ -5,7 +5,7 @@ class Projects::TodosController < Projects::ApplicationController todo = TodoService.new.mark_todo(issuable, current_user) render json: { - count: current_user.todos_pending_count, + count: TodosFinder.new(current_user, state: :pending).execute.count, delete_path: dashboard_todo_path(todo) } end diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb index 7ec1e73b3be..607fe9c7fed 100644 --- a/app/controllers/projects/wikis_controller.rb +++ b/app/controllers/projects/wikis_controller.rb @@ -124,5 +124,4 @@ class Projects::WikisController < Projects::ApplicationController def wiki_params params[:wiki].slice(:title, :content, :format, :message) end - end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 8044c637825..4e5bcff9cf8 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,10 +1,11 @@ class ProjectsController < Projects::ApplicationController include ExtractsPath - before_action :authenticate_user!, except: [:show, :activity] + before_action :authenticate_user!, except: [:show, :activity, :refs] before_action :project, except: [:new, :create] before_action :repository, except: [:new, :create] - before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists? + before_action :assign_ref_vars, only: [:show], if: :repo_exists? + before_action :tree, only: [:show], if: [:repo_exists?, :project_view_files?] # Authorize before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping, :download_export, :export, :remove_export, :generate_new_export] @@ -52,11 +53,11 @@ class ProjectsController < Projects::ApplicationController notice: "Project '#{@project.name}' was successfully updated." ) end - format.js else format.html { render 'edit' } - format.js end + + format.js end end @@ -251,6 +252,24 @@ class ProjectsController < Projects::ApplicationController } end + def refs + options = { + 'Branches' => @repository.branch_names, + } + + unless @repository.tag_count.zero? + options['Tags'] = VersionSorter.rsort(@repository.tag_names) + end + + # If reference is commit id - we should add it to branch/tag selectbox + ref = Addressable::URI.unescape(params[:ref]) + if ref && options.flatten(2).exclude?(ref) && ref =~ /\A[0-9a-zA-Z]{6,52}\z/ + options['Commits'] = [ref] + end + + render json: options.to_json + end + private def determine_layout @@ -285,8 +304,18 @@ class ProjectsController < Projects::ApplicationController project.repository_exists? && !project.empty_repo? end - # Override get_id from ExtractsPath, which returns the branch and file path + def project_view_files? + current_user && current_user.project_view == 'files' + end + + # Override extract_ref from ExtractsPath, which returns the branch and file path # for the blob/tree, which in this case is just the root of the default branch. + # This way we avoid to access the repository.ref_names. + def extract_ref(_id) + [get_id, ''] + end + + # Override get_id from ExtractsPath in this case is just the root of the default branch. def get_id project.repository.root_ref end |