time-tracker/backend/internal/api/handlers/activity_handler.go

203 lines
6.1 KiB
Go

package handlers
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/oklog/ulid/v2"
"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"
)
// ActivityHandler handles activity-related API endpoints
type ActivityHandler struct{}
// NewActivityHandler creates a new ActivityHandler
func NewActivityHandler() *ActivityHandler {
return &ActivityHandler{}
}
// GetActivities handles GET /activities
//
// @Summary Get all activities
// @Description Get a list of all activities
// @Tags activities
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} utils.Response{data=[]dto.ActivityDto}
// @Failure 401 {object} utils.Response{error=utils.ErrorInfo}
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
// @Router /activities [get]
func (h *ActivityHandler) GetActivities(c *gin.Context) {
utils.HandleGetAll(c, models.GetAllActivities, convertActivityToDTO, "activities")
}
// GetActivityByID handles GET /activities/:id
//
// @Summary Get activity by ID
// @Description Get an activity by its ID
// @Tags activities
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path string true "Activity ID"
// @Success 200 {object} utils.Response{data=dto.ActivityDto}
// @Failure 400 {object} utils.Response{error=utils.ErrorInfo}
// @Failure 401 {object} utils.Response{error=utils.ErrorInfo}
// @Failure 404 {object} utils.Response{error=utils.ErrorInfo}
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
// @Router /activities/{id} [get]
func (h *ActivityHandler) GetActivityByID(c *gin.Context) {
utils.HandleGetByID(c, models.GetActivityByID, convertActivityToDTO, "activity")
}
// CreateActivity handles POST /activities
//
// @Summary Create a new activity
// @Description Create a new activity
// @Tags activities
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param activity body dto.ActivityCreateDto true "Activity data"
// @Success 201 {object} utils.Response{data=dto.ActivityDto}
// @Failure 400 {object} utils.Response{error=utils.ErrorInfo}
// @Failure 401 {object} utils.Response{error=utils.ErrorInfo}
// @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)
}
// UpdateActivity handles PUT /activities/:id
//
// @Summary Update an activity
// @Description Update an existing activity
// @Tags activities
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path string true "Activity ID"
// @Param activity body dto.ActivityUpdateDto true "Activity data"
// @Success 200 {object} utils.Response{data=dto.ActivityDto}
// @Failure 400 {object} utils.Response{error=utils.ErrorInfo}
// @Failure 401 {object} utils.Response{error=utils.ErrorInfo}
// @Failure 404 {object} utils.Response{error=utils.ErrorInfo}
// @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)
}
// DeleteActivity handles DELETE /activities/:id
//
// @Summary Delete an activity
// @Description Delete an activity by its ID
// @Tags activities
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path string true "Activity ID"
// @Success 204 {object} utils.Response
// @Failure 400 {object} utils.Response{error=utils.ErrorInfo}
// @Failure 401 {object} utils.Response{error=utils.ErrorInfo}
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
// @Router /activities/{id} [delete]
func (h *ActivityHandler) DeleteActivity(c *gin.Context) {
utils.HandleDelete(c, models.DeleteActivity, "activity")
}
// Helper functions for DTO conversion
func convertActivityToDTO(activity *models.Activity) dto.ActivityDto {
return dto.ActivityDto{
ID: activity.ID.String(),
CreatedAt: activity.CreatedAt,
UpdatedAt: activity.UpdatedAt,
Name: activity.Name,
BillingRate: activity.BillingRate,
}
}
func convertCreateActivityDTOToModel(dto dto.ActivityCreateDto) models.ActivityCreate {
return models.ActivityCreate{
Name: dto.Name,
BillingRate: dto.BillingRate,
}
}
func convertUpdateActivityDTOToModel(dto dto.ActivityUpdateDto) models.ActivityUpdate {
id, _ := ulid.Parse(dto.ID)
update := models.ActivityUpdate{
ID: types.FromULID(id),
}
if dto.Name != nil {
update.Name = dto.Name
}
if dto.BillingRate != nil {
update.BillingRate = dto.BillingRate
}
return update
}