diff --git a/internal/interactor/event.go b/internal/interactor/event.go index 15b7084a..aa4b4dd6 100644 --- a/internal/interactor/event.go +++ b/internal/interactor/event.go @@ -2,11 +2,9 @@ package interactor import ( "context" - "fmt" "time" "github.com/gitploy-io/gitploy/ent" - "github.com/gitploy-io/gitploy/ent/event" "go.uber.org/zap" ) @@ -52,41 +50,3 @@ func (i *Interactor) SubscribeEvent(fn func(e *ent.Event)) error { func (i *Interactor) UnsubscribeEvent(fn func(e *ent.Event)) error { return i.events.Unsubscribe(gitployEvent, fn) } - -func (i *Interactor) ListUsersOfEvent(ctx context.Context, e *ent.Event) ([]*ent.User, error) { - if e.Kind == event.KindDeployment { - d, err := i.Store.FindDeploymentByID(ctx, e.DeploymentID) - if err != nil { - return nil, fmt.Errorf("It has failed to find the deployment: %w", err) - } - - return []*ent.User{d.Edges.User}, nil - } - - // Notify to who has the request of approval. - if e.Kind == event.KindApproval && e.Type == event.TypeCreated { - a, err := i.Store.FindApprovalByID(ctx, e.ApprovalID) - if err != nil { - return nil, fmt.Errorf("It has failed to find the approval: %w", err) - } - - return []*ent.User{a.Edges.User}, nil - } - - // Notify to who has requested the approval. - if e.Kind == event.KindApproval && e.Type == event.TypeUpdated { - a, err := i.Store.FindApprovalByID(ctx, e.ApprovalID) - if err != nil { - return nil, fmt.Errorf("It has failed to find the approval: %w", err) - } - - d, err := i.Store.FindDeploymentByID(ctx, a.DeploymentID) - if err != nil { - return nil, fmt.Errorf("It has failed to find the deployment of the approval: %w", err) - } - - return []*ent.User{d.Edges.User}, nil - } - - return nil, fmt.Errorf("It is out of use-cases.") -} diff --git a/internal/server/slack/interface.go b/internal/server/slack/interface.go index c8b5dd8f..fff74de7 100644 --- a/internal/server/slack/interface.go +++ b/internal/server/slack/interface.go @@ -38,7 +38,6 @@ type ( SubscribeEvent(fn func(e *ent.Event)) error UnsubscribeEvent(fn func(e *ent.Event)) error - ListUsersOfEvent(ctx context.Context, e *ent.Event) ([]*ent.User, error) CheckNotificationRecordOfEvent(ctx context.Context, e *ent.Event) bool CreateEvent(ctx context.Context, e *ent.Event) (*ent.Event, error) diff --git a/internal/server/slack/notification.go b/internal/server/slack/notification.go index 1f8f23ad..c43430ad 100644 --- a/internal/server/slack/notification.go +++ b/internal/server/slack/notification.go @@ -20,111 +20,127 @@ const ( colorRed = "#f5222d" ) -func (s *Slack) Notify(ctx context.Context, e *ent.Event) error { - if s.i.CheckNotificationRecordOfEvent(ctx, e) { - return nil +func (s *Slack) Notify(ctx context.Context, e *ent.Event) { + if e.Kind == event.KindDeployment { + s.notifyDeploymentEvent(ctx, e) } - var ( - users []*ent.User - err error - ) - - if users, err = s.i.ListUsersOfEvent(ctx, e); err != nil { - return err + if e.Kind == event.KindApproval { + s.notifyApprovalEvent(ctx, e) } +} - for _, u := range users { - // Eager loading for chat user. - if u, err = s.i.FindUserByID(ctx, u.ID); err != nil { - s.log.Error("It has failed to eager load.", zap.Error(err)) - continue - } - if u.Edges.ChatUser == nil { - continue - } +func (s *Slack) notifyDeploymentEvent(ctx context.Context, e *ent.Event) { + if err := e.CheckEagerLoading(); err != nil { + s.log.Error("The eager loading of event has failed.") + return + } - if err := s.notify(ctx, u.Edges.ChatUser, e); err != nil { - s.log.Error("It has failed to notify the event.", zap.Error(err)) - } + d := e.Edges.Deployment + if err := d.CheckEagerLoading(); err != nil { + s.log.Error("The eager loading of deployment has failed.") + return } - return nil -} + owner, err := s.i.FindUserByID(ctx, d.Edges.User.ID) + if err != nil { + s.log.Error("It has failed to find the owner of the deployment.", zap.Error(err)) + return + } + if owner.Edges.ChatUser == nil { + s.log.Debug("Skip the notification. The owner is not connected with Slack.") + return + } -func (s *Slack) notify(ctx context.Context, cu *ent.ChatUser, e *ent.Event) error { + // Build the message and post it. var option slack.MsgOption - // Check the event has processed eager loading. + if e.Type == event.TypeCreated { + option = slack.MsgOptionAttachments(slack.Attachment{ + Color: mapDeploymentStatusToColor(d.Status), + Pretext: fmt.Sprintf("*New Deployment #%d*", d.Number), + Text: fmt.Sprintf("*%s* deploys `%s` to the `%s` environment of `%s`. <%s|• View Details> ", owner.Login, d.GetShortRef(), d.Env, d.Edges.Repo.GetFullName(), s.buildDeploymentLink(d.Edges.Repo, d)), + }) + } else if e.Type == event.TypeUpdated { + option = slack.MsgOptionAttachments(slack.Attachment{ + Color: mapDeploymentStatusToColor(d.Status), + Pretext: fmt.Sprintf("*Deployment Updated #%d*", d.Number), + Text: fmt.Sprintf("The deployment <%s|#%d> of `%s` is updated `%s`.", s.buildDeploymentLink(d.Edges.Repo, d), d.Number, d.Edges.Repo.GetFullName(), d.Status), + }) + } + + if _, _, err := slack. + New(owner.Edges.ChatUser.BotToken). + PostMessageContext(ctx, owner.Edges.ChatUser.ID, option); err != nil { + s.log.Error("It has failed to post the message.", zap.Error(err)) + } +} + +func (s *Slack) notifyApprovalEvent(ctx context.Context, e *ent.Event) { if err := e.CheckEagerLoading(); err != nil { - return err + s.log.Error("The eager loading of event has failed.") + return } - if e.Kind == event.KindDeployment { - d := e.Edges.Deployment - if err := d.CheckEagerLoading(); err != nil { - return err - } + a := e.Edges.Approval + if err := a.CheckEagerLoading(); err != nil { + s.log.Error("The eager loading of approval has failed.") + return + } - var ( - r = d.Edges.Repo - u = d.Edges.User - ) - - if e.Type == event.TypeCreated { - option = slack.MsgOptionAttachments( - slack.Attachment{ - Color: mapDeploymentStatusToColor(d.Status), - Pretext: fmt.Sprintf("*New Deployment #%d*", d.Number), - Text: fmt.Sprintf("*%s* deploys `%s` to the `%s` environment of `%s`. <%s|• View Details> ", u.Login, d.GetShortRef(), d.Env, r.GetFullName(), s.buildDeploymentLink(r, d)), - }, - ) - } else if e.Type == event.TypeUpdated { - option = slack.MsgOptionAttachments( - slack.Attachment{ - Color: mapDeploymentStatusToColor(d.Status), - Pretext: fmt.Sprintf("*Deployment Updated #%d*", d.Number), - Text: fmt.Sprintf("The deployment <%s|#%d> of `%s` is updated `%s`.", s.buildDeploymentLink(r, d), d.Number, r.GetFullName(), d.Status), - }, - ) + d := e.Edges.Deployment + if err := d.CheckEagerLoading(); err != nil { + s.log.Error("The eager loading of deployment has failed.") + return + } + + if e.Type == event.TypeCreated { + option := slack.MsgOptionAttachments(slack.Attachment{ + Color: colorPurple, + Pretext: "*Approval Requested*", + Text: fmt.Sprintf("%s has requested the approval for the deployment <%s|#%d> of `%s`.", d.Edges.User.Login, s.buildDeploymentLink(d.Edges.Repo, d), d.Number, d.Edges.Repo.GetFullName()), + }) + + recipient, err := s.i.FindUserByID(ctx, a.Edges.User.ID) + if err != nil { + s.log.Error("It has failed to find the recipient of the approval.", zap.Error(err)) + return } - } else if e.Kind == event.KindApproval { - a := e.Edges.Approval - if err := a.CheckEagerLoading(); err != nil { - return err + if recipient.Edges.ChatUser == nil { + s.log.Debug("Skip the notification. The recipient is not connected with Slack.") + return } - var ( - u *ent.User = a.Edges.User - d *ent.Deployment = a.Edges.Deployment - r *ent.Repo - ) + if _, _, err := slack. + New(recipient.Edges.ChatUser.BotToken). + PostMessageContext(ctx, recipient.Edges.ChatUser.ID, option); err != nil { + s.log.Error("It has failed to post the message.", zap.Error(err)) + } + } - // Approval have to process eager loading for the deployment, too. - if err := d.CheckEagerLoading(); err != nil { - return err + if e.Type == event.TypeUpdated { + option := slack.MsgOptionAttachments(slack.Attachment{ + Color: mapApprovalStatusToColor(a.Status), + Pretext: "*Approval Responded*", + Text: fmt.Sprintf("%s has *%s* for the deployment <%s|#%d> of `%s`.", a.Edges.User.Login, a.Status, s.buildDeploymentLink(d.Edges.Repo, d), d.Number, d.Edges.Repo.GetFullName()), + }) + + requester, err := s.i.FindUserByID(ctx, d.Edges.User.ID) + if err != nil { + s.log.Error("It has failed to find the requester of the approval.", zap.Error(err)) + return } - r = d.Edges.Repo - - if e.Type == event.TypeCreated { - option = slack.MsgOptionAttachments(slack.Attachment{ - Color: colorPurple, - Pretext: "*Approval Requested*", - Text: fmt.Sprintf("%s has requested the approval for the deployment <%s|#%d> of `%s`.", u.Login, s.buildDeploymentLink(r, d), d.Number, r.GetFullName()), - }) - } else if e.Type == event.TypeUpdated { - option = slack.MsgOptionAttachments(slack.Attachment{ - Color: mapApprovalStatusToColor(a.Status), - Pretext: "*Approval Responded*", - Text: fmt.Sprintf("%s has *%s* for the deployment <%s|#%d> of `%s`.", u.Login, a.Status, s.buildDeploymentLink(r, d), d.Number, r.GetFullName()), - }) + if requester.Edges.ChatUser == nil { + s.log.Debug("Skip the notification. The requester is not connected with Slack.") + return } - } - _, _, err := slack. - New(cu.BotToken). - PostMessageContext(ctx, cu.ID, option) - return err + if _, _, err := slack. + New(requester.Edges.ChatUser.BotToken). + PostMessageContext(ctx, requester.Edges.ChatUser.ID, option); err != nil { + s.log.Error("It has failed to post the message.", zap.Error(err)) + } + } } func (s *Slack) buildDeploymentLink(r *ent.Repo, d *ent.Deployment) string { diff --git a/internal/server/slack/slack.go b/internal/server/slack/slack.go index 011c9243..db644014 100644 --- a/internal/server/slack/slack.go +++ b/internal/server/slack/slack.go @@ -42,9 +42,7 @@ func NewSlack(c *SlackConfig) *Slack { } s.i.SubscribeEvent(func(e *ent.Event) { - if err := s.Notify(context.Background(), e); err != nil { - s.log.Error("It has failed to push notificaitons.", zap.Error(err)) - } + s.Notify(context.Background(), e) }) return s