user devices

This commit is contained in:
Efril
2026-05-10 10:42:09 +07:00
parent 23b6293502
commit bbd6666299
18 changed files with 1162 additions and 32 deletions
+34 -11
View File
@@ -8,7 +8,9 @@ import (
"apskel-pos-be/config"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/entities"
"apskel-pos-be/internal/models"
"apskel-pos-be/internal/processor"
"apskel-pos-be/internal/transformer"
"github.com/golang-jwt/jwt/v5"
@@ -24,11 +26,12 @@ type AuthService interface {
}
type AuthServiceImpl struct {
userProcessor UserProcessor
jwtSecret string
refreshSecret string
tokenTTL time.Duration
refreshTokenTTL time.Duration
userProcessor UserProcessor
userDeviceProcessor processor.UserDeviceProcessor
jwtSecret string
refreshSecret string
tokenTTL time.Duration
refreshTokenTTL time.Duration
}
type Claims struct {
@@ -39,13 +42,14 @@ type Claims struct {
jwt.RegisteredClaims
}
func NewAuthService(userProcessor UserProcessor, authConfig *config.AuthConfig) AuthService {
func NewAuthService(userProcessor UserProcessor, userDeviceProcessor processor.UserDeviceProcessor, authConfig *config.AuthConfig) AuthService {
return &AuthServiceImpl{
userProcessor: userProcessor,
jwtSecret: authConfig.AccessTokenSecret(),
refreshSecret: authConfig.RefreshTokenSecret(),
tokenTTL: authConfig.AccessTokenTTL(),
refreshTokenTTL: authConfig.RefreshTokenTTL(),
userProcessor: userProcessor,
userDeviceProcessor: userDeviceProcessor,
jwtSecret: authConfig.AccessTokenSecret(),
refreshSecret: authConfig.RefreshTokenSecret(),
tokenTTL: authConfig.AccessTokenTTL(),
refreshTokenTTL: authConfig.RefreshTokenTTL(),
}
}
@@ -81,6 +85,25 @@ func (s *AuthServiceImpl) Login(ctx context.Context, req *contract.LoginRequest)
return nil, fmt.Errorf("failed to generate refresh token: %w", err)
}
// Register or update device info if provided
if req.DeviceID != "" && s.userDeviceProcessor != nil {
deviceReq := &models.RegisterUserDeviceRequest{
UserID: userResponse.ID,
DeviceID: req.DeviceID,
DeviceName: req.DeviceName,
DeviceType: entities.DeviceType(req.DeviceType),
Platform: entities.DevicePlatform(req.Platform),
FCMToken: req.FCMToken,
AppVersion: req.AppVersion,
OsVersion: req.OsVersion,
}
// Non-blocking: log error but don't fail login
if _, err := s.userDeviceProcessor.RegisterDevice(ctx, deviceReq); err != nil {
// Log but don't fail the login
_ = err
}
}
return &contract.LoginResponse{
Token: token,
RefreshToken: refreshToken,
+122
View File
@@ -0,0 +1,122 @@
package service
import (
"context"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/processor"
"apskel-pos-be/internal/transformer"
"github.com/google/uuid"
)
type UserDeviceService interface {
RegisterDevice(ctx context.Context, userID uuid.UUID, req *contract.RegisterUserDeviceRequest) *contract.Response
UpdateDevice(ctx context.Context, id uuid.UUID, req *contract.UpdateUserDeviceRequest) *contract.Response
DeleteDevice(ctx context.Context, id uuid.UUID) *contract.Response
GetDeviceByID(ctx context.Context, id uuid.UUID) *contract.Response
GetDevicesByUserID(ctx context.Context, userID uuid.UUID) *contract.Response
ListDevices(ctx context.Context, req *contract.ListUserDevicesRequest) *contract.Response
}
type UserDeviceServiceImpl struct {
userDeviceProcessor processor.UserDeviceProcessor
}
func NewUserDeviceService(userDeviceProcessor processor.UserDeviceProcessor) *UserDeviceServiceImpl {
return &UserDeviceServiceImpl{
userDeviceProcessor: userDeviceProcessor,
}
}
func (s *UserDeviceServiceImpl) RegisterDevice(ctx context.Context, userID uuid.UUID, req *contract.RegisterUserDeviceRequest) *contract.Response {
modelReq := transformer.RegisterUserDeviceRequestToModel(req)
modelReq.UserID = userID
deviceResponse, err := s.userDeviceProcessor.RegisterDevice(ctx, modelReq)
if err != nil {
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.UserDeviceServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
contractResponse := transformer.UserDeviceModelResponseToResponse(deviceResponse)
return contract.BuildSuccessResponse(contractResponse)
}
func (s *UserDeviceServiceImpl) UpdateDevice(ctx context.Context, id uuid.UUID, req *contract.UpdateUserDeviceRequest) *contract.Response {
modelReq := transformer.UpdateUserDeviceRequestToModel(req)
deviceResponse, err := s.userDeviceProcessor.UpdateDevice(ctx, id, modelReq)
if err != nil {
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.UserDeviceServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
contractResponse := transformer.UserDeviceModelResponseToResponse(deviceResponse)
return contract.BuildSuccessResponse(contractResponse)
}
func (s *UserDeviceServiceImpl) DeleteDevice(ctx context.Context, id uuid.UUID) *contract.Response {
err := s.userDeviceProcessor.DeleteDevice(ctx, id)
if err != nil {
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.UserDeviceServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
return contract.BuildSuccessResponse(map[string]interface{}{
"message": "Device deleted successfully",
})
}
func (s *UserDeviceServiceImpl) GetDeviceByID(ctx context.Context, id uuid.UUID) *contract.Response {
deviceResponse, err := s.userDeviceProcessor.GetDeviceByID(ctx, id)
if err != nil {
errorResp := contract.NewResponseError(constants.NotFoundErrorCode, constants.UserDeviceServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
contractResponse := transformer.UserDeviceModelResponseToResponse(deviceResponse)
return contract.BuildSuccessResponse(contractResponse)
}
func (s *UserDeviceServiceImpl) GetDevicesByUserID(ctx context.Context, userID uuid.UUID) *contract.Response {
deviceResponses, err := s.userDeviceProcessor.GetDevicesByUserID(ctx, userID)
if err != nil {
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.UserDeviceServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
contractResponses := transformer.UserDeviceModelResponsesToResponses(deviceResponses)
return contract.BuildSuccessResponse(contractResponses)
}
func (s *UserDeviceServiceImpl) ListDevices(ctx context.Context, req *contract.ListUserDevicesRequest) *contract.Response {
modelReq := transformer.ListUserDevicesRequestToModel(req)
filters := make(map[string]interface{})
if modelReq.UserID != "" {
filters["user_id"] = modelReq.UserID
}
if modelReq.Platform != "" {
filters["platform"] = modelReq.Platform
}
devices, totalPages, err := s.userDeviceProcessor.ListDevices(ctx, filters, modelReq.Page, modelReq.Limit)
if err != nil {
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.UserDeviceServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
contractResponses := transformer.UserDeviceModelResponsesToResponses(devices)
response := contract.ListUserDevicesResponse{
Devices: contractResponses,
TotalCount: len(contractResponses),
Page: modelReq.Page,
Limit: modelReq.Limit,
TotalPages: totalPages,
}
return contract.BuildSuccessResponse(response)
}