mirror of
https://github.com/veops/oneterm.git
synced 2025-10-05 15:27:01 +08:00
330 lines
10 KiB
Go
330 lines
10 KiB
Go
package controller
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/spf13/cast"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/veops/oneterm/internal/acl"
|
|
"github.com/veops/oneterm/internal/model"
|
|
"github.com/veops/oneterm/internal/service"
|
|
myErrors "github.com/veops/oneterm/pkg/errors"
|
|
)
|
|
|
|
// CreateAuthorizationV2 godoc
|
|
//
|
|
// @Tags authorization_v2
|
|
// @Param authorization body model.AuthorizationV2 true "authorization rule"
|
|
// @Success 200 {object} HttpResponse
|
|
// @Router /authorization_v2 [post]
|
|
func (c *Controller) CreateAuthorizationV2(ctx *gin.Context) {
|
|
auth := &model.AuthorizationV2{}
|
|
err := ctx.ShouldBindBodyWithJSON(auth)
|
|
if err != nil {
|
|
ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
|
|
return
|
|
}
|
|
|
|
authV2Service := service.NewAuthorizationV2Service()
|
|
|
|
// Check permissions
|
|
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
|
if !acl.IsAdmin(currentUser) {
|
|
ctx.AbortWithError(http.StatusForbidden, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}})
|
|
return
|
|
}
|
|
|
|
// Create the rule
|
|
err = authV2Service.CreateRule(ctx, auth)
|
|
if err != nil {
|
|
if ctx.IsAborted() {
|
|
return
|
|
}
|
|
ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, HttpResponse{
|
|
Data: map[string]any{
|
|
"id": auth.GetId(),
|
|
},
|
|
})
|
|
}
|
|
|
|
// UpdateAuthorizationV2 godoc
|
|
//
|
|
// @Tags authorization_v2
|
|
// @Param id path int true "authorization id"
|
|
// @Param authorization body model.AuthorizationV2 true "authorization rule"
|
|
// @Success 200 {object} HttpResponse
|
|
// @Router /authorization_v2/:id [put]
|
|
func (c *Controller) UpdateAuthorizationV2(ctx *gin.Context) {
|
|
authId := cast.ToInt(ctx.Param("id"))
|
|
auth := &model.AuthorizationV2{}
|
|
err := ctx.ShouldBindBodyWithJSON(auth)
|
|
if err != nil {
|
|
ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
|
|
return
|
|
}
|
|
|
|
auth.Id = authId
|
|
authV2Service := service.NewAuthorizationV2Service()
|
|
|
|
// Check permissions
|
|
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
|
if !acl.IsAdmin(currentUser) {
|
|
ctx.AbortWithError(http.StatusForbidden, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}})
|
|
return
|
|
}
|
|
|
|
// Update the rule
|
|
err = authV2Service.UpdateRule(ctx, auth)
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
|
|
} else {
|
|
ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
|
|
}
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, HttpResponse{
|
|
Data: map[string]any{
|
|
"id": auth.GetId(),
|
|
},
|
|
})
|
|
}
|
|
|
|
// DeleteAuthorizationV2 godoc
|
|
//
|
|
// @Tags authorization_v2
|
|
// @Param id path int true "authorization id"
|
|
// @Success 200 {object} HttpResponse
|
|
// @Router /authorization_v2/:id [delete]
|
|
func (c *Controller) DeleteAuthorizationV2(ctx *gin.Context) {
|
|
authId := cast.ToInt(ctx.Param("id"))
|
|
|
|
authV2Service := service.NewAuthorizationV2Service()
|
|
|
|
// Check permissions
|
|
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
|
if !acl.IsAdmin(currentUser) {
|
|
ctx.AbortWithError(http.StatusForbidden, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}})
|
|
return
|
|
}
|
|
|
|
// Delete the rule
|
|
if err := authV2Service.DeleteRule(ctx, authId); err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
|
|
} else {
|
|
ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
|
|
}
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, HttpResponse{
|
|
Data: map[string]any{
|
|
"id": authId,
|
|
},
|
|
})
|
|
}
|
|
|
|
// GetAuthorizationV2 godoc
|
|
//
|
|
// @Tags authorization_v2
|
|
// @Param id path int true "authorization id"
|
|
// @Success 200 {object} HttpResponse{data=model.AuthorizationV2}
|
|
// @Router /authorization_v2/:id [get]
|
|
func (c *Controller) GetAuthorizationV2(ctx *gin.Context) {
|
|
authId := cast.ToInt(ctx.Param("id"))
|
|
|
|
authV2Service := service.NewAuthorizationV2Service()
|
|
|
|
// Get the rule
|
|
auth, err := authV2Service.GetRuleById(ctx, authId)
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
ctx.AbortWithError(http.StatusNotFound, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
|
|
} else {
|
|
ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
|
|
}
|
|
return
|
|
}
|
|
|
|
if auth == nil {
|
|
ctx.AbortWithError(http.StatusNotFound, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": "rule not found"}})
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, HttpResponse{
|
|
Data: auth,
|
|
})
|
|
}
|
|
|
|
// CloneAuthorizationV2 godoc
|
|
//
|
|
// @Tags authorization_v2
|
|
// @Param id path int true "source authorization id"
|
|
// @Param body body object true "clone request"
|
|
// @Success 200 {object} HttpResponse{data=model.AuthorizationV2}
|
|
// @Router /authorization_v2/:id/clone [post]
|
|
func (c *Controller) CloneAuthorizationV2(ctx *gin.Context) {
|
|
sourceId := cast.ToInt(ctx.Param("id"))
|
|
|
|
// Parse request body
|
|
var req struct {
|
|
Name string `json:"name" binding:"required"`
|
|
}
|
|
err := ctx.ShouldBindBodyWithJSON(&req)
|
|
if err != nil {
|
|
ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err}})
|
|
return
|
|
}
|
|
|
|
authV2Service := service.NewAuthorizationV2Service()
|
|
|
|
// Check permissions
|
|
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
|
if !acl.IsAdmin(currentUser) {
|
|
ctx.AbortWithError(http.StatusForbidden, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}})
|
|
return
|
|
}
|
|
|
|
// Clone the rule
|
|
clonedRule, err := authV2Service.CloneRule(ctx, sourceId, req.Name)
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
ctx.AbortWithError(http.StatusNotFound, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": "source rule not found"}})
|
|
} else {
|
|
ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
|
|
}
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, HttpResponse{
|
|
Data: clonedRule,
|
|
})
|
|
}
|
|
|
|
// GetAuthorizationsV2 godoc
|
|
//
|
|
// @Tags authorization_v2
|
|
// @Param page_index query int false "page index"
|
|
// @Param page_size query int false "page size"
|
|
// @Param enabled query bool false "filter by enabled status"
|
|
// @Param search query string false "search by name or description"
|
|
// @Success 200 {object} HttpResponse{data=ListData{list=[]model.AuthorizationV2}}
|
|
// @Router /authorization_v2 [get]
|
|
func (c *Controller) GetAuthorizationsV2(ctx *gin.Context) {
|
|
pageIndex := cast.ToInt(ctx.DefaultQuery("page_index", "1"))
|
|
pageSize := cast.ToInt(ctx.DefaultQuery("page_size", "20"))
|
|
enabled := ctx.Query("enabled")
|
|
search := ctx.Query("search")
|
|
|
|
// Check permissions
|
|
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
|
if !acl.IsAdmin(currentUser) {
|
|
ctx.AbortWithError(http.StatusForbidden, &myErrors.ApiError{Code: myErrors.ErrNoPerm, Data: map[string]any{"perm": acl.READ}})
|
|
return
|
|
}
|
|
|
|
authV2Service := service.NewAuthorizationV2Service()
|
|
|
|
// Build query with filters
|
|
db, err := authV2Service.BuildQuery(ctx)
|
|
if err != nil {
|
|
ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
|
|
return
|
|
}
|
|
|
|
// Apply filters
|
|
if enabled != "" {
|
|
db = db.Where("enabled = ?", enabled == "true")
|
|
}
|
|
if search != "" {
|
|
db = db.Where("name LIKE ? OR description LIKE ?", "%"+search+"%", "%"+search+"%")
|
|
}
|
|
|
|
// Get total count
|
|
var count int64
|
|
if err := db.Count(&count).Error; err != nil {
|
|
ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
|
|
return
|
|
}
|
|
|
|
// Apply pagination
|
|
offset := (pageIndex - 1) * pageSize
|
|
var auths []*model.AuthorizationV2
|
|
if err := db.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&auths).Error; err != nil {
|
|
ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal, Data: map[string]any{"err": err}})
|
|
return
|
|
}
|
|
|
|
// Convert to slice of any type
|
|
authsAny := make([]any, 0, len(auths))
|
|
for _, a := range auths {
|
|
authsAny = append(authsAny, a)
|
|
}
|
|
|
|
result := &ListData{
|
|
Count: count,
|
|
List: authsAny,
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, HttpResponse{
|
|
Data: result,
|
|
})
|
|
}
|
|
|
|
// CheckPermissionV2 godoc
|
|
//
|
|
// @Tags authorization_v2
|
|
// @Param request body CheckPermissionRequest true "permission check request"
|
|
// @Success 200 {object} HttpResponse{data=model.AuthResult}
|
|
// @Router /authorization_v2/check [post]
|
|
func (c *Controller) CheckPermissionV2(ctx *gin.Context) {
|
|
var req CheckPermissionRequest
|
|
if err := ctx.ShouldBindBodyWithJSON(&req); err != nil {
|
|
ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument})
|
|
return
|
|
}
|
|
|
|
result, err := service.DefaultAuthService.CheckPermission(ctx, req.NodeId, req.AssetId, req.AccountId, req.Action)
|
|
if err != nil {
|
|
ctx.AbortWithError(http.StatusInternalServerError, &myErrors.ApiError{Code: myErrors.ErrInternal})
|
|
return
|
|
}
|
|
|
|
ctx.JSON(http.StatusOK, HttpResponse{Data: result})
|
|
}
|
|
|
|
// CheckPermissionRequest represents a permission check request
|
|
type CheckPermissionRequest struct {
|
|
NodeId int `json:"node_id" binding:"gte=0"`
|
|
AssetId int `json:"asset_id" binding:"gte=0"`
|
|
AccountId int `json:"account_id" binding:"gte=0"`
|
|
Action model.AuthAction `json:"action" binding:"required"`
|
|
}
|
|
|
|
// AuthorizationV2 hooks
|
|
var (
|
|
authV2PreHooks = []preHook[*model.AuthorizationV2]{
|
|
func(ctx *gin.Context, data *model.AuthorizationV2) {
|
|
authV2Service := service.NewAuthorizationV2Service()
|
|
if err := authV2Service.ValidateRule(ctx, data); err != nil {
|
|
ctx.AbortWithError(http.StatusBadRequest, &myErrors.ApiError{Code: myErrors.ErrInvalidArgument, Data: map[string]any{"err": err.Error()}})
|
|
}
|
|
},
|
|
}
|
|
|
|
authV2PostHooks = []postHook[*model.AuthorizationV2]{
|
|
func(ctx *gin.Context, data []*model.AuthorizationV2) {
|
|
// Add any post-processing logic here
|
|
},
|
|
}
|
|
)
|