TP-54496 | Created justification message prompt for de-escalation (#360)
* TP-54496| created justification message prompt for de-escalation * TP-54496| added migration file to update new column in log table * TP-54496| added feature flag * TP-54496| created util functions and constants * TP-54496| updated design changes * TP-54496| made the requested changed in PR comments * TP-54496| fixed bugs in merge conflicts * TP-54496| acknowledging to slack before hand so to not time out * TP-54496| modified log entity field justification --------- Co-authored-by: Shashank Shekhar <shashank.shekhar@navi.com>
This commit is contained in:
committed by
GitHub
parent
44756e482d
commit
a4c648649b
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/spf13/viper"
|
||||
incidentHelper "houston/common/util"
|
||||
"houston/common/util/structUtil"
|
||||
"houston/internal/processor/action/view"
|
||||
"houston/logger"
|
||||
"houston/model/incident"
|
||||
@@ -48,6 +49,11 @@ func NewIncidentUpdateSeverityAction(
|
||||
}
|
||||
}
|
||||
|
||||
type JustificationMetadata struct {
|
||||
SeverityId uint
|
||||
ChannelId string
|
||||
}
|
||||
|
||||
func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverityRequestProcess(callback slack.InteractionCallback, request *socketmode.Request) {
|
||||
incidentSeverity, err := isp.severityRepository.GetAllActiveSeverity()
|
||||
if err != nil || incidentSeverity == nil {
|
||||
@@ -68,9 +74,53 @@ func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverityRequestProcess(c
|
||||
isp.client.Ack(*request, payload)
|
||||
|
||||
}
|
||||
func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverityJustification(callback slack.InteractionCallback, request *socketmode.Request, user slack.User) {
|
||||
var justificationMetadata JustificationMetadata
|
||||
err := structUtil.StringToStruct(callback.View.PrivateMetadata, &justificationMetadata)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("error in converting string to justification metadata for trigger id: %s, privatemetadata: %s",
|
||||
callback.TriggerID, callback.View.PrivateMetadata), zap.Error(err))
|
||||
return
|
||||
}
|
||||
severityId := justificationMetadata.SeverityId
|
||||
channelId := justificationMetadata.ChannelId
|
||||
|
||||
incidentEntity, err := isp.incidentRepository.FindIncidentByChannelId(channelId)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("error in fetching incident with channel id: %s", channelId), zap.Error(err))
|
||||
return
|
||||
} else if incidentEntity == nil {
|
||||
logger.Error(fmt.Sprintf("incident not found with channel id: %s", channelId))
|
||||
return
|
||||
}
|
||||
|
||||
teamEntity, _, incidentStatusEntity, incidentChannels, err := isp.incidentServiceV2.FetchAllEntitiesForIncident(incidentEntity)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("error in fetching entities for incident with id: %d", incidentEntity.ID), zap.Error(err))
|
||||
return
|
||||
}
|
||||
var payload interface{}
|
||||
isp.client.Ack(*request, payload)
|
||||
if err := isp.incidentServiceV2.UpdateSeverityId(
|
||||
service.UpdateIncidentRequest{
|
||||
Id: incidentEntity.ID,
|
||||
SeverityId: strconv.Itoa(int(severityId)),
|
||||
Justification: callback.View.State.Values[view.JustificationBlockId][view.JustificationActionId].Value,
|
||||
},
|
||||
user.ID,
|
||||
incidentEntity,
|
||||
teamEntity,
|
||||
incidentStatusEntity,
|
||||
incidentChannels,
|
||||
); err != nil {
|
||||
logger.Error(fmt.Sprintf("error in updating severity: %v", err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverity(callback slack.InteractionCallback, request *socketmode.Request, channel slack.Channel, user slack.User) {
|
||||
incidentEntity, err := isp.incidentRepository.FindIncidentByChannelId(callback.View.PrivateMetadata)
|
||||
channelId := callback.View.PrivateMetadata
|
||||
incidentEntity, err := isp.incidentRepository.FindIncidentByChannelId(channelId)
|
||||
if err != nil {
|
||||
logger.Error("FindIncidentByChannelId error",
|
||||
zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name),
|
||||
@@ -86,13 +136,28 @@ func (isp *IncidentUpdateSevertityAction) IncidentUpdateSeverity(callback slack.
|
||||
incidentSeverityId := buildUpdateIncidentSeverityRequest(callback.View.State.Values)
|
||||
|
||||
if viper.GetBool("UPDATE_INCIDENT_V2_ENABLED") {
|
||||
var payload interface{}
|
||||
isp.client.Ack(*request, payload)
|
||||
teamEntity, _, incidentStatusEntity, incidentChannels, err := isp.incidentServiceV2.FetchAllEntitiesForIncident(incidentEntity)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("error in fetching entities for incident with id: %d %v", incidentEntity.ID, err))
|
||||
return
|
||||
}
|
||||
var payload interface{}
|
||||
isp.client.Ack(*request, payload)
|
||||
if viper.GetBool("ENABLE_DE_ESCALATION_JUSTIFICATION") {
|
||||
if uint(incidentSeverityId) > incidentEntity.SeverityId {
|
||||
justificationMetadata := JustificationMetadata{SeverityId: uint(incidentSeverityId), ChannelId: channelId}
|
||||
stringData, stringErr := structUtil.StructToString(justificationMetadata)
|
||||
if stringErr != nil {
|
||||
logger.Error(fmt.Sprintf("error in converting justification metadata to string for incident id: %d", incidentEntity.ID), zap.Error(stringErr))
|
||||
}
|
||||
_, viewErr := isp.client.OpenView(callback.TriggerID, view.CreateSeverityJustificationBlock(stringData))
|
||||
if viewErr != nil {
|
||||
logger.Error(fmt.Sprintf("error in opening justification view for incident with id: %d", incidentEntity.ID), zap.Error(viewErr))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := isp.incidentServiceV2.UpdateSeverityId(
|
||||
service.UpdateIncidentRequest{
|
||||
Id: incidentEntity.ID,
|
||||
|
||||
@@ -4,12 +4,17 @@ import (
|
||||
"fmt"
|
||||
"github.com/slack-go/slack"
|
||||
"github.com/slack-go/slack/socketmode"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
"houston/appcontext"
|
||||
incidentHelper "houston/common/util"
|
||||
"houston/common/util/structUtil"
|
||||
"houston/internal"
|
||||
"houston/internal/processor/action/view"
|
||||
"houston/logger"
|
||||
"houston/pkg/slackbot"
|
||||
service "houston/service/request"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -72,6 +77,47 @@ func (action *SetSeverityCommandAction) setSeverity(cmd slack.SlashCommand, seve
|
||||
logger.Error(fmt.Sprintf("%s no DB entity found for %s. %+v", setSeverityActionLogTag, severity, err))
|
||||
return fmt.Errorf("%s is not a valid severity", severity)
|
||||
}
|
||||
|
||||
if viper.GetBool("UPDATE_INCIDENT_V2_ENABLED") {
|
||||
incidentSeverityId := severityEntity.ID
|
||||
teamEntity, _, incidentStatusEntity, incidentChannels, err := appcontext.GetIncidentService().FetchAllEntitiesForIncident(incidentEntity)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("error in fetching entities for incident with id: %d %v", incidentEntity.ID, err))
|
||||
return err
|
||||
}
|
||||
if viper.GetBool("ENABLE_DE_ESCALATION_JUSTIFICATION") {
|
||||
if incidentSeverityId > incidentEntity.SeverityId {
|
||||
justificationMetadata := JustificationMetadata{SeverityId: incidentSeverityId, ChannelId: cmd.ChannelID}
|
||||
stringData, stringErr := structUtil.StructToString(justificationMetadata)
|
||||
if stringErr != nil {
|
||||
logger.Error(fmt.Sprintf("error in converting justification metadata to string for incident id: %d", incidentEntity.ID), zap.Error(stringErr))
|
||||
}
|
||||
_, viewErr := action.socketModeClient.OpenView(cmd.TriggerID, view.CreateSeverityJustificationBlock(stringData))
|
||||
if viewErr != nil {
|
||||
logger.Error(fmt.Sprintf("error in opening justification view for incident with id: %d", incidentEntity.ID), zap.Error(viewErr))
|
||||
return viewErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := appcontext.GetIncidentService().UpdateSeverityId(
|
||||
service.UpdateIncidentRequest{
|
||||
Id: incidentEntity.ID,
|
||||
SeverityId: strconv.Itoa(int(incidentSeverityId)),
|
||||
},
|
||||
cmd.UserID,
|
||||
incidentEntity,
|
||||
teamEntity,
|
||||
incidentStatusEntity,
|
||||
incidentChannels,
|
||||
); err != nil {
|
||||
logger.Error(fmt.Sprintf("error in updating severity: %v", err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
incidentEntity.SeverityId = severityEntity.ID
|
||||
incidentEntity.UpdatedBy = cmd.UserID
|
||||
incidentEntity.SeverityTat = time.Now().AddDate(0, 0, severityEntity.Sla)
|
||||
|
||||
@@ -9,6 +9,11 @@ import (
|
||||
"github.com/slack-go/slack"
|
||||
)
|
||||
|
||||
const (
|
||||
JustificationBlockId = "justificationBlockId"
|
||||
JustificationActionId = "justificationActionId"
|
||||
)
|
||||
|
||||
func BuildIncidentUpdateSeverityModal(channelID string, incidentSeverity []severity.SeverityEntity) slack.ModalViewRequest {
|
||||
titleText := slack.NewTextBlockObject(slack.PlainTextType, "Set severity of incident", false, false)
|
||||
closeText := slack.NewTextBlockObject(slack.PlainTextType, "Close", false, false)
|
||||
@@ -51,3 +56,31 @@ func createIncidentSeverityBlock(options []severity.SeverityEntity) []*slack.Opt
|
||||
}
|
||||
return optionBlockObjects
|
||||
}
|
||||
|
||||
func CreateSeverityJustificationBlock(metadata string) slack.ModalViewRequest {
|
||||
subTitle := slack.NewTextBlockObject(slack.PlainTextType, "Justification", false, false)
|
||||
closeText := slack.NewTextBlockObject(slack.PlainTextType, "Close", false, false)
|
||||
submitText := slack.NewTextBlockObject(slack.PlainTextType, "Submit", false, false)
|
||||
|
||||
inputPlaceHolder := slack.NewTextBlockObject(slack.PlainTextType, "Provide reason for reducing the severity of this incident", false, false)
|
||||
|
||||
inputElement := slack.NewPlainTextInputBlockElement(inputPlaceHolder, JustificationActionId)
|
||||
inputElement.MaxLength = 100
|
||||
justificationBlock := slack.NewInputBlock(JustificationBlockId, subTitle, nil, inputElement)
|
||||
justificationBlock.Optional = false
|
||||
|
||||
blocks := slack.Blocks{
|
||||
BlockSet: []slack.Block{
|
||||
justificationBlock,
|
||||
},
|
||||
}
|
||||
return slack.ModalViewRequest{
|
||||
Type: slack.VTModal,
|
||||
Title: subTitle,
|
||||
Close: closeText,
|
||||
Submit: submitText,
|
||||
Blocks: blocks,
|
||||
PrivateMetadata: metadata,
|
||||
CallbackID: util.SeverityJustificationSubmit,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +295,10 @@ func (vsp *ViewSubmissionProcessor) ProcessCommand(callback slack.InteractionCal
|
||||
{
|
||||
vsp.incidentUpdateSeverityAction.IncidentUpdateSeverity(callback, request, callback.Channel, callback.User)
|
||||
}
|
||||
case util.SeverityJustificationSubmit:
|
||||
{
|
||||
vsp.incidentUpdateSeverityAction.IncidentUpdateSeverityJustification(callback, request, callback.User)
|
||||
}
|
||||
case util.SetIncidentTypeSubmit:
|
||||
{
|
||||
vsp.incidentUpdateTypeAction.IncidentUpdateType(callback, request, callback.Channel, callback.User)
|
||||
|
||||
Reference in New Issue
Block a user