package service import ( "context" "github.com/calendarapi/internal/models" "github.com/calendarapi/internal/repository" "github.com/calendarapi/internal/utils" "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" ) type UserService struct { pool *pgxpool.Pool queries *repository.Queries audit *AuditService } func NewUserService(pool *pgxpool.Pool, queries *repository.Queries, audit *AuditService) *UserService { return &UserService{pool: pool, queries: queries, audit: audit} } func (s *UserService) GetMe(ctx context.Context, userID uuid.UUID) (*models.User, error) { u, err := s.queries.GetUserByID(ctx, utils.ToPgUUID(userID)) if err != nil { if err == pgx.ErrNoRows { return nil, models.ErrNotFound } return nil, models.ErrInternal } user := userFromIDRow(u) return &user, nil } type UserUpdateInput struct { Timezone *string WeekStartDay *int DateFormat *string TimeFormat *string DefaultEventDurationMinutes *int DefaultReminderMinutes *int ShowWeekends *bool WorkingHoursStart *string WorkingHoursEnd *string NotificationsEmail *bool } func (s *UserService) Update(ctx context.Context, userID uuid.UUID, in *UserUpdateInput) (*models.User, error) { if in == nil { in = &UserUpdateInput{} } if in.Timezone != nil { if err := utils.ValidateTimezone(*in.Timezone); err != nil { return nil, err } } u, err := s.queries.UpdateUser(ctx, repository.UpdateUserParams{ ID: utils.ToPgUUID(userID), Timezone: utils.ToPgTextPtr(in.Timezone), WeekStartDay: utils.ToPgInt2Ptr(in.WeekStartDay), DateFormat: utils.ToPgTextPtr(in.DateFormat), TimeFormat: utils.ToPgTextPtr(in.TimeFormat), DefaultEventDurationMinutes: utils.ToPgInt4Ptr(in.DefaultEventDurationMinutes), DefaultReminderMinutes: utils.ToPgInt4Ptr(in.DefaultReminderMinutes), ShowWeekends: utils.ToPgBoolPtr(in.ShowWeekends), WorkingHoursStart: utils.ToPgTextPtr(in.WorkingHoursStart), WorkingHoursEnd: utils.ToPgTextPtr(in.WorkingHoursEnd), NotificationsEmail: utils.ToPgBoolPtr(in.NotificationsEmail), }) if err != nil { if err == pgx.ErrNoRows { return nil, models.ErrNotFound } return nil, models.ErrInternal } user := userFromUpdateRow(u) return &user, nil } func (s *UserService) Delete(ctx context.Context, userID uuid.UUID) error { tx, err := s.pool.Begin(ctx) if err != nil { return models.ErrInternal } defer tx.Rollback(ctx) qtx := s.queries.WithTx(tx) pgID := utils.ToPgUUID(userID) if err := qtx.SoftDeleteContactsByOwner(ctx, pgID); err != nil { return models.ErrInternal } if err := qtx.SoftDeleteEventsByCreator(ctx, pgID); err != nil { return models.ErrInternal } if err := qtx.SoftDeleteCalendarsByOwner(ctx, pgID); err != nil { return models.ErrInternal } if err := qtx.RevokeAllUserAPIKeys(ctx, pgID); err != nil { return models.ErrInternal } if err := qtx.RevokeAllUserRefreshTokens(ctx, pgID); err != nil { return models.ErrInternal } if err := qtx.SoftDeleteUser(ctx, pgID); err != nil { return models.ErrInternal } if err := tx.Commit(ctx); err != nil { return models.ErrInternal } s.audit.Log(ctx, "user", userID, "DELETE_USER", userID) return nil }