diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 848aa562..507f3e7c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,6 +12,7 @@ jobs: runs-on: ubuntu-20.04 strategy: + fail-fast: false matrix: database: ['mysql', 'postgres', 'sqlite'] diff --git a/api/graphql/models/actions/album_actions.go b/api/graphql/models/actions/album_actions.go index 6787249e..2c429c8a 100644 --- a/api/graphql/models/actions/album_actions.go +++ b/api/graphql/models/actions/album_actions.go @@ -72,6 +72,41 @@ func Album(db *gorm.DB, user *models.User, id int) (*models.Album, error) { return &album, nil } +func AlbumPath(db *gorm.DB, user *models.User, album *models.Album) ([]*models.Album, error) { + var album_path []*models.Album + + err := db.Raw(` + WITH recursive path_albums AS ( + SELECT * FROM albums anchor WHERE anchor.id = ? + UNION + SELECT parent.* FROM path_albums child JOIN albums parent ON parent.id = child.parent_album_id + ) + SELECT * FROM path_albums WHERE id != ? + `, album.ID, album.ID).Scan(&album_path).Error + + // Make sure to only return albums this user owns + for i := len(album_path) - 1; i >= 0; i-- { + album := album_path[i] + + owns, err := user.OwnsAlbum(db, album) + if err != nil { + return nil, err + } + + if !owns { + album_path = album_path[i+1:] + break + } + + } + + if err != nil { + return nil, err + } + + return album_path, nil +} + func SetAlbumCover(db *gorm.DB, user *models.User, mediaID int) (*models.Album, error) { var media models.Media diff --git a/api/graphql/models/actions/album_actions_test.go b/api/graphql/models/actions/album_actions_test.go index 3cdc4e8d..99a76bfb 100644 --- a/api/graphql/models/actions/album_actions_test.go +++ b/api/graphql/models/actions/album_actions_test.go @@ -9,6 +9,36 @@ import ( "github.com/stretchr/testify/assert" ) +func TestAlbumPath(t *testing.T) { + db := test_utils.DatabaseTest(t) + + album := models.Album{ + Title: "Three", + Path: "/one/two/three", + ParentAlbum: &models.Album{ + Title: "Two", + Path: "/one/two", + ParentAlbum: &models.Album{ + Title: "One", + Path: "/one", + }, + }, + } + + assert.NoError(t, db.Save(&album).Error) + + user, err := models.RegisterUser(db, "user", nil, false) + assert.NoError(t, err) + + db.Model(&user).Association("Albums").Append(album.ParentAlbum.ParentAlbum) + + albumPath, err := actions.AlbumPath(db, user, &album) + assert.NoError(t, err) + assert.Len(t, albumPath, 2) + assert.Equal(t, "Two", albumPath[0].Title) + assert.Equal(t, "One", albumPath[1].Title) +} + func TestAlbumCover(t *testing.T) { db := test_utils.DatabaseTest(t) diff --git a/api/graphql/resolvers/album.go b/api/graphql/resolvers/album.go index b89388e9..d57df3b6 100644 --- a/api/graphql/resolvers/album.go +++ b/api/graphql/resolvers/album.go @@ -131,38 +131,7 @@ func (r *albumResolver) Path(ctx context.Context, obj *models.Album) ([]*models. return empty, nil } - var album_path []*models.Album - - err := r.Database.Raw(` - WITH recursive path_albums AS ( - SELECT * FROM albums anchor WHERE anchor.id = ? - UNION - SELECT parent.* FROM path_albums child JOIN albums parent ON parent.id = child.parent_album_id - ) - SELECT * FROM path_albums WHERE id != ? - `, obj.ID, obj.ID).Scan(&album_path).Error - - // Make sure to only return albums this user owns - for i := len(album_path) - 1; i >= 0; i-- { - album := album_path[i] - - owns, err := user.OwnsAlbum(r.Database, album) - if err != nil { - return nil, err - } - - if !owns { - album_path = album_path[i+1:] - break - } - - } - - if err != nil { - return nil, err - } - - return album_path, nil + return actions.AlbumPath(r.Database, user, obj) } // Takes album_id, resets album.cover_id to 0 (null)