1
Fork 0

Add timeline resolver tests

This commit is contained in:
viktorstrate 2021-09-27 20:23:10 +02:00
parent 794243e1bd
commit e66a9199a1
No known key found for this signature in database
GPG Key ID: 3F855605109C1E8A
5 changed files with 172 additions and 42 deletions

View File

@ -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
}

View File

@ -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)
})
}

View File

@ -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
}

View File

@ -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) {

View File

@ -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
} }