feat: applied auth on go services

This commit is contained in:
Jean Jacques Avril 2025-01-04 14:10:20 +00:00
parent 02af66b585
commit 55edac6abe
No known key found for this signature in database
8 changed files with 182 additions and 112 deletions

View File

@ -31,10 +31,10 @@ func main() {
authRepo := repository.NewInMemoryAuthRepositoryImpl("secret") authRepo := repository.NewInMemoryAuthRepositoryImpl("secret")
// Initialize services // Initialize services
userService := services.NewUserService(userRepo) userService := services.NewUserService(authRepo, userRepo)
projectService := services.NewProjectService(projectRepo) projectService := services.NewProjectService(authRepo, projectRepo)
projectTaskService := services.NewProjectTaskService(projectTaskRepo) projectTaskService := services.NewProjectTaskService(authRepo, projectTaskRepo)
timeEntryService := services.NewTimeEntryService(timeEntryRepo) timeEntryService := services.NewTimeEntryService(authRepo, timeEntryRepo)
authService := services.NewAuthService(authRepo, userRepo) authService := services.NewAuthService(authRepo, userRepo)
// Initialize and start the server // Initialize and start the server

View File

@ -67,40 +67,34 @@ func (s *AuthService) Login(c *gin.Context) {
// Validate handles token validation. // Validate handles token validation.
func (s *AuthService) Validate(c *gin.Context) { func (s *AuthService) Validate(c *gin.Context) {
var tokenRequest dto.TokenRequestDTO F.Pipe4(
if err := c.ShouldBindJSON(&tokenRequest); err != nil { ReadSessionToken(c),
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) E.FromOption[string, error](
return F.Constant[error](app_error.NewUnauthorizedError("No session token found"))),
} E.Chain(
s.authRepository.ValidateToken(c.Request.Context()),
F.Pipe2( ),
s.authRepository.ValidateToken(c.Request.Context())(tokenRequest.Token), E.Map[error](func(userID string) gin.H {
E.Map[error](func(userID string) dto.TokenResponseDTO { return gin.H{"message": "Token validated", "user_id": userID}
return dto.TokenResponseDTO{
Token: tokenRequest.Token,
UserID: userID,
}
}), }),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
HandleSuccess[dto.TokenResponseDTO](c, http.StatusOK), HandleSuccess[gin.H](c, http.StatusOK),
), ),
) )
} }
// Logout and token revocation. // Logout and token revocation.
func (s *AuthService) Logout(c *gin.Context) { func (s *AuthService) Logout(c *gin.Context) {
var tokenRequest dto.TokenRequestDTO F.Pipe4(
if err := c.ShouldBindJSON(&tokenRequest); err != nil { ReadSessionToken(c),
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) E.FromOption[string, error](
return F.Constant[error](app_error.NewUnauthorizedError("No session token found"))),
} E.Chain(
s.authRepository.RevokeToken(c.Request.Context()),
deleteSessionTokenCookie(c) ),
F.Pipe2(
s.authRepository.RevokeToken(c.Request.Context())(tokenRequest.Token),
E.Map[error](func(userID string) gin.H { E.Map[error](func(userID string) gin.H {
deleteSessionTokenCookie(c)
return gin.H{"message": "Token revoked", "user_id": userID} return gin.H{"message": "Token revoked", "user_id": userID}
}), }),
E.Fold( E.Fold(

View File

@ -6,11 +6,6 @@ type TokenResponseDTO struct {
UserID string `json:"user_id"` UserID string `json:"user_id"`
} }
// TokenRequestDTO represents a request for operations involving tokens.
type TokenRequestDTO struct {
Token string `json:"token"`
}
// LoginRequestDTO represents the login request. // LoginRequestDTO represents the login request.
type LoginRequestDTO struct { type LoginRequestDTO struct {
Email string `json:"email"` Email string `json:"email"`

View File

@ -2,8 +2,12 @@ package services
import ( import (
"actatempus_backend/internal/domain/app_error" "actatempus_backend/internal/domain/app_error"
"actatempus_backend/internal/domain/repository"
"net/http" "net/http"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -41,3 +45,29 @@ func HandleSuccess[T any](c *gin.Context, statusCode int) func(T) any {
return nil return nil
} }
} }
func ReadSessionToken(c *gin.Context) O.Option[string] {
sessionToken, err := c.Cookie("session_token")
if err != nil || sessionToken == "" {
return O.None[string]()
}
return O.Some(sessionToken)
}
func CheckAuth(c *gin.Context, authRepository repository.AuthRepository) E.Either[error, string] {
return F.Pipe2(
ReadSessionToken(c),
E.FromOption[string, error](
F.Constant[error](app_error.NewUnauthorizedError("No session token found"))),
E.Chain(
authRepository.ValidateToken(c.Request.Context()),
),
//E.MapLeft[string](
// func(e error) error {
// HandleError(c)(e)
// return e
// },
//),
)
}

View File

@ -14,12 +14,13 @@ import (
// ProjectService handles project-related HTTP requests. // ProjectService handles project-related HTTP requests.
type ProjectService struct { type ProjectService struct {
authRepository repository.AuthRepository
repository repository.ProjectRepository repository repository.ProjectRepository
} }
// NewProjectService creates a new instance of ProjectService. // NewProjectService creates a new instance of ProjectService.
func NewProjectService(repo repository.ProjectRepository) *ProjectService { func NewProjectService(authRepo repository.AuthRepository, repo repository.ProjectRepository) *ProjectService {
return &ProjectService{repository: repo} return &ProjectService{authRepository: authRepo, repository: repo}
} }
// RegisterRoutes registers the project-related routes with Gin. // RegisterRoutes registers the project-related routes with Gin.
@ -38,9 +39,11 @@ func (s *ProjectService) CreateProject(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return return
} }
F.Pipe3( F.Pipe5(
mappers.MapCreateDTOToProject(projectCreateDTO), CheckAuth(c, s.authRepository),
s.repository.Create(c.Request.Context()), E.Map[error](F.Constant1[string](projectCreateDTO)),
E.Map[error](mappers.MapCreateDTOToProject),
E.Chain(s.repository.Create(c.Request.Context())),
E.Map[error](mappers.MapProjectToDTO), E.Map[error](mappers.MapProjectToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -51,9 +54,10 @@ func (s *ProjectService) CreateProject(c *gin.Context) {
// GetProjectByID handles fetching a project by its ID. // GetProjectByID handles fetching a project by its ID.
func (s *ProjectService) GetProjectByID(c *gin.Context) { func (s *ProjectService) GetProjectByID(c *gin.Context) {
F.Pipe3( F.Pipe4(
c.Param("id"), CheckAuth(c, s.authRepository),
s.repository.FindByID(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("id"))),
E.Chain(s.repository.FindByID(c.Request.Context())),
E.Map[error](mappers.MapProjectToDTO), E.Map[error](mappers.MapProjectToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -64,8 +68,9 @@ func (s *ProjectService) GetProjectByID(c *gin.Context) {
// GetAllProjects handles fetching all projects. // GetAllProjects handles fetching all projects.
func (s *ProjectService) GetAllProjects(c *gin.Context) { func (s *ProjectService) GetAllProjects(c *gin.Context) {
F.Pipe2( F.Pipe3(
s.repository.FindAll(c.Request.Context()), CheckAuth(c, s.authRepository),
E.Chain(F.Constant1[string](s.repository.FindAll(c.Request.Context()))),
E.Map[error](A.Map(mappers.MapProjectToDTO)), E.Map[error](A.Map(mappers.MapProjectToDTO)),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -76,7 +81,6 @@ func (s *ProjectService) GetAllProjects(c *gin.Context) {
// UpdateProject handles updating an existing project. // UpdateProject handles updating an existing project.
func (s *ProjectService) UpdateProject(c *gin.Context) { func (s *ProjectService) UpdateProject(c *gin.Context) {
id := c.Param("id")
var projectUpdateDTO dto.ProjectUpdateDTO var projectUpdateDTO dto.ProjectUpdateDTO
if err := c.ShouldBindJSON(&projectUpdateDTO); err != nil { if err := c.ShouldBindJSON(&projectUpdateDTO); err != nil {
@ -84,9 +88,13 @@ func (s *ProjectService) UpdateProject(c *gin.Context) {
return return
} }
F.Pipe3( F.Pipe5(
mappers.MapUpdateDTOToProject(projectUpdateDTO, id), CheckAuth(c, s.authRepository),
s.repository.Update(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("id"))),
E.Map[error](
F.Curry2(mappers.MapUpdateDTOToProject)(projectUpdateDTO),
),
E.Chain(s.repository.Update(c.Request.Context())),
E.Map[error](mappers.MapProjectToDTO), E.Map[error](mappers.MapProjectToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -97,9 +105,10 @@ func (s *ProjectService) UpdateProject(c *gin.Context) {
// DeleteProject handles deleting a project by its ID. // DeleteProject handles deleting a project by its ID.
func (s *ProjectService) DeleteProject(c *gin.Context) { func (s *ProjectService) DeleteProject(c *gin.Context) {
F.Pipe3( F.Pipe4(
c.Param("id"), CheckAuth(c, s.authRepository),
s.repository.Delete(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("id"))),
E.Chain(s.repository.Delete(c.Request.Context())),
E.Map[error](mappers.MapProjectToDTO), E.Map[error](mappers.MapProjectToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),

View File

@ -14,12 +14,13 @@ import (
// ProjectTaskService handles project task-related HTTP requests. // ProjectTaskService handles project task-related HTTP requests.
type ProjectTaskService struct { type ProjectTaskService struct {
authRepository repository.AuthRepository
repository repository.ProjectTaskRepository repository repository.ProjectTaskRepository
} }
// NewProjectTaskService creates a new instance of ProjectTaskService. // NewProjectTaskService creates a new instance of ProjectTaskService.
func NewProjectTaskService(repo repository.ProjectTaskRepository) *ProjectTaskService { func NewProjectTaskService(authRepo repository.AuthRepository, repo repository.ProjectTaskRepository) *ProjectTaskService {
return &ProjectTaskService{repository: repo} return &ProjectTaskService{authRepository: authRepo, repository: repo}
} }
// RegisterRoutes registers the project task-related routes with Gin. // RegisterRoutes registers the project task-related routes with Gin.
@ -39,9 +40,13 @@ func (s *ProjectTaskService) CreateTask(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return return
} }
F.Pipe3( F.Pipe5(
mappers.MapCreateDTOToProjectTask(taskCreateDTO), CheckAuth(c, s.authRepository),
E.Map[error](F.Constant1[string](taskCreateDTO)),
E.Map[error](mappers.MapCreateDTOToProjectTask),
E.Chain(
s.repository.Create(c.Request.Context()), s.repository.Create(c.Request.Context()),
),
E.Map[error](mappers.MapProjectTaskToDTO), E.Map[error](mappers.MapProjectTaskToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -52,9 +57,10 @@ func (s *ProjectTaskService) CreateTask(c *gin.Context) {
// GetTaskByID handles fetching a project task by its ID. // GetTaskByID handles fetching a project task by its ID.
func (s *ProjectTaskService) GetTaskByID(c *gin.Context) { func (s *ProjectTaskService) GetTaskByID(c *gin.Context) {
F.Pipe3( F.Pipe4(
c.Param("id"), CheckAuth(c, s.authRepository),
s.repository.FindByID(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("id"))),
E.Chain(s.repository.FindByID(c.Request.Context())),
E.Map[error](mappers.MapProjectTaskToDTO), E.Map[error](mappers.MapProjectTaskToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -65,9 +71,10 @@ func (s *ProjectTaskService) GetTaskByID(c *gin.Context) {
// GetTasksByProjectID handles fetching project tasks by project ID. // GetTasksByProjectID handles fetching project tasks by project ID.
func (s *ProjectTaskService) GetTasksByProjectID(c *gin.Context) { func (s *ProjectTaskService) GetTasksByProjectID(c *gin.Context) {
F.Pipe3( F.Pipe4(
c.Param("projectID"), CheckAuth(c, s.authRepository),
s.repository.FindByProjectID(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("projectID"))),
E.Chain(s.repository.FindByProjectID(c.Request.Context())),
E.Map[error](A.Map(mappers.MapProjectTaskToDTO)), E.Map[error](A.Map(mappers.MapProjectTaskToDTO)),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -78,8 +85,9 @@ func (s *ProjectTaskService) GetTasksByProjectID(c *gin.Context) {
// GetAllTasks handles fetching all project tasks. // GetAllTasks handles fetching all project tasks.
func (s *ProjectTaskService) GetAllTasks(c *gin.Context) { func (s *ProjectTaskService) GetAllTasks(c *gin.Context) {
F.Pipe2( F.Pipe3(
s.repository.FindAll(c.Request.Context()), CheckAuth(c, s.authRepository),
E.Chain(F.Constant1[string](s.repository.FindAll(c.Request.Context()))),
E.Map[error](A.Map(mappers.MapProjectTaskToDTO)), E.Map[error](A.Map(mappers.MapProjectTaskToDTO)),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -90,7 +98,6 @@ func (s *ProjectTaskService) GetAllTasks(c *gin.Context) {
// UpdateTask handles updating an existing project task. // UpdateTask handles updating an existing project task.
func (s *ProjectTaskService) UpdateTask(c *gin.Context) { func (s *ProjectTaskService) UpdateTask(c *gin.Context) {
id := c.Param("id")
var taskUpdateDTO dto.ProjectTaskUpdateDTO var taskUpdateDTO dto.ProjectTaskUpdateDTO
if err := c.ShouldBindJSON(&taskUpdateDTO); err != nil { if err := c.ShouldBindJSON(&taskUpdateDTO); err != nil {
@ -98,9 +105,15 @@ func (s *ProjectTaskService) UpdateTask(c *gin.Context) {
return return
} }
F.Pipe3( F.Pipe5(
mappers.MapUpdateDTOToProjectTask(taskUpdateDTO, id), CheckAuth(c, s.authRepository),
E.Map[error](F.Constant1[string](c.Param("id"))),
E.Map[error](
F.Curry2(mappers.MapUpdateDTOToProjectTask)(taskUpdateDTO),
),
E.Chain(
s.repository.Update(c.Request.Context()), s.repository.Update(c.Request.Context()),
),
E.Map[error](mappers.MapProjectTaskToDTO), E.Map[error](mappers.MapProjectTaskToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -111,9 +124,10 @@ func (s *ProjectTaskService) UpdateTask(c *gin.Context) {
// DeleteTask handles deleting a project task by its ID and returns the deleted object. // DeleteTask handles deleting a project task by its ID and returns the deleted object.
func (s *ProjectTaskService) DeleteTask(c *gin.Context) { func (s *ProjectTaskService) DeleteTask(c *gin.Context) {
F.Pipe3( F.Pipe4(
c.Param("id"), CheckAuth(c, s.authRepository),
s.repository.Delete(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("id"))),
E.Chain(s.repository.Delete(c.Request.Context())),
E.Map[error](mappers.MapProjectTaskToDTO), E.Map[error](mappers.MapProjectTaskToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),

View File

@ -14,12 +14,13 @@ import (
// TimeEntryService handles time entry-related HTTP requests. // TimeEntryService handles time entry-related HTTP requests.
type TimeEntryService struct { type TimeEntryService struct {
authRepository repository.AuthRepository
repository repository.TimeEntryRepository repository repository.TimeEntryRepository
} }
// NewTimeEntryService creates a new instance of TimeEntryService. // NewTimeEntryService creates a new instance of TimeEntryService.
func NewTimeEntryService(repo repository.TimeEntryRepository) *TimeEntryService { func NewTimeEntryService(authRepo repository.AuthRepository, repo repository.TimeEntryRepository) *TimeEntryService {
return &TimeEntryService{repository: repo} return &TimeEntryService{authRepository: authRepo, repository: repo}
} }
// RegisterRoutes registers the time entry-related routes with Gin. // RegisterRoutes registers the time entry-related routes with Gin.
@ -40,9 +41,11 @@ func (s *TimeEntryService) CreateTimeEntry(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return return
} }
F.Pipe3( F.Pipe5( // disabled for creating the initial user
mappers.MapCreateDTOToTimeEntry(timeEntryCreateDTO), CheckAuth(c, s.authRepository),
s.repository.Create(c.Request.Context()), E.Map[error](F.Constant1[string](timeEntryCreateDTO)),
E.Map[error](mappers.MapCreateDTOToTimeEntry),
E.Chain(s.repository.Create(c.Request.Context())),
E.Map[error](mappers.MapTimeEntryToDTO), E.Map[error](mappers.MapTimeEntryToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -53,9 +56,10 @@ func (s *TimeEntryService) CreateTimeEntry(c *gin.Context) {
// GetTimeEntryByID handles fetching a time entry by its ID. // GetTimeEntryByID handles fetching a time entry by its ID.
func (s *TimeEntryService) GetTimeEntryByID(c *gin.Context) { func (s *TimeEntryService) GetTimeEntryByID(c *gin.Context) {
F.Pipe3( F.Pipe4(
c.Param("id"), CheckAuth(c, s.authRepository),
s.repository.FindByID(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("id"))),
E.Chain(s.repository.FindByID(c.Request.Context())),
E.Map[error](mappers.MapTimeEntryToDTO), E.Map[error](mappers.MapTimeEntryToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -66,9 +70,10 @@ func (s *TimeEntryService) GetTimeEntryByID(c *gin.Context) {
// GetTimeEntriesByUserID handles fetching time entries by user ID. // GetTimeEntriesByUserID handles fetching time entries by user ID.
func (s *TimeEntryService) GetTimeEntriesByUserID(c *gin.Context) { func (s *TimeEntryService) GetTimeEntriesByUserID(c *gin.Context) {
F.Pipe3( F.Pipe4(
c.Param("userID"), CheckAuth(c, s.authRepository),
s.repository.FindByUserID(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("userID"))),
E.Chain(s.repository.FindByUserID(c.Request.Context())),
E.Map[error](A.Map(mappers.MapTimeEntryToDTO)), E.Map[error](A.Map(mappers.MapTimeEntryToDTO)),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -79,9 +84,10 @@ func (s *TimeEntryService) GetTimeEntriesByUserID(c *gin.Context) {
// GetTimeEntriesByProjectID handles fetching time entries by project ID. // GetTimeEntriesByProjectID handles fetching time entries by project ID.
func (s *TimeEntryService) GetTimeEntriesByProjectID(c *gin.Context) { func (s *TimeEntryService) GetTimeEntriesByProjectID(c *gin.Context) {
F.Pipe3( F.Pipe4(
c.Param("projectID"), CheckAuth(c, s.authRepository),
s.repository.FindByProjectID(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("projectID"))),
E.Chain(s.repository.FindByProjectID(c.Request.Context())),
E.Map[error](A.Map(mappers.MapTimeEntryToDTO)), E.Map[error](A.Map(mappers.MapTimeEntryToDTO)),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -92,8 +98,9 @@ func (s *TimeEntryService) GetTimeEntriesByProjectID(c *gin.Context) {
// GetAllTimeEntries handles fetching all time entries. // GetAllTimeEntries handles fetching all time entries.
func (s *TimeEntryService) GetAllTimeEntries(c *gin.Context) { func (s *TimeEntryService) GetAllTimeEntries(c *gin.Context) {
F.Pipe2( F.Pipe3(
s.repository.FindAll(c.Request.Context()), CheckAuth(c, s.authRepository),
E.Chain(F.Constant1[string](s.repository.FindAll(c.Request.Context()))),
E.Map[error](A.Map(mappers.MapTimeEntryToDTO)), E.Map[error](A.Map(mappers.MapTimeEntryToDTO)),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -104,7 +111,6 @@ func (s *TimeEntryService) GetAllTimeEntries(c *gin.Context) {
// UpdateTimeEntry handles updating an existing time entry. // UpdateTimeEntry handles updating an existing time entry.
func (s *TimeEntryService) UpdateTimeEntry(c *gin.Context) { func (s *TimeEntryService) UpdateTimeEntry(c *gin.Context) {
id := c.Param("id")
var timeEntryUpdateDTO dto.TimeEntryUpdateDTO var timeEntryUpdateDTO dto.TimeEntryUpdateDTO
if err := c.ShouldBindJSON(&timeEntryUpdateDTO); err != nil { if err := c.ShouldBindJSON(&timeEntryUpdateDTO); err != nil {
@ -112,9 +118,12 @@ func (s *TimeEntryService) UpdateTimeEntry(c *gin.Context) {
return return
} }
F.Pipe3( F.Pipe5(
mappers.MapUpdateDTOToTimeEntry(timeEntryUpdateDTO, id), CheckAuth(c, s.authRepository),
s.repository.Update(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("id"))),
E.Map[error](
F.Curry2(mappers.MapUpdateDTOToTimeEntry)(timeEntryUpdateDTO)),
E.Chain(s.repository.Update(c.Request.Context())),
E.Map[error](mappers.MapTimeEntryToDTO), E.Map[error](mappers.MapTimeEntryToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -125,9 +134,10 @@ func (s *TimeEntryService) UpdateTimeEntry(c *gin.Context) {
// DeleteTimeEntry handles deleting a time entry by its ID and returns the deleted object. // DeleteTimeEntry handles deleting a time entry by its ID and returns the deleted object.
func (s *TimeEntryService) DeleteTimeEntry(c *gin.Context) { func (s *TimeEntryService) DeleteTimeEntry(c *gin.Context) {
F.Pipe3( F.Pipe4(
c.Param("id"), CheckAuth(c, s.authRepository),
s.repository.Delete(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("id"))),
E.Chain(s.repository.Delete(c.Request.Context())),
E.Map[error](mappers.MapTimeEntryToDTO), E.Map[error](mappers.MapTimeEntryToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),

View File

@ -14,12 +14,13 @@ import (
// UserService handles user-related HTTP requests. // UserService handles user-related HTTP requests.
type UserService struct { type UserService struct {
authRepository repository.AuthRepository
repository repository.UserRepository repository repository.UserRepository
} }
// NewUserService creates a new instance of UserService. // NewUserService creates a new instance of UserService.
func NewUserService(repo repository.UserRepository) *UserService { func NewUserService(authRepo repository.AuthRepository, repo repository.UserRepository) *UserService {
return &UserService{repository: repo} return &UserService{authRepository: authRepo, repository: repo}
} }
// RegisterRoutes registers the user-related routes with Gin. // RegisterRoutes registers the user-related routes with Gin.
@ -47,13 +48,28 @@ func (s *UserService) CreateUser(c *gin.Context) {
HandleSuccess[dto.UserDTO](c, http.StatusCreated), HandleSuccess[dto.UserDTO](c, http.StatusCreated),
), ),
) )
//F.Pipe5( // disabled for creating the initial user
// CheckAuth(c, s.authRepository),
// E.Map[error](F.Constant1[string](userCreateDTO)),
// E.Map[error](mappers.MapCreateDTOToUser),
// E.Chain(
// s.repository.Create(c.Request.Context()),
// ),
// E.Map[error](mappers.MapUserToDTO),
// E.Fold(
// HandleError(c),
// HandleSuccess[dto.UserDTO](c, http.StatusCreated),
// ),
//)
} }
// GetUserByID handles fetching a user by their ID. // GetUserByID handles fetching a user by their ID.
func (s *UserService) GetUserByID(c *gin.Context) { func (s *UserService) GetUserByID(c *gin.Context) {
F.Pipe3( F.Pipe4(
c.Param("id"), CheckAuth(c, s.authRepository),
s.repository.FindByID(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("id"))),
E.Chain(s.repository.FindByID(c.Request.Context())),
E.Map[error](mappers.MapUserToDTO), E.Map[error](mappers.MapUserToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -64,8 +80,9 @@ func (s *UserService) GetUserByID(c *gin.Context) {
// GetAllUsers handles fetching all users. // GetAllUsers handles fetching all users.
func (s *UserService) GetAllUsers(c *gin.Context) { func (s *UserService) GetAllUsers(c *gin.Context) {
F.Pipe2( F.Pipe3(
s.repository.FindAll(c.Request.Context()), CheckAuth(c, s.authRepository),
E.Chain(F.Constant1[string](s.repository.FindAll(c.Request.Context()))),
E.Map[error](A.Map(mappers.MapUserToDTO)), E.Map[error](A.Map(mappers.MapUserToDTO)),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -76,17 +93,17 @@ func (s *UserService) GetAllUsers(c *gin.Context) {
// UpdateUser handles updating an existing user. // UpdateUser handles updating an existing user.
func (s *UserService) UpdateUser(c *gin.Context) { func (s *UserService) UpdateUser(c *gin.Context) {
id := c.Param("id")
var userUpdateDTO dto.UserUpdateDTO var userUpdateDTO dto.UserUpdateDTO
if err := c.ShouldBindJSON(&userUpdateDTO); err != nil { if err := c.ShouldBindJSON(&userUpdateDTO); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return return
} }
F.Pipe3( F.Pipe5(
mappers.MapUpdateDTOToUser(userUpdateDTO, id), CheckAuth(c, s.authRepository),
s.repository.Update(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("id"))),
E.Map[error](F.Curry2(mappers.MapUpdateDTOToUser)(userUpdateDTO)),
E.Chain(s.repository.Update(c.Request.Context())),
E.Map[error](mappers.MapUserToDTO), E.Map[error](mappers.MapUserToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),
@ -97,9 +114,10 @@ func (s *UserService) UpdateUser(c *gin.Context) {
// DeleteUser handles deleting a user by their ID. // DeleteUser handles deleting a user by their ID.
func (s *UserService) DeleteUser(c *gin.Context) { func (s *UserService) DeleteUser(c *gin.Context) {
F.Pipe3( F.Pipe4(
c.Param("id"), CheckAuth(c, s.authRepository),
s.repository.Delete(c.Request.Context()), E.Map[error](F.Constant1[string](c.Param("id"))),
E.Chain(s.repository.Delete(c.Request.Context())),
E.Map[error](mappers.MapUserToDTO), E.Map[error](mappers.MapUserToDTO),
E.Fold( E.Fold(
HandleError(c), HandleError(c),