Add timeline resolver tests
This commit is contained in:
parent
794243e1bd
commit
e66a9199a1
|
@ -0,0 +1,36 @@
|
||||||
|
package actions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/photoview/photoview/api/graphql/models"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MyTimeline(db *gorm.DB, user *models.User, paginate *models.Pagination, onlyFavorites *bool, fromDate *time.Time) ([]*models.Media, error) {
|
||||||
|
query := db.
|
||||||
|
Joins("JOIN albums ON media.album_id = albums.id").
|
||||||
|
Where("albums.id IN (?)", db.Table("user_albums").Select("user_albums.album_id").Where("user_id = ?", user.ID)).
|
||||||
|
Order("YEAR(media.date_shot) DESC").
|
||||||
|
Order("MONTH(media.date_shot) DESC").
|
||||||
|
Order("DAY(media.date_shot) DESC").
|
||||||
|
Order("albums.title ASC").
|
||||||
|
Order("TIME(media.date_shot) DESC")
|
||||||
|
|
||||||
|
if fromDate != nil {
|
||||||
|
query = query.Where("media.date_shot < ?", fromDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
if onlyFavorites != nil && *onlyFavorites == true {
|
||||||
|
query = query.Where("media.id IN (?)", db.Table("user_media_data").Select("user_media_data.media_id").Where("user_media_data.user_id = ?", user.ID).Where("user_media_data.favorite = 1"))
|
||||||
|
}
|
||||||
|
|
||||||
|
query = models.FormatSQL(query, nil, paginate)
|
||||||
|
|
||||||
|
var media []*models.Media
|
||||||
|
if err := query.Find(&media).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return media, nil
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
package actions_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/photoview/photoview/api/graphql/models"
|
||||||
|
"github.com/photoview/photoview/api/graphql/models/actions"
|
||||||
|
"github.com/photoview/photoview/api/test_utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMyTimeline(t *testing.T) {
|
||||||
|
db := test_utils.DatabaseTest(t)
|
||||||
|
|
||||||
|
password := "1234"
|
||||||
|
user, err := models.RegisterUser(db, "user", &password, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
rootAlbum := models.Album{
|
||||||
|
Title: "root",
|
||||||
|
Path: "/photos",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NoError(t, db.Save(&rootAlbum).Error)
|
||||||
|
|
||||||
|
childAlbum := models.Album{
|
||||||
|
Title: "subalbum",
|
||||||
|
Path: "/photos/subalbum",
|
||||||
|
ParentAlbumID: &rootAlbum.ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NoError(t, db.Save(&childAlbum).Error)
|
||||||
|
|
||||||
|
assert.NoError(t, db.Model(&user).Association("Albums").Append(&rootAlbum))
|
||||||
|
assert.NoError(t, db.Model(&user).Association("Albums").Append(&childAlbum))
|
||||||
|
|
||||||
|
media := []models.Media{
|
||||||
|
{
|
||||||
|
Title: "pic1",
|
||||||
|
Path: "/photos/pic1",
|
||||||
|
AlbumID: rootAlbum.ID,
|
||||||
|
DateShot: time.Unix(1632758400, 0), // Sep 27 2021 16:00:00
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Title: "pic2",
|
||||||
|
Path: "/photos/pic2",
|
||||||
|
AlbumID: rootAlbum.ID,
|
||||||
|
DateShot: time.Unix(1628762400, 0), // Aug 12 2021 10:00:00
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Title: "pic3",
|
||||||
|
Path: "/photos/subalbum/pic3",
|
||||||
|
AlbumID: childAlbum.ID,
|
||||||
|
DateShot: time.Unix(1632763800, 0), // Sep 27 2021 17:30:00
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Title: "pic4",
|
||||||
|
Path: "/photos/subalbum/pic4",
|
||||||
|
AlbumID: childAlbum.ID,
|
||||||
|
DateShot: time.Unix(1628775900, 0), // Aug 12 2021 13:45:00
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NoError(t, db.Save(&media).Error)
|
||||||
|
|
||||||
|
_, err = user.FavoriteMedia(db, media[0].ID, true)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Add media not owned by first user
|
||||||
|
anotherUser, err := models.RegisterUser(db, "user2", &password, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
anotherAlbum := models.Album{
|
||||||
|
Title: "AnotherAlbum",
|
||||||
|
Path: "/another",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NoError(t, db.Save(&anotherAlbum).Error)
|
||||||
|
|
||||||
|
anotherMedia := models.Media{
|
||||||
|
Title: "anotherPic",
|
||||||
|
Path: "/another/anotherPic",
|
||||||
|
AlbumID: anotherAlbum.ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NoError(t, db.Save(&anotherMedia).Error)
|
||||||
|
assert.NoError(t, db.Model(&anotherUser).Association("Albums").Append(&anotherAlbum))
|
||||||
|
|
||||||
|
t.Run("MyTimeline with no filters", func(t *testing.T) {
|
||||||
|
timelineMedia, err := actions.MyTimeline(db, user, nil, nil, nil)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, timelineMedia, 4)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("MyTimeline with only favorites", func(t *testing.T) {
|
||||||
|
favorites := true
|
||||||
|
timelineMedia, err := actions.MyTimeline(db, user, nil, &favorites, nil)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, timelineMedia, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("MyTimeline before date", func(t *testing.T) {
|
||||||
|
beforeDate := time.Unix(1629792000, 0) // Aug 24 2021 08:00:00
|
||||||
|
timelineMedia, err := actions.MyTimeline(db, user, nil, nil, &beforeDate)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, timelineMedia, 2)
|
||||||
|
})
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
|
@ -185,3 +186,23 @@ func (user *User) OwnsAlbum(db *gorm.DB, album *Album) (bool, error) {
|
||||||
|
|
||||||
return len(ownedParents) > 0, nil
|
return len(ownedParents) > 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FavoriteMedia sets/clears a media as favorite for the user
|
||||||
|
func (user *User) FavoriteMedia(db *gorm.DB, mediaID int, favorite bool) (*Media, error) {
|
||||||
|
userMediaData := UserMediaData{
|
||||||
|
UserID: user.ID,
|
||||||
|
MediaID: mediaID,
|
||||||
|
Favorite: favorite,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Clauses(clause.OnConflict{UpdateAll: true}).Create(&userMediaData).Error; err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "update user favorite media in database")
|
||||||
|
}
|
||||||
|
|
||||||
|
var media Media
|
||||||
|
if err := db.First(&media, mediaID).Error; err != nil {
|
||||||
|
return nil, errors.Wrap(err, "get media from database after favorite update")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &media, nil
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"github.com/photoview/photoview/api/graphql/models/actions"
|
"github.com/photoview/photoview/api/graphql/models/actions"
|
||||||
"github.com/photoview/photoview/api/scanner/face_detection"
|
"github.com/photoview/photoview/api/scanner/face_detection"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gorm.io/gorm/clause"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *queryResolver) MyMedia(ctx context.Context, order *models.Ordering, paginate *models.Pagination) ([]*models.Media, error) {
|
func (r *queryResolver) MyMedia(ctx context.Context, order *models.Ordering, paginate *models.Pagination) ([]*models.Media, error) {
|
||||||
|
@ -198,22 +197,7 @@ func (r *mutationResolver) FavoriteMedia(ctx context.Context, mediaID int, favor
|
||||||
return nil, auth.ErrUnauthorized
|
return nil, auth.ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
userMediaData := models.UserMediaData{
|
return user.FavoriteMedia(r.Database, mediaID, favorite)
|
||||||
UserID: user.ID,
|
|
||||||
MediaID: mediaID,
|
|
||||||
Favorite: favorite,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := r.Database.Clauses(clause.OnConflict{UpdateAll: true}).Create(&userMediaData).Error; err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "update user favorite media in database")
|
|
||||||
}
|
|
||||||
|
|
||||||
var media models.Media
|
|
||||||
if err := r.Database.First(&media, mediaID).Error; err != nil {
|
|
||||||
return nil, errors.Wrap(err, "get media from database after favorite update")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &media, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *mediaResolver) Faces(ctx context.Context, media *models.Media) ([]*models.ImageFace, error) {
|
func (r *mediaResolver) Faces(ctx context.Context, media *models.Media) ([]*models.ImageFace, error) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/photoview/photoview/api/graphql/auth"
|
"github.com/photoview/photoview/api/graphql/auth"
|
||||||
"github.com/photoview/photoview/api/graphql/models"
|
"github.com/photoview/photoview/api/graphql/models"
|
||||||
|
"github.com/photoview/photoview/api/graphql/models/actions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *queryResolver) MyTimeline(ctx context.Context, paginate *models.Pagination, onlyFavorites *bool, fromDate *time.Time) ([]*models.Media, error) {
|
func (r *queryResolver) MyTimeline(ctx context.Context, paginate *models.Pagination, onlyFavorites *bool, fromDate *time.Time) ([]*models.Media, error) {
|
||||||
|
@ -14,29 +15,5 @@ func (r *queryResolver) MyTimeline(ctx context.Context, paginate *models.Paginat
|
||||||
return nil, auth.ErrUnauthorized
|
return nil, auth.ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
query := r.Database.
|
return actions.MyTimeline(r.Database, user, paginate, onlyFavorites, fromDate)
|
||||||
Joins("JOIN albums ON media.album_id = albums.id").
|
|
||||||
Where("albums.id IN (?)", r.Database.Table("user_albums").Select("user_albums.album_id").Where("user_id = ?", user.ID)).
|
|
||||||
Order("YEAR(media.date_shot) DESC").
|
|
||||||
Order("MONTH(media.date_shot) DESC").
|
|
||||||
Order("DAY(media.date_shot) DESC").
|
|
||||||
Order("albums.title ASC").
|
|
||||||
Order("TIME(media.date_shot) DESC")
|
|
||||||
|
|
||||||
if fromDate != nil {
|
|
||||||
query = query.Where("media.date_shot < ?", fromDate)
|
|
||||||
}
|
|
||||||
|
|
||||||
if onlyFavorites != nil && *onlyFavorites == true {
|
|
||||||
query = query.Where("media.id IN (?)", r.Database.Table("user_media_data").Select("user_media_data.media_id").Where("user_media_data.user_id = ?", user.ID).Where("user_media_data.favorite = 1"))
|
|
||||||
}
|
|
||||||
|
|
||||||
query = models.FormatSQL(query, nil, paginate)
|
|
||||||
|
|
||||||
var media []*models.Media
|
|
||||||
if err := query.Find(&media).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return media, nil
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue