diff --git a/Makefile b/Makefile index 8f5e098..19631c9 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,7 @@ generatemocks: @rm -rf $(CURDIR)/mocks @echo "Generating mocks..." @mkdir "mocks" + @mkdir "mocks/incidentStatus" cd $(CURDIR)/pkg/google/googleDrive && minimock -i DriveActions -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/pkg/conference && minimock -i ICalendarActions -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/pkg/rest/ && minimock -i HttpRestClient -s _mock.go -o $(CURDIR)/mocks @@ -42,20 +43,18 @@ generatemocks: cd $(CURDIR)/repository/rca && minimock -i IRcaRepository -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/model/incident && minimock -i IIncidentRepository -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/pkg/monitoringService && minimock -i MonitoringServiceActions -s _mock.go -o $(CURDIR)/mocks - cd $(CURDIR)/model/incident && minimock -i IIncidentRepository -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/pkg/monitoringService && minimock -i ServiceActions -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/pkg/monitoringService && minimock -i MonitoringServiceActions -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/common/util/channel && minimock -i IChannelUtil -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/service/incident_channel && minimock -i IIncidentChannelService -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/model/team && minimock -i ITeamRepository -s _mock.go -o $(CURDIR)/mocks - cd $(CURDIR)/model/severity && minimock -i ISeverityRepository -s _mock.go -o $(CURDIR)/mocks + cd $(CURDIR)/repository/severity && minimock -i ISeverityRepository -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/model/user && minimock -i IUserRepository -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/pkg/documentService && minimock -i ServiceActions -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/repository/rcaInput && minimock -i IRcaInputRepository -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/service/teamService && minimock -i ITeamServiceV2 -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/model/user && minimock -i IUserRepositoryInterface -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/model/tag && minimock -i ITagRepository -s _mock.go -o $(CURDIR)/mocks - cd $(CURDIR)/model/incident && minimock -i IIncidentRepository -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/pkg/monitoringService && minimock -i MonitoringServiceActions -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/service/krakatoa && minimock -i IKrakatoaService -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/pkg/socketModeClient && minimock -i ISocketModeClientWrapper -s _mock.go -o $(CURDIR)/mocks @@ -83,3 +82,5 @@ generatemocks: cd $(CURDIR)/repository/teamUser && minimock -i TeamUserRepository -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/repository/teamUserSeverity && minimock -i TeamUserSeverityRepository -s _mock.go -o $(CURDIR)/mocks cd $(CURDIR)/model/incident_channel && minimock -i IncidentChannelRepositoryInterface -s _mock.go -o $(CURDIR)/mocks + cd $(CURDIR)/repository/incidentStatus && minimock -i IncidentStatusRepository -s _mock.go -o $(CURDIR)/mocks/incidentStatus + cd $(CURDIR)/service/incidentStatus && minimock -i IncidentStatusService -s _mock.go -o $(CURDIR)/mocks diff --git a/appcontext/app.go b/appcontext/app.go index 4ef9998..502650b 100644 --- a/appcontext/app.go +++ b/appcontext/app.go @@ -9,7 +9,6 @@ import ( "houston/model/log" productModel "houston/model/product" "houston/model/products_teams" - "houston/model/severity" "houston/model/tag" "houston/model/team" "houston/model/user" @@ -18,8 +17,10 @@ import ( "houston/pkg/postgres" "houston/pkg/rest" "houston/repository/externalTeamRepo" + incidentStatusRepo "houston/repository/incidentStatus" rcaRepository "houston/repository/rca/impl" "houston/repository/rcaInput" + "houston/repository/severity" teamSeverityRepo "houston/repository/teamSeverity" teamUserRepo "houston/repository/teamUser" teamUserSeverityRepo "houston/repository/teamUserSeverity" @@ -28,6 +29,7 @@ import ( "houston/service/google" incidentService "houston/service/incident/impl" "houston/service/incidentProducts" + "houston/service/incidentStatus" "houston/service/products" "houston/service/productsTeams" rcaService "houston/service/rca/impl" @@ -76,6 +78,7 @@ type houstonServices struct { teamUserSeverityService teamUserSeverity.ITeamUserSeverityService teamService teamService.ITeamServiceV2 reminderService reminder.ReminderService + incidentStatusService incidentStatus.IncidentStatusService } var appContext *applicationContext @@ -92,11 +95,13 @@ func InitializeServices() { severityRepo := initSeverityRepo() teamRepo := initTeamRepo(logRepo) slaService := initSlackService() + severityService := initSeverityService() + incidentStatusService := initIncidentStatusService() services = &houstonServices{ logRepo: logRepo, teamRepo: teamRepo, severityRepo: severityRepo, - incidentRepo: initIncidentRepo(severityRepo, logRepo, teamRepo, slaService.SocketModeClientWrapper.GetClient()), + incidentRepo: initIncidentRepo(severityService, incidentStatusService, logRepo, teamRepo, slaService.SocketModeClientWrapper.GetClient()), slackService: slaService, incidentService: initIncidentService(), tagRepo: initTagRepo(), @@ -110,10 +115,11 @@ func InitializeServices() { productsService: initProductsService(), incidentProductsService: initIncidentProductsService(), productTeamsService: initProductTeamsService(), - severityService: initSeverityService(), + severityService: severityService, teamSeverityService: initTeamSeverityService(), teamUserService: initTeamUserService(), teamUserSeverityService: initTeamUserSeverityService(), + incidentStatusService: incidentStatusService, } services.userService = initUserService() services.teamService = initTeamService() @@ -159,12 +165,13 @@ func GetSeverityRepo() *severity.Repository { } func initIncidentRepo( - severityRepo *severity.Repository, + severityService severityService.ISeverityService, + incidentStatusService incidentStatus.IncidentStatusService, logRepo *log.Repository, teamRepo *team.Repository, socketModeClient *socketmode.Client, ) *incident.Repository { - return incident.NewIncidentRepository(GetDB(), severityRepo, logRepo, teamRepo, socketModeClient) + return incident.NewIncidentRepository(GetDB(), severityService, incidentStatusService, logRepo, teamRepo, socketModeClient) } func GetIncidentRepo() *incident.Repository { @@ -226,6 +233,14 @@ func initIncidentProductsService() incidentProducts.IncidentProductsService { return incidentProducts.NewIncidentProductsService(incident_products.NewIncidentProductsRepo(GetDB())) } +func initIncidentStatusService() incidentStatus.IncidentStatusService { + return incidentStatus.NewIncidentStatusService(incidentStatusRepo.NewIncidentStatusRepository(GetDB())) +} + +func GetIncidentStatusService() incidentStatus.IncidentStatusService { + return services.incidentStatusService +} + func GetIncidentProductsService() incidentProducts.IncidentProductsService { return services.incidentProductsService } diff --git a/cmd/app/handler/slack_handler.go b/cmd/app/handler/slack_handler.go index ad0853d..4b648cf 100644 --- a/cmd/app/handler/slack_handler.go +++ b/cmd/app/handler/slack_handler.go @@ -9,7 +9,6 @@ import ( "houston/internal/resolver" "houston/model/incident" "houston/model/log" - "houston/model/severity" "houston/model/tag" "houston/model/team" "houston/model/user" @@ -17,6 +16,7 @@ import ( "houston/pkg/slackbot" rcaRepository "houston/repository/rca/impl" "houston/repository/rcaInput" + "houston/repository/severity" "houston/service/documentService" incidentServiceV2 "houston/service/incident/impl" "houston/service/orchestration" @@ -51,7 +51,10 @@ func NewSlackHandler( logRepository := log.NewLogRepository(gormClient) tagService := tag.NewTagRepository(gormClient) teamService := team.NewTeamRepository(gormClient, logRepository) - incidentService := incident.NewIncidentRepository(gormClient, severityService, logRepository, teamService, socketModeClient) + incidentService := incident.NewIncidentRepository( + gormClient, appcontext.GetSeverityService(), appcontext.GetIncidentStatusService(), + logRepository, teamService, socketModeClient, + ) productsService := appcontext.GetProductsService() userService := user.NewUserRepository(gormClient) slackbotClient := slackbot.NewSlackClient(socketModeClient) diff --git a/common/util/dto_converter.go b/common/util/dto/dto_converter.go similarity index 94% rename from common/util/dto_converter.go rename to common/util/dto/dto_converter.go index 023f189..fd476ca 100644 --- a/common/util/dto_converter.go +++ b/common/util/dto/dto_converter.go @@ -1,4 +1,4 @@ -package util +package dto type DTOConvertible[T any] interface { ToDTO() T diff --git a/internal/processor/action/incident_channel_message_update_action.go b/internal/processor/action/incident_channel_message_update_action.go index 27ad73d..59de018 100644 --- a/internal/processor/action/incident_channel_message_update_action.go +++ b/internal/processor/action/incident_channel_message_update_action.go @@ -3,41 +3,46 @@ package action import ( "errors" "fmt" + "github.com/slack-go/slack" + "github.com/slack-go/slack/socketmode" + "go.uber.org/zap" + "houston/appcontext" "houston/common/util" "houston/internal/processor/action/view" "houston/logger" "houston/model/incident" + "houston/model/incidentStatus" "houston/model/severity" "houston/model/team" - - "github.com/slack-go/slack" - "github.com/slack-go/slack/socketmode" - "go.uber.org/zap" + severityRepo "houston/repository/severity" + incidentStatusService "houston/service/incidentStatus" ) type IncidentChannelMessageUpdateAction struct { - socketModeClient *socketmode.Client - incidentService *incident.Repository - teamService *team.Repository - severityService *severity.Repository + socketModeClient *socketmode.Client + incidentService *incident.Repository + teamService *team.Repository + severityService *severityRepo.Repository + incidentStatusService incidentStatusService.IncidentStatusService } func NewIncidentChannelMessageUpdateAction( socketModeClient *socketmode.Client, incidentService *incident.Repository, teamService *team.Repository, - severityService *severity.Repository, + severityService *severityRepo.Repository, ) *IncidentChannelMessageUpdateAction { return &IncidentChannelMessageUpdateAction{ - socketModeClient: socketModeClient, - incidentService: incidentService, - teamService: teamService, - severityService: severityService, + socketModeClient: socketModeClient, + incidentService: incidentService, + teamService: teamService, + severityService: severityService, + incidentStatusService: appcontext.GetIncidentStatusService(), } } func (icm *IncidentChannelMessageUpdateAction) ProcessAction(channelId string) { - incidentEntity, teamEntity, severityEntity, incidentChannels, incidentStatusEntity, err := icm.getEntities(channelId) + incidentEntity, teamEntity, severityEntity, incidentChannels, incidentStatus, err := icm.getEntities(channelId) if err != nil { return } @@ -51,7 +56,7 @@ func (icm *IncidentChannelMessageUpdateAction) ProcessAction(channelId string) { } blocks := view.IncidentSummarySectionV3( - incidentEntity, reportingTeamEntity, teamEntity, severityEntity, incidentStatusEntity, + incidentEntity, reportingTeamEntity, teamEntity, severityEntity, incidentStatus, ) color := util.GetColorBySeverity(severityEntity.ID) att := slack.Attachment{Blocks: blocks, Color: color} @@ -66,7 +71,7 @@ func (icm *IncidentChannelMessageUpdateAction) ProcessAction(channelId string) { } func (icm *IncidentChannelMessageUpdateAction) getEntities(channelId string) (*incident.IncidentEntity, *team.TeamEntity, - *severity.SeverityEntity, *[]incident.IncidentChannelEntity, *incident.IncidentStatusEntity, error) { + *severity.SeverityEntity, *[]incident.IncidentChannelEntity, *incidentStatus.IncidentStatusDTO, error) { incidentEntity, err := icm.incidentService.FindIncidentByChannelId(channelId) if err != nil || incidentEntity == nil { return nil, nil, nil, nil, nil, errors.New("exception occurred while getting incident") @@ -87,10 +92,10 @@ func (icm *IncidentChannelMessageUpdateAction) getEntities(channelId string) (*i return nil, nil, nil, nil, nil, errors.New("exception occurred while getting incident severity") } - incidentStatusEntity, err := icm.incidentService.FindIncidentStatusById(incidentEntity.Status) - if err != nil || incidentStatusEntity == nil { + incidentStatus, err := icm.incidentStatusService.GetIncidentStatusByStatusId(incidentEntity.Status) + if err != nil || incidentStatus == nil { return nil, nil, nil, nil, nil, errors.New("exception occurred while getting incident status") } - return incidentEntity, teamEntity, severityEntity, incidentChannels, incidentStatusEntity, nil + return incidentEntity, teamEntity, severityEntity, incidentChannels, incidentStatus, nil } diff --git a/internal/processor/action/incident_mark_duplicate_action.go b/internal/processor/action/incident_mark_duplicate_action.go index be9b0fd..03b11ca 100644 --- a/internal/processor/action/incident_mark_duplicate_action.go +++ b/internal/processor/action/incident_mark_duplicate_action.go @@ -11,9 +11,9 @@ import ( "houston/logger" "houston/model/customErrors" "houston/model/incident" - "houston/model/severity" "houston/model/tag" "houston/model/team" + "houston/repository/severity" "houston/service/conference" incidentService "houston/service/incident" "strconv" diff --git a/internal/processor/action/incident_rca_details_action.go b/internal/processor/action/incident_rca_details_action.go index ae809fd..1604537 100644 --- a/internal/processor/action/incident_rca_details_action.go +++ b/internal/processor/action/incident_rca_details_action.go @@ -11,9 +11,9 @@ import ( "houston/internal/processor/action/view" "houston/logger" "houston/model/incident" - "houston/model/severity" "houston/model/tag" "houston/model/team" + "houston/repository/severity" incidentService "houston/service/incident" incidentServiceImpl "houston/service/incident/impl" rcaService "houston/service/rca/impl" diff --git a/internal/processor/action/incident_resolve_action.go b/internal/processor/action/incident_resolve_action.go deleted file mode 100644 index 45ee50b..0000000 --- a/internal/processor/action/incident_resolve_action.go +++ /dev/null @@ -1,142 +0,0 @@ -package action - -import ( - "fmt" - "houston/appcontext" - slackUtil "houston/common/util/slack" - "houston/logger" - "houston/model/incident" - "houston/model/severity" - "houston/model/tag" - "houston/model/team" - "houston/service/conference" - incidentService "houston/service/incident" - rcaService "houston/service/rca/impl" - "time" - - "github.com/slack-go/slack" - "github.com/slack-go/slack/socketmode" - "go.uber.org/zap" -) - -type ResolveIncidentAction struct { - client *socketmode.Client - incidentService *incident.Repository - tagService *tag.Repository - teamRepository *team.Repository - severityRepository *severity.Repository - rcaService *rcaService.RcaService - calendarService conference.ICalendarService - incidentServiceV2 incidentService.IIncidentService -} - -func NewIncidentResolveProcessor( - client *socketmode.Client, - incidentService *incident.Repository, - tagService *tag.Repository, - teamRepository *team.Repository, - severityRepository *severity.Repository, - rcaService *rcaService.RcaService, -) *ResolveIncidentAction { - return &ResolveIncidentAction{ - client: client, - incidentService: incidentService, - tagService: tagService, - teamRepository: teamRepository, - severityRepository: severityRepository, - rcaService: rcaService, - calendarService: appcontext.GetCalendarService(), - incidentServiceV2: appcontext.GetIncidentService(), - } -} - -func (irp *ResolveIncidentAction) IncidentResolveProcess(callback slack.InteractionCallback, request *socketmode.Request) { - channelId := callback.View.PrivateMetadata - incidentEntity, err := irp.incidentService.FindIncidentByChannelId(channelId) - if err != nil { - logger.Error("incident not found", - zap.String("channel", channelId), - zap.String("user_id", callback.User.ID), zap.Error(err)) - } - if incidentEntity.Status == incident.ResolvedId { - slackUtil.PostIncidentStatusErrorMessage(incident.Resolved, channelId, callback.User.ID, irp.client) - return - } - incidentStatusEntity, _ := irp.incidentService.FindIncidentStatusByName(incident.Resolved) - //check if active tags are set or else throw error - var flag = true - activeTags, err := irp.tagService.GetMandatoryActiveTags() - if err != nil { - logger.Error(fmt.Sprintf("failed to get mandatory active tags due to error : %s", err.Error())) - return - } - if len(*activeTags) > 0 { - for _, activeTag := range *activeTags { - incidentTag, _ := irp.incidentService.GetIncidentTagsByTagIds(incidentEntity.ID, []uint{activeTag.Id}) - if incidentTag.TagValueIds == nil || len(incidentTag.TagValueIds) < 1 { - logger.Error(fmt.Sprintf(" %s for incidentId: %v is not set", activeTag.Label, incidentEntity.ID)) - flag = false - msgOption := slack.MsgOptionText(fmt.Sprintf("`%s tags are not set`", activeTag.Label), false) - _, errMessage := irp.client.PostEphemeral(callback.Channel.ID, callback.User.ID, msgOption) - if errMessage != nil { - logger.Error("post response failed for tags not set message", zap.Error(errMessage)) - return - } - } - } - } - - // check if all tags are set - if flag == true { - now := time.Now() - incidentEntity.Status = incidentStatusEntity.ID - incidentEntity.EndTime = &now - - err = irp.incidentService.UpdateIncident(incidentEntity) - if err != nil { - logger.Error("failed to update incident to resolve state", - zap.String("channel", channelId), - zap.String("user_id", callback.User.ID), zap.Error(err)) - return - } - - logger.Info("successfully resolved the incident", - zap.String("channel", channelId), - zap.String("user_id", callback.User.ID)) - msgOption := slack.MsgOptionText(fmt.Sprintf("<@%s> *>* `set status to %s`", callback.User.ID, - incident.Resolved), false) - _, _, errMessage := irp.client.PostMessage(channelId, msgOption) - if errMessage != nil { - logger.Error("post response failed for ResolveIncident", zap.Error(errMessage)) - return - } - msgUpdate := NewIncidentChannelMessageUpdateAction(irp.client, irp.incidentService, irp.teamRepository, irp.severityRepository) - msgUpdate.ProcessAction(incidentEntity.SlackChannel) - go irp.incidentServiceV2.DeleteConferenceEvent(incidentEntity) - go func() { - if incidentEntity.SeverityId != incident.Sev0Id && incidentEntity.SeverityId != incident.Sev1Id { - msg, err := slackUtil.GetArchivalTimeOfIncidentChannel(incident.Resolved, int(incidentEntity.SeverityId)) - if err != nil { - logger.Error("failed to get archival time to incident channel", zap.String("channel id", channelId), zap.Error(err)) - } else { - _, _, postErr := irp.client.PostMessage(channelId, slack.MsgOptionText(msg, false)) - if postErr != nil { - logger.Error("failed to post archival time to incident channel", zap.String("channel id", channelId), zap.Error(err)) - } - } - } - _ = irp.rcaService.GenerateRCA(incidentEntity, callback.User.ID) - }() - } else { - msgOption := slack.MsgOptionText(fmt.Sprintf("`Please set tag value`"), false) - _, errMessage := irp.client.PostEphemeral(channelId, callback.User.ID, msgOption) - if errMessage != nil { - logger.Error("post response failed for ResolveIncident", zap.Error(errMessage)) - return - } - - } - - var payload interface{} - irp.client.Ack(*request, payload) -} diff --git a/internal/processor/action/incident_update_product_action.go b/internal/processor/action/incident_update_product_action.go index 73bc09b..5e1197e 100644 --- a/internal/processor/action/incident_update_product_action.go +++ b/internal/processor/action/incident_update_product_action.go @@ -11,8 +11,8 @@ import ( "houston/internal/processor/action/view" "houston/logger" "houston/model/incident" - "houston/model/severity" "houston/pkg/slackbot" + "houston/repository/severity" incidentV2 "houston/service/incident/impl" "houston/service/orchestration" "houston/service/products" diff --git a/internal/processor/action/incident_update_severity_action.go b/internal/processor/action/incident_update_severity_action.go index a6557df..1d8c11d 100644 --- a/internal/processor/action/incident_update_severity_action.go +++ b/internal/processor/action/incident_update_severity_action.go @@ -5,16 +5,18 @@ import ( "github.com/slack-go/slack" "github.com/slack-go/slack/socketmode" "go.uber.org/zap" + "houston/appcontext" "houston/common/metrics" "houston/common/util/structUtil" "houston/internal/processor/action/view" "houston/logger" "houston/model/incident" - "houston/model/severity" "houston/model/team" "houston/pkg/slackbot" + "houston/repository/severity" incidentService "houston/service/incident/impl" service "houston/service/request" + severityService "houston/service/severity" "strconv" ) @@ -25,6 +27,7 @@ type IncidentUpdateSeverityAction struct { teamRepository *team.Repository slackbotClient *slackbot.Client incidentServiceV2 *incidentService.IncidentServiceV2 + severityService severityService.ISeverityService } func NewIncidentUpdateSeverityAction( @@ -42,6 +45,7 @@ func NewIncidentUpdateSeverityAction( teamRepository: teamRepository, slackbotClient: slackbotClient, incidentServiceV2: incidentServiceV2, + severityService: appcontext.GetSeverityService(), } } @@ -51,14 +55,14 @@ type JustificationMetadata struct { } func (isp *IncidentUpdateSeverityAction) IncidentUpdateSeverityRequestProcess(callback slack.InteractionCallback, request *socketmode.Request) { - incidentSeverity, err := isp.severityRepository.GetAllActiveSeverity() + incidentSeverity, err := isp.severityService.GetSeveritiesNotMatchingIncidentSeverity(callback.Channel.ID) if err != nil || incidentSeverity == nil { logger.Error("FindSeverityEntity error", zap.String("incident_slack_channel_id", callback.Channel.ID), zap.String("channel", callback.Channel.Name), zap.String("user_id", callback.User.ID), zap.Error(err)) return } - modalRequest := view.BuildIncidentUpdateSeverityModal(callback.Channel.ID, *incidentSeverity) + modalRequest := view.BuildIncidentUpdateSeverityModal(callback.Channel.ID, incidentSeverity) _, err = isp.client.OpenView(callback.TriggerID, modalRequest) if err != nil { diff --git a/internal/processor/action/incident_update_status_action.go b/internal/processor/action/incident_update_status_action.go index ea69f37..b742aea 100644 --- a/internal/processor/action/incident_update_status_action.go +++ b/internal/processor/action/incident_update_status_action.go @@ -5,24 +5,27 @@ import ( "github.com/slack-go/slack" "github.com/slack-go/slack/socketmode" "go.uber.org/zap" + "houston/appcontext" "houston/common/metrics" "houston/internal/processor/action/view" "houston/logger" "houston/model/incident" - "houston/model/severity" "houston/model/tag" "houston/model/team" + "houston/repository/severity" incidentV2 "houston/service/incident/impl" + "houston/service/incidentStatus" service "houston/service/request" ) type UpdateIncidentAction struct { - client *socketmode.Client - incidentService *incident.Repository - tagService *tag.Repository - teamRepository *team.Repository - severityRepository *severity.Repository - incidentServiceV2 *incidentV2.IncidentServiceV2 + client *socketmode.Client + incidentService *incident.Repository + tagService *tag.Repository + teamRepository *team.Repository + severityRepository *severity.Repository + incidentServiceV2 *incidentV2.IncidentServiceV2 + incidentStatusService incidentStatus.IncidentStatusService } func NewIncidentUpdateAction( @@ -33,23 +36,24 @@ func NewIncidentUpdateAction( severityRepository *severity.Repository, incidentServiceV2 *incidentV2.IncidentServiceV2) *UpdateIncidentAction { return &UpdateIncidentAction{ - client: client, - incidentService: incidentService, - tagService: tagService, - teamRepository: teamRepository, - severityRepository: severityRepository, - incidentServiceV2: incidentServiceV2, + client: client, + incidentService: incidentService, + tagService: tagService, + teamRepository: teamRepository, + severityRepository: severityRepository, + incidentServiceV2: incidentServiceV2, + incidentStatusService: appcontext.GetIncidentStatusService(), } } func (isp *UpdateIncidentAction) IncidentUpdateStatusRequestProcess(callback slack.InteractionCallback, request *socketmode.Request) { - incidentStatuses, err := isp.incidentService.FetchAllNonTerminalIncidentStatuses() + incidentStatuses, err := isp.incidentStatusService.GetNonTerminalStatusesNotMatchingIncidentStatus(callback.Channel.ID) if err != nil || incidentStatuses == nil { logger.Error("failed to get the all active incident statuses") return } - modalRequest := view.BuildIncidentUpdateStatusModal(*incidentStatuses, callback.Channel.ID) + modalRequest := view.BuildIncidentUpdateStatusModal(incidentStatuses, callback.Channel.ID) _, err = isp.client.OpenView(callback.TriggerID, modalRequest) if err != nil { diff --git a/internal/processor/action/incident_update_title_action.go b/internal/processor/action/incident_update_title_action.go index 406fa46..aedd2d8 100644 --- a/internal/processor/action/incident_update_title_action.go +++ b/internal/processor/action/incident_update_title_action.go @@ -2,13 +2,15 @@ package action import ( "fmt" + "houston/appcontext" "houston/internal/processor/action/view" "houston/logger" "houston/model/incident" - "houston/model/severity" "houston/model/team" "houston/pkg/slackbot" + "houston/repository/severity" "houston/service/incident/impl" + "houston/service/incidentStatus" slackService "houston/service/slack" service "houston/service/utils" @@ -18,22 +20,24 @@ import ( ) type IncidentUpdateTitleAction struct { - client *socketmode.Client - incidentService *incident.Repository - teamService *team.Repository - severityService *severity.Repository - slackbotClient *slackbot.Client - slackService slackService.ISlackService + client *socketmode.Client + incidentService *incident.Repository + teamService *team.Repository + severityService *severity.Repository + slackbotClient *slackbot.Client + slackService slackService.ISlackService + incidentStatusService incidentStatus.IncidentStatusService } func NewIncidentUpdateTitleAction(client *socketmode.Client, incidentService *incident.Repository, teamService *team.Repository, severityService *severity.Repository, slackbotClient *slackbot.Client, service slackService.ISlackService) *IncidentUpdateTitleAction { return &IncidentUpdateTitleAction{ - client: client, - incidentService: incidentService, - teamService: teamService, - severityService: severityService, - slackbotClient: slackbotClient, - slackService: service, + client: client, + incidentService: incidentService, + teamService: teamService, + severityService: severityService, + slackbotClient: slackbotClient, + slackService: service, + incidentStatusService: appcontext.GetIncidentStatusService(), } } @@ -76,12 +80,12 @@ func (itp *IncidentUpdateTitleAction) IncidentUpdateTitle(callback slack.Interac return } - statusEntity, err := itp.incidentService.FindIncidentStatusById(incidentEntity.Status) + status, err := itp.incidentStatusService.GetIncidentStatusByStatusId(incidentEntity.Status) if err != nil { logger.Error("error in fetching status in incident update type action", zap.String("channel", incidentEntity.SlackChannel), zap.Uint("incident_id", incidentEntity.ID), zap.Error(err)) return - } else if statusEntity == nil { + } else if status == nil { logger.Info("status not found in incident update type action", zap.String("channel", incidentEntity.SlackChannel), zap.Uint("incident_id", incidentEntity.ID)) return @@ -94,7 +98,7 @@ func (itp *IncidentUpdateTitleAction) IncidentUpdateTitle(callback slack.Interac incidentEntity.IncidentName = service.ConstructIncidentChannelName( incidentEntity.ID, incidentEntity.SeverityId, - statusEntity.Name, + status.Name, incidentEntity.Title, ) err = itp.incidentService.UpdateIncident(incidentEntity) @@ -145,7 +149,7 @@ func (itp *IncidentUpdateTitleAction) IncidentUpdateTitle(callback slack.Interac ReportingTeamName: incidentEntity.ReportingTeam.Name, ResponderTeamName: teamEntity.Name, SeverityName: severityEntity.Name, - StatusName: statusEntity.Name, + StatusName: status.Name, Title: incidentEntity.Title, } diff --git a/internal/processor/action/incident_update_type_action.go b/internal/processor/action/incident_update_type_action.go index 93b2ddb..6cb8495 100644 --- a/internal/processor/action/incident_update_type_action.go +++ b/internal/processor/action/incident_update_type_action.go @@ -9,9 +9,9 @@ import ( "houston/internal/processor/action/view" "houston/logger" "houston/model/incident" - "houston/model/severity" "houston/model/team" "houston/pkg/slackbot" + "houston/repository/severity" incidentV2 "houston/service/incident/impl" "houston/service/orchestration" service "houston/service/request" diff --git a/internal/processor/action/member_join_action.go b/internal/processor/action/member_join_action.go index 5c06875..590491d 100644 --- a/internal/processor/action/member_join_action.go +++ b/internal/processor/action/member_join_action.go @@ -2,30 +2,33 @@ package action import ( "fmt" - "houston/internal/processor/action/view" - "houston/logger" - "houston/model/incident" - "houston/model/severity" - "houston/model/team" - "github.com/slack-go/slack/slackevents" "github.com/slack-go/slack/socketmode" "go.uber.org/zap" + "houston/appcontext" + "houston/internal/processor/action/view" + "houston/logger" + "houston/model/incident" + "houston/model/team" + "houston/repository/severity" + incidentStatusService "houston/service/incidentStatus" ) type MemberJoinAction struct { - client *socketmode.Client - incidentService *incident.Repository - teamService *team.Repository - severityService *severity.Repository + client *socketmode.Client + incidentService *incident.Repository + teamService *team.Repository + severityService *severity.Repository + incidentStatusService incidentStatusService.IncidentStatusService } func NewMemberJoinAction(socketModeClient *socketmode.Client, incidentService *incident.Repository, teamService *team.Repository, severityService *severity.Repository) *MemberJoinAction { return &MemberJoinAction{ - client: socketModeClient, - incidentService: incidentService, - teamService: teamService, - severityService: severityService, + client: socketModeClient, + incidentService: incidentService, + teamService: teamService, + severityService: severityService, + incidentStatusService: appcontext.GetIncidentStatusService(), } } @@ -65,12 +68,12 @@ func (mp *MemberJoinAction) PerformAction(memberJoinedChannelEvent *slackevents. return } - incidentStatusEntity, err := mp.incidentService.FindIncidentStatusById(incidentEntity.Status) + incidentStatus, err := mp.incidentStatusService.GetIncidentStatusByStatusId(incidentEntity.Status) if err != nil { logger.Error("error in fetching incident status", zap.String("channel", memberJoinedChannelEvent.Channel), zap.Uint("incident_id", incidentEntity.ID), zap.Error(err)) return - } else if incidentStatusEntity == nil { + } else if incidentStatus == nil { logger.Info("incident status not found", zap.String("channel", memberJoinedChannelEvent.Channel), zap.Uint("incident_id", incidentEntity.ID)) return @@ -86,7 +89,7 @@ func (mp *MemberJoinAction) PerformAction(memberJoinedChannelEvent *slackevents. } blocks := view.IncidentSummarySectionV3( - incidentEntity, reportingTeamEntity, teamEntity, severityEntity, incidentStatusEntity, + incidentEntity, reportingTeamEntity, teamEntity, severityEntity, incidentStatus, ) msgOption := view.IncidentEphemeralMessage(incidentEntity, blocks) diff --git a/internal/processor/action/open_set_severity_view_modal_command_action.go b/internal/processor/action/open_set_severity_view_modal_command_action.go index 89acf51..4a019a8 100644 --- a/internal/processor/action/open_set_severity_view_modal_command_action.go +++ b/internal/processor/action/open_set_severity_view_modal_command_action.go @@ -51,12 +51,12 @@ func (action *OpenSetSeverityViewModalCommandAction) PerformAction(evt *socketmo func (action *OpenSetSeverityViewModalCommandAction) openSetSeverityViewModal(cmd slack.SlashCommand) error { logger.Info(fmt.Sprintf("%s opening severity view modal", openSetSeverityViewModalActionLogTag)) return executeForHoustonChannel(cmd, func() error { - severityEntities, err := appcontext.GetSeverityRepo().GetAllActiveSeverity() + severities, err := appcontext.GetSeverityService().GetSeveritiesNotMatchingIncidentSeverity(cmd.ChannelID) if err != nil { logger.Error(fmt.Sprintf("%s error in fetching all severity entities from DB. %+v", openSetSeverityViewModalActionLogTag, err)) return genericBackendError } - _, err = action.socketModeClient.OpenView(cmd.TriggerID, view.BuildIncidentUpdateSeverityModal(cmd.ChannelID, *severityEntities)) + _, err = action.socketModeClient.OpenView(cmd.TriggerID, view.BuildIncidentUpdateSeverityModal(cmd.ChannelID, severities)) if err != nil { logger.Error(fmt.Sprintf("%s failed to open set severity view modal: %+v", openSetSeverityViewModalActionLogTag, err)) return fmt.Errorf("failed to open set severity view modal") diff --git a/internal/processor/action/open_set_status_view_modal_command_action.go b/internal/processor/action/open_set_status_view_modal_command_action.go index f593a37..faec146 100644 --- a/internal/processor/action/open_set_status_view_modal_command_action.go +++ b/internal/processor/action/open_set_status_view_modal_command_action.go @@ -51,12 +51,12 @@ func (action *OpenSetStatusViewModalCommandAction) PerformAction(evt *socketmode func (action *OpenSetStatusViewModalCommandAction) openSetStatusViewModal(cmd slack.SlashCommand) error { logger.Info("opening set status view modal") return executeForHoustonChannel(cmd, func() error { - statusEntities, err := appcontext.GetIncidentRepo().FetchAllIncidentStatuses() + statuses, err := appcontext.GetIncidentStatusService().GetNonTerminalStatusesNotMatchingIncidentStatus(cmd.ChannelID) if err != nil { logger.Error(fmt.Sprintf("%s failed to fetch all active teams from DB. %+v", openSetStatusViewModalActionLogTag, err)) return genericBackendError } - _, err = action.socketModeClient.OpenView(cmd.TriggerID, view.BuildIncidentUpdateStatusModal(*statusEntities, cmd.ChannelID)) + _, err = action.socketModeClient.OpenView(cmd.TriggerID, view.BuildIncidentUpdateStatusModal(statuses, cmd.ChannelID)) if err != nil { return fmt.Errorf("failed to open set status view modal: %s", err.Error()) } diff --git a/internal/processor/action/set_status_command_action.go b/internal/processor/action/set_status_command_action.go index adbf400..0827084 100644 --- a/internal/processor/action/set_status_command_action.go +++ b/internal/processor/action/set_status_command_action.go @@ -79,17 +79,17 @@ func (action *SetStatusCommandAction) setStatus(cmd slack.SlashCommand, status s return genericBackendError } - incidentStatusEntity, err := appcontext.GetIncidentRepo().GetIncidentStatusByStatusName(status) + incidentStatus, err := appcontext.GetIncidentStatusService().GetIncidentStatusByStatusName(status) if err != nil { logger.Error(fmt.Sprintf("%s error in finding incident status for status name %s. %+v", setStatusActionLogTag, status, err)) return genericBackendError } - if incidentStatusEntity == nil { + if incidentStatus == nil { logger.Error(fmt.Sprintf("%s no entity found or status name %s", setStatusActionLogTag, status)) return fmt.Errorf("%s is not a valid status", status) } - statusID := incidentStatusEntity.ID + statusID := incidentStatus.ID incidentEntity.Status = statusID incidentEntity.UpdatedBy = cmd.UserID incidentEntity.UpdatedAt = time.Now() @@ -101,7 +101,7 @@ func (action *SetStatusCommandAction) setStatus(cmd slack.SlashCommand, status s } go func() { - errMessage := util.PostIncidentStatusUpdateMessage(cmd.UserID, incidentStatusEntity.Name, cmd.ChannelID, action.socketModeClient) + errMessage := util.PostIncidentStatusUpdateMessage(cmd.UserID, incidentStatus.Name, cmd.ChannelID, action.socketModeClient) if errMessage != nil { logger.Error("post response failed for IncidentUpdateStatus", zap.Error(errMessage)) return diff --git a/internal/processor/action/show_incidents_block_action.go b/internal/processor/action/show_incidents_block_action.go index 6e4ce0a..3eb380a 100644 --- a/internal/processor/action/show_incidents_block_action.go +++ b/internal/processor/action/show_incidents_block_action.go @@ -1,14 +1,13 @@ package action import ( - "houston/internal/processor/action/view" - "houston/logger" - "houston/model/severity" - "houston/model/team" - "github.com/slack-go/slack" "github.com/slack-go/slack/socketmode" "go.uber.org/zap" + "houston/internal/processor/action/view" + "houston/logger" + "houston/model/team" + "houston/repository/severity" ) type ShowIncidentsAction struct { diff --git a/internal/processor/action/start_incident_block_action.go b/internal/processor/action/start_incident_block_action.go index cfad177..ec2095b 100644 --- a/internal/processor/action/start_incident_block_action.go +++ b/internal/processor/action/start_incident_block_action.go @@ -11,6 +11,7 @@ import ( "houston/logger" "houston/model/severity" "houston/model/team" + severityRepo "houston/repository/severity" "houston/service/orchestration" "houston/service/productsTeams" "time" @@ -20,14 +21,14 @@ type StartIncidentBlockAction struct { socketModeClient *socketmode.Client productTeamService productsTeams.ProductTeamsService teamService *team.Repository - severityService *severity.Repository + severityService *severityRepo.Repository incidentOrchestrator orchestration.IncidentOrchestrator } func NewStartIncidentBlockAction( client *socketmode.Client, teamService *team.Repository, - severityService *severity.Repository, + severityService *severityRepo.Repository, orchestrator orchestration.IncidentOrchestrator, ) *StartIncidentBlockAction { return &StartIncidentBlockAction{ diff --git a/internal/processor/action/start_incident_modal_submission_action.go b/internal/processor/action/start_incident_modal_submission_action.go index 340dd68..4180127 100644 --- a/internal/processor/action/start_incident_modal_submission_action.go +++ b/internal/processor/action/start_incident_modal_submission_action.go @@ -11,9 +11,9 @@ import ( "houston/internal" "houston/logger" "houston/model/incident" - "houston/model/severity" "houston/model/team" "houston/pkg/slackbot" + "houston/repository/severity" incidentServiceImpl "houston/service/incident/impl" "houston/service/orchestration" request "houston/service/request/incident" diff --git a/internal/processor/action/view/incident_severity.go b/internal/processor/action/view/incident_severity.go index 282d1c0..28b07e7 100644 --- a/internal/processor/action/view/incident_severity.go +++ b/internal/processor/action/view/incident_severity.go @@ -14,7 +14,7 @@ const ( JustificationActionId = "justificationActionId" ) -func BuildIncidentUpdateSeverityModal(channelID string, incidentSeverity []severity.SeverityEntity) slack.ModalViewRequest { +func BuildIncidentUpdateSeverityModal(channelID string, incidentSeverity []severity.SeverityDTO) slack.ModalViewRequest { titleText := slack.NewTextBlockObject(slack.PlainTextType, "Set severity of incident", false, false) closeText := slack.NewTextBlockObject(slack.PlainTextType, "Close", false, false) submitText := slack.NewTextBlockObject(slack.PlainTextType, "Submit", false, false) @@ -47,12 +47,12 @@ func BuildIncidentUpdateSeverityModal(channelID string, incidentSeverity []sever } -func createIncidentSeverityBlock(options []severity.SeverityEntity) []*slack.OptionBlockObject { +func createIncidentSeverityBlock(options []severity.SeverityDTO) []*slack.OptionBlockObject { optionBlockObjects := make([]*slack.OptionBlockObject, 0, len(options)) - for _, o := range options { - txt := fmt.Sprintf("%s (%s)", o.Name, o.Description) + for _, opt := range options { + txt := fmt.Sprintf("%s (%s)", opt.Name, opt.Description) optionText := slack.NewTextBlockObject(slack.PlainTextType, txt, false, false) - optionBlockObjects = append(optionBlockObjects, slack.NewOptionBlockObject(strconv.FormatUint(uint64(o.ID), 10), optionText, nil)) + optionBlockObjects = append(optionBlockObjects, slack.NewOptionBlockObject(strconv.FormatUint(uint64(opt.ID), 10), optionText, nil)) } return optionBlockObjects } diff --git a/internal/processor/action/view/incident_status_update_modal.go b/internal/processor/action/view/incident_status_update_modal.go index 5fa3bb2..beb21f8 100644 --- a/internal/processor/action/view/incident_status_update_modal.go +++ b/internal/processor/action/view/incident_status_update_modal.go @@ -3,13 +3,13 @@ package view import ( "fmt" "houston/common/util" - "houston/model/incident" + "houston/model/incidentStatus" "strconv" "github.com/slack-go/slack" ) -func BuildIncidentUpdateStatusModal(statuses []incident.IncidentStatusEntity, channelID string) slack.ModalViewRequest { +func BuildIncidentUpdateStatusModal(statuses []incidentStatus.IncidentStatusDTO, channelID string) slack.ModalViewRequest { titleText := slack.NewTextBlockObject(slack.PlainTextType, "Set status of incident", false, false) closeText := slack.NewTextBlockObject(slack.PlainTextType, "Close", false, false) submitText := slack.NewTextBlockObject(slack.PlainTextType, "Submit", false, false) @@ -42,12 +42,12 @@ func BuildIncidentUpdateStatusModal(statuses []incident.IncidentStatusEntity, ch } -func createIncidentStatusBlock(options []incident.IncidentStatusEntity) []*slack.OptionBlockObject { +func createIncidentStatusBlock(options []incidentStatus.IncidentStatusDTO) []*slack.OptionBlockObject { optionBlockObjects := make([]*slack.OptionBlockObject, 0, len(options)) - for _, o := range options { - txt := fmt.Sprintf("%s - %s", o.Name, o.Description) + for _, opt := range options { + txt := fmt.Sprintf("%s - %s", opt.Name, opt.Description) optionText := slack.NewTextBlockObject(slack.PlainTextType, txt, false, false) - optionBlockObjects = append(optionBlockObjects, slack.NewOptionBlockObject(strconv.FormatUint(uint64(o.ID), 10), optionText, nil)) + optionBlockObjects = append(optionBlockObjects, slack.NewOptionBlockObject(strconv.FormatUint(uint64(opt.ID), 10), optionText, nil)) } return optionBlockObjects } diff --git a/internal/processor/action/view/incident_summary_section.go b/internal/processor/action/view/incident_summary_section.go index 64935a8..5fc55e0 100644 --- a/internal/processor/action/view/incident_summary_section.go +++ b/internal/processor/action/view/incident_summary_section.go @@ -5,12 +5,13 @@ import ( "github.com/slack-go/slack" "houston/common/util" "houston/model/incident" + "houston/model/incidentStatus" "houston/model/severity" "houston/model/team" "strings" ) -func IncidentSummarySection(incident *incident.IncidentEntity, team *team.TeamEntity, severity *severity.SeverityEntity, incidentStatus *incident.IncidentStatusEntity) slack.Blocks { +func IncidentSummarySection(incident *incident.IncidentEntity, team *team.TeamEntity, severity *severity.SeverityEntity, incidentStatus *incidentStatus.IncidentStatusDTO) slack.Blocks { return slack.Blocks{ BlockSet: []slack.Block{ buildSummaryHeader(incident.Title), @@ -28,7 +29,7 @@ func IncidentSummarySectionV3( reportingTeam *team.TeamEntity, responderTeam *team.TeamEntity, severity *severity.SeverityEntity, - incidentStatus *incident.IncidentStatusEntity, + incidentStatus *incidentStatus.IncidentStatusDTO, ) slack.Blocks { isV2 := reportingTeam == nil if isV2 { diff --git a/internal/processor/event_type_interactive_processor.go b/internal/processor/event_type_interactive_processor.go index eafe9a8..d1f2515 100644 --- a/internal/processor/event_type_interactive_processor.go +++ b/internal/processor/event_type_interactive_processor.go @@ -8,10 +8,10 @@ import ( "houston/internal/processor/action" "houston/logger" "houston/model/incident" - "houston/model/severity" "houston/model/tag" "houston/model/team" "houston/pkg/slackbot" + "houston/repository/severity" incidentService "houston/service/incident/impl" "houston/service/orchestration" "houston/service/products" @@ -35,7 +35,6 @@ type BlockActionProcessor struct { showIncidentsAction *action.ShowIncidentsAction helpCommandsAction *action.HelpCommandsAction assignIncidentAction *action.AssignIncidentAction - incidentResolveAction *action.ResolveIncidentAction incidentUpdateAction *action.UpdateIncidentAction incidentUpdateTypeAction *action.IncidentUpdateTypeAction incidentUpdateProductAction *action.IncidentUpdateProductAction @@ -73,8 +72,6 @@ func NewBlockActionProcessor( showIncidentsAction: action.ShowIncidentsBlockAction(socketModeClient, teamService), helpCommandsAction: action.NewHelpCommandsAction(socketModeClient), assignIncidentAction: action.NewAssignIncidentAction(socketModeClient, incidentRepository), - incidentResolveAction: action.NewIncidentResolveProcessor(socketModeClient, incidentRepository, - tagService, teamService, severityService, rcaService), incidentUpdateAction: action.NewIncidentUpdateAction(socketModeClient, incidentRepository, tagService, teamService, severityService, incidentServiceV2), incidentUpdateTypeAction: action.NewIncidentUpdateTypeAction(socketModeClient, incidentRepository, diff --git a/internal/processor/events_api_event_processor.go b/internal/processor/events_api_event_processor.go index b4bd1f9..836fd1e 100644 --- a/internal/processor/events_api_event_processor.go +++ b/internal/processor/events_api_event_processor.go @@ -7,9 +7,9 @@ import ( "houston/internal/processor/action" "houston/logger" "houston/model/incident" - "houston/model/severity" "houston/model/team" "houston/model/user" + "houston/repository/severity" ) type eventsApiEventProcessor interface { diff --git a/model/incident/entity.go b/model/incident/entity.go index c058d76..4a56961 100644 --- a/model/incident/entity.go +++ b/model/incident/entity.go @@ -143,18 +143,6 @@ func (IncidentChannelEntity) TableName() string { return "incident_channel" } -// IncidentStatusEntity contains the possible incident statuses -type IncidentStatusEntity struct { - gorm.Model - Name string `gorm:"column:name"` - Description string `gorm:"column:description"` - IsTerminalStatus bool `gorm:"column:is_terminal_status"` -} - -func (IncidentStatusEntity) TableName() string { - return "incident_status" -} - type IncidentTagEntity struct { gorm.Model IncidentId uint `gorm:"column:incident_id"` diff --git a/model/incident/incident.go b/model/incident/incident.go index c7b0292..054634c 100644 --- a/model/incident/incident.go +++ b/model/incident/incident.go @@ -2,29 +2,30 @@ package incident import ( "encoding/json" - "errors" "fmt" "github.com/slack-go/slack/socketmode" + "go.uber.org/zap" "houston/logger" "houston/model/log" "houston/model/product" - "houston/model/severity" "houston/model/team" + "houston/service/incidentStatus" + "houston/service/severity" utils "houston/service/utils" "strconv" "strings" "time" - "go.uber.org/zap" "gorm.io/gorm" ) type Repository struct { - gormClient *gorm.DB - severityRepository *severity.Repository - logRepository *log.Repository - teamRepository *team.Repository - socketModeClient *socketmode.Client + gormClient *gorm.DB + logRepository *log.Repository + teamRepository *team.Repository + socketModeClient *socketmode.Client + severityService severity.ISeverityService + incidentStatusService incidentStatus.IncidentStatusService } var valueBeforeUpdate IncidentEntity @@ -35,17 +36,19 @@ var differences []utils.Difference func NewIncidentRepository( gormClient *gorm.DB, - severityService *severity.Repository, + severityService severity.ISeverityService, + incidentStatusService incidentStatus.IncidentStatusService, logRepository *log.Repository, teamRepository *team.Repository, socketModeClient *socketmode.Client, ) *Repository { return &Repository{ - gormClient: gormClient, - severityRepository: severityService, - logRepository: logRepository, - teamRepository: teamRepository, - socketModeClient: socketModeClient, + gormClient: gormClient, + severityService: severityService, + incidentStatusService: incidentStatusService, + logRepository: logRepository, + teamRepository: teamRepository, + socketModeClient: socketModeClient, } } @@ -54,13 +57,13 @@ func (r *Repository) CreateIncidentEntity(request *CreateIncidentDTO, tx *gorm.D if err != nil { return nil, fmt.Errorf("fetch channel conversationInfo failed. err: %v", err) } - severity, err := r.severityRepository.FindSeverityById(uint(severityId)) + 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) - incidentStatusEntity, _ := r.GetIncidentStatusByStatusName(string(request.Status)) + 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}) @@ -69,7 +72,7 @@ func (r *Repository) CreateIncidentEntity(request *CreateIncidentDTO, tx *gorm.D incidentEntity := &IncidentEntity{ Title: request.Title, Description: request.Description, - Status: incidentStatusEntity.ID, + Status: incidentStatus.ID, SeverityId: uint(severityId), DetectionTime: request.DetectionTime, StartTime: request.StartTime, @@ -129,27 +132,27 @@ func (r *Repository) processDiffIds() []byte { case "Status": if differences[index].From != "" { statusIdString, _ := strconv.Atoi(differences[index].From) - statusEntity, _ := r.GetIncidentStatusNameByStatus(uint(statusIdString)) - if statusEntity != nil { - differences[index].From = statusEntity.Name + fromStatus, _ := r.incidentStatusService.GetIncidentStatusByStatusId(uint(statusIdString)) + if fromStatus != nil { + differences[index].From = fromStatus.Name } } statusIdString, _ := strconv.Atoi(differences[index].To) - statusEntity, _ := r.GetIncidentStatusNameByStatus(uint(statusIdString)) - differences[index].To = statusEntity.Name + 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.severityRepository.FindSeverityById(uint(severityIdString)) + severityEntity, _ := r.severityService.FindSeverityById(uint(severityIdString)) if severityEntity != nil { differences[index].From = severityEntity.Name } } severityIdString, _ := strconv.Atoi(differences[index].To) - severityEntity, _ := r.severityRepository.FindSeverityById(uint(severityIdString)) + severityEntity, _ := r.severityService.FindSeverityById(uint(severityIdString)) differences[index].To = severityEntity.Name case "TeamId": @@ -255,57 +258,6 @@ func (r *Repository) UpdateIncidentWithJustification(incidentEntity *IncidentEnt return nil } -func (r *Repository) GetIncidentStatusByStatusName(status string) (*IncidentStatusEntity, error) { - var incidentStatus IncidentStatusEntity - - result := r.gormClient.Find(&incidentStatus, "LOWER(name) = LOWER(?)", status) - if result.Error != nil { - return nil, result.Error - } - if result.RowsAffected == 0 { - return nil, nil - } - - return &incidentStatus, nil -} - -func (r *Repository) GetIncidentStatusNameByStatus(status uint) (*IncidentStatusEntity, error) { - var incidentStatus IncidentStatusEntity - - result := r.gormClient.Find(&incidentStatus, "id = ?", status) - if result.Error != nil { - return nil, result.Error - } - if result.RowsAffected == 0 { - return nil, nil - } - - return &incidentStatus, nil -} - -func (r *Repository) GetOpenIncidents(limit int) (*[]IncidentSeverityTeamDTO, error) { - var incidentSeverityTeamDTO []IncidentSeverityTeamDTO - - result := r.gormClient.Raw(` - select i.title, ins.name as status, i.slack_channel, s.name as severity_name, t.name as team_name - from incident i - inner join severity s on s.id = i.severity_id - inner join team t on t.id = i.team_id - inner join incident_status ins on ins.id = i.status - where ins.name <> ? and i.deleted_at is null - limit ? - `, Resolved, limit).Scan(&incidentSeverityTeamDTO) - - if result.Error != nil { - return nil, result.Error - } - if result.RowsAffected == 0 { - return nil, nil - } - - return &incidentSeverityTeamDTO, nil -} - func (r *Repository) FindIncidentByChannelId(channelId string) (*IncidentEntity, error) { var incidentEntity IncidentEntity @@ -336,19 +288,6 @@ func (r *Repository) FindIncidentById(Id uint) (*IncidentEntity, error) { return &incidentEntity, nil } -func (r *Repository) GetAllOpenIncidents() (*[]IncidentEntity, int, error) { - statusEntities, err := r.FetchAllNonTerminalIncidentStatuses() - if err != nil { - logger.Error(fmt.Sprintf("%s failed to fetch all non terminal incident statuses. Error: %+v", "[incident_repository]", err)) - } - var nonTerminalStatuses []uint - for _, status := range *statusEntities { - nonTerminalStatuses = append(nonTerminalStatuses, status.ID) - } - - return r.GetAllIncidents(nil, nil, nonTerminalStatuses) -} - func (r *Repository) GetAllIncidents(teamsIds, severityIds, statusIds []uint) (*[]IncidentEntity, int, error) { var query = r.gormClient.Model([]IncidentEntity{}) var incidentEntity []IncidentEntity @@ -444,27 +383,6 @@ func (r *Repository) FetchAllIncidentsPaginated( return incidentEntity, int(totalElements), nil } -func (r *Repository) FindIncidentSeverityTeamJoin(slackChannelId string) (*IncidentSeverityTeamDTO, error) { - var incidentSeverityTeamJoinEntity IncidentSeverityTeamDTO - - result := r.gormClient.Table("incident"). - Where("incident.slack_channel = ? and incident.deleted_at IS NULL", slackChannelId). - Joins("JOIN severity ON severity.id = incident.severity_id"). - Joins("JOIN team ON team.id = incident.team_id"). - Joins("JOIN incident_status on incident.status = incident_status.id"). - Select("incident.title, incident_status.name as status, incident.slack_channel, severity.name as severity_name ,team.name as team_name"). - Scan(&incidentSeverityTeamJoinEntity) - - if result.Error != nil { - return nil, result.Error - } - if result.RowsAffected == 0 { - return nil, nil - } - - return &incidentSeverityTeamJoinEntity, nil -} - func (r *Repository) UpsertIncidentRole(addIncidentRoleRequest *AddIncidentRoleRequest) error { incidentRolesEntity := &IncidentRoleEntity{ IncidentId: addIncidentRoleRequest.IncidentId, @@ -498,48 +416,6 @@ func (r *Repository) UpsertIncidentRole(addIncidentRoleRequest *AddIncidentRoleR return gorm.ErrInvalidData } -func (r *Repository) FindIncidentStatusById(incidentStatusId uint) (*IncidentStatusEntity, error) { - var incidentStatusEntity IncidentStatusEntity - - result := r.gormClient.Find(&incidentStatusEntity, "id = ?", incidentStatusId) - if result.Error != nil { - return nil, result.Error - } - if result.RowsAffected == 0 { - return nil, nil - } - - return &incidentStatusEntity, nil -} - -func (r *Repository) FindIncidentStatusByName(name string) (*IncidentStatusEntity, error) { - var incidentStatusEntity IncidentStatusEntity - - result := r.gormClient.Find(&incidentStatusEntity, "LOWER(name) = LOWER(?)", name) - if result.Error != nil { - return nil, result.Error - } - if result.RowsAffected == 0 { - return nil, nil - } - - return &incidentStatusEntity, nil -} - -func (r *Repository) FetchAllIncidentStatuses() (*[]IncidentStatusEntity, error) { - var incidentStatusEntity []IncidentStatusEntity - result := r.gormClient.Find(&incidentStatusEntity) - if result.Error != nil { - return nil, result.Error - } - - if result.RowsAffected == 0 { - return nil, nil - } - - return &incidentStatusEntity, nil -} - func (r *Repository) CreateIncidentChannelEntry(request *CreateIncidentChannelEntry) error { messageEntity := &IncidentChannelEntity{ SlackChannel: request.SlackChannel, @@ -648,28 +524,6 @@ func (r *Repository) SaveIncidentTag(entity IncidentTagEntity) (*IncidentTagEnti return &entity, nil } -func (r *Repository) FindIncidentsByNotResolvedStatusAndGreaterSeverityTatThanCurrentDateAndNotSev0(db *gorm.DB, resolvedIndex int) ([]IncidentEntity, error) { - var incidentEntity []IncidentEntity - - currentTime := time.Now() - - result := r.gormClient.Table("incident"). - Where("incident_status.name <> ? and incident_status.name <> ? and incident_status.name <> ? and incident.severity_tat <= ? and severity.id <> ?", Resolved, Duplicated, Monitoring, currentTime, 1). - Joins("JOIN severity ON severity.id = incident.severity_id"). - Joins("JOIN incident_status on incident.status = incident_status.id"). - Select("incident.*"). - Scan(&incidentEntity) - - if result.Error != nil { - return nil, result.Error - } - if result.RowsAffected == 0 { - return nil, nil - } - - return incidentEntity, nil -} - func (r *Repository) GetIncidentsForEscalation() ([]IncidentEntity, error) { var incidentEntity []IncidentEntity @@ -728,32 +582,12 @@ func (r *Repository) GetIncidentRolesByIncidentIdsAndRole(incidentsIds []uint, r return incidentRoleEntity, nil } -func (r *Repository) GetOpenIncidentsByCreatorIdForGivenTeam(created_by string, teamId uint) (*[]IncidentEntity, error) { +func (r *Repository) GetOpenIncidentsByCreatorIdForGivenTeamAndStatuses(created_by string, teamId uint, statusIds []uint) (*[]IncidentEntity, error) { var incidentEntities []IncidentEntity - - incidentStatuses, err := r.FetchAllNonTerminalIncidentStatuses() - - if err != nil { - logger.Error("Error in fetching non terminal incident statuses", zap.Error(err)) - return nil, err - } - - if incidentStatuses == nil { - err := errors.New("Could not find any non terminal incident statuses") - logger.Error("Error in fetching non terminal incident statuses", zap.Error(err)) - return nil, err - } - - var statusIds []uint - - for _, status := range *incidentStatuses { - statusIds = append(statusIds, status.ID) - } - 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(err)) + 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 } @@ -771,20 +605,6 @@ func (r *Repository) FindOpenIncidentsByTeamOrderedByCreationTimeAndSeverity(tea return &incidentEntity, nil } -func (r *Repository) FetchAllNonTerminalIncidentStatuses() (*[]IncidentStatusEntity, error) { - var incidentStatusEntity []IncidentStatusEntity - result := r.gormClient.Find(&incidentStatusEntity, "is_terminal_status", false) - if result.Error != nil { - return nil, result.Error - } - - if result.RowsAffected == 0 { - return nil, nil - } - - return &incidentStatusEntity, nil -} - func (r *Repository) FetchIncidentsWithSeverityTatBetweenGivenRange(slaStart, slaEnd string) (*[]IncidentEntity, error) { var incidents []IncidentEntity query := r.gormClient.Where( diff --git a/model/incident/incident_repository_interface.go b/model/incident/incident_repository_interface.go index db8d49c..0b9e907 100644 --- a/model/incident/incident_repository_interface.go +++ b/model/incident/incident_repository_interface.go @@ -1,6 +1,8 @@ package incident -import "gorm.io/gorm" +import ( + "gorm.io/gorm" +) type IIncidentRepository interface { CreateIncidentEntity(request *CreateIncidentDTO, tx *gorm.DB) (*IncidentEntity, error) @@ -9,12 +11,8 @@ type IIncidentRepository interface { UpdateIncidentWithJustification(incidentEntity *IncidentEntity, justification string) error CreateIncidentTag(incidentId, tagId uint) (*IncidentTagEntity, error) CreateIncidentTagsInBatchesForAnIncident(incidentId uint, tagIds []uint) (*[]IncidentTagEntity, error) - GetIncidentStatusByStatusName(status string) (*IncidentStatusEntity, error) - GetIncidentStatusNameByStatus(status uint) (*IncidentStatusEntity, error) - GetOpenIncidents(limit int) (*[]IncidentSeverityTeamDTO, error) FindIncidentByChannelId(channelId string) (*IncidentEntity, error) FindIncidentById(Id uint) (*IncidentEntity, error) - GetAllOpenIncidents() (*[]IncidentEntity, int, error) GetAllIncidents(teamsIds, severityIds, statusIds []uint) (*[]IncidentEntity, int, error) FetchAllIncidentsPaginated( productIds []uint, @@ -28,11 +26,7 @@ type IIncidentRepository interface { from string, to string, ) ([]IncidentEntity, int, error) - FindIncidentSeverityTeamJoin(slackChannelId string) (*IncidentSeverityTeamDTO, error) UpsertIncidentRole(addIncidentRoleRequest *AddIncidentRoleRequest) error - FindIncidentStatusById(incidentStatusId uint) (*IncidentStatusEntity, error) - FindIncidentStatusByName(name string) (*IncidentStatusEntity, error) - FetchAllIncidentStatuses() (*[]IncidentStatusEntity, error) CreateIncidentChannelEntry(request *CreateIncidentChannelEntry) error GetIncidentChannels(incidentId uint) (*[]IncidentChannelEntity, error) GetIncidentTagsByIncidentId(incidentId uint) (*[]IncidentTagEntity, error) @@ -44,9 +38,8 @@ type IIncidentRepository interface { GetIncidentRoleByIncidentIdAndRole(incident_id uint, role string) (*IncidentRoleEntity, error) GetIncidentRolesByIncidentIdsAndRole(incidentsIds []uint, role string) ([]IncidentRoleEntity, error) FindOpenIncidentsByTeamOrderedByCreationTimeAndSeverity(team string) (*[]IncidentEntity, error) - FetchAllNonTerminalIncidentStatuses() (*[]IncidentStatusEntity, error) UpdateIncidentChannelEntity(incidentChannelEntity *IncidentChannelEntity) error - GetOpenIncidentsByCreatorIdForGivenTeam(created_by string, teamId uint) (*[]IncidentEntity, error) + GetOpenIncidentsByCreatorIdForGivenTeamAndStatuses(created_by string, teamId uint, statusIds []uint) (*[]IncidentEntity, error) GetIncidentTagsByTagIds(incidentId uint, tagIds []uint) (*IncidentTagEntity, error) FetchIncidentsWithSeverityTatBetweenGivenRange(slaStart, slaEnd string) (*[]IncidentEntity, error) } diff --git a/model/incidentStatus/entity.go b/model/incidentStatus/entity.go new file mode 100644 index 0000000..a0d4f54 --- /dev/null +++ b/model/incidentStatus/entity.go @@ -0,0 +1,26 @@ +package incidentStatus + +import ( + "gorm.io/gorm" +) + +// IncidentStatusEntity contains the possible incident statuses +type IncidentStatusEntity struct { + gorm.Model + Name string `gorm:"column:name"` + Description string `gorm:"column:description"` + IsTerminalStatus bool `gorm:"column:is_terminal_status"` +} + +func (i IncidentStatusEntity) ToDTO() IncidentStatusDTO { + return IncidentStatusDTO{ + ID: i.ID, + Name: i.Name, + Description: i.Description, + IsTerminalStatus: i.IsTerminalStatus, + } +} + +func (IncidentStatusEntity) TableName() string { + return "incident_status" +} diff --git a/model/incidentStatus/model.go b/model/incidentStatus/model.go new file mode 100644 index 0000000..f67fa88 --- /dev/null +++ b/model/incidentStatus/model.go @@ -0,0 +1,8 @@ +package incidentStatus + +type IncidentStatusDTO struct { + ID uint + Name string + Description string + IsTerminalStatus bool +} diff --git a/model/severity/severity_repository_interface.go b/model/severity/severity_repository_interface.go deleted file mode 100644 index 66f86d0..0000000 --- a/model/severity/severity_repository_interface.go +++ /dev/null @@ -1,9 +0,0 @@ -package severity - -type ISeverityRepository interface { - GetAllActiveSeverity() (*[]SeverityEntity, error) - FindIncidentSeverityEntityById(id int) (*SeverityEntity, error) - FindSeverityById(severityId uint) (*SeverityEntity, error) - FindSeverityByName(severityName string) (*SeverityEntity, error) - Update(severityEntity *SeverityEntity) error -} diff --git a/repository/incidentStatus/incident_status_repository.go b/repository/incidentStatus/incident_status_repository.go new file mode 100644 index 0000000..14d1c61 --- /dev/null +++ b/repository/incidentStatus/incident_status_repository.go @@ -0,0 +1,18 @@ +package incidentStatus + +import ( + "gorm.io/gorm" + "houston/model/incidentStatus" +) + +type IncidentStatusRepository interface { + GetNonTerminalStatusesNotMatchingIncidentStatus(channelID string) ([]incidentStatus.IncidentStatusEntity, error) + GetIncidentStatusByStatusName(status string) (*incidentStatus.IncidentStatusEntity, error) + GetIncidentStatusByStatusId(statusId uint) (*incidentStatus.IncidentStatusEntity, error) + GetAllIncidentStatuses() (*[]incidentStatus.IncidentStatusEntity, error) + FetchAllNonTerminalStatuses() (*[]incidentStatus.IncidentStatusEntity, error) +} + +func NewIncidentStatusRepository(db *gorm.DB) IncidentStatusRepository { + return &incidentStatusRepositoryImpl{db: db} +} diff --git a/repository/incidentStatus/incident_status_repository_impl.go b/repository/incidentStatus/incident_status_repository_impl.go new file mode 100644 index 0000000..6ecda3f --- /dev/null +++ b/repository/incidentStatus/incident_status_repository_impl.go @@ -0,0 +1,80 @@ +package incidentStatus + +import ( + "gorm.io/gorm" + "houston/model/incidentStatus" +) + +type incidentStatusRepositoryImpl struct { + db *gorm.DB +} + +func (repo *incidentStatusRepositoryImpl) GetNonTerminalStatusesNotMatchingIncidentStatus(channelID string) ([]incidentStatus.IncidentStatusEntity, error) { + var statuses []incidentStatus.IncidentStatusEntity + err := repo.db.Table("incident_status"). + Joins("Join incident on incident.slack_channel = ? AND incident.status != incident_status.id", channelID). + Where("incident_status.is_terminal_status = ?", false). + Find(&statuses).Error + + if err != nil { + return nil, err + } + + return statuses, nil +} + +func (repo *incidentStatusRepositoryImpl) GetIncidentStatusByStatusName(status string) (*incidentStatus.IncidentStatusEntity, error) { + var incidentStatus incidentStatus.IncidentStatusEntity + + result := repo.db.Find(&incidentStatus, "LOWER(name) = LOWER(?)", status) + if result.Error != nil { + return nil, result.Error + } + if result.RowsAffected == 0 { + return nil, nil + } + + return &incidentStatus, nil +} + +func (repo *incidentStatusRepositoryImpl) GetIncidentStatusByStatusId(statusId uint) (*incidentStatus.IncidentStatusEntity, error) { + var incidentStatus incidentStatus.IncidentStatusEntity + + result := repo.db.Find(&incidentStatus, "id = ?", statusId) + if result.Error != nil { + return nil, result.Error + } + if result.RowsAffected == 0 { + return nil, nil + } + + return &incidentStatus, nil +} + +func (repo *incidentStatusRepositoryImpl) GetAllIncidentStatuses() (*[]incidentStatus.IncidentStatusEntity, error) { + var incidentStatusEntity []incidentStatus.IncidentStatusEntity + result := repo.db.Find(&incidentStatusEntity) + if result.Error != nil { + return nil, result.Error + } + + if result.RowsAffected == 0 { + return nil, nil + } + + return &incidentStatusEntity, nil +} + +func (repo *incidentStatusRepositoryImpl) FetchAllNonTerminalStatuses() (*[]incidentStatus.IncidentStatusEntity, error) { + var incidentStatusEntity []incidentStatus.IncidentStatusEntity + result := repo.db.Find(&incidentStatusEntity, "is_terminal_status", false) + if result.Error != nil { + return nil, result.Error + } + + if result.RowsAffected == 0 { + return nil, nil + } + + return &incidentStatusEntity, nil +} diff --git a/model/severity/severity.go b/repository/severity/severity_repository.go similarity index 55% rename from model/severity/severity.go rename to repository/severity/severity_repository.go index e75728b..10d0619 100644 --- a/model/severity/severity.go +++ b/repository/severity/severity_repository.go @@ -4,6 +4,7 @@ import ( "go.uber.org/zap" "gorm.io/gorm" "houston/logger" + "houston/model/severity" ) type Repository struct { @@ -16,9 +17,9 @@ func NewSeverityRepository(gormClient *gorm.DB) *Repository { } } -func (r *Repository) GetAllActiveSeverity() (*[]SeverityEntity, error) { - var severityEntity []SeverityEntity - result := r.gormClient.Where("deleted_at is NULL").Order("name desc").Find(&severityEntity) +func (s *Repository) GetAllActiveSeverity() (*[]severity.SeverityEntity, error) { + var severityEntity []severity.SeverityEntity + result := s.gormClient.Where("deleted_at is NULL").Order("name desc").Find(&severityEntity) if result.Error != nil { logger.Error("fetching severity query failed", zap.Error(result.Error)) return nil, result.Error @@ -30,8 +31,8 @@ func (r *Repository) GetAllActiveSeverity() (*[]SeverityEntity, error) { return &severityEntity, nil } -func (s *Repository) FindIncidentSeverityEntityById(id int) (*SeverityEntity, error) { - var severityEntity SeverityEntity +func (s *Repository) FindIncidentSeverityEntityById(id int) (*severity.SeverityEntity, error) { + var severityEntity severity.SeverityEntity result := s.gormClient.Find(&severityEntity, "id = ?", id) if result.Error != nil { @@ -45,8 +46,8 @@ func (s *Repository) FindIncidentSeverityEntityById(id int) (*SeverityEntity, er return &severityEntity, nil } -func (s *Repository) FindSeverityById(severityId uint) (*SeverityEntity, error) { - var severityEntity SeverityEntity +func (s *Repository) FindSeverityById(severityId uint) (*severity.SeverityEntity, error) { + var severityEntity severity.SeverityEntity result := s.gormClient.Find(&severityEntity, "id = ?", severityId) if result.Error != nil { @@ -60,8 +61,8 @@ func (s *Repository) FindSeverityById(severityId uint) (*SeverityEntity, error) return &severityEntity, nil } -func (s *Repository) FindSeverityByName(severityName string) (*SeverityEntity, error) { - var severityEntity SeverityEntity +func (s *Repository) FindSeverityByName(severityName string) (*severity.SeverityEntity, error) { + var severityEntity severity.SeverityEntity result := s.gormClient.Find(&severityEntity, "LOWER(name) = LOWER(?)", severityName) if result.Error != nil { @@ -75,10 +76,24 @@ func (s *Repository) FindSeverityByName(severityName string) (*SeverityEntity, e return &severityEntity, nil } -func (s *Repository) Update(severityEntity *SeverityEntity) error { +func (s *Repository) Update(severityEntity *severity.SeverityEntity) error { result := s.gormClient.Updates(severityEntity) if result.Error != nil { return result.Error } return nil } + +func (s *Repository) GetSeveritiesNotMatchingIncidentSeverity(channelID string) ([]severity.SeverityEntity, error) { + var severities []severity.SeverityEntity + err := s.gormClient.Table("severity"). + Joins("JOIN incident ON incident.slack_channel = ? AND severity.id != incident.severity_id", channelID). + Order("severity.priority DESC"). + Find(&severities).Error + + if err != nil { + return nil, err + } + + return severities, nil +} diff --git a/repository/severity/severity_repository_interface.go b/repository/severity/severity_repository_interface.go new file mode 100644 index 0000000..0b84503 --- /dev/null +++ b/repository/severity/severity_repository_interface.go @@ -0,0 +1,12 @@ +package severity + +import "houston/model/severity" + +type ISeverityRepository interface { + GetAllActiveSeverity() (*[]severity.SeverityEntity, error) + FindIncidentSeverityEntityById(id int) (*severity.SeverityEntity, error) + FindSeverityById(severityId uint) (*severity.SeverityEntity, error) + FindSeverityByName(severityName string) (*severity.SeverityEntity, error) + Update(severityEntity *severity.SeverityEntity) error + GetSeveritiesNotMatchingIncidentSeverity(channelID string) ([]severity.SeverityEntity, error) +} diff --git a/service/filter_service.go b/service/filter_service.go index e41bb65..dfc6a38 100644 --- a/service/filter_service.go +++ b/service/filter_service.go @@ -5,8 +5,9 @@ import ( "houston/logger" "houston/model/incident" "houston/model/log" - "houston/model/severity" "houston/model/team" + "houston/repository/severity" + incidentStatus "houston/service/incidentStatus" "houston/service/products" response "houston/service/response" common "houston/service/response/common" @@ -19,16 +20,18 @@ import ( ) type filterService struct { - gin *gin.Engine - db *gorm.DB - productService products.ProductService + gin *gin.Engine + db *gorm.DB + productService products.ProductService + incidentStatusService incidentStatus.IncidentStatusService } func NewFilterService(gin *gin.Engine, db *gorm.DB) *filterService { return &filterService{ - gin: gin, - db: db, - productService: appcontext.GetProductsService(), + gin: gin, + db: db, + productService: appcontext.GetProductsService(), + incidentStatusService: appcontext.GetIncidentStatusService(), } } @@ -37,8 +40,8 @@ func (f *filterService) GetFilters(c *gin.Context) { logger.Info("Inside GetFilter function", zap.String("correlationId", correlationId)) var filterResponses []response.FilterResponse - incidentRepository, severityRepository, teamRespository := f.GetEntityRepositories() - incidentStatusFilterData, err := f.GetIncidentStatusFilterData(incidentRepository) + _, severityRepository, teamRespository := f.GetEntityRepositories() + incidentStatusFilterData, err := f.GetIncidentStatusFilterData() if err != nil { logger.Error("error in fetching incident status data", zap.Error(err)) c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil)) @@ -73,18 +76,21 @@ func (f *filterService) GetEntityRepositories() ( severityRepository := severity.NewSeverityRepository(f.db) logRepository := log.NewLogRepository(f.db) teamRespository := team.NewTeamRepository(f.db, logRepository) - incidentRepository := incident.NewIncidentRepository(f.db, severityRepository, logRepository, teamRespository, nil) + incidentRepository := incident.NewIncidentRepository( + f.db, appcontext.GetSeverityService(), appcontext.GetIncidentStatusService(), + logRepository, teamRespository, nil, + ) return incidentRepository, severityRepository, teamRespository } -func (f *filterService) GetIncidentStatusFilterData(incidentRepository *incident.Repository) (*response.FilterResponse, error) { - incidentStatusEntities, err := incidentRepository.FetchAllIncidentStatuses() +func (f *filterService) GetIncidentStatusFilterData() (*response.FilterResponse, error) { + incidentStatuses, err := f.incidentStatusService.GetAllIncidentStatuses() if err != nil { logger.Error("error in fetching incident statues", zap.Error(err)) return nil, err } var incidentStatusOptions []response.Options - for _, incidentStatus := range *incidentStatusEntities { + for _, incidentStatus := range *incidentStatuses { incidentStatusOptions = append(incidentStatusOptions, response.Options{ Label: incidentStatus.Name, Value: strconv.Itoa(int(incidentStatus.ID)), diff --git a/service/incident/impl/escalate_incident_test.go b/service/incident/impl/escalate_incident_test.go index ae2774e..754cc9a 100644 --- a/service/incident/impl/escalate_incident_test.go +++ b/service/incident/impl/escalate_incident_test.go @@ -82,7 +82,7 @@ func (suite *IncidentServiceSuite) Test_Escalate_Success() { suite.incidentRepository.UpdateIncidentWithJustificationMock.When(mockIncident, "").Then(nil) suite.slackService.PostMessageByChannelIDMock.Return("", nil) suite.teamRepository.FindTeamByIdMock.Return(GetMockTeamWithId(1), nil) - suite.incidentRepository.FindIncidentStatusByIdMock.Return(GetMockIncidentStatus(), nil) + suite.incidentStatusService.GetIncidentStatusByStatusIdMock.Return(GetMockIncidentStatusDTO(), nil) suite.slackService.UpdateMessageWithAttachmentsMock.Return(nil) @@ -98,7 +98,7 @@ func (suite *IncidentServiceSuite) Test_Escalate_Success() { suite.slackService.PostMessageOptionMock.Return("", nil) - suite.incidentRepository.GetOpenIncidentsByCreatorIdForGivenTeamMock.Return(&krakatoaIncidents, nil) + suite.incidentRepository.GetOpenIncidentsByCreatorIdForGivenTeamAndStatusesMock.Return(&krakatoaIncidents, nil) suite.krakatoaService.ExecuteKrakatoaWorkflowMock.Return(nil) tu := teamUserModel.TeamUserDTO{User: user.UserDTO{ID: 1, Name: "test", Email: "", SlackUserId: "1", Active: true}} diff --git a/service/incident/impl/fetch_incidents.go b/service/incident/impl/fetch_incidents.go index 6eb2029..174959f 100644 --- a/service/incident/impl/fetch_incidents.go +++ b/service/incident/impl/fetch_incidents.go @@ -1,7 +1,7 @@ package impl import ( - "houston/common/util" + "houston/common/util/dto" "houston/model/incident" "time" ) @@ -14,5 +14,5 @@ func (i *IncidentServiceV2) FetchIncidentsApproachingSlaBreach() ([]incident.Inc if err != nil { return nil, err } - return util.ToDtoArray[incident.IncidentEntity, incident.IncidentDTO](*incidents), nil + return dto.ToDtoArray[incident.IncidentEntity, incident.IncidentDTO](*incidents), nil } diff --git a/service/incident/impl/incident_service_test.go b/service/incident/impl/incident_service_test.go index 65d9810..9e929ab 100644 --- a/service/incident/impl/incident_service_test.go +++ b/service/incident/impl/incident_service_test.go @@ -11,6 +11,7 @@ import ( "houston/logger" "houston/mocks" "houston/model/incident" + "houston/model/incidentStatus" "houston/model/incident_channel" "houston/model/product" "houston/model/severity" @@ -40,6 +41,7 @@ type IncidentServiceSuite struct { rcaService mocks.IRcaServiceMock severityService mocks.ISeverityServiceMock teamServiceV2 mocks.ITeamServiceV2Mock + incidentStatusService mocks.IncidentStatusServiceMock mockDirectory string mockPngName string mockCsvName string @@ -63,8 +65,8 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_Success() { mockUpdatedTeam := GetMockTeamWithId(suite.updatedTeamId) mockSeverity := GetMockSeverityWithId(suite.previousSeverityId) mockUpdatedSeverity := GetMockSeverityWithId(suite.updatedSeverityId) - mockStatus := GetMockStatusWithId(suite.previousStatusId) - mockUpdatedStatus := GetMockStatusWithId(suite.updatedStatusId) + mockStatusDTO := GetMockStatusDTOWithId(suite.previousStatusId) + mockUpdatedStatusDTO := GetMockStatusDTOWithId(suite.updatedStatusId) mockChannels := GetMockChannels() mockMetaData := getMockMetaData() krakatoaIncidents := []incident.IncidentEntity{*GetMockIncident(), *GetMockIncident()} @@ -83,6 +85,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_Success() { suite.userRepository.FindHoustonUserBySlackUserIdMock.When(mockUser.ID). Then(mockHoustonUser, nil) + suite.incidentStatusService.FetchAllNonTerminalStatusIdsMock.Return([]uint{1, 2}, nil) suite.teamRepository.FindTeamByIdMock.When(suite.updatedTeamId). Then(mockUpdatedTeam, nil) @@ -93,11 +96,11 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_Success() { suite.severityRepository.FindSeverityByIdMock.When(suite.updatedSeverityId). Then(mockUpdatedSeverity, nil) - suite.incidentRepository.FindIncidentStatusByIdMock.When(suite.previousStatusId). - Then(mockStatus, nil) + suite.incidentStatusService.GetIncidentStatusByStatusIdMock.When(suite.previousStatusId). + Then(mockStatusDTO, nil) - suite.incidentRepository.FindIncidentStatusByIdMock.When(suite.updatedStatusId). - Then(mockUpdatedStatus, nil) + suite.incidentStatusService.GetIncidentStatusByStatusIdMock.When(suite.updatedStatusId). + Then(mockUpdatedStatusDTO, nil) suite.incidentChannelService.GetIncidentChannelsMock.When(mockIncident.ID). Then(mockChannels, nil) @@ -122,7 +125,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_Success() { suite.slackService.PostMessageOptionMock.Return("", nil) - suite.incidentRepository.GetOpenIncidentsByCreatorIdForGivenTeamMock.Return(&krakatoaIncidents, nil) + suite.incidentRepository.GetOpenIncidentsByCreatorIdForGivenTeamAndStatusesMock.Return(&krakatoaIncidents, nil) suite.krakatoaService.ExecuteKrakatoaWorkflowMock.Return(nil) tu := teamUserModel.TeamUserDTO{User: user.UserDTO{ID: 1, Name: "test", Email: "", SlackUserId: "1", Active: true}} @@ -220,7 +223,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_InvalidStatus() { suite.severityRepository.FindSeverityByIdMock.Return(mockSeverity, nil) - suite.incidentRepository.FindIncidentStatusByIdMock.Return(nil, errors.New("record not found")) + suite.incidentStatusService.GetIncidentStatusByStatusIdMock.Return(nil, errors.New("record not found")) _, err := suite.incidentService.UpdateIncident( service.UpdateIncidentRequest{ @@ -237,7 +240,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_InvalidChannel() { mockUser := GetMockUser() mockTeam := GetMockTeamWithId(suite.previousTeamId) mockSeverity := GetMockSeverityWithId(suite.previousSeverityId) - mockStatus := GetMockStatusWithId(suite.previousStatusId) + mockStatus := GetMockStatusDTOWithId(suite.previousStatusId) suite.incidentRepository.FindIncidentByIdMock.When(suite.mockIncidentId). Then(mockIncident, nil) @@ -248,7 +251,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_InvalidChannel() { suite.severityRepository.FindSeverityByIdMock.Return(mockSeverity, nil) - suite.incidentRepository.FindIncidentStatusByIdMock.Return(mockStatus, nil) + suite.incidentStatusService.GetIncidentStatusByStatusIdMock.Return(mockStatus, nil) suite.incidentChannelService.GetIncidentChannelsMock.Return(nil, errors.New("record not found")) @@ -267,7 +270,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_DBError() { mockUser := GetMockUser() mockTeam := GetMockTeamWithId(suite.previousTeamId) mockSeverity := GetMockSeverityWithId(suite.previousSeverityId) - mockStatus := GetMockStatusWithId(suite.previousStatusId) + mockStatus := GetMockStatusDTOWithId(suite.previousStatusId) mockChannels := GetMockChannels() mockHoustonUser := GetMockHoustonUser() @@ -280,7 +283,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_DBError() { suite.severityRepository.FindSeverityByIdMock.Return(mockSeverity, nil) - suite.incidentRepository.FindIncidentStatusByIdMock.Return(mockStatus, nil) + suite.incidentStatusService.GetIncidentStatusByStatusIdMock.Return(mockStatus, nil) suite.incidentChannelService.GetIncidentChannelsMock.Return(mockChannels, nil) @@ -303,7 +306,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_SlackError() { mockUser := GetMockUser() mockTeam := GetMockTeamWithId(suite.previousTeamId) mockSeverity := GetMockSeverityWithId(suite.previousSeverityId) - mockStatus := GetMockStatusWithId(suite.previousStatusId) + mockStatus := GetMockStatusDTOWithId(suite.previousStatusId) mockChannels := GetMockChannels() mockHoustonUser := GetMockHoustonUser() @@ -319,7 +322,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_SlackError() { suite.severityRepository.FindSeverityByIdMock.Return(mockSeverity, nil) - suite.incidentRepository.FindIncidentStatusByIdMock.Return(mockStatus, nil) + suite.incidentStatusService.GetIncidentStatusByStatusIdMock.Return(mockStatus, nil) suite.incidentChannelService.GetIncidentChannelsMock.Return(mockChannels, nil) @@ -348,7 +351,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_ChannelRenameError() { mockUser := GetMockUser() mockTeam := GetMockTeamWithId(suite.previousTeamId) mockSeverity := GetMockSeverityWithId(suite.previousSeverityId) - mockStatus := GetMockStatusWithId(suite.previousStatusId) + mockStatus := GetMockStatusDTOWithId(suite.previousStatusId) mockChannels := GetMockChannels() suite.incidentRepository.FindIncidentByIdMock.When(suite.mockIncidentId). @@ -360,7 +363,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_ChannelRenameError() { suite.severityRepository.FindSeverityByIdMock.Return(mockSeverity, nil) - suite.incidentRepository.FindIncidentStatusByIdMock.Return(mockStatus, nil) + suite.incidentStatusService.GetIncidentStatusByStatusIdMock.Return(mockStatus, nil) suite.incidentChannelService.GetIncidentChannelsMock.Return(mockChannels, nil) @@ -503,8 +506,8 @@ func GetMockSeverityDTOWitId(severityId uint) *severity.SeverityDTO { } } -func GetMockStatusWithId(statusId uint) *incident.IncidentStatusEntity { - return &incident.IncidentStatusEntity{ +func GetMockStatusWithId(statusId uint) *incidentStatus.IncidentStatusEntity { + return &incidentStatus.IncidentStatusEntity{ Model: gorm.Model{ ID: statusId, CreatedAt: time.Time{}, @@ -515,6 +518,15 @@ func GetMockStatusWithId(statusId uint) *incident.IncidentStatusEntity { } } +func GetMockStatusDTOWithId(statusId uint) *incidentStatus.IncidentStatusDTO { + return &incidentStatus.IncidentStatusDTO{ + ID: statusId, + Name: "Mock Status", + Description: "Mock Description", + IsTerminalStatus: false, + } +} + func GetMockChannels() []incident_channel.IncidentChannelEntity { return []incident_channel.IncidentChannelEntity{ { @@ -584,6 +596,7 @@ func (suite *IncidentServiceSuite) SetupTest() { suite.teamUserService = *mocks.NewITeamUserServiceMock(suite.T()) suite.severityService = *mocks.NewISeverityServiceMock(suite.T()) suite.teamServiceV2 = *mocks.NewITeamServiceV2Mock(suite.T()) + suite.incidentStatusService = *mocks.NewIncidentStatusServiceMock(suite.T()) suite.incidentService = &IncidentServiceV2{ db: nil, slackService: &suite.slackService, @@ -600,6 +613,7 @@ func (suite *IncidentServiceSuite) SetupTest() { teamUserService: &suite.teamUserService, severityService: &suite.severityService, teamServiceV2: &suite.teamServiceV2, + incidentStatusService: &suite.incidentStatusService, } suite.mockDirectory = "test_file" diff --git a/service/incident/impl/incident_service_v2.go b/service/incident/impl/incident_service_v2.go index 364e373..3fc678b 100644 --- a/service/incident/impl/incident_service_v2.go +++ b/service/incident/impl/incident_service_v2.go @@ -12,11 +12,13 @@ import ( "gorm.io/gorm" "houston/common/metrics" "houston/common/util" + "houston/common/util/dto" houstonSlackUtil "houston/common/util/slack" stringUtil "houston/common/util/string" "houston/internal/processor/action/view" "houston/logger" "houston/model/incident" + incidentStatusModel "houston/model/incidentStatus" "houston/model/incident_channel" incidentJiraModel "houston/model/incident_jira" "houston/model/log" @@ -31,8 +33,10 @@ import ( "houston/pkg/google/googleDrive" "houston/pkg/rest" "houston/repository/externalTeamRepo" + "houston/repository/incidentStatus" rcaRepository "houston/repository/rca/impl" "houston/repository/rcaInput" + severityRepo "houston/repository/severity" teamSeverityRepo "houston/repository/teamSeverity" "houston/repository/teamUser" teamUserSeverityRepo "houston/repository/teamUserSeverity" @@ -41,6 +45,7 @@ import ( "houston/service/documentService" "houston/service/google" incidentService "houston/service/incident" + incidentStatusRepo "houston/service/incidentStatus" incidentChannel "houston/service/incident_channel" "houston/service/incident_jira" "houston/service/krakatoa" @@ -76,7 +81,7 @@ type IncidentServiceV2 struct { slackService slack.ISlackService incidentChannelService incidentChannel.IIncidentChannelService teamRepository team.ITeamRepository - severityRepository severity.ISeverityRepository + severityRepository severityRepo.ISeverityRepository incidentRepository incident.IIncidentRepository userRepository user.IUserRepository krakatoaService krakatoa.IKrakatoaService @@ -88,6 +93,7 @@ type IncidentServiceV2 struct { alertService alertService.IAlertService teamUserService teamUser2.ITeamUserService severityService severityService.ISeverityService + incidentStatusService incidentStatusRepo.IncidentStatusService } /* @@ -96,13 +102,15 @@ public function to build and return the incidentservicev2 struct with required d func NewIncidentServiceV2(db *gorm.DB) *IncidentServiceV2 { logRepository := log.NewLogRepository(db) teamRepository := team.NewTeamRepository(db, logRepository) - severityRepository := severity.NewSeverityRepository(db) + severityRepository := severityRepo.NewSeverityRepository(db) + incidentStatusService := incidentStatusRepo.NewIncidentStatusService(incidentStatus.NewIncidentStatusRepository(db)) userRepository := user.NewUserRepository(db) slackService := slack.NewSlackService() incidentRepository := incident.NewIncidentRepository( - db, severityRepository, logRepository, teamRepository, slackService.SocketModeClientWrapper.GetClient(), + db, severityServiceImpl.NewSeverityService(severityRepository), incidentStatusService, + logRepository, teamRepository, slackService.SocketModeClientWrapper.GetClient(), ) - severityService := severityServiceImpl.NewSeverityService(severity.NewSeverityRepository(db)) + severityService := severityServiceImpl.NewSeverityService(severityRepo.NewSeverityRepository(db)) incidentChannelService := incidentChannel.NewIncidentChannelService(db) krakatoaService := krakatoa.NewKrakatoaService() calendarActions := conference.GetCalendarActions() @@ -140,6 +148,7 @@ func NewIncidentServiceV2(db *gorm.DB) *IncidentServiceV2 { alertService: alertService.NewAlertService(), teamUserService: teamUserService, severityService: severityService, + incidentStatusService: incidentStatusService, } driveActions, _ := googleDrive.NewGoogleDriveActions() incidentService.rcaService = rcaServiceImpl.NewRcaService( @@ -190,7 +199,7 @@ func (i *IncidentServiceV2) PostIncidentCreationWorkflow( if err != nil { logger.Error(fmt.Sprintf("%s failed to get team and severity entity", logTag), zap.Error(err)) } - incidentStatusEntity, err := getIncidentStatusEntity(i, incidentEntity.ID, incidentEntity.Status, incidentEntity.IncidentName) + incidentStatus, err := getIncidentStatus(i, incidentEntity.ID, incidentEntity.Status, incidentEntity.IncidentName) if err != nil { logger.Error(fmt.Sprintf("%s failed to get incident status entity", logTag), zap.Error(err)) } @@ -200,7 +209,7 @@ func (i *IncidentServiceV2) PostIncidentCreationWorkflow( incidentEntity, responderTeam, severityEntity, - incidentStatusEntity, + incidentStatus, blazeGroupChannelID, ) if err != nil { @@ -427,8 +436,19 @@ func getJQLFromJiraLinks(jiraLinks ...string) (string, error) { // GetAllOpenIncidents - returns list of all the open incidents and length of the result when success otherwise error func (i *IncidentServiceV2) GetAllOpenIncidents() ([]incident.IncidentDTO, int, error) { - incidents, resultLength, err := i.incidentRepository.GetAllOpenIncidents() - return util.ToDtoArray[incident.IncidentEntity, incident.IncidentDTO](*incidents), resultLength, err + nonTerminalStatusIds, err := i.incidentStatusService.FetchAllNonTerminalStatusIds() + if err != nil { + logger.Error(fmt.Sprintf("%s failed to fetch all non-terminal status ids", logTag), zap.Error(err)) + return nil, 0, err + } + + incidents, resultLength, err := i.incidentRepository.GetAllIncidents(nil, nil, nonTerminalStatusIds) + if err != nil { + logger.Error(fmt.Sprintf("%s failed to get all incidents", logTag), zap.Error(err)) + return nil, 0, err + } + + return dto.ToDtoArray[incident.IncidentEntity, incident.IncidentDTO](*incidents), resultLength, err } func (i *IncidentServiceV2) GetAllIncidents(teamIds, severityIds, statusIds []uint) ([]incident.IncidentDTO, int, error) { @@ -436,7 +456,7 @@ func (i *IncidentServiceV2) GetAllIncidents(teamIds, severityIds, statusIds []ui if err != nil { return nil, 0, err } - return util.ToDtoArray[incident.IncidentEntity, incident.IncidentDTO](*incidents), resultLength, err + return dto.ToDtoArray[incident.IncidentEntity, incident.IncidentDTO](*incidents), resultLength, err } func (i *IncidentServiceV2) GetIncidentRoleByIncidentIdAndRole( @@ -455,7 +475,7 @@ func (i *IncidentServiceV2) GetIncidentRolesByIncidentIdsAndRole( logger.Info(fmt.Sprintf("%s failed to get incident roles by incident ids and role", logTag)) return nil, err } - return util.ToDtoArray[incident.IncidentRoleEntity, incident.IncidentRoleDTO](incidentRoles), nil + return dto.ToDtoArray[incident.IncidentRoleEntity, incident.IncidentRoleDTO](incidentRoles), nil } func (i *IncidentServiceV2) IsHoustonChannel(channelID string) (bool, error) { @@ -588,7 +608,7 @@ func createIncidentWorkflow( incidentEntity *incident.IncidentEntity, responderTeam *team.TeamEntity, severityEntity *severity.SeverityEntity, - incidentStatusEntity *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, blazeGroupChannelID string, ) error { incidentName := incidentEntity.IncidentName @@ -607,7 +627,7 @@ func createIncidentWorkflow( reportingTeam, responderTeam, severityEntity, - incidentStatusEntity, + incidentStatus, i.incidentRepository, blazeGroupChannelID, i.slackService, @@ -699,9 +719,14 @@ func (i *IncidentServiceV2) HandleKrakatoaWorkflow(incidentEntity *incident.Inci } func (i *IncidentServiceV2) fetchKrakatoaIncidentsForTeamById(teamId uint) (*[]incident.IncidentEntity, error) { - krakatoaIncidents, err := i.incidentRepository.GetOpenIncidentsByCreatorIdForGivenTeam( - viper.GetString("KRAKATOA_BOT_ID"), - teamId, + nonTerminalStatusIds, err := i.incidentStatusService.FetchAllNonTerminalStatusIds() + if err != nil { + logger.Error(fmt.Sprintf("Failed to fetch all non-terminal status ids"), zap.Error(err)) + return nil, err + } + + krakatoaIncidents, err := i.incidentRepository.GetOpenIncidentsByCreatorIdForGivenTeamAndStatuses( + viper.GetString("KRAKATOA_BOT_ID"), teamId, nonTerminalStatusIds, ) if err != nil { @@ -733,13 +758,13 @@ func postIncidentSummary( reportingTeamEntity *team.TeamEntity, teamEntity *team.TeamEntity, severityEntity *severity.SeverityEntity, - incidentStatusEntity *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, incidentRepository incident.IIncidentRepository, blazeGroupChannelID string, slackService slack.ISlackService, ) (*string, error) { blocks := view.IncidentSummarySectionV3( - incidentEntity, reportingTeamEntity, teamEntity, severityEntity, incidentStatusEntity, + incidentEntity, reportingTeamEntity, teamEntity, severityEntity, incidentStatus, ) color := util.GetColorBySeverity(incidentEntity.SeverityId) if blazeGroupChannelID != "" { @@ -937,13 +962,13 @@ func assignResponderToIncident( /* returns incident status entity for a given status ID */ -func getIncidentStatusEntity( +func getIncidentStatus( i *IncidentServiceV2, incidentID, statusID uint, incidentName string, -) (*incident.IncidentStatusEntity, error) { - incidentStatusEntity, err := i.incidentRepository.FindIncidentStatusById(statusID) +) (*incidentStatusModel.IncidentStatusDTO, error) { + incidentStatusEntity, err := i.incidentStatusService.GetIncidentStatusByStatusId(statusID) if err != nil || incidentStatusEntity == nil { logger.Error( fmt.Sprintf( @@ -1112,7 +1137,7 @@ func processUpdateMessage( incidentEntity *incident.IncidentEntity, teamEntity *team.TeamEntity, severityEntity *severity.SeverityEntity, - incidentStatusEntity *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, incidentChannels []incident_channel.IncidentChannelEntity, i *IncidentServiceV2, ) []error { @@ -1126,7 +1151,7 @@ func processUpdateMessage( errs = append(errs, err) } } - blocks := view.IncidentSummarySectionV3(incidentEntity, reportingTeamEntity, teamEntity, severityEntity, incidentStatusEntity) + blocks := view.IncidentSummarySectionV3(incidentEntity, reportingTeamEntity, teamEntity, severityEntity, incidentStatus) color := util.GetColorBySeverity(severityEntity.ID) att := slackUtil.Attachment{Blocks: blocks, Color: color} @@ -1174,7 +1199,7 @@ func (i *IncidentServiceV2) FetchAllUpdateIncidentData(incidentId uint, userEmai *slackUtil.User, *team.TeamEntity, *severity.SeverityEntity, - *incident.IncidentStatusEntity, + *incidentStatusModel.IncidentStatusDTO, []incident_channel.IncidentChannelEntity, error, ) { @@ -1211,7 +1236,7 @@ func (i *IncidentServiceV2) FetchAllUpdateIncidentData(incidentId uint, userEmai } } - teamEntity, severityEntity, incidentStatusEntity, incidentChannels, err := + teamEntity, severityEntity, incidentStatus, incidentChannels, err := i.FetchAllEntitiesForIncident(incidentEntity) if err != nil { logger.Error( @@ -1223,7 +1248,7 @@ func (i *IncidentServiceV2) FetchAllUpdateIncidentData(incidentId uint, userEmai return nil, nil, nil, nil, nil, nil, err } - return incidentEntity, userInfo, teamEntity, severityEntity, incidentStatusEntity, incidentChannels, nil + return incidentEntity, userInfo, teamEntity, severityEntity, incidentStatus, incidentChannels, nil } /* @@ -1233,7 +1258,7 @@ returns all the required entities for team, severity, status and channels during func (i *IncidentServiceV2) FetchAllEntitiesForIncident(incidentEntity *incident.IncidentEntity) ( *team.TeamEntity, *severity.SeverityEntity, - *incident.IncidentStatusEntity, + *incidentStatusModel.IncidentStatusDTO, []incident_channel.IncidentChannelEntity, error, ) { @@ -1246,7 +1271,7 @@ func (i *IncidentServiceV2) FetchAllEntitiesForIncident(incidentEntity *incident return nil, nil, nil, nil, err } - incidentStatusEntity, err := getIncidentStatusEntity( + incidentStatus, err := getIncidentStatus( i, incidentEntity.ID, incidentEntity.Status, incidentEntity.IncidentName, ) if err != nil { @@ -1262,7 +1287,7 @@ func (i *IncidentServiceV2) FetchAllEntitiesForIncident(incidentEntity *incident return nil, nil, nil, nil, err } - return teamEntity, severityEntity, incidentStatusEntity, incidentChannels, nil + return teamEntity, severityEntity, incidentStatus, incidentChannels, nil } /* @@ -1275,7 +1300,7 @@ func (i *IncidentServiceV2) UpdateIncident( ) (*string, error) { logger.Info(fmt.Sprintf("%s received request to update incident: %+v", updateLogTag, request)) - incidentEntity, userInfo, teamEntity, severityEntity, incidentStatusEntity, incidentChannels, err := + incidentEntity, userInfo, teamEntity, severityEntity, incidentStatus, incidentChannels, err := i.FetchAllUpdateIncidentData(request.Id, userEmail) if err != nil { @@ -1287,7 +1312,7 @@ func (i *IncidentServiceV2) UpdateIncident( } if err := i.UpdateSeverityId( - request, userInfo.ID, incidentEntity, teamEntity, incidentStatusEntity, incidentChannels, + request, userInfo.ID, incidentEntity, teamEntity, incidentStatus, incidentChannels, ); err != nil { logger.Error(fmt.Sprintf("%s error in updating severity: %v", updateLogTag, err)) metrics.PublishHoustonFlowFailureMetrics(UPDATE_INCIDENT_SEVERITY, err.Error()) @@ -1303,7 +1328,7 @@ func (i *IncidentServiceV2) UpdateIncident( } if err := i.UpdateTeamId( - request, userInfo.ID, incidentEntity, incidentStatusEntity, incidentChannels, + request, userInfo.ID, incidentEntity, incidentStatus, incidentChannels, ); err != nil { logger.Error(fmt.Sprintf("%s error in updating teamId: %v", updateLogTag, err)) metrics.PublishHoustonFlowFailureMetrics(UPDATE_INCIDENT_TEAM, err.Error()) @@ -1312,7 +1337,7 @@ func (i *IncidentServiceV2) UpdateIncident( if len(request.ProductIDs) > 0 { if err := i.UpdateProductID( - request, userInfo.ID, incidentEntity, severityEntity, incidentStatusEntity, incidentChannels, + request, userInfo.ID, incidentEntity, severityEntity, incidentStatus, incidentChannels, ); err != nil { logger.Error(fmt.Sprintf("%s error in updating teamId: %v", updateLogTag, err)) return nil, err @@ -1337,7 +1362,7 @@ func (i *IncidentServiceV2) UpdateSeverityId( userId string, incidentEntity *incident.IncidentEntity, teamEntity *team.TeamEntity, - incidentStatusEntity *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, incidentChannels []incident_channel.IncidentChannelEntity, ) error { // Add it here for the change incident. @@ -1406,7 +1431,7 @@ func (i *IncidentServiceV2) UpdateSeverityId( incidentEntity.IncidentName = utils.ConstructIncidentChannelName( incidentEntity.ID, incidentEntity.SeverityId, - incidentStatusEntity.Name, + incidentStatus.Name, incidentEntity.Title, ) @@ -1417,7 +1442,7 @@ func (i *IncidentServiceV2) UpdateSeverityId( } err = i.UpdateSeverityWorkflow( - userId, incidentEntity, teamEntity, severityEntity, incidentStatusEntity, incidentChannels, + userId, incidentEntity, teamEntity, severityEntity, incidentStatus, incidentChannels, ) if err != nil { logger.Error(fmt.Sprintf("%s error in update severity workflow", updateLogTag), zap.Error(err)) @@ -1468,7 +1493,7 @@ func (i *IncidentServiceV2) UpdateSeverityWorkflow( incidentEntity *incident.IncidentEntity, teamEntity *team.TeamEntity, severityEntity *severity.SeverityEntity, - incidentStatusEntity *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, incidentChannels []incident_channel.IncidentChannelEntity, ) error { var slackErrors []error @@ -1533,7 +1558,7 @@ func (i *IncidentServiceV2) UpdateSeverityWorkflow( }) go util.ExecuteConcurrentAction(&waitGroup, func() { - processUpdateMessage(incidentEntity, teamEntity, severityEntity, incidentStatusEntity, incidentChannels, i) + processUpdateMessage(incidentEntity, teamEntity, severityEntity, incidentStatus, incidentChannels, i) }) go util.ExecuteConcurrentAction(&waitGroup, func() { @@ -1550,7 +1575,7 @@ func (i *IncidentServiceV2) UpdateSeverityWorkflow( ReportingTeamName: incidentEntity.ReportingTeam.Name, ResponderTeamName: teamEntity.Name, SeverityName: severityEntity.Name, - StatusName: incidentStatusEntity.Name, + StatusName: incidentStatus.Name, Title: incidentEntity.Title, } err := i.slackService.SetTopicOfConversationByChannelId( @@ -1596,8 +1621,8 @@ func (i *IncidentServiceV2) UpdateStatus( return fmt.Errorf("Invalid status ID: %s", request.Status) } if incidentEntity.Status != uint(statusID) { - currentStatus, _ := i.incidentRepository.FindIncidentStatusById(incidentEntity.Status) - statusToBeUpdated, _ := i.incidentRepository.FindIncidentStatusById(uint(statusID)) + currentStatus, _ := i.incidentStatusService.GetIncidentStatusByStatusId(incidentEntity.Status) + statusToBeUpdated, _ := i.incidentStatusService.GetIncidentStatusByStatusId(uint(statusID)) if statusToBeUpdated == nil { logger.Error(fmt.Sprintf("%s no status found for status id %s", updateLogTag, request.Status), @@ -1681,7 +1706,7 @@ func (i *IncidentServiceV2) UpdateStatusWorkflow( incidentEntity *incident.IncidentEntity, teamEntity *team.TeamEntity, severityEntity *severity.SeverityEntity, - incidentStatus *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, incidentChannels []incident_channel.IncidentChannelEntity, ) error { var waitGroup sync.WaitGroup @@ -1758,7 +1783,7 @@ func (i *IncidentServiceV2) UpdateTeamId( request request.UpdateIncidentRequest, userId string, incidentEntity *incident.IncidentEntity, - incidentStatusEntity *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, incidentChannels []incident_channel.IncidentChannelEntity, ) error { if !util.IsBlank(request.TeamId) { @@ -1790,7 +1815,7 @@ func (i *IncidentServiceV2) UpdateTeamId( } err = i.UpdateTeamIdWorkflow( - userId, incidentEntity.ID, teamEntity, severityEntity, incidentStatusEntity, incidentChannels, + userId, incidentEntity.ID, teamEntity, severityEntity, incidentStatus, incidentChannels, ) if err != nil { logger.Error(fmt.Sprintf("%s error in update team id workflow", updateLogTag), zap.Error(err)) @@ -1832,12 +1857,12 @@ func (i *IncidentServiceV2) postTeamUpdateFlows( userId string, incidentEntity *incident.IncidentEntity, severityEntity *severity.SeverityEntity, - incidentStatusEntity *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, incidentChannels []incident_channel.IncidentChannelEntity, teamEntity *team.TeamEntity, ) error { err := i.UpdateTeamIdWorkflow( - userId, incidentEntity.ID, teamEntity, severityEntity, incidentStatusEntity, incidentChannels, + userId, incidentEntity.ID, teamEntity, severityEntity, incidentStatus, incidentChannels, ) if err != nil { logger.Error(fmt.Sprintf("%s error in update team id workflow", updateLogTag), zap.Error(err)) @@ -1852,12 +1877,12 @@ func (i *IncidentServiceV2) postProductUpdateFlows( userId string, incidentEntity *incident.IncidentEntity, severityEntity *severity.SeverityEntity, - incidentStatusEntity *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, incidentChannels []incident_channel.IncidentChannelEntity, teamEntity *team.TeamEntity, ) error { err := i.UpdateProductIdWorkflow( - userId, incidentEntity.ID, teamEntity, severityEntity, incidentStatusEntity, incidentChannels, + userId, incidentEntity.ID, teamEntity, severityEntity, incidentStatus, incidentChannels, ) if err != nil { logger.Error(fmt.Sprintf("%s error in update team id workflow", updateLogTag), zap.Error(err)) @@ -1871,7 +1896,7 @@ func (i *IncidentServiceV2) UpdateProductID( userId string, incidentEntity *incident.IncidentEntity, severityEntity *severity.SeverityEntity, - incidentStatusEntity *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, incidentChannels []incident_channel.IncidentChannelEntity, ) error { var existingProductsIds []uint @@ -1909,13 +1934,13 @@ func (i *IncidentServiceV2) UpdateProductID( } if isTeamUpdateRequired { - err = i.postTeamUpdateFlows(userId, incidentEntity, severityEntity, incidentStatusEntity, incidentChannels, teamEntity) + err = i.postTeamUpdateFlows(userId, incidentEntity, severityEntity, incidentStatus, incidentChannels, teamEntity) if err != nil { logger.Error(fmt.Sprintf("%s error in running post team update workflow", updateLogTag), zap.Error(err)) return err } } else { - err := i.postProductUpdateFlows(userId, incidentEntity, severityEntity, incidentStatusEntity, incidentChannels, teamEntity) + err := i.postProductUpdateFlows(userId, incidentEntity, severityEntity, incidentStatus, incidentChannels, teamEntity) if err != nil { logger.Error(fmt.Sprintf("%s error in running post product update workflow", updateLogTag), zap.Error(err)) return err @@ -1936,7 +1961,7 @@ func (i *IncidentServiceV2) UpdateTeamIdWorkflow( incidentID uint, teamEntity *team.TeamEntity, severityEntity *severity.SeverityEntity, - incidentStatus *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, incidentChannels []incident_channel.IncidentChannelEntity, ) error { var slackErrors []error @@ -2048,7 +2073,7 @@ func (i *IncidentServiceV2) UpdateProductIdWorkflow( incidentID uint, teamEntity *team.TeamEntity, severityEntity *severity.SeverityEntity, - incidentStatus *incident.IncidentStatusEntity, + incidentStatus *incidentStatusModel.IncidentStatusDTO, incidentChannels []incident_channel.IncidentChannelEntity, ) error { var slackErrors []error diff --git a/service/incident/impl/incident_update_status.go b/service/incident/impl/incident_update_status.go index b8a5c2f..5ed34ae 100644 --- a/service/incident/impl/incident_update_status.go +++ b/service/incident/impl/incident_update_status.go @@ -654,7 +654,7 @@ func (i *IncidentServiceV2) updateIncidentResolveStatus(incidentEntity *incident return customErrors.NewInvalidInputError(errMessage) } - incidentStatusEntity, err := i.incidentRepository.FindIncidentStatusByName(incident.Resolved) + incidentStatus, err := i.incidentStatusService.GetIncidentStatusByStatusName(incident.Resolved) if err != nil { logger.Error( fmt.Sprintf("%s Error while getting incident status by name %s", resolveLogTag, incident.Resolved), @@ -680,7 +680,7 @@ func (i *IncidentServiceV2) updateIncidentResolveStatus(incidentEntity *incident } endTime := time.Now() - incidentEntity.Status = incidentStatusEntity.ID + incidentEntity.Status = incidentStatus.ID incidentEntity.EndTime = &endTime incidentEntity.IncidentName = utils.ConstructIncidentChannelName( incidentEntity.ID, diff --git a/service/incident/impl/incident_update_status_test.go b/service/incident/impl/incident_update_status_test.go index ce7492c..1eea89c 100644 --- a/service/incident/impl/incident_update_status_test.go +++ b/service/incident/impl/incident_update_status_test.go @@ -5,6 +5,7 @@ import ( "github.com/lib/pq" "houston/model/customErrors" "houston/model/incident" + "houston/model/incidentStatus" "houston/model/tag" service "houston/service/request" ) @@ -416,7 +417,7 @@ func (suite *IncidentServiceSuite) TestResolveIncident_IncidentStatusFetchingErr suite.incidentJiraService.GetJiraLinksValuesByIncidentIDMock.Return([]string{suite.mockValidJiraLink}, nil) suite.slackService.PostMessageWithAttachmentsMock.Return("", nil) suite.slackService.PostMessageByChannelIDMock.Return("", nil) - suite.incidentRepository.FindIncidentStatusByNameMock.Return(nil, errors.New("DB Error")) + suite.incidentStatusService.GetIncidentStatusByStatusNameMock.Return(nil, errors.New("DB Error")) err := suite.incidentService.ResolveIncident(sampleRequest, "") suite.Error(err, "service must throw error") suite.IsTypef(err, &customErrors.DataAccessError{}, "error must be of data access error type") @@ -427,7 +428,7 @@ func (suite *IncidentServiceSuite) TestResolveIncident_MandatoryActiveTagFetchin mockUser := GetMockUser() mockTagValue := GetMockTagValue() mockTag := GetMockTag() - mockStatus := GetMockIncidentStatus() + mockStatus := GetMockIncidentStatusDTO() sampleRequest := GetSampleResolveRequest() sampleRequest.JiraLinks = []string{suite.mockValidJiraLink} suite.incidentRepository.FindIncidentByIdMock.Return(mockIncident, nil) @@ -445,7 +446,7 @@ func (suite *IncidentServiceSuite) TestResolveIncident_MandatoryActiveTagFetchin suite.incidentJiraService.GetJiraLinksValuesByIncidentIDMock.Return([]string{suite.mockValidJiraLink}, nil) suite.slackService.PostMessageWithAttachmentsMock.Return("", nil) suite.slackService.PostMessageByChannelIDMock.Return("", nil) - suite.incidentRepository.FindIncidentStatusByNameMock.Return(mockStatus, nil) + suite.incidentStatusService.GetIncidentStatusByStatusNameMock.Return(mockStatus, nil) suite.tagService.GetMandatoryActiveTagsMock.Return(nil, errors.New("DB Error")) err := suite.incidentService.ResolveIncident(sampleRequest, "") suite.Error(err, "service must throw error") @@ -457,7 +458,7 @@ func (suite *IncidentServiceSuite) TestResolveIncident_IncidentTagByTagIDError() mockUser := GetMockUser() mockTagValue := GetMockTagValue() mockTag := GetMockTag() - mockStatus := GetMockIncidentStatus() + mockStatus := GetMockIncidentStatusDTO() sampleRequest := GetSampleResolveRequest() sampleRequest.JiraLinks = []string{suite.mockValidJiraLink} suite.incidentRepository.FindIncidentByIdMock.Return(mockIncident, nil) @@ -475,7 +476,7 @@ func (suite *IncidentServiceSuite) TestResolveIncident_IncidentTagByTagIDError() suite.incidentJiraService.GetJiraLinksValuesByIncidentIDMock.Return([]string{suite.mockValidJiraLink}, nil) suite.slackService.PostMessageWithAttachmentsMock.Return("", nil) suite.slackService.PostMessageByChannelIDMock.Return("", nil) - suite.incidentRepository.FindIncidentStatusByNameMock.Return(mockStatus, nil) + suite.incidentStatusService.GetIncidentStatusByStatusNameMock.Return(mockStatus, nil) suite.tagService.GetMandatoryActiveTagsMock.Return(GetMockActiveMandatoryTags(), nil) suite.incidentRepository.GetIncidentTagsByTagIdsMock.Return(nil, errors.New("DB Error")) err := suite.incidentService.ResolveIncident(sampleRequest, "") @@ -488,7 +489,7 @@ func (suite *IncidentServiceSuite) TestResolveIncident_TagNotSetCase() { mockUser := GetMockUser() mockTagValue := GetMockTagValue() mockTag := GetMockTag() - mockStatus := GetMockIncidentStatus() + mockStatus := GetMockIncidentStatusDTO() sampleRequest := GetSampleResolveRequest() sampleRequest.JiraLinks = []string{suite.mockValidJiraLink} suite.incidentRepository.FindIncidentByIdMock.Return(mockIncident, nil) @@ -506,7 +507,7 @@ func (suite *IncidentServiceSuite) TestResolveIncident_TagNotSetCase() { suite.incidentJiraService.GetJiraLinksValuesByIncidentIDMock.Return([]string{suite.mockValidJiraLink}, nil) suite.slackService.PostMessageWithAttachmentsMock.Return("", nil) suite.slackService.PostMessageByChannelIDMock.Return("", nil) - suite.incidentRepository.FindIncidentStatusByNameMock.Return(mockStatus, nil) + suite.incidentStatusService.GetIncidentStatusByStatusNameMock.Return(mockStatus, nil) suite.tagService.GetMandatoryActiveTagsMock.Return(GetMockActiveMandatoryTags(), nil) suite.incidentRepository.GetIncidentTagsByTagIdsMock.Return(GetMockIncidentTag(1, 1), nil) err := suite.incidentService.ResolveIncident(sampleRequest, "") @@ -521,7 +522,7 @@ func (suite *IncidentServiceSuite) TestResolveIncident_PostResolveFlowErrorCase( mockTag := GetMockTag() mockIncidentTag := GetMockIncidentTag(1, 1) mockIncidentTag.TagValueIds = pq.Int32Array{1, 2, 3} - mockStatus := GetMockIncidentStatus() + mockStatus := GetMockIncidentStatusDTO() sampleRequest := GetSampleResolveRequest() sampleRequest.JiraLinks = []string{suite.mockValidJiraLink} suite.incidentRepository.FindIncidentByIdMock.Return(mockIncident, nil) @@ -539,14 +540,14 @@ func (suite *IncidentServiceSuite) TestResolveIncident_PostResolveFlowErrorCase( suite.incidentJiraService.GetJiraLinksValuesByIncidentIDMock.Return([]string{suite.mockValidJiraLink}, nil) suite.slackService.PostMessageWithAttachmentsMock.Return("", nil) suite.slackService.PostMessageByChannelIDMock.Return("", nil) - suite.incidentRepository.FindIncidentStatusByNameMock.Return(mockStatus, nil) + suite.incidentStatusService.GetIncidentStatusByStatusNameMock.Return(mockStatus, nil) suite.tagService.GetMandatoryActiveTagsMock.Return(GetMockActiveMandatoryTags(), nil) suite.incidentRepository.GetIncidentTagsByTagIdsMock.Return(mockIncidentTag, nil) suite.slackService.PostMessageOptionMock.Return("", errors.New("Slack Error")) suite.slackService.RenameSlackChannelMock.Return(nil) suite.teamRepository.FindTeamByIdMock.Return(GetMockTeamWithId(1), nil) suite.severityRepository.FindSeverityByIdMock.Return(GetMockSeverityWithId(3), nil) - suite.incidentRepository.FindIncidentStatusByIdMock.Return(GetMockIncidentStatus(), nil) + suite.incidentStatusService.GetIncidentStatusByStatusIdMock.Return(GetMockIncidentStatusDTO(), nil) suite.incidentChannelService.GetIncidentChannelsMock.Return(GetMockChannels(), nil) suite.slackService.UpdateMessageWithAttachmentsMock.Return(errors.New("Slack Error")) suite.calendarService.DeleteEventMock.Return(nil) @@ -565,7 +566,7 @@ func (suite *IncidentServiceSuite) TestResolveIncident_HappyFlow() { mockTag := GetMockTag() mockIncidentTag := GetMockIncidentTag(1, 1) mockIncidentTag.TagValueIds = pq.Int32Array{1, 2, 3} - mockStatus := GetMockIncidentStatus() + mockStatus := GetMockIncidentStatusDTO() sampleRequest := GetSampleResolveRequest() sampleRequest.JiraLinks = []string{suite.mockValidJiraLink} suite.incidentRepository.FindIncidentByIdMock.Return(mockIncident, nil) @@ -583,13 +584,13 @@ func (suite *IncidentServiceSuite) TestResolveIncident_HappyFlow() { suite.incidentJiraService.GetJiraLinksValuesByIncidentIDMock.Return([]string{suite.mockValidJiraLink}, nil) suite.slackService.PostMessageWithAttachmentsMock.Return("", nil) suite.slackService.PostMessageByChannelIDMock.Return("", nil) - suite.incidentRepository.FindIncidentStatusByNameMock.Return(mockStatus, nil) + suite.incidentStatusService.GetIncidentStatusByStatusNameMock.Return(mockStatus, nil) suite.tagService.GetMandatoryActiveTagsMock.Return(GetMockActiveMandatoryTags(), nil) suite.incidentRepository.GetIncidentTagsByTagIdsMock.Return(mockIncidentTag, nil) suite.slackService.PostMessageOptionMock.Return("", nil) suite.teamRepository.FindTeamByIdMock.Return(GetMockTeamWithId(1), nil) suite.severityRepository.FindSeverityByIdMock.Return(GetMockSeverityWithId(3), nil) - suite.incidentRepository.FindIncidentStatusByIdMock.Return(GetMockIncidentStatus(), nil) + suite.incidentStatusService.GetIncidentStatusByStatusIdMock.Return(GetMockIncidentStatusDTO(), nil) suite.incidentChannelService.GetIncidentChannelsMock.Return(GetMockChannels(), nil) suite.slackService.UpdateMessageWithAttachmentsMock.Return(nil) suite.calendarService.DeleteEventMock.Return(nil) @@ -666,8 +667,14 @@ func GetMockIncidentTags() *[]incident.IncidentTagEntity { } } -func GetMockIncidentStatus() *incident.IncidentStatusEntity { - return &incident.IncidentStatusEntity{ +func GetMockIncidentStatus() *incidentStatus.IncidentStatusEntity { + return &incidentStatus.IncidentStatusEntity{ + Name: "resolved", + } +} + +func GetMockIncidentStatusDTO() *incidentStatus.IncidentStatusDTO { + return &incidentStatus.IncidentStatusDTO{ Name: "resolved", } } diff --git a/service/incident/incident_slack_utils.go b/service/incident/incident_slack_utils.go index 3789d26..c323d1e 100644 --- a/service/incident/incident_slack_utils.go +++ b/service/incident/incident_slack_utils.go @@ -6,7 +6,7 @@ import ( "houston/common/util" "houston/logger" "houston/model/incident" - "houston/model/severity" + "houston/repository/severity" "time" ) diff --git a/service/incidentStatus/incident_status_service.go b/service/incidentStatus/incident_status_service.go new file mode 100644 index 0000000..35f5bac --- /dev/null +++ b/service/incidentStatus/incident_status_service.go @@ -0,0 +1,19 @@ +package incidentStatus + +import ( + incidentStatusModel "houston/model/incidentStatus" + "houston/repository/incidentStatus" +) + +type IncidentStatusService interface { + GetNonTerminalStatusesNotMatchingIncidentStatus(channelID string) ([]incidentStatusModel.IncidentStatusDTO, error) + GetIncidentStatusByStatusName(statusName string) (*incidentStatusModel.IncidentStatusDTO, error) + GetIncidentStatusByStatusId(statusId uint) (*incidentStatusModel.IncidentStatusDTO, error) + GetAllIncidentStatuses() (*[]incidentStatusModel.IncidentStatusDTO, error) + FetchAllNonTerminalStatuses() (*[]incidentStatusModel.IncidentStatusDTO, error) + FetchAllNonTerminalStatusIds() ([]uint, error) +} + +func NewIncidentStatusService(repo incidentStatus.IncidentStatusRepository) IncidentStatusService { + return newIncidentStatusServiceImpl(repo) +} diff --git a/service/incidentStatus/incident_status_service_impl.go b/service/incidentStatus/incident_status_service_impl.go new file mode 100644 index 0000000..9a63211 --- /dev/null +++ b/service/incidentStatus/incident_status_service_impl.go @@ -0,0 +1,112 @@ +package incidentStatus + +import ( + "fmt" + "houston/common/util/dto" + "houston/logger" + incidentStatusModel "houston/model/incidentStatus" + "houston/repository/incidentStatus" +) + +type incidentStatusServiceImpl struct { + repo incidentStatus.IncidentStatusRepository +} + +const logTag = "[incident-status-service]" + +func newIncidentStatusServiceImpl(repo incidentStatus.IncidentStatusRepository) *incidentStatusServiceImpl { + return &incidentStatusServiceImpl{repo} +} + +func (service *incidentStatusServiceImpl) GetNonTerminalStatusesNotMatchingIncidentStatus(channelID string) ([]incidentStatusModel.IncidentStatusDTO, error) { + logger.Info(fmt.Sprintf("%s getting non-terminal statuses not matching incident status for channel %s", logTag, channelID)) + + statuses, err := service.repo.GetNonTerminalStatusesNotMatchingIncidentStatus(channelID) + if err != nil { + logger.Error(fmt.Sprintf("%s error getting non-terminal statuses not matching incident status for channel %s: %v", logTag, channelID, err.Error())) + return nil, err + } + + return dto.ToDtoArray[incidentStatusModel.IncidentStatusEntity, incidentStatusModel.IncidentStatusDTO](statuses), nil +} + +func (service *incidentStatusServiceImpl) GetIncidentStatusByStatusName(statusName string) (*incidentStatusModel.IncidentStatusDTO, error) { + logger.Info(fmt.Sprintf("%s getting incident status by name %s", logTag, statusName)) + + statusEntity, err := service.repo.GetIncidentStatusByStatusName(statusName) + if err != nil { + logger.Error(fmt.Sprintf("%s error getting incident status by name %s: %v", logTag, statusName, err.Error())) + return nil, err + } + + if statusEntity == nil { + errMessage := fmt.Sprintf("%s incident status with name %s not found", logTag, statusName) + logger.Error(fmt.Sprintf("%s %s", logTag, errMessage)) + return nil, fmt.Errorf(errMessage) + } + + statusDTO := statusEntity.ToDTO() + return &statusDTO, nil +} + +func (service *incidentStatusServiceImpl) GetIncidentStatusByStatusId(statusId uint) (*incidentStatusModel.IncidentStatusDTO, error) { + logger.Info(fmt.Sprintf("%s getting incident status by id %d", logTag, statusId)) + + statusEntity, err := service.repo.GetIncidentStatusByStatusId(statusId) + if err != nil { + logger.Error(fmt.Sprintf("%s error getting incident status by id %d: %v", logTag, statusId, err.Error())) + return nil, err + } + + if statusEntity == nil { + errMessage := fmt.Sprintf("%s incident status with id %d not found", logTag, statusId) + logger.Error(fmt.Sprintf("%s %s", logTag, errMessage)) + return nil, fmt.Errorf(errMessage) + } + + statusDTO := statusEntity.ToDTO() + return &statusDTO, nil +} + +func (service *incidentStatusServiceImpl) GetAllIncidentStatuses() (*[]incidentStatusModel.IncidentStatusDTO, error) { + logger.Info(fmt.Sprintf("%s getting all incident statuses", logTag)) + + statusEntities, err := service.repo.GetAllIncidentStatuses() + if err != nil { + logger.Error(fmt.Sprintf("%s error getting all incident statuses: %v", logTag, err.Error())) + return nil, err + } + + statusDTOs := dto.ToDtoArray[incidentStatusModel.IncidentStatusEntity, incidentStatusModel.IncidentStatusDTO](*statusEntities) + return &statusDTOs, nil +} + +func (service *incidentStatusServiceImpl) FetchAllNonTerminalStatuses() (*[]incidentStatusModel.IncidentStatusDTO, error) { + logger.Info(fmt.Sprintf("%s fetching all non-terminal statuses", logTag)) + + statusEntities, err := service.repo.FetchAllNonTerminalStatuses() + if err != nil { + logger.Error(fmt.Sprintf("%s error fetching all non-terminal statuses: %v", logTag, err.Error())) + return nil, err + } + + statusDTOs := dto.ToDtoArray[incidentStatusModel.IncidentStatusEntity, incidentStatusModel.IncidentStatusDTO](*statusEntities) + return &statusDTOs, nil +} + +func (service *incidentStatusServiceImpl) FetchAllNonTerminalStatusIds() ([]uint, error) { + logger.Info(fmt.Sprintf("%s fetching all non-terminal status ids", logTag)) + + statusEntities, err := service.FetchAllNonTerminalStatuses() + if err != nil { + logger.Error(fmt.Sprintf("%s error fetching all non-terminal status ids: %v", logTag, err.Error())) + return nil, err + } + + statusIds := make([]uint, len(*statusEntities)) + for i, status := range *statusEntities { + statusIds[i] = status.ID + } + + return statusIds, nil +} diff --git a/service/incidentStatus/incident_status_service_test.go b/service/incidentStatus/incident_status_service_test.go new file mode 100644 index 0000000..24d9661 --- /dev/null +++ b/service/incidentStatus/incident_status_service_test.go @@ -0,0 +1,114 @@ +package incidentStatus + +import ( + "errors" + "github.com/stretchr/testify/suite" + "houston/logger" + mocks "houston/mocks/incidentStatus" + "houston/model/incidentStatus" + "testing" +) + +type IncidentStatusServiceSuite struct { + suite.Suite + incidentStatusService IncidentStatusService + incidentStatusRepository *mocks.IncidentStatusRepositoryMock +} + +func (suite *IncidentStatusServiceSuite) Test_GetNonTerminalStatusesNotMatchingIncidentStatus_RepoFailureCase() { + suite.incidentStatusRepository.GetNonTerminalStatusesNotMatchingIncidentStatusMock.Return(nil, errors.New("error")) + + statuses, err := suite.incidentStatusService.GetNonTerminalStatusesNotMatchingIncidentStatus("channelID") + suite.Nil(statuses, "statuses should be nil") + suite.EqualError(err, "error", "error should be error") +} + +func (suite *IncidentStatusServiceSuite) Test_GetNonTerminalStatusesNotMatchingIncidentStatus_SuccessCase() { + mockIncidentStatusEntities := []incidentStatus.IncidentStatusEntity{{Name: "a"}, {Name: "b"}} + suite.incidentStatusRepository.GetNonTerminalStatusesNotMatchingIncidentStatusMock.Return(mockIncidentStatusEntities, nil) + + statuses, err := suite.incidentStatusService.GetNonTerminalStatusesNotMatchingIncidentStatus("channelID") + suite.Nil(err, "error should be nil") + suite.NotNil(statuses, "statuses should not be nil") + suite.Len(statuses, len(mockIncidentStatusEntities), "length of statuses should be equal") +} + +func (suite *IncidentStatusServiceSuite) Test_GetIncidentStatusByStatusName_RepoFailureCase() { + suite.incidentStatusRepository.GetIncidentStatusByStatusNameMock.Return(nil, errors.New("error")) + + status, err := suite.incidentStatusService.GetIncidentStatusByStatusName("statusName") + suite.Nil(status, "status should be nil") + suite.NotNil(err, "error should not be nil") +} + +func (suite *IncidentStatusServiceSuite) Test_GetIncidentStatusByStatusName_NilDataCase() { + suite.incidentStatusRepository.GetIncidentStatusByStatusNameMock.Return(nil, nil) + + status, err := suite.incidentStatusService.GetIncidentStatusByStatusName("statusName") + suite.Nil(status, "status should be nil") + suite.NotNil(err, "error should not be nil") +} + +func (suite *IncidentStatusServiceSuite) Test_GetIncidentStatusByStatusName_SuccessCase() { + mockIncidentStatusEntity := incidentStatus.IncidentStatusEntity{Name: "statusName"} + suite.incidentStatusRepository.GetIncidentStatusByStatusNameMock.Return(&mockIncidentStatusEntity, nil) + + status, err := suite.incidentStatusService.GetIncidentStatusByStatusName("statusName") + suite.Nil(err, "error should be nil") + suite.NotNil(status, "status should not be nil") + suite.Equal(status.Name, mockIncidentStatusEntity.Name, "status name should be equal") +} + +func (suite *IncidentStatusServiceSuite) Test_GetIncidentStatusByStatusId_RepoFailureCase() { + suite.incidentStatusRepository.GetIncidentStatusByStatusIdMock.Return(nil, errors.New("error")) + + status, err := suite.incidentStatusService.GetIncidentStatusByStatusId(1) + suite.Nil(status, "status should be nil") + suite.NotNil(err, "error should not be nil") +} + +func (suite *IncidentStatusServiceSuite) Test_GetIncidentStatusByStatusId_NilDataCase() { + suite.incidentStatusRepository.GetIncidentStatusByStatusIdMock.Return(nil, nil) + + status, err := suite.incidentStatusService.GetIncidentStatusByStatusId(1) + suite.Nil(status, "status should be nil") + suite.NotNil(err, "error should not be nil") +} + +func (suite *IncidentStatusServiceSuite) Test_GetIncidentStatusByStatusId_SuccessCase() { + mockIncidentStatusEntity := incidentStatus.IncidentStatusEntity{Name: "statusName"} + suite.incidentStatusRepository.GetIncidentStatusByStatusIdMock.Return(&mockIncidentStatusEntity, nil) + + status, err := suite.incidentStatusService.GetIncidentStatusByStatusId(1) + suite.Nil(err, "error should be nil") + suite.NotNil(status, "status should not be nil") + suite.Equal(status.Name, mockIncidentStatusEntity.Name, "status name should be equal") +} + +func (suite *IncidentStatusServiceSuite) Test_GetAllIncidentStatuses_RepoFailureCase() { + suite.incidentStatusRepository.GetAllIncidentStatusesMock.Return(nil, errors.New("error")) + + statuses, err := suite.incidentStatusService.GetAllIncidentStatuses() + suite.Nil(statuses, "statuses should be nil") + suite.EqualError(err, "error", "error should be error") +} + +func (suite *IncidentStatusServiceSuite) Test_GetAllIncidentStatuses_SuccessCase() { + mockIncidentStatusEntities := []incidentStatus.IncidentStatusEntity{{Name: "a"}, {Name: "b"}} + suite.incidentStatusRepository.GetAllIncidentStatusesMock.Return(&mockIncidentStatusEntities, nil) + + statuses, err := suite.incidentStatusService.GetAllIncidentStatuses() + suite.Nil(err, "error should be nil") + suite.NotNil(statuses, "statuses should not be nil") + suite.Len(*statuses, len(mockIncidentStatusEntities), "length of statuses should be equal") +} + +func (suite *IncidentStatusServiceSuite) SetupSuite() { + logger.InitLogger() + suite.incidentStatusRepository = mocks.NewIncidentStatusRepositoryMock(suite.T()) + suite.incidentStatusService = newIncidentStatusServiceImpl(suite.incidentStatusRepository) +} + +func TestIncidentStatusService(t *testing.T) { + suite.Run(t, new(IncidentStatusServiceSuite)) +} diff --git a/service/incident_service.go b/service/incident_service.go index ed1e3c9..2fd9bc9 100644 --- a/service/incident_service.go +++ b/service/incident_service.go @@ -8,15 +8,18 @@ import ( "houston/model/incident" "houston/model/log" "houston/model/product" - "houston/model/severity" "houston/model/team" "houston/model/user" "houston/pkg/slackbot" + "houston/repository/incidentStatus" + "houston/repository/severity" "houston/service/incident/impl" + incidentStatusService "houston/service/incidentStatus" rcaService "houston/service/rca/impl" request "houston/service/request" service "houston/service/response" common "houston/service/response/common" + severityServiceImpl "houston/service/severity/impl" slack2 "houston/service/slack" "houston/service/teamService" utils "houston/service/utils" @@ -36,28 +39,35 @@ import ( ) type incidentService struct { - gin *gin.Engine - db *gorm.DB - socketModeClient *socketmode.Client - teamRepository *team.Repository - teamService teamService.ITeamServiceV2 - severityRepository *severity.Repository - incidentRepository *incident.Repository - userRepository *user.Repository - messageUpdateAction *action.IncidentChannelMessageUpdateAction - slackbotClient *slackbot.Client - slackService slack2.ISlackService - incidentServiceV2 *impl.IncidentServiceV2 - rcaService *rcaService.RcaService + gin *gin.Engine + db *gorm.DB + socketModeClient *socketmode.Client + teamRepository *team.Repository + teamService teamService.ITeamServiceV2 + severityRepository *severity.Repository + incidentRepository *incident.Repository + userRepository *user.Repository + messageUpdateAction *action.IncidentChannelMessageUpdateAction + slackbotClient *slackbot.Client + slackService slack2.ISlackService + incidentServiceV2 *impl.IncidentServiceV2 + rcaService *rcaService.RcaService + incidentStatusService incidentStatusService.IncidentStatusService } func NewIncidentService( gin *gin.Engine, db *gorm.DB, socketModeClient *socketmode.Client, teamService teamService.ITeamServiceV2, ) *incidentService { severityRepository := severity.NewSeverityRepository(db) + incidentStatusRepository := incidentStatus.NewIncidentStatusRepository(db) logRepository := log.NewLogRepository(db) teamRepository := team.NewTeamRepository(db, logRepository) - incidentRepository := incident.NewIncidentRepository(db, severityRepository, logRepository, teamRepository, socketModeClient) + incidentStatusService := incidentStatusService.NewIncidentStatusService(incidentStatusRepository) + incidentRepository := incident.NewIncidentRepository( + db, severityServiceImpl.NewSeverityService(severityRepository), + incidentStatusService, logRepository, + teamRepository, socketModeClient, + ) userRepository := user.NewUserRepository(db) messageUpdateAction := action.NewIncidentChannelMessageUpdateAction( socketModeClient, incidentRepository, teamRepository, severityRepository) @@ -65,19 +75,20 @@ func NewIncidentService( incidentServiceV2 := impl.NewIncidentServiceV2(db) rcaService := appcontext.GetRCAService() return &incidentService{ - gin: gin, - db: db, - socketModeClient: socketModeClient, - teamRepository: teamRepository, - teamService: teamService, - severityRepository: severityRepository, - incidentRepository: incidentRepository, - userRepository: userRepository, - messageUpdateAction: messageUpdateAction, - slackbotClient: slackBot, - slackService: appcontext.GetSlackService(), - incidentServiceV2: incidentServiceV2, - rcaService: rcaService, + gin: gin, + db: db, + socketModeClient: socketModeClient, + teamRepository: teamRepository, + teamService: teamService, + severityRepository: severityRepository, + incidentRepository: incidentRepository, + userRepository: userRepository, + messageUpdateAction: messageUpdateAction, + slackbotClient: slackBot, + slackService: appcontext.GetSlackService(), + incidentServiceV2: incidentServiceV2, + rcaService: rcaService, + incidentStatusService: incidentStatusService, } } @@ -176,7 +187,7 @@ func (i *incidentService) GetIncidentResponseFromIncidentEntity( return nil, err } - incidentStatuses, err := incidentRepository.FetchAllIncidentStatuses() + incidentStatuses, err := i.incidentStatusService.GetAllIncidentStatuses() if err != nil { logger.Error("error in fetching incidentStatuses", zap.Error(err)) return nil, err @@ -308,11 +319,11 @@ func (i *incidentService) GetIncidentHeader(c *gin.Context) { incidentHeaderResponse.Severities = append(incidentHeaderResponse.Severities, severityResponse) } - incidentStatusEntities, err := i.incidentRepository.FetchAllIncidentStatuses() + incidentStatuses, err := i.incidentStatusService.GetAllIncidentStatuses() if err != nil { logger.Error("error in fetching incident statuses", zap.Error(err)) } - for _, incidentStatus := range *incidentStatusEntities { + for _, incidentStatus := range *incidentStatuses { incidentStatusResponse := service.IncidentHeaderOption{ Value: incidentStatus.ID, Label: incidentStatus.Name, @@ -351,7 +362,7 @@ func (i *incidentService) GetTeamIncidents(c *gin.Context) { var Statuses string InputStatuses := c.Query("statuses") if InputStatuses == "" { - incidentStatuses, err := i.incidentRepository.FetchAllIncidentStatuses() + incidentStatuses, err := i.incidentStatusService.GetAllIncidentStatuses() if err != nil { logger.Error("error in fetching incident statuses", zap.Error(err)) c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil)) diff --git a/service/severity/impl/severity_service.go b/service/severity/impl/severity_service.go index ba2cc83..c9f3c90 100644 --- a/service/severity/impl/severity_service.go +++ b/service/severity/impl/severity_service.go @@ -1,18 +1,21 @@ package impl import ( + "fmt" "go.uber.org/zap" + "houston/common/util/dto" "houston/logger" "houston/model/severity" + severityRepo "houston/repository/severity" "houston/service/dtoConverter" "sort" ) type SeverityService struct { - severityRepository severity.ISeverityRepository + severityRepository severityRepo.ISeverityRepository } -func NewSeverityService(severityRepository severity.ISeverityRepository) *SeverityService { +func NewSeverityService(severityRepository severityRepo.ISeverityRepository) *SeverityService { return &SeverityService{ severityRepository: severityRepository, } @@ -44,11 +47,27 @@ func (service *SeverityService) FindSeverityById(severityId uint) (*severity.Sev return nil, err } + if severityEntity == nil { + errMessage := fmt.Sprintf("severity with id %d not found", severityId) + logger.Error(errMessage) + return nil, fmt.Errorf(errMessage) + } + severityDTO := severityEntity.ToDTO() return &severityDTO, err } +func (service *SeverityService) GetSeveritiesNotMatchingIncidentSeverity(channelID string) ([]severity.SeverityDTO, error) { + severities, err := service.severityRepository.GetSeveritiesNotMatchingIncidentSeverity(channelID) + if err != nil { + logger.Error("failed to get severities not matching incident severity", zap.Error(err)) + return nil, err + } + + return dto.ToDtoArray[severity.SeverityEntity, severity.SeverityDTO](severities), nil +} + func (service *SeverityService) createSeverityEscalationMap(severities []severity.SeverityDTO) map[uint]*severity.SeverityDTO { sort.Slice(severities, func(i, j int) bool { return severities[i].Priority > severities[j].Priority diff --git a/service/severity/impl/severity_service_test.go b/service/severity/impl/severity_service_test.go index 2121530..4d07fe3 100644 --- a/service/severity/impl/severity_service_test.go +++ b/service/severity/impl/severity_service_test.go @@ -33,6 +33,25 @@ func (suite *SeverityServiceSuite) Test_GetAllActiveSeverities_SuccessCase() { suite.Len(severities, len(*mockSeverityEntities), "length of severities should be equal") } +func (suite *SeverityServiceSuite) Test_GetSeveritiesNotMatchingIncidentSeverity_RepoFailureCase() { + suite.severityRepository.GetSeveritiesNotMatchingIncidentSeverityMock.Return(nil, errors.New("error")) + + severities, err := suite.severityService.GetSeveritiesNotMatchingIncidentSeverity("channelID") + suite.Nil(severities, "severities should be nil") + suite.NotNil(err, "error should not be nil") +} + +func (suite *SeverityServiceSuite) Test_GetSeveritiesNotMatchingIncidentSeverity_SuccessCase() { + mockSeverityEntities := *GetMockSeverityEntities() + suite.severityRepository.GetSeveritiesNotMatchingIncidentSeverityMock.Return(mockSeverityEntities, nil) + + severities, err := suite.severityService.GetSeveritiesNotMatchingIncidentSeverity("channelID") + suite.Nil(err, "error should be nil") + suite.NotNil(severities, "severities should not be nil") + suite.Len(severities, len(mockSeverityEntities), "length of severities should be equal") + +} + func GetMockSeverityEntities() *[]severity.SeverityEntity { return &[]severity.SeverityEntity{ {Name: "Low", Description: "Low severity"}, diff --git a/service/severity/severity_service_interface.go b/service/severity/severity_service_interface.go index ff61711..fb278c6 100644 --- a/service/severity/severity_service_interface.go +++ b/service/severity/severity_service_interface.go @@ -6,4 +6,5 @@ type ISeverityService interface { GetAllActiveSeverities() ([]severity.SeverityDTO, error) GetSeverityEscalationMap() (map[uint]*severity.SeverityDTO, error) FindSeverityById(severityId uint) (*severity.SeverityDTO, error) + GetSeveritiesNotMatchingIncidentSeverity(channelID string) ([]severity.SeverityDTO, error) } diff --git a/service/severity_service.go b/service/severity_service.go index e5fc46d..750f186 100644 --- a/service/severity_service.go +++ b/service/severity_service.go @@ -4,8 +4,8 @@ import ( "fmt" commonutil "houston/common/util" "houston/logger" - "houston/model/severity" "houston/pkg/slackbot" + "houston/repository/severity" request "houston/service/request" service "houston/service/response" common "houston/service/response/common" diff --git a/service/users_service.go b/service/users_service.go index 60d377e..a132f9e 100644 --- a/service/users_service.go +++ b/service/users_service.go @@ -7,11 +7,11 @@ import ( "github.com/slack-go/slack/socketmode" "go.uber.org/zap" "gorm.io/gorm" + "houston/appcontext" "houston/common/util" "houston/logger" "houston/model/incident" "houston/model/log" - "houston/model/severity" "houston/model/team" "houston/model/user" "houston/pkg/slackbot" @@ -36,14 +36,16 @@ func NewUserService(gin *gin.Engine, client *slackbot.Client, db *gorm.DB, logRepository := log.NewLogRepository(db) teamRepository := team.NewTeamRepository(db, logRepository) return &UserService{ - gin: gin, - client: client, - db: db, - socketModeClient: socketModeClient, - authService: authService, - userRepository: user.NewUserRepository(db), - incidentRepository: incident.NewIncidentRepository(db, severity.NewSeverityRepository(db), logRepository, teamRepository, socketModeClient), - teamRepository: teamRepository, + gin: gin, + client: client, + db: db, + socketModeClient: socketModeClient, + authService: authService, + userRepository: user.NewUserRepository(db), + incidentRepository: incident.NewIncidentRepository( + db, appcontext.GetSeverityService(), appcontext.GetIncidentStatusService(), logRepository, teamRepository, socketModeClient, + ), + teamRepository: teamRepository, } }