From 147958cc1ac24e3fb850900cc0ea36e58dbfbacb Mon Sep 17 00:00:00 2001 From: Shashank Shekhar Date: Wed, 16 Aug 2023 13:43:07 +0530 Subject: [PATCH] TP-38301 | ading resolution text modal and action (#120) * TP-38301 | ading resolution text modal and action * TP-38301 | ading resolution text processor --- common/util/constant.go | 46 ++++----- .../action/incident_resolve_action.go | 73 ++++++++------ .../incident_update_resolution_text_action.go | 99 +++++++++++++++++++ .../action/view/incident_resolution_text.go | 42 ++++++++ .../processor/action/view/incident_section.go | 7 ++ .../event_type_interactive_processor.go | 86 +++++++++------- model/incident/entity.go | 1 + 7 files changed, 265 insertions(+), 89 deletions(-) create mode 100644 internal/processor/action/incident_update_resolution_text_action.go create mode 100644 internal/processor/action/view/incident_resolution_text.go diff --git a/common/util/constant.go b/common/util/constant.go index a2957d9..3042bfe 100644 --- a/common/util/constant.go +++ b/common/util/constant.go @@ -3,31 +3,33 @@ package util type BlockActionType string const ( - StartIncident BlockActionType = "start_incident" - ShowIncidents = "show_incidents" - Incident = "incident" - Tags = "tags" - AssignIncidentRole = "assign_incident_role" - ResolveIncident = "resolve_incident" - SetIncidentStatus = "set_incident_status" - SetIncidentType = "set_incident_type" - SetIncidentSeverity = "set_incident_severity" - SetIncidentTitle = "set_incident_title" - SetIncidentDescription = "set_incident_description" - AddTags = "add_tags" - ShowTags = "show_tags" - RemoveTag = "remove_tags" + StartIncident BlockActionType = "start_incident" + ShowIncidents = "show_incidents" + Incident = "incident" + Tags = "tags" + AssignIncidentRole = "assign_incident_role" + ResolveIncident = "resolve_incident" + SetIncidentStatus = "set_incident_status" + SetIncidentType = "set_incident_type" + SetIncidentSeverity = "set_incident_severity" + SetIncidentTitle = "set_incident_title" + SetIncidentDescription = "set_incident_description" + SetIncidentResolutionText = "set_incident_resolution_text" + AddTags = "add_tags" + ShowTags = "show_tags" + RemoveTag = "remove_tags" ) type ViewSubmissionType string const ( - StartIncidentSubmit ViewSubmissionType = "start_incident_submit" - AssignIncidentRoleSubmit = "assign_incident_role_submit" - SetIncidentStatusSubmit = "set_incident_status_submit" - SetIncidentTitleSubmit = "set_incident_title_submit" - SetIncidentDescriptionSubmit = "set_incident_description_submit" - SetIncidentSeveritySubmit = "set_incident_severity_submit" - SetIncidentTypeSubmit = "set_incident_type_submit" - UpdateTagSubmit = "updateTagSubmit" + StartIncidentSubmit ViewSubmissionType = "start_incident_submit" + AssignIncidentRoleSubmit = "assign_incident_role_submit" + SetIncidentStatusSubmit = "set_incident_status_submit" + SetIncidentTitleSubmit = "set_incident_title_submit" + SetIncidentDescriptionSubmit = "set_incident_description_submit" + SetIncidentSeveritySubmit = "set_incident_severity_submit" + SetIncidentTypeSubmit = "set_incident_type_submit" + UpdateTagSubmit = "updateTagSubmit" + SetIncidentResolutionTextSubmit = "set_incident_resolution_text_submit" ) diff --git a/internal/processor/action/incident_resolve_action.go b/internal/processor/action/incident_resolve_action.go index 1679234..d3584e5 100644 --- a/internal/processor/action/incident_resolve_action.go +++ b/internal/processor/action/incident_resolve_action.go @@ -6,6 +6,7 @@ import ( "houston/model/severity" "houston/model/tag" "houston/model/team" + "strings" "time" "github.com/slack-go/slack" @@ -49,6 +50,7 @@ func (irp *ResolveIncidentAction) IncidentResolveProcess(callback slack.Interact irp.logger.Error(fmt.Sprintf("failure while getting tags for incident id: %v", incidentEntity.ID)) return } + // check if tags are required to be set var flag = true for _, t := range *tags { if t.Optional == false { @@ -77,42 +79,53 @@ func (irp *ResolveIncidentAction) IncidentResolveProcess(callback slack.Interact } } - if flag == true { - now := time.Now() - incidentEntity.Status = incidentStatusEntity.ID - incidentEntity.EndTime = &now - - err = irp.incidentService.UpdateIncident(incidentEntity) - if err != nil { - irp.logger.Error("failed to update incident to resolve state", - zap.String("channel", channelId), - zap.String("user_id", callback.User.ID), zap.Error(err)) - return - } - - irp.logger.Info("successfully resolved the incident", - zap.String("channel", channelId), - zap.String("user_id", callback.User.ID)) - msgOption := slack.MsgOptionText(fmt.Sprintf("<@%s> *>* `houston set status to %s`", callback.User.ID, - incident.Resolved), false) - _, _, errMessage := irp.client.PostMessage(callback.Channel.ID, msgOption) - if errMessage != nil { - irp.logger.Error("post response failed for ResolveIncident", zap.Error(errMessage)) - return - } - msgUpdate := NewIncidentChannelMessageUpdateAction(irp.client, irp.logger, irp.incidentService, irp.teamRepository, irp.severityRepository) - msgUpdate.ProcessAction(incidentEntity.SlackChannel) - if incidentEntity.SeverityId != 1 && incidentEntity.SeverityId != 2 { - irp.client.ArchiveConversation(channelId) - } - } else { - msgOption := slack.MsgOptionText(fmt.Sprintf("`Please set tag value`"), false) + // check if resolution text is set + if strings.TrimSpace(incidentEntity.ResolutionText) == "" { + msgOption := slack.MsgOptionText(fmt.Sprintf("`Please set incident resolution text`"), false) _, errMessage := irp.client.PostEphemeral(callback.Channel.ID, callback.User.ID, msgOption) if errMessage != nil { irp.logger.Error("post response failed for ResolveIncident", zap.Error(errMessage)) return } + } else { + // 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 { + irp.logger.Error("failed to update incident to resolve state", + zap.String("channel", channelId), + zap.String("user_id", callback.User.ID), zap.Error(err)) + return + } + + irp.logger.Info("successfully resolved the incident", + zap.String("channel", channelId), + zap.String("user_id", callback.User.ID)) + msgOption := slack.MsgOptionText(fmt.Sprintf("<@%s> *>* `houston set status to %s`", callback.User.ID, + incident.Resolved), false) + _, _, errMessage := irp.client.PostMessage(callback.Channel.ID, msgOption) + if errMessage != nil { + irp.logger.Error("post response failed for ResolveIncident", zap.Error(errMessage)) + return + } + msgUpdate := NewIncidentChannelMessageUpdateAction(irp.client, irp.logger, irp.incidentService, irp.teamRepository, irp.severityRepository) + msgUpdate.ProcessAction(incidentEntity.SlackChannel) + if incidentEntity.SeverityId != 1 && incidentEntity.SeverityId != 2 { + irp.client.ArchiveConversation(channelId) + } + } else { + msgOption := slack.MsgOptionText(fmt.Sprintf("`Please set tag value`"), false) + _, errMessage := irp.client.PostEphemeral(callback.Channel.ID, callback.User.ID, msgOption) + if errMessage != nil { + irp.logger.Error("post response failed for ResolveIncident", zap.Error(errMessage)) + return + } + + } } var payload interface{} diff --git a/internal/processor/action/incident_update_resolution_text_action.go b/internal/processor/action/incident_update_resolution_text_action.go new file mode 100644 index 0000000..ddf6992 --- /dev/null +++ b/internal/processor/action/incident_update_resolution_text_action.go @@ -0,0 +1,99 @@ +package action + +import ( + "fmt" + "houston/internal/processor/action/view" + "houston/model/incident" + + "github.com/slack-go/slack" + "github.com/slack-go/slack/socketmode" + "go.uber.org/zap" +) + +type IncidentUpdateResolutionTextAction struct { + client *socketmode.Client + logger *zap.Logger + incidentRepository *incident.Repository +} + +func NewIncidentUpdateResolutionTextAction(client *socketmode.Client, logger *zap.Logger, incidentRepository *incident.Repository) *IncidentUpdateResolutionTextAction { + return &IncidentUpdateResolutionTextAction{ + client: client, + logger: logger, + incidentRepository: incidentRepository, + } +} + +func (idp *IncidentUpdateResolutionTextAction) IncidentUpdateResolutionTextRequestProcess(callback slack.InteractionCallback, request *socketmode.Request) { + result, err := idp.incidentRepository.FindIncidentByChannelId(callback.Channel.ID) + if err != nil { + idp.logger.Error("FindIncidentByChannelId 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 + } else if result == nil { + idp.logger.Error("IncidentEntity not found ", + 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.BuildIncidentResolutionTextModal(callback.Channel, result.ResolutionText) + + _, err = idp.client.OpenView(callback.TriggerID, modalRequest) + if err != nil { + idp.logger.Error("houston slackbot openview command for IncidentUpdateResolutionTextRequestProcess failed.", + zap.String("trigger_id", callback.TriggerID), zap.String("channel_id", callback.Channel.ID), zap.Error(err)) + return + } + var payload interface{} + idp.client.Ack(*request, payload) +} + +func (itp *IncidentUpdateResolutionTextAction) IncidentUpdateResolutionText(callback slack.InteractionCallback, request *socketmode.Request, channel slack.Channel, user slack.User) { + incidentEntity, err := itp.incidentRepository.FindIncidentByChannelId(callback.View.PrivateMetadata) + if err != nil { + itp.logger.Error("FindIncidentByChannelId error", + zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name), + zap.String("user_id", user.ID), zap.Error(err)) + return + } else if incidentEntity == nil { + itp.logger.Error("IncidentEntity not found ", + 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 + } + + incidentResolutionText := buildUpdateIncidentResolutionTextRequest(callback.View.State.Values) + + incidentEntity.ResolutionText = incidentResolutionText + incidentEntity.UpdatedBy = user.ID + err = itp.incidentRepository.UpdateIncident(incidentEntity) + if err != nil { + itp.logger.Error("IncidentUpdateResolutionText error", + zap.String("incident_slack_channel_id", channel.ID), zap.String("channel", channel.Name), + zap.String("user_id", user.ID), zap.Error(err)) + return + } + msgOption := slack.MsgOptionText(fmt.Sprintf("<@%s> *>* `houston set resolution_text = to %s`", user.ID, incidentEntity.ResolutionText), false) + _, _, errMessage := itp.client.PostMessage(callback.View.PrivateMetadata, msgOption) + if errMessage != nil { + itp.logger.Error("post response failed for IncidentUpdateResolutionText", zap.Error(errMessage)) + return + } + + var payload interface{} + itp.client.Ack(*request, payload) +} + +func buildUpdateIncidentResolutionTextRequest(blockActions map[string]map[string]slack.BlockAction) string { + var requestMap = make(map[string]string, 0) + for _, actions := range blockActions { + for actionID, a := range actions { + if a.Type == "plain_text_input" { + requestMap[actionID] = a.Value + } + } + } + + return requestMap["incident_resolution_text"] +} diff --git a/internal/processor/action/view/incident_resolution_text.go b/internal/processor/action/view/incident_resolution_text.go new file mode 100644 index 0000000..e251904 --- /dev/null +++ b/internal/processor/action/view/incident_resolution_text.go @@ -0,0 +1,42 @@ +package view + +import ( + "github.com/slack-go/slack" + "houston/common/util" +) + +func BuildIncidentResolutionTextModal(channel slack.Channel, description string) slack.ModalViewRequest { + titleText := slack.NewTextBlockObject(slack.PlainTextType, "Set Resolution Text", false, false) + closeText := slack.NewTextBlockObject(slack.PlainTextType, "Close", false, false) + submitText := slack.NewTextBlockObject(slack.PlainTextType, "Submit", false, false) + + headerText := slack.NewTextBlockObject("mrkdwn", "Incident Resolution Text", false, false) + headerSection := slack.NewSectionBlock(headerText, nil, nil) + + incidentResolutionTextText := slack.NewTextBlockObject(slack.PlainTextType, "Incident Resolution Text", false, false) + incidentResolutionTextPlaceholder := slack.NewTextBlockObject(slack.PlainTextType, "Write incident resolution text", false, false) + incidentResolutionTextElement := slack.NewPlainTextInputBlockElement(incidentResolutionTextPlaceholder, "incident_resolution_text") + incidentResolutionTextElement.Multiline = true + incidentResolutionTextElement.InitialValue = description + incidentResolutionTextElement.MaxLength = 3000 + incidentResolutionText := slack.NewInputBlock("Incident resolution text", incidentResolutionTextText, nil, incidentResolutionTextElement) + incidentResolutionText.Optional = true + + blocks := slack.Blocks{ + BlockSet: []slack.Block{ + headerSection, + incidentResolutionText, + }, + } + + return slack.ModalViewRequest{ + Type: slack.VTModal, + Title: titleText, + Close: closeText, + Submit: submitText, + Blocks: blocks, + PrivateMetadata: channel.ID, + CallbackID: util.SetIncidentResolutionTextSubmit, + } + +} diff --git a/internal/processor/action/view/incident_section.go b/internal/processor/action/view/incident_section.go index 22b346f..17cf7fa 100644 --- a/internal/processor/action/view/incident_section.go +++ b/internal/processor/action/view/incident_section.go @@ -127,6 +127,13 @@ func incidentSectionBlock() *slack.SectionBlock { }, Value: util.SetIncidentDescription, }, + { + Text: &slack.TextBlockObject{ + Type: "plain_text", + Text: "Set Incident Resolution Text", + }, + Value: util.SetIncidentResolutionText, + }, } accessoryOption := &slack.Accessory{ diff --git a/internal/processor/event_type_interactive_processor.go b/internal/processor/event_type_interactive_processor.go index 2e1e9ae..513a522 100644 --- a/internal/processor/event_type_interactive_processor.go +++ b/internal/processor/event_type_interactive_processor.go @@ -20,38 +20,40 @@ type interactiveEventProcessor interface { } type BlockActionProcessor struct { - logger *zap.Logger - socketModeClient *socketmode.Client - startIncidentBlockAction *action.StartIncidentBlockAction - showIncidentsAction *action.ShowIncidentsAction - assignIncidentAction *action.AssignIncidentAction - incidentResolveAction *action.ResolveIncidentAction - incidentUpdateAction *action.UpdateIncidentAction - incidentUpdateTypeAction *action.IncidentUpdateTypeAction - incidentUpdateSeverityAction *action.IncidentUpdateSevertityAction - incidentUpdateTitleAction *action.IncidentUpdateTitleAction - incidentUpdateDescriptionAction *action.IncidentUpdateDescriptionAction - incidentUpdateTagsAction *action.IncidentUpdateTagsAction - incidentShowTagsAction *action.IncidentShowTagsAction + logger *zap.Logger + socketModeClient *socketmode.Client + startIncidentBlockAction *action.StartIncidentBlockAction + showIncidentsAction *action.ShowIncidentsAction + assignIncidentAction *action.AssignIncidentAction + incidentResolveAction *action.ResolveIncidentAction + incidentUpdateAction *action.UpdateIncidentAction + incidentUpdateTypeAction *action.IncidentUpdateTypeAction + incidentUpdateSeverityAction *action.IncidentUpdateSevertityAction + incidentUpdateTitleAction *action.IncidentUpdateTitleAction + incidentUpdateDescriptionAction *action.IncidentUpdateDescriptionAction + incidentUpdateTagsAction *action.IncidentUpdateTagsAction + incidentShowTagsAction *action.IncidentShowTagsAction + incidentUpdateResolutionTextAction *action.IncidentUpdateResolutionTextAction } -func NewBlockActionProcessor(logger *zap.Logger, socketModeClient *socketmode.Client, incidentService *incident.Repository, +func NewBlockActionProcessor(logger *zap.Logger, socketModeClient *socketmode.Client, incidentRepository *incident.Repository, teamService *team.Repository, severityService *severity.Repository, tagService *tag.Repository, slackbotClient *slackbot.Client) *BlockActionProcessor { return &BlockActionProcessor{ - logger: logger, - socketModeClient: socketModeClient, - startIncidentBlockAction: action.NewStartIncidentBlockAction(socketModeClient, logger, teamService, severityService), - showIncidentsAction: action.ShowIncidentsProcessor(socketModeClient, logger, incidentService), - assignIncidentAction: action.NewAssignIncidentAction(socketModeClient, logger, incidentService), - incidentResolveAction: action.NewIncidentResolveProcessor(socketModeClient, logger, incidentService, tagService, teamService, severityService), - incidentUpdateAction: action.NewIncidentUpdateAction(socketModeClient, logger, incidentService, tagService, teamService, severityService), - incidentUpdateTypeAction: action.NewIncidentUpdateTypeAction(socketModeClient, logger, incidentService, teamService, severityService, slackbotClient), - incidentUpdateSeverityAction: action.NewIncidentUpdateSeverityAction(socketModeClient, logger, incidentService, severityService, teamService, slackbotClient), - incidentUpdateTitleAction: action.NewIncidentUpdateTitleAction(socketModeClient, logger, incidentService, teamService, severityService, slackbotClient), - incidentUpdateDescriptionAction: action.NewIncidentUpdateDescriptionAction(socketModeClient, logger, incidentService), - incidentUpdateTagsAction: action.NewIncidentUpdateTagsAction(socketModeClient, logger, incidentService, teamService, tagService), - incidentShowTagsAction: action.NewIncidentShowTagsProcessor(socketModeClient, logger, incidentService, tagService), + logger: logger, + socketModeClient: socketModeClient, + startIncidentBlockAction: action.NewStartIncidentBlockAction(socketModeClient, logger, teamService, severityService), + showIncidentsAction: action.ShowIncidentsProcessor(socketModeClient, logger, incidentRepository), + assignIncidentAction: action.NewAssignIncidentAction(socketModeClient, logger, incidentRepository), + incidentResolveAction: action.NewIncidentResolveProcessor(socketModeClient, logger, incidentRepository, tagService, teamService, severityService), + incidentUpdateAction: action.NewIncidentUpdateAction(socketModeClient, logger, incidentRepository, tagService, teamService, severityService), + incidentUpdateTypeAction: action.NewIncidentUpdateTypeAction(socketModeClient, logger, incidentRepository, teamService, severityService, slackbotClient), + incidentUpdateSeverityAction: action.NewIncidentUpdateSeverityAction(socketModeClient, logger, incidentRepository, severityService, teamService, slackbotClient), + incidentUpdateTitleAction: action.NewIncidentUpdateTitleAction(socketModeClient, logger, incidentRepository, teamService, severityService, slackbotClient), + incidentUpdateDescriptionAction: action.NewIncidentUpdateDescriptionAction(socketModeClient, logger, incidentRepository), + incidentUpdateTagsAction: action.NewIncidentUpdateTagsAction(socketModeClient, logger, incidentRepository, teamService, tagService), + incidentShowTagsAction: action.NewIncidentShowTagsProcessor(socketModeClient, logger, incidentRepository, tagService), + incidentUpdateResolutionTextAction: action.NewIncidentUpdateResolutionTextAction(socketModeClient, logger, incidentRepository), } } @@ -132,6 +134,10 @@ func (bap *BlockActionProcessor) processIncidentCommands(callback slack.Interact { bap.incidentUpdateDescriptionAction.IncidentUpdateDescriptionRequestProcess(callback, request) } + case util.SetIncidentResolutionText: + { + bap.incidentUpdateResolutionTextAction.IncidentUpdateResolutionTextRequestProcess(callback, request) + } } } @@ -165,23 +171,25 @@ type ViewSubmissionProcessor struct { incidentUpdateSeverityAction *action.IncidentUpdateSevertityAction incidentUpdateTypeAction *action.IncidentUpdateTypeAction incidentUpdateTagsAction *action.IncidentUpdateTagsAction + incidentUpdateResolutionText *action.IncidentUpdateResolutionTextAction } -func NewViewSubmissionProcessor(logger *zap.Logger, socketModeClient *socketmode.Client, incidentService *incident.Repository, +func NewViewSubmissionProcessor(logger *zap.Logger, socketModeClient *socketmode.Client, incidentRepository *incident.Repository, teamService *team.Repository, severityService *severity.Repository, tagService *tag.Repository, slackbotClient *slackbot.Client) *ViewSubmissionProcessor { return &ViewSubmissionProcessor{ logger: logger, socketModeClient: socketModeClient, - incidentChannelMessageUpdateAction: action.NewIncidentChannelMessageUpdateAction(socketModeClient, logger, incidentService, teamService, severityService), - createIncidentAction: action.NewCreateIncidentProcessor(socketModeClient, logger, incidentService, teamService, severityService, slackbotClient), - assignIncidentAction: action.NewAssignIncidentAction(socketModeClient, logger, incidentService), - updateIncidentAction: action.NewIncidentUpdateAction(socketModeClient, logger, incidentService, tagService, teamService, severityService), - incidentUpdateTitleAction: action.NewIncidentUpdateTitleAction(socketModeClient, logger, incidentService, teamService, severityService, slackbotClient), - incidentUpdateDescriptionAction: action.NewIncidentUpdateDescriptionAction(socketModeClient, logger, incidentService), - incidentUpdateSeverityAction: action.NewIncidentUpdateSeverityAction(socketModeClient, logger, incidentService, severityService, teamService, slackbotClient), - incidentUpdateTypeAction: action.NewIncidentUpdateTypeAction(socketModeClient, logger, incidentService, teamService, severityService, slackbotClient), - incidentUpdateTagsAction: action.NewIncidentUpdateTagsAction(socketModeClient, logger, incidentService, teamService, tagService), + incidentChannelMessageUpdateAction: action.NewIncidentChannelMessageUpdateAction(socketModeClient, logger, incidentRepository, teamService, severityService), + createIncidentAction: action.NewCreateIncidentProcessor(socketModeClient, logger, incidentRepository, teamService, severityService, slackbotClient), + assignIncidentAction: action.NewAssignIncidentAction(socketModeClient, logger, incidentRepository), + updateIncidentAction: action.NewIncidentUpdateAction(socketModeClient, logger, incidentRepository, tagService, teamService, severityService), + incidentUpdateTitleAction: action.NewIncidentUpdateTitleAction(socketModeClient, logger, incidentRepository, teamService, severityService, slackbotClient), + incidentUpdateDescriptionAction: action.NewIncidentUpdateDescriptionAction(socketModeClient, logger, incidentRepository), + incidentUpdateSeverityAction: action.NewIncidentUpdateSeverityAction(socketModeClient, logger, incidentRepository, severityService, teamService, slackbotClient), + incidentUpdateTypeAction: action.NewIncidentUpdateTypeAction(socketModeClient, logger, incidentRepository, teamService, severityService, slackbotClient), + incidentUpdateTagsAction: action.NewIncidentUpdateTagsAction(socketModeClient, logger, incidentRepository, teamService, tagService), + incidentUpdateResolutionText: action.NewIncidentUpdateResolutionTextAction(socketModeClient, logger, incidentRepository), } } @@ -226,6 +234,10 @@ func (vsp *ViewSubmissionProcessor) ProcessCommand(callback slack.InteractionCal { vsp.incidentUpdateTagsAction.IncidentUpdateTags(callback, request) } + case util.SetIncidentResolutionTextSubmit: + { + vsp.incidentUpdateResolutionText.IncidentUpdateResolutionText(callback, request, callback.Channel, callback.User) + } default: { return diff --git a/model/incident/entity.go b/model/incident/entity.go index 071a831..9ff6af9 100644 --- a/model/incident/entity.go +++ b/model/incident/entity.go @@ -47,6 +47,7 @@ type IncidentEntity struct { CreatedBy string `gorm:"column:created_by"` UpdatedBy string `gorm:"column:updated_by"` MetaData JSON `gorm:"column:meta_data"` + ResolutionText string `gorm:"column:resolution_text"` } func (IncidentEntity) TableName() string {