Improve scanner_album NewRootPath tests
This commit is contained in:
parent
253f126aaf
commit
542e5c8532
|
@ -159,6 +159,7 @@ var database_models []interface{} = []interface{}{
|
||||||
&models.VideoMetadata{},
|
&models.VideoMetadata{},
|
||||||
&models.ShareToken{},
|
&models.ShareToken{},
|
||||||
&models.UserMediaData{},
|
&models.UserMediaData{},
|
||||||
|
&models.UserAlbums{},
|
||||||
&models.UserPreferences{},
|
&models.UserPreferences{},
|
||||||
|
|
||||||
// Face detection
|
// Face detection
|
||||||
|
@ -167,9 +168,12 @@ var database_models []interface{} = []interface{}{
|
||||||
}
|
}
|
||||||
|
|
||||||
func MigrateDatabase(db *gorm.DB) error {
|
func MigrateDatabase(db *gorm.DB) error {
|
||||||
err := db.AutoMigrate(database_models...)
|
|
||||||
|
|
||||||
if err != nil {
|
if err := db.SetupJoinTable(&models.User{}, "Albums", &models.UserAlbums{}); err != nil {
|
||||||
|
log.Printf("Setup UserAlbums join table failed: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.AutoMigrate(database_models...); err != nil {
|
||||||
log.Printf("Auto migration failed: %v\n", err)
|
log.Printf("Auto migration failed: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,8 +184,7 @@ func MigrateDatabase(db *gorm.DB) error {
|
||||||
|
|
||||||
// v2.3.0 - Changed type of MediaEXIF.Exposure and MediaEXIF.Flash
|
// v2.3.0 - Changed type of MediaEXIF.Exposure and MediaEXIF.Flash
|
||||||
// from string values to decimal and int respectively
|
// from string values to decimal and int respectively
|
||||||
err = migrate_exif_fields(db)
|
if err := migrate_exif_fields(db); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to run exif fields migration: %v\n", err)
|
log.Printf("Failed to run exif fields migration: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ type Album struct {
|
||||||
ParentAlbum *Album `gorm:"constraint:OnDelete:SET NULL;"`
|
ParentAlbum *Album `gorm:"constraint:OnDelete:SET NULL;"`
|
||||||
// OwnerID int `gorm:"not null"`
|
// OwnerID int `gorm:"not null"`
|
||||||
// Owner User
|
// Owner User
|
||||||
Owners []User `gorm:"many2many:user_albums"`
|
Owners []User `gorm:"many2many:user_albums;constraint:OnDelete:CASCADE;"`
|
||||||
Path string `gorm:"not null"`
|
Path string `gorm:"not null"`
|
||||||
PathHash string `gorm:"unique"`
|
PathHash string `gorm:"unique"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@ package models
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -17,7 +15,7 @@ type User struct {
|
||||||
Username string `gorm:"unique;size:128"`
|
Username string `gorm:"unique;size:128"`
|
||||||
Password *string `gorm:"size:256"`
|
Password *string `gorm:"size:256"`
|
||||||
// RootPath string `gorm:"size:512`
|
// RootPath string `gorm:"size:512`
|
||||||
Albums []Album `gorm:"many2many:user_albums"`
|
Albums []Album `gorm:"many2many:user_albums;constraint:OnDelete:CASCADE;"`
|
||||||
Admin bool `gorm:"default:false"`
|
Admin bool `gorm:"default:false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +26,11 @@ type UserMediaData struct {
|
||||||
Favorite bool `gorm:"not null;default:false"`
|
Favorite bool `gorm:"not null;default:false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserAlbums struct {
|
||||||
|
UserID int `gorm:"primaryKey;autoIncrement:false;constraint:OnDelete:CASCADE;"`
|
||||||
|
AlbumID int `gorm:"primaryKey;autoIncrement:false;constraint:OnDelete:CASCADE;"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessToken struct {
|
type AccessToken struct {
|
||||||
Model
|
Model
|
||||||
UserID int `gorm:"not null;index"`
|
UserID int `gorm:"not null;index"`
|
||||||
|
@ -95,18 +98,6 @@ func AuthorizeUser(db *gorm.DB, username string, password string) (*User, error)
|
||||||
return &user, nil
|
return &user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var ErrorInvalidRootPath = errors.New("invalid root path")
|
|
||||||
|
|
||||||
func ValidRootPath(rootPath string) bool {
|
|
||||||
_, err := os.Stat(rootPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Warn: invalid root path: '%s'\n%s\n", rootPath, err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterUser(db *gorm.DB, username string, password *string, admin bool) (*User, error) {
|
func RegisterUser(db *gorm.DB, username string, password *string, admin bool) (*User, error) {
|
||||||
user := User{
|
user := User{
|
||||||
Username: username,
|
Username: username,
|
||||||
|
|
|
@ -2,11 +2,9 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
api "github.com/photoview/photoview/api/graphql"
|
api "github.com/photoview/photoview/api/graphql"
|
||||||
"github.com/photoview/photoview/api/graphql/auth"
|
"github.com/photoview/photoview/api/graphql/auth"
|
||||||
|
@ -314,39 +312,6 @@ func (r *mutationResolver) UserAddRootPath(ctx context.Context, id int, rootPath
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !models.ValidRootPath(rootPath) {
|
|
||||||
return nil, errors.New("invalid root path")
|
|
||||||
}
|
|
||||||
|
|
||||||
upperPaths := make([]string, 1)
|
|
||||||
upperPath := rootPath
|
|
||||||
upperPaths[0] = upperPath
|
|
||||||
for {
|
|
||||||
|
|
||||||
substrIndex := strings.LastIndex(upperPath, "/")
|
|
||||||
if substrIndex == -1 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if substrIndex == 0 {
|
|
||||||
upperPaths = append(upperPaths, "/")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
upperPath = upperPath[0:substrIndex]
|
|
||||||
upperPaths = append(upperPaths, upperPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
var upperAlbums []models.Album
|
|
||||||
if err := r.Database.Model(&user).Association("Albums").Find(&upperAlbums, "albums.path IN (?)", upperPaths); err != nil {
|
|
||||||
// if err := r.Database.Model(models.Album{}).Where("path IN (?)", upperPaths).Find(&upperAlbums).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(upperAlbums) > 0 {
|
|
||||||
return nil, errors.New(fmt.Sprintf("user already owns a path containing this path: %s", upperAlbums[0].Path))
|
|
||||||
}
|
|
||||||
|
|
||||||
newAlbum, err := scanner.NewRootAlbum(r.Database, rootPath, &user)
|
newAlbum, err := scanner.NewRootAlbum(r.Database, rootPath, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -18,6 +19,19 @@ import (
|
||||||
|
|
||||||
func NewRootAlbum(db *gorm.DB, rootPath string, owner *models.User) (*models.Album, error) {
|
func NewRootAlbum(db *gorm.DB, rootPath string, owner *models.User) (*models.Album, error) {
|
||||||
|
|
||||||
|
if !ValidRootPath(rootPath) {
|
||||||
|
return nil, ErrorInvalidRootPath
|
||||||
|
}
|
||||||
|
|
||||||
|
if !path.IsAbs(rootPath) {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rootPath = path.Join(wd, rootPath)
|
||||||
|
}
|
||||||
|
|
||||||
owners := []models.User{
|
owners := []models.User{
|
||||||
*owner,
|
*owner,
|
||||||
}
|
}
|
||||||
|
@ -36,7 +50,7 @@ func NewRootAlbum(db *gorm.DB, rootPath string, owner *models.User) (*models.Alb
|
||||||
}
|
}
|
||||||
|
|
||||||
if matchedUserAlbumCount > 0 {
|
if matchedUserAlbumCount > 0 {
|
||||||
return nil, errors.New(fmt.Sprintf("user already owns path (%s)", rootPath))
|
return nil, errors.New(fmt.Sprintf("user already owns a path containing this path: %s", rootPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := db.Model(&owner).Association("Albums").Append(&album); err != nil {
|
if err := db.Model(&owner).Association("Albums").Append(&album); err != nil {
|
||||||
|
@ -59,6 +73,18 @@ func NewRootAlbum(db *gorm.DB, rootPath string, owner *models.User) (*models.Alb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrorInvalidRootPath = errors.New("invalid root path")
|
||||||
|
|
||||||
|
func ValidRootPath(rootPath string) bool {
|
||||||
|
_, err := os.Stat(rootPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Warn: invalid root path: '%s'\n%s\n", rootPath, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func scanAlbum(album *models.Album, cache *AlbumScannerCache, db *gorm.DB) {
|
func scanAlbum(album *models.Album, cache *AlbumScannerCache, db *gorm.DB) {
|
||||||
|
|
||||||
album_notify_key := utils.GenerateToken()
|
album_notify_key := utils.GenerateToken()
|
||||||
|
|
|
@ -27,7 +27,7 @@ func TestNewRootPath(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.NotNil(t, album)
|
assert.NotNil(t, album)
|
||||||
assert.Equal(t, "./test_data", album.Path)
|
assert.Contains(t, album.Path, "/api/scanner/test_data")
|
||||||
assert.NotEmpty(t, album.Owners)
|
assert.NotEmpty(t, album.Owners)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -36,7 +36,37 @@ func TestNewRootPath(t *testing.T) {
|
||||||
_, err := scanner.NewRootAlbum(db, "./test_data", &user)
|
_, err := scanner.NewRootAlbum(db, "./test_data", &user)
|
||||||
|
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, err.Error(), "user already owns path (./test_data)")
|
assert.Contains(t, err.Error(), "user already owns a path containing this path:")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Insert invalid root album", func(t *testing.T) {
|
||||||
|
|
||||||
|
_, err := scanner.NewRootAlbum(db, "./invalid_path", &user)
|
||||||
|
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, err.Error(), "invalid root path")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Add existing root album to new user", func(t *testing.T) {
|
||||||
|
|
||||||
|
user2 := models.User{
|
||||||
|
Username: "user2",
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assert.NoError(t, db.Save(&user2).Error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
album, err := scanner.NewRootAlbum(db, "./test_data", &user2)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NotNil(t, album)
|
||||||
|
assert.Contains(t, album.Path, "/api/scanner/test_data")
|
||||||
|
|
||||||
|
owner_count := db.Model(&album).Association("Owners").Count()
|
||||||
|
assert.EqualValues(t, 2, owner_count)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,10 @@ func (dbm *TestDBManager) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := dbm.reset(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
sqlDB, err := dbm.DB.DB()
|
sqlDB, err := dbm.DB.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "get db instance when closing test database")
|
return errors.Wrap(err, "get db instance when closing test database")
|
||||||
|
@ -47,7 +51,9 @@ func (dbm *TestDBManager) setup() error {
|
||||||
|
|
||||||
dbm.DB = db
|
dbm.DB = db
|
||||||
|
|
||||||
dbm.reset()
|
if err := dbm.reset(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue