Files
houston-be/service/incident_service.go
Shashank Shekhar 36d590221c INFRA-2829 | Implemented transaction in create incident flow (#371)
* INFRA-2829 | Implemented transaction in create incident flow

* INFRA-2829 | created util func for rollback

* INFRA-2829 | removed redundant cod to create slack channel
2024-02-16 14:47:22 +05:30

796 lines
28 KiB
Go

package service
import (
"encoding/json"
"errors"
"fmt"
"houston/appcontext"
"houston/common/util"
slackUtil "houston/common/util/slack"
"houston/internal/processor/action"
"houston/internal/processor/action/view"
logger "houston/logger"
"houston/model/incident"
"houston/model/log"
"houston/model/severity"
"houston/model/team"
"houston/model/user"
"houston/pkg/slackbot"
incidentV2 "houston/service/incident"
"houston/service/incident/impl"
rcaService "houston/service/rca/impl"
request "houston/service/request"
incidentRequest "houston/service/request/incident"
service "houston/service/response"
common "houston/service/response/common"
slack2 "houston/service/slack"
utils "houston/service/utils"
"math"
"net/http"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/slack-go/slack"
"github.com/slack-go/slack/socketmode"
"github.com/spf13/viper"
"github.com/thoas/go-funk"
"go.uber.org/zap"
"gorm.io/gorm"
)
type incidentService struct {
gin *gin.Engine
db *gorm.DB
socketModeClient *socketmode.Client
teamRepository *team.Repository
severityRepository *severity.Repository
incidentRepository *incident.Repository
userRepository *user.Repository
messageUpdateAction *action.IncidentChannelMessageUpdateAction
slackbotClient *slackbot.Client
slackService slack2.ISlackService
incidentServiceV2 *impl.IncidentServiceV2
rcaService *rcaService.RcaService
}
func NewIncidentService(gin *gin.Engine, db *gorm.DB, socketModeClient *socketmode.Client) *incidentService {
severityRepository := severity.NewSeverityRepository(db)
logRepository := log.NewLogRepository(db)
teamRepository := team.NewTeamRepository(db, logRepository)
incidentRepository := incident.NewIncidentRepository(db, severityRepository, logRepository, teamRepository, socketModeClient)
userRepository := user.NewUserRepository(db)
messageUpdateAction := action.NewIncidentChannelMessageUpdateAction(
socketModeClient, incidentRepository, teamRepository, severityRepository)
slackBot := slackbot.NewSlackClient(socketModeClient)
incidentServiceV2 := impl.NewIncidentServiceV2(db)
rcaService := appcontext.GetRCAService()
return &incidentService{
gin: gin,
db: db,
socketModeClient: socketModeClient,
teamRepository: teamRepository,
severityRepository: severityRepository,
incidentRepository: incidentRepository,
userRepository: userRepository,
messageUpdateAction: messageUpdateAction,
slackbotClient: slackBot,
slackService: appcontext.GetSlackService(),
incidentServiceV2: incidentServiceV2,
rcaService: rcaService,
}
}
func (i *incidentService) GetIncidents(c *gin.Context) {
IncidentId := c.Param("id")
TeamIds := c.Query("team_ids")
SeverityIds := c.Query("severity_ids")
Status := c.Query("statuses")
IncidentName := c.Query("incident_name")
From := c.Query("from")
To := c.Query("to")
if IncidentId != "" {
numIncidentId, err := strconv.Atoi(IncidentId)
if err != nil {
logger.Error("error in converting string to int", zap.String("IncidentId", IncidentId), zap.Error(err))
c.JSON(http.StatusBadGateway, common.ErrorResponse(err, http.StatusBadRequest, nil))
}
incidentEntity, err := i.incidentRepository.FindIncidentById(uint(numIncidentId))
if err != nil {
logger.Error("error in finding incident by id", zap.Int("numIncidentId", numIncidentId))
c.JSON(http.StatusBadGateway, common.ErrorResponse(err, http.StatusBadRequest, nil))
}
incidentResponse, _ := i.rcaService.GetIncidentResponseWithRCALink(incidentEntity)
c.JSON(http.StatusOK, common.SuccessResponse(incidentResponse, http.StatusOK))
return
}
pageSize, pageNumber, err :=
utils.ValidatePage(c.Query("page_size"), c.Query("page_number"))
if err != nil {
logger.Error("error in query parameters", zap.Int64("page_size", pageSize),
zap.Int64("page_number", pageNumber), zap.Error(err))
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
incidents, totalElements, err := i.GetAllIncidents(request.IncidentFilters{
TeamIds: TeamIds,
SeverityIds: SeverityIds,
StatusIds: Status,
PageSize: pageSize,
PageNumber: pageNumber,
IncidentName: IncidentName,
From: From,
To: To,
}, i.incidentRepository)
if err != nil {
logger.Info("error in fetching incidents", zap.Error(err))
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
incidentResponses, err := i.GetIncidentResponseFromIncidentEntity(
incidents, i.incidentRepository, i.severityRepository, i.teamRepository)
if err != nil {
logger.Error("error in GetIncidentResponseFromIncidentEntity", zap.Error(err))
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
page := common.Page{
PageSize: pageSize,
PageNumber: pageNumber,
TotalElements: totalElements,
}
c.JSON(http.StatusOK, common.SuccessPaginatedResponse(incidentResponses, common.Page{
PageSize: page.PageSize,
TotalPages: int64(math.Ceil(float64(page.TotalElements) / float64(pageSize))),
PageNumber: pageNumber,
TotalElements: page.TotalElements,
}, http.StatusOK))
}
func (i *incidentService) GetIncidentResponseFromIncidentEntity(
incidents []incident.IncidentEntity, incidentRepository *incident.Repository, severityRepository *severity.Repository,
teamRepository *team.Repository) ([]service.IncidentResponse, error) {
teams, err := teamRepository.GetAllActiveTeams()
if err != nil {
logger.Error("error in fetching teams", zap.Error(err))
return nil, err
}
severities, err := severityRepository.GetAllActiveSeverity()
if err != nil {
logger.Error("error in fetching severities", zap.Error(err))
return nil, err
}
incidentStatuses, err := incidentRepository.FetchAllIncidentStatuses()
if err != nil {
logger.Error("error in fetching incidentStatuses", zap.Error(err))
return nil, err
}
userEmailMappings, err := i.GetUserIdAndIdentityMappingOfAllIncidents(incidents)
if err != nil {
logger.Error("error in fetching user emails mapping by ids", zap.Error(err))
return nil, err
}
var incidentResponses []service.IncidentResponse = []service.IncidentResponse{}
for incidentIndex := range incidents {
incidentResponse, _ := i.rcaService.GetIncidentResponseWithRCALink(&incidents[incidentIndex])
incidentResponses = append(incidentResponses, incidentResponse)
for _, t := range *teams {
if t.ID == incidents[incidentIndex].TeamId {
incidentResponses[incidentIndex].TeamName = t.Name
}
}
for _, s := range *severities {
if s.ID == incidents[incidentIndex].SeverityId {
incidentResponses[incidentIndex].SeverityName = s.Name
}
}
for _, is := range *incidentStatuses {
if is.ID == incidents[incidentIndex].Status {
incidentResponses[incidentIndex].StatusName = is.Name
}
}
if userEmailMappings[incidents[incidentIndex].CreatedBy] != "" {
incidentResponses[incidentIndex].CreatedBy = userEmailMappings[incidents[incidentIndex].CreatedBy]
} else {
incidentResponses[incidentIndex].CreatedBy = incidents[incidentIndex].CreatedBy
}
if userEmailMappings[incidents[incidentIndex].UpdatedBy] != "" {
incidentResponses[incidentIndex].UpdatedBy = userEmailMappings[incidents[incidentIndex].UpdatedBy]
} else {
incidentResponses[incidentIndex].UpdatedBy = incidents[incidentIndex].UpdatedBy
}
}
return incidentResponses, nil
}
func (i *incidentService) GetUserIdAndIdentityMappingOfAllIncidents(incidents []incident.IncidentEntity) (
map[string]string, error) {
listOfUserIds := funk.Map(incidents, func(incd incident.IncidentEntity) string {
return incd.CreatedBy
}).([]string)
listOfUserIds = append(listOfUserIds, funk.Map(incidents, func(incd incident.IncidentEntity) string {
return incd.UpdatedBy
}).([]string)...)
userIdAndIdentityMapping, err := i.slackbotClient.GetUserEmailsOrNameByIds(listOfUserIds...)
if err != nil {
logger.Error("error in fetching user emails by ids", zap.Any("listOfUserIds", listOfUserIds), zap.Error(err))
return map[string]string{}, err
}
return userIdAndIdentityMapping, nil
}
func (i *incidentService) GetAllIncidents(incidentFilters request.IncidentFilters, incidentRepository *incident.Repository) ([]incident.IncidentEntity, int, error) {
var TeamIds []uint
var SeverityIds []uint
var StatusIds []uint
if incidentFilters.TeamIds != "" {
TeamIds = i.SplitStringAndGetUintArray(incidentFilters.TeamIds)
}
if incidentFilters.SeverityIds != "" {
SeverityIds = i.SplitStringAndGetUintArray(incidentFilters.SeverityIds)
}
if incidentFilters.StatusIds != "" {
StatusIds = i.SplitStringAndGetUintArray(incidentFilters.StatusIds)
}
return incidentRepository.FetchAllIncidentsPaginated(
TeamIds, SeverityIds, StatusIds, incidentFilters.PageNumber, incidentFilters.PageSize, incidentFilters.IncidentName, incidentFilters.From, incidentFilters.To)
}
func (i *incidentService) SplitStringAndGetUintArray(str string) []uint {
uintsStr := strings.Split(str, ",")
var uints []uint
for _, uintStr := range uintsStr {
uintVal, err := strconv.ParseUint(uintStr, 10, 64)
if err != nil {
panic(err)
}
uints = append(uints, uint(uintVal))
}
return uints
}
func (i *incidentService) GetIncidentHeader(c *gin.Context) {
var incidentHeaderResponse service.IncidentHeaderResponse
severityEntities, err := i.severityRepository.GetAllActiveSeverity()
if err != nil {
logger.Error("error in fetching severities", zap.Error(err))
}
for _, severity := range *severityEntities {
severityResponse := service.IncidentHeaderOption{
Value: severity.ID,
Label: severity.Name,
}
incidentHeaderResponse.Severities = append(incidentHeaderResponse.Severities, severityResponse)
}
incidentStatusEntities, err := i.incidentRepository.FetchAllIncidentStatuses()
if err != nil {
logger.Error("error in fetching incident statuses", zap.Error(err))
}
for _, incidentStatus := range *incidentStatusEntities {
incidentStatusResponse := service.IncidentHeaderOption{
Value: incidentStatus.ID,
Label: incidentStatus.Name,
}
incidentHeaderResponse.IncidentStatuses =
append(incidentHeaderResponse.IncidentStatuses, incidentStatusResponse)
}
teamEntities, err := i.teamRepository.GetAllActiveTeams()
if err != nil {
logger.Error("error in fetching severities", zap.Error(err))
}
for _, team := range *teamEntities {
teamResponse := service.IncidentHeaderOption{
Value: team.ID,
Label: team.Name,
}
incidentHeaderResponse.Teams = append(incidentHeaderResponse.Teams, teamResponse)
}
c.JSON(http.StatusMultiStatus, common.SuccessResponse(incidentHeaderResponse, http.StatusMultiStatus))
}
func (i *incidentService) GetTeamIncidents(c *gin.Context) {
var Statuses string
InputStatuses := c.Query("statuses")
if InputStatuses == "" {
incidentStatuses, err := i.incidentRepository.FetchAllIncidentStatuses()
if err != nil {
logger.Error("error in fetching incident statuses", zap.Error(err))
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
for _, incidentStatus := range *incidentStatuses {
if incidentStatus.IsTerminalStatus != true {
Statuses += fmt.Sprintf("%d,", incidentStatus.ID)
}
}
Statuses = Statuses[:len(Statuses)-1]
}
incidents, _, err := i.GetAllIncidents(request.IncidentFilters{
TeamIds: c.Param("teamId"),
StatusIds: Statuses,
PageNumber: 0,
PageSize: viper.GetInt64("CRM_TEAM_INCIDENT_COUNT"),
}, i.incidentRepository)
if err != nil {
logger.Error("error in fetching incidents", zap.Error(err))
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
c.JSON(http.StatusOK, common.SuccessResponse(incidents, http.StatusOK))
}
func (i *incidentService) CreateIncident(c *gin.Context) {
var createIncRequest incidentRequest.CreateIncidentRequest
if err := c.ShouldBindJSON(&createIncRequest); err != nil {
c.JSON(http.StatusInternalServerError, err)
return
}
if err := utils.ValidateCreateIncidentRequest(createIncRequest); err != nil {
logger.Error("[Create incident Api] Error while creating incident", zap.Error(err))
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
incidentDTO, err := i.buildCreateIncidentDTO(createIncRequest)
if err != nil {
c.JSON(http.StatusBadRequest, err)
}
// Save the incident to the database
tx := i.db.Begin()
defer util.RollbackTransaction(tx)
incidentEntity, err := i.incidentRepository.CreateIncidentEntity(incidentDTO, tx)
if err != nil {
logger.Error("[Create incident Api] Error while creating incident", zap.Error(err))
tx.Rollback()
return
}
teamEntity, severityEntity, incidentStatusEntity, err := i.getTeamAndSeverityAndStatus(
incidentEntity.TeamId,
incidentEntity.SeverityId,
incidentEntity.Status,
)
if err != nil {
logger.Error("[CIP] failed while getting team, severity and status", zap.Error(err))
tx.Rollback()
return
}
channel, err := appcontext.GetSlackService().CreateSlackChannel(incidentEntity.ID)
if err != nil {
logger.Error("[Create incident] Error while creating incident channel", zap.Error(err))
tx.Rollback()
return
}
tx.Commit()
incidentEntity.SlackChannel = channel.ID
incidentEntity.IncidentName = channel.Name
err = i.incidentRepository.UpdateIncident(incidentEntity)
if err != nil {
logger.Error(fmt.Sprintf("[CIP] failed to update the slack channel name for incident-id: %v", incidentEntity.ID))
return
}
// Post incident summary to Blaze Group channel and incident channel
_, err = i.postIncidentSummary(channel.ID, incidentEntity, teamEntity,
severityEntity, incidentStatusEntity)
if err != nil {
logger.Error("[Create incident] error while posting incident summary", zap.Error(err))
return
}
// Check if the user is a slack user and get the slack user id
isSlackUser, slackUser := i.userRepository.IsAHoustonUser(incidentEntity.CreatedBy)
if isSlackUser {
//Add user who created the incident
i.slackbotClient.InviteUsersToConversation(incidentEntity.SlackChannel, slackUser.SlackUserId)
}
// add default users to the incident
err = i.addDefaultUsersToIncident(channel.ID, teamEntity, severityEntity)
if err != nil {
logger.Error("[Create Incident] error while adding default users to incident", zap.Error(err))
return
}
util.TagPseOrDevOncallToIncident(channel.ID, severityEntity, teamEntity, i.slackbotClient, i.socketModeClient)
err = util.AssignResponderToIncident(
i.incidentRepository,
incidentEntity,
teamEntity, severityEntity,
i.socketModeClient,
incidentEntity.CreatedBy,
)
if err != nil {
logger.Error("[Create incident] Error while assigning responder to the incident ", zap.Error(err))
}
err = incidentV2.PostIncidentSLAMessageToChannel(incidentEntity, i.severityRepository, i.socketModeClient)
if err != nil {
return
}
go i.incidentServiceV2.HandleKrakatoaWorkflow(incidentEntity)
incidentResponse := service.ConvertToIncidentResponse(*incidentEntity)
c.JSON(http.StatusOK, common.SuccessResponse(incidentResponse, http.StatusOK))
}
func (i *incidentService) InvitePseOnCallPersonToIncident(channelId, ts string) {
go func() {
time.Sleep(3 * time.Second)
msg, _, _, _ := i.socketModeClient.GetConversationReplies(&slack.GetConversationRepliesParameters{
ChannelID: channelId,
Timestamp: ts,
Limit: 2,
},
)
if len(msg) > 1 {
//User id needs to sliced from `<@XXXXXXXXXXXX>` format to `XXXXXXXXXXXX`
i.socketModeClient.InviteUsersToConversation(channelId, msg[1].Text[2:13])
}
}()
}
func (i *incidentService) addDefaultUsersToIncident(channelId string, teamEntity *team.TeamEntity,
severityEntity *severity.SeverityEntity) error {
var userIdList []string
userIdList = append(append(userIdList, teamEntity.SlackUserIds...), severityEntity.SlackUserIds...)
for _, o := range userIdList {
i.slackbotClient.InviteUsersToConversation(channelId, o)
}
return nil
}
func (i *incidentService) postIncidentSummary(incidentChannelID string,
incidentEntity *incident.IncidentEntity, teamEntity *team.TeamEntity, severityEntity *severity.SeverityEntity,
incidentStatusEntity *incident.IncidentStatusEntity) (*string, error) {
// Post incident summary to Blaze Group channel and incident channel
blocks := view.IncidentSummarySection(incidentEntity, teamEntity, severityEntity, incidentStatusEntity)
color := util.GetColorBySeverity(incidentEntity.SeverityId)
att := slack.Attachment{Blocks: blocks, Color: color}
_, timestamp, err := i.socketModeClient.PostMessage(incidentChannelID, slack.MsgOptionAttachments(att))
if incidentEntity.MetaData != nil {
msgOption, noMetaDataError := slackUtil.BuildSlackTextMessageFromMetaData(incidentEntity.MetaData, true)
if noMetaDataError == nil {
_, _, err = i.socketModeClient.PostMessage(incidentChannelID, msgOption)
if err != nil {
return nil, err
}
}
}
if err == nil {
i.incidentRepository.CreateIncidentChannelEntry(&incident.CreateIncidentChannelEntry{
SlackChannel: incidentChannelID,
MessageTimeStamp: timestamp,
IncidentId: incidentEntity.ID,
})
} else {
return nil, fmt.Errorf("[CIP] error in saving message %v", err)
}
return &timestamp, nil
}
func (i *incidentService) getTeamAndSeverityAndStatus(teamId, severityId, status uint) (*team.TeamEntity,
*severity.SeverityEntity, *incident.IncidentStatusEntity, error) {
teamEntity, err := i.teamRepository.FindTeamById(teamId)
if err != nil || teamEntity == nil {
return nil, nil, nil, err
}
severityEntity, err := i.severityRepository.FindSeverityById(severityId)
if err != nil || severityEntity == nil {
return nil, nil, nil, err
}
incidentStatusEntity, err := i.incidentRepository.FindIncidentStatusById(status)
if err != nil || incidentStatusEntity == nil {
return nil, nil, nil, err
}
return teamEntity, severityEntity, incidentStatusEntity, nil
}
func (i *incidentService) buildCreateIncidentDTO(createIncRequest incidentRequest.CreateIncidentRequest) (*incident.CreateIncidentDTO, error) {
var createIncidentRequest incident.CreateIncidentDTO
teamEntity, err := i.teamRepository.FindTeamByTeamName(createIncRequest.TeamName)
if err != nil {
return nil, err
}
severityEntity, err := i.severityRepository.FindSeverityByName(createIncRequest.SeverityName)
if err != nil {
return nil, err
}
var rawJson, _ = json.Marshal([]incidentRequest.CreateIncidentMetaData{createIncRequest.MetaData})
createdBy := slackUtil.GetSlackUserIdFromEmail(createIncRequest.CreatedBy, i.slackbotClient)
createIncidentRequest.Title = createIncRequest.Title
createIncidentRequest.Description = createIncRequest.Description
createIncidentRequest.Severity = fmt.Sprintf("%d", severityEntity.ID)
createIncidentRequest.TeamId = fmt.Sprintf("%d", teamEntity.ID)
createIncidentRequest.Status = incident.Investigating
createIncidentRequest.CreatedBy = createdBy
createIncidentRequest.UpdatedBy = createdBy
createIncidentRequest.StartTime = time.Now()
createIncidentRequest.EnableReminder = false
createIncidentRequest.MetaData = rawJson
return &createIncidentRequest, nil
}
func (i *incidentService) UpdateIncident(c *gin.Context) {
userEmail := c.GetHeader("X-User-Email")
var updateIncidentRequest request.UpdateIncidentRequest
if err := c.ShouldBindJSON(&updateIncidentRequest); err != nil {
c.JSON(http.StatusInternalServerError, err)
return
}
err := utils.ValidateUpdateIncidentRequest(updateIncidentRequest, userEmail)
if err != nil {
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
incidentEntity, err := i.incidentRepository.FindIncidentById(updateIncidentRequest.Id)
if err != nil {
logger.Error("error in fetching incident", zap.Any("incidentId", updateIncidentRequest.Id), zap.Error(err))
c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
if incidentEntity == nil {
logger.Info("incident not found", zap.Any("incidentId", updateIncidentRequest.Id))
c.JSON(http.StatusBadRequest, common.ErrorResponse(errors.New(fmt.Sprintf("incident with id: %v not found", updateIncidentRequest.Id)), http.StatusBadRequest, nil))
return
}
userInfo, err := i.slackbotClient.GetUserByEmail(userEmail)
if err != nil {
logger.Error(fmt.Sprintf("error in fetching user by email: %v, hence using user email as user Id", userEmail), zap.String("userEmail", userEmail), zap.Error(err))
userInfo = &slack.User{
ID: userEmail,
}
}
err = i.UpdateSeverityId(updateIncidentRequest, userInfo.ID, incidentEntity)
if err != nil {
logger.Error("error in updating severity", zap.Error(err))
c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
err = i.UpdateStatus(updateIncidentRequest, userInfo.ID, incidentEntity.SlackChannel, incidentEntity)
if err != nil {
logger.Error("error in updating status", zap.Error(err))
c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
err = i.UpdateTeamId(updateIncidentRequest, userInfo.ID, incidentEntity)
if err != nil {
logger.Error("error in updating teamId", zap.Error(err))
c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
err = i.UpdateMetaData(updateIncidentRequest, incidentEntity, userInfo.ID)
if err != nil {
logger.Error("error in updating metadata", zap.Error(err))
c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusBadRequest, nil))
return
}
incidentEntity.UpdatedAt = time.Now()
incidentEntity.UpdatedBy = userInfo.ID
i.incidentRepository.UpdateIncident(incidentEntity)
i.messageUpdateAction.ProcessAction(incidentEntity.SlackChannel)
if updateIncidentRequest.SeverityId != "" || updateIncidentRequest.TeamId != "" {
teamEntity, err := i.teamRepository.FindTeamById(incidentEntity.TeamId)
if err != nil {
logger.Error(fmt.Sprintf("error in fetching team by id: %v", incidentEntity.TeamId), zap.Error(err))
}
incidentSeverityEntity, err := i.severityRepository.FindIncidentSeverityEntityById(int(incidentEntity.SeverityId))
if err != nil {
logger.Error(fmt.Sprintf("error in fetching severity by id: %v", incidentEntity.SeverityId), zap.Error(err))
}
topic := fmt.Sprintf("%s-%s(%s) Incident-%d | %s", teamEntity.Name, incidentSeverityEntity.Name, incidentSeverityEntity.Description, incidentEntity.ID, incidentEntity.Title)
i.socketModeClient.SetTopicOfConversation(incidentEntity.SlackChannel, topic)
if !util.IsBlank(updateIncidentRequest.TeamId) {
go i.incidentServiceV2.HandleKrakatoaWorkflow(incidentEntity)
}
}
c.JSON(http.StatusOK, common.SuccessResponse(incidentEntity.SlackChannel, http.StatusOK))
}
func (i *incidentService) UpdateSeverityId(
updateIncidentRequest request.UpdateIncidentRequest, userId string, incidentEntity *incident.IncidentEntity) error {
if updateIncidentRequest.SeverityId != "" {
num, err := strconv.ParseUint(updateIncidentRequest.SeverityId, 10, 64)
if err != nil {
logger.Error("error in string to int conversion",
zap.String("SeverityId", updateIncidentRequest.SeverityId), zap.Error(err))
return err
}
severityEntity, err := i.severityRepository.FindSeverityById(uint(num))
if err != nil {
logger.Error("error in fetching severity", zap.Any("severity", incidentEntity.SeverityId), zap.Error(err))
return err
}
if updateIncidentRequest.SeverityId != "" {
num, err := strconv.ParseUint(updateIncidentRequest.SeverityId, 10, 64)
if err != nil {
logger.Error("error in string to int conversion",
zap.String("SeverityId", updateIncidentRequest.SeverityId), zap.Error(err))
return err
}
if incidentEntity.SeverityId != uint(num) {
incidentEntity.SeverityId = uint(num)
incidentEntity.SeverityTat = time.Now().AddDate(0, 0, severityEntity.Sla)
errMessage := util.PostIncidentSeverityUpdateMessage(userId, severityEntity.Name, incidentEntity.SlackChannel, i.socketModeClient)
if errMessage != nil {
logger.Error("post response failed for IncidentUpdateSeverity", zap.Error(errMessage))
return err
}
}
}
}
return nil
}
func (i *incidentService) UpdateStatus(
updateIncidentRequest request.UpdateIncidentRequest, userId, slackChannel string,
incidentEntity *incident.IncidentEntity) error {
if updateIncidentRequest.Status != "" {
num, err := strconv.ParseUint(updateIncidentRequest.Status, 10, 64)
if err != nil {
logger.Error("error in string to int conversion",
zap.String("Status", updateIncidentRequest.Status), zap.Error(err))
return err
}
if incidentEntity.Status != uint(num) {
incidentEntity.Status = uint(num)
incidentStatus, _ := i.incidentRepository.FindIncidentStatusById(incidentEntity.Status)
errMessage := util.PostIncidentStatusUpdateMessage(userId, incidentStatus.Name, slackChannel, i.socketModeClient)
if errMessage != nil {
logger.Error("post response failed for IncidentUpdateStatus", zap.Error(errMessage))
return err
}
if incidentStatus.IsTerminalStatus {
now := time.Now()
incidentEntity.EndTime = &now
}
}
}
return nil
}
func (i *incidentService) UpdateTeamId(
updateIncidentRequest request.UpdateIncidentRequest, userId string, incidentEntity *incident.IncidentEntity) error {
if updateIncidentRequest.TeamId != "" {
severityEntity, err := i.severityRepository.FindSeverityById(incidentEntity.SeverityId)
if err != nil {
logger.Error("error in fetching severity", zap.Any("severity", incidentEntity.SeverityId), zap.Error(err))
return err
}
if updateIncidentRequest.TeamId != "" {
num, err := strconv.ParseUint(updateIncidentRequest.TeamId, 10, 64)
if err != nil {
logger.Error("error in string to int conversion",
zap.String("TeamId", updateIncidentRequest.TeamId), zap.Error(err))
return err
}
if incidentEntity.TeamId != uint(num) {
incidentEntity.TeamId = uint(num)
teamEntity, err := i.teamRepository.FindTeamById(incidentEntity.TeamId)
if err != nil {
logger.Error("error in fetching team by id",
zap.String("TeamId", updateIncidentRequest.TeamId), zap.Error(err))
return err
}
errMessage := util.PostIncidentTypeUpdateMessage(
userId, teamEntity.Name, severityEntity.Name, severityEntity.Description,
incidentEntity.IncidentName, incidentEntity.Title, incidentEntity.SlackChannel, i.socketModeClient)
if errMessage != nil {
logger.Error("post response failed for IncidentUpdateType", zap.Error(errMessage))
return err
}
err = i.addDefaultUsersToIncident(incidentEntity.SlackChannel, teamEntity, severityEntity)
if err != nil {
logger.Error("[Update Incident] error while adding default users to incident", zap.Error(err))
return err
}
util.TagPseOrDevOncallToIncident(
incidentEntity.SlackChannel,
severityEntity,
teamEntity,
i.slackbotClient,
i.socketModeClient,
)
err = util.AssignResponderToIncident(
i.incidentRepository,
incidentEntity,
teamEntity,
severityEntity,
i.socketModeClient,
incidentEntity.UpdatedBy,
)
if err != nil {
logger.Error("[Update Incident][update team id] error while assigning responder to the incident ", zap.Error(err))
}
}
}
}
return nil
}
func (i *incidentService) UpdateMetaData(updateIncidentRequest request.UpdateIncidentRequest, incidentEntity *incident.IncidentEntity, userId string) error {
metaData := incidentRequest.CreateIncidentMetaData{}
if updateIncidentRequest.MetaData != metaData {
metaData.CrmTicketCreationTime = updateIncidentRequest.MetaData.CrmTicketCreationTime
metaData.CustomerId = updateIncidentRequest.MetaData.CustomerId
metaData.PhoneNumber = updateIncidentRequest.MetaData.PhoneNumber
metaData.TicketId = updateIncidentRequest.MetaData.TicketId
metaData.AgentName = updateIncidentRequest.MetaData.AgentName
metaData.TicketGroup = updateIncidentRequest.MetaData.TicketGroup
var incidentMetadata []incidentRequest.CreateIncidentMetaData
if incidentEntity.MetaData != nil {
err := json.Unmarshal(incidentEntity.MetaData, &incidentMetadata)
if err != nil {
logger.Error("error occurred while converting incident metadata to json", zap.Error(err))
return err
}
}
incidentMetadata = append(incidentMetadata, metaData)
var err error
incidentEntity.MetaData, err = json.Marshal(incidentMetadata)
if err != nil {
logger.Error("error occurred while converting incident metadata to json", zap.Error(err))
return err
}
errMessage := slackUtil.PostIncidentCustomerDataUpdateMessage(updateIncidentRequest.MetaData, userId, incidentEntity.SlackChannel, i.socketModeClient)
if errMessage != nil {
logger.Error("post response failed for IncidentUpdateCustomerData", zap.Error(errMessage))
return errMessage
}
}
return nil
}