package repository import ( "context" "database/sql" "errors" dbgen "Yimaru-Backend/gen/db" "Yimaru-Backend/internal/domain" "Yimaru-Backend/internal/ports" "Yimaru-Backend/internal/services/authentication" "github.com/jackc/pgx/v5/pgtype" ) // NewTokenStore returns a TokenStore implementation func NewTokenStore(s *Store) ports.TokenStore { return s } // CreateRefreshToken inserts a new refresh token into the database func (s *Store) CreateRefreshToken(ctx context.Context, rt domain.RefreshToken) error { return s.queries.CreateRefreshToken(ctx, dbgen.CreateRefreshTokenParams{ UserID: rt.UserID, Token: rt.Token, ExpiresAt: pgtype.Timestamptz{Time: rt.ExpiresAt}, CreatedAt: pgtype.Timestamptz{Time: rt.CreatedAt}, Revoked: rt.Revoked, }) } // GetRefreshToken retrieves a refresh token by its token string func (s *Store) GetRefreshToken(ctx context.Context, token string) (domain.RefreshToken, error) { rf, err := s.queries.GetRefreshToken(ctx, token) if err != nil { if errors.Is(err, sql.ErrNoRows) { return domain.RefreshToken{}, authentication.ErrRefreshTokenNotFound } return domain.RefreshToken{}, err } return domain.RefreshToken{ Token: rf.Token, UserID: rf.UserID, CreatedAt: rf.CreatedAt.Time, ExpiresAt: rf.ExpiresAt.Time, Revoked: rf.Revoked, }, nil } // GetRefreshTokenByUserID retrieves a refresh token for a specific user func (s *Store) GetRefreshTokenByUserID(ctx context.Context, id int64) (domain.RefreshToken, error) { rf, err := s.queries.GetRefreshTokenByUserID(ctx, id) if err != nil { if errors.Is(err, sql.ErrNoRows) { return domain.RefreshToken{}, authentication.ErrRefreshTokenNotFound } return domain.RefreshToken{}, err } return domain.RefreshToken{ Token: rf.Token, UserID: rf.UserID, CreatedAt: rf.CreatedAt.Time, ExpiresAt: rf.ExpiresAt.Time, Revoked: rf.Revoked, }, nil } // RevokeRefreshToken marks a refresh token as revoked func (s *Store) RevokeRefreshToken(ctx context.Context, token string) error { return s.queries.RevokeRefreshToken(ctx, token) } // GetUserByEmailOrPhone retrieves a user by email or phone number and optional organization ID func (s *Store) GetUserByEmailOrPhone(ctx context.Context, email, phone string, organizationID *int64) (domain.User, error) { // prepare organizationID param for the query // var orgParam pgtype.Int8 // if organizationID != nil { // orgParam = pgtype.Int8{Int64: *organizationID} // } else { // orgParam = pgtype.Int8{Status: pgtype.Null} // } u, err := s.queries.GetUserByEmailPhone(ctx, dbgen.GetUserByEmailPhoneParams{ Email: pgtype.Text{String: email, Valid: email != ""}, PhoneNumber: pgtype.Text{String: phone, Valid: phone != ""}, OrganizationID: pgtype.Int8{Int64: *organizationID}, }) if err != nil { if errors.Is(err, sql.ErrNoRows) { return domain.User{}, authentication.ErrUserNotFound } return domain.User{}, err } return domain.User{ ID: u.ID, FirstName: u.FirstName, LastName: u.LastName, Email: u.Email.String, PhoneNumber: u.PhoneNumber.String, Role: domain.Role(u.Role), Password: u.Password, EmailVerified: u.EmailVerified, PhoneVerified: u.PhoneVerified, Suspended: u.Suspended, SuspendedAt: u.SuspendedAt.Time, OrganizationID: domain.ValidInt64{Value: u.OrganizationID.Int64, Valid: u.OrganizationID.Valid}, CreatedAt: u.CreatedAt.Time, UpdatedAt: u.UpdatedAt.Time, }, nil }