feat: custom stickers apis
This commit is contained in:
@@ -16,7 +16,12 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
crand "crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/prabhupadasays/spsays-bff/internal/model"
|
||||
@@ -64,7 +69,10 @@ type SadhnaService struct {
|
||||
posts *repository.PostRepo
|
||||
users *repository.UserRepo
|
||||
rewards *repository.RewardRepo
|
||||
logger *zap.Logger
|
||||
// r2 stores custom gift artwork. Optional: nil disables custom gifts
|
||||
// rather than failing anything that already works.
|
||||
r2 *repository.R2
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
func NewSadhnaService(
|
||||
@@ -72,9 +80,13 @@ func NewSadhnaService(
|
||||
posts *repository.PostRepo,
|
||||
users *repository.UserRepo,
|
||||
rewards *repository.RewardRepo,
|
||||
r2 *repository.R2,
|
||||
logger *zap.Logger,
|
||||
) *SadhnaService {
|
||||
return &SadhnaService{logs: logs, posts: posts, users: users, rewards: rewards, logger: logger}
|
||||
return &SadhnaService{
|
||||
logs: logs, posts: posts, users: users, rewards: rewards,
|
||||
r2: r2, logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
const dayFmt = "2006-01-02"
|
||||
@@ -415,6 +427,57 @@ func (s *SadhnaService) GiftToEveryone(ctx context.Context, rewardKey string) (i
|
||||
return s.rewards.GrantGiftToEveryone(ctx, reward.ID)
|
||||
}
|
||||
|
||||
// customKeyPrefix namespaces admin-made rewards away from the seeded catalog,
|
||||
// so Seed can never collide with one.
|
||||
const customKeyPrefix = "custom_"
|
||||
|
||||
var nonSlug = regexp.MustCompile(`[^a-z0-9]+`)
|
||||
|
||||
// customRewardKey derives a stable, unique key from a name.
|
||||
//
|
||||
// The random suffix is what makes it unique: two gifts may reasonably share a
|
||||
// name, and a collision would overwrite the first one's artwork.
|
||||
func customRewardKey(name string) (string, error) {
|
||||
slug := strings.Trim(nonSlug.ReplaceAllString(strings.ToLower(name), "_"), "_")
|
||||
if slug == "" {
|
||||
slug = "gift"
|
||||
}
|
||||
if len(slug) > 32 {
|
||||
slug = slug[:32]
|
||||
}
|
||||
suffix := make([]byte, 4)
|
||||
if _, err := crand.Read(suffix); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return customKeyPrefix + slug + "_" + hex.EncodeToString(suffix), nil
|
||||
}
|
||||
|
||||
// CreateCustomGift adds a new sticker to the catalog. It is not granted to
|
||||
// anyone until it is sent.
|
||||
func (s *SadhnaService) CreateCustomGift(ctx context.Context, name, meaning, imageURL string) (*model.SadhnaReward, error) {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
return nil, errors.New("a gift needs a name")
|
||||
}
|
||||
if strings.TrimSpace(imageURL) == "" {
|
||||
return nil, errors.New("a gift needs an image")
|
||||
}
|
||||
key, err := customRewardKey(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.rewards.CreateCustom(ctx, key, name, strings.TrimSpace(meaning), imageURL)
|
||||
}
|
||||
|
||||
// PresignGiftImage issues an upload URL for custom sticker artwork.
|
||||
//
|
||||
// Returns the PUBLIC URL, not a key: sadhna_rewards.image_url stores an
|
||||
// absolute address, and stickers render for every participant in a chat, so
|
||||
// the artwork belongs in the public bucket alongside avatars and post images.
|
||||
func (s *SadhnaService) PresignGiftImage(ctx context.Context, contentType string) (uploadURL, publicURL string, err error) {
|
||||
return presignImage(ctx, s.r2, "reward-gifts", "custom", contentType)
|
||||
}
|
||||
|
||||
// GiftableRewards is the catalog an admin picks from.
|
||||
func (s *SadhnaService) GiftableRewards(ctx context.Context) ([]model.SadhnaReward, error) {
|
||||
return s.rewards.ListGiftable(ctx)
|
||||
|
||||
Reference in New Issue
Block a user