254 lines
7.3 KiB
Go
254 lines
7.3 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"
|
|
)
|
|
|
|
// 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) {
|
|
// Get activities from the database
|
|
activities, err := models.GetAllActivities(c.Request.Context())
|
|
if err != nil {
|
|
utils.InternalErrorResponse(c, "Error retrieving activities: "+err.Error())
|
|
return
|
|
}
|
|
|
|
// Convert to DTOs
|
|
activityDTOs := make([]dto.ActivityDto, len(activities))
|
|
for i, activity := range activities {
|
|
activityDTOs[i] = convertActivityToDTO(&activity)
|
|
}
|
|
|
|
utils.SuccessResponse(c, http.StatusOK, activityDTOs)
|
|
}
|
|
|
|
// 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) {
|
|
// Parse ID from URL
|
|
idStr := c.Param("id")
|
|
id, err := ulid.Parse(idStr)
|
|
if err != nil {
|
|
utils.BadRequestResponse(c, "Invalid activity ID format")
|
|
return
|
|
}
|
|
|
|
// Get activity from the database
|
|
activity, err := models.GetActivityByID(c.Request.Context(), id)
|
|
if err != nil {
|
|
utils.InternalErrorResponse(c, "Error retrieving 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)
|
|
}
|
|
|
|
// 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 := c.ShouldBindJSON(&activityCreateDTO); err != nil {
|
|
utils.BadRequestResponse(c, "Invalid request body: "+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
|
|
idStr := c.Param("id")
|
|
id, err := ulid.Parse(idStr)
|
|
if err != nil {
|
|
utils.BadRequestResponse(c, "Invalid activity ID format")
|
|
return
|
|
}
|
|
|
|
// Parse request body
|
|
var activityUpdateDTO dto.ActivityUpdateDto
|
|
if err := c.ShouldBindJSON(&activityUpdateDTO); err != nil {
|
|
utils.BadRequestResponse(c, "Invalid request body: "+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) {
|
|
// Parse ID from URL
|
|
idStr := c.Param("id")
|
|
id, err := ulid.Parse(idStr)
|
|
if err != nil {
|
|
utils.BadRequestResponse(c, "Invalid activity ID format")
|
|
return
|
|
}
|
|
|
|
// Delete activity from the database
|
|
err = models.DeleteActivity(c.Request.Context(), id)
|
|
if err != nil {
|
|
utils.InternalErrorResponse(c, "Error deleting activity: "+err.Error())
|
|
return
|
|
}
|
|
|
|
utils.SuccessResponse(c, http.StatusNoContent, nil)
|
|
}
|
|
|
|
// 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: id,
|
|
}
|
|
|
|
if dto.Name != nil {
|
|
update.Name = dto.Name
|
|
}
|
|
|
|
if dto.BillingRate != nil {
|
|
update.BillingRate = dto.BillingRate
|
|
}
|
|
|
|
return update
|
|
}
|