feat: assign per-user WebDAV paths
This commit is contained in:
+17
-3
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -14,6 +15,8 @@ func (a *App) audit(operator uint, action, targetType, targetID, metadata string
|
|||||||
_ = a.db.Create(&AuditLog{OperatorID: operator, Action: action, TargetType: targetType, TargetID: targetID, Metadata: metadata}).Error
|
_ = a.db.Create(&AuditLog{OperatorID: operator, Action: action, TargetType: targetType, TargetID: targetID, Metadata: metadata}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var usernamePattern = regexp.MustCompile(`^[A-Za-z]{4,10}$`)
|
||||||
|
|
||||||
func defaultPermissions(role string) []string {
|
func defaultPermissions(role string) []string {
|
||||||
if role == RolePrivileged {
|
if role == RolePrivileged {
|
||||||
return []string{PermDownload, PermRedeem, PermWebDAV, PermWebDAVConfig}
|
return []string{PermDownload, PermRedeem, PermWebDAV, PermWebDAVConfig}
|
||||||
@@ -59,8 +62,13 @@ func (a *App) adminCreateUser(c *gin.Context) {
|
|||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
Credits int64 `json:"credits"`
|
Credits int64 `json:"credits"`
|
||||||
}
|
}
|
||||||
if c.BindJSON(&in) != nil || strings.TrimSpace(in.Username) == "" || len(in.Password) < 8 {
|
if c.BindJSON(&in) != nil {
|
||||||
c.JSON(400, gin.H{"error": "username and password(8+) required"})
|
c.JSON(400, gin.H{"error": "invalid request body"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
in.Username = strings.TrimSpace(in.Username)
|
||||||
|
if !usernamePattern.MatchString(in.Username) || len(in.Password) < 8 {
|
||||||
|
c.JSON(400, gin.H{"error": "username must be 4-10 English letters and password must be 8+ characters"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if in.Role == "" {
|
if in.Role == "" {
|
||||||
@@ -78,10 +86,16 @@ func (a *App) adminCreateUser(c *gin.Context) {
|
|||||||
admin := c.MustGet("user").(*User)
|
admin := c.MustGet("user").(*User)
|
||||||
var u User
|
var u User
|
||||||
err = a.db.Transaction(func(tx *gorm.DB) error {
|
err = a.db.Transaction(func(tx *gorm.DB) error {
|
||||||
u = User{Username: strings.TrimSpace(in.Username), PasswordHash: hash, Role: in.Role, Status: UserActive}
|
u = User{Username: in.Username, PasswordHash: hash, Role: in.Role, Status: UserActive}
|
||||||
if err := tx.Create(&u).Error; err != nil {
|
if err := tx.Create(&u).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if in.Role != RoleAdmin {
|
||||||
|
root := cleanWebDAVRoot(strings.TrimRight(a.cfg.WebDAVPath, "/") + "/" + u.Username)
|
||||||
|
if err := tx.Create(&WebDAVConfig{UserID: u.ID, Enabled: true, RootPath: root}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := tx.Create(&CreditAccount{UserID: u.ID, Balance: in.Credits}).Error; err != nil {
|
if err := tx.Create(&CreditAccount{UserID: u.ID, Balance: in.Credits}).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ func main() {
|
|||||||
a := &App{db: db, cfg: cfg, queue: make(chan uint, 100), httpClient: client}
|
a := &App{db: db, cfg: cfg, queue: make(chan uint, 100), httpClient: client}
|
||||||
a.loadSettings()
|
a.loadSettings()
|
||||||
a.bootstrapAdmin()
|
a.bootstrapAdmin()
|
||||||
|
must(a.initializeUserWebDAVDefaults())
|
||||||
must(backfillMediaAssets(db, a.cfg.DownloadDir))
|
must(backfillMediaAssets(db, a.cfg.DownloadDir))
|
||||||
if os.Getenv("MIGRATION_CHECK") == "1" {
|
if os.Getenv("MIGRATION_CHECK") == "1" {
|
||||||
var users, tasks, assets int64
|
var users, tasks, assets int64
|
||||||
|
|||||||
+40
-2
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/studio-b12/gowebdav"
|
"github.com/studio-b12/gowebdav"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func cleanWebDAVRoot(root string) string {
|
func cleanWebDAVRoot(root string) string {
|
||||||
@@ -18,6 +19,28 @@ func cleanWebDAVRoot(root string) string {
|
|||||||
return strings.Trim(root, "/")
|
return strings.Trim(root, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) initializeUserWebDAVDefaults() error {
|
||||||
|
var users []User
|
||||||
|
if err := a.db.Where("role <> ?", RoleAdmin).Find(&users).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, user := range users {
|
||||||
|
var cfg WebDAVConfig
|
||||||
|
err := a.db.Where("user_id = ?", user.ID).First(&cfg).Error
|
||||||
|
if err == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != gorm.ErrRecordNotFound {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
root := cleanWebDAVRoot(strings.TrimRight(a.cfg.WebDAVPath, "/") + "/" + user.Username)
|
||||||
|
if err := a.db.Create(&WebDAVConfig{UserID: user.ID, Enabled: true, RootPath: root}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) getUserWebDAV(c *gin.Context) {
|
func (a *App) getUserWebDAV(c *gin.Context) {
|
||||||
user := c.MustGet("user").(*User)
|
user := c.MustGet("user").(*User)
|
||||||
var cfg WebDAVConfig
|
var cfg WebDAVConfig
|
||||||
@@ -98,6 +121,10 @@ func (a *App) storageForTask(t *Task) (RemoteStorage, string, bool) {
|
|||||||
if a.cfg.WebDAVURL == "" || a.storage == nil {
|
if a.cfg.WebDAVURL == "" || a.storage == nil {
|
||||||
return nil, "", false
|
return nil, "", false
|
||||||
}
|
}
|
||||||
|
var cfg WebDAVConfig
|
||||||
|
if a.db.Where("user_id = ?", user.ID).First(&cfg).Error == nil && cfg.RootPath != "" {
|
||||||
|
return a.storage, cfg.RootPath, true
|
||||||
|
}
|
||||||
return a.storage, a.cfg.WebDAVPath, true
|
return a.storage, a.cfg.WebDAVPath, true
|
||||||
}
|
}
|
||||||
if user.Role == RoleAdmin {
|
if user.Role == RoleAdmin {
|
||||||
@@ -107,13 +134,24 @@ func (a *App) storageForTask(t *Task) (RemoteStorage, string, bool) {
|
|||||||
return a.storage, a.cfg.WebDAVPath, true
|
return a.storage, a.cfg.WebDAVPath, true
|
||||||
}
|
}
|
||||||
var cfg WebDAVConfig
|
var cfg WebDAVConfig
|
||||||
if a.db.Where("user_id = ? AND enabled = ?", user.ID, true).First(&cfg).Error != nil || cfg.URL == "" {
|
if a.db.Where("user_id = ? AND enabled = ?", user.ID, true).First(&cfg).Error != nil {
|
||||||
// Privileged users fall back to the global WebDAV until a custom
|
// Privileged users fall back to the global WebDAV until a custom
|
||||||
// WebDAV configuration is enabled and tested successfully.
|
// WebDAV configuration is enabled.
|
||||||
if a.cfg.WebDAVURL == "" || a.storage == nil {
|
if a.cfg.WebDAVURL == "" || a.storage == nil {
|
||||||
return nil, "", false
|
return nil, "", false
|
||||||
}
|
}
|
||||||
return a.storage, a.cfg.WebDAVPath, true
|
return a.storage, a.cfg.WebDAVPath, true
|
||||||
}
|
}
|
||||||
|
if cfg.URL == "" {
|
||||||
|
// An empty URL means this user inherits the global WebDAV connection,
|
||||||
|
// while keeping the user's own destination path.
|
||||||
|
if a.cfg.WebDAVURL == "" || a.storage == nil {
|
||||||
|
return nil, "", false
|
||||||
|
}
|
||||||
|
if cfg.RootPath != "" {
|
||||||
|
return a.storage, cfg.RootPath, true
|
||||||
|
}
|
||||||
|
return a.storage, a.cfg.WebDAVPath, true
|
||||||
|
}
|
||||||
return NewWebDAVStorage(Config{WebDAVURL: cfg.URL, WebDAVUser: cfg.Username, WebDAVPass: cfg.Password}), cfg.RootPath, true
|
return NewWebDAVStorage(Config{WebDAVURL: cfg.URL, WebDAVUser: cfg.Username, WebDAVPass: cfg.Password}), cfg.RootPath, true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user