Commit dfb3cb1d authored by Felipe Artur's avatar Felipe Artur

Move controllers/services service desk code to core

Part of the plan to move service desk feature
into core tier.

More info: https://gitlab.com/gitlab-org/gitlab/-/issues/215364
parent 9d64b959
......@@ -81,6 +81,7 @@ module IssuableCollections
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def finder_options
strong_memoize(:finder_options) do
params[:state] = default_state if params[:state].blank?
options = {
......@@ -110,6 +111,7 @@ module IssuableCollections
params.permit(finder_type.valid_params).merge(options)
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def default_state
......
......@@ -11,11 +11,11 @@ class Projects::IssuesController < Projects::ApplicationController
include RecordUserLastActivity
def issue_except_actions
%i[index calendar new create bulk_update import_csv export_csv]
%i[index calendar new create bulk_update import_csv export_csv service_desk]
end
def set_issuables_index_only_actions
%i[index calendar]
%i[index calendar service_desk]
end
prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) }
......@@ -223,6 +223,11 @@ class Projects::IssuesController < Projects::ApplicationController
redirect_to project_issues_path(project)
end
def service_desk
@issues = @issuables # rubocop:disable Gitlab/ModuleWithInstanceVariables
@users.push(User.support_bot) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
protected
def sorting_field
......@@ -320,6 +325,17 @@ class Projects::IssuesController < Projects::ApplicationController
private
def finder_options
options = super
return options unless service_desk?
options.reject! { |key| key == 'author_username' || key == 'author_id' }
options[:author_id] = User.support_bot
options
end
def branch_link(branch)
project_compare_path(project, from: project.default_branch, to: branch[:name])
end
......@@ -337,6 +353,10 @@ class Projects::IssuesController < Projects::ApplicationController
def rate_limiter
::Gitlab::ApplicationRateLimiter
end
def service_desk?
action_name == 'service_desk'
end
end
Projects::IssuesController.prepend_if_ee('EE::Projects::IssuesController')
......@@ -38,6 +38,7 @@ class ProjectsController < Projects::ApplicationController
before_action only: [:new, :create] do
frontend_experimentation_tracking_data(:new_create_project_ui, 'click_tab')
push_frontend_feature_flag(:new_create_project_ui) if experiment_enabled?(:new_create_project_ui)
push_frontend_feature_flag(:service_desk_custom_address, @project)
end
layout :determine_layout
......@@ -391,6 +392,7 @@ class ProjectsController < Projects::ApplicationController
:initialize_with_readme,
:autoclose_referenced_issues,
:suggestion_commit_message,
:service_desk_enabled,
project_feature_attributes: %i[
builds_access_level
......
......@@ -19,11 +19,22 @@ module Issues
notify_participants
# Updates old issue sent notifications allowing
# to receive service desk emails on the new moved issue.
update_service_desk_sent_notifications
new_entity
end
private
def update_service_desk_sent_notifications
return unless original_entity.from_service_desk?
original_entity
.sent_notifications.update_all(project_id: new_entity.project_id, noteable_id: new_entity.id)
end
def update_old_entity
super
......
......@@ -294,6 +294,7 @@ class NotificationService
return true if note.system_note_with_references?
send_new_note_notifications(note)
send_service_desk_notification(note)
end
def send_new_note_notifications(note)
......@@ -305,6 +306,21 @@ class NotificationService
end
end
def send_service_desk_notification(note)
return unless Gitlab::ServiceDesk.supported?
return unless note.noteable_type == 'Issue'
issue = note.noteable
support_bot = User.support_bot
return unless issue.service_desk_reply_to.present?
return unless issue.project.service_desk_enabled?
return if note.author == support_bot
return unless issue.subscribed?(support_bot, issue.project)
mailer.service_desk_new_note_email(issue.id, note.id).deliver_later
end
# Notify users when a new release is created
def send_new_release_notifications(release)
recipients = NotificationRecipients::BuildService.build_new_release_recipients(release)
......
......@@ -17,6 +17,7 @@ resources :issues, concerns: :awardable, constraints: { id: /\d+/ } do
end
collection do
get :service_desk
post :bulk_update
post :import_csv
post :export_csv
......
......@@ -340,6 +340,12 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
# All new routes should go under /-/ scope.
# Look for scope '-' at the top of the file.
#
# Service Desk
#
get '/service_desk' => 'service_desk#show', as: :service_desk
put '/service_desk' => 'service_desk#update', as: :service_desk_refresh
#
# Templates
#
......
......@@ -16,21 +16,6 @@ module EE
end
end
override :issue_except_actions
def issue_except_actions
super + %i[service_desk]
end
override :set_issuables_index_only_actions
def set_issuables_index_only_actions
super + %i[service_desk]
end
def service_desk
@issues = @issuables # rubocop:disable Gitlab/ModuleWithInstanceVariables
@users.push(::User.support_bot) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
private
def issue_params_attributes
......@@ -41,20 +26,13 @@ module EE
attrs
end
override :finder_options
def finder_options
options = super
options.reject! { |key| key == 'weight' } unless project.feature_available?(:issue_weights)
if service_desk?
options.reject! { |key| key == 'author_username' || key == 'author_id' }
options[:author_id] = ::User.support_bot
end
options
end
return super if project.feature_available?(:issue_weights)
def service_desk?
action_name == 'service_desk'
options.reject { |key| key == 'weight' }
end
def whitelist_query_limiting_ee
......
......@@ -9,10 +9,6 @@ module EE
before_action :log_download_export_audit_event, only: [:download_export]
before_action :log_archive_audit_event, only: [:archive]
before_action :log_unarchive_audit_event, only: [:unarchive]
before_action do
push_frontend_feature_flag(:service_desk_custom_address, @project)
end
end
def restore
......@@ -79,7 +75,6 @@ module EE
merge_requests_template
repository_size_limit
reset_approvals_on_push
service_desk_enabled
ci_cd_only
use_custom_template
packages_enabled
......
......@@ -5,17 +5,6 @@ module EE
module MoveService
extend ::Gitlab::Utils::Override
override :execute
def execute(issue, target_project)
super
# Updates old issue sent notifications allowing
# to receive service desk emails on the new moved issue.
update_service_desk_sent_notifications
new_entity
end
override :update_old_entity
def update_old_entity
rewrite_epic_issue
......@@ -25,13 +14,6 @@ module EE
private
def update_service_desk_sent_notifications
return unless original_entity.from_service_desk?
original_entity
.sent_notifications.update_all(project_id: new_entity.project_id, noteable_id: new_entity.id)
end
def rewrite_epic_issue
return unless epic_issue = original_entity.epic_issue
return unless can?(current_user, :update_epic, epic_issue.epic.group)
......
# frozen_string_literal: true
require 'gitlab/service_desk'
module EE
module NotificationService
extend ::Gitlab::Utils::Override
# When we add approvers to a merge request we should send an email to:
#
# * the new approvers
......@@ -24,12 +20,6 @@ module EE
unapprove_mr_email(merge_request, merge_request.target_project, current_user)
end
override :send_new_note_notifications
def send_new_note_notifications(note)
super
send_service_desk_notification(note)
end
def mirror_was_hard_failed(project)
return if project.emails_disabled?
......@@ -96,21 +86,6 @@ module EE
end
end
def send_service_desk_notification(note)
return unless ::Gitlab::ServiceDesk.supported?
return unless note.noteable_type == 'Issue'
issue = note.noteable
support_bot = ::User.support_bot
return unless issue.service_desk_reply_to.present?
return unless issue.project.service_desk_enabled?
return if note.author == support_bot
return unless issue.subscribed?(support_bot, issue.project)
mailer.service_desk_new_note_email(issue.id, note.id).deliver_later
end
def removed_iteration_resource_email(target, current_user)
recipients = ::NotificationRecipients::BuildService.build_recipients(
target,
......
......@@ -6,7 +6,7 @@
- can_edit_project_settings = can?(current_user, :admin_project, @project)
- title_text = _("Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab")
- if ::Gitlab::ServiceDesk.supported?
- if Gitlab::ServiceDesk.supported?
%div{ class: "#{callout_selector}" }
.svg-content
= render svg_path
......
......@@ -6,9 +6,5 @@ resources :issues, only: [], constraints: { id: /\d+/ } do
delete '/descriptions/:version_id', action: :delete_description_version, as: :delete_description_version
end
collection do
get :service_desk
end
resources :issue_links, only: [:index, :create, :destroy], as: 'links', path: 'links'
end
......@@ -122,9 +122,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resource :tracing, only: [:show]
get '/service_desk' => 'service_desk#show', as: :service_desk
put '/service_desk' => 'service_desk#update', as: :service_desk_refresh
post '/restore' => '/projects#restore', as: :restore
resource :insights, only: [:show], trailing_slash: true do
......
......@@ -29,7 +29,7 @@ module Gitlab
end
def can_handle?
::Gitlab::ServiceDesk.supported? && (project_id || can_handle_legacy_format? || service_desk_key)
Gitlab::ServiceDesk.supported? && (project_id || can_handle_legacy_format? || service_desk_key)
end
def execute
......
......@@ -115,42 +115,6 @@ RSpec.describe Projects::IssuesController do
end
end
describe 'GET service_desk' do
let(:support_bot) { User.support_bot }
let(:other_user) { create(:user) }
let!(:service_desk_issue_1) { create(:issue, project: project, author: support_bot) }
let!(:service_desk_issue_2) { create(:issue, project: project, author: support_bot, assignees: [other_user]) }
let!(:other_user_issue) { create(:issue, project: project, author: other_user) }
def get_service_desk(extra_params = {})
get :service_desk, params: extra_params.merge(namespace_id: project.namespace, project_id: project)
end
it 'adds an author filter for the support bot user' do
get_service_desk
expect(assigns(:issues)).to contain_exactly(service_desk_issue_1, service_desk_issue_2)
end
it 'does not allow any other author to be set' do
get_service_desk(author_username: other_user.username)
expect(assigns(:issues)).to contain_exactly(service_desk_issue_1, service_desk_issue_2)
end
it 'supports other filters' do
get_service_desk(assignee_username: other_user.username)
expect(assigns(:issues)).to contain_exactly(service_desk_issue_2)
end
it 'allows an assignee to be specified by id' do
get_service_desk(assignee_id: other_user.id)
expect(assigns(:users)).to contain_exactly(other_user, support_bot)
end
end
describe 'GET #discussions' do
let(:issue) { create(:issue, project: project) }
let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) }
......
......@@ -216,25 +216,6 @@ RSpec.describe ProjectsController do
end
end
it 'updates Service Desk attributes' do
allow(Gitlab::IncomingEmail).to receive(:enabled?) { true }
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
params = {
service_desk_enabled: true
}
put :update,
params: {
namespace_id: project.namespace,
id: project,
project: params
}
project.reload
expect(response).to have_gitlab_http_status(:found)
expect(project.service_desk_enabled).to eq(true)
end
context 'when merge_pipelines_enabled param is specified' do
let(:params) { { merge_pipelines_enabled: true } }
......
......@@ -33,7 +33,7 @@ RSpec.describe 'Service Desk Issue Tracker', :js do
describe 'issues list' do
context 'when service desk is misconfigured' do
before do
allow(::Gitlab::ServiceDesk).to receive(:supported?).and_return(false)
allow(Gitlab::ServiceDesk).to receive(:supported?).and_return(false)
visit service_desk_project_issues_path(project)
end
......
......@@ -142,7 +142,7 @@ RSpec.describe Gitlab::Email::Handler::CreateNoteHandler do
context 'is enabled' do
before do
allow(::Gitlab::ServiceDesk).to receive(:enabled?).with(project: project).and_return(true)
allow(Gitlab::ServiceDesk).to receive(:enabled?).and_return(true)
project.project_feature.update!(issues_access_level: issues_access_level)
end
......@@ -185,7 +185,7 @@ RSpec.describe Gitlab::Email::Handler::CreateNoteHandler do
context 'is disabled' do
before do
allow(::Gitlab::ServiceDesk).to receive(:enabled?).with(project: project).and_return(false)
allow(Gitlab::ServiceDesk).to receive(:enabled?).and_return(false)
end
it 'does not create a comment' do
......
......@@ -20,7 +20,7 @@ RSpec.describe Gitlab::Email::Handler::EE::ServiceDeskHandler do
let_it_be(:project) { create(:project, :repository, :public, namespace: namespace, path: 'test', service_desk_enabled: true) }
before do
allow(::Gitlab::ServiceDesk).to receive(:supported?).and_return(true)
allow(Gitlab::ServiceDesk).to receive(:supported?).and_return(true)
end
shared_examples 'a new issue request' do
......@@ -248,7 +248,7 @@ RSpec.describe Gitlab::Email::Handler::EE::ServiceDeskHandler do
context 'when service desk is not enabled for project' do
before do
allow(::Gitlab::ServiceDesk).to receive(:enabled?).and_return(false)
allow(Gitlab::ServiceDesk).to receive(:enabled?).and_return(false)
end
it 'does not create an issue' do
......
......@@ -109,47 +109,4 @@ RSpec.describe Issues::MoveService do
end
end
end
context 'updating sent notifications' do
let!(:old_issue_notification_1) { create(:sent_notification, project: old_issue.project, noteable: old_issue) }
let!(:old_issue_notification_2) { create(:sent_notification, project: old_issue.project, noteable: old_issue) }
let!(:other_issue_notification) { create(:sent_notification, project: old_issue.project) }
context 'when issue is from service desk' do
before do
allow(old_issue).to receive(:from_service_desk?).and_return(true)
end
it 'updates moved issue sent notifications' do
new_issue = move_service.execute(old_issue, new_project)
old_issue_notification_1.reload
old_issue_notification_2.reload
expect(old_issue_notification_1.project_id).to eq(new_issue.project_id)
expect(old_issue_notification_1.noteable_id).to eq(new_issue.id)
expect(old_issue_notification_2.project_id).to eq(new_issue.project_id)
expect(old_issue_notification_2.noteable_id).to eq(new_issue.id)
end
it 'does not update other issues sent notifications' do
expect do
move_service.execute(old_issue, new_project)
other_issue_notification.reload
end.not_to change { other_issue_notification.noteable_id }
end
end
context 'when issue is not from service desk' do
it 'does not update sent notifications' do
move_service.execute(old_issue, new_project)
old_issue_notification_1.reload
old_issue_notification_2.reload
expect(old_issue_notification_1.project_id).to eq(old_issue.project_id)
expect(old_issue_notification_1.noteable_id).to eq(old_issue.id)
expect(old_issue_notification_2.project_id).to eq(old_issue.project_id)
expect(old_issue_notification_2.noteable_id).to eq(old_issue.id)
end
end
end
end
......@@ -10,76 +10,6 @@ RSpec.describe EE::NotificationService, :mailer do
let(:mailer) { double(deliver_later: true) }
context 'service desk issues' do
before do
allow(Notify).to receive(:service_desk_new_note_email)
.with(Integer, Integer).and_return(mailer)
allow(::Gitlab::IncomingEmail).to receive(:enabled?) { true }
allow(::Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
end
def should_email!
expect(Notify).to receive(:service_desk_new_note_email)
.with(issue.id, note.id)
end
def should_not_email!
expect(Notify).not_to receive(:service_desk_new_note_email)
end
def execute!
subject.new_note(note)
end
def self.it_should_email!
it 'sends the email' do
should_email!
execute!
end
end
def self.it_should_not_email!
it 'doesn\'t send the email' do
should_not_email!
execute!
end
end
let(:issue) { create(:issue, author: User.support_bot) }
let(:project) { issue.project }
let(:note) { create(:note, noteable: issue, project: project) }
context 'a non-service-desk issue' do
it_should_not_email!
end
context 'a service-desk issue' do
before do
issue.update!(service_desk_reply_to: 'service.desk@example.com')
project.update!(service_desk_enabled: true)
end
it_should_email!
context 'where the project has disabled the feature' do
before do
project.update(service_desk_enabled: false)
end
it_should_not_email!
end
context 'when the support bot has unsubscribed' do
before do
issue.unsubscribe(User.support_bot, project)
end
it_should_not_email!
end
end
end
context 'new review' do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
......
......@@ -1564,6 +1564,43 @@ RSpec.describe Projects::IssuesController do
end
end
describe 'GET service_desk' do
let_it_be(:project) { create(:project_empty_repo, :public) }
let_it_be(:support_bot) { User.support_bot }
let_it_be(:other_user) { create(:user) }
let_it_be(:service_desk_issue_1) { create(:issue, project: project, author: support_bot) }
let_it_be(:service_desk_issue_2) { create(:issue, project: project, author: support_bot, assignees: [other_user]) }
let_it_be(:other_user_issue) { create(:issue, project: project, author: other_user) }
def get_service_desk(extra_params = {})
get :service_desk, params: extra_params.merge(namespace_id: project.namespace, project_id: project)
end
it 'adds an author filter for the support bot user' do
get_service_desk
expect(assigns(:issues)).to contain_exactly(service_desk_issue_1, service_desk_issue_2)
end
it 'does not allow any other author to be set' do
get_service_desk(author_username: other_user.username)
expect(assigns(:issues)).to contain_exactly(service_desk_issue_1, service_desk_issue_2)
end
it 'supports other filters' do
get_service_desk(assignee_username: other_user.username)
expect(assigns(:issues)).to contain_exactly(service_desk_issue_2)
end
it 'allows an assignee to be specified by id' do
get_service_desk(assignee_id: other_user.id)
expect(assigns(:users)).to contain_exactly(other_user, support_bot)
end
end
describe 'GET #discussions' do
let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) }
......
......@@ -11,8 +11,6 @@ RSpec.describe Projects::ServiceDeskController do
let_it_be(:user) { create(:user) }
before do
allow(License).to receive(:feature_available?).and_call_original
allow(License).to receive(:feature_available?).with(:service_desk) { true }
allow(Gitlab::IncomingEmail).to receive(:enabled?) { true }
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
......@@ -56,7 +54,7 @@ RSpec.describe Projects::ServiceDeskController do
context 'when issue template file becomes outdated' do
it 'returns template_file_missing as true' do
service = ServiceDeskSetting.new(project_id: project.id, issue_template_key: 'deleted')
service.save(validate: false)
service.save!(validate: false)
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }, format: :json
......
......@@ -6,7 +6,7 @@ RSpec.describe ProjectsController do
include ExternalAuthorizationServiceHelpers
include ProjectForksHelper
let(:project) { create(:project) }
let(:project) { create(:project, service_desk_enabled: false) }
let(:public_project) { create(:project, :public) }
let(:user) { create(:user) }
let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') }
......@@ -1396,6 +1396,27 @@ RSpec.describe ProjectsController do
end
end
it 'updates Service Desk attributes' do
project.add_maintainer(user)
sign_in(user)
allow(Gitlab::IncomingEmail).to receive(:enabled?) { true }
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
params = {
service_desk_enabled: true
}
put :update,
params: {
namespace_id: project.namespace,
id: project,
project: params
}
project.reload
expect(response).to have_gitlab_http_status(:found)
expect(project.service_desk_enabled).to eq(true)
end
def project_moved_message(redirect_route, project)
"Project '#{redirect_route.path}' was moved to '#{project.full_path}'. Please update any links and bookmarks that may still have the old path."
end
......
......@@ -210,4 +210,49 @@ RSpec.describe Issues::MoveService do
end
end
end
context 'updating sent notifications' do
let!(:old_issue_notification_1) { create(:sent_notification, project: old_issue.project, noteable: old_issue) }
let!(:old_issue_notification_2) { create(:sent_notification, project: old_issue.project, noteable: old_issue) }
let!(:other_issue_notification) { create(:sent_notification, project: old_issue.project) }
include_context 'user can move issue'
context 'when issue is from service desk' do
before do
allow(old_issue).to receive(:from_service_desk?).and_return(true)
end
it 'updates moved issue sent notifications' do
new_issue = move_service.execute(old_issue, new_project)
old_issue_notification_1.reload
old_issue_notification_2.reload
expect(old_issue_notification_1.project_id).to eq(new_issue.project_id)
expect(old_issue_notification_1.noteable_id).to eq(new_issue.id)
expect(old_issue_notification_2.project_id).to eq(new_issue.project_id)
expect(old_issue_notification_2.noteable_id).to eq(new_issue.id)
end
it 'does not update other issues sent notifications' do
expect do
move_service.execute(old_issue, new_project)
other_issue_notification.reload
end.not_to change { other_issue_notification.noteable_id }
end
end
context 'when issue is not from service desk' do
it 'does not update sent notifications' do
move_service.execute(old_issue, new_project)
old_issue_notification_1.reload
old_issue_notification_2.reload
expect(old_issue_notification_1.project_id).to eq(old_issue.project_id)
expect(old_issue_notification_1.noteable_id).to eq(old_issue.id)
expect(old_issue_notification_2.project_id).to eq(old_issue.project_id)
expect(old_issue_notification_2.noteable_id).to eq(old_issue.id)
end
end
end
end
......@@ -343,6 +343,79 @@ RSpec.describe NotificationService, :mailer do
end
end
context 'on service desk issue' do
before do
allow(Notify).to receive(:service_desk_new_note_email)
.with(Integer, Integer).and_return(mailer)
allow(::Gitlab::IncomingEmail).to receive(:enabled?) { true }
allow(::Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
end
let(:subject) { NotificationService.new }
let(:mailer) { double(deliver_later: true) }
def should_email!
expect(Notify).to receive(:service_desk_new_note_email)
.with(issue.id, note.id)
end
def should_not_email!
expect(Notify).not_to receive(:service_desk_new_note_email)
end
def execute!
subject.new_note(note)
end
def self.it_should_email!
it 'sends the email' do
should_email!
execute!
end
end
def self.it_should_not_email!
it 'doesn\'t send the email' do
should_not_email!
execute!
end
end
let(:issue) { create(:issue, author: User.support_bot) }
let(:project) { issue.project }
let(:note) { create(:note, noteable: issue, project: project) }
context 'a non-service-desk issue' do
it_should_not_email!
end
context 'a service-desk issue' do
before do
issue.update!(service_desk_reply_to: 'service.desk@example.com')
project.update!(service_desk_enabled: true)
end
it_should_email!
context 'where the project has disabled the feature' do
before do
project.update(service_desk_enabled: false)
end
it_should_not_email!
end
context 'when the support bot has unsubscribed' do
before do
issue.unsubscribe(User.support_bot, project)
end
it_should_not_email!
end
end
end
describe 'new note on issue in project that belongs to a group' do
before do
note.project.namespace_id = group.id
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment