* NTP-22602 : Disable sla breach message and auto escalation in sev-1 to sev-0 cases * NTP-22602 : Make env vars for severities * NTP-22602 : Query fix * NTP-22602 : Add to application.properties file --------- Co-authored-by: Vijay Joshi <ee-automation@navi.com>
752 lines
22 KiB
Go
752 lines
22 KiB
Go
package incident
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/slack-go/slack/socketmode"
|
|
"github.com/spf13/viper"
|
|
"go.uber.org/zap"
|
|
"houston/logger"
|
|
"houston/model/log"
|
|
"houston/model/product"
|
|
"houston/model/team"
|
|
"houston/service/incidentStatus"
|
|
"houston/service/severity"
|
|
utils "houston/service/utils"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type Repository struct {
|
|
gormClient *gorm.DB
|
|
logRepository *log.Repository
|
|
teamRepository *team.Repository
|
|
socketModeClient *socketmode.Client
|
|
severityService severity.ISeverityService
|
|
incidentStatusService incidentStatus.IncidentStatusService
|
|
}
|
|
|
|
var valueBeforeUpdate IncidentEntity
|
|
var valueAfterUpdate IncidentEntity
|
|
var valueBeforeCreate IncidentEntity
|
|
var valueAfterCreate IncidentEntity
|
|
var differences []utils.Difference
|
|
|
|
func NewIncidentRepository(
|
|
gormClient *gorm.DB,
|
|
severityService severity.ISeverityService,
|
|
incidentStatusService incidentStatus.IncidentStatusService,
|
|
logRepository *log.Repository,
|
|
teamRepository *team.Repository,
|
|
socketModeClient *socketmode.Client,
|
|
) *Repository {
|
|
return &Repository{
|
|
gormClient: gormClient,
|
|
severityService: severityService,
|
|
incidentStatusService: incidentStatusService,
|
|
logRepository: logRepository,
|
|
teamRepository: teamRepository,
|
|
socketModeClient: socketModeClient,
|
|
}
|
|
}
|
|
|
|
func (r *Repository) CreateIncidentEntity(request *CreateIncidentDTO, tx *gorm.DB) (*IncidentEntity, error) {
|
|
severityId, err := strconv.Atoi(request.Severity)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("fetch channel conversationInfo failed. err: %v", err)
|
|
}
|
|
severity, err := r.severityService.FindSeverityById(uint(severityId))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("fetch FindSeverityById failed. err: %v", err)
|
|
}
|
|
|
|
teamId, _ := strconv.Atoi(request.TeamId)
|
|
incidentStatus, _ := r.incidentStatusService.GetIncidentStatusByStatusName(string(request.Status))
|
|
var products = make([]product.ProductEntity, 0)
|
|
for _, productId := range request.ProductIds {
|
|
products = append(products, product.ProductEntity{ID: productId})
|
|
}
|
|
|
|
incidentEntity := &IncidentEntity{
|
|
Title: request.Title,
|
|
Description: request.Description,
|
|
Status: incidentStatus.ID,
|
|
SeverityId: uint(severityId),
|
|
DetectionTime: request.DetectionTime,
|
|
StartTime: request.StartTime,
|
|
TeamId: uint(teamId),
|
|
EnableReminder: request.EnableReminder,
|
|
SeverityTat: time.Now().AddDate(0, 0, severity.Sla),
|
|
CreatedBy: request.CreatedBy,
|
|
UpdatedBy: request.UpdatedBy,
|
|
MetaData: request.MetaData,
|
|
ReportingTeamId: request.ReportingTeamID,
|
|
Products: products,
|
|
IsPrivate: request.IsPrivate,
|
|
}
|
|
|
|
tx.Create(incidentEntity)
|
|
|
|
return incidentEntity, nil
|
|
}
|
|
|
|
func (i *IncidentEntity) AfterCreate(tx *gorm.DB) (err error) {
|
|
println(fmt.Sprintf("AfterUpdate executed at: %v", time.Now()))
|
|
valueBeforeCreate = IncidentEntity{}
|
|
valueAfterCreate = IncidentEntity{}
|
|
if err := tx.First(&valueAfterCreate, i.ID).Error; err != nil {
|
|
return err
|
|
}
|
|
println(fmt.Sprintf("incident entity after created is: %s", valueAfterCreate))
|
|
differences = utils.DeepCompare(valueBeforeCreate, valueAfterCreate)
|
|
return nil
|
|
}
|
|
|
|
func (i *IncidentEntity) BeforeUpdate(tx *gorm.DB) (err error) {
|
|
println(fmt.Sprintf("BeforeUpdate executed at: %v", time.Now()))
|
|
valueBeforeUpdate = IncidentEntity{}
|
|
if err := tx.First(&valueBeforeUpdate, i.ID).Error; err != nil {
|
|
return err
|
|
}
|
|
println(fmt.Sprintf("incident entity before update is: %s", valueBeforeUpdate))
|
|
return nil
|
|
}
|
|
|
|
func (i *IncidentEntity) AfterUpdate(tx *gorm.DB) (err error) {
|
|
println(fmt.Sprintf("AfterUpdate executed at: %v", time.Now()))
|
|
valueAfterUpdate = IncidentEntity{}
|
|
if err := tx.First(&valueAfterUpdate, i.ID).Error; err != nil {
|
|
return err
|
|
}
|
|
println(fmt.Sprintf("incident entity after updated is: %s", valueAfterUpdate))
|
|
differences = append(differences, utils.DeepCompare(valueBeforeUpdate, valueAfterUpdate)...)
|
|
return nil
|
|
}
|
|
|
|
func (r *Repository) processDiffIds() []byte {
|
|
var jsonDiff []byte
|
|
|
|
for index := range differences {
|
|
switch differences[index].Attribute {
|
|
case "Status":
|
|
if differences[index].From != "" {
|
|
statusIdString, _ := strconv.Atoi(differences[index].From)
|
|
fromStatus, _ := r.incidentStatusService.GetIncidentStatusByStatusId(uint(statusIdString))
|
|
if fromStatus != nil {
|
|
differences[index].From = fromStatus.Name
|
|
}
|
|
}
|
|
|
|
statusIdString, _ := strconv.Atoi(differences[index].To)
|
|
toStatus, _ := r.incidentStatusService.GetIncidentStatusByStatusId(uint(statusIdString))
|
|
differences[index].To = toStatus.Name
|
|
|
|
case "SeverityId":
|
|
if differences[index].From != "" {
|
|
severityIdString, _ := strconv.Atoi(differences[index].From)
|
|
severityEntity, _ := r.severityService.FindSeverityById(uint(severityIdString))
|
|
if severityEntity != nil {
|
|
differences[index].From = severityEntity.Name
|
|
}
|
|
}
|
|
|
|
severityIdString, _ := strconv.Atoi(differences[index].To)
|
|
severityEntity, _ := r.severityService.FindSeverityById(uint(severityIdString))
|
|
differences[index].To = severityEntity.Name
|
|
|
|
case "TeamId":
|
|
if differences[index].From != "" {
|
|
teamIdString, _ := strconv.Atoi(differences[index].From)
|
|
teamEntity, _ := r.teamRepository.FindTeamById(uint(teamIdString))
|
|
if teamEntity != nil {
|
|
differences[index].From = teamEntity.Name
|
|
}
|
|
}
|
|
teamIdString, _ := strconv.Atoi(differences[index].To)
|
|
teamEntity, _ := r.teamRepository.FindTeamById(uint(teamIdString))
|
|
if teamEntity != nil {
|
|
differences[index].To = teamEntity.Name
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
jsonDiff, _ = json.Marshal(differences)
|
|
|
|
return jsonDiff
|
|
}
|
|
|
|
func (r *Repository) processUserInfo() ([]byte, error) {
|
|
user, err := r.socketModeClient.GetUsersInfo(valueAfterUpdate.UpdatedBy)
|
|
|
|
if err != nil {
|
|
errorMessage := fmt.Sprintf("failed to get user info from slack for userID: %s", valueAfterUpdate.UpdatedBy)
|
|
logger.Error(errorMessage)
|
|
return nil, fmt.Errorf("%s. Error: %v", errorMessage, err)
|
|
}
|
|
|
|
if len(*user) != 0 {
|
|
userData := (*user)[0]
|
|
userInfo := log.UserInfo{
|
|
Id: userData.ID,
|
|
Email: userData.Profile.Email,
|
|
Name: userData.Profile.RealName,
|
|
}
|
|
return json.Marshal(userInfo)
|
|
}
|
|
|
|
return nil, fmt.Errorf("%s is not a valid user", valueAfterUpdate.UpdatedBy)
|
|
}
|
|
|
|
func (r *Repository) captureLogs(justification string) {
|
|
if differences != nil && len(differences) > 0 {
|
|
jsonUser, _ := r.processUserInfo()
|
|
|
|
jsonDiff := r.processDiffIds()
|
|
|
|
logEntity := log.LogEntity{
|
|
CreatedAt: time.Now(),
|
|
RelationName: "incident",
|
|
RecordId: valueAfterUpdate.ID,
|
|
UserInfo: jsonUser,
|
|
Changes: jsonDiff,
|
|
}
|
|
if justification != "" {
|
|
logEntity.Justification = justification
|
|
}
|
|
_, err := r.logRepository.CreateLog(&logEntity)
|
|
if err != nil {
|
|
logger.Error(fmt.Sprintf("%d failed to create log. Error: %v", logEntity.RecordId, err))
|
|
}
|
|
|
|
differences = []utils.Difference{}
|
|
}
|
|
}
|
|
|
|
func (r *Repository) UpdateIncident(incidentEntity *IncidentEntity) error {
|
|
result := r.gormClient.Updates(incidentEntity)
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
|
|
r.captureLogs("")
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Repository) UpdateIncidentWithAssociations(incidentEntity *IncidentEntity) error {
|
|
err := r.gormClient.Model(&incidentEntity).Association("Products").Replace(incidentEntity.Products)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
result := r.gormClient.Updates(incidentEntity)
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
r.captureLogs("")
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Repository) UpdateIncidentWithJustification(incidentEntity *IncidentEntity, justification string) error {
|
|
result := r.gormClient.Updates(incidentEntity)
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
r.captureLogs(justification)
|
|
return nil
|
|
}
|
|
|
|
func (r *Repository) FindIncidentByChannelId(channelId string) (*IncidentEntity, error) {
|
|
var incidentEntity IncidentEntity
|
|
|
|
result := r.gormClient.Preload("Products").Preload("ReportingTeam").Find(&incidentEntity, "slack_channel = ?", channelId)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
|
|
if result.RowsAffected == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
return &incidentEntity, nil
|
|
}
|
|
|
|
func (r *Repository) FindIncidentById(Id uint) (*IncidentEntity, error) {
|
|
var incidentEntity IncidentEntity
|
|
|
|
result := r.gormClient.Preload("Products").Preload("ReportingTeam").Find(&incidentEntity, "id = ?", Id)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
|
|
if result.RowsAffected == 0 {
|
|
return nil, fmt.Errorf("could not find incident with ID: %d", Id)
|
|
}
|
|
|
|
return &incidentEntity, nil
|
|
}
|
|
|
|
func (r *Repository) GetAllIncidents(teamsIds, severityIds, statusIds []uint, isPrivate *bool, isArchived *bool) (*[]IncidentEntity, int, error) {
|
|
var query = r.gormClient.Model([]IncidentEntity{})
|
|
var incidentEntity []IncidentEntity
|
|
|
|
if isArchived != nil {
|
|
query = query.Joins(
|
|
"JOIN incident_channel on incident.slack_channel = incident_channel.slack_channel "+
|
|
"and incident_channel.is_archived = ?",
|
|
isArchived,
|
|
)
|
|
}
|
|
|
|
if len(teamsIds) != 0 {
|
|
query = query.Where("team_id IN ?", teamsIds)
|
|
}
|
|
if len(severityIds) != 0 {
|
|
query = query.Where("severity_id IN ?", severityIds)
|
|
}
|
|
if len(statusIds) != 0 {
|
|
query = query.Where("status IN ?", statusIds)
|
|
}
|
|
if isPrivate != nil {
|
|
query = query.Where("is_private = ?", isPrivate)
|
|
}
|
|
|
|
var totalElements int64
|
|
result := query.Count(&totalElements)
|
|
if result.Error != nil {
|
|
return nil, 0, result.Error
|
|
}
|
|
|
|
if result.RowsAffected == 0 {
|
|
return nil, int(totalElements), nil
|
|
}
|
|
|
|
result = query.Order("created_at desc").Preload("Team").Preload("Severity").Preload("ReportingTeam").Find(&incidentEntity)
|
|
|
|
if result.Error != nil {
|
|
return nil, 0, result.Error
|
|
}
|
|
if result.RowsAffected == 0 {
|
|
return nil, int(totalElements), nil
|
|
}
|
|
|
|
return &incidentEntity, int(totalElements), nil
|
|
}
|
|
|
|
func (r *Repository) FetchAllIncidentsPaginated(
|
|
productIds []uint,
|
|
reportingTeamIds []uint,
|
|
TeamsId []uint,
|
|
SeverityIds []uint,
|
|
StatusIds []uint,
|
|
pageNumber int64,
|
|
pageSize int64,
|
|
incidentName string,
|
|
from string,
|
|
to string,
|
|
userId *uint,
|
|
) ([]IncidentEntity, int, error) {
|
|
var query = r.gormClient.Model([]IncidentEntity{}).Preload("Products")
|
|
var incidentEntity []IncidentEntity
|
|
if len(TeamsId) != 0 {
|
|
query = query.Where("team_id IN ?", TeamsId)
|
|
}
|
|
if len(reportingTeamIds) != 0 {
|
|
query = query.Where("reporting_team_id IN ?", reportingTeamIds)
|
|
}
|
|
if len(SeverityIds) != 0 {
|
|
query = query.Where("severity_id IN ?", SeverityIds)
|
|
}
|
|
if len(StatusIds) != 0 {
|
|
query = query.Where("status IN ?", StatusIds)
|
|
}
|
|
if len(strings.TrimSpace(incidentName)) != 0 {
|
|
query = query.Where("incident_name LIKE ?", "%"+incidentName+"%")
|
|
}
|
|
if len(from) != 0 {
|
|
query = query.Where("created_at >= ?", from)
|
|
}
|
|
if len(to) != 0 {
|
|
query = query.Where("created_at <= ?", to)
|
|
}
|
|
if len(productIds) != 0 {
|
|
query = query.
|
|
Joins("JOIN incident_products ON incident_products.incident_entity_id = incident.id").
|
|
Where("incident_products.product_entity_id IN ?", productIds).
|
|
Group("incident.id")
|
|
}
|
|
if userId != nil {
|
|
query = query.Where(
|
|
fmt.Sprintf("%s OR %s or %s", isPrivateCondition, incidentTeamsAccessCondition, userInIncidentCondition),
|
|
false, *userId, *userId,
|
|
)
|
|
} else {
|
|
query = query.Where("is_private = ?", false)
|
|
}
|
|
|
|
var totalElements int64
|
|
result := query.Count(&totalElements)
|
|
if result.Error != nil {
|
|
return nil, 0, result.Error
|
|
}
|
|
|
|
result = query.Order("created_at desc").Offset(int(pageNumber * pageSize)).Limit(int(pageSize)).Find(&incidentEntity)
|
|
|
|
if result.Error != nil {
|
|
return nil, 0, result.Error
|
|
}
|
|
if result.RowsAffected == 0 {
|
|
return nil, int(totalElements), nil
|
|
}
|
|
|
|
return incidentEntity, int(totalElements), nil
|
|
}
|
|
|
|
func (r *Repository) UpsertIncidentRole(addIncidentRoleRequest *AddIncidentRoleRequest) error {
|
|
incidentRolesEntity := &IncidentRoleEntity{
|
|
IncidentId: addIncidentRoleRequest.IncidentId,
|
|
Role: addIncidentRoleRequest.Role,
|
|
AssignedTo: addIncidentRoleRequest.UserId,
|
|
AssignedBy: addIncidentRoleRequest.CreatedById,
|
|
}
|
|
var incidentRole IncidentRoleEntity
|
|
|
|
result := r.gormClient.Find(&incidentRole, "incident_id = ? AND role = ?", addIncidentRoleRequest.IncidentId, addIncidentRoleRequest.Role)
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
if result.RowsAffected == 1 {
|
|
incidentRolesEntity.ID = incidentRole.ID
|
|
incidentRolesEntity.CreatedAt = incidentRole.CreatedAt
|
|
incidentRolesEntity.UpdatedAt = time.Now()
|
|
addResult := r.gormClient.Save(incidentRolesEntity)
|
|
if addResult != nil {
|
|
return addResult.Error
|
|
}
|
|
return nil
|
|
|
|
} else if result.RowsAffected == 0 {
|
|
addResult := r.gormClient.Create(incidentRolesEntity)
|
|
if addResult != nil {
|
|
return addResult.Error
|
|
}
|
|
return nil
|
|
}
|
|
return gorm.ErrInvalidData
|
|
}
|
|
|
|
func (r *Repository) CreateIncidentChannelEntry(request *CreateIncidentChannelEntry) error {
|
|
messageEntity := &IncidentChannelEntity{
|
|
SlackChannel: request.SlackChannel,
|
|
MessageTimeStamp: request.MessageTimeStamp,
|
|
IncidentId: request.IncidentId,
|
|
}
|
|
|
|
result := r.gormClient.Create(&messageEntity)
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Repository) CreateIncidentTag(incidentId, tagId uint) (*IncidentTagEntity, error) {
|
|
incidentTag := IncidentTagEntity{
|
|
IncidentId: incidentId,
|
|
TagId: tagId,
|
|
}
|
|
|
|
result := r.gormClient.Create(&incidentTag)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
return &incidentTag, nil
|
|
}
|
|
|
|
func (r *Repository) CreateIncidentTagsInBatchesForAnIncident(incidentId uint, tagIds []uint) (*[]IncidentTagEntity, error) {
|
|
var incidentTags []IncidentTagEntity
|
|
for _, tagId := range tagIds {
|
|
incidentTag := IncidentTagEntity{
|
|
IncidentId: incidentId,
|
|
TagId: tagId,
|
|
}
|
|
incidentTags = append(incidentTags, incidentTag)
|
|
}
|
|
|
|
result := r.gormClient.CreateInBatches(&incidentTags, len(incidentTags))
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
return &incidentTags, nil
|
|
}
|
|
|
|
func (r *Repository) GetIncidentChannels(incidentId uint) (*[]IncidentChannelEntity, error) {
|
|
var incidentChannels []IncidentChannelEntity
|
|
|
|
result := r.gormClient.Find(&incidentChannels, "incident_id = ?", incidentId)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
|
|
if result.RowsAffected == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
return &incidentChannels, nil
|
|
}
|
|
|
|
func (r *Repository) GetIncidentTagsByIncidentId(incidentId uint) (*[]IncidentTagEntity, error) {
|
|
var incidentTags []IncidentTagEntity
|
|
|
|
result := r.gormClient.Find(&incidentTags, "incident_id = ?", incidentId)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
if result.RowsAffected == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
return &incidentTags, nil
|
|
}
|
|
|
|
func (r *Repository) GetIncidentTagByTagId(incidentId uint, tagId uint) (*IncidentTagEntity, error) {
|
|
var incidentTag IncidentTagEntity
|
|
|
|
result := r.gormClient.Find(&incidentTag, "incident_id = ? and tag_id = ?", incidentId, tagId)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
} else if result.RowsAffected == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
return &incidentTag, nil
|
|
}
|
|
|
|
func (r *Repository) GetIncidentTagsByTagIds(incidentId uint, tagIds []uint) (*IncidentTagEntity, error) {
|
|
var incidentTag IncidentTagEntity
|
|
|
|
result := r.gormClient.Find(&incidentTag, "incident_id = ? and tag_id in ?", incidentId, tagIds)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
} else if result.RowsAffected == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
return &incidentTag, nil
|
|
}
|
|
|
|
func (r *Repository) SaveIncidentTag(entity IncidentTagEntity) (*IncidentTagEntity, error) {
|
|
tx := r.gormClient.Save(&entity)
|
|
if tx.Error != nil {
|
|
return nil, tx.Error
|
|
}
|
|
return &entity, nil
|
|
}
|
|
|
|
func (r *Repository) GetIncidentsForEscalation() ([]IncidentEntity, error) {
|
|
var incidentEntity []IncidentEntity
|
|
|
|
currentTime := time.Now()
|
|
|
|
result := r.gormClient.Find(&incidentEntity,
|
|
fmt.Sprintf("status IN (?) AND severity_id NOT IN %s AND severity_tat <= ?", viper.GetString("severities.excluded.for.escalation")),
|
|
statusesForEscalation, currentTime)
|
|
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
|
|
return incidentEntity, nil
|
|
}
|
|
|
|
func (r *Repository) GetIncidentsForMovingToInvestigating() ([]IncidentEntity, error) {
|
|
var incidentEntities []IncidentEntity
|
|
rawTeamIDs := viper.GetString("investigation.reopen.ignore.team_ids")
|
|
var teamIDsToIgnore []int
|
|
for _, str := range strings.Split(rawTeamIDs, ",") {
|
|
teamID, err := strconv.Atoi(strings.TrimSpace(str))
|
|
if err != nil {
|
|
logger.Error(fmt.Sprintf("Error converting value to integer: %v", err))
|
|
}
|
|
teamIDsToIgnore = append(teamIDsToIgnore, teamID)
|
|
}
|
|
|
|
incidentInvestigationReopenDays := viper.GetInt("investigation.reopen.threshold.days")
|
|
dateBefore := time.Now().AddDate(0, 0, -incidentInvestigationReopenDays).Format(time.RFC3339)
|
|
|
|
result := r.gormClient.Raw(incidentsToMoveToInvestigating, teamIDsToIgnore, dateBefore).Scan(&incidentEntities)
|
|
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
|
|
return incidentEntities, nil
|
|
}
|
|
|
|
func (r *Repository) GetIncidentsByTeamIdAndNotResolvedAndOfSev0OrSev1OrSev2(team_id uint) (*[]IncidentEntity, error) {
|
|
var incidentEntity []IncidentEntity
|
|
|
|
result := r.gormClient.Order("severity_id").Order("created_at desc").Find(&incidentEntity, "team_id = ? AND status NOT IN ? AND severity_id IN ?", team_id, []uint{4, 5}, []uint{1, 2, 3})
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
|
|
return &incidentEntity, nil
|
|
}
|
|
|
|
func (r *Repository) GetCountOfIncidentsByTeamIdAndNotResolved(team_id uint) (int, error) {
|
|
var incidentEntity []IncidentEntity
|
|
|
|
result := r.gormClient.Find(&incidentEntity, "team_id = ? AND status NOT IN ? AND severity_id IN (1,2,3)", team_id, []uint{4, 5})
|
|
if result.Error != nil {
|
|
return 0, result.Error
|
|
}
|
|
|
|
return int(result.RowsAffected), nil
|
|
}
|
|
|
|
func (r *Repository) GetIncidentRoleByIncidentIdAndRole(incident_id uint, role string) (*IncidentRoleEntity, error) {
|
|
var incidentRoleEntity IncidentRoleEntity
|
|
|
|
result := r.gormClient.Find(&incidentRoleEntity, "incident_id = ? and role = ? and deleted_at IS NULL", incident_id, role)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
|
|
return &incidentRoleEntity, nil
|
|
}
|
|
|
|
func (r *Repository) GetIncidentRolesByIncidentIdsAndRole(incidentsIds []uint, role string) ([]IncidentRoleEntity, error) {
|
|
var incidentRoleEntity []IncidentRoleEntity
|
|
|
|
result := r.gormClient.Find(&incidentRoleEntity, "incident_id IN ? and role = ? and deleted_at IS NULL", incidentsIds, role)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
|
|
return incidentRoleEntity, nil
|
|
}
|
|
|
|
func (r *Repository) GetOpenIncidentsByCreatorIdForGivenTeamAndStatuses(created_by string, teamId uint, statusIds []uint) (*[]IncidentEntity, error) {
|
|
var incidentEntities []IncidentEntity
|
|
result := r.gormClient.Find(&incidentEntities, "created_by = ? AND team_id = ? AND status IN ?", created_by, teamId, statusIds)
|
|
|
|
if result.Error != nil {
|
|
logger.Error(fmt.Sprintf("Error in fetching open incidents created by %s and for team %d", created_by, teamId), zap.Error(result.Error))
|
|
return nil, result.Error
|
|
}
|
|
|
|
return &incidentEntities, nil
|
|
}
|
|
|
|
func (r *Repository) FindOpenIncidentsByTeamOrderedByCreationTimeAndSeverity(team string) (*[]IncidentEntity, error) {
|
|
var incidentEntity []IncidentEntity
|
|
query := fmt.Sprintf("SELECT * FROM incident WHERE team_id = %v AND status NOT IN (4, 5) AND is_private = false AND deleted_at IS NULL ORDER BY severity_id, id", team)
|
|
result :=
|
|
r.gormClient.Raw(query).Scan(&incidentEntity)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
return &incidentEntity, nil
|
|
}
|
|
|
|
func (r *Repository) FetchIncidentsWithSeverityTatBetweenGivenRange(slaStart, slaEnd string) (*[]IncidentEntity, error) {
|
|
var incidents []IncidentEntity
|
|
query := r.gormClient.Where(
|
|
fmt.Sprintf("severity_tat >= ? AND severity_tat < ? AND severity_id IN %s AND status IN (?)", viper.GetString("severities.for.sla.breach")),
|
|
slaStart, slaEnd, statusesForEscalation).
|
|
Order("team_id").Preload("Team").Preload("Severity").Find(&incidents)
|
|
if query.Error != nil {
|
|
return nil, query.Error
|
|
}
|
|
return &incidents, nil
|
|
}
|
|
|
|
func (r *Repository) UpdateIncidentChannelEntity(incidentChannelEntity *IncidentChannelEntity) error {
|
|
result := r.gormClient.Select("*").Updates(incidentChannelEntity)
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *Repository) CanUserWithEmailAccessIncidentWithId(userEmail string, incidentId uint) (bool, error) {
|
|
var count int64
|
|
query := r.gormClient.Table("incident").Joins("JOIN houston_user ON houston_user.email = ?", userEmail)
|
|
|
|
query = query.Where("incident.id = ?", incidentId)
|
|
|
|
query = query.Where(
|
|
fmt.Sprintf("%s OR %s or %s", isPrivateCondition, incidentTeamsAccessCondition, userInIncidentCondition),
|
|
false, gorm.Expr("houston_user.id"), gorm.Expr("houston_user.id"),
|
|
)
|
|
|
|
if err := query.Count(&count).Error; err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return count > 0, nil
|
|
}
|
|
|
|
func (r *Repository) GetIncidentsByIds(incidentIds []uint) ([]IncidentEntity, error) {
|
|
var incidents []IncidentEntity
|
|
query := r.gormClient.Where("id IN ?", incidentIds).Find(&incidents)
|
|
if query.Error != nil {
|
|
return nil, query.Error
|
|
}
|
|
return incidents, nil
|
|
}
|
|
|
|
var statusesForEscalation = []uint{1, 2}
|
|
|
|
const isPrivateCondition = "is_private = ?"
|
|
const incidentTeamsAccessCondition = `EXISTS (
|
|
SELECT 1
|
|
FROM team_user
|
|
WHERE team_user.user_id = ?
|
|
AND (
|
|
team_user.team_id = incident.team_id
|
|
OR team_user.team_id = incident.reporting_team_id
|
|
)
|
|
)`
|
|
const userInIncidentCondition = `EXISTS (
|
|
SELECT 1
|
|
FROM incident_user
|
|
WHERE incident_user.incident_id = incident.id
|
|
AND incident_user.user_id = ?
|
|
)`
|
|
const incidentsToMoveToInvestigating = `
|
|
WITH incidents_in_monitoring_or_identified_stage AS (
|
|
SELECT *
|
|
FROM incident i
|
|
WHERE i.status IN (
|
|
SELECT ists.id
|
|
FROM incident_status ists
|
|
WHERE ists.name IN ('Monitoring', 'Identified')
|
|
) AND i.team_id NOT IN ?
|
|
),
|
|
max_log_entries AS (
|
|
SELECT
|
|
record_id,
|
|
MAX(id) AS max_id
|
|
FROM log
|
|
WHERE relation_name = 'incident'
|
|
AND log.created_at < ?
|
|
AND EXISTS (
|
|
SELECT 1
|
|
FROM jsonb_array_elements(log.changes) AS change
|
|
WHERE change->>'attribute' = 'Status'
|
|
AND change->>'to' IN ('Monitoring', 'Identified')
|
|
)
|
|
GROUP BY record_id
|
|
)
|
|
SELECT imi.*
|
|
FROM log l
|
|
JOIN max_log_entries m ON l.record_id = m.record_id AND l.id = m.max_id
|
|
JOIN incidents_in_monitoring_or_identified_stage as imi on imi.id = l.record_id;
|
|
`
|