// codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/repo/blockedemail/blockedemail.go package blockedemail import ( "context" "strings" "go.uber.org/zap" "github.com/gocql/gocql" "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config" dom_blockedemail "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/blockedemail" "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/validation" ) type blockedEmailRepositoryImpl struct { config *config.Configuration logger *zap.Logger session *gocql.Session } func NewBlockedEmailRepository( config *config.Configuration, logger *zap.Logger, session *gocql.Session, ) dom_blockedemail.BlockedEmailRepository { logger = logger.Named("BlockedEmailRepository") return &blockedEmailRepositoryImpl{ config: config, logger: logger, session: session, } } func (r *blockedEmailRepositoryImpl) Create(ctx context.Context, blockedEmail *dom_blockedemail.BlockedEmail) error { // Normalize email to lowercase normalizedEmail := strings.ToLower(strings.TrimSpace(blockedEmail.BlockedEmail)) query := `INSERT INTO user_blocked_emails ( user_id, blocked_email, blocked_user_id, reason, created_at ) VALUES (?, ?, ?, ?, ?)` err := r.session.Query(query, blockedEmail.UserID, normalizedEmail, blockedEmail.BlockedUserID, blockedEmail.Reason, blockedEmail.CreatedAt, ).WithContext(ctx).Exec() if err != nil { r.logger.Error("Failed to create blocked email", zap.Any("error", err), zap.Any("user_id", blockedEmail.UserID), zap.String("blocked_email", validation.MaskEmail(normalizedEmail))) return err } r.logger.Debug("Blocked email created", zap.Any("user_id", blockedEmail.UserID), zap.String("blocked_email", validation.MaskEmail(normalizedEmail))) return nil } func (r *blockedEmailRepositoryImpl) Get(ctx context.Context, userID gocql.UUID, blockedEmail string) (*dom_blockedemail.BlockedEmail, error) { // Normalize email to lowercase normalizedEmail := strings.ToLower(strings.TrimSpace(blockedEmail)) query := `SELECT user_id, blocked_email, blocked_user_id, reason, created_at FROM user_blocked_emails WHERE user_id = ? AND blocked_email = ?` var result dom_blockedemail.BlockedEmail err := r.session.Query(query, userID, normalizedEmail). WithContext(ctx). Scan( &result.UserID, &result.BlockedEmail, &result.BlockedUserID, &result.Reason, &result.CreatedAt, ) if err != nil { if err == gocql.ErrNotFound { return nil, nil } r.logger.Error("Failed to get blocked email", zap.Any("error", err), zap.Any("user_id", userID), zap.String("blocked_email", validation.MaskEmail(normalizedEmail))) return nil, err } return &result, nil } func (r *blockedEmailRepositoryImpl) List(ctx context.Context, userID gocql.UUID) ([]*dom_blockedemail.BlockedEmail, error) { query := `SELECT user_id, blocked_email, blocked_user_id, reason, created_at FROM user_blocked_emails WHERE user_id = ?` iter := r.session.Query(query, userID).WithContext(ctx).Iter() var results []*dom_blockedemail.BlockedEmail var entry dom_blockedemail.BlockedEmail for iter.Scan( &entry.UserID, &entry.BlockedEmail, &entry.BlockedUserID, &entry.Reason, &entry.CreatedAt, ) { results = append(results, &dom_blockedemail.BlockedEmail{ UserID: entry.UserID, BlockedEmail: entry.BlockedEmail, BlockedUserID: entry.BlockedUserID, Reason: entry.Reason, CreatedAt: entry.CreatedAt, }) } if err := iter.Close(); err != nil { r.logger.Error("Failed to list blocked emails", zap.Any("error", err), zap.Any("user_id", userID)) return nil, err } r.logger.Debug("Listed blocked emails", zap.Any("user_id", userID), zap.Int("count", len(results))) return results, nil } func (r *blockedEmailRepositoryImpl) Delete(ctx context.Context, userID gocql.UUID, blockedEmail string) error { // Normalize email to lowercase normalizedEmail := strings.ToLower(strings.TrimSpace(blockedEmail)) query := `DELETE FROM user_blocked_emails WHERE user_id = ? AND blocked_email = ?` err := r.session.Query(query, userID, normalizedEmail).WithContext(ctx).Exec() if err != nil { r.logger.Error("Failed to delete blocked email", zap.Any("error", err), zap.Any("user_id", userID), zap.String("blocked_email", validation.MaskEmail(normalizedEmail))) return err } r.logger.Debug("Blocked email deleted", zap.Any("user_id", userID), zap.String("blocked_email", validation.MaskEmail(normalizedEmail))) return nil } func (r *blockedEmailRepositoryImpl) IsBlocked(ctx context.Context, userID gocql.UUID, email string) (bool, error) { // Normalize email to lowercase normalizedEmail := strings.ToLower(strings.TrimSpace(email)) query := `SELECT blocked_email FROM user_blocked_emails WHERE user_id = ? AND blocked_email = ?` var blockedEmail string err := r.session.Query(query, userID, normalizedEmail). WithContext(ctx). Scan(&blockedEmail) if err != nil { if err == gocql.ErrNotFound { return false, nil } r.logger.Error("Failed to check if email is blocked", zap.Any("error", err), zap.Any("user_id", userID), zap.String("email", validation.MaskEmail(normalizedEmail))) return false, err } return true, nil } func (r *blockedEmailRepositoryImpl) Count(ctx context.Context, userID gocql.UUID) (int, error) { query := `SELECT COUNT(*) FROM user_blocked_emails WHERE user_id = ?` var count int err := r.session.Query(query, userID).WithContext(ctx).Scan(&count) if err != nil { r.logger.Error("Failed to count blocked emails", zap.Any("error", err), zap.Any("user_id", userID)) return 0, err } return count, nil }