Cleanup graphql schema, and general refactoring

- Separate graphql `filter` into `paginate` and `order`
- Remove GalleryGroups, replaced by TimelineGallery
- Fix Apollo cache such that sorting works again
This commit is contained in:
viktorstrate
2021-02-13 15:08:05 +01:00
parent 60f2635e21
commit 926aa3de3d
16 changed files with 252 additions and 359 deletions

View File

@@ -55,12 +55,12 @@ type ComplexityRoot struct {
Album struct {
FilePath func(childComplexity int) int
ID func(childComplexity int) int
Media func(childComplexity int, filter *models.Filter, onlyFavorites *bool) int
Media func(childComplexity int, order *models.Ordering, paginate *models.Pagination, onlyFavorites *bool) int
Owner func(childComplexity int) int
ParentAlbum func(childComplexity int) int
Path func(childComplexity int) int
Shares func(childComplexity int) int
SubAlbums func(childComplexity int, filter *models.Filter) int
SubAlbums func(childComplexity int, order *models.Ordering, paginate *models.Pagination) int
Thumbnail func(childComplexity int) int
Title func(childComplexity int) int
}
@@ -149,16 +149,16 @@ type ComplexityRoot struct {
MapboxToken func(childComplexity int) int
Media func(childComplexity int, id int) int
MediaList func(childComplexity int, ids []int) int
MyAlbums func(childComplexity int, filter *models.Filter, onlyRoot *bool, showEmpty *bool, onlyWithFavorites *bool) int
MyMedia func(childComplexity int, filter *models.Filter) int
MyAlbums func(childComplexity int, order *models.Ordering, paginate *models.Pagination, onlyRoot *bool, showEmpty *bool, onlyWithFavorites *bool) int
MyMedia func(childComplexity int, order *models.Ordering, paginate *models.Pagination) int
MyMediaGeoJSON func(childComplexity int) int
MyTimeline func(childComplexity int, limit *int, offset *int, onlyFavorites *bool) int
MyTimeline func(childComplexity int, paginate *models.Pagination, onlyFavorites *bool) int
MyUser func(childComplexity int) int
Search func(childComplexity int, query string, limitMedia *int, limitAlbums *int) int
ShareToken func(childComplexity int, token string, password *string) int
ShareTokenValidatePassword func(childComplexity int, token string, password *string) int
SiteInfo func(childComplexity int) int
User func(childComplexity int, filter *models.Filter) int
User func(childComplexity int, order *models.Ordering, paginate *models.Pagination) int
}
ScannerResult struct {
@@ -224,8 +224,8 @@ type ComplexityRoot struct {
}
type AlbumResolver interface {
Media(ctx context.Context, obj *models.Album, filter *models.Filter, onlyFavorites *bool) ([]*models.Media, error)
SubAlbums(ctx context.Context, obj *models.Album, filter *models.Filter) ([]*models.Album, error)
Media(ctx context.Context, obj *models.Album, order *models.Ordering, paginate *models.Pagination, onlyFavorites *bool) ([]*models.Media, error)
SubAlbums(ctx context.Context, obj *models.Album, order *models.Ordering, paginate *models.Pagination) ([]*models.Album, error)
Owner(ctx context.Context, obj *models.Album) (*models.User, error)
@@ -265,14 +265,14 @@ type MutationResolver interface {
}
type QueryResolver interface {
SiteInfo(ctx context.Context) (*models.SiteInfo, error)
User(ctx context.Context, filter *models.Filter) ([]*models.User, error)
User(ctx context.Context, order *models.Ordering, paginate *models.Pagination) ([]*models.User, error)
MyUser(ctx context.Context) (*models.User, error)
MyAlbums(ctx context.Context, filter *models.Filter, onlyRoot *bool, showEmpty *bool, onlyWithFavorites *bool) ([]*models.Album, error)
MyAlbums(ctx context.Context, order *models.Ordering, paginate *models.Pagination, onlyRoot *bool, showEmpty *bool, onlyWithFavorites *bool) ([]*models.Album, error)
Album(ctx context.Context, id int) (*models.Album, error)
MyMedia(ctx context.Context, filter *models.Filter) ([]*models.Media, error)
MyMedia(ctx context.Context, order *models.Ordering, paginate *models.Pagination) ([]*models.Media, error)
Media(ctx context.Context, id int) (*models.Media, error)
MediaList(ctx context.Context, ids []int) ([]*models.Media, error)
MyTimeline(ctx context.Context, limit *int, offset *int, onlyFavorites *bool) ([]*models.TimelineGroup, error)
MyTimeline(ctx context.Context, paginate *models.Pagination, onlyFavorites *bool) ([]*models.TimelineGroup, error)
MyMediaGeoJSON(ctx context.Context) (interface{}, error)
MapboxToken(ctx context.Context) (*string, error)
ShareToken(ctx context.Context, token string, password *string) (*models.ShareToken, error)
@@ -329,7 +329,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Album.Media(childComplexity, args["filter"].(*models.Filter), args["onlyFavorites"].(*bool)), true
return e.complexity.Album.Media(childComplexity, args["order"].(*models.Ordering), args["paginate"].(*models.Pagination), args["onlyFavorites"].(*bool)), true
case "Album.owner":
if e.complexity.Album.Owner == nil {
@@ -369,7 +369,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Album.SubAlbums(childComplexity, args["filter"].(*models.Filter)), true
return e.complexity.Album.SubAlbums(childComplexity, args["order"].(*models.Ordering), args["paginate"].(*models.Pagination)), true
case "Album.thumbnail":
if e.complexity.Album.Thumbnail == nil {
@@ -919,7 +919,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Query.MyAlbums(childComplexity, args["filter"].(*models.Filter), args["onlyRoot"].(*bool), args["showEmpty"].(*bool), args["onlyWithFavorites"].(*bool)), true
return e.complexity.Query.MyAlbums(childComplexity, args["order"].(*models.Ordering), args["paginate"].(*models.Pagination), args["onlyRoot"].(*bool), args["showEmpty"].(*bool), args["onlyWithFavorites"].(*bool)), true
case "Query.myMedia":
if e.complexity.Query.MyMedia == nil {
@@ -931,7 +931,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Query.MyMedia(childComplexity, args["filter"].(*models.Filter)), true
return e.complexity.Query.MyMedia(childComplexity, args["order"].(*models.Ordering), args["paginate"].(*models.Pagination)), true
case "Query.myMediaGeoJson":
if e.complexity.Query.MyMediaGeoJSON == nil {
@@ -950,7 +950,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Query.MyTimeline(childComplexity, args["limit"].(*int), args["offset"].(*int), args["onlyFavorites"].(*bool)), true
return e.complexity.Query.MyTimeline(childComplexity, args["paginate"].(*models.Pagination), args["onlyFavorites"].(*bool)), true
case "Query.myUser":
if e.complexity.Query.MyUser == nil {
@@ -1012,7 +1012,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Query.User(childComplexity, args["filter"].(*models.Filter)), true
return e.complexity.Query.User(childComplexity, args["order"].(*models.Ordering), args["paginate"].(*models.Pagination)), true
case "ScannerResult.finished":
if e.complexity.ScannerResult.Finished == nil {
@@ -1364,24 +1364,28 @@ enum OrderDirection {
DESC
}
input Filter {
order_by: String
order_direction: OrderDirection
input Pagination {
limit: Int
offset: Int
}
input Ordering {
order_by: String
order_direction: OrderDirection
}
type Query {
siteInfo: SiteInfo!
"List of registered users, must be admin to call"
user(filter: Filter): [User!]! @isAdmin
user(order: Ordering, paginate: Pagination): [User!]! @isAdmin
"Information about the currently logged in user"
myUser: User!
"List of albums owned by the logged in user."
myAlbums(
filter: Filter
order: Ordering,
paginate: Pagination
"Return only albums from the root directory of the user"
onlyRoot: Boolean
"Return also albums with no media directly in them"
@@ -1393,14 +1397,14 @@ type Query {
album(id: ID!): Album!
"List of media owned by the logged in user"
myMedia(filter: Filter): [Media!]!
myMedia(order: Ordering, paginate: Pagination): [Media!]!
"Get media by id, user must own the media or be admin"
media(id: ID!): Media!
"Get a list of media by their ids, user must own the media or be admin"
mediaList(ids: [ID!]!): [Media!]!
myTimeline(limit: Int, offset: Int, onlyFavorites: Boolean): [TimelineGroup!]!
myTimeline(paginate: Pagination, onlyFavorites: Boolean): [TimelineGroup!]!
"Get media owned by the logged in user, returned in GeoJson format"
myMediaGeoJson: Any!
@@ -1545,14 +1549,21 @@ type User {
type Album {
id: ID!
title: String!
"The media inside this album"
media(
filter: Filter,
order: Ordering,
paginate: Pagination
"Return only the favorited media"
onlyFavorites: Boolean
): [Media!]!
"The albums contained in this album"
subAlbums(filter: Filter): [Album!]!
subAlbums(
order: Ordering,
paginate: Pagination
): [Album!]!
"The album witch contains this album"
parentAlbum: Album
"The user who owns this album"
@@ -1670,39 +1681,57 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...)
func (ec *executionContext) field_Album_media_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 *models.Filter
if tmp, ok := rawArgs["filter"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter"))
arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp)
var arg0 *models.Ordering
if tmp, ok := rawArgs["order"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("order"))
arg0, err = ec.unmarshalOOrdering2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrdering(ctx, tmp)
if err != nil {
return nil, err
}
}
args["filter"] = arg0
var arg1 *bool
args["order"] = arg0
var arg1 *models.Pagination
if tmp, ok := rawArgs["paginate"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("paginate"))
arg1, err = ec.unmarshalOPagination2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPagination(ctx, tmp)
if err != nil {
return nil, err
}
}
args["paginate"] = arg1
var arg2 *bool
if tmp, ok := rawArgs["onlyFavorites"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("onlyFavorites"))
arg1, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
arg2, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
if err != nil {
return nil, err
}
}
args["onlyFavorites"] = arg1
args["onlyFavorites"] = arg2
return args, nil
}
func (ec *executionContext) field_Album_subAlbums_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 *models.Filter
if tmp, ok := rawArgs["filter"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter"))
arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp)
var arg0 *models.Ordering
if tmp, ok := rawArgs["order"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("order"))
arg0, err = ec.unmarshalOOrdering2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrdering(ctx, tmp)
if err != nil {
return nil, err
}
}
args["filter"] = arg0
args["order"] = arg0
var arg1 *models.Pagination
if tmp, ok := rawArgs["paginate"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("paginate"))
arg1, err = ec.unmarshalOPagination2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPagination(ctx, tmp)
if err != nil {
return nil, err
}
}
args["paginate"] = arg1
return args, nil
}
@@ -2138,90 +2167,99 @@ func (ec *executionContext) field_Query_media_args(ctx context.Context, rawArgs
func (ec *executionContext) field_Query_myAlbums_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 *models.Filter
if tmp, ok := rawArgs["filter"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter"))
arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp)
var arg0 *models.Ordering
if tmp, ok := rawArgs["order"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("order"))
arg0, err = ec.unmarshalOOrdering2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrdering(ctx, tmp)
if err != nil {
return nil, err
}
}
args["filter"] = arg0
var arg1 *bool
args["order"] = arg0
var arg1 *models.Pagination
if tmp, ok := rawArgs["paginate"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("paginate"))
arg1, err = ec.unmarshalOPagination2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPagination(ctx, tmp)
if err != nil {
return nil, err
}
}
args["paginate"] = arg1
var arg2 *bool
if tmp, ok := rawArgs["onlyRoot"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("onlyRoot"))
arg1, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
if err != nil {
return nil, err
}
}
args["onlyRoot"] = arg1
var arg2 *bool
if tmp, ok := rawArgs["showEmpty"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("showEmpty"))
arg2, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
if err != nil {
return nil, err
}
}
args["showEmpty"] = arg2
args["onlyRoot"] = arg2
var arg3 *bool
if tmp, ok := rawArgs["onlyWithFavorites"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("onlyWithFavorites"))
if tmp, ok := rawArgs["showEmpty"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("showEmpty"))
arg3, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
if err != nil {
return nil, err
}
}
args["onlyWithFavorites"] = arg3
args["showEmpty"] = arg3
var arg4 *bool
if tmp, ok := rawArgs["onlyWithFavorites"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("onlyWithFavorites"))
arg4, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
if err != nil {
return nil, err
}
}
args["onlyWithFavorites"] = arg4
return args, nil
}
func (ec *executionContext) field_Query_myMedia_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 *models.Filter
if tmp, ok := rawArgs["filter"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter"))
arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp)
var arg0 *models.Ordering
if tmp, ok := rawArgs["order"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("order"))
arg0, err = ec.unmarshalOOrdering2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrdering(ctx, tmp)
if err != nil {
return nil, err
}
}
args["filter"] = arg0
args["order"] = arg0
var arg1 *models.Pagination
if tmp, ok := rawArgs["paginate"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("paginate"))
arg1, err = ec.unmarshalOPagination2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPagination(ctx, tmp)
if err != nil {
return nil, err
}
}
args["paginate"] = arg1
return args, nil
}
func (ec *executionContext) field_Query_myTimeline_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["limit"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("limit"))
arg0, err = ec.unmarshalOInt2ᚖint(ctx, tmp)
var arg0 *models.Pagination
if tmp, ok := rawArgs["paginate"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("paginate"))
arg0, err = ec.unmarshalOPagination2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPagination(ctx, tmp)
if err != nil {
return nil, err
}
}
args["limit"] = arg0
var arg1 *int
if tmp, ok := rawArgs["offset"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("offset"))
arg1, err = ec.unmarshalOInt2ᚖint(ctx, tmp)
if err != nil {
return nil, err
}
}
args["offset"] = arg1
var arg2 *bool
args["paginate"] = arg0
var arg1 *bool
if tmp, ok := rawArgs["onlyFavorites"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("onlyFavorites"))
arg2, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
arg1, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
if err != nil {
return nil, err
}
}
args["onlyFavorites"] = arg2
args["onlyFavorites"] = arg1
return args, nil
}
@@ -2309,15 +2347,24 @@ func (ec *executionContext) field_Query_shareToken_args(ctx context.Context, raw
func (ec *executionContext) field_Query_user_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
var arg0 *models.Filter
if tmp, ok := rawArgs["filter"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter"))
arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp)
var arg0 *models.Ordering
if tmp, ok := rawArgs["order"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("order"))
arg0, err = ec.unmarshalOOrdering2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrdering(ctx, tmp)
if err != nil {
return nil, err
}
}
args["filter"] = arg0
args["order"] = arg0
var arg1 *models.Pagination
if tmp, ok := rawArgs["paginate"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("paginate"))
arg1, err = ec.unmarshalOPagination2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPagination(ctx, tmp)
if err != nil {
return nil, err
}
}
args["paginate"] = arg1
return args, nil
}
@@ -2454,7 +2501,7 @@ func (ec *executionContext) _Album_media(ctx context.Context, field graphql.Coll
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.Album().Media(rctx, obj, args["filter"].(*models.Filter), args["onlyFavorites"].(*bool))
return ec.resolvers.Album().Media(rctx, obj, args["order"].(*models.Ordering), args["paginate"].(*models.Pagination), args["onlyFavorites"].(*bool))
})
if err != nil {
ec.Error(ctx, err)
@@ -2496,7 +2543,7 @@ func (ec *executionContext) _Album_subAlbums(ctx context.Context, field graphql.
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.Album().SubAlbums(rctx, obj, args["filter"].(*models.Filter))
return ec.resolvers.Album().SubAlbums(rctx, obj, args["order"].(*models.Ordering), args["paginate"].(*models.Pagination))
})
if err != nil {
ec.Error(ctx, err)
@@ -4943,7 +4990,7 @@ func (ec *executionContext) _Query_user(ctx context.Context, field graphql.Colle
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
directive0 := func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().User(rctx, args["filter"].(*models.Filter))
return ec.resolvers.Query().User(rctx, args["order"].(*models.Ordering), args["paginate"].(*models.Pagination))
}
directive1 := func(ctx context.Context) (interface{}, error) {
if ec.directives.IsAdmin == nil {
@@ -5039,7 +5086,7 @@ func (ec *executionContext) _Query_myAlbums(ctx context.Context, field graphql.C
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.Query().MyAlbums(rctx, args["filter"].(*models.Filter), args["onlyRoot"].(*bool), args["showEmpty"].(*bool), args["onlyWithFavorites"].(*bool))
return ec.resolvers.Query().MyAlbums(rctx, args["order"].(*models.Ordering), args["paginate"].(*models.Pagination), args["onlyRoot"].(*bool), args["showEmpty"].(*bool), args["onlyWithFavorites"].(*bool))
})
if err != nil {
ec.Error(ctx, err)
@@ -5123,7 +5170,7 @@ func (ec *executionContext) _Query_myMedia(ctx context.Context, field graphql.Co
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.Query().MyMedia(rctx, args["filter"].(*models.Filter))
return ec.resolvers.Query().MyMedia(rctx, args["order"].(*models.Ordering), args["paginate"].(*models.Pagination))
})
if err != nil {
ec.Error(ctx, err)
@@ -5249,7 +5296,7 @@ func (ec *executionContext) _Query_myTimeline(ctx context.Context, field graphql
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.Query().MyTimeline(rctx, args["limit"].(*int), args["offset"].(*int), args["onlyFavorites"].(*bool))
return ec.resolvers.Query().MyTimeline(rctx, args["paginate"].(*models.Pagination), args["onlyFavorites"].(*bool))
})
if err != nil {
ec.Error(ctx, err)
@@ -7972,8 +8019,8 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co
// region **************************** input.gotpl *****************************
func (ec *executionContext) unmarshalInputFilter(ctx context.Context, obj interface{}) (models.Filter, error) {
var it models.Filter
func (ec *executionContext) unmarshalInputOrdering(ctx context.Context, obj interface{}) (models.Ordering, error) {
var it models.Ordering
var asMap = obj.(map[string]interface{})
for k, v := range asMap {
@@ -7994,6 +8041,18 @@ func (ec *executionContext) unmarshalInputFilter(ctx context.Context, obj interf
if err != nil {
return it, err
}
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputPagination(ctx context.Context, obj interface{}) (models.Pagination, error) {
var it models.Pagination
var asMap = obj.(map[string]interface{})
for k, v := range asMap {
switch k {
case "limit":
var err error
@@ -10205,14 +10264,6 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast
return graphql.MarshalBoolean(*v)
}
func (ec *executionContext) unmarshalOFilter2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx context.Context, v interface{}) (*models.Filter, error) {
if v == nil {
return nil, nil
}
res, err := ec.unmarshalInputFilter(ctx, v)
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) unmarshalOFloat2ᚖfloat64(ctx context.Context, v interface{}) (*float64, error) {
if v == nil {
return nil, nil
@@ -10280,6 +10331,22 @@ func (ec *executionContext) marshalOOrderDirection2ᚖgithubᚗcomᚋphotoview
return v
}
func (ec *executionContext) unmarshalOOrdering2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrdering(ctx context.Context, v interface{}) (*models.Ordering, error) {
if v == nil {
return nil, nil
}
res, err := ec.unmarshalInputOrdering(ctx, v)
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) unmarshalOPagination2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPagination(ctx context.Context, v interface{}) (*models.Pagination, error) {
if v == nil {
return nil, nil
}
res, err := ec.unmarshalInputPagination(ctx, v)
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOShareToken2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx context.Context, sel ast.SelectionSet, v []*models.ShareToken) graphql.Marshaler {
if v == nil {
return graphql.Null

View File

@@ -15,13 +15,6 @@ type AuthorizeResult struct {
Token *string `json:"token"`
}
type Filter struct {
OrderBy *string `json:"order_by"`
OrderDirection *OrderDirection `json:"order_direction"`
Limit *int `json:"limit"`
Offset *int `json:"offset"`
}
type MediaDownload struct {
Title string `json:"title"`
MediaURL *MediaURL `json:"mediaUrl"`
@@ -39,6 +32,16 @@ type Notification struct {
Timeout *int `json:"timeout"`
}
type Ordering struct {
OrderBy *string `json:"order_by"`
OrderDirection *OrderDirection `json:"order_direction"`
}
type Pagination struct {
Limit *int `json:"limit"`
Offset *int `json:"offset"`
}
type ScannerResult struct {
Finished bool `json:"finished"`
Success bool `json:"success"`

View File

@@ -11,17 +11,15 @@ import (
type Media struct {
Model
Title string `gorm:"not null"`
Path string `gorm:"not null"`
PathHash string `gorm:"not null;unique"`
AlbumID int `gorm:"not null;index"`
Album Album `gorm:"constraint:OnDelete:CASCADE;"`
ExifID *int `gorm:"index"`
Exif *MediaEXIF `gorm:"constraint:OnDelete:CASCADE;"`
MediaURL []MediaURL `gorm:"constraint:OnDelete:CASCADE;"`
DateShot time.Time `gorm:"not null"`
DateImported time.Time `gorm:"not null"`
// Favorite bool `gorm:"not null, default:false"`
Title string `gorm:"not null"`
Path string `gorm:"not null"`
PathHash string `gorm:"not null;unique"`
AlbumID int `gorm:"not null;index"`
Album Album `gorm:"constraint:OnDelete:CASCADE;"`
ExifID *int `gorm:"index"`
Exif *MediaEXIF `gorm:"constraint:OnDelete:CASCADE;"`
MediaURL []MediaURL `gorm:"constraint:OnDelete:CASCADE;"`
DateShot time.Time `gorm:"not null"`
Type MediaType `gorm:"not null;index"`
VideoMetadataID *int `gorm:"index"`
VideoMetadata *VideoMetadata `gorm:"constraint:OnDelete:CASCADE;"`

View File

@@ -8,32 +8,29 @@ import (
"gorm.io/gorm/clause"
)
func (filter *Filter) FormatSQL(tx *gorm.DB) *gorm.DB {
func FormatSQL(tx *gorm.DB, order *Ordering, paginate *Pagination) *gorm.DB {
if filter == nil {
return tx
if paginate != nil {
if paginate.Limit != nil {
tx.Limit(*paginate.Limit)
}
if paginate.Offset != nil {
tx.Offset(*paginate.Offset)
}
}
if filter.Limit != nil {
tx.Limit(*filter.Limit)
}
if filter.Offset != nil {
tx.Offset(*filter.Offset)
}
if filter.OrderBy != nil {
if order != nil && order.OrderBy != nil {
desc := true
if filter.OrderDirection != nil && filter.OrderDirection.IsValid() {
if *filter.OrderDirection == OrderDirectionAsc {
if order.OrderDirection != nil && order.OrderDirection.IsValid() {
if *order.OrderDirection == OrderDirectionAsc {
desc = false
}
}
tx.Order(clause.OrderByColumn{
Column: clause.Column{
Name: *filter.OrderBy,
Name: *order.OrderBy,
},
Desc: desc,
})

View File

@@ -10,7 +10,7 @@ import (
"gorm.io/gorm"
)
func (r *queryResolver) MyAlbums(ctx context.Context, filter *models.Filter, onlyRoot *bool, showEmpty *bool, onlyWithFavorites *bool) ([]*models.Album, error) {
func (r *queryResolver) MyAlbums(ctx context.Context, order *models.Ordering, paginate *models.Pagination, onlyRoot *bool, showEmpty *bool, onlyWithFavorites *bool) ([]*models.Album, error) {
user := auth.UserFromContext(ctx)
if user == nil {
return nil, auth.ErrUnauthorized
@@ -50,7 +50,7 @@ func (r *queryResolver) MyAlbums(ctx context.Context, filter *models.Filter, onl
query = query.Where("EXISTS (?)", subQuery)
}
query = filter.FormatSQL(query)
query = models.FormatSQL(query, order, paginate)
var albums []*models.Album
if err := query.Scan(&albums).Error; err != nil {
@@ -92,7 +92,7 @@ func (r *Resolver) Album() api.AlbumResolver {
type albumResolver struct{ *Resolver }
func (r *albumResolver) Media(ctx context.Context, album *models.Album, filter *models.Filter, onlyFavorites *bool) ([]*models.Media, error) {
func (r *albumResolver) Media(ctx context.Context, album *models.Album, order *models.Ordering, paginate *models.Pagination, onlyFavorites *bool) ([]*models.Media, error) {
query := r.Database.
Where("media.album_id = ?", album.ID).
@@ -111,7 +111,7 @@ func (r *albumResolver) Media(ctx context.Context, album *models.Album, filter *
query = query.Where("EXISTS (?)", favoriteQuery)
}
query = filter.FormatSQL(query)
query = models.FormatSQL(query, order, paginate)
var media []*models.Media
if err := query.Find(&media).Error; err != nil {
@@ -146,12 +146,12 @@ func (r *albumResolver) Thumbnail(ctx context.Context, obj *models.Album) (*mode
return &media, nil
}
func (r *albumResolver) SubAlbums(ctx context.Context, parent *models.Album, filter *models.Filter) ([]*models.Album, error) {
func (r *albumResolver) SubAlbums(ctx context.Context, parent *models.Album, order *models.Ordering, paginate *models.Pagination) ([]*models.Album, error) {
var albums []*models.Album
query := r.Database.Where("parent_album_id = ?", parent.ID)
query = filter.FormatSQL(query)
query = models.FormatSQL(query, order, paginate)
if err := query.Find(&albums).Error; err != nil {
return nil, err

View File

@@ -11,7 +11,7 @@ import (
"gorm.io/gorm/clause"
)
func (r *queryResolver) MyMedia(ctx context.Context, filter *models.Filter) ([]*models.Media, error) {
func (r *queryResolver) MyMedia(ctx context.Context, order *models.Ordering, paginate *models.Pagination) ([]*models.Media, error) {
user := auth.UserFromContext(ctx)
if user == nil {
return nil, errors.New("unauthorized")
@@ -33,7 +33,7 @@ func (r *queryResolver) MyMedia(ctx context.Context, filter *models.Filter) ([]*
Where("albums.id IN (?)", userAlbumIDs).
Where("media.id IN (?)", r.Database.Model(&models.MediaURL{}).Select("id").Where("media_url.media_id = media.id"))
query = filter.FormatSQL(query)
query = models.FormatSQL(query, order, paginate)
if err := query.Scan(&media).Error; err != nil {
return nil, err

View File

@@ -9,7 +9,7 @@ import (
"gorm.io/gorm"
)
func (r *queryResolver) MyTimeline(ctx context.Context, limit *int, offset *int, onlyFavorites *bool) ([]*models.TimelineGroup, error) {
func (r *queryResolver) MyTimeline(ctx context.Context, paginate *models.Pagination, onlyFavorites *bool) ([]*models.TimelineGroup, error) {
user := auth.UserFromContext(ctx)
if user == nil {
return nil, auth.ErrUnauthorized
@@ -33,12 +33,14 @@ func (r *queryResolver) MyTimeline(ctx context.Context, limit *int, offset *int,
daysQuery.Where("media.id IN (?)", tx.Table("user_media_data").Select("user_media_data.media_id").Where("user_media_data.user_id = ?", user.ID).Where("user_media_data.favorite = 1"))
}
if limit != nil {
daysQuery.Limit(*limit)
}
if paginate != nil {
if paginate.Limit != nil {
daysQuery.Limit(*paginate.Limit)
}
if offset != nil {
daysQuery.Offset(*offset)
if paginate.Offset != nil {
daysQuery.Offset(*paginate.Offset)
}
}
rows, err := daysQuery.Group("albums.id, YEAR(media.date_shot), MONTH(media.date_shot), DAY(media.date_shot)").

View File

@@ -25,11 +25,11 @@ func (r *Resolver) User() api.UserResolver {
return &userResolver{r}
}
func (r *queryResolver) User(ctx context.Context, filter *models.Filter) ([]*models.User, error) {
func (r *queryResolver) User(ctx context.Context, order *models.Ordering, paginate *models.Pagination) ([]*models.User, error) {
var users []*models.User
if err := filter.FormatSQL(r.Database.Model(models.User{})).Scan(&users).Error; err != nil {
if err := models.FormatSQL(r.Database.Model(models.User{}), order, paginate).Scan(&users).Error; err != nil {
return nil, err
}

View File

@@ -8,24 +8,28 @@ enum OrderDirection {
DESC
}
input Filter {
order_by: String
order_direction: OrderDirection
input Pagination {
limit: Int
offset: Int
}
input Ordering {
order_by: String
order_direction: OrderDirection
}
type Query {
siteInfo: SiteInfo!
"List of registered users, must be admin to call"
user(filter: Filter): [User!]! @isAdmin
user(order: Ordering, paginate: Pagination): [User!]! @isAdmin
"Information about the currently logged in user"
myUser: User!
"List of albums owned by the logged in user."
myAlbums(
filter: Filter
order: Ordering,
paginate: Pagination
"Return only albums from the root directory of the user"
onlyRoot: Boolean
"Return also albums with no media directly in them"
@@ -37,14 +41,14 @@ type Query {
album(id: ID!): Album!
"List of media owned by the logged in user"
myMedia(filter: Filter): [Media!]!
myMedia(order: Ordering, paginate: Pagination): [Media!]!
"Get media by id, user must own the media or be admin"
media(id: ID!): Media!
"Get a list of media by their ids, user must own the media or be admin"
mediaList(ids: [ID!]!): [Media!]!
myTimeline(limit: Int, offset: Int, onlyFavorites: Boolean): [TimelineGroup!]!
myTimeline(paginate: Pagination, onlyFavorites: Boolean): [TimelineGroup!]!
"Get media owned by the logged in user, returned in GeoJson format"
myMediaGeoJson: Any!
@@ -189,14 +193,21 @@ type User {
type Album {
id: ID!
title: String!
"The media inside this album"
media(
filter: Filter,
order: Ordering,
paginate: Pagination
"Return only the favorited media"
onlyFavorites: Boolean
): [Media!]!
"The albums contained in this album"
subAlbums(filter: Filter): [Album!]!
subAlbums(
order: Ordering,
paginate: Pagination
): [Album!]!
"The album witch contains this album"
parentAlbum: Album
"The user who owns this album"

View File

@@ -20,7 +20,7 @@ const albumQuery = gql`
album(id: $id) {
id
title
subAlbums(filter: { order_by: "title" }) {
subAlbums(order: { order_by: "title" }) {
id
title
thumbnail {
@@ -30,9 +30,8 @@ const albumQuery = gql`
}
}
media(
filter: {
limit: $limit
offset: $offset
paginate: { limit: $limit, offset: $offset }
order: {
order_by: $mediaOrderBy
order_direction: $mediaOrderDirection
}

View File

@@ -5,7 +5,7 @@ import { useQuery, gql } from '@apollo/client'
const getAlbumsQuery = gql`
query getMyAlbums {
myAlbums(filter: { order_by: "title" }, onlyRoot: true, showEmpty: true) {
myAlbums(order: { order_by: "title" }, onlyRoot: true, showEmpty: true) {
id
title
thumbnail {

View File

@@ -36,7 +36,7 @@ export const SHARE_TOKEN_QUERY = gql`
url
}
}
media(filter: { order_by: "title", order_direction: DESC }) {
media(order: { order_by: "title", order_direction: DESC }) {
...MediaProps
}
}

View File

@@ -120,7 +120,7 @@ const memoryCache = new InMemoryCache({
Album: {
fields: {
media: {
keyArgs: ['onlyFavorites'],
keyArgs: ['onlyFavorites', 'order'],
merge(existing = [], incoming) {
return [...existing, ...incoming]
},

View File

@@ -11,8 +11,8 @@ const sortingOptions = [
text: 'Date shot',
},
{
key: 'date_imported',
value: 'date_imported',
key: 'updated_at',
value: 'updated_at',
text: 'Date imported',
},
{
@@ -21,7 +21,7 @@ const sortingOptions = [
text: 'Title',
},
{
key: 'kind',
key: 'type',
value: 'type',
text: 'Kind',
},

View File

@@ -1,187 +0,0 @@
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useLocation } from 'react-router-dom'
import { useQuery, gql } from '@apollo/client'
import PhotoGallery from '../../components/photoGallery/PhotoGallery'
import AlbumTitle from '../../components/AlbumTitle'
import { authToken } from '../../authentication'
import PropTypes from 'prop-types'
import AlbumFilter from '../../components/AlbumFilter'
const photoQuery = gql`
query allGalleryGroups(
$onlyWithFavorites: Boolean
$mediaOrderBy: String
$mediaOrderDirection: OrderDirection
) {
myAlbums(
filter: { order_by: "title", order_direction: ASC, limit: 100 }
onlyWithFavorites: $onlyWithFavorites
) {
title
id
media(
filter: {
order_by: $mediaOrderBy
order_direction: $mediaOrderDirection
limit: 12
}
onlyFavorites: $onlyWithFavorites
) {
id
title
type
thumbnail {
url
width
height
}
highRes {
url
width
height
}
videoWeb {
url
}
favorite
}
}
}
`
const GalleryGroups = ({ subPage }) => {
const [activeIndex, setActiveIndex] = useState({ album: -1, media: -1 })
const [presenting, setPresenting] = useState(false)
const [onlyWithFavorites, setOnlyWithFavorites] = useState(
subPage === 'favorites'
)
const urlParams = new URLSearchParams(useLocation().search)
const [ordering, setOrdering] = useState({
orderBy: urlParams.get('orderBy') || 'date_shot',
orderDirection: urlParams.get('orderDirection') || 'ASC',
})
const setOrderingCallback = useCallback(
ordering => {
setOrdering(prevState => {
return {
...prevState,
...ordering,
}
})
},
[setOrdering]
)
const refetchNeeded = useRef({ all: false, favorites: false })
const { loading, error, data, refetch } = useQuery(photoQuery, {
variables: {
onlyWithFavorites: onlyWithFavorites,
mediaOrderBy: ordering.orderBy,
mediaOrderDirection: ordering.orderDirection,
},
})
const nextImage = useCallback(() => {
setActiveIndex(index => {
const albumMediaCount = data.myAlbums[index.album].media.length
if (index.media + 1 < albumMediaCount) {
return {
...index,
media: index.media + 1,
}
} else {
return index
}
})
}, [data])
const previousImage = useCallback(() => {
setActiveIndex(index =>
index.media > 0 ? { ...index, media: index.media - 1 } : index
)
})
const setOnlyFavorites = useCallback(
onlyWithFavorites => {
history.replaceState(
{},
'',
'/photos' + (onlyWithFavorites ? '/favorites' : '')
)
if (
(refetchNeeded.current.all && !onlyWithFavorites) ||
(refetchNeeded.current.favorites && onlyWithFavorites)
) {
refetch({ onlyWithFavorites: onlyWithFavorites }).then(() => {
if (onlyWithFavorites) {
refetchNeeded.current.favorites = false
} else {
refetchNeeded.current.all = false
}
setOnlyWithFavorites(onlyWithFavorites)
})
} else {
setOnlyWithFavorites(onlyWithFavorites)
}
},
[setOnlyWithFavorites]
)
useEffect(() => {
const pathName = `/photos${onlyWithFavorites ? '/favorites' : ''}`
const queryString = `orderBy=${ordering.orderBy}&orderDirection=${ordering.orderDirection}`
history.replaceState({}, '', pathName + '?' + queryString)
}, [onlyWithFavorites, ordering])
if (error) return error
let galleryGroups = []
if (!loading && data.myAlbums && authToken()) {
galleryGroups = data.myAlbums.map((album, index) => (
<div key={album.id}>
<AlbumTitle album={album} />
<PhotoGallery
onSelectImage={mediaIndex => {
setActiveIndex({ album: index, media: mediaIndex })
}}
onFavorite={() => {
refetchNeeded.current.all = true
refetchNeeded.current.favorites = true
}}
activeIndex={activeIndex.album === index ? activeIndex.media : -1}
presenting={presenting === index}
setPresenting={presenting =>
setPresenting(presenting ? index : false)
}
loading={loading}
media={album.media}
nextImage={nextImage}
previousImage={previousImage}
/>
</div>
))
}
return (
<>
<AlbumFilter
setOnlyFavorites={setOnlyFavorites}
setOrdering={setOrderingCallback}
ordering={ordering}
/>
{galleryGroups}
</>
)
}
GalleryGroups.propTypes = {
subPage: PropTypes.string,
}
export default GalleryGroups

View File

@@ -11,7 +11,10 @@ import useScrollPagination from '../../hooks/useScrollPagination'
const MY_TIMELINE_QUERY = gql`
query myTimeline($onlyFavorites: Boolean, $limit: Int, $offset: Int) {
myTimeline(onlyFavorites: $onlyFavorites, limit: $limit, offset: $offset) {
myTimeline(
onlyFavorites: $onlyFavorites
paginate: { limit: $limit, offset: $offset }
) {
album {
id
title