Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorDouwe Maan <douwe@selenight.nl>2016-07-29 01:57:42 +0300
committerDouwe Maan <douwe@selenight.nl>2016-07-29 01:57:42 +0300
commitce1843b7dea3b63cfced7800612098a766c68e13 (patch)
tree3340c4b5aca30047c2e22986c15f355bf3f845fe /app
parent8b1a2e4d0b635c6040cd7e4a7a5870ffae516cb0 (diff)
parentb9b0c0283a001010370741c2683e2fe400bf7599 (diff)
Merge branch 'master' into diff-line-comment-vuejs
# Conflicts: # db/schema.rb
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/importer_status.js8
-rw-r--r--app/assets/javascripts/users_select.js4
-rw-r--r--app/assets/stylesheets/pages/issues.scss30
-rw-r--r--app/controllers/admin/requests_profiles_controller.rb17
-rw-r--r--app/controllers/autocomplete_controller.rb1
-rw-r--r--app/controllers/explore/application_controller.rb2
-rw-r--r--app/controllers/help_controller.rb2
-rw-r--r--app/controllers/projects/branches_controller.rb1
-rw-r--r--app/controllers/projects/issues_controller.rb7
-rw-r--r--app/controllers/projects/merge_requests_controller.rb5
-rw-r--r--app/controllers/projects/tags_controller.rb3
-rw-r--r--app/controllers/search_controller.rb2
-rw-r--r--app/helpers/notes_helper.rb15
-rw-r--r--app/helpers/selects_helper.rb30
-rw-r--r--app/models/ability.rb12
-rw-r--r--app/models/ci/build.rb2
-rw-r--r--app/models/concerns/issuable.rb2
-rw-r--r--app/models/concerns/spammable.rb16
-rw-r--r--app/models/issue.rb1
-rw-r--r--app/models/legacy_diff_note.rb10
-rw-r--r--app/models/member.rb4
-rw-r--r--app/models/project.rb22
-rw-r--r--app/models/project_services/hipchat_service.rb21
-rw-r--r--app/models/project_team.rb72
-rw-r--r--app/models/repository.rb11
-rw-r--r--app/services/issues/create_service.rb14
-rw-r--r--app/services/projects/update_service.rb2
-rw-r--r--app/services/spam_check_service.rb38
-rw-r--r--app/views/admin/background_jobs/_head.html.haml4
-rw-r--r--app/views/admin/requests_profiles/index.html.haml26
-rw-r--r--app/views/import/bitbucket/status.html.haml4
-rw-r--r--app/views/import/fogbugz/status.html.haml3
-rw-r--r--app/views/import/github/status.html.haml3
-rw-r--r--app/views/import/gitlab/status.html.haml3
-rw-r--r--app/views/import/gitorious/status.html.haml3
-rw-r--r--app/views/import/google_code/status.html.haml3
-rw-r--r--app/views/layouts/nav/_admin.html.haml2
-rw-r--r--app/views/projects/branches/index.html.haml40
-rw-r--r--app/views/projects/builds/_sidebar.html.haml5
-rw-r--r--app/views/projects/ci/builds/_build.html.haml2
-rw-r--r--app/views/projects/diffs/_diffs.html.haml2
-rw-r--r--app/views/projects/edit.html.haml2
-rw-r--r--app/views/projects/graphs/ci/_build_times.haml7
-rw-r--r--app/views/projects/graphs/ci/_builds.haml7
-rw-r--r--app/views/projects/graphs/commits.html.haml4
-rw-r--r--app/views/projects/issues/_issue_by_email.html.haml27
-rw-r--r--app/views/projects/issues/index.html.haml7
-rw-r--r--app/views/projects/update.js.haml2
-rw-r--r--app/views/shared/icons/_icon_status_cancel.svg14
-rw-r--r--app/views/shared/icons/_icon_status_failed.svg14
-rw-r--r--app/views/shared/icons/_icon_status_pending.svg15
-rw-r--r--app/views/shared/icons/_icon_status_running.svg14
-rw-r--r--app/views/shared/icons/_icon_status_success.svg17
-rw-r--r--app/views/shared/icons/_icon_status_warning.svg17
-rw-r--r--app/workers/email_receiver_worker.rb54
-rw-r--r--app/workers/repository_fork_worker.rb5
-rw-r--r--app/workers/requests_profiles_worker.rb9
57 files changed, 469 insertions, 200 deletions
diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js
index 55b6f132bab..0f840821f53 100644
--- a/app/assets/javascripts/importer_status.js
+++ b/app/assets/javascripts/importer_status.js
@@ -66,4 +66,12 @@
})();
+ $(function() {
+ if ($('.js-importer-status').length) {
+ var jobsImportPath = $('.js-importer-status').data('jobs-import-path');
+ var importPath = $('.js-importer-status').data('import-path');
+
+ new ImporterStatus(jobsImportPath, importPath);
+ }
+ });
}).call(this);
diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js
index 64a29d36cdf..4af2a214e12 100644
--- a/app/assets/javascripts/users_select.js
+++ b/app/assets/javascripts/users_select.js
@@ -189,6 +189,7 @@
_this.groupId = $(select).data('group-id');
_this.showCurrentUser = $(select).data('current-user');
_this.authorId = $(select).data('author-id');
+ _this.skipUsers = $(select).data('skip-users');
showNullUser = $(select).data('null-user');
showAnyUser = $(select).data('any-user');
showEmailUser = $(select).data('email-user');
@@ -320,7 +321,8 @@
project_id: this.projectId,
group_id: this.groupId,
current_user: this.showCurrentUser,
- author_id: this.authorId
+ author_id: this.authorId,
+ skip_users: this.skipUsers
},
dataType: "json"
}).done(function(users) {
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index ee3b2d2b801..dfe1e3075da 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -99,3 +99,33 @@ form.edit-issue {
.issue-form .select2-container {
width: 250px !important;
}
+
+.issues-footer {
+ padding-top: $gl-padding;
+ padding-bottom: 37px;
+}
+
+.issue-email-modal-btn {
+ padding: 0;
+ color: $gl-link-color;
+ background-color: transparent;
+ border: 0;
+ outline: 0;
+
+ &:hover {
+ text-decoration: underline;
+ }
+}
+
+.email-modal-input-group {
+ margin-bottom: 10px;
+
+ .form-control {
+ background-color: $white-light;
+ }
+
+ .btn {
+ background-color: $background-color;
+ border: 1px solid $border-gray-light;
+ }
+}
diff --git a/app/controllers/admin/requests_profiles_controller.rb b/app/controllers/admin/requests_profiles_controller.rb
new file mode 100644
index 00000000000..a478176e138
--- /dev/null
+++ b/app/controllers/admin/requests_profiles_controller.rb
@@ -0,0 +1,17 @@
+class Admin::RequestsProfilesController < Admin::ApplicationController
+ def index
+ @profile_token = Gitlab::RequestProfiler.profile_token
+ @profiles = Gitlab::RequestProfiler::Profile.all.group_by(&:request_path)
+ end
+
+ def show
+ clean_name = Rack::Utils.clean_path_info(params[:name])
+ profile = Gitlab::RequestProfiler::Profile.find(clean_name)
+
+ if profile
+ render text: profile.content
+ else
+ redirect_to admin_requests_profiles_path, alert: 'Profile not found'
+ end
+ end
+end
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index c89678cf2d8..d828d163c28 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -5,6 +5,7 @@ class AutocompleteController < ApplicationController
def users
@users ||= User.none
@users = @users.search(params[:search]) if params[:search].present?
+ @users = @users.where.not(id: params[:skip_users]) if params[:skip_users].present?
@users = @users.active
@users = @users.reorder(:name)
@users = @users.page(params[:page])
diff --git a/app/controllers/explore/application_controller.rb b/app/controllers/explore/application_controller.rb
index 461fc059a3c..a1ab8b99048 100644
--- a/app/controllers/explore/application_controller.rb
+++ b/app/controllers/explore/application_controller.rb
@@ -1,5 +1,5 @@
class Explore::ApplicationController < ApplicationController
- skip_before_action :authenticate_user!, :reject_blocked
+ skip_before_action :authenticate_user!, :reject_blocked!
layout 'explore'
end
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index f7b44099b78..4eca278599f 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -1,5 +1,5 @@
class HelpController < ApplicationController
- skip_before_action :authenticate_user!, :reject_blocked
+ skip_before_action :authenticate_user!, :reject_blocked!
layout 'help'
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 6126acccaab..e926043f3eb 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -6,6 +6,7 @@ class Projects::BranchesController < Projects::ApplicationController
before_action :authorize_push_code!, only: [:new, :create, :destroy]
def index
+ @sort = params[:sort].presence || 'name'
@branches = BranchesFinder.new(@repository, params).execute
@branches = Kaminari.paginate_array(@branches).page(params[:page])
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index fa663c9bda4..3c6f29ac0ba 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -1,4 +1,5 @@
class Projects::IssuesController < Projects::ApplicationController
+ include NotesHelper
include ToggleSubscriptionAction
include IssuableActions
include ToggleAwardEmoji
@@ -70,6 +71,8 @@ class Projects::IssuesController < Projects::ApplicationController
@note = @project.notes.new(noteable: @issue)
@noteable = @issue
+ preload_max_access_for_authors(@notes, @project)
+
respond_to do |format|
format.html
format.json do
@@ -79,7 +82,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def create
- @issue = Issues::CreateService.new(project, current_user, issue_params).execute
+ @issue = Issues::CreateService.new(project, current_user, issue_params.merge(request: request)).execute
respond_to do |format|
format.html do
@@ -89,7 +92,7 @@ class Projects::IssuesController < Projects::ApplicationController
render :new
end
end
- format.js do |format|
+ format.js do
@link = @issue.attachment.url.to_js
end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 72ab7cff90c..b162384d44d 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -3,6 +3,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
include DiffForPath
include DiffHelper
include IssuableActions
+ include NotesHelper
include ToggleAwardEmoji
before_action :module_enabled
@@ -382,6 +383,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@project_wiki,
@ref
)
+
+ preload_max_access_for_authors(@notes, @project)
end
def define_widget_vars
@@ -401,7 +404,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
}
@use_legacy_diff_notes = !@merge_request.support_new_diff_notes?
- @grouped_diff_discussions = @merge_request.notes.grouped_diff_discussions
+ @grouped_diff_discussions = @merge_request.notes.inc_author_project_award_emoji.grouped_diff_discussions
Banzai::NoteRenderer.render(
@grouped_diff_discussions.values.flat_map(&:notes),
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 6dc495247c8..8592579abbd 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -10,11 +10,12 @@ class Projects::TagsController < Projects::ApplicationController
@tags = @repository.tags_sorted_by(@sort)
@tags = Kaminari.paginate_array(@tags).page(params[:page])
- @releases = project.releases.where(tag: @tags)
+ @releases = project.releases.where(tag: @tags.map(&:name))
end
def show
@tag = @repository.find_tag(params[:id])
+
@release = @project.releases.find_or_initialize_by(tag: @tag.name)
@commit = @repository.commit(@tag.target)
end
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 69c92d2bed2..61517d21f9f 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -1,5 +1,5 @@
class SearchController < ApplicationController
- skip_before_action :authenticate_user!, :reject_blocked
+ skip_before_action :authenticate_user!, :reject_blocked!
include SearchHelper
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 87bf84adad1..9d9b0dba57f 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -7,7 +7,7 @@ module NotesHelper
end
def note_editable?(note)
- note.editable? && can?(current_user, :admin_note, note)
+ Ability.can_edit_note?(current_user, note)
end
def noteable_json(noteable)
@@ -85,14 +85,13 @@ module NotesHelper
data: data, title: 'Add a reply'
end
- def note_max_access_for_user(note)
- @max_access_by_user_id ||= Hash.new do |hash, key|
- project = key[:project]
- hash[key] = project.team.human_max_access(key[:user_id])
- end
+ def preload_max_access_for_authors(notes, project)
+ user_ids = notes.map(&:author_id)
+ project.team.max_member_access_for_user_ids(user_ids)
+ end
- full_key = { project: note.project, user_id: note.author_id }
- @max_access_by_user_id[full_key]
+ def note_max_access_for_user(note)
+ note.project.team.human_max_access(note.author_id)
end
def discussion_diff_path(discussion)
diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb
index bb395e37884..5f27e33c6ad 100644
--- a/app/helpers/selects_helper.rb
+++ b/app/helpers/selects_helper.rb
@@ -5,21 +5,9 @@ module SelectsHelper
css_class << "skip_ldap " if opts[:skip_ldap]
css_class << (opts[:class] || '')
value = opts[:selected] || ''
-
- first_user = opts[:first_user] && current_user ? current_user.username : false
-
html = {
class: css_class,
- data: {
- placeholder: opts[:placeholder] || 'Search for a user',
- null_user: opts[:null_user] || false,
- any_user: opts[:any_user] || false,
- email_user: opts[:email_user] || false,
- first_user: first_user,
- current_user: opts[:current_user] || false,
- "push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
- author_id: opts[:author_id] || ''
- }
+ data: users_select_data_attributes(opts)
}
unless opts[:scope] == :all
@@ -68,4 +56,20 @@ module SelectsHelper
hidden_field_tag(id, value, class: css_class)
end
+
+ private
+
+ def users_select_data_attributes(opts)
+ {
+ placeholder: opts[:placeholder] || 'Search for a user',
+ null_user: opts[:null_user] || false,
+ any_user: opts[:any_user] || false,
+ email_user: opts[:email_user] || false,
+ first_user: opts[:first_user] && current_user ? current_user.username : false,
+ current_user: opts[:current_user] || false,
+ "push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
+ author_id: opts[:author_id] || '',
+ skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil,
+ }
+ end
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index ac3bf441c32..5075076c27b 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -389,6 +389,18 @@ class Ability
GroupProjectsFinder.new(group).execute(user).any?
end
+ def can_edit_note?(user, note)
+ return false if !note.editable? || !user.present?
+ return true if note.author == user || user.admin?
+
+ if note.project
+ max_access_level = note.project.team.max_member_access(user.id)
+ max_access_level >= Gitlab::Access::MASTER
+ else
+ false
+ end
+ end
+
def namespace_abilities(user, namespace)
rules = []
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index cbfa14e81f1..aac78d75f57 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -331,7 +331,7 @@ module Ci
end
def valid_token?(token)
- project.valid_runners_token? token
+ project.valid_runners_token?(token)
end
def has_tags?
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index acb6f5a2998..cbae1cd439b 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -17,7 +17,7 @@ module Issuable
belongs_to :assignee, class_name: "User"
belongs_to :updated_by, class_name: "User"
belongs_to :milestone
- has_many :notes, as: :noteable, dependent: :destroy do
+ has_many :notes, as: :noteable, inverse_of: :noteable, dependent: :destroy do
def authors_loaded?
# We check first if we're loaded to not load unnecessarily.
loaded? && to_a.all? { |note| note.association(:author).loaded? }
diff --git a/app/models/concerns/spammable.rb b/app/models/concerns/spammable.rb
new file mode 100644
index 00000000000..3b8e6df2da9
--- /dev/null
+++ b/app/models/concerns/spammable.rb
@@ -0,0 +1,16 @@
+module Spammable
+ extend ActiveSupport::Concern
+
+ included do
+ attr_accessor :spam
+ after_validation :check_for_spam, on: :create
+ end
+
+ def spam?
+ @spam
+ end
+
+ def check_for_spam
+ self.errors.add(:base, "Your #{self.class.name.underscore} has been recognized as spam and has been discarded.") if spam?
+ end
+end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 60af8c15340..d9428ebc9fb 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -6,6 +6,7 @@ class Issue < ActiveRecord::Base
include Referable
include Sortable
include Taskable
+ include Spammable
DueDateStruct = Struct.new(:title, :name).freeze
NoDueDate = DueDateStruct.new('No Due Date', '0').freeze
diff --git a/app/models/legacy_diff_note.rb b/app/models/legacy_diff_note.rb
index 7bff9f4f052..bbb9f2346eb 100644
--- a/app/models/legacy_diff_note.rb
+++ b/app/models/legacy_diff_note.rb
@@ -25,6 +25,14 @@ class LegacyDiffNote < Note
@discussion_id ||= Digest::SHA1.hexdigest(self.class.build_discussion_id(noteable_type, noteable_id || commit_id, line_code))
end
+ def project_repository
+ if RequestStore.active?
+ RequestStore.fetch("project:#{project_id}:repository") { self.project.repository }
+ else
+ self.project.repository
+ end
+ end
+
def diff_file_hash
line_code.split('_')[0] if line_code
end
@@ -34,7 +42,7 @@ class LegacyDiffNote < Note
end
def diff_file
- @diff_file ||= Gitlab::Diff::File.new(diff, repository: self.project.repository) if diff
+ @diff_file ||= Gitlab::Diff::File.new(diff, repository: project_repository) if diff
end
def diff_line
diff --git a/app/models/member.rb b/app/models/member.rb
index 44db3d977fa..24ab1276ee9 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -53,6 +53,10 @@ class Member < ActiveRecord::Base
default_value_for :notification_level, NotificationSetting.levels[:global]
class << self
+ def access_for_user_ids(user_ids)
+ where(user_id: user_ids).has_access.pluck(:user_id, :access_level).to_h
+ end
+
def find_by_invite_token(invite_token)
invite_token = Devise.token_generator.digest(self, :invite_token, invite_token)
find_by(invite_token: invite_token)
diff --git a/app/models/project.rb b/app/models/project.rb
index 023b1dc3725..dc44a757b4b 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -451,7 +451,9 @@ class Project < ActiveRecord::Base
def add_import_job
if forked?
- job_id = RepositoryForkWorker.perform_async(self.id, forked_from_project.path_with_namespace, self.namespace.path)
+ job_id = RepositoryForkWorker.perform_async(id, forked_from_project.repository_storage_path,
+ forked_from_project.path_with_namespace,
+ self.namespace.path)
else
job_id = RepositoryImportWorker.perform_async(self.id)
end
@@ -584,7 +586,11 @@ class Project < ActiveRecord::Base
end
def to_param
- path
+ if persisted? && errors.include?(:path)
+ path_was
+ else
+ path
+ end
end
def to_reference(_from_project = nil)
@@ -599,6 +605,13 @@ class Project < ActiveRecord::Base
web_url.split('://')[1]
end
+ def new_issue_address(author)
+ if Gitlab::IncomingEmail.enabled? && author
+ Gitlab::IncomingEmail.reply_address(
+ "#{path_with_namespace}+#{author.authentication_token}")
+ end
+ end
+
def build_commit_note(commit)
notes.new(commit_id: commit.id, noteable_type: 'Commit')
end
@@ -1151,7 +1164,10 @@ class Project < ActiveRecord::Base
def schedule_delete!(user_id, params)
# Queue this task for after the commit, so once we mark pending_delete it will run
- run_after_commit { ProjectDestroyWorker.perform_async(id, user_id, params) }
+ run_after_commit do
+ job_id = ProjectDestroyWorker.perform_async(id, user_id, params)
+ Rails.logger.info("User #{user_id} scheduled destruction of project #{path_with_namespace} with job ID #{job_id}")
+ end
update_attribute(:pending_delete, true)
end
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index 23e5b16221b..d7c986c1a91 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -46,7 +46,7 @@ class HipchatService < Service
return unless supported_events.include?(data[:object_kind])
message = create_message(data)
return unless message.present?
- gate[room].send('GitLab', message, message_options)
+ gate[room].send('GitLab', message, message_options(data))
end
def test(data)
@@ -67,8 +67,8 @@ class HipchatService < Service
@gate ||= HipChat::Client.new(token, options)
end
- def message_options
- { notify: notify.present? && notify == '1', color: color || 'yellow' }
+ def message_options(data = nil)
+ { notify: notify.present? && notify == '1', color: message_color(data) }
end
def create_message(data)
@@ -240,6 +240,21 @@ class HipchatService < Service
"#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)"
end
+ def message_color(data)
+ build_status_color(data) || color || 'yellow'
+ end
+
+ def build_status_color(data)
+ return unless data && data[:object_kind] == 'build'
+
+ case data[:commit][:status]
+ when 'success'
+ 'green'
+ else
+ 'red'
+ end
+ end
+
def project_name
project.name_with_namespace.gsub(/\s/, '')
end
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 9d312a53790..fdfaf052730 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -132,39 +132,63 @@ class ProjectTeam
Gitlab::Access.options_with_owner.key(max_member_access(user_id))
end
- # This method assumes project and group members are eager loaded for optimal
- # performance.
- def max_member_access(user_id)
- access = []
+ # Determine the maximum access level for a group of users in bulk.
+ #
+ # Returns a Hash mapping user ID -> maximum access level.
+ def max_member_access_for_user_ids(user_ids)
+ user_ids = user_ids.uniq
+ key = "max_member_access:#{project.id}"
+ RequestStore.store[key] ||= {}
+ access = RequestStore.store[key]
- access += project.members.where(user_id: user_id).has_access.pluck(:access_level)
+ # Lookup only the IDs we need
+ user_ids = user_ids - access.keys
- if group
- access += group.members.where(user_id: user_id).has_access.pluck(:access_level)
- end
+ if user_ids.present?
+ user_ids.each { |id| access[id] = Gitlab::Access::NO_ACCESS }
- if project.invited_groups.any? && project.allowed_to_share_with_group?
- access << max_invited_level(user_id)
+ member_access = project.members.access_for_user_ids(user_ids)
+ merge_max!(access, member_access)
+
+ if group
+ group_access = group.members.access_for_user_ids(user_ids)
+ merge_max!(access, group_access)
+ end
+
+ # Each group produces a list of maximum access level per user. We take the
+ # max of the values produced by each group.
+ if project.invited_groups.any? && project.allowed_to_share_with_group?
+ project.project_group_links.each do |group_link|
+ invited_access = max_invited_level_for_users(group_link, user_ids)
+ merge_max!(access, invited_access)
+ end
+ end
end
- access.compact.max
+ access
+ end
+
+ def max_member_access(user_id)
+ max_member_access_for_user_ids([user_id])[user_id]
end
private
- def max_invited_level(user_id)
- project.project_group_links.map do |group_link|
- invited_group = group_link.group
- access = invited_group.group_members.find_by(user_id: user_id).try(:access_field)
+ # For a given group, return the maximum access level for the user. This is the min of
+ # the invited access level of the group and the access level of the user within the group.
+ # For example, if the group has been given DEVELOPER access but the member has MASTER access,
+ # the user should receive only DEVELOPER access.
+ def max_invited_level_for_users(group_link, user_ids)
+ invited_group = group_link.group
+ capped_access_level = group_link.group_access
+ access = invited_group.group_members.access_for_user_ids(user_ids)
- # If group member has higher access level we should restrict it
- # to max allowed access level
- if access && access > group_link.group_access
- access = group_link.group_access
- end
+ # If the user is not in the list, assume he/she does not have access
+ missing_users = user_ids - access.keys
+ missing_users.each { |id| access[id] = Gitlab::Access::NO_ACCESS }
- access
- end.compact.max
+ # Cap the maximum access by the invited level access
+ access.each { |key, value| access[key] = [value, capped_access_level].min }
end
def fetch_members(level = nil)
@@ -215,4 +239,8 @@ class ProjectTeam
def group
project.group
end
+
+ def merge_max!(first_hash, second_hash)
+ first_hash.merge!(second_hash) { |_key, old, new| old > new ? old : new }
+ end
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index e9d5f4c91f8..af65e5b20ec 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -211,6 +211,9 @@ class Repository
rugged.references.create(keep_around_ref_name(sha), sha, force: true)
rescue Rugged::ReferenceError => ex
Rails.logger.error "Unable to create keep-around reference for repository #{path}: #{ex}"
+ rescue Rugged::OSError => ex
+ raise unless ex.message =~ /Failed to create locked file/ && ex.message =~ /File exists/
+ Rails.logger.error "Unable to create keep-around reference for repository #{path}: #{ex}"
end
end
@@ -612,11 +615,11 @@ class Repository
case value
when 'name'
branches.sort_by(&:name)
- when 'recently_updated'
+ when 'updated_desc'
branches.sort do |a, b|
commit(b.target).committed_date <=> commit(a.target).committed_date
end
- when 'last_updated'
+ when 'updated_asc'
branches.sort do |a, b|
commit(a.target).committed_date <=> commit(b.target).committed_date
end
@@ -985,6 +988,10 @@ class Repository
if was_empty || !target_branch
# Create branch
rugged.references.create(ref, newrev)
+
+ # If repo was empty expire cache
+ after_create if was_empty
+ after_create_branch
else
# Update head
current_head = find_branch(branch).target
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index e63e1af8766..5e2de2ccf64 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -2,10 +2,14 @@ module Issues
class CreateService < Issues::BaseService
def execute
filter_params
- label_params = params[:label_ids]
- issue = project.issues.new(params.except(:label_ids))
+ label_params = params.delete(:label_ids)
+ request = params.delete(:request)
+ api = params.delete(:api)
+ issue = project.issues.new(params)
issue.author = params[:author] || current_user
+ issue.spam = spam_check_service.execute(request, api)
+
if issue.save
issue.update_attributes(label_ids: label_params)
notification_service.new_issue(issue, current_user)
@@ -17,5 +21,11 @@ module Issues
issue
end
+
+ private
+
+ def spam_check_service
+ SpamCheckService.new(project, current_user, params)
+ end
end
end
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index f06311511cc..921ca6748d3 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -3,7 +3,7 @@ module Projects
def execute
# check that user is allowed to set specified visibility_level
new_visibility = params[:visibility_level]
-
+
if new_visibility && new_visibility.to_i != project.visibility_level
unless can?(current_user, :change_visibility_level, project) &&
Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
diff --git a/app/services/spam_check_service.rb b/app/services/spam_check_service.rb
new file mode 100644
index 00000000000..7c3e692bde9
--- /dev/null
+++ b/app/services/spam_check_service.rb
@@ -0,0 +1,38 @@
+class SpamCheckService < BaseService
+ include Gitlab::AkismetHelper
+
+ attr_accessor :request, :api
+
+ def execute(request, api)
+ @request, @api = request, api
+ return false unless request || check_for_spam?(project)
+ return false unless is_spam?(request.env, current_user, text)
+
+ create_spam_log
+
+ true
+ end
+
+ private
+
+ def text
+ [params[:title], params[:description]].reject(&:blank?).join("\n")
+ end
+
+ def spam_log_attrs
+ {
+ user_id: current_user.id,
+ project_id: project.id,
+ title: params[:title],
+ description: params[:description],
+ source_ip: client_ip(request.env),
+ user_agent: user_agent(request.env),
+ noteable_type: 'Issue',
+ via_api: api
+ }
+ end
+
+ def create_spam_log
+ CreateSpamLogService.new(project, current_user, spam_log_attrs).execute
+ end
+end
diff --git a/app/views/admin/background_jobs/_head.html.haml b/app/views/admin/background_jobs/_head.html.haml
index 9d722bd7382..89d7a40d6b0 100644
--- a/app/views/admin/background_jobs/_head.html.haml
+++ b/app/views/admin/background_jobs/_head.html.haml
@@ -16,3 +16,7 @@
= link_to admin_health_check_path, title: 'Health Check' do
%span
Health Check
+ = nav_link(controller: :requests_profiles) do
+ = link_to admin_requests_profiles_path, title: 'Requests Profiles' do
+ %span
+ Requests Profiles
diff --git a/app/views/admin/requests_profiles/index.html.haml b/app/views/admin/requests_profiles/index.html.haml
new file mode 100644
index 00000000000..ae918086a57
--- /dev/null
+++ b/app/views/admin/requests_profiles/index.html.haml
@@ -0,0 +1,26 @@
+- @no_container = true
+- page_title 'Requests Profiles'
+= render 'admin/background_jobs/head'
+
+%div{ class: container_class }
+ %h3.page-title
+ = page_title
+
+ .bs-callout.clearfix
+ Pass the header
+ %code X-Profile-Token: #{@profile_token}
+ to profile the request
+
+ - if @profiles.present?
+ .prepend-top-default
+ - @profiles.each do |path, profiles|
+ .panel.panel-default.panel-small
+ .panel-heading
+ %code= path
+ %ul.content-list
+ - profiles.each do |profile|
+ %li
+ = link_to profile.time.to_s(:long), admin_requests_profile_path(profile), data: {no_turbolink: true}
+ - else
+ %p
+ No profiles found
diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml
index 6e993e58f0d..15dd98077c8 100644
--- a/app/views/import/bitbucket/status.html.haml
+++ b/app/views/import/bitbucket/status.html.haml
@@ -74,6 +74,4 @@
= link_to "import flow", status_import_bitbucket_path, "data-no-turbolink" => "true"
again.
-
-:javascript
- new ImporterStatus("#{jobs_import_bitbucket_path}", "#{import_bitbucket_path}");
+.js-importer-status{ data: { jobs_import_path: "#{jobs_import_bitbucket_path}", import_path: "#{import_bitbucket_path}" } }
diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml
index d3d3c595c17..c8a6fa1aa9e 100644
--- a/app/views/import/fogbugz/status.html.haml
+++ b/app/views/import/fogbugz/status.html.haml
@@ -56,5 +56,4 @@
Import
= icon("spinner spin", class: "loading-icon")
-:javascript
- new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}");
+.js-importer-status{ data: { jobs_import_path: "#{jobs_import_fogbugz_path}", import_path: "#{import_fogbugz_path}" } }
diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml
index 7486b1423e2..deaaf9af875 100644
--- a/app/views/import/github/status.html.haml
+++ b/app/views/import/github/status.html.haml
@@ -55,5 +55,4 @@
Import
= icon("spinner spin", class: "loading-icon")
-:javascript
- new ImporterStatus("#{jobs_import_github_path}", "#{import_github_path}");
+.js-importer-status{ data: { jobs_import_path: "#{jobs_import_github_path}", import_path: "#{import_github_path}" } }
diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml
index aedb8468eca..fcfc6fd37f4 100644
--- a/app/views/import/gitlab/status.html.haml
+++ b/app/views/import/gitlab/status.html.haml
@@ -51,5 +51,4 @@
Import
= icon("spinner spin", class: "loading-icon")
-:javascript
- new ImporterStatus("#{jobs_import_gitlab_path}", "#{import_gitlab_path}");
+.js-importer-status{ data: { jobs_import_path: "#{jobs_import_gitlab_path}", import_path: "#{import_gitlab_path}" } }
diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml
index 267eee4f262..ed3afb0ce33 100644
--- a/app/views/import/gitorious/status.html.haml
+++ b/app/views/import/gitorious/status.html.haml
@@ -51,5 +51,4 @@
Import
= icon("spinner spin", class: "loading-icon")
-:javascript
- new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}");
+.js-importer-status{ data: { jobs_import_path: "#{jobs_import_gitorious_path}", import_path: "#{import_gitorious_path}" } }
diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml
index 5ada6b174eb..e79f122940a 100644
--- a/app/views/import/google_code/status.html.haml
+++ b/app/views/import/google_code/status.html.haml
@@ -77,5 +77,4 @@
= link_to "import flow", new_import_google_code_path
again.
-:javascript
- new ImporterStatus("#{jobs_import_google_code_path}", "#{import_google_code_path}");
+.js-importer-status{ data: { jobs_import_path: "#{jobs_import_google_code_path}", import_path: "#{import_google_code_path}" } }
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
index 5ee8772882e..ac04f57e217 100644
--- a/app/views/layouts/nav/_admin.html.haml
+++ b/app/views/layouts/nav/_admin.html.haml
@@ -9,7 +9,7 @@
= link_to admin_root_path, title: 'Overview', class: 'shortcuts-tree' do
%span
Overview
- = nav_link(controller: %w(system_info background_jobs logs health_check)) do
+ = nav_link(controller: %w(system_info background_jobs logs health_check requests_profiles)) do
= link_to admin_system_info_path, title: 'Monitoring' do
%span
Monitoring
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 6f806e3ce53..e889f29c816 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -7,28 +7,28 @@
.nav-text
Protected branches can be managed in project settings
- - if can? current_user, :push_code, @project
- .nav-controls
- = form_tag(filter_branches_path, method: :get) do
- = search_field_tag :search, params[:search], { placeholder: 'Filter by branch name', id: 'branch-search', class: 'form-control search-text-input input-short', spellcheck: false }
- .dropdown.inline
- %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
- %span.light
- - if params[:sort].present?
- = params[:sort].humanize
- - else
- Name
- %b.caret
- %ul.dropdown-menu.dropdown-menu-align-right
- %li
- = link_to filter_branches_path(sort: nil) do
- = sort_title_name
- = link_to filter_branches_path(sort: 'recently_updated') do
- = sort_title_recently_updated
- = link_to filter_branches_path(sort: 'last_updated') do
- = sort_title_oldest_updated
+ .nav-controls
+ = form_tag(filter_branches_path, method: :get) do
+ = search_field_tag :search, params[:search], { placeholder: 'Filter by branch name', id: 'branch-search', class: 'form-control search-text-input input-short', spellcheck: false }
+
+ .dropdown.inline
+ %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
+ %span.light
+ = projects_sort_options_hash[@sort]
+ %b.caret
+ %ul.dropdown-menu.dropdown-menu-align-right
+ %li
+ = link_to filter_branches_path(sort: sort_value_name) do
+ = sort_title_name
+ = link_to filter_branches_path(sort: sort_value_recently_updated) do
+ = sort_title_recently_updated
+ = link_to filter_branches_path(sort: sort_value_oldest_updated) do
+ = sort_title_oldest_updated
+
+ - if can? current_user, :push_code, @project
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
New branch
+
- if @branches.any?
%ul.content-list.all-branches
- @branches.each do |branch|
diff --git a/app/views/projects/builds/_sidebar.html.haml b/app/views/projects/builds/_sidebar.html.haml
index b89183c40dc..a8bc53c2849 100644
--- a/app/views/projects/builds/_sidebar.html.haml
+++ b/app/views/projects/builds/_sidebar.html.haml
@@ -88,8 +88,9 @@
%p
%span.build-light-text Variables:
- %code
- - @build.trigger_request.variables.each do |key, value|
+
+ - @build.trigger_request.variables.each do |key, value|
+ %code
#{key}=#{value}
.block
diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml
index a9fb3c58431..a3114771a42 100644
--- a/app/views/projects/ci/builds/_build.html.haml
+++ b/app/views/projects/ci/builds/_build.html.haml
@@ -22,6 +22,8 @@
- if defined?(ref) && ref
- if build.ref
+ .icon-container
+ = build.tag? ? icon('tag') : icon('code-fork')
= link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref), class: "monospace branch-name"
- else
.light none
diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml
index 8ae433b4823..4bf3ccace20 100644
--- a/app/views/projects/diffs/_diffs.html.haml
+++ b/app/views/projects/diffs/_diffs.html.haml
@@ -7,7 +7,7 @@
.content-block.oneline-block.files-changed
.inline-parallel-buttons
- if !expand_all_diffs? && diff_files.any? { |diff_file| diff_file.collapsed? }
- = link_to 'Expand all', url_for(params.merge(expand_all_diffs: 1, format: 'html')), class: 'btn btn-default'
+ = link_to 'Expand all', url_for(params.merge(expand_all_diffs: 1, format: nil)), class: 'btn btn-default'
- if show_whitespace_toggle
- if current_controller?(:commit)
= commit_diff_whitespace_link(@project, @commit, class: 'hidden-xs')
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 921155e970b..b282aa52b25 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -4,6 +4,7 @@
%h4.prepend-top-0
Project settings
.col-lg-9
+ .project-edit-errors
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit-project" }, authenticity_token: true do |f|
%fieldset.append-bottom-0
.form-group
@@ -190,6 +191,7 @@
%h4.prepend-top-0.warning-title
Rename repository
.col-lg-9
+ = render 'projects/errors'
= form_for([@project.namespace.becomes(Namespace), @project]) do |f|
.form-group.project_name_holder
= f.label :name, class: 'label-light' do
diff --git a/app/views/projects/graphs/ci/_build_times.haml b/app/views/projects/graphs/ci/_build_times.haml
index c58223fd39e..195f18afc76 100644
--- a/app/views/projects/graphs/ci/_build_times.haml
+++ b/app/views/projects/graphs/ci/_build_times.haml
@@ -19,4 +19,9 @@
]
}
var ctx = $("#build_timesChart").get(0).getContext("2d");
- new Chart(ctx).Bar(data,{"scaleOverlay": true, responsive: true, maintainAspectRatio: false});
+ var options = { scaleOverlay: true, responsive: true, maintainAspectRatio: false };
+ if (window.innerWidth < 768) {
+ // Scale fonts if window width lower than 768px (iPad portrait)
+ options.scaleFontSize = 8
+ }
+ new Chart(ctx).Bar(data, options);
diff --git a/app/views/projects/graphs/ci/_builds.haml b/app/views/projects/graphs/ci/_builds.haml
index 8fca07114fa..1fbf6ca2c1c 100644
--- a/app/views/projects/graphs/ci/_builds.haml
+++ b/app/views/projects/graphs/ci/_builds.haml
@@ -48,4 +48,9 @@
]
}
var ctx = $("##{scope}Chart").get(0).getContext("2d");
- new Chart(ctx).Line(data,{"scaleOverlay": true, responsive: true, maintainAspectRatio: false});
+ var options = { scaleOverlay: true, responsive: true, maintainAspectRatio: false };
+ if (window.innerWidth < 768) {
+ // Scale fonts if window width lower than 768px (iPad portrait)
+ options.scaleFontSize = 8
+ }
+ new Chart(ctx).Line(data, options);
diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml
index 65db8af494d..7e34a89f9ae 100644
--- a/app/views/projects/graphs/commits.html.haml
+++ b/app/views/projects/graphs/commits.html.haml
@@ -59,6 +59,10 @@
var container = $(selector).parent();
var generateChart = function() {
selector.attr('width', $(container).width());
+ if (window.innerWidth < 768) {
+ // Scale fonts if window width lower than 768px (iPad portrait)
+ options.scaleFontSize = 8
+ }
return new Chart(ctx).Bar(data, options);
};
// enabling auto-resizing
diff --git a/app/views/projects/issues/_issue_by_email.html.haml b/app/views/projects/issues/_issue_by_email.html.haml
new file mode 100644
index 00000000000..72669372497
--- /dev/null
+++ b/app/views/projects/issues/_issue_by_email.html.haml
@@ -0,0 +1,27 @@
+.issues-footer.text-center
+ %button.issue-email-modal-btn{ type: "button", data: { toggle: "modal", target: "#issue-email-modal" } }
+ Email a new issue to this project
+
+#issue-email-modal.modal.fade{ tabindex: "-1", role: "dialog" }
+ .modal-dialog{ role: "document" }
+ .modal-content
+ .modal-header
+ %button.close{ type: "button", data: { dismiss: "modal" }, aria: { label: "close" } }
+ %span{ aria: { hidden: "true" } }= icon("times")
+ %h4.modal-title
+ Create new issue by email
+ .modal-body
+ %p
+ Write an email to the below email address. (This is a private email address, so keep it secret.)
+ .email-modal-input-group.input-group
+ = text_field_tag :issue_email, email, class: "monospace js-select-on-focus form-control", readonly: true
+ .input-group-btn
+ = clipboard_button(clipboard_target: '#issue_email')
+ %p
+ Send an email to this address to create an issue.
+ %p
+ Use the subject line as the title of your issue.
+ %p
+ Use the message as the body of your issue (feel free to include some nice
+ = succeed ")." do
+ = link_to "Markdown", help_page_path('markdown', 'markdown')
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 7612fe3719a..d0edd2f22ec 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -1,5 +1,6 @@
- @no_container = true
- page_title "Issues"
+- new_issue_email = @project.new_issue_address(current_user)
= render "projects/issues/head"
= content_for :meta_tags do
@@ -23,7 +24,9 @@
= render 'shared/issuable/filter', type: :issues
.issues-holder
- = render "issues"
+ = render 'issues'
+ - if new_issue_email
+ = render 'issue_by_email', email: new_issue_email
- else
.blank-state.blank-state-welcome
%h2.blank-state-title.blank-state-welcome-title
@@ -40,3 +43,5 @@
- if can? current_user, :create_issue, @project
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: "btn btn-new", title: "New Issue", id: "new_issue_link" do
New Issue
+ - if new_issue_email
+ = render 'issue_by_email', email: new_issue_email
diff --git a/app/views/projects/update.js.haml b/app/views/projects/update.js.haml
index 7d9bd08385a..dcf1f767bf7 100644
--- a/app/views/projects/update.js.haml
+++ b/app/views/projects/update.js.haml
@@ -6,4 +6,4 @@
$(".project-edit-errors").html("#{escape_javascript(render('errors'))}");
$('.save-project-loader').hide();
$('.project-edit-container').show();
- $('.project-edit-content .btn-save').enable();
+ $('.edit-project .btn-save').enable();
diff --git a/app/views/shared/icons/_icon_status_cancel.svg b/app/views/shared/icons/_icon_status_cancel.svg
index 6a0bc1490c4..fd1ebbcbabd 100644
--- a/app/views/shared/icons/_icon_status_cancel.svg
+++ b/app/views/shared/icons/_icon_status_cancel.svg
@@ -1,12 +1,6 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <circle id="a" cx="7" cy="7" r="7"/>
- <mask id="b" width="14" height="14" x="0" y="0" fill="white">
- <use xlink:href="#a"/>
- </mask>
- </defs>
- <g fill="none" fill-rule="evenodd">
- <use stroke="#5C5C5C" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
- <rect width="10" height="1" x="2" y="6.5" fill="#5C5C5C" transform="rotate(45 7 7)" rx=".3"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+ <g fill="#5C5C5C" fill-rule="evenodd">
+ <path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
+ <rect width="8" height="2" x="3" y="6" transform="rotate(45 7 7)" rx=".5"/>
</g>
</svg>
diff --git a/app/views/shared/icons/_icon_status_failed.svg b/app/views/shared/icons/_icon_status_failed.svg
index c41ca18cae7..e56e0887416 100644
--- a/app/views/shared/icons/_icon_status_failed.svg
+++ b/app/views/shared/icons/_icon_status_failed.svg
@@ -1,12 +1,6 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <circle id="a" cx="7" cy="7" r="7"/>
- <mask id="b" width="14" height="14" x="0" y="0" fill="white">
- <use xlink:href="#a"/>
- </mask>
- </defs>
- <g fill="none" fill-rule="evenodd">
- <use stroke="#D22852" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
- <path fill="#D22852" d="M7.5,6.5 L7.5,4.30578971 C7.5,4.12531853 7.36809219,4 7.20537567,4 L6.79462433,4 C6.63904572,4 6.5,4.13690672 6.5,4.30578971 L6.5,6.5 L4.30578971,6.5 C4.12531853,6.5 4,6.63190781 4,6.79462433 L4,7.20537567 C4,7.36095428 4.13690672,7.5 4.30578971,7.5 L6.5,7.5 L6.5,9.69421029 C6.5,9.87468147 6.63190781,10 6.79462433,10 L7.20537567,10 C7.36095428,10 7.5,9.86309328 7.5,9.69421029 L7.5,7.5 L9.69421029,7.5 C9.87468147,7.5 10,7.36809219 10,7.20537567 L10,6.79462433 C10,6.63904572 9.86309328,6.5 9.69421029,6.5 L7.5,6.5 Z" transform="rotate(45 7 7)"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+ <g fill="#D22852" fill-rule="evenodd">
+ <path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
+ <path d="M7.72916667,6.27083333 L7.72916667,4.28939247 C7.72916667,4.12531853 7.59703895,4 7.43405116,4 L6.56594884,4 C6.40541585,4 6.27083333,4.12956542 6.27083333,4.28939247 L6.27083333,6.27083333 L4.28939247,6.27083333 C4.12531853,6.27083333 4,6.40296105 4,6.56594884 L4,7.43405116 C4,7.59458415 4.12956542,7.72916667 4.28939247,7.72916667 L6.27083333,7.72916667 L6.27083333,9.71060753 C6.27083333,9.87468147 6.40296105,10 6.56594884,10 L7.43405116,10 C7.59458415,10 7.72916667,9.87043458 7.72916667,9.71060753 L7.72916667,7.72916667 L9.71060753,7.72916667 C9.87468147,7.72916667 10,7.59703895 10,7.43405116 L10,6.56594884 C10,6.40541585 9.87043458,6.27083333 9.71060753,6.27083333 L7.72916667,6.27083333 Z" transform="rotate(-45 7 7)"/>
</g>
</svg>
diff --git a/app/views/shared/icons/_icon_status_pending.svg b/app/views/shared/icons/_icon_status_pending.svg
index 035cd8b4ccc..117f0367161 100644
--- a/app/views/shared/icons/_icon_status_pending.svg
+++ b/app/views/shared/icons/_icon_status_pending.svg
@@ -1,13 +1,6 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <circle id="a" cx="7" cy="7" r="7"/>
- <mask id="b" width="14" height="14" x="0" y="0" fill="white">
- <use xlink:href="#a"/>
- </mask>
- </defs>
- <g fill="none" fill-rule="evenodd">
- <use stroke="#E75E40" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
- <rect width="1" height="4" x="5" y="5" fill="#E75E40" rx=".3"/>
- <rect width="1" height="4" x="8" y="5" fill="#E75E40" rx=".3"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+ <g fill="#E75E40" fill-rule="evenodd">
+ <path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
+ <path d="M4.69999981,5.30065012 C4.69999981,5.13460564 4.83842754,5 5.00354719,5 L5.89645243,5 C6.06409702,5 6.19999981,5.13308716 6.19999981,5.30065012 L6.19999981,8.69934988 C6.19999981,8.86539436 6.06157207,9 5.89645243,9 L5.00354719,9 C4.8359026,9 4.69999981,8.86691284 4.69999981,8.69934988 L4.69999981,5.30065012 Z M7.69999981,5.30065012 C7.69999981,5.13460564 7.83842754,5 8.00354719,5 L8.89645243,5 C9.06409702,5 9.19999981,5.13308716 9.19999981,5.30065012 L9.19999981,8.69934988 C9.19999981,8.86539436 9.06157207,9 8.89645243,9 L8.00354719,9 C7.8359026,9 7.69999981,8.86691284 7.69999981,8.69934988 L7.69999981,5.30065012 Z"/>
</g>
</svg>
diff --git a/app/views/shared/icons/_icon_status_running.svg b/app/views/shared/icons/_icon_status_running.svg
index a48b3a25099..920d7952eb5 100644
--- a/app/views/shared/icons/_icon_status_running.svg
+++ b/app/views/shared/icons/_icon_status_running.svg
@@ -1,12 +1,6 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <circle id="a" cx="7" cy="7" r="7"/>
- <mask id="b" width="14" height="14" x="0" y="0" fill="white">
- <use xlink:href="#a"/>
- </mask>
- </defs>
- <g fill="none" fill-rule="evenodd">
- <use stroke="#2D9FD8" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
- <path fill="#2D9FD8" d="M7,3.00800862 C9.09023405,3.13960661 10.7448145,4.87657932 10.7448145,7 C10.7448145,9.209139 8.95395346,11 6.74481446,11 C5.4560962,11 4.30972054,10.3905589 3.57817301,9.44416214 L7,7 L7,3.00800862 Z"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+ <g fill="#2D9FD8" fill-rule="evenodd">
+ <path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
+ <path d="M7,3 C9.209139,3 11,4.790861 11,7 C11,9.209139 9.209139,11 7,11 C5.65802855,11 4.47040669,10.3391508 3.74481446,9.32513253 L7,7 L7,3 L7,3 Z"/>
</g>
</svg>
diff --git a/app/views/shared/icons/_icon_status_success.svg b/app/views/shared/icons/_icon_status_success.svg
index 260eab013a3..67b378b3571 100644
--- a/app/views/shared/icons/_icon_status_success.svg
+++ b/app/views/shared/icons/_icon_status_success.svg
@@ -1,15 +1,6 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <circle id="a" cx="7" cy="7" r="7"/>
- <mask id="b" width="14" height="14" x="0" y="0" fill="white">
- <use xlink:href="#a"/>
- </mask>
- </defs>
- <g fill="none" fill-rule="evenodd">
- <use stroke="#31AF64" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
- <g fill="#31AF64" transform="rotate(45 -.13 10.953)">
- <rect width="1" height="5" x="2" rx=".3"/>
- <rect width="3" height="1" y="4" rx=".3"/>
- </g>
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+ <g fill="#31AF64" fill-rule="evenodd">
+ <path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
+ <path d="M7.29166667,7.875 L5.54840803,7.875 C5.38293028,7.875 5.25,8.00712771 5.25,8.17011551 L5.25,9.03821782 C5.25,9.19875081 5.38360183,9.33333333 5.54840803,9.33333333 L8.24853534,9.33333333 C8.52035522,9.33333333 8.75,9.11228506 8.75,8.83960819 L8.75,8.46475969 L8.75,4.07392947 C8.75,3.92144267 8.61787229,3.79166667 8.45488449,3.79166667 L7.58678218,3.79166667 C7.42624919,3.79166667 7.29166667,3.91804003 7.29166667,4.07392947 L7.29166667,7.875 Z" transform="rotate(45 7 6.563)"/>
</g>
</svg>
diff --git a/app/views/shared/icons/_icon_status_warning.svg b/app/views/shared/icons/_icon_status_warning.svg
index d47e7a1c93f..d0ad4bd65b1 100644
--- a/app/views/shared/icons/_icon_status_warning.svg
+++ b/app/views/shared/icons/_icon_status_warning.svg
@@ -1,15 +1,6 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <circle id="a" cx="7" cy="7" r="7"/>
- <mask id="b" width="14" height="14" x="0" y="0" fill="white">
- <use xlink:href="#a"/>
- </mask>
- </defs>
- <g fill="none" fill-rule="evenodd">
- <g fill="#FF8A24" transform="translate(6 3)">
- <rect width="2" height="5" rx=".5"/>
- <rect width="2" height="2" y="6" rx=".5"/>
- </g>
- <use stroke="#FF8A24" stroke-width="2" mask="url(#b)" xlink:href="#a"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+ <g fill="#FF8A24" fill-rule="evenodd">
+ <path d="M12.5,7 C12.5,3.96243388 10.0375661,1.5 7,1.5 C3.96243388,1.5 1.5,3.96243388 1.5,7 C1.5,10.0375661 3.96243388,12.5 7,12.5 C10.0375661,12.5 12.5,10.0375661 12.5,7 Z M0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 C3.13400675,14 0,10.8659932 0,7 Z"/>
+ <path d="M6,3.49769878 C6,3.22282734 6.21403503,3 6.50468445,3 L7.49531555,3 C7.77404508,3 8,3.21484375 8,3.49769878 L8,7.50230122 C8,7.77717266 7.78596497,8 7.49531555,8 L6.50468445,8 C6.22595492,8 6,7.78515625 6,7.50230122 L6,3.49769878 Z M6,9.50468445 C6,9.22595492 6.21403503,9 6.50468445,9 L7.49531555,9 C7.77404508,9 8,9.21403503 8,9.50468445 L8,10.4953156 C8,10.7740451 7.78596497,11 7.49531555,11 L6.50468445,11 C6.22595492,11 6,10.785965 6,10.4953156 L6,9.50468445 Z"/>
</g>
</svg>
diff --git a/app/workers/email_receiver_worker.rb b/app/workers/email_receiver_worker.rb
index f2649e38eb3..842eebdea9e 100644
--- a/app/workers/email_receiver_worker.rb
+++ b/app/workers/email_receiver_worker.rb
@@ -21,31 +21,35 @@ class EmailReceiverWorker
return unless raw.present?
can_retry = false
- reason = nil
-
- case e
- when Gitlab::Email::Receiver::SentNotificationNotFoundError
- reason = "We couldn't figure out what the email is in reply to. Please create your comment through the web interface."
- when Gitlab::Email::Receiver::EmptyEmailError
- can_retry = true
- reason = "It appears that the email is blank. Make sure your reply is at the top of the email, we can't process inline replies."
- when Gitlab::Email::Receiver::AutoGeneratedEmailError
- reason = "The email was marked as 'auto generated', which we can't accept. Please create your comment through the web interface."
- when Gitlab::Email::Receiver::UserNotFoundError
- reason = "We couldn't figure out what user corresponds to the email. Please create your comment through the web interface."
- when Gitlab::Email::Receiver::UserBlockedError
- reason = "Your account has been blocked. If you believe this is in error, contact a staff member."
- when Gitlab::Email::Receiver::UserNotAuthorizedError
- reason = "You are not allowed to respond to the thread you are replying to. If you believe this is in error, contact a staff member."
- when Gitlab::Email::Receiver::NoteableNotFoundError
- reason = "The thread you are replying to no longer exists, perhaps it was deleted? If you believe this is in error, contact a staff member."
- when Gitlab::Email::Receiver::InvalidNoteError
- can_retry = true
- reason = e.message
- else
- return
+ reason =
+ case e
+ when Gitlab::Email::UnknownIncomingEmail
+ "We couldn't figure out what the email is for. Please create your issue or comment through the web interface."
+ when Gitlab::Email::SentNotificationNotFoundError
+ "We couldn't figure out what the email is in reply to. Please create your comment through the web interface."
+ when Gitlab::Email::ProjectNotFound
+ "We couldn't find the project. Please check if there's any typo."
+ when Gitlab::Email::EmptyEmailError
+ can_retry = true
+ "It appears that the email is blank. Make sure your reply is at the top of the email, we can't process inline replies."
+ when Gitlab::Email::AutoGeneratedEmailError
+ "The email was marked as 'auto generated', which we can't accept. Please create your comment through the web interface."
+ when Gitlab::Email::UserNotFoundError
+ "We couldn't figure out what user corresponds to the email. Please create your comment through the web interface."
+ when Gitlab::Email::UserBlockedError
+ "Your account has been blocked. If you believe this is in error, contact a staff member."
+ when Gitlab::Email::UserNotAuthorizedError
+ "You are not allowed to perform this action. If you believe this is in error, contact a staff member."
+ when Gitlab::Email::NoteableNotFoundError
+ "The thread you are replying to no longer exists, perhaps it was deleted? If you believe this is in error, contact a staff member."
+ when Gitlab::Email::InvalidNoteError,
+ Gitlab::Email::InvalidIssueError
+ can_retry = true
+ e.message
+ end
+
+ if reason
+ EmailRejectionMailer.rejection(reason, raw, can_retry).deliver_later
end
-
- EmailRejectionMailer.rejection(reason, raw, can_retry).deliver_later
end
end
diff --git a/app/workers/repository_fork_worker.rb b/app/workers/repository_fork_worker.rb
index f7604e48f83..d69d6037053 100644
--- a/app/workers/repository_fork_worker.rb
+++ b/app/workers/repository_fork_worker.rb
@@ -4,7 +4,7 @@ class RepositoryForkWorker
sidekiq_options queue: :gitlab_shell
- def perform(project_id, source_path, target_path)
+ def perform(project_id, forked_from_repository_storage_path, source_path, target_path)
project = Project.find_by_id(project_id)
unless project.present?
@@ -12,7 +12,8 @@ class RepositoryForkWorker
return
end
- result = gitlab_shell.fork_repository(project.repository_storage_path, source_path, target_path)
+ result = gitlab_shell.fork_repository(forked_from_repository_storage_path, source_path,
+ project.repository_storage_path, target_path)
unless result
logger.error("Unable to fork project #{project_id} for repository #{source_path} -> #{target_path}")
project.mark_import_as_failed('The project could not be forked.')
diff --git a/app/workers/requests_profiles_worker.rb b/app/workers/requests_profiles_worker.rb
new file mode 100644
index 00000000000..9dd228a2483
--- /dev/null
+++ b/app/workers/requests_profiles_worker.rb
@@ -0,0 +1,9 @@
+class RequestsProfilesWorker
+ include Sidekiq::Worker
+
+ sidekiq_options queue: :default
+
+ def perform
+ Gitlab::RequestProfiler.remove_all_profiles
+ end
+end