drone/app/services/notification/comment_created.go

210 lines
5.1 KiB
Go

// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package notification
import (
"context"
"fmt"
pullreqevents "github.com/harness/gitness/app/events/pullreq"
"github.com/harness/gitness/events"
"github.com/harness/gitness/types"
)
type CommentPayload struct {
Base *BasePullReqPayload
Commenter *types.PrincipalInfo
Text string
}
func (s *Service) notifyCommentCreated(
ctx context.Context,
event *events.Event[*pullreqevents.CommentCreatedPayload],
) error {
payload, mentions, participants, author, err := s.processCommentCreatedEvent(ctx, event)
if err != nil {
return fmt.Errorf(
"failed to process %s event for pullReqID %d: %w",
pullreqevents.CommentCreatedEvent,
event.Payload.PullReqID,
err,
)
}
if len(mentions) > 0 {
err = s.notificationClient.SendCommentMentions(ctx, mentions, payload)
if err != nil {
return fmt.Errorf(
"failed to send notification to mentions for event %s for pullReqID %d: %w",
pullreqevents.CommentCreatedEvent,
event.Payload.PullReqID,
err,
)
}
}
if len(participants) > 0 {
err = s.notificationClient.SendCommentParticipants(ctx, participants, payload)
if err != nil {
return fmt.Errorf(
"failed to send notification to participants for event %s for pullReqID %d: %w",
pullreqevents.CommentCreatedEvent,
event.Payload.PullReqID,
err,
)
}
}
if author != nil {
err = s.notificationClient.SendCommentPRAuthor(
ctx,
[]*types.PrincipalInfo{author},
payload,
)
if err != nil {
return fmt.Errorf(
"failed to send notification to author for event %s for pullReqID %d: %w",
pullreqevents.CommentCreatedEvent,
event.Payload.PullReqID,
err,
)
}
}
return nil
}
func (s *Service) processCommentCreatedEvent(
ctx context.Context,
event *events.Event[*pullreqevents.CommentCreatedPayload],
) (
payload *CommentPayload,
mentions []*types.PrincipalInfo,
participants []*types.PrincipalInfo,
author *types.PrincipalInfo,
err error,
) {
base, err := s.getBasePayload(ctx, event.Payload.Base)
if err != nil {
return nil, nil, nil, nil, fmt.Errorf("failed to get base payload: %w", err)
}
activity, err := s.pullReqActivityStore.Find(ctx, event.Payload.ActivityID)
if err != nil {
return nil, nil, nil, nil, fmt.Errorf("failed to fetch activity from pullReqActivityStore: %w", err)
}
commenter, err := s.principalInfoView.Find(ctx, activity.CreatedBy)
if err != nil {
return nil, nil, nil, nil, fmt.Errorf("failed to fetch commenter from principalInfoView: %w", err)
}
payload = &CommentPayload{
Base: base,
Commenter: commenter,
Text: activity.Text,
}
seen := make(map[int64]bool)
seen[commenter.ID] = true
// process mentions
mentions, err = s.processMentions(ctx, activity.Metadata, seen)
if err != nil {
return nil, nil, nil, nil, err
}
// process participants
participants, err = s.processParticipants(
ctx, event.Payload.IsReply, seen, event.Payload.PullReqID, activity.Order)
if err != nil {
return nil, nil, nil, nil, err
}
// process author
if !seen[base.Author.ID] {
author = base.Author
}
return payload, mentions, participants, author, nil
}
func (s *Service) processMentions(
ctx context.Context,
metadata *types.PullReqActivityMetadata,
seen map[int64]bool,
) ([]*types.PrincipalInfo, error) {
if metadata == nil || metadata.Mentions == nil {
return []*types.PrincipalInfo{}, nil
}
var ids []int64
for _, id := range metadata.Mentions.IDs {
if !seen[id] {
ids = append(ids, id)
seen[id] = true
}
}
if len(ids) == 0 {
return []*types.PrincipalInfo{}, nil
}
mentions, err := s.principalInfoView.FindMany(ctx, ids)
if err != nil {
return nil, fmt.Errorf("failed to fetch thread mentions from principalInfoView: %w", err)
}
return mentions, nil
}
func (s *Service) processParticipants(
ctx context.Context,
isReply bool,
seen map[int64]bool,
prID int64,
order int64,
) ([]*types.PrincipalInfo, error) {
var participants []*types.PrincipalInfo
if !isReply {
return participants, nil
}
authorIDs, err := s.pullReqActivityStore.ListAuthorIDs(
ctx,
prID,
order,
)
if err != nil {
return participants, fmt.Errorf("failed to fetch thread participant IDs from pullReqActivityStore: %w", err)
}
var participantIDs []int64
for _, authorID := range authorIDs {
if !seen[authorID] {
participantIDs = append(participantIDs, authorID)
seen[authorID] = true
}
}
if len(participantIDs) > 0 {
participants, err = s.principalInfoView.FindMany(ctx, participantIDs)
if err != nil {
return participants, fmt.Errorf("failed to fetch thread participants from principalInfoView: %w", err)
}
}
return participants, nil
}