Commit cf72a5a2 authored by Felipe Artur's avatar Felipe Artur Committed by Andreas Brandl

Allow to use issue templates on service desk

Let issue templates be applied on service desk issues
parent e1557877
# frozen_string_literal: true
class CreateServiceDeskSettings < ActiveRecord::Migration[5.2]
DOWNTIME = false
def change
create_table :service_desk_settings, id: false do |t|
t.references :project,
primary_key: true,
default: nil,
null: false,
index: false,
foreign_key: { on_delete: :cascade }
t.string :issue_template_key, limit: 255
end
end
end
......@@ -3486,6 +3486,10 @@ ActiveRecord::Schema.define(version: 2019_11_15_091425) do
t.index ["reply_key"], name: "index_sent_notifications_on_reply_key", unique: true
end
create_table "service_desk_settings", primary_key: "project_id", id: :bigint, default: nil, force: :cascade do |t|
t.string "issue_template_key", limit: 255
end
create_table "services", id: :serial, force: :cascade do |t|
t.string "type"
t.string "title"
......@@ -4509,6 +4513,7 @@ ActiveRecord::Schema.define(version: 2019_11_15_091425) do
add_foreign_key "scim_oauth_access_tokens", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "self_managed_prometheus_alert_events", "environments", on_delete: :cascade
add_foreign_key "self_managed_prometheus_alert_events", "projects", on_delete: :cascade
add_foreign_key "service_desk_settings", "projects", on_delete: :cascade
add_foreign_key "services", "projects", name: "fk_71cce407f9", on_delete: :cascade
add_foreign_key "slack_integrations", "services", on_delete: :cascade
add_foreign_key "smartcard_identities", "users", on_delete: :cascade
......
......@@ -10,6 +10,8 @@ class Projects::ServiceDeskController < Projects::ApplicationController
def update
Projects::UpdateService.new(project, current_user, { service_desk_enabled: params[:service_desk_enabled] }).execute
ServiceDeskSetting.update_template_key_for(project: project, issue_template_key: params[:issue_template_key])
json_response
end
......@@ -17,8 +19,15 @@ class Projects::ServiceDeskController < Projects::ApplicationController
def json_response
respond_to do |format|
service_desk_settings = project.service_desk_setting
service_desk_attributes =
{ service_desk_address: project.service_desk_address, service_desk_enabled: project.service_desk_enabled }
{
service_desk_address: project.service_desk_address,
service_desk_enabled: project.service_desk_enabled,
issue_template_key: service_desk_settings&.issue_template_key,
template_file_missing: service_desk_settings&.issue_template_missing?
}
format.json { render json: service_desk_attributes }
end
......
......@@ -48,6 +48,7 @@ module EE
has_one :gitlab_slack_application_service
has_one :alerts_service
has_one :service_desk_setting, class_name: 'ServiceDeskSetting'
has_one :tracing_setting, class_name: 'ProjectTracingSetting'
has_one :alerting_setting, inverse_of: :project, class_name: 'Alerting::ProjectAlertingSetting'
has_one :incident_management_setting, inverse_of: :project, class_name: 'IncidentManagement::ProjectIncidentManagementSetting'
......
# frozen_string_literal: true
class ServiceDeskSetting < ApplicationRecord
include Gitlab::Utils::StrongMemoize
belongs_to :project
validates :project_id, presence: true
validate :valid_issue_template
def self.update_template_key_for(project:, issue_template_key:)
return unless issue_template_key
settings = safe_find_or_create_by!(project_id: project.id)
settings.update!(issue_template_key: issue_template_key)
settings
end
def issue_template_content
strong_memoize(:issue_template_content) do
next unless issue_template_key.present?
Gitlab::Template::IssueTemplate.find(issue_template_key, project).content
rescue ::Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError
end
end
def issue_template_missing?
issue_template_key.present? && !issue_template_content.present?
end
def valid_issue_template
if issue_template_missing?
errors.add(:issue_template_key, "Issue template empty or not found")
end
end
end
---
title: Use issue templates on service desk(backend)
merge_request: 19515
author:
type: added
......@@ -9,6 +9,7 @@ module Gitlab
module EE
class ServiceDeskHandler < BaseHandler
include ReplyProcessing
include Gitlab::Utils::StrongMemoize
HANDLER_REGEX = /\A#{HANDLER_ACTION_BASE_REGEX}-issue-\z/.freeze
HANDLER_REGEX_LEGACY = /\A(?<project_path>[^\+]*)\z/.freeze
......@@ -62,18 +63,59 @@ module Gitlab
project,
User.support_bot,
title: issue_title,
description: message_including_reply,
description: message_including_template,
confidential: true,
service_desk_reply_to: from_address
).execute
raise InvalidIssueError unless @issue.persisted?
if service_desk_setting&.issue_template_missing?
create_template_not_found_note(@issue)
end
end
def send_thank_you_email!
Notify.service_desk_thank_you_email(@issue.id).deliver_later!
end
def message_including_template
description = message_including_reply
template_content = service_desk_setting&.issue_template_content
if template_content.present?
description += " \n" + template_content
end
description
end
def service_desk_setting
strong_memoize(:service_desk_setting) do
project.service_desk_setting
end
end
def create_template_not_found_note(issue)
issue_template_key = service_desk_setting&.issue_template_key
warning_note = <<-MD.strip_heredoc
WARNING: The template file #{issue_template_key}.md used for service desk issues is empty or could not be found.
Please check service desk settings and update the file to be used.
MD
note_params = {
noteable: issue,
note: warning_note
}
::Notes::CreateService.new(
project,
User.support_bot,
note_params
).execute
end
def from_address
(mail.reply_to || []).first || mail.from.first || mail.sender
end
......
......@@ -37,6 +37,30 @@ describe Projects::ServiceDeskController do
expect(response.status).to eq(404)
end
end
context 'when issue template is present' do
it 'returns template_file_missing as false' do
template_path = '.gitlab/issue_templates/service_desk.md'
project.repository.create_file(user, template_path, 'text from template', message: 'message', branch_name: 'master')
ServiceDeskSetting.update_template_key_for(project: project, issue_template_key: 'service_desk')
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }, format: :json
response_hash = JSON.parse(response.body)
expect(response_hash['template_file_missing']).to eq(false)
end
end
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)
get :show, params: { namespace_id: project.namespace.to_param, project_id: project }, format: :json
expect(json_response['template_file_missing']).to eq(true)
end
end
end
describe 'PUT service desk properties' do
......@@ -50,6 +74,20 @@ describe Projects::ServiceDeskController do
expect(response.status).to eq(200)
end
it 'sets issue_template_key' do
template_path = '.gitlab/issue_templates/service_desk.md'
project.repository.create_file(user, template_path, 'template text', message: 'message', branch_name: 'master')
ServiceDeskSetting.update_template_key_for(project: project, issue_template_key: 'service_desk')
put :update, params: { namespace_id: project.namespace.to_param, project_id: project, issue_template_key: 'service_desk' }, format: :json
settings = project.service_desk_setting
expect(settings).to be_present
expect(settings.issue_template_key).to eq('service_desk')
expect(json_response['template_file_missing']).to eq(false)
expect(json_response['issue_template_key']).to eq('service_desk')
end
context 'when user cannot admin the project' do
let(:other_user) { create(:user) }
......
......@@ -11,11 +11,11 @@ describe Gitlab::Email::Handler::EE::ServiceDeskHandler do
end
let(:email_raw) { email_fixture('emails/service_desk.eml', dir: 'ee') }
let(:namespace) { create(:namespace, name: "email") }
let_it_be(:namespace) { create(:namespace, name: "email") }
let(:expected_description) { "Service desk stuff!\n\n```\na = b\n```\n\n![image](uploads/image.png)" }
context 'service desk is enabled for the project' do
let(:project) { create(:project, :public, namespace: namespace, path: 'test', service_desk_enabled: true) }
let_it_be(:project) { create(:project, :repository, :public, namespace: namespace, path: 'test', service_desk_enabled: true) }
before do
allow(::EE::Gitlab::ServiceDesk).to receive(:enabled?).and_return(true)
......@@ -52,6 +52,63 @@ describe Gitlab::Email::Handler::EE::ServiceDeskHandler do
it_behaves_like 'a new issue request'
end
context 'when using issue templates' do
let_it_be(:user) { create(:user) }
before do
setup_attachment
end
context 'and template is present' do
it 'appends template text to issue description' do
template_path = '.gitlab/issue_templates/service_desk.md'
project.repository.create_file(user, template_path, 'text from template', message: 'message', branch_name: 'master')
ServiceDeskSetting.update_template_key_for(project: project, issue_template_key: 'service_desk')
receiver.execute
issue_description = Issue.last.description
expect(issue_description).to include(expected_description)
expect(issue_description.lines.last).to eq('text from template')
end
end
context 'and template cannot be found' do
before do
service = ServiceDeskSetting.new(project_id: project.id, issue_template_key: 'unknown')
service.save(validate: false)
end
it 'does not append template text to issue description' do
receiver.execute
new_issue = Issue.last
expect(new_issue.description).to eq(expected_description.strip)
end
it 'creates support bot note on issue' do
receiver.execute
note = Note.last
expect(note.note).to include("WARNING: The template file unknown.md used for service desk issues is empty or could not be found.")
expect(note.author).to eq(User.support_bot)
end
it 'does not send warning note email' do
ActionMailer::Base.deliveries = []
perform_enqueued_jobs do
expect { receiver.execute }.to change { ActionMailer::Base.deliveries.size }.by(1)
end
# Only sends created issue email
expect(ActionMailer::Base.deliveries.last.text_part.body).to include("Thank you for your support request!")
end
end
end
end
describe '#can_handle?' do
......
# frozen_string_literal: true
require 'spec_helper'
describe ServiceDeskSetting do
describe 'validations' do
it { is_expected.to validate_presence_of(:project_id) }
end
describe 'associations' do
it { is_expected.to belong_to(:project) }
end
describe '.update_template_key_for' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
context 'when template exists' do
it 'updates issue_template_key' do
template_path = '.gitlab/issue_templates/service_desk.md'
project.repository.create_file(user, template_path, 'Template text', message: 'message', branch_name: 'master')
described_class.update_template_key_for(project: project, issue_template_key: 'service_desk')
expect(project.service_desk_setting.issue_template_key).to eq('service_desk')
end
end
context 'when template does not exist' do
it 'raises error' do
expect do
described_class.update_template_key_for(project: project, issue_template_key: 'unknown')
end.to raise_error(ActiveRecord::RecordInvalid)
end
end
end
end
......@@ -275,3 +275,4 @@ ee:
- :unprotect_access_levels
- protected_environments:
- :deploy_access_levels
- :service_desk_setting
......@@ -432,6 +432,7 @@ project:
- downstream_projects
- upstream_project_subscriptions
- downstream_project_subscriptions
- service_desk_setting
award_emoji:
- awardable
- user
......
......@@ -762,3 +762,6 @@ ZoomMeeting:
- url
- created_at
- updated_at
ServiceDeskSetting:
- project_id
- issue_template_key
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