mirror of
https://github.com/veops/oneterm.git
synced 2025-10-05 23:37:03 +08:00
175 lines
5.1 KiB
Go
175 lines
5.1 KiB
Go
package controller
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"github.com/samber/lo"
|
|
"github.com/spf13/cast"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/veops/oneterm/internal/acl"
|
|
"github.com/veops/oneterm/internal/model"
|
|
dbpkg "github.com/veops/oneterm/pkg/db"
|
|
)
|
|
|
|
// CreateShare godoc
|
|
//
|
|
// @Tags share
|
|
// @Param share body []model.Share true "share"
|
|
// @Success 200 {object} HttpResponse{data=ListData{list=[]string}}
|
|
// @Router /share [post]
|
|
func (c *Controller) CreateShare(ctx *gin.Context) {
|
|
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
|
|
|
shares := make([]*model.Share, 0)
|
|
|
|
if err := ctx.ShouldBindBodyWithJSON(&shares); err != nil {
|
|
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}})
|
|
return
|
|
}
|
|
|
|
for _, s := range shares {
|
|
if !hasPermShare(ctx, s, acl.GRANT) {
|
|
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}})
|
|
return
|
|
}
|
|
s.CreatorId = currentUser.GetUid()
|
|
s.UpdaterId = currentUser.GetUid()
|
|
}
|
|
|
|
uuids := lo.Map(shares, func(s *model.Share, _ int) string {
|
|
s.Uuid = uuid.New().String()
|
|
return s.Uuid
|
|
})
|
|
if err := dbpkg.DB.Create(&shares).Error; err != nil {
|
|
ctx.AbortWithError(http.StatusInternalServerError, &ApiError{Code: ErrInternal, Data: map[string]any{"err": err}})
|
|
return
|
|
}
|
|
ctx.JSON(http.StatusOK, toListData(uuids))
|
|
}
|
|
|
|
// DeleteShare godoc
|
|
//
|
|
// @Tags share
|
|
// @Param id path int true "share id"
|
|
// @Success 200 {object} HttpResponse
|
|
// @Router /share/:id [delete]
|
|
func (c *Controller) DeleteShare(ctx *gin.Context) {
|
|
share := &model.Share{
|
|
Id: cast.ToInt(ctx.Param("id")),
|
|
}
|
|
|
|
if err := dbpkg.DB.Model(share).Where("id=?", share.Id).First(share); err != nil {
|
|
ctx.AbortWithError(http.StatusBadRequest, &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}})
|
|
return
|
|
}
|
|
|
|
if !hasPermShare(ctx, share, acl.GRANT) {
|
|
ctx.AbortWithError(http.StatusForbidden, &ApiError{Code: ErrNoPerm, Data: map[string]any{"perm": acl.GRANT}})
|
|
return
|
|
}
|
|
doDelete(ctx, false, &model.Share{}, "")
|
|
}
|
|
|
|
// GetShare godoc
|
|
//
|
|
// @Tags share
|
|
// @Param page_index query int true "page_index"
|
|
// @Param page_size query int true "page_size"
|
|
// @Param search query string false "name or ip"
|
|
// @Param start query string false "start, RFC3339"
|
|
// @Param end query string false "end, RFC3339"
|
|
// @Param asset_id query string false "asset id"
|
|
// @Param account_id query string false "account id"
|
|
// @Success 200 {object} HttpResponse{data=ListData{list=[]model.Share}}
|
|
// @Router /share [get]
|
|
func (c *Controller) GetShare(ctx *gin.Context) {
|
|
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
|
|
|
db := dbpkg.DB.Model(&model.Share{})
|
|
db = filterSearch(ctx, db)
|
|
db, err := filterStartEnd(ctx, db)
|
|
if err != nil {
|
|
return
|
|
}
|
|
db = filterEqual(ctx, db, "asset_id", "account_id")
|
|
|
|
if !acl.IsAdmin(currentUser) {
|
|
_, assetIds, accountIds, err := getNodeAssetAccoutIdsByAction(ctx, acl.GRANT)
|
|
if err != nil {
|
|
return
|
|
}
|
|
db = db.Where("asset_id IN (?) OR account_id IN (?)", assetIds, accountIds)
|
|
}
|
|
|
|
doGet[*model.Share](ctx, false, db, "")
|
|
}
|
|
|
|
// ConnectShare godoc
|
|
//
|
|
// @Tags share
|
|
// @Success 200 {object} HttpResponse
|
|
// @Param w query int false "width"
|
|
// @Param h query int false "height"
|
|
// @Param dpi query int false "dpi"
|
|
// @Success 200 {object} HttpResponse{}
|
|
// @Router /share/connect/:uuid [get]
|
|
func (c *Controller) ConnectShare(ctx *gin.Context) {
|
|
share := &model.Share{}
|
|
if err := dbpkg.DB.Transaction(func(tx *gorm.DB) (err error) {
|
|
if err = tx.Where("uuid=?", ctx.Param("uuid")).First(share).Error; err != nil {
|
|
return
|
|
}
|
|
now := time.Now()
|
|
if now.Before(share.Start) || now.After(share.End) {
|
|
err = fmt.Errorf("share expired or not started")
|
|
return
|
|
}
|
|
if share.NoLimit {
|
|
return
|
|
}
|
|
db := tx.Model(share).Where("uuid=? AND times>0", share.Uuid).Update("times", gorm.Expr("times-?", 1))
|
|
if db.Error != nil {
|
|
return
|
|
}
|
|
if db.RowsAffected != 1 {
|
|
err = fmt.Errorf("no times left")
|
|
return
|
|
}
|
|
return
|
|
}); err != nil {
|
|
ctx.Set("shareErr", &ApiError{Code: ErrInvalidArgument, Data: map[string]any{"err": err}})
|
|
}
|
|
|
|
ctx.Params = lo.Filter(ctx.Params, func(p gin.Param, _ int) bool {
|
|
return !lo.Contains([]string{"account_id", "asset_id", "protocol"}, p.Key)
|
|
})
|
|
ctx.Params = append(ctx.Params, gin.Param{Key: "account_id", Value: cast.ToString(share.AccountId)})
|
|
ctx.Params = append(ctx.Params, gin.Param{Key: "asset_id", Value: cast.ToString(share.AssetId)})
|
|
ctx.Params = append(ctx.Params, gin.Param{Key: "protocol", Value: cast.ToString(share.Protocol)})
|
|
ctx.Set("shareId", share.Id)
|
|
ctx.Set("session", &acl.Session{})
|
|
ctx.Set("shareEnd", share.End)
|
|
c.Connect(ctx)
|
|
}
|
|
|
|
func hasPermShare(ctx context.Context, share *model.Share, action string) (ok bool) {
|
|
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
|
|
|
if ok = acl.IsAdmin(currentUser); ok {
|
|
return true
|
|
}
|
|
|
|
_, assetIds, accountIds, err := getNodeAssetAccoutIdsByAction(ctx, action)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
return lo.Contains(assetIds, share.AssetId) || lo.Contains(accountIds, share.AccountId)
|
|
}
|