mirror of
https://git.vectorsigma.ru/public/photoview.git
synced 2026-08-03 20:59:03 +00:00
Proof of concept for variable album covers - GQL playground working.
This commit is contained in:
@@ -57,6 +57,7 @@ type DirectiveRoot struct {
|
||||
|
||||
type ComplexityRoot struct {
|
||||
Album struct {
|
||||
CoverID func(childComplexity int) int
|
||||
FilePath func(childComplexity int) int
|
||||
ID func(childComplexity int) int
|
||||
Media func(childComplexity int, order *models.Ordering, paginate *models.Pagination, onlyFavorites *bool) int
|
||||
@@ -155,6 +156,7 @@ type ComplexityRoot struct {
|
||||
RecognizeUnlabeledFaces func(childComplexity int) int
|
||||
ScanAll func(childComplexity int) int
|
||||
ScanUser func(childComplexity int, userID int) int
|
||||
SetAlbumCoverID func(childComplexity int, albumID int, coverID *int) int
|
||||
SetFaceGroupLabel func(childComplexity int, faceGroupID int, label *string) int
|
||||
SetPeriodicScanInterval func(childComplexity int, interval int) int
|
||||
SetScannerConcurrentWorkers func(childComplexity int, workers int) int
|
||||
@@ -312,6 +314,7 @@ type MutationResolver interface {
|
||||
SetPeriodicScanInterval(ctx context.Context, interval int) (int, error)
|
||||
SetScannerConcurrentWorkers(ctx context.Context, workers int) (int, error)
|
||||
ChangeUserPreferences(ctx context.Context, language *string) (*models.UserPreferences, error)
|
||||
SetAlbumCoverID(ctx context.Context, albumID int, coverID *int) (*models.Album, error)
|
||||
SetFaceGroupLabel(ctx context.Context, faceGroupID int, label *string) (*models.FaceGroup, error)
|
||||
CombineFaceGroups(ctx context.Context, destinationFaceGroupID int, sourceFaceGroupID int) (*models.FaceGroup, error)
|
||||
MoveImageFaces(ctx context.Context, imageFaceIDs []int, destinationFaceGroupID int) (*models.FaceGroup, error)
|
||||
@@ -366,6 +369,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
_ = ec
|
||||
switch typeName + "." + field {
|
||||
|
||||
case "Album.coverID":
|
||||
if e.complexity.Album.CoverID == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Album.CoverID(childComplexity), true
|
||||
|
||||
case "Album.filePath":
|
||||
if e.complexity.Album.FilePath == nil {
|
||||
break
|
||||
@@ -938,6 +948,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.Mutation.ScanUser(childComplexity, args["userId"].(int)), true
|
||||
|
||||
case "Mutation.setAlbumCoverID":
|
||||
if e.complexity.Mutation.SetAlbumCoverID == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_setAlbumCoverID_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.SetAlbumCoverID(childComplexity, args["albumID"].(int), args["coverID"].(*int)), true
|
||||
|
||||
case "Mutation.setFaceGroupLabel":
|
||||
if e.complexity.Mutation.SetFaceGroupLabel == nil {
|
||||
break
|
||||
@@ -1700,7 +1722,7 @@ type Query {
|
||||
"Get media owned by the logged in user, returned in GeoJson format"
|
||||
myMediaGeoJson: Any! @isAuthorized
|
||||
"Get the mapbox api token, returns null if mapbox is not enabled"
|
||||
mapboxToken: String
|
||||
mapboxToken: String @isAuthorized
|
||||
|
||||
shareToken(credentials: ShareTokenCredentials!): ShareToken!
|
||||
shareTokenValidatePassword(credentials: ShareTokenCredentials!): Boolean!
|
||||
@@ -1766,6 +1788,9 @@ type Mutation {
|
||||
|
||||
changeUserPreferences(language: String): UserPreferences! @isAuthorized
|
||||
|
||||
"Assign a cover image to an album, set coverID to -1 to remove the current one"
|
||||
setAlbumCoverID(albumID: ID!, coverID: Int): Album!
|
||||
|
||||
"Assign a label to a face group, set label to null to remove the current one"
|
||||
setFaceGroupLabel(faceGroupID: ID!, label: String): FaceGroup! @isAuthorized
|
||||
"Merge two face groups into a single one, all ImageFaces from source will be moved to destination"
|
||||
@@ -1905,6 +1930,8 @@ type Album {
|
||||
path: [Album!]!
|
||||
|
||||
shares: [ShareToken!]!
|
||||
|
||||
coverID: Int!
|
||||
}
|
||||
|
||||
type MediaURL {
|
||||
@@ -2364,6 +2391,30 @@ func (ec *executionContext) field_Mutation_scanUser_args(ctx context.Context, ra
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_setAlbumCoverID_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 int
|
||||
if tmp, ok := rawArgs["albumID"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("albumID"))
|
||||
arg0, err = ec.unmarshalNID2int(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["albumID"] = arg0
|
||||
var arg1 *int
|
||||
if tmp, ok := rawArgs["coverID"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("coverID"))
|
||||
arg1, err = ec.unmarshalOInt2ᚖint(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["coverID"] = arg1
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_setFaceGroupLabel_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
@@ -3264,6 +3315,41 @@ func (ec *executionContext) _Album_shares(ctx context.Context, field graphql.Col
|
||||
return ec.marshalNShareToken2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareTokenᚄ(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Album_coverID(ctx context.Context, field graphql.CollectedField, obj *models.Album) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "Album",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.CoverID, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(int)
|
||||
fc.Result = res
|
||||
return ec.marshalNInt2int(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _AuthorizeResult_success(ctx context.Context, field graphql.CollectedField, obj *models.AuthorizeResult) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@@ -5863,6 +5949,48 @@ func (ec *executionContext) _Mutation_changeUserPreferences(ctx context.Context,
|
||||
return ec.marshalNUserPreferences2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUserPreferences(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_setAlbumCoverID(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "Mutation",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Mutation_setAlbumCoverID_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
fc.Args = args
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().SetAlbumCoverID(rctx, args["albumID"].(int), args["coverID"].(*int))
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*models.Album)
|
||||
fc.Result = res
|
||||
return ec.marshalNAlbum2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_setFaceGroupLabel(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@@ -7031,8 +7159,28 @@ func (ec *executionContext) _Query_mapboxToken(ctx context.Context, field graphq
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Query().MapboxToken(rctx)
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Query().MapboxToken(rctx)
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.IsAuthorized == nil {
|
||||
return nil, errors.New("directive isAuthorized is not implemented")
|
||||
}
|
||||
return ec.directives.IsAuthorized(ctx, nil, directive0)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.(*string); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be *string`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
@@ -10112,6 +10260,11 @@ func (ec *executionContext) _Album(ctx context.Context, sel ast.SelectionSet, ob
|
||||
}
|
||||
return res
|
||||
})
|
||||
case "coverID":
|
||||
out.Values[i] = ec._Album_coverID(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&invalids, 1)
|
||||
}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
@@ -10682,6 +10835,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "setAlbumCoverID":
|
||||
out.Values[i] = ec._Mutation_setAlbumCoverID(ctx, field)
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "setFaceGroupLabel":
|
||||
out.Values[i] = ec._Mutation_setFaceGroupLabel(ctx, field)
|
||||
if out.Values[i] == graphql.Null {
|
||||
|
||||
@@ -17,6 +17,7 @@ type Album struct {
|
||||
Owners []User `gorm:"many2many:user_albums;constraint:OnDelete:CASCADE;"`
|
||||
Path string `gorm:"not null"`
|
||||
PathHash string `gorm:"unique"`
|
||||
CoverID int `gorm:"index;default:-1;"`
|
||||
}
|
||||
|
||||
func (a *Album) FilePath() string {
|
||||
|
||||
@@ -3,6 +3,8 @@ package resolvers
|
||||
import (
|
||||
"context"
|
||||
|
||||
"fmt"
|
||||
|
||||
api "github.com/photoview/photoview/api/graphql"
|
||||
"github.com/photoview/photoview/api/graphql/auth"
|
||||
"github.com/photoview/photoview/api/graphql/models"
|
||||
@@ -148,24 +150,45 @@ func (r *albumResolver) Thumbnail(ctx context.Context, obj *models.Album) (*mode
|
||||
|
||||
var media models.Media
|
||||
|
||||
err := r.Database.Raw(`
|
||||
WITH recursive sub_albums AS (
|
||||
SELECT * FROM albums AS root WHERE id = ?
|
||||
UNION ALL
|
||||
SELECT child.* FROM albums AS child JOIN sub_albums ON child.parent_album_id = sub_albums.id
|
||||
)
|
||||
fmt.Print(obj.CoverID)
|
||||
|
||||
SELECT * FROM media WHERE media.album_id IN (
|
||||
SELECT id FROM sub_albums
|
||||
) AND media.id IN (
|
||||
SELECT media_id FROM media_urls WHERE media_urls.media_id = media.id
|
||||
) LIMIT 1
|
||||
`, obj.ID).Find(&media).Error
|
||||
if obj.CoverID == -1 {
|
||||
if err := r.Database.Raw(`
|
||||
WITH recursive sub_albums AS (
|
||||
SELECT * FROM albums AS root WHERE id = ?
|
||||
UNION ALL
|
||||
SELECT child.* FROM albums AS child JOIN sub_albums ON child.parent_album_id = sub_albums.id
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
SELECT * FROM media WHERE media.album_id IN (
|
||||
SELECT id FROM sub_albums
|
||||
) AND media.id IN (
|
||||
SELECT media_id FROM media_urls WHERE media_urls.media_id = media.id
|
||||
) LIMIT 1
|
||||
`, obj.ID).Find(&media).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := r.Database.Where("id = ?", obj.CoverID).Find(&media).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// err := r.Database.Raw(`
|
||||
// WITH recursive sub_albums AS (
|
||||
// SELECT * FROM albums AS root WHERE id = ?
|
||||
// UNION ALL
|
||||
// SELECT child.* FROM albums AS child JOIN sub_albums ON child.parent_album_id = sub_albums.id
|
||||
// )
|
||||
//
|
||||
// SELECT * FROM media WHERE media.album_id IN (
|
||||
// SELECT id FROM sub_albums
|
||||
// ) AND media.id IN (
|
||||
// SELECT media_id FROM media_urls WHERE media_urls.media_id = media.id
|
||||
// ) LIMIT 1
|
||||
// `, obj.ID).Find(&media).Error
|
||||
|
||||
return &media, nil
|
||||
}
|
||||
|
||||
@@ -242,3 +265,46 @@ func (r *albumResolver) Path(ctx context.Context, obj *models.Album) ([]*models.
|
||||
|
||||
return album_path, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) SetAlbumCoverID(ctx context.Context, albumID int, coverID *int) (*models.Album, error) {
|
||||
user := auth.UserFromContext(ctx)
|
||||
if user == nil {
|
||||
return nil, errors.New("unauthorized")
|
||||
}
|
||||
|
||||
var album models.Album
|
||||
if err := r.Database.Find(&album, albumID).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//
|
||||
// var album models.Album
|
||||
//
|
||||
ownsAlbum, err := user.OwnsAlbum(r.Database, &album)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !ownsAlbum {
|
||||
return nil, errors.New("forbidden")
|
||||
}
|
||||
|
||||
|
||||
|
||||
if err := r.Database.Model(&album).Update("cover_id", coverID).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// var faceGroup models.FaceGroup
|
||||
// if err := db.Where("id = ?", faceGroupID).Find(&faceGroup).Error; err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// return &faceGroup, nil
|
||||
//
|
||||
// if err := r.Database.Model(faceGroup).Update("label", label).Error; err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
return &album, nil
|
||||
}
|
||||
|
||||
@@ -134,6 +134,9 @@ type Mutation {
|
||||
|
||||
changeUserPreferences(language: String): UserPreferences! @isAuthorized
|
||||
|
||||
"Assign a cover image to an album, set coverID to -1 to remove the current one"
|
||||
setAlbumCoverID(albumID: ID!, coverID: Int): Album!
|
||||
|
||||
"Assign a label to a face group, set label to null to remove the current one"
|
||||
setFaceGroupLabel(faceGroupID: ID!, label: String): FaceGroup! @isAuthorized
|
||||
"Merge two face groups into a single one, all ImageFaces from source will be moved to destination"
|
||||
@@ -273,6 +276,8 @@ type Album {
|
||||
path: [Album!]!
|
||||
|
||||
shares: [ShareToken!]!
|
||||
|
||||
coverID: Int!
|
||||
}
|
||||
|
||||
type MediaURL {
|
||||
|
||||
Reference in New Issue
Block a user