feat: invite management API: DELETE /v1/user/invite/:id (204, cancels a pending invite) and POST /v1/user/invite/:id/renew (200, new code, expires_at = now+3d, created_at = now, resends the invitation email, old link dead)

This commit is contained in:
fsylvain committed 2026-09-30 01:36:43 +02:00
1 parent 461e93e3b5
commit 153fd8719a
18 files changed
+1147 -44

No files matched your search

@@ -0,0 +1,59 @@
package useCases
import (
"RenewCMS/internal/domain/hash"
"RenewCMS/internal/domain/invite"
"RenewCMS/internal/domain/mail"
"RenewCMS/internal/domain/user"
"errors"
"time"
)
type RenewInviteUseCase struct {
userRepository user.Repository
inviteRepository invite.Repository
hasher hash.Hasher
mailer inviteMailer
}
type RenewInviteCommand struct {
ID uint32
RenewedBy uint32
}
func NewRenewInviteUseCase(userRepository user.Repository, inviteRepository invite.Repository, hasher hash.Hasher, mailRepository mail.Repository, publicURL string) *RenewInviteUseCase {
return &RenewInviteUseCase{userRepository, inviteRepository, hasher, inviteMailer{mailRepository, publicURL}}
}
func (u *RenewInviteUseCase) RenewInvite(command RenewInviteCommand) (invite.Invite, error) {
now := time.Now()
renewer, err := u.userRepository.Get(command.RenewedBy)
if err != nil {
return invite.Invite{}, err
}
previous, err := findManageableInvite(u.inviteRepository, command.ID)
if err != nil {
return invite.Invite{}, err
}
rawCode, hashedCode, err := newInviteCode(u.hasher)
if err != nil {
return invite.Invite{}, err
}
renewed, err := u.inviteRepository.Renew(previous.ID, hashedCode, now.Add(invite.Lifetime), now)
if err != nil {
return invite.Invite{}, err
}
if sendErr := u.mailer.send(renewed.Email, rawCode, renewer); sendErr != nil {
if _, restoreErr := u.inviteRepository.Renew(previous.ID, previous.HashedCode, previous.ExpiresAt, previous.CreatedAt); restoreErr != nil {
return invite.Invite{}, errors.Join(sendErr, restoreErr)
}
return invite.Invite{}, sendErr
}
return renewed, nil
}