refactor: remove repeating code etc
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"context"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/oklog/ulid/v2"
|
||||
"github.com/timetracker/backend/internal/api/dto"
|
||||
"github.com/timetracker/backend/internal/api/responses"
|
||||
"github.com/timetracker/backend/internal/api/utils"
|
||||
dto "github.com/timetracker/backend/internal/dtos"
|
||||
"github.com/timetracker/backend/internal/models"
|
||||
"github.com/timetracker/backend/internal/types"
|
||||
)
|
||||
@@ -69,27 +70,7 @@ func (h *ActivityHandler) GetActivityByID(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /activities [post]
|
||||
func (h *ActivityHandler) CreateActivity(c *gin.Context) {
|
||||
// Parse request body
|
||||
var activityCreateDTO dto.ActivityCreateDto
|
||||
if err := utils.BindJSON(c, &activityCreateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
activityCreate := convertCreateActivityDTOToModel(activityCreateDTO)
|
||||
|
||||
// Create activity in the database
|
||||
activity, err := models.CreateActivity(c.Request.Context(), activityCreate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error creating activity: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
activityDTO := convertActivityToDTO(activity)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusCreated, activityDTO)
|
||||
utils.HandleCreate(c, createActivityWrapper, convertActivityToDTO, "activity")
|
||||
}
|
||||
|
||||
// UpdateActivity handles PUT /activities/:id
|
||||
@@ -109,42 +90,7 @@ func (h *ActivityHandler) CreateActivity(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /activities/{id} [put]
|
||||
func (h *ActivityHandler) UpdateActivity(c *gin.Context) {
|
||||
// Parse ID from URL
|
||||
id, err := utils.ParseID(c, "id")
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid activity ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var activityUpdateDTO dto.ActivityUpdateDto
|
||||
if err := utils.BindJSON(c, &activityUpdateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Set ID from URL
|
||||
activityUpdateDTO.ID = id.String()
|
||||
|
||||
// Convert DTO to model
|
||||
activityUpdate := convertUpdateActivityDTOToModel(activityUpdateDTO)
|
||||
|
||||
// Update activity in the database
|
||||
activity, err := models.UpdateActivity(c.Request.Context(), activityUpdate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error updating activity: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if activity == nil {
|
||||
utils.NotFoundResponse(c, "Activity not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
activityDTO := convertActivityToDTO(activity)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, activityDTO)
|
||||
utils.HandleUpdate(c, models.UpdateActivity, convertActivityToDTO, prepareActivityUpdate, "activity")
|
||||
}
|
||||
|
||||
// DeleteActivity handles DELETE /activities/:id
|
||||
@@ -200,3 +146,35 @@ func convertUpdateActivityDTOToModel(dto dto.ActivityUpdateDto) models.ActivityU
|
||||
|
||||
return update
|
||||
}
|
||||
|
||||
// prepareActivityUpdate prepares the activity update object by parsing the ID, binding the JSON, and converting the DTO to a model
|
||||
func prepareActivityUpdate(c *gin.Context) (models.ActivityUpdate, error) {
|
||||
// Parse ID from URL
|
||||
id, err := utils.ParseID(c, "id")
|
||||
if err != nil {
|
||||
responses.BadRequestResponse(c, "Invalid activity ID format")
|
||||
return models.ActivityUpdate{}, err
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var activityUpdateDTO dto.ActivityUpdateDto
|
||||
if err := utils.BindJSON(c, &activityUpdateDTO); err != nil {
|
||||
responses.BadRequestResponse(c, err.Error())
|
||||
return models.ActivityUpdate{}, err
|
||||
}
|
||||
|
||||
// Set ID from URL
|
||||
activityUpdateDTO.ID = id.String()
|
||||
|
||||
// Convert DTO to model
|
||||
return convertUpdateActivityDTOToModel(activityUpdateDTO), nil
|
||||
}
|
||||
|
||||
// createActivityWrapper is a wrapper function for models.CreateActivity that takes a DTO as input
|
||||
func createActivityWrapper(ctx context.Context, createDTO dto.ActivityCreateDto) (*models.Activity, error) {
|
||||
// Convert DTO to model
|
||||
activityCreate := convertCreateActivityDTOToModel(createDTO)
|
||||
|
||||
// Call the original function
|
||||
return models.CreateActivity(ctx, activityCreate)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"context"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/timetracker/backend/internal/api/dto"
|
||||
"github.com/timetracker/backend/internal/api/responses"
|
||||
"github.com/timetracker/backend/internal/api/utils"
|
||||
dto "github.com/timetracker/backend/internal/dtos"
|
||||
"github.com/timetracker/backend/internal/models"
|
||||
"github.com/timetracker/backend/internal/types"
|
||||
)
|
||||
@@ -68,27 +69,7 @@ func (h *CompanyHandler) GetCompanyByID(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /companies [post]
|
||||
func (h *CompanyHandler) CreateCompany(c *gin.Context) {
|
||||
// Parse request body
|
||||
var companyCreateDTO dto.CompanyCreateDto
|
||||
if err := utils.BindJSON(c, &companyCreateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
companyCreate := convertCreateCompanyDTOToModel(companyCreateDTO)
|
||||
|
||||
// Create company in the database
|
||||
company, err := models.CreateCompany(c.Request.Context(), companyCreate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error creating company: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
companyDTO := convertCompanyToDTO(company)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusCreated, companyDTO)
|
||||
utils.HandleCreate(c, createCompanyWrapper, convertCompanyToDTO, "company")
|
||||
}
|
||||
|
||||
// UpdateCompany handles PUT /companies/:id
|
||||
@@ -108,39 +89,7 @@ func (h *CompanyHandler) CreateCompany(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /companies/{id} [put]
|
||||
func (h *CompanyHandler) UpdateCompany(c *gin.Context) {
|
||||
// Parse ID from URL
|
||||
id, err := utils.ParseID(c, "id")
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid company ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var companyUpdateDTO dto.CompanyUpdateDto
|
||||
if err := utils.BindJSON(c, &companyUpdateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
companyUpdate := convertUpdateCompanyDTOToModel(companyUpdateDTO, id)
|
||||
|
||||
// Update company in the database
|
||||
company, err := models.UpdateCompany(c.Request.Context(), companyUpdate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error updating company: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if company == nil {
|
||||
utils.NotFoundResponse(c, "Company not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
companyDTO := convertCompanyToDTO(company)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, companyDTO)
|
||||
utils.HandleUpdate(c, models.UpdateCompany, convertCompanyToDTO, prepareCompanyUpdate, "company")
|
||||
}
|
||||
|
||||
// DeleteCompany handles DELETE /companies/:id
|
||||
@@ -189,3 +138,32 @@ func convertUpdateCompanyDTOToModel(dto dto.CompanyUpdateDto, id types.ULID) mod
|
||||
|
||||
return update
|
||||
}
|
||||
|
||||
// prepareCompanyUpdate prepares the company update object by parsing the ID, binding the JSON, and converting the DTO to a model
|
||||
func prepareCompanyUpdate(c *gin.Context) (models.CompanyUpdate, error) {
|
||||
// Parse ID from URL
|
||||
id, err := utils.ParseID(c, "id")
|
||||
if err != nil {
|
||||
responses.BadRequestResponse(c, "Invalid company ID format")
|
||||
return models.CompanyUpdate{}, err
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var companyUpdateDTO dto.CompanyUpdateDto
|
||||
if err := utils.BindJSON(c, &companyUpdateDTO); err != nil {
|
||||
responses.BadRequestResponse(c, err.Error())
|
||||
return models.CompanyUpdate{}, err
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
return convertUpdateCompanyDTOToModel(companyUpdateDTO, id), nil
|
||||
}
|
||||
|
||||
// createCompanyWrapper is a wrapper function for models.CreateCompany that takes a DTO as input
|
||||
func createCompanyWrapper(ctx context.Context, createDTO dto.CompanyCreateDto) (*models.Company, error) {
|
||||
// Convert DTO to model
|
||||
companyCreate := convertCreateCompanyDTOToModel(createDTO)
|
||||
|
||||
// Call the original function
|
||||
return models.CreateCompany(ctx, companyCreate)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/timetracker/backend/internal/api/dto"
|
||||
"github.com/timetracker/backend/internal/api/middleware"
|
||||
"github.com/timetracker/backend/internal/api/responses"
|
||||
"github.com/timetracker/backend/internal/api/utils"
|
||||
dto "github.com/timetracker/backend/internal/dtos"
|
||||
"github.com/timetracker/backend/internal/models"
|
||||
"github.com/timetracker/backend/internal/types"
|
||||
)
|
||||
@@ -74,21 +76,26 @@ func (h *CustomerHandler) GetCustomersByCompanyID(c *gin.Context) {
|
||||
companyIDStr := c.Param("companyId")
|
||||
companyID, err := parseCompanyID(companyIDStr)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid company ID format")
|
||||
responses.BadRequestResponse(c, "Invalid company ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Get customers from the database
|
||||
customers, err := models.GetCustomersByCompanyID(c.Request.Context(), companyID)
|
||||
// Create a wrapper function that takes a ULID but calls the original function with an int
|
||||
getByCompanyIDFn := func(ctx context.Context, _ types.ULID) ([]models.Customer, error) {
|
||||
return models.GetCustomersByCompanyID(ctx, companyID)
|
||||
}
|
||||
|
||||
// Get customers from the database and convert to DTOs
|
||||
customers, err := getByCompanyIDFn(c.Request.Context(), types.ULID{})
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving customers: "+err.Error())
|
||||
responses.InternalErrorResponse(c, "Error retrieving customers: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTOs
|
||||
customerDTOs := utils.ConvertToDTO(customers, convertCustomerToDTO)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, customerDTOs)
|
||||
responses.SuccessResponse(c, http.StatusOK, customerDTOs)
|
||||
}
|
||||
|
||||
// CreateCustomer handles POST /customers
|
||||
@@ -106,37 +113,19 @@ func (h *CustomerHandler) GetCustomersByCompanyID(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /customers [post]
|
||||
func (h *CustomerHandler) CreateCustomer(c *gin.Context) {
|
||||
// We need to use a custom wrapper for CreateCustomer because we need to get the user ID from the context
|
||||
userID, err := middleware.GetUserIDFromContext(c)
|
||||
if err != nil {
|
||||
utils.UnauthorizedResponse(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
// Parse request body
|
||||
var customerCreateDTO dto.CustomerCreateDto
|
||||
if err := utils.BindJSON(c, &customerCreateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
responses.UnauthorizedResponse(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
customerCreate, err := convertCreateCustomerDTOToModel(customerCreateDTO)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
||||
return
|
||||
}
|
||||
customerCreate.OwnerUserID = &userID
|
||||
|
||||
// Create customer in the database
|
||||
customer, err := models.CreateCustomer(c.Request.Context(), customerCreate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error creating customer: "+err.Error())
|
||||
return
|
||||
// Use a closure to capture the userID
|
||||
createFn := func(ctx context.Context, createDTO dto.CustomerCreateDto) (*models.Customer, error) {
|
||||
return createCustomerWrapper(ctx, createDTO, userID)
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
customerDTO := convertCustomerToDTO(customer)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusCreated, customerDTO)
|
||||
utils.HandleCreate(c, createFn, convertCustomerToDTO, "customer")
|
||||
}
|
||||
|
||||
// UpdateCustomer handles PUT /customers/:id
|
||||
@@ -156,46 +145,7 @@ func (h *CustomerHandler) CreateCustomer(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /customers/{id} [put]
|
||||
func (h *CustomerHandler) UpdateCustomer(c *gin.Context) {
|
||||
// Parse ID from URL
|
||||
id, err := utils.ParseID(c, "id")
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid customer ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var customerUpdateDTO dto.CustomerUpdateDto
|
||||
if err := utils.BindJSON(c, &customerUpdateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Set ID from URL
|
||||
customerUpdateDTO.ID = id.String()
|
||||
|
||||
// Convert DTO to model
|
||||
customerUpdate, err := convertUpdateCustomerDTOToModel(customerUpdateDTO)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Update customer in the database
|
||||
customer, err := models.UpdateCustomer(c.Request.Context(), customerUpdate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error updating customer: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if customer == nil {
|
||||
utils.NotFoundResponse(c, "Customer not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
customerDTO := convertCustomerToDTO(customer)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, customerDTO)
|
||||
utils.HandleUpdate(c, models.UpdateCustomer, convertCustomerToDTO, prepareCustomerUpdate, "customer")
|
||||
}
|
||||
|
||||
// DeleteCustomer handles DELETE /customers/:id
|
||||
@@ -282,3 +232,47 @@ func parseCompanyID(idStr string) (int, error) {
|
||||
_, err := fmt.Sscanf(idStr, "%d", &id)
|
||||
return id, err
|
||||
}
|
||||
|
||||
// prepareCustomerUpdate prepares the customer update object by parsing the ID, binding the JSON, and converting the DTO to a model
|
||||
func prepareCustomerUpdate(c *gin.Context) (models.CustomerUpdate, error) {
|
||||
// Parse ID from URL
|
||||
id, err := utils.ParseID(c, "id")
|
||||
if err != nil {
|
||||
responses.BadRequestResponse(c, "Invalid customer ID format")
|
||||
return models.CustomerUpdate{}, err
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var customerUpdateDTO dto.CustomerUpdateDto
|
||||
if err := utils.BindJSON(c, &customerUpdateDTO); err != nil {
|
||||
responses.BadRequestResponse(c, err.Error())
|
||||
return models.CustomerUpdate{}, err
|
||||
}
|
||||
|
||||
// Set ID from URL
|
||||
customerUpdateDTO.ID = id.String()
|
||||
|
||||
// Convert DTO to model
|
||||
customerUpdate, err := convertUpdateCustomerDTOToModel(customerUpdateDTO)
|
||||
if err != nil {
|
||||
responses.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
||||
return models.CustomerUpdate{}, err
|
||||
}
|
||||
|
||||
return customerUpdate, nil
|
||||
}
|
||||
|
||||
// createCustomerWrapper is a wrapper function for models.CreateCustomer that takes a DTO as input
|
||||
func createCustomerWrapper(ctx context.Context, createDTO dto.CustomerCreateDto, userID types.ULID) (*models.Customer, error) {
|
||||
// Convert DTO to model
|
||||
customerCreate, err := convertCreateCustomerDTOToModel(createDTO)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set the owner user ID
|
||||
customerCreate.OwnerUserID = &userID
|
||||
|
||||
// Call the original function
|
||||
return models.CreateCustomer(ctx, customerCreate)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/timetracker/backend/internal/api/dto"
|
||||
"github.com/timetracker/backend/internal/api/responses"
|
||||
"github.com/timetracker/backend/internal/api/utils"
|
||||
dto "github.com/timetracker/backend/internal/dtos"
|
||||
"github.com/timetracker/backend/internal/models"
|
||||
"github.com/timetracker/backend/internal/types"
|
||||
)
|
||||
@@ -48,17 +49,7 @@ func (h *ProjectHandler) GetProjects(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /projects/with-customers [get]
|
||||
func (h *ProjectHandler) GetProjectsWithCustomers(c *gin.Context) {
|
||||
// Get projects with customers from the database
|
||||
projects, err := models.GetAllProjectsWithCustomers(c.Request.Context())
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving projects: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTOs
|
||||
projectDTOs := utils.ConvertToDTO(projects, convertProjectToDTO)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, projectDTOs)
|
||||
utils.HandleGetAll(c, models.GetAllProjectsWithCustomers, convertProjectToDTO, "projects with customers")
|
||||
}
|
||||
|
||||
// GetProjectByID handles GET /projects/:id
|
||||
@@ -95,24 +86,7 @@ func (h *ProjectHandler) GetProjectByID(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /projects/customer/{customerId} [get]
|
||||
func (h *ProjectHandler) GetProjectsByCustomerID(c *gin.Context) {
|
||||
// Parse customer ID from URL
|
||||
customerID, err := utils.ParseID(c, "customerId")
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid customer ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Get projects from the database
|
||||
projects, err := models.GetProjectsByCustomerID(c.Request.Context(), customerID)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving projects: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTOs
|
||||
projectDTOs := utils.ConvertToDTO(projects, convertProjectToDTO)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, projectDTOs)
|
||||
utils.HandleGetByFilter(c, models.GetProjectsByCustomerID, convertProjectToDTO, "projects", "customerId")
|
||||
}
|
||||
|
||||
// CreateProject handles POST /projects
|
||||
@@ -130,31 +104,7 @@ func (h *ProjectHandler) GetProjectsByCustomerID(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /projects [post]
|
||||
func (h *ProjectHandler) CreateProject(c *gin.Context) {
|
||||
// Parse request body
|
||||
var projectCreateDTO dto.ProjectCreateDto
|
||||
if err := utils.BindJSON(c, &projectCreateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
projectCreate, err := convertCreateProjectDTOToModel(projectCreateDTO)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Create project in the database
|
||||
project, err := models.CreateProject(c.Request.Context(), projectCreate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error creating project: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
projectDTO := convertProjectToDTO(project)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusCreated, projectDTO)
|
||||
utils.HandleCreate(c, createProjectWrapper, convertProjectToDTO, "project")
|
||||
}
|
||||
|
||||
// UpdateProject handles PUT /projects/:id
|
||||
@@ -174,43 +124,7 @@ func (h *ProjectHandler) CreateProject(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /projects/{id} [put]
|
||||
func (h *ProjectHandler) UpdateProject(c *gin.Context) {
|
||||
// Parse ID from URL
|
||||
id, err := utils.ParseID(c, "id")
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid project ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var projectUpdateDTO dto.ProjectUpdateDto
|
||||
if err := utils.BindJSON(c, &projectUpdateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
projectUpdate, err := convertUpdateProjectDTOToModel(projectUpdateDTO, id)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Update project in the database
|
||||
project, err := models.UpdateProject(c.Request.Context(), projectUpdate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error updating project: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if project == nil {
|
||||
utils.NotFoundResponse(c, "Project not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
projectDTO := convertProjectToDTO(project)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, projectDTO)
|
||||
utils.HandleUpdate(c, models.UpdateProject, convertProjectToDTO, prepareProjectUpdate, "project")
|
||||
}
|
||||
|
||||
// DeleteProject handles DELETE /projects/:id
|
||||
@@ -228,21 +142,7 @@ func (h *ProjectHandler) UpdateProject(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /projects/{id} [delete]
|
||||
func (h *ProjectHandler) DeleteProject(c *gin.Context) {
|
||||
// Parse ID from URL
|
||||
id, err := utils.ParseID(c, "id")
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid project ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Delete project from the database
|
||||
err = models.DeleteProject(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error deleting project: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessResponse(c, http.StatusNoContent, nil)
|
||||
utils.HandleDelete(c, models.DeleteProject, "project")
|
||||
}
|
||||
|
||||
// Helper functions for DTO conversion
|
||||
@@ -294,3 +194,41 @@ func convertUpdateProjectDTOToModel(dto dto.ProjectUpdateDto, id types.ULID) (mo
|
||||
|
||||
return update, nil
|
||||
}
|
||||
|
||||
// prepareProjectUpdate prepares the project update object by parsing the ID, binding the JSON, and converting the DTO to a model
|
||||
func prepareProjectUpdate(c *gin.Context) (models.ProjectUpdate, error) {
|
||||
// Parse ID from URL
|
||||
id, err := utils.ParseID(c, "id")
|
||||
if err != nil {
|
||||
responses.BadRequestResponse(c, "Invalid project ID format")
|
||||
return models.ProjectUpdate{}, err
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var projectUpdateDTO dto.ProjectUpdateDto
|
||||
if err := utils.BindJSON(c, &projectUpdateDTO); err != nil {
|
||||
responses.BadRequestResponse(c, err.Error())
|
||||
return models.ProjectUpdate{}, err
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
projectUpdate, err := convertUpdateProjectDTOToModel(projectUpdateDTO, id)
|
||||
if err != nil {
|
||||
responses.BadRequestResponse(c, err.Error())
|
||||
return models.ProjectUpdate{}, err
|
||||
}
|
||||
|
||||
return projectUpdate, nil
|
||||
}
|
||||
|
||||
// createProjectWrapper is a wrapper function for models.CreateProject that takes a DTO as input
|
||||
func createProjectWrapper(ctx context.Context, createDTO dto.ProjectCreateDto) (*models.Project, error) {
|
||||
// Convert DTO to model
|
||||
projectCreate, err := convertCreateProjectDTOToModel(createDTO)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Call the original function
|
||||
return models.CreateProject(ctx, projectCreate)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/oklog/ulid/v2"
|
||||
"github.com/timetracker/backend/internal/api/middleware"
|
||||
"github.com/timetracker/backend/internal/api/dto"
|
||||
"github.com/timetracker/backend/internal/api/responses"
|
||||
"github.com/timetracker/backend/internal/api/utils"
|
||||
dto "github.com/timetracker/backend/internal/dtos"
|
||||
"github.com/timetracker/backend/internal/models"
|
||||
"github.com/timetracker/backend/internal/types"
|
||||
)
|
||||
@@ -35,20 +33,7 @@ func NewTimeEntryHandler() *TimeEntryHandler {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /time-entries [get]
|
||||
func (h *TimeEntryHandler) GetTimeEntries(c *gin.Context) {
|
||||
// Get time entries from the database
|
||||
timeEntries, err := models.GetAllTimeEntries(c.Request.Context())
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving time entries: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTOs
|
||||
timeEntryDTOs := make([]dto.TimeEntryDto, len(timeEntries))
|
||||
for i, timeEntry := range timeEntries {
|
||||
timeEntryDTOs[i] = convertTimeEntryToDTO(&timeEntry)
|
||||
}
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, timeEntryDTOs)
|
||||
utils.HandleGetAll(c, models.GetAllTimeEntries, convertTimeEntryToDTO, "time entries")
|
||||
}
|
||||
|
||||
// GetTimeEntryByID handles GET /time-entries/:id
|
||||
@@ -67,30 +52,7 @@ func (h *TimeEntryHandler) GetTimeEntries(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /time-entries/{id} [get]
|
||||
func (h *TimeEntryHandler) GetTimeEntryByID(c *gin.Context) {
|
||||
// Parse ID from URL
|
||||
idStr := c.Param("id")
|
||||
id, err := ulid.Parse(idStr)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid time entry ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Get time entry from the database
|
||||
timeEntry, err := models.GetTimeEntryByID(c.Request.Context(), types.FromULID(id))
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving time entry: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if timeEntry == nil {
|
||||
utils.NotFoundResponse(c, "Time entry not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
timeEntryDTO := convertTimeEntryToDTO(timeEntry)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, timeEntryDTO)
|
||||
utils.HandleGetByID(c, models.GetTimeEntryByID, convertTimeEntryToDTO, "time entry")
|
||||
}
|
||||
|
||||
// GetTimeEntriesByUserID handles GET /time-entries/user/:userId
|
||||
@@ -108,28 +70,7 @@ func (h *TimeEntryHandler) GetTimeEntryByID(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /time-entries/user/{userId} [get]
|
||||
func (h *TimeEntryHandler) GetTimeEntriesByUserID(c *gin.Context) {
|
||||
// Parse user ID from URL
|
||||
userIDStr := c.Param("userId")
|
||||
userID, err := ulid.Parse(userIDStr)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid user ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Get time entries from the database
|
||||
timeEntries, err := models.GetTimeEntriesByUserID(c.Request.Context(), types.FromULID(userID))
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving time entries: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTOs
|
||||
timeEntryDTOs := make([]dto.TimeEntryDto, len(timeEntries))
|
||||
for i, timeEntry := range timeEntries {
|
||||
timeEntryDTOs[i] = convertTimeEntryToDTO(&timeEntry)
|
||||
}
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, timeEntryDTOs)
|
||||
utils.HandleGetByFilter(c, models.GetTimeEntriesByUserID, convertTimeEntryToDTO, "time entries", "userId")
|
||||
}
|
||||
|
||||
// GetMyTimeEntries handles GET /time-entries/me
|
||||
@@ -145,27 +86,7 @@ func (h *TimeEntryHandler) GetTimeEntriesByUserID(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /time-entries/me [get]
|
||||
func (h *TimeEntryHandler) GetMyTimeEntries(c *gin.Context) {
|
||||
// Get user ID from context (set by AuthMiddleware)
|
||||
userID, err := middleware.GetUserIDFromContext(c)
|
||||
if err != nil {
|
||||
utils.UnauthorizedResponse(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
// Get time entries from the database
|
||||
timeEntries, err := models.GetTimeEntriesByUserID(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving time entries: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTOs
|
||||
timeEntryDTOs := make([]dto.TimeEntryDto, len(timeEntries))
|
||||
for i, timeEntry := range timeEntries {
|
||||
timeEntryDTOs[i] = convertTimeEntryToDTO(&timeEntry)
|
||||
}
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, timeEntryDTOs)
|
||||
utils.HandleGetByUserID(c, models.GetTimeEntriesByUserID, convertTimeEntryToDTO, "time entries")
|
||||
}
|
||||
|
||||
// GetTimeEntriesByProjectID handles GET /time-entries/project/:projectId
|
||||
@@ -183,27 +104,7 @@ func (h *TimeEntryHandler) GetMyTimeEntries(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /time-entries/project/{projectId} [get]
|
||||
func (h *TimeEntryHandler) GetTimeEntriesByProjectID(c *gin.Context) {
|
||||
// Parse project ID from URL
|
||||
projectID, err := utils.ParseID(c, "projectId")
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid project ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Get time entries from the database
|
||||
timeEntries, err := models.GetTimeEntriesByProjectID(c.Request.Context(), projectID)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving time entries: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTOs
|
||||
timeEntryDTOs := make([]dto.TimeEntryDto, len(timeEntries))
|
||||
for i, timeEntry := range timeEntries {
|
||||
timeEntryDTOs[i] = convertTimeEntryToDTO(&timeEntry)
|
||||
}
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, timeEntryDTOs)
|
||||
utils.HandleGetByFilter(c, models.GetTimeEntriesByProjectID, convertTimeEntryToDTO, "time entries", "projectId")
|
||||
}
|
||||
|
||||
// GetTimeEntriesByDateRange handles GET /time-entries/range
|
||||
@@ -222,46 +123,7 @@ func (h *TimeEntryHandler) GetTimeEntriesByProjectID(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /time-entries/range [get]
|
||||
func (h *TimeEntryHandler) GetTimeEntriesByDateRange(c *gin.Context) {
|
||||
// Parse date range from query parameters
|
||||
startStr := c.Query("start")
|
||||
endStr := c.Query("end")
|
||||
|
||||
if startStr == "" || endStr == "" {
|
||||
utils.BadRequestResponse(c, "Start and end dates are required")
|
||||
return
|
||||
}
|
||||
|
||||
start, err := time.Parse(time.RFC3339, startStr)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid start date format. Use ISO 8601 format (e.g., 2023-01-01T00:00:00Z)")
|
||||
return
|
||||
}
|
||||
|
||||
end, err := time.Parse(time.RFC3339, endStr)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid end date format. Use ISO 8601 format (e.g., 2023-01-01T00:00:00Z)")
|
||||
return
|
||||
}
|
||||
|
||||
if end.Before(start) {
|
||||
utils.BadRequestResponse(c, "End date cannot be before start date")
|
||||
return
|
||||
}
|
||||
|
||||
// Get time entries from the database
|
||||
timeEntries, err := models.GetTimeEntriesByDateRange(c.Request.Context(), start, end)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving time entries: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTOs
|
||||
timeEntryDTOs := make([]dto.TimeEntryDto, len(timeEntries))
|
||||
for i, timeEntry := range timeEntries {
|
||||
timeEntryDTOs[i] = convertTimeEntryToDTO(&timeEntry)
|
||||
}
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, timeEntryDTOs)
|
||||
utils.HandleGetByDateRange(c, models.GetTimeEntriesByDateRange, convertTimeEntryToDTO, "time entries")
|
||||
}
|
||||
|
||||
// CreateTimeEntry handles POST /time-entries
|
||||
@@ -279,31 +141,7 @@ func (h *TimeEntryHandler) GetTimeEntriesByDateRange(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /time-entries [post]
|
||||
func (h *TimeEntryHandler) CreateTimeEntry(c *gin.Context) {
|
||||
// Parse request body
|
||||
var timeEntryCreateDTO dto.TimeEntryCreateDto
|
||||
if err := c.ShouldBindJSON(&timeEntryCreateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
timeEntryCreate, err := convertCreateTimeEntryDTOToModel(timeEntryCreateDTO)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Create time entry in the database
|
||||
timeEntry, err := models.CreateTimeEntry(c.Request.Context(), timeEntryCreate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error creating time entry: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
timeEntryDTO := convertTimeEntryToDTO(timeEntry)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusCreated, timeEntryDTO)
|
||||
utils.HandleCreate(c, createTimeEntryWrapper, convertTimeEntryToDTO, "time entry")
|
||||
}
|
||||
|
||||
// UpdateTimeEntry handles PUT /time-entries/:id
|
||||
@@ -323,44 +161,7 @@ func (h *TimeEntryHandler) CreateTimeEntry(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /time-entries/{id} [put]
|
||||
func (h *TimeEntryHandler) UpdateTimeEntry(c *gin.Context) {
|
||||
// Parse ID from URL
|
||||
idStr := c.Param("id")
|
||||
id, err := types.ULIDFromString(idStr)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid time entry ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var timeEntryUpdateDTO dto.TimeEntryUpdateDto
|
||||
if err := c.ShouldBindJSON(&timeEntryUpdateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
timeEntryUpdate, err := convertUpdateTimeEntryDTOToModel(timeEntryUpdateDTO, id)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Update time entry in the database
|
||||
timeEntry, err := models.UpdateTimeEntry(c.Request.Context(), timeEntryUpdate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error updating time entry: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if timeEntry == nil {
|
||||
utils.NotFoundResponse(c, "Time entry not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
timeEntryDTO := convertTimeEntryToDTO(timeEntry)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, timeEntryDTO)
|
||||
utils.HandleUpdate(c, models.UpdateTimeEntry, convertTimeEntryToDTO, prepareTimeEntryUpdate, "time entry")
|
||||
}
|
||||
|
||||
// DeleteTimeEntry handles DELETE /time-entries/:id
|
||||
@@ -378,22 +179,7 @@ func (h *TimeEntryHandler) UpdateTimeEntry(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /time-entries/{id} [delete]
|
||||
func (h *TimeEntryHandler) DeleteTimeEntry(c *gin.Context) {
|
||||
// Parse ID from URL
|
||||
idStr := c.Param("id")
|
||||
id, err := ulid.Parse(idStr)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid time entry ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Delete time entry from the database
|
||||
err = models.DeleteTimeEntry(c.Request.Context(), types.FromULID(id))
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error deleting time entry: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessResponse(c, http.StatusNoContent, nil)
|
||||
utils.HandleDelete(c, models.DeleteTimeEntry, "time entry")
|
||||
}
|
||||
|
||||
// Helper functions for DTO conversion
|
||||
@@ -489,3 +275,42 @@ func convertUpdateTimeEntryDTOToModel(dto dto.TimeEntryUpdateDto, id types.ULID)
|
||||
|
||||
return update, nil
|
||||
}
|
||||
|
||||
// prepareTimeEntryUpdate prepares the time entry update object by parsing the ID, binding the JSON, and converting the DTO to a model
|
||||
func prepareTimeEntryUpdate(c *gin.Context) (models.TimeEntryUpdate, error) {
|
||||
// Parse ID from URL
|
||||
idStr := c.Param("id")
|
||||
id, err := types.ULIDFromString(idStr)
|
||||
if err != nil {
|
||||
responses.BadRequestResponse(c, "Invalid time entry ID format")
|
||||
return models.TimeEntryUpdate{}, err
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var timeEntryUpdateDTO dto.TimeEntryUpdateDto
|
||||
if err := utils.BindJSON(c, &timeEntryUpdateDTO); err != nil {
|
||||
responses.BadRequestResponse(c, err.Error())
|
||||
return models.TimeEntryUpdate{}, err
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
timeEntryUpdate, err := convertUpdateTimeEntryDTOToModel(timeEntryUpdateDTO, id)
|
||||
if err != nil {
|
||||
responses.BadRequestResponse(c, err.Error())
|
||||
return models.TimeEntryUpdate{}, err
|
||||
}
|
||||
|
||||
return timeEntryUpdate, nil
|
||||
}
|
||||
|
||||
// createTimeEntryWrapper is a wrapper function for models.CreateTimeEntry that takes a DTO as input
|
||||
func createTimeEntryWrapper(ctx context.Context, createDTO dto.TimeEntryCreateDto) (*models.TimeEntry, error) {
|
||||
// Convert DTO to model
|
||||
timeEntryCreate, err := convertCreateTimeEntryDTOToModel(createDTO)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Call the original function
|
||||
return models.CreateTimeEntry(ctx, timeEntryCreate)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/oklog/ulid/v2"
|
||||
"github.com/timetracker/backend/internal/api/dto"
|
||||
"github.com/timetracker/backend/internal/api/middleware"
|
||||
"github.com/timetracker/backend/internal/api/responses"
|
||||
"github.com/timetracker/backend/internal/api/utils"
|
||||
dto "github.com/timetracker/backend/internal/dtos"
|
||||
"github.com/timetracker/backend/internal/models"
|
||||
"github.com/timetracker/backend/internal/types"
|
||||
)
|
||||
@@ -33,20 +34,7 @@ func NewUserHandler() *UserHandler {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /users [get]
|
||||
func (h *UserHandler) GetUsers(c *gin.Context) {
|
||||
// Get users from the database
|
||||
users, err := models.GetAllUsers(c.Request.Context())
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving users: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTOs
|
||||
userDTOs := make([]dto.UserDto, len(users))
|
||||
for i, user := range users {
|
||||
userDTOs[i] = convertUserToDTO(&user)
|
||||
}
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, userDTOs)
|
||||
utils.HandleGetAll(c, models.GetAllUsers, convertUserToDTO, "users")
|
||||
}
|
||||
|
||||
// GetUserByID handles GET /users/:id
|
||||
@@ -65,30 +53,29 @@ func (h *UserHandler) GetUsers(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /users/{id} [get]
|
||||
func (h *UserHandler) GetUserByID(c *gin.Context) {
|
||||
// Parse ID from URL
|
||||
idStr := c.Param("id")
|
||||
id, err := ulid.Parse(idStr)
|
||||
// We need a custom wrapper for GetUserByID because the ID parameter is parsed differently
|
||||
id, err := utils.ParseID(c, "id")
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid user ID format")
|
||||
responses.BadRequestResponse(c, "Invalid user ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Get user from the database
|
||||
user, err := models.GetUserByID(c.Request.Context(), types.FromULID(id))
|
||||
user, err := models.GetUserByID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving user: "+err.Error())
|
||||
responses.InternalErrorResponse(c, "Error retrieving user: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
utils.NotFoundResponse(c, "User not found")
|
||||
responses.NotFoundResponse(c, "User not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
userDTO := convertUserToDTO(user)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, userDTO)
|
||||
responses.SuccessResponse(c, http.StatusOK, userDTO)
|
||||
}
|
||||
|
||||
// CreateUser handles POST /users
|
||||
@@ -106,27 +93,7 @@ func (h *UserHandler) GetUserByID(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /users [post]
|
||||
func (h *UserHandler) CreateUser(c *gin.Context) {
|
||||
// Parse request body
|
||||
var userCreateDTO dto.UserCreateDto
|
||||
if err := c.ShouldBindJSON(&userCreateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert DTO to model
|
||||
userCreate := convertCreateDTOToModel(userCreateDTO)
|
||||
|
||||
// Create user in the database
|
||||
user, err := models.CreateUser(c.Request.Context(), userCreate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error creating user: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
userDTO := convertUserToDTO(user)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusCreated, userDTO)
|
||||
utils.HandleCreate(c, createUserWrapper, convertUserToDTO, "user")
|
||||
}
|
||||
|
||||
// UpdateUser handles PUT /users/:id
|
||||
@@ -146,68 +113,7 @@ func (h *UserHandler) CreateUser(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /users/{id} [put]
|
||||
func (h *UserHandler) UpdateUser(c *gin.Context) {
|
||||
// Parse ID from URL
|
||||
idStr := c.Param("id")
|
||||
id, err := types.ULIDFromString(idStr)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid user ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var userUpdateDTO dto.UserUpdateDto
|
||||
if err := c.ShouldBindJSON(&userUpdateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Convert DTO to Model
|
||||
update := models.UserUpdate{
|
||||
ID: id,
|
||||
}
|
||||
|
||||
if userUpdateDTO.Email != nil {
|
||||
update.Email = userUpdateDTO.Email
|
||||
}
|
||||
if userUpdateDTO.Password != nil {
|
||||
update.Password = userUpdateDTO.Password
|
||||
}
|
||||
if userUpdateDTO.Role != nil {
|
||||
update.Role = userUpdateDTO.Role
|
||||
}
|
||||
|
||||
if userUpdateDTO.CompanyID.Valid {
|
||||
if userUpdateDTO.CompanyID.Value != nil {
|
||||
companyID, err := types.ULIDFromString(*userUpdateDTO.CompanyID.Value)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid company ID format")
|
||||
return
|
||||
}
|
||||
update.CompanyID = types.NewNullable(companyID)
|
||||
} else {
|
||||
update.CompanyID = types.Null[types.ULID]()
|
||||
}
|
||||
}
|
||||
|
||||
if userUpdateDTO.HourlyRate != nil {
|
||||
update.HourlyRate = userUpdateDTO.HourlyRate
|
||||
}
|
||||
// Update user in the database
|
||||
user, err := models.UpdateUser(c.Request.Context(), update)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error updating user: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
utils.NotFoundResponse(c, "User not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
userDTO := convertUserToDTO(user)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, userDTO)
|
||||
utils.HandleUpdate(c, models.UpdateUser, convertUserToDTO, prepareUserUpdate, "user")
|
||||
}
|
||||
|
||||
// DeleteUser handles DELETE /users/:id
|
||||
@@ -225,22 +131,7 @@ func (h *UserHandler) UpdateUser(c *gin.Context) {
|
||||
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
||||
// @Router /users/{id} [delete]
|
||||
func (h *UserHandler) DeleteUser(c *gin.Context) {
|
||||
// Parse ID from URL
|
||||
idStr := c.Param("id")
|
||||
id, err := ulid.Parse(idStr)
|
||||
if err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid user ID format")
|
||||
return
|
||||
}
|
||||
|
||||
// Delete user from the database
|
||||
err = models.DeleteUser(c.Request.Context(), types.FromULID(id))
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error deleting user: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessResponse(c, http.StatusNoContent, nil)
|
||||
utils.HandleDelete(c, models.DeleteUser, "user")
|
||||
}
|
||||
|
||||
// Login handles POST /auth/login
|
||||
@@ -260,21 +151,21 @@ func (h *UserHandler) Login(c *gin.Context) {
|
||||
// Parse request body
|
||||
var loginDTO dto.LoginDto
|
||||
if err := c.ShouldBindJSON(&loginDTO); err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
||||
responses.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Authenticate user
|
||||
user, err := models.AuthenticateUser(c.Request.Context(), loginDTO.Email, loginDTO.Password)
|
||||
if err != nil {
|
||||
utils.UnauthorizedResponse(c, "Invalid login credentials")
|
||||
responses.UnauthorizedResponse(c, "Invalid login credentials")
|
||||
return
|
||||
}
|
||||
|
||||
// Generate JWT token
|
||||
token, err := middleware.GenerateToken(user, c)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error generating token: "+err.Error())
|
||||
responses.InternalErrorResponse(c, "Error generating token: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -284,7 +175,7 @@ func (h *UserHandler) Login(c *gin.Context) {
|
||||
User: convertUserToDTO(user),
|
||||
}
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, tokenDTO)
|
||||
responses.SuccessResponse(c, http.StatusOK, tokenDTO)
|
||||
}
|
||||
|
||||
// Register handles POST /auth/register
|
||||
@@ -303,7 +194,7 @@ func (h *UserHandler) Register(c *gin.Context) {
|
||||
// Parse request body
|
||||
var userCreateDTO dto.UserCreateDto
|
||||
if err := c.ShouldBindJSON(&userCreateDTO); err != nil {
|
||||
utils.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
||||
responses.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -313,14 +204,14 @@ func (h *UserHandler) Register(c *gin.Context) {
|
||||
// Create user in the database
|
||||
user, err := models.CreateUser(c.Request.Context(), userCreate)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error creating user: "+err.Error())
|
||||
responses.InternalErrorResponse(c, "Error creating user: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Generate JWT token
|
||||
token, err := middleware.GenerateToken(user, c)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error generating token: "+err.Error())
|
||||
responses.InternalErrorResponse(c, "Error generating token: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -330,7 +221,7 @@ func (h *UserHandler) Register(c *gin.Context) {
|
||||
User: convertUserToDTO(user),
|
||||
}
|
||||
|
||||
utils.SuccessResponse(c, http.StatusCreated, tokenDTO)
|
||||
responses.SuccessResponse(c, http.StatusCreated, tokenDTO)
|
||||
}
|
||||
|
||||
// GetCurrentUser handles GET /auth/me
|
||||
@@ -349,26 +240,26 @@ func (h *UserHandler) GetCurrentUser(c *gin.Context) {
|
||||
// Get user ID from context (set by AuthMiddleware)
|
||||
userID, err := middleware.GetUserIDFromContext(c)
|
||||
if err != nil {
|
||||
utils.UnauthorizedResponse(c, "User not authenticated")
|
||||
responses.UnauthorizedResponse(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
// Get user from the database
|
||||
user, err := models.GetUserByID(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
utils.InternalErrorResponse(c, "Error retrieving user: "+err.Error())
|
||||
responses.InternalErrorResponse(c, "Error retrieving user: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
utils.NotFoundResponse(c, "User not found")
|
||||
responses.NotFoundResponse(c, "User not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to DTO
|
||||
userDTO := convertUserToDTO(user)
|
||||
|
||||
utils.SuccessResponse(c, http.StatusOK, userDTO)
|
||||
responses.SuccessResponse(c, http.StatusOK, userDTO)
|
||||
}
|
||||
|
||||
// Helper functions for DTO conversion
|
||||
@@ -390,6 +281,58 @@ func convertUserToDTO(user *models.User) dto.UserDto {
|
||||
}
|
||||
}
|
||||
|
||||
// prepareUserUpdate prepares the user update object by parsing the ID, binding the JSON, and converting the DTO to a model
|
||||
func prepareUserUpdate(c *gin.Context) (models.UserUpdate, error) {
|
||||
// Parse ID from URL
|
||||
idStr := c.Param("id")
|
||||
id, err := types.ULIDFromString(idStr)
|
||||
if err != nil {
|
||||
responses.BadRequestResponse(c, "Invalid user ID format")
|
||||
return models.UserUpdate{}, err
|
||||
}
|
||||
|
||||
// Parse request body
|
||||
var userUpdateDTO dto.UserUpdateDto
|
||||
if err := utils.BindJSON(c, &userUpdateDTO); err != nil {
|
||||
responses.BadRequestResponse(c, err.Error())
|
||||
return models.UserUpdate{}, err
|
||||
}
|
||||
|
||||
// Convert DTO to Model
|
||||
update := models.UserUpdate{
|
||||
ID: id,
|
||||
}
|
||||
|
||||
if userUpdateDTO.Email != nil {
|
||||
update.Email = userUpdateDTO.Email
|
||||
}
|
||||
if userUpdateDTO.Password != nil {
|
||||
update.Password = userUpdateDTO.Password
|
||||
}
|
||||
if userUpdateDTO.Role != nil {
|
||||
update.Role = userUpdateDTO.Role
|
||||
}
|
||||
|
||||
if userUpdateDTO.CompanyID.Valid {
|
||||
if userUpdateDTO.CompanyID.Value != nil {
|
||||
companyID, err := types.ULIDFromString(*userUpdateDTO.CompanyID.Value)
|
||||
if err != nil {
|
||||
responses.BadRequestResponse(c, "Invalid company ID format")
|
||||
return models.UserUpdate{}, err
|
||||
}
|
||||
update.CompanyID = types.NewNullable(companyID)
|
||||
} else {
|
||||
update.CompanyID = types.Null[types.ULID]()
|
||||
}
|
||||
}
|
||||
|
||||
if userUpdateDTO.HourlyRate != nil {
|
||||
update.HourlyRate = userUpdateDTO.HourlyRate
|
||||
}
|
||||
|
||||
return update, nil
|
||||
}
|
||||
|
||||
func convertCreateDTOToModel(dto dto.UserCreateDto) models.UserCreate {
|
||||
var companyID *types.ULID
|
||||
if dto.CompanyID != nil {
|
||||
@@ -405,3 +348,12 @@ func convertCreateDTOToModel(dto dto.UserCreateDto) models.UserCreate {
|
||||
HourlyRate: dto.HourlyRate,
|
||||
}
|
||||
}
|
||||
|
||||
// createUserWrapper is a wrapper function for models.CreateUser that takes a DTO as input
|
||||
func createUserWrapper(ctx context.Context, createDTO dto.UserCreateDto) (*models.User, error) {
|
||||
// Convert DTO to model
|
||||
userCreate := convertCreateDTOToModel(createDTO)
|
||||
|
||||
// Call the original function
|
||||
return models.CreateUser(ctx, userCreate)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user