Yimaru-BackEnd/internal/repository/auth.go

114 lines
3.4 KiB
Go

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
}