From 7c1defba01fbc91cc81e1a0841cecb6738056db7 Mon Sep 17 00:00:00 2001 From: Johnny Date: Sun, 1 Mar 2026 20:11:23 +0800 Subject: [PATCH] feat(webhook): dispatch webhook on memo comment creation --- server/router/api/v1/memo_service.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/server/router/api/v1/memo_service.go b/server/router/api/v1/memo_service.go index 954a665c5..f7f8e7622 100644 --- a/server/router/api/v1/memo_service.go +++ b/server/router/api/v1/memo_service.go @@ -625,6 +625,10 @@ func (s *APIV1Service) CreateMemoComment(ctx context.Context, request *v1pb.Crea } } + if err := s.DispatchMemoCommentCreatedWebhook(ctx, memoComment, relatedMemo.CreatorID); err != nil { + slog.Warn("Failed to dispatch memo comment created webhook", slog.Any("err", err)) + } + return memoComment, nil } @@ -745,6 +749,24 @@ func (s *APIV1Service) DispatchMemoDeletedWebhook(ctx context.Context, memo *v1p return s.dispatchMemoRelatedWebhook(ctx, memo, "memos.memo.deleted") } +// DispatchMemoCommentCreatedWebhook dispatches webhook to the related memo owner when a comment is created. +func (s *APIV1Service) DispatchMemoCommentCreatedWebhook(ctx context.Context, commentMemo *v1pb.Memo, relatedMemoCreatorID int32) error { + webhooks, err := s.Store.GetUserWebhooks(ctx, relatedMemoCreatorID) + if err != nil { + return err + } + for _, hook := range webhooks { + payload, err := convertMemoToWebhookPayload(commentMemo) + if err != nil { + return errors.Wrap(err, "failed to convert memo to webhook payload") + } + payload.ActivityType = "memos.memo.comment.created" + payload.URL = hook.Url + webhook.PostAsync(payload) + } + return nil +} + func (s *APIV1Service) dispatchMemoRelatedWebhook(ctx context.Context, memo *v1pb.Memo, activityType string) error { creatorID, err := ExtractUserIDFromName(memo.Creator) if err != nil {