mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2026-05-06 23:31:59 +08:00
feat(sharing): allow custom share IDs (#2353)
feat: allow custom share IDs - Change sharing ID column from char(12) to varchar(64) - Add new_id field to UpdateSharingReq for renaming share IDs - Add ID validation (max 64 chars, alphanumeric/CJK/hyphens/underscores) - Add conflict check when updating share ID - Add customize_share_id permission (bit 15) Closes OpenListTeam/OpenList#1806
This commit is contained in:
@@ -64,6 +64,14 @@ func UpdateSharing(s *model.SharingDB) error {
|
||||
return errors.WithStack(db.Save(s).Error)
|
||||
}
|
||||
|
||||
func UpdateSharingId(oldId, newId string) error {
|
||||
// Check if new ID already exists
|
||||
if err := db.Where("id = ?", newId).First(&model.SharingDB{}).Error; err == nil {
|
||||
return errors.New("sharing id already exists")
|
||||
}
|
||||
return errors.WithStack(db.Model(&model.SharingDB{}).Where("id = ?", oldId).Update("id", newId).Error)
|
||||
}
|
||||
|
||||
func DeleteSharingById(id string) error {
|
||||
s := model.SharingDB{ID: id}
|
||||
return errors.WithStack(db.Where(s).Delete(&s).Error)
|
||||
|
||||
@@ -3,7 +3,7 @@ package model
|
||||
import "time"
|
||||
|
||||
type SharingDB struct {
|
||||
ID string `json:"id" gorm:"type:char(12);primaryKey"`
|
||||
ID string `json:"id" gorm:"type:varchar(64);primaryKey"`
|
||||
FilesRaw string `json:"-" gorm:"type:text"`
|
||||
Expires *time.Time `json:"expires"`
|
||||
Pwd string `json:"pwd"`
|
||||
|
||||
@@ -63,6 +63,7 @@ type User struct {
|
||||
// 12: can read archives
|
||||
// 13: can decompress archives
|
||||
// 14: can share
|
||||
// 15: can customize share id
|
||||
Permission int32 `json:"permission"`
|
||||
OtpSecret string `json:"-"`
|
||||
SsoID string `json:"sso_id"` // unique by sso platform
|
||||
@@ -219,6 +220,14 @@ func (u *User) CanShare() bool {
|
||||
return CanShare(u.Permission)
|
||||
}
|
||||
|
||||
func CanCustomizeShareID(permission int32) bool {
|
||||
return (permission>>15)&1 == 1
|
||||
}
|
||||
|
||||
func (u *User) CanCustomizeShareID() bool {
|
||||
return CanCustomizeShareID(u.Permission)
|
||||
}
|
||||
|
||||
func (u *User) JoinPath(reqPath string) (string, error) {
|
||||
return utils.JoinBasePath(u.BasePath, reqPath)
|
||||
}
|
||||
|
||||
@@ -133,6 +133,15 @@ func UpdateSharing(sharing *model.Sharing, skipMarshal ...bool) (err error) {
|
||||
return db.UpdateSharing(sharing.SharingDB)
|
||||
}
|
||||
|
||||
func UpdateSharingId(sharing *model.Sharing, newId string) error {
|
||||
sharingCache.Del(sharing.ID)
|
||||
if err := db.UpdateSharingId(sharing.ID, newId); err != nil {
|
||||
return err
|
||||
}
|
||||
sharing.ID = newId
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteSharing(sid string) error {
|
||||
sharingCache.Del(sid)
|
||||
return db.DeleteSharingById(sid)
|
||||
|
||||
@@ -3,6 +3,7 @@ package handles
|
||||
import (
|
||||
"fmt"
|
||||
stdpath "path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -416,6 +417,19 @@ type UpdateSharingReq struct {
|
||||
CreatorName string `json:"creator"`
|
||||
Accessed int `json:"accessed"`
|
||||
ID string `json:"id"`
|
||||
NewID string `json:"new_id"`
|
||||
}
|
||||
|
||||
var validSharingID = regexp.MustCompile(`^[\w\p{Han}\-]+$`)
|
||||
|
||||
func validateSharingID(id string) error {
|
||||
if len([]rune(id)) > 64 {
|
||||
return errors.New("share id must be at most 64 characters")
|
||||
}
|
||||
if !validSharingID.MatchString(id) {
|
||||
return errors.New("share id can only contain letters, numbers, underscores, hyphens, and CJK characters")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateSharing(c *gin.Context) {
|
||||
@@ -471,6 +485,20 @@ func UpdateSharing(c *gin.Context) {
|
||||
s.Readme = req.Readme
|
||||
s.Remark = req.Remark
|
||||
s.Creator = user
|
||||
if req.NewID != "" && req.NewID != req.ID {
|
||||
if !reqUser.CanCustomizeShareID() {
|
||||
common.ErrorStrResp(c, "permission denied", 403)
|
||||
return
|
||||
}
|
||||
if err = validateSharingID(req.NewID); err != nil {
|
||||
common.ErrorResp(c, err, 400)
|
||||
return
|
||||
}
|
||||
if err = op.UpdateSharingId(s, req.NewID); err != nil {
|
||||
common.ErrorResp(c, err, 500)
|
||||
return
|
||||
}
|
||||
}
|
||||
if err = op.UpdateSharing(s); err != nil {
|
||||
common.ErrorResp(c, err, 500)
|
||||
} else {
|
||||
@@ -493,6 +521,12 @@ func CreateSharing(c *gin.Context) {
|
||||
common.ErrorStrResp(c, "must add at least 1 object", 400)
|
||||
return
|
||||
}
|
||||
if req.ID != "" {
|
||||
if err = validateSharingID(req.ID); err != nil {
|
||||
common.ErrorResp(c, err, 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
var user *model.User
|
||||
reqUser := c.Request.Context().Value(conf.UserKey).(*model.User)
|
||||
if reqUser.IsAdmin() && req.CreatorName != "" {
|
||||
@@ -503,7 +537,7 @@ func CreateSharing(c *gin.Context) {
|
||||
}
|
||||
} else {
|
||||
user = reqUser
|
||||
if !user.CanShare() || (!user.IsAdmin() && req.ID != "") {
|
||||
if !user.CanShare() || (!user.CanCustomizeShareID() && req.ID != "") {
|
||||
common.ErrorStrResp(c, "permission denied", 403)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user