summaryrefslogtreecommitdiff
path: root/app/services
diff options
context:
space:
mode:
Diffstat (limited to 'app/services')
-rw-r--r--app/services/chat_names/find_user_service.rb4
-rw-r--r--app/services/ci/create_trace_artifact_service.rb30
-rw-r--r--app/services/issuable_base_service.rb16
-rw-r--r--app/services/labels/find_or_create_service.rb22
-rw-r--r--app/services/members/approve_access_request_service.rb45
-rw-r--r--app/services/members/authorized_destroy_service.rb61
-rw-r--r--app/services/members/base_service.rb49
-rw-r--r--app/services/members/create_service.rb15
-rw-r--r--app/services/members/destroy_service.rb77
-rw-r--r--app/services/members/request_access_service.rb13
-rw-r--r--app/services/members/update_service.rb16
-rw-r--r--app/services/notification_service.rb32
-rw-r--r--app/services/projects/autocomplete_service.rb11
-rw-r--r--app/services/projects/update_pages_configuration_service.rb10
-rw-r--r--app/services/projects/update_service.rb15
-rw-r--r--app/services/quick_actions/interpret_service.rb45
-rw-r--r--app/services/system_hooks_service.rb2
-rw-r--r--app/services/verify_pages_domain_service.rb107
18 files changed, 377 insertions, 193 deletions
diff --git a/app/services/chat_names/find_user_service.rb b/app/services/chat_names/find_user_service.rb
index 4f5c5567b42..d458b814183 100644
--- a/app/services/chat_names/find_user_service.rb
+++ b/app/services/chat_names/find_user_service.rb
@@ -9,8 +9,8 @@ module ChatNames
chat_name = find_chat_name
return unless chat_name
- chat_name.touch(:last_used_at)
- chat_name.user
+ chat_name.update_last_used_at
+ chat_name
end
private
diff --git a/app/services/ci/create_trace_artifact_service.rb b/app/services/ci/create_trace_artifact_service.rb
index 280a2c3afa4..ffde824972c 100644
--- a/app/services/ci/create_trace_artifact_service.rb
+++ b/app/services/ci/create_trace_artifact_service.rb
@@ -4,13 +4,33 @@ module Ci
return if job.job_artifacts_trace
job.trace.read do |stream|
- if stream.file?
- job.create_job_artifacts_trace!(
- project: job.project,
- file_type: :trace,
- file: stream)
+ break unless stream.file?
+
+ clone_file!(stream.path, JobArtifactUploader.workhorse_upload_path) do |clone_path|
+ create_job_trace!(job, clone_path)
+ FileUtils.rm(stream.path)
end
end
end
+
+ private
+
+ def create_job_trace!(job, path)
+ File.open(path) do |stream|
+ job.create_job_artifacts_trace!(
+ project: job.project,
+ file_type: :trace,
+ file: stream)
+ end
+ end
+
+ def clone_file!(src_path, temp_dir)
+ FileUtils.mkdir_p(temp_dir)
+ Dir.mktmpdir('tmp-trace', temp_dir) do |dir_path|
+ temp_path = File.join(dir_path, "job.log")
+ FileUtils.copy(src_path, temp_path)
+ yield(temp_path)
+ end
+ end
end
end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index e7463e6e25c..e87fd49d193 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -77,8 +77,12 @@ class IssuableBaseService < BaseService
return unless labels
params[:label_ids] = labels.split(",").map do |label_name|
- service = Labels::FindOrCreateService.new(current_user, project, title: label_name.strip)
- label = service.execute
+ label = Labels::FindOrCreateService.new(
+ current_user,
+ parent,
+ title: label_name.strip,
+ available_labels: available_labels
+ ).execute
label.try(:id)
end.compact
@@ -102,7 +106,7 @@ class IssuableBaseService < BaseService
end
def available_labels
- LabelsFinder.new(current_user, project_id: @project.id).execute
+ @available_labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute
end
def merge_quick_actions_into_params!(issuable)
@@ -247,7 +251,7 @@ class IssuableBaseService < BaseService
when 'add'
todo_service.mark_todo(issuable, current_user)
when 'done'
- todo = TodosFinder.new(current_user).execute.find_by(target: issuable)
+ todo = TodosFinder.new(current_user).find_by(target: issuable)
todo_service.mark_todos_as_done_by_ids(todo, current_user) if todo
end
end
@@ -303,4 +307,8 @@ class IssuableBaseService < BaseService
def update_project_counter_caches?(issuable)
issuable.state_changed?
end
+
+ def parent
+ project
+ end
end
diff --git a/app/services/labels/find_or_create_service.rb b/app/services/labels/find_or_create_service.rb
index 940c8b333d3..079f611b3f3 100644
--- a/app/services/labels/find_or_create_service.rb
+++ b/app/services/labels/find_or_create_service.rb
@@ -1,8 +1,9 @@
module Labels
class FindOrCreateService
- def initialize(current_user, project, params = {})
+ def initialize(current_user, parent, params = {})
@current_user = current_user
- @project = project
+ @parent = parent
+ @available_labels = params.delete(:available_labels)
@params = params.dup.with_indifferent_access
end
@@ -13,12 +14,13 @@ module Labels
private
- attr_reader :current_user, :project, :params, :skip_authorization
+ attr_reader :current_user, :parent, :params, :skip_authorization
def available_labels
@available_labels ||= LabelsFinder.new(
current_user,
- project_id: project.id
+ "#{parent_type}_id".to_sym => parent.id,
+ only_group_labels: parent_is_group?
).execute(skip_authorization: skip_authorization)
end
@@ -27,8 +29,8 @@ module Labels
def find_or_create_label
new_label = available_labels.find_by(title: title)
- if new_label.nil? && (skip_authorization || Ability.allowed?(current_user, :admin_label, project))
- new_label = Labels::CreateService.new(params).execute(project: project)
+ if new_label.nil? && (skip_authorization || Ability.allowed?(current_user, :admin_label, parent))
+ new_label = Labels::CreateService.new(params).execute(parent_type.to_sym => parent)
end
new_label
@@ -37,5 +39,13 @@ module Labels
def title
params[:title] || params[:name]
end
+
+ def parent_type
+ parent.model_name.param_key
+ end
+
+ def parent_is_group?
+ parent_type == "group"
+ end
end
end
diff --git a/app/services/members/approve_access_request_service.rb b/app/services/members/approve_access_request_service.rb
index 2a2bb0cae5b..6be08b590bc 100644
--- a/app/services/members/approve_access_request_service.rb
+++ b/app/services/members/approve_access_request_service.rb
@@ -1,51 +1,20 @@
module Members
- class ApproveAccessRequestService < BaseService
- include MembersHelper
-
- attr_accessor :source
-
- # source - The source object that respond to `#requesters` (i.g. project or group)
- # current_user - The user that performs the access request approval
- # params - A hash of parameters
- # :user_id - User ID used to retrieve the access requester
- # :id - Member ID used to retrieve the access requester
- # :access_level - Optional access level set when the request is accepted
- def initialize(source, current_user, params = {})
- @source = source
- @current_user = current_user
- @params = params.slice(:user_id, :id, :access_level)
- end
-
- # opts - A hash of options
- # :force - Bypass permission check: current_user can be nil in that case
- def execute(opts = {})
- condition = params[:user_id] ? { user_id: params[:user_id] } : { id: params[:id] }
- access_requester = source.requesters.find_by!(condition)
-
- raise Gitlab::Access::AccessDeniedError unless can_update_access_requester?(access_requester, opts)
+ class ApproveAccessRequestService < Members::BaseService
+ def execute(access_requester, skip_authorization: false, skip_log_audit_event: false)
+ raise Gitlab::Access::AccessDeniedError unless skip_authorization || can_update_access_requester?(access_requester)
access_requester.access_level = params[:access_level] if params[:access_level]
access_requester.accept_request
+ after_execute(member: access_requester, skip_log_audit_event: skip_log_audit_event)
+
access_requester
end
private
- def can_update_access_requester?(access_requester, opts = {})
- access_requester && (
- opts[:force] ||
- can?(current_user, update_member_permission(access_requester), access_requester)
- )
- end
-
- def update_member_permission(member)
- case member
- when GroupMember
- :update_group_member
- when ProjectMember
- :update_project_member
- end
+ def can_update_access_requester?(access_requester)
+ can?(current_user, update_member_permission(access_requester), access_requester)
end
end
end
diff --git a/app/services/members/authorized_destroy_service.rb b/app/services/members/authorized_destroy_service.rb
deleted file mode 100644
index 2e89f00dad8..00000000000
--- a/app/services/members/authorized_destroy_service.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-module Members
- class AuthorizedDestroyService < BaseService
- attr_accessor :member, :user
-
- def initialize(member, user = nil)
- @member, @user = member, user
- end
-
- def execute
- return false if member.is_a?(GroupMember) && member.source.last_owner?(member.user)
-
- Member.transaction do
- unassign_issues_and_merge_requests(member) unless member.invite?
- member.notification_setting&.destroy
-
- member.destroy
- end
-
- if member.request? && member.user != user
- notification_service.decline_access_request(member)
- end
-
- member
- end
-
- private
-
- def unassign_issues_and_merge_requests(member)
- if member.is_a?(GroupMember)
- issues = Issue.unscoped.select(1)
- .joins(:project)
- .where('issues.id = issue_assignees.issue_id AND projects.namespace_id = ?', member.source_id)
-
- # DELETE FROM issue_assignees WHERE user_id = X AND EXISTS (...)
- IssueAssignee.unscoped
- .where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues)
- .delete_all
-
- MergeRequestsFinder.new(user, group_id: member.source_id, assignee_id: member.user_id)
- .execute
- .update_all(assignee_id: nil)
- else
- project = member.source
-
- # SELECT 1 FROM issues WHERE issues.id = issue_assignees.issue_id AND issues.project_id = X
- issues = Issue.unscoped.select(1)
- .where('issues.id = issue_assignees.issue_id')
- .where(project_id: project.id)
-
- # DELETE FROM issue_assignees WHERE user_id = X AND EXISTS (...)
- IssueAssignee.unscoped
- .where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues)
- .delete_all
-
- project.merge_requests.opened.assigned_to(member.user).update_all(assignee_id: nil)
- end
-
- member.user.invalidate_cache_counts
- end
- end
-end
diff --git a/app/services/members/base_service.rb b/app/services/members/base_service.rb
new file mode 100644
index 00000000000..74556fb20cf
--- /dev/null
+++ b/app/services/members/base_service.rb
@@ -0,0 +1,49 @@
+module Members
+ class BaseService < ::BaseService
+ # current_user - The user that performs the action
+ # params - A hash of parameters
+ def initialize(current_user = nil, params = {})
+ @current_user = current_user
+ @params = params
+ end
+
+ def after_execute(args)
+ # overriden in EE::Members modules
+ end
+
+ private
+
+ def update_member_permission(member)
+ case member
+ when GroupMember
+ :update_group_member
+ when ProjectMember
+ :update_project_member
+ else
+ raise "Unknown member type: #{member}!"
+ end
+ end
+
+ def override_member_permission(member)
+ case member
+ when GroupMember
+ :override_group_member
+ when ProjectMember
+ :override_project_member
+ else
+ raise "Unknown member type: #{member}!"
+ end
+ end
+
+ def action_member_permission(action, member)
+ case action
+ when :update
+ update_member_permission(member)
+ when :override
+ override_member_permission(member)
+ else
+ raise "Unknown action '#{action}' on #{member}!"
+ end
+ end
+ end
+end
diff --git a/app/services/members/create_service.rb b/app/services/members/create_service.rb
index 26906ae7167..bc6a9405aac 100644
--- a/app/services/members/create_service.rb
+++ b/app/services/members/create_service.rb
@@ -1,15 +1,8 @@
module Members
- class CreateService < BaseService
+ class CreateService < Members::BaseService
DEFAULT_LIMIT = 100
- def initialize(source, current_user, params = {})
- @source = source
- @current_user = current_user
- @params = params
- @error = nil
- end
-
- def execute
+ def execute(source)
return error('No users specified.') if params[:user_ids].blank?
user_ids = params[:user_ids].split(',').uniq
@@ -17,13 +10,15 @@ module Members
return error("Too many users specified (limit is #{user_limit})") if
user_limit && user_ids.size > user_limit
- @source.add_users(
+ members = source.add_users(
user_ids,
params[:access_level],
expires_at: params[:expires_at],
current_user: current_user
)
+ members.each { |member| after_execute(member: member) }
+
success
end
diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb
index 05b93ac8fdb..b141bfd5fbc 100644
--- a/app/services/members/destroy_service.rb
+++ b/app/services/members/destroy_service.rb
@@ -1,42 +1,30 @@
module Members
- class DestroyService < BaseService
- include MembersHelper
+ class DestroyService < Members::BaseService
+ def execute(member, skip_authorization: false)
+ raise Gitlab::Access::AccessDeniedError unless skip_authorization || can_destroy_member?(member)
- attr_accessor :source
+ return member if member.is_a?(GroupMember) && member.source.last_owner?(member.user)
- ALLOWED_SCOPES = %i[members requesters all].freeze
+ Member.transaction do
+ unassign_issues_and_merge_requests(member) unless member.invite?
+ member.notification_setting&.destroy
- def initialize(source, current_user, params = {})
- @source = source
- @current_user = current_user
- @params = params
- end
-
- def execute(scope = :members)
- raise "scope :#{scope} is not allowed!" unless ALLOWED_SCOPES.include?(scope)
+ member.destroy
+ end
- member = find_member!(scope)
+ if member.request? && member.user != current_user
+ notification_service.decline_access_request(member)
+ end
- raise Gitlab::Access::AccessDeniedError unless can_destroy_member?(member)
+ after_execute(member: member)
- AuthorizedDestroyService.new(member, current_user).execute
+ member
end
private
- def find_member!(scope)
- condition = params[:user_id] ? { user_id: params[:user_id] } : { id: params[:id] }
- case scope
- when :all
- source.members.find_by(condition) ||
- source.requesters.find_by!(condition)
- else
- source.public_send(scope).find_by!(condition) # rubocop:disable GitlabSecurity/PublicSend
- end
- end
-
def can_destroy_member?(member)
- member && can?(current_user, destroy_member_permission(member), member)
+ can?(current_user, destroy_member_permission(member), member)
end
def destroy_member_permission(member)
@@ -45,7 +33,42 @@ module Members
:destroy_group_member
when ProjectMember
:destroy_project_member
+ else
+ raise "Unknown member type: #{member}!"
end
end
+
+ def unassign_issues_and_merge_requests(member)
+ if member.is_a?(GroupMember)
+ issues = Issue.unscoped.select(1)
+ .joins(:project)
+ .where('issues.id = issue_assignees.issue_id AND projects.namespace_id = ?', member.source_id)
+
+ # DELETE FROM issue_assignees WHERE user_id = X AND EXISTS (...)
+ IssueAssignee.unscoped
+ .where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues)
+ .delete_all
+
+ MergeRequestsFinder.new(current_user, group_id: member.source_id, assignee_id: member.user_id)
+ .execute
+ .update_all(assignee_id: nil)
+ else
+ project = member.source
+
+ # SELECT 1 FROM issues WHERE issues.id = issue_assignees.issue_id AND issues.project_id = X
+ issues = Issue.unscoped.select(1)
+ .where('issues.id = issue_assignees.issue_id')
+ .where(project_id: project.id)
+
+ # DELETE FROM issue_assignees WHERE user_id = X AND EXISTS (...)
+ IssueAssignee.unscoped
+ .where('user_id = :user_id AND EXISTS (:sub)', user_id: member.user_id, sub: issues)
+ .delete_all
+
+ project.merge_requests.opened.assigned_to(member.user).update_all(assignee_id: nil)
+ end
+
+ member.user.invalidate_cache_counts
+ end
end
end
diff --git a/app/services/members/request_access_service.rb b/app/services/members/request_access_service.rb
index 2614153d900..24293b30005 100644
--- a/app/services/members/request_access_service.rb
+++ b/app/services/members/request_access_service.rb
@@ -1,13 +1,6 @@
module Members
- class RequestAccessService < BaseService
- attr_accessor :source
-
- def initialize(source, current_user)
- @source = source
- @current_user = current_user
- end
-
- def execute
+ class RequestAccessService < Members::BaseService
+ def execute(source)
raise Gitlab::Access::AccessDeniedError unless can_request_access?(source)
source.members.create(
@@ -19,7 +12,7 @@ module Members
private
def can_request_access?(source)
- source && can?(current_user, :request_access, source)
+ can?(current_user, :request_access, source)
end
end
end
diff --git a/app/services/members/update_service.rb b/app/services/members/update_service.rb
new file mode 100644
index 00000000000..48b3d59f7bd
--- /dev/null
+++ b/app/services/members/update_service.rb
@@ -0,0 +1,16 @@
+module Members
+ class UpdateService < Members::BaseService
+ # returns the updated member
+ def execute(member, permission: :update)
+ raise Gitlab::Access::AccessDeniedError unless can?(current_user, action_member_permission(permission, member), member)
+
+ old_access_level = member.human_access
+
+ if member.update_attributes(params)
+ after_execute(action: permission, old_access_level: old_access_level, member: member)
+ end
+
+ member
+ end
+ end
+end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 56e941d90ff..e07ecda27b5 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -339,6 +339,30 @@ class NotificationService
end
end
+ def pages_domain_verification_succeeded(domain)
+ recipients_for_pages_domain(domain).each do |user|
+ mailer.pages_domain_verification_succeeded_email(domain, user).deliver_later
+ end
+ end
+
+ def pages_domain_verification_failed(domain)
+ recipients_for_pages_domain(domain).each do |user|
+ mailer.pages_domain_verification_failed_email(domain, user).deliver_later
+ end
+ end
+
+ def pages_domain_enabled(domain)
+ recipients_for_pages_domain(domain).each do |user|
+ mailer.pages_domain_enabled_email(domain, user).deliver_later
+ end
+ end
+
+ def pages_domain_disabled(domain)
+ recipients_for_pages_domain(domain).each do |user|
+ mailer.pages_domain_disabled_email(domain, user).deliver_later
+ end
+ end
+
protected
def new_resource_email(target, method)
@@ -433,6 +457,14 @@ class NotificationService
private
+ def recipients_for_pages_domain(domain)
+ project = domain.project
+
+ return [] unless project
+
+ notifiable_users(project.team.masters, :watch, target: project)
+ end
+
def notifiable?(*args)
NotificationRecipientService.notifiable?(*args)
end
diff --git a/app/services/projects/autocomplete_service.rb b/app/services/projects/autocomplete_service.rb
index 1ae2c40872a..e61ecb696d0 100644
--- a/app/services/projects/autocomplete_service.rb
+++ b/app/services/projects/autocomplete_service.rb
@@ -50,16 +50,7 @@ module Projects
return [] unless noteable&.is_a?(Issuable)
- opts = {
- project: project,
- issuable: noteable,
- current_user: current_user
- }
- QuickActions::InterpretService.command_definitions.map do |definition|
- next unless definition.available?(opts)
-
- definition.to_h(opts)
- end.compact
+ QuickActions::InterpretService.new(project, current_user).available_commands(noteable)
end
end
end
diff --git a/app/services/projects/update_pages_configuration_service.rb b/app/services/projects/update_pages_configuration_service.rb
index cacb74b1205..52ff64cc938 100644
--- a/app/services/projects/update_pages_configuration_service.rb
+++ b/app/services/projects/update_pages_configuration_service.rb
@@ -23,7 +23,7 @@ module Projects
end
def pages_domains_config
- project.pages_domains.map do |domain|
+ enabled_pages_domains.map do |domain|
{
domain: domain.domain,
certificate: domain.certificate,
@@ -32,6 +32,14 @@ module Projects
end
end
+ def enabled_pages_domains
+ if Gitlab::CurrentSettings.pages_domain_verification_enabled?
+ project.pages_domains.enabled
+ else
+ project.pages_domains
+ end
+ end
+
def reload_daemon
# GitLab Pages daemon constantly watches for modification time of `pages.path`
# It reloads configuration when `pages.path` is modified
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index 0e235a6d2a0..379a8068023 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -15,6 +15,8 @@ module Projects
return error("Could not set the default branch") unless project.change_head(params[:default_branch])
end
+ ensure_wiki_exists if enabling_wiki?
+
if project.update_attributes(params.except(:default_branch))
if project.previous_changes.include?('path')
project.rename_repo
@@ -52,5 +54,18 @@ module Projects
project.repository.exists? &&
new_branch && new_branch != project.default_branch
end
+
+ def enabling_wiki?
+ return false if @project.wiki_enabled?
+
+ params[:project_feature_attributes][:wiki_access_level].to_i > ProjectFeature::DISABLED
+ end
+
+ def ensure_wiki_exists
+ ProjectWiki.new(project, project.owner).wiki
+ rescue ProjectWiki::CouldNotCreateWikiError
+ log_error("Could not create wiki for #{project.full_name}")
+ Gitlab::Metrics.counter(:wiki_can_not_be_created_total, 'Counts the times we failed to create a wiki')
+ end
end
end
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index 669c1ba0a22..1e9bd84e749 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -7,6 +7,18 @@ module QuickActions
SHRUG = '¯\\_(ツ)_/¯'.freeze
TABLEFLIP = '(╯°□°)╯︵ ┻━┻'.freeze
+ # Takes an issuable and returns an array of all the available commands
+ # represented with .to_h
+ def available_commands(issuable)
+ @issuable = issuable
+
+ self.class.command_definitions.map do |definition|
+ next unless definition.available?(self)
+
+ definition.to_h(self)
+ end.compact
+ end
+
# Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and hash of changes to be applied to a record.
def execute(content, issuable)
@@ -15,8 +27,8 @@ module QuickActions
@issuable = issuable
@updates = {}
- content, commands = extractor.extract_commands(content, context)
- extract_updates(commands, context)
+ content, commands = extractor.extract_commands(content)
+ extract_updates(commands)
[content, @updates]
end
@@ -28,8 +40,8 @@ module QuickActions
@issuable = issuable
- content, commands = extractor.extract_commands(content, context)
- commands = explain_commands(commands, context)
+ content, commands = extractor.extract_commands(content)
+ commands = explain_commands(commands)
[content, commands]
end
@@ -157,11 +169,11 @@ module QuickActions
params '%"milestone"'
condition do
current_user.can?(:"admin_#{issuable.to_ability_name}", project) &&
- project.milestones.active.any?
+ find_milestones(project, state: 'active').any?
end
parse_params do |milestone_param|
extract_references(milestone_param, :milestone).first ||
- project.milestones.find_by(title: milestone_param.strip)
+ find_milestones(project, title: milestone_param.strip).first
end
command :milestone do |milestone|
@updates[:milestone_id] = milestone.id if milestone
@@ -544,6 +556,10 @@ module QuickActions
users
end
+ def find_milestones(project, params = {})
+ MilestonesFinder.new(params.merge(project_ids: [project.id], group_ids: [project.group&.id])).execute
+ end
+
def find_labels(labels_param)
extract_references(labels_param, :label) |
LabelsFinder.new(current_user, project_id: project.id, name: labels_param.split).execute
@@ -557,21 +573,21 @@ module QuickActions
find_labels(labels_param).map(&:id)
end
- def explain_commands(commands, opts)
+ def explain_commands(commands)
commands.map do |name, arg|
definition = self.class.definition_by_name(name)
next unless definition
- definition.explain(self, opts, arg)
+ definition.explain(self, arg)
end.compact
end
- def extract_updates(commands, opts)
+ def extract_updates(commands)
commands.each do |name, arg|
definition = self.class.definition_by_name(name)
next unless definition
- definition.execute(self, opts, arg)
+ definition.execute(self, arg)
end
end
@@ -581,14 +597,5 @@ module QuickActions
ext.references(type)
end
-
- def context
- {
- issuable: issuable,
- current_user: current_user,
- project: project,
- params: params
- }
- end
end
end
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index a6b7a6e1416..af8c02a10b7 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -11,6 +11,8 @@ class SystemHooksService
SystemHook.hooks_for(hooks_scope).find_each do |hook|
hook.async_execute(data, 'system_hooks')
end
+
+ Gitlab::Plugin.execute_all_async(data)
end
private
diff --git a/app/services/verify_pages_domain_service.rb b/app/services/verify_pages_domain_service.rb
new file mode 100644
index 00000000000..86166047302
--- /dev/null
+++ b/app/services/verify_pages_domain_service.rb
@@ -0,0 +1,107 @@
+require 'resolv'
+
+class VerifyPagesDomainService < BaseService
+ # The maximum number of seconds to be spent on each DNS lookup
+ RESOLVER_TIMEOUT_SECONDS = 15
+
+ # How long verification lasts for
+ VERIFICATION_PERIOD = 7.days
+
+ attr_reader :domain
+
+ def initialize(domain)
+ @domain = domain
+ end
+
+ def execute
+ return error("No verification code set for #{domain.domain}") unless domain.verification_code.present?
+
+ if !verification_enabled? || dns_record_present?
+ verify_domain!
+ elsif expired?
+ disable_domain!
+ else
+ unverify_domain!
+ end
+ end
+
+ private
+
+ def verify_domain!
+ was_disabled = !domain.enabled?
+ was_unverified = domain.unverified?
+
+ # Prevent any pre-existing grace period from being truncated
+ reverify = [domain.enabled_until, VERIFICATION_PERIOD.from_now].compact.max
+
+ domain.update!(verified_at: Time.now, enabled_until: reverify)
+
+ if was_disabled
+ notify(:enabled)
+ elsif was_unverified
+ notify(:verification_succeeded)
+ end
+
+ success
+ end
+
+ def unverify_domain!
+ if domain.verified?
+ domain.update!(verified_at: nil)
+ notify(:verification_failed)
+ end
+
+ error("Couldn't verify #{domain.domain}")
+ end
+
+ def disable_domain!
+ domain.update!(verified_at: nil, enabled_until: nil)
+
+ notify(:disabled)
+
+ error("Couldn't verify #{domain.domain}. It is now disabled.")
+ end
+
+ # A domain is only expired until `disable!` has been called
+ def expired?
+ domain.enabled_until && domain.enabled_until < Time.now
+ end
+
+ def dns_record_present?
+ Resolv::DNS.open do |resolver|
+ resolver.timeouts = RESOLVER_TIMEOUT_SECONDS
+
+ check(domain.domain, resolver) || check(domain.verification_domain, resolver)
+ end
+ end
+
+ def check(domain_name, resolver)
+ records = parse(txt_records(domain_name, resolver))
+
+ records.any? do |record|
+ record == domain.keyed_verification_code || record == domain.verification_code
+ end
+ rescue => err
+ log_error("Failed to check TXT records on #{domain_name} for #{domain.domain}: #{err}")
+ false
+ end
+
+ def txt_records(domain_name, resolver)
+ resolver.getresources(domain_name, Resolv::DNS::Resource::IN::TXT)
+ end
+
+ def parse(records)
+ records.flat_map(&:strings).flat_map(&:split)
+ end
+
+ def verification_enabled?
+ Gitlab::CurrentSettings.pages_domain_verification_enabled?
+ end
+
+ def notify(type)
+ return unless verification_enabled?
+
+ Gitlab::AppLogger.info("Pages domain '#{domain.domain}' changed state to '#{type}'")
+ notification_service.public_send("pages_domain_#{type}", domain) # rubocop:disable GitlabSecurity/PublicSend
+ end
+end