Files
oneterm/backend/internal/api/controller/time_template.go
2025-07-16 18:11:04 +08:00

199 lines
6.6 KiB
Go

package controller
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/spf13/cast"
"github.com/veops/oneterm/internal/acl"
"github.com/veops/oneterm/internal/model"
"github.com/veops/oneterm/internal/service"
pkgErrors "github.com/veops/oneterm/pkg/errors"
)
var (
timeTemplateService = service.NewTimeTemplateService()
)
// CreateTimeTemplate godoc
//
// @Tags time_template
// @Param template body model.TimeTemplate true "time template"
// @Success 200 {object} HttpResponse
// @Router /time_template [post]
func (c *Controller) CreateTimeTemplate(ctx *gin.Context) {
// Time templates require admin permission - no ACL needed
currentUser, _ := acl.GetSessionFromCtx(ctx)
if !acl.IsAdmin(currentUser) {
ctx.AbortWithError(http.StatusForbidden, &pkgErrors.ApiError{Code: pkgErrors.ErrNoPerm, Data: map[string]any{"perm": "admin"}})
return
}
template := &model.TimeTemplate{}
doCreate(ctx, false, template, "", timeTemplatePreHooks...)
}
// DeleteTimeTemplate godoc
//
// @Tags time_template
// @Param id path int true "template id"
// @Success 200 {object} HttpResponse
// @Router /time_template/:id [delete]
func (c *Controller) DeleteTimeTemplate(ctx *gin.Context) {
// Time templates require admin permission - no ACL needed
currentUser, _ := acl.GetSessionFromCtx(ctx)
if !acl.IsAdmin(currentUser) {
ctx.AbortWithError(http.StatusForbidden, &pkgErrors.ApiError{Code: pkgErrors.ErrNoPerm, Data: map[string]any{"perm": "admin"}})
return
}
doDelete(ctx, false, &model.TimeTemplate{}, "", timeTemplateDeleteChecks...)
}
// UpdateTimeTemplate godoc
//
// @Tags time_template
// @Param id path int true "template id"
// @Param template body model.TimeTemplate true "time template"
// @Success 200 {object} HttpResponse
// @Router /time_template/:id [put]
func (c *Controller) UpdateTimeTemplate(ctx *gin.Context) {
// Time templates require admin permission - no ACL needed
currentUser, _ := acl.GetSessionFromCtx(ctx)
if !acl.IsAdmin(currentUser) {
ctx.AbortWithError(http.StatusForbidden, &pkgErrors.ApiError{Code: pkgErrors.ErrNoPerm, Data: map[string]any{"perm": "admin"}})
return
}
template := &model.TimeTemplate{}
doUpdate(ctx, false, template, "", timeTemplatePreHooks...)
}
// GetTimeTemplates godoc
//
// @Tags time_template
// @Param page_index query int false "page index"
// @Param page_size query int false "page size"
// @Param search query string false "search by name or description"
// @Param category query string false "template category"
// @Param active query bool false "filter by active status"
// @Param info query bool false "info mode"
// @Success 200 {object} HttpResponse{data=[]model.TimeTemplate}
// @Router /time_template [get]
func (c *Controller) GetTimeTemplates(ctx *gin.Context) {
info := cast.ToBool(ctx.Query("info"))
// Build base query using service layer with all filters
db, err := timeTemplateService.BuildQuery(ctx)
if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &pkgErrors.ApiError{Code: pkgErrors.ErrInternal, Data: map[string]any{"err": err}})
return
}
doGet(ctx, !info, db, "", timeTemplatePostHooks...)
}
// GetBuiltInTimeTemplates godoc
//
// @Tags time_template
// @Success 200 {object} HttpResponse{data=[]model.TimeTemplate}
// @Router /time_template/builtin [get]
func (c *Controller) GetBuiltInTimeTemplates(ctx *gin.Context) {
templates, err := timeTemplateService.GetBuiltInTemplates(ctx)
if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &pkgErrors.ApiError{Code: pkgErrors.ErrInternal, Data: map[string]any{"err": err}})
return
}
ctx.JSON(http.StatusOK, NewHttpResponseWithData(templates))
}
// CheckTimeAccess godoc
//
// @Tags time_template
// @Param request body CheckTimeAccessRequest true "time access check request"
// @Success 200 {object} HttpResponse{data=CheckTimeAccessResponse}
// @Router /time_template/check [post]
func (c *Controller) CheckTimeAccess(ctx *gin.Context) {
var req CheckTimeAccessRequest
if err := ctx.ShouldBindBodyWithJSON(&req); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &pkgErrors.ApiError{Code: pkgErrors.ErrInvalidArgument})
return
}
allowed, err := timeTemplateService.CheckTimeAccess(ctx, req.TemplateID, req.Timezone)
if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &pkgErrors.ApiError{Code: pkgErrors.ErrInternal, Data: map[string]any{"err": err}})
return
}
response := CheckTimeAccessResponse{
Allowed: allowed,
TemplateID: req.TemplateID,
Timezone: req.Timezone,
CheckedAt: "now",
}
ctx.JSON(http.StatusOK, NewHttpResponseWithData(response))
}
// InitBuiltInTemplates godoc
//
// @Tags time_template
// @Success 200 {object} HttpResponse
// @Router /time_template/init [post]
func (c *Controller) InitBuiltInTemplates(ctx *gin.Context) {
if err := timeTemplateService.InitializeBuiltInTemplates(ctx); err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &pkgErrors.ApiError{Code: pkgErrors.ErrInternal, Data: map[string]any{"err": err}})
return
}
ctx.JSON(http.StatusOK, NewHttpResponseWithData("Built-in time templates initialized successfully"))
}
// CheckTimeAccessRequest represents a time access check request
type CheckTimeAccessRequest struct {
TemplateID int `json:"template_id" binding:"required,gt=0"`
Timezone string `json:"timezone"`
}
// CheckTimeAccessResponse represents a time access check response
type CheckTimeAccessResponse struct {
Allowed bool `json:"allowed"`
TemplateID int `json:"template_id"`
Timezone string `json:"timezone"`
CheckedAt string `json:"checked_at"`
}
// Time template hooks
var (
timeTemplatePreHooks = []preHook[*model.TimeTemplate]{
func(ctx *gin.Context, data *model.TimeTemplate) {
if err := timeTemplateService.ValidateTimeTemplate(data); err != nil {
ctx.AbortWithError(http.StatusBadRequest, &pkgErrors.ApiError{Code: pkgErrors.ErrInvalidArgument, Data: map[string]any{"err": err.Error()}})
}
},
}
timeTemplatePostHooks = []postHook[*model.TimeTemplate]{
func(ctx *gin.Context, data []*model.TimeTemplate) {
// Add any post-processing logic here
},
}
timeTemplateDeleteChecks = []deleteCheck{
func(ctx *gin.Context, id int) {
// Check if template is built-in
template, err := timeTemplateService.GetTimeTemplate(ctx, id)
if err != nil {
ctx.AbortWithError(http.StatusInternalServerError, &pkgErrors.ApiError{Code: pkgErrors.ErrInternal, Data: map[string]any{"err": err}})
return
}
if template != nil && template.IsBuiltIn {
ctx.AbortWithError(http.StatusBadRequest, &pkgErrors.ApiError{Code: pkgErrors.ErrInvalidArgument, Data: map[string]any{"err": "cannot delete built-in time template"}})
}
},
}
)