refactor: [shitty claude AI first try] restructure server and user services, add new test cases, and improve error handling

This commit is contained in:
2025-08-10 21:40:15 +03:00
parent 588576b82f
commit f503e45be1
23 changed files with 2568 additions and 134 deletions

View File

@ -2,10 +2,12 @@ package service
import (
"context"
"net/http"
"strconv"
"git.logidex.ru/fakz9/logidex-id/internal/api/auth/domain"
userDomain "git.logidex.ru/fakz9/logidex-id/internal/api/user/domain"
userService "git.logidex.ru/fakz9/logidex-id/internal/api/user/service"
"git.logidex.ru/fakz9/logidex-id/internal/phoneutil"
hydraApi "github.com/ory/hydra-client-go"
)
@ -18,24 +20,75 @@ type AuthService interface {
type authService struct {
repo domain.AuthRepository
userRepo userDomain.UserRepository
userService userService.UserService
hydraClient *hydraApi.APIClient
}
func (a authService) AcceptConsent(ctx context.Context, phoneNumber string, challenge string) (string, error) {
phoneNumber, err := phoneutil.ParseAndFormatPhoneNumber(phoneNumber)
func (a authService) validateAndFormatPhoneNumber(phoneNumber string) (string, error) {
formattedPhone, err := phoneutil.ParseAndFormatPhoneNumber(phoneNumber)
if err != nil {
return "", domain.ErrInvalidPhoneNumber{
PhoneNumber: phoneNumber,
Err: err,
}
}
user, err := a.userRepo.GetUserByPhoneNumber(ctx, phoneNumber)
return formattedPhone, nil
}
func (a authService) getUserByPhoneNumber(ctx context.Context, phoneNumber string) (*userDomain.User, error) {
user, err := a.userService.GetUserByPhoneNumber(ctx, phoneNumber)
if err != nil {
return nil, err
}
if user == nil {
return nil, domain.ErrUserNotFound{PhoneNumber: phoneNumber}
}
return user, nil
}
func (a authService) getOrCreateUser(ctx context.Context, phoneNumber string) (*userDomain.User, error) {
user, err := a.userService.GetUserByPhoneNumber(ctx, phoneNumber)
if err != nil {
return nil, err
}
if user == nil {
user, err = a.userService.CreateUser(ctx, phoneNumber)
if err != nil {
return nil, err
}
}
return user, nil
}
func (a authService) validateHydraResponse(rawRsp *http.Response, userUuid string) error {
if rawRsp.StatusCode != 200 {
return domain.ErrInvalidHydraAccept{
Message: "Hydra response status: " + strconv.Itoa(rawRsp.StatusCode),
Uuid: userUuid,
}
}
return nil
}
func (a authService) extractRedirectUrl(rsp interface{ GetRedirectToOk() (*string, bool) }, userUuid string) (string, error) {
redirectTo, ok := rsp.GetRedirectToOk()
if !ok || redirectTo == nil {
return "", domain.ErrInvalidHydraAccept{
Message: "Hydra redirectTo is nil",
Uuid: userUuid,
}
}
return *redirectTo, nil
}
func (a authService) AcceptConsent(ctx context.Context, phoneNumber string, challenge string) (string, error) {
phoneNumber, err := a.validateAndFormatPhoneNumber(phoneNumber)
if err != nil {
return "", err
}
if user == nil {
return "", domain.ErrUserNotFound{PhoneNumber: phoneNumber}
user, err := a.getUserByPhoneNumber(ctx, phoneNumber)
if err != nil {
return "", err
}
request := hydraApi.AcceptConsentRequest{}
request.SetGrantScope([]string{"openid"})
@ -50,86 +103,65 @@ func (a authService) AcceptConsent(ctx context.Context, phoneNumber string, chal
if err != nil {
return "", err
}
if rawRsp.StatusCode != 200 {
return "", domain.ErrInvalidHydraAccept{
Message: "Hydra response is nil: " + strconv.Itoa(rawRsp.StatusCode),
Uuid: "",
}
if err = a.validateHydraResponse(rawRsp, user.Uuid); err != nil {
return "", err
}
redirectTo, ok := rsp.GetRedirectToOk()
if !ok || redirectTo == nil {
return "", domain.ErrInvalidHydraAccept{
Message: "Hydra redirectTo is nil",
Uuid: "",
}
}
// TODO: Verify user in the database
_, err = a.userRepo.VerifyUser(ctx, user.Uuid.String())
redirectUrl, err := a.extractRedirectUrl(rsp, user.Uuid)
if err != nil {
return "", err
}
return *redirectTo, nil
// TODO: Verify user in the database
_, err = a.userService.VerifyUser(ctx, user.Uuid)
if err != nil {
return "", err
}
return redirectUrl, nil
}
func (a authService) OtpRequest(ctx context.Context, phoneNumber string) error {
phoneNumber, err := phoneutil.ParseAndFormatPhoneNumber(phoneNumber)
phoneNumber, err := a.validateAndFormatPhoneNumber(phoneNumber)
if err != nil {
return domain.ErrInvalidPhoneNumber{
PhoneNumber: phoneNumber,
Err: err,
}
return err
}
user, err := a.userRepo.GetUserByPhoneNumber(ctx, phoneNumber)
//if err != nil {
// return err
//}
if user == nil {
// Create a new user if it does not exist
user, err = a.userRepo.CreateUser(ctx, phoneNumber)
if err != nil {
return err
}
user, err := a.getOrCreateUser(ctx, phoneNumber)
if err != nil {
return err
}
code := "123456"
err = a.repo.SaveOtpRequest(ctx, user.Uuid.String(), code)
err = a.repo.SaveOtpRequest(ctx, user.Uuid, code)
if err != nil {
return err
}
// TODO implement sending OTP code via SMS
return nil
}
func (a authService) OtpVerify(ctx context.Context, phoneNumber string, code string, loggingChallenge string) (string, error) {
phoneNumber, err := phoneutil.ParseAndFormatPhoneNumber(phoneNumber)
if err != nil {
return "", domain.ErrInvalidPhoneNumber{
PhoneNumber: phoneNumber,
Err: err,
}
}
user, err := a.userRepo.GetUserByPhoneNumber(ctx, phoneNumber)
phoneNumber, err := a.validateAndFormatPhoneNumber(phoneNumber)
if err != nil {
return "", err
}
if user == nil {
return "", domain.ErrUserNotFound{PhoneNumber: phoneNumber}
user, err := a.getUserByPhoneNumber(ctx, phoneNumber)
if err != nil {
return "", err
}
otp, err := a.repo.GetOtpRequest(ctx, user.Uuid.String())
otp, err := a.repo.GetOtpRequest(ctx, user.Uuid)
if err != nil {
return "", err
}
if otp == nil {
return "", domain.ErrOtpNotFound{Uuid: user.Uuid.String()}
return "", domain.ErrOtpNotFound{Uuid: user.Uuid}
}
if *otp != code {
return "", domain.ErrOtpInvalid{Uuid: user.Uuid.String(), Code: code}
return "", domain.ErrOtpInvalid{Uuid: user.Uuid, Code: code}
}
request := hydraApi.AcceptLoginRequest{}
request.SetSubject(user.Uuid.String())
request.SetSubject(user.Uuid)
request.SetRemember(true)
request.SetRememberFor(3600) // 1 hour
@ -141,27 +173,22 @@ func (a authService) OtpVerify(ctx context.Context, phoneNumber string, code str
if err != nil {
return "", err
}
if rawRsp.StatusCode != 200 {
return "", domain.ErrInvalidHydraAccept{
Message: "Hydra response is nil: " + strconv.Itoa(rawRsp.StatusCode),
Uuid: user.Uuid.String(),
}
if err = a.validateHydraResponse(rawRsp, user.Uuid); err != nil {
return "", err
}
redirectTo, ok := rsp.GetRedirectToOk()
if !ok || redirectTo == nil {
return "", domain.ErrInvalidHydraAccept{
Message: "Hydra redirectTo is nil",
Uuid: user.Uuid.String(),
}
redirectUrl, err := a.extractRedirectUrl(rsp, user.Uuid)
if err != nil {
return "", err
}
return *redirectTo, nil
return redirectUrl, nil
}
func NewAuthService(repo domain.AuthRepository, userRepo userDomain.UserRepository, hydraClient *hydraApi.APIClient) AuthService {
func NewAuthService(repo domain.AuthRepository, userService userService.UserService, hydraClient *hydraApi.APIClient) AuthService {
return &authService{
repo: repo,
userRepo: userRepo,
userService: userService,
hydraClient: hydraClient,
}
}