package cache import ( "backend/internal/domain" "backend/pkg/cache" "context" "encoding/json" "fmt" "time" "github.com/redis/go-redis/v9" ) type OTPRepository struct { redis *cache.Redis } func NewOTPRepository(redis *cache.Redis) domain.OTPRepo { return &OTPRepository{ redis: redis, } } func (r *OTPRepository) Create(ctx context.Context, phone string, otp *domain.OTP) error { key := r.getOTPKey(phone) otpData, err := json.Marshal(otp) if err != nil { return fmt.Errorf("failed to marshal otp: %w", err) } ttl := time.Until(otp.ExpiresAt) if ttl <= 0 { return fmt.Errorf("OTP expired already") } if err := r.redis.Client().Set(ctx, key, otpData, ttl).Err(); err != nil { return fmt.Errorf("failed to store otp in redis: %w", err) } return nil } func (r *OTPRepository) Delete(ctx context.Context, phone string) error { key := r.getOTPKey(phone) if err := r.redis.Client().Del(ctx, key).Err(); err != nil { return fmt.Errorf("failed to del otp from redis") } return nil } func (r *OTPRepository) Get(ctx context.Context, phone string) (*domain.OTP, error) { key := r.getOTPKey(phone) result, err := r.redis.Client().Get(ctx, key).Result() if err != nil { if err == redis.Nil { return nil, fmt.Errorf("otp code not found") } return nil, err } var otp domain.OTP if err := json.Unmarshal([]byte(result), &otp); err != nil { return nil, err } if otp.IsExpired() { r.Delete(ctx, phone) return nil, fmt.Errorf("otp is expired") } return &otp, nil } func (r *OTPRepository) getOTPKey(phone string) string { return fmt.Sprintf("challenge:%s", phone) }