Skip to content

Commit

Permalink
feat: torrent edit api (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tohrusky authored Jul 23, 2024
1 parent cd38d7a commit eeea8ae
Show file tree
Hide file tree
Showing 12 changed files with 120 additions and 38 deletions.
10 changes: 10 additions & 0 deletions internal/common/db/torrent.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ func CreateTorrent(torrent *model.Torrent) (err error) {
return err
}

// PatchTorrent 更新种子信息,根据 torrentID 和 details 更新种子信息
func PatchTorrent[T *model.Torrent | map[string]any | any](torrentID int32, details T) (err error) {
q := query.Torrent
_, err = q.Where(q.TorrentID.Eq(torrentID)).Updates(details)
if err != nil {
return err
}
return nil
}

// GetTorrentByHash 根据 Hash 获取种子
func GetTorrentByHash(hash string) (*model.Torrent, error) {
q := query.Torrent
Expand Down
2 changes: 1 addition & 1 deletion internal/common/db/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func CreateUser(user *model.User) (err error) {
}

// PatchUser 更新用户信息,根据 userID 和 details 更新用户信息
func PatchUser(userID int32, details *model.User) (err error) {
func PatchUser[T *model.User | map[string]any | any](userID int32, details T) (err error) {
q := query.User
ResultInfo, err := q.Where(q.UserID.Eq(userID)).Updates(details)
if err != nil {
Expand Down
28 changes: 15 additions & 13 deletions internal/middleware/rbac/access_control.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/gin-gonic/gin"
)

// RABC 获取用户角色,存入上下文,进行权限控制,allowRoles 为允许的角色
// RABC 获取用户角色,存入上下文,进行权限控制,allowRoles 为允许的角色,为空则不限制
func RABC(allowRoles ...string) gin.HandlerFunc {
return func(c *gin.Context) {
userID, _ := resp.GetUserIDFromGinContext(c)
Expand All @@ -23,20 +23,22 @@ func RABC(allowRoles ...string) gin.HandlerFunc {
return
}

// 检查用户是否有合适的角色
hasAllowedRole := false
for _, role := range roles {
if util.CheckStringInSlice(role, allowRoles) {
hasAllowedRole = true
break
if len(allowRoles) > 0 {
// 检查用户是否有合适的角色
hasAllowedRole := false
for _, role := range roles {
if util.CheckStringInSlice(role, allowRoles) {
hasAllowedRole = true
break
}
}
}

// 用户没有合适的角色,拦截请求
if !hasAllowedRole {
resp.AbortWithMsg(c, code.AuthErrorNoPermission, "Role has no permission")
log.Logger.Errorf("RABC Role has no permission, userID: %d, roles: %v", userID, roles)
return
// 用户没有合适的角色,拦截请求
if !hasAllowedRole {
resp.AbortWithMsg(c, code.AuthErrorNoPermission, "Role has no permission")
log.Logger.Errorf("RABC Role has no permission, userID: %d, roles: %v", userID, roles)
return
}
}

// 将角色信息存储在 Gin 上下文中
Expand Down
6 changes: 5 additions & 1 deletion internal/router/api/v1/torrent.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ func TorrentRouterGroup(api *gin.RouterGroup) {
jwt.RequireAuth(false),
rbac.RABC(role.ADMIN, role.UPLOADER, role.ADVANCED_USER),
torrent_service.Upload)

// 种子编辑
torrent.POST("edit",
jwt.RequireAuth(false),
rbac.RABC(),
torrent_service.Edit)
// 获取种子文件列表
torrent.GET("filelist",
jwt.RequireAuth(false),
Expand Down
68 changes: 68 additions & 0 deletions internal/service/torrent/edit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package torrent

import (
"github.com/TensoRaws/NuxBT-Backend/internal/common/db"
"github.com/TensoRaws/NuxBT-Backend/module/code"
"github.com/TensoRaws/NuxBT-Backend/module/log"
"github.com/TensoRaws/NuxBT-Backend/module/resp"
"github.com/TensoRaws/NuxBT-Backend/module/role"
"github.com/TensoRaws/NuxBT-Backend/module/util"
"github.com/gin-gonic/gin"
)

type EditRequest struct {
TorrentID int32 `form:"torrent_id" binding:"required"`
AnidbID int32 `form:"anidb_id" binding:"required"`
AudioCodec string `form:"audio_codec" binding:"required,oneof=FLAC AAC AC3 DTS DDP LPCM other"`
Description string `form:"description" binding:"required"`
Essay string `form:"essay" binding:"required"`
Genre string `form:"genre" binding:"required,oneof=BDrip WEBrip DVDrip Remux Blu-ray WEB-DL DVD HDTV other"` //nolint:lll
Img string `form:"img" binding:"required"`
Language string `form:"language" binding:"required,oneof=Chinese English Japanese other"`
Resolution string `form:"resolution" binding:"required,oneof=480p 720p 1080p 2160p other"`
Subtitle string `form:"subtitle" binding:"required"`
Title string `form:"title" binding:"required"`
VideoCodec string `form:"video_codec" binding:"required,oneof=H.265 H.264 AV1 VP9 other"`
}

// Edit 更新种子信息 (POST /edit)
func Edit(c *gin.Context) {
// 参数绑定
var req EditRequest
if err := c.ShouldBind(&req); err != nil {
resp.AbortWithMsg(c, code.RequestErrorInvalidParams, err.Error())
return
}

userID, _ := resp.GetUserIDFromGinContext(c)

roles, err := resp.GetRolesFromGinContext(c)
if err != nil {
resp.AbortWithMsg(c, code.UnknownError, err.Error())
log.Logger.Error("failed to get roles from gin context: " + err.Error())
return
}

bt, err := db.GetTorrentByID(req.TorrentID)
if err != nil {
resp.AbortWithMsg(c, code.DatabaseErrorRecordNotFound, err.Error())
log.Logger.Error("failed to get torrent by id: " + err.Error())
return
}

if bt.UploaderID != userID && !util.CheckStringInSlice(role.ADMIN, roles) {
resp.AbortWithMsg(c, code.AuthErrorNoPermission, "permission denied")
log.Logger.Errorf("permission denied, user id: %v", userID)
return
}

err = db.PatchTorrent(req.TorrentID, &req)
if err != nil {
resp.AbortWithMsg(c, code.DatabaseErrorRecordPatchFailed, err.Error())
return
}

resp.OK(c)

log.Logger.Infof("update torrent info success, torrent id: %v", req.TorrentID)
}
2 changes: 1 addition & 1 deletion internal/service/torrent/filelist.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type FileListRequest struct {

type FileListResponse []torrent.BitTorrentFileListItem

// FileList 获取种子文件列表
// FileList 获取种子文件列表 (GET /filelist)
func FileList(c *gin.Context) {
// 绑定参数
var req FileListRequest
Expand Down
1 change: 1 addition & 0 deletions internal/service/torrent/official.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package torrent
4 changes: 2 additions & 2 deletions internal/service/torrent/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type UploadRequest struct {
AnidbID int32 `form:"anidb_id" binding:"required"`
AudioCodec string `form:"audio_codec" binding:"required,oneof=FLAC AAC AC3 DTS DDP LPCM other"`
Description string `form:"description" binding:"required"`
Essay *string `form:"essay" binding:"omitempty"`
Essay string `form:"essay" binding:"required"`
Genre string `form:"genre" binding:"required,oneof=BDrip WEBrip DVDrip Remux Blu-ray WEB-DL DVD HDTV other"` //nolint:lll
Img string `form:"img" binding:"required"`
Language string `form:"language" binding:"required,oneof=Chinese English Japanese other"`
Expand Down Expand Up @@ -131,7 +131,7 @@ func Upload(c *gin.Context) {
Status: status,
Title: req.Title,
Subtitle: req.Subtitle,
Essay: *req.Essay,
Essay: req.Essay,
Description: req.Description,
Genre: req.Genre,
AnidbID: req.AnidbID,
Expand Down
1 change: 1 addition & 0 deletions internal/service/user/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type ProfileOthersRequest struct {
func ProfileMe(c *gin.Context) {
userID, _ := resp.GetUserIDFromGinContext(c)

// 更新活跃时间
err := db.PatchUser(userID, &model.User{LastActive: time.Now()})
if err != nil {
resp.AbortWithMsg(c, code.UnknownError, err.Error())
Expand Down
30 changes: 14 additions & 16 deletions internal/service/user/profile_update.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package user

import (
"github.com/TensoRaws/NuxBT-Backend/dal/model"
"github.com/TensoRaws/NuxBT-Backend/internal/common/db"
"github.com/TensoRaws/NuxBT-Backend/module/code"
"github.com/TensoRaws/NuxBT-Backend/module/log"
Expand All @@ -11,12 +10,12 @@ import (
)

type ProfileUpdateRequest struct {
Avatar *string `json:"avatar" binding:"omitempty"`
Background *string `json:"background" binding:"omitempty"`
Email *string `json:"email" binding:"omitempty,email"`
Private *bool `json:"private" binding:"omitempty"`
Signature *string `json:"signature" binding:"omitempty"`
Username *string `json:"username" binding:"omitempty"`
Avatar string `json:"avatar" binding:"required"`
Background string `json:"background" binding:"required"`
Email string `json:"email" binding:"required,email"`
Private *bool `json:"private" binding:"required"`
Signature string `json:"signature" binding:"required"`
Username string `json:"username" binding:"required"`
}

// ProfileUpdate 用户信息更新 (POST /profile/update)
Expand All @@ -28,23 +27,22 @@ func ProfileUpdate(c *gin.Context) {
return
}

err := util.CheckUsername(*req.Username)
err := util.CheckUsername(req.Username)
if err != nil {
resp.AbortWithMsg(c, code.UserErrorInvalidUsername, err.Error())
return
}

userID, _ := resp.GetUserIDFromGinContext(c)

// 没传数字,直接序列化嗯造
updateInfo, err := util.StructToMap(req)
if err != nil {
resp.AbortWithMsg(c, code.UnknownError, err.Error())
return
}
// 执行更新
err = db.PatchUser(userID, &model.User{
Avatar: *req.Avatar,
Background: *req.Background,
Email: *req.Email,
Private: *req.Private,
Signature: *req.Signature,
Username: *req.Username,
})
err = db.PatchUser(userID, updateInfo)

if err != nil {
resp.AbortWithMsg(c, code.DatabaseErrorRecordPatchFailed, err.Error())
Expand Down
4 changes: 1 addition & 3 deletions internal/service/user/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ func ResetPassword(c *gin.Context) {
}

// 修改密码
err = db.PatchUser(userID, &model.User{
Password: string(password),
})
err = db.PatchUser(userID, &model.User{Password: string(password)})

if err != nil {
resp.AbortWithMsg(c, code.DatabaseErrorRecordPatchFailed, "reset password fail")
Expand Down
2 changes: 1 addition & 1 deletion module/util/ds.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func StringToStruct(str string, s interface{}) error {
return sonic.Unmarshal([]byte(str), s)
}

// StructToMap 结构体转 map[string]interface{}
// StructToMap 结构体转 map[string]interface{},请勿在有数字情况下使用,请使用反射
func StructToMap(s interface{}) (map[string]interface{}, error) {
// 使用 sonic 将结构体序列化为 JSON
jsonBytes, err := sonic.Marshal(s)
Expand Down

0 comments on commit eeea8ae

Please sign in to comment.