mirror of
https://git.vectorsigma.ru/public/photoview.git
synced 2026-08-03 22:29:07 +00:00
Working on integrating backend with ui
This commit is contained in:
@@ -2,4 +2,5 @@
|
||||
|
||||
MYSQL_URL=user:password@/dbname
|
||||
|
||||
API_PORT=4001
|
||||
API_PORT=4001
|
||||
API_ENDPOINT=http://localhost:4001/
|
||||
@@ -53,7 +53,7 @@ type ComplexityRoot struct {
|
||||
Owner func(childComplexity int) int
|
||||
ParentAlbum func(childComplexity int) int
|
||||
Path func(childComplexity int) int
|
||||
Photos func(childComplexity int) int
|
||||
Photos func(childComplexity int, filter *models.Filter) int
|
||||
SubAlbums func(childComplexity int) int
|
||||
Title func(childComplexity int) int
|
||||
}
|
||||
@@ -105,12 +105,12 @@ type ComplexityRoot struct {
|
||||
|
||||
Query struct {
|
||||
Album func(childComplexity int, id *string) int
|
||||
MyAlbums func(childComplexity int) int
|
||||
MyPhotos func(childComplexity int) int
|
||||
MyAlbums func(childComplexity int, filter *models.Filter) int
|
||||
MyPhotos func(childComplexity int, filter *models.Filter) int
|
||||
MyUser func(childComplexity int) int
|
||||
Photo func(childComplexity int, id string) int
|
||||
SiteInfo func(childComplexity int) int
|
||||
Users func(childComplexity int) int
|
||||
Users func(childComplexity int, filter *models.Filter) int
|
||||
}
|
||||
|
||||
ScannerResult struct {
|
||||
@@ -133,7 +133,7 @@ type ComplexityRoot struct {
|
||||
}
|
||||
|
||||
type AlbumResolver interface {
|
||||
Photos(ctx context.Context, obj *models.Album) ([]*models.Photo, error)
|
||||
Photos(ctx context.Context, obj *models.Album, filter *models.Filter) ([]*models.Photo, error)
|
||||
SubAlbums(ctx context.Context, obj *models.Album) ([]*models.Album, error)
|
||||
ParentAlbum(ctx context.Context, obj *models.Album) (*models.Album, error)
|
||||
Owner(ctx context.Context, obj *models.Album) (*models.User, error)
|
||||
@@ -154,11 +154,11 @@ type PhotoResolver interface {
|
||||
}
|
||||
type QueryResolver interface {
|
||||
SiteInfo(ctx context.Context) (*models.SiteInfo, error)
|
||||
Users(ctx context.Context) ([]*models.User, error)
|
||||
Users(ctx context.Context, filter *models.Filter) ([]*models.User, error)
|
||||
MyUser(ctx context.Context) (*models.User, error)
|
||||
MyAlbums(ctx context.Context) ([]*models.Album, error)
|
||||
MyAlbums(ctx context.Context, filter *models.Filter) ([]*models.Album, error)
|
||||
Album(ctx context.Context, id *string) (*models.Album, error)
|
||||
MyPhotos(ctx context.Context) ([]*models.Photo, error)
|
||||
MyPhotos(ctx context.Context, filter *models.Filter) ([]*models.Photo, error)
|
||||
Photo(ctx context.Context, id string) (*models.Photo, error)
|
||||
}
|
||||
|
||||
@@ -210,7 +210,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Album.Photos(childComplexity), true
|
||||
args, err := ec.field_Album_photos_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Album.Photos(childComplexity, args["filter"].(*models.Filter)), true
|
||||
|
||||
case "Album.subAlbums":
|
||||
if e.complexity.Album.SubAlbums == nil {
|
||||
@@ -473,14 +478,24 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Query.MyAlbums(childComplexity), true
|
||||
args, err := ec.field_Query_myAlbums_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Query.MyAlbums(childComplexity, args["filter"].(*models.Filter)), true
|
||||
|
||||
case "Query.myPhotos":
|
||||
if e.complexity.Query.MyPhotos == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Query.MyPhotos(childComplexity), true
|
||||
args, err := ec.field_Query_myPhotos_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Query.MyPhotos(childComplexity, args["filter"].(*models.Filter)), true
|
||||
|
||||
case "Query.myUser":
|
||||
if e.complexity.Query.MyUser == nil {
|
||||
@@ -513,7 +528,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Query.Users(childComplexity), true
|
||||
args, err := ec.field_Query_users_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Query.Users(childComplexity, args["filter"].(*models.Filter)), true
|
||||
|
||||
case "ScannerResult.finished":
|
||||
if e.complexity.ScannerResult.Finished == nil {
|
||||
@@ -644,21 +664,33 @@ var parsedSchema = gqlparser.MustLoadSchema(
|
||||
|
||||
scalar Time
|
||||
|
||||
enum OrderDirection {
|
||||
ASC
|
||||
DESC
|
||||
}
|
||||
|
||||
input Filter {
|
||||
order_by: String
|
||||
order_direction: OrderDirection
|
||||
limit: Int
|
||||
offset: Int
|
||||
}
|
||||
|
||||
type Query {
|
||||
siteInfo: SiteInfo!
|
||||
|
||||
"List of registered users, must be admin to call"
|
||||
users: [User!]! @isAdmin
|
||||
users(filter: Filter): [User!]! @isAdmin
|
||||
"Information about the currently logged in user"
|
||||
myUser: User!
|
||||
|
||||
"List of albums owned by the logged in user"
|
||||
myAlbums: [Album!]!
|
||||
myAlbums(filter: Filter): [Album!]!
|
||||
"Get album by id, user must own the album or be admin"
|
||||
album(id: ID): Album!
|
||||
|
||||
"List of photos owned by the logged in user"
|
||||
myPhotos: [Photo!]!
|
||||
myPhotos(filter: Filter): [Photo!]!
|
||||
"Get photo by id, user must own the photo or be admin"
|
||||
photo(id: ID!): Photo!
|
||||
}
|
||||
@@ -717,7 +749,7 @@ type User {
|
||||
type Album {
|
||||
id: ID!
|
||||
title: String!
|
||||
photos: [Photo!]!
|
||||
photos(filter: Filter): [Photo!]!
|
||||
subAlbums: [Album!]!
|
||||
parentAlbum: Album
|
||||
owner: User!
|
||||
@@ -783,6 +815,20 @@ type PhotoEXIF {
|
||||
|
||||
// region ***************************** args.gotpl *****************************
|
||||
|
||||
func (ec *executionContext) field_Album_photos_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 {
|
||||
arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["filter"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_authorizeUser_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
@@ -907,6 +953,34 @@ func (ec *executionContext) field_Query_album_args(ctx context.Context, rawArgs
|
||||
return args, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["filter"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Query_myPhotos_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 {
|
||||
arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["filter"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Query_photo_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
@@ -921,6 +995,20 @@ func (ec *executionContext) field_Query_photo_args(ctx context.Context, rawArgs
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Query_users_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 {
|
||||
arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["filter"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
@@ -1047,10 +1135,17 @@ func (ec *executionContext) _Album_photos(ctx context.Context, field graphql.Col
|
||||
IsMethod: true,
|
||||
}
|
||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Album_photos_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
rctx.Args = args
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Album().Photos(rctx, obj)
|
||||
return ec.resolvers.Album().Photos(rctx, obj, args["filter"].(*models.Filter))
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
@@ -2362,11 +2457,18 @@ func (ec *executionContext) _Query_users(ctx context.Context, field graphql.Coll
|
||||
IsMethod: true,
|
||||
}
|
||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Query_users_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
rctx.Args = args
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
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().Users(rctx)
|
||||
return ec.resolvers.Query().Users(rctx, args["filter"].(*models.Filter))
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.IsAdmin == nil {
|
||||
@@ -2456,10 +2558,17 @@ func (ec *executionContext) _Query_myAlbums(ctx context.Context, field graphql.C
|
||||
IsMethod: true,
|
||||
}
|
||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Query_myAlbums_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
rctx.Args = args
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
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)
|
||||
return ec.resolvers.Query().MyAlbums(rctx, args["filter"].(*models.Filter))
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
@@ -2537,10 +2646,17 @@ func (ec *executionContext) _Query_myPhotos(ctx context.Context, field graphql.C
|
||||
IsMethod: true,
|
||||
}
|
||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Query_myPhotos_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
rctx.Args = args
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Query().MyPhotos(rctx)
|
||||
return ec.resolvers.Query().MyPhotos(rctx, args["filter"].(*models.Filter))
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
@@ -4175,6 +4291,42 @@ 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
|
||||
var asMap = obj.(map[string]interface{})
|
||||
|
||||
for k, v := range asMap {
|
||||
switch k {
|
||||
case "order_by":
|
||||
var err error
|
||||
it.OrderBy, err = ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
case "order_direction":
|
||||
var err error
|
||||
it.OrderDirection, err = ec.unmarshalOOrderDirection2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
case "limit":
|
||||
var err error
|
||||
it.Limit, err = ec.unmarshalOInt2ᚖint(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
case "offset":
|
||||
var err error
|
||||
it.Offset, err = ec.unmarshalOInt2ᚖint(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return it, nil
|
||||
}
|
||||
|
||||
// endregion **************************** input.gotpl *****************************
|
||||
|
||||
// region ************************** interface.gotpl ***************************
|
||||
@@ -5554,6 +5706,18 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast
|
||||
return ec.marshalOBoolean2bool(ctx, sel, *v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalOFilter2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx context.Context, v interface{}) (models.Filter, error) {
|
||||
return ec.unmarshalInputFilter(ctx, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalOFilter2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx context.Context, v interface{}) (*models.Filter, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
res, err := ec.unmarshalOFilter2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, v)
|
||||
return &res, err
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalOFloat2float64(ctx context.Context, v interface{}) (float64, error) {
|
||||
return graphql.UnmarshalFloat(v)
|
||||
}
|
||||
@@ -5623,6 +5787,30 @@ func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.Sele
|
||||
return ec.marshalOInt2int(ctx, sel, *v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalOOrderDirection2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx context.Context, v interface{}) (models.OrderDirection, error) {
|
||||
var res models.OrderDirection
|
||||
return res, res.UnmarshalGQL(v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOOrderDirection2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx context.Context, sel ast.SelectionSet, v models.OrderDirection) graphql.Marshaler {
|
||||
return v
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalOOrderDirection2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx context.Context, v interface{}) (*models.OrderDirection, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
res, err := ec.unmarshalOOrderDirection2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx, v)
|
||||
return &res, err
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOOrderDirection2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx context.Context, sel ast.SelectionSet, v *models.OrderDirection) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOPhoto2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPhoto(ctx context.Context, sel ast.SelectionSet, v models.Photo) graphql.Marshaler {
|
||||
return ec._Photo(ctx, sel, &v)
|
||||
}
|
||||
|
||||
@@ -26,3 +26,17 @@ func NewAlbumFromRow(row *sql.Row) (*Album, error) {
|
||||
|
||||
return &album, nil
|
||||
}
|
||||
|
||||
func NewAlbumsFromRows(rows *sql.Rows) ([]*Album, error) {
|
||||
albums := make([]*Album, 0)
|
||||
|
||||
for rows.Next() {
|
||||
var album Album
|
||||
if err := rows.Scan(&album.AlbumID, &album.Title, &album.ParentAlbum, &album.OwnerID, &album.Path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
albums = append(albums, &album)
|
||||
}
|
||||
|
||||
return albums, nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -12,6 +15,13 @@ 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"`
|
||||
}
|
||||
|
||||
// EXIF metadata from the camera
|
||||
type PhotoExif struct {
|
||||
Photo *Photo `json:"photo"`
|
||||
@@ -47,3 +57,44 @@ type ScannerResult struct {
|
||||
type SiteInfo struct {
|
||||
InitialSetup bool `json:"initialSetup"`
|
||||
}
|
||||
|
||||
type OrderDirection string
|
||||
|
||||
const (
|
||||
OrderDirectionAsc OrderDirection = "ASC"
|
||||
OrderDirectionDesc OrderDirection = "DESC"
|
||||
)
|
||||
|
||||
var AllOrderDirection = []OrderDirection{
|
||||
OrderDirectionAsc,
|
||||
OrderDirectionDesc,
|
||||
}
|
||||
|
||||
func (e OrderDirection) IsValid() bool {
|
||||
switch e {
|
||||
case OrderDirectionAsc, OrderDirectionDesc:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e OrderDirection) String() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
func (e *OrderDirection) UnmarshalGQL(v interface{}) error {
|
||||
str, ok := v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("enums must be strings")
|
||||
}
|
||||
|
||||
*e = OrderDirection(str)
|
||||
if !e.IsValid() {
|
||||
return fmt.Errorf("%s is not a valid OrderDirection", str)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e OrderDirection) MarshalGQL(w io.Writer) {
|
||||
fmt.Fprint(w, strconv.Quote(e.String()))
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -61,7 +63,12 @@ func NewPhotosFromRows(rows *sql.Rows) ([]*Photo, error) {
|
||||
}
|
||||
|
||||
func (p *PhotoURL) URL() string {
|
||||
return fmt.Sprintf("/photo/%s", p.PhotoName)
|
||||
imageUrl, err := url.Parse(os.Getenv("API_ENDPOINT"))
|
||||
if err != nil {
|
||||
return path.Join("/photo", p.PhotoName)
|
||||
}
|
||||
imageUrl.Path = path.Join(imageUrl.Path, "photo", p.PhotoName)
|
||||
return imageUrl.String()
|
||||
}
|
||||
|
||||
func NewPhotoURLFromRow(row *sql.Row) (*PhotoURL, error) {
|
||||
|
||||
47
api/graphql/models/utils.go
Normal file
47
api/graphql/models/utils.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (filter *Filter) FormatSQL() (string, error) {
|
||||
if filter == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
result := ""
|
||||
|
||||
if filter.Limit != nil {
|
||||
log.Println("Limit")
|
||||
offset := 0
|
||||
if filter.Offset != nil && *filter.Offset >= 0 {
|
||||
offset = *filter.Offset
|
||||
}
|
||||
|
||||
result += fmt.Sprintf(" LIMIT %d OFFSET %d", *filter.Limit, offset)
|
||||
}
|
||||
|
||||
if filter.OrderBy != nil {
|
||||
log.Println("Order by")
|
||||
order_by := filter.OrderBy
|
||||
match, err := regexp.MatchString("^(\\w+(,\\s*))*\\w+$", strings.TrimSpace(*filter.OrderBy))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if match {
|
||||
direction := "ASC"
|
||||
if filter.OrderDirection != nil && filter.OrderDirection.IsValid() {
|
||||
direction = filter.OrderDirection.String()
|
||||
}
|
||||
|
||||
result += fmt.Sprintf(" ORDER BY %s %s", *order_by, direction)
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Filter: " + result)
|
||||
return result, nil
|
||||
}
|
||||
@@ -8,9 +8,30 @@ import (
|
||||
"github.com/viktorstrate/photoview/api/graphql/models"
|
||||
)
|
||||
|
||||
func (r *queryResolver) MyAlbums(ctx context.Context) ([]*models.Album, error) {
|
||||
panic("Not implemented")
|
||||
func (r *queryResolver) MyAlbums(ctx context.Context, filter *models.Filter) ([]*models.Album, error) {
|
||||
user := auth.UserFromContext(ctx)
|
||||
if user == nil {
|
||||
return nil, auth.ErrUnauthorized
|
||||
}
|
||||
|
||||
filterSQL, err := filter.FormatSQL()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := r.Database.Query("SELECT * FROM album WHERE owner_id = ? AND parent_album IS NULL"+filterSQL, user.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
albums, err := models.NewAlbumsFromRows(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return albums, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Album(ctx context.Context, id *string) (*models.Album, error) {
|
||||
user := auth.UserFromContext(ctx)
|
||||
if user == nil {
|
||||
@@ -32,8 +53,14 @@ func (r *Resolver) Album() api.AlbumResolver {
|
||||
|
||||
type albumResolver struct{ *Resolver }
|
||||
|
||||
func (r *albumResolver) Photos(ctx context.Context, obj *models.Album) ([]*models.Photo, error) {
|
||||
photoRows, err := r.Database.Query("SELECT photo.* FROM album, photo WHERE album.album_id = ? AND photo.album_id = album.album_id", obj.AlbumID)
|
||||
func (r *albumResolver) Photos(ctx context.Context, obj *models.Album, filter *models.Filter) ([]*models.Photo, error) {
|
||||
|
||||
filterSQL, err := filter.FormatSQL()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
photoRows, err := r.Database.Query("SELECT photo.* FROM album, photo WHERE album.album_id = ? AND photo.album_id = album.album_id"+filterSQL, obj.AlbumID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +75,17 @@ func (r *albumResolver) Photos(ctx context.Context, obj *models.Album) ([]*model
|
||||
}
|
||||
|
||||
func (r *albumResolver) SubAlbums(ctx context.Context, obj *models.Album) ([]*models.Album, error) {
|
||||
panic("not implemented")
|
||||
rows, err := r.Database.Query("SELECT * FROM album WHERE parent_album = ?", obj.AlbumID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
albums, err := models.NewAlbumsFromRows(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return albums, nil
|
||||
}
|
||||
|
||||
func (r *albumResolver) ParentAlbum(ctx context.Context, obj *models.Album) (*models.Album, error) {
|
||||
|
||||
@@ -9,13 +9,18 @@ import (
|
||||
"github.com/viktorstrate/photoview/api/graphql/models"
|
||||
)
|
||||
|
||||
func (r *queryResolver) MyPhotos(ctx context.Context) ([]*models.Photo, error) {
|
||||
func (r *queryResolver) MyPhotos(ctx context.Context, filter *models.Filter) ([]*models.Photo, error) {
|
||||
user := auth.UserFromContext(ctx)
|
||||
if user == nil {
|
||||
return nil, errors.New("unauthorized")
|
||||
}
|
||||
|
||||
rows, err := r.Database.Query("SELECT photo.* FROM photo, album WHERE photo.album_id = album.album_id AND album.owner_id = ?", user.UserID)
|
||||
filterSQL, err := filter.FormatSQL()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := r.Database.Query("SELECT photo.* FROM photo, album WHERE photo.album_id = album.album_id AND album.owner_id = ?"+filterSQL, user.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -14,9 +14,14 @@ import (
|
||||
|
||||
// type userResolver struct{ *Resolver }
|
||||
|
||||
func (r *queryResolver) Users(ctx context.Context) ([]*models.User, error) {
|
||||
func (r *queryResolver) Users(ctx context.Context, filter *models.Filter) ([]*models.User, error) {
|
||||
|
||||
rows, err := r.Database.Query("SELECT * FROM users")
|
||||
filterSQL, err := filter.FormatSQL()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := r.Database.Query("SELECT * FROM users" + filterSQL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2,21 +2,33 @@ directive @isAdmin on FIELD_DEFINITION
|
||||
|
||||
scalar Time
|
||||
|
||||
enum OrderDirection {
|
||||
ASC
|
||||
DESC
|
||||
}
|
||||
|
||||
input Filter {
|
||||
order_by: String
|
||||
order_direction: OrderDirection
|
||||
limit: Int
|
||||
offset: Int
|
||||
}
|
||||
|
||||
type Query {
|
||||
siteInfo: SiteInfo!
|
||||
|
||||
"List of registered users, must be admin to call"
|
||||
users: [User!]! @isAdmin
|
||||
users(filter: Filter): [User!]! @isAdmin
|
||||
"Information about the currently logged in user"
|
||||
myUser: User!
|
||||
|
||||
"List of albums owned by the logged in user"
|
||||
myAlbums: [Album!]!
|
||||
myAlbums(filter: Filter): [Album!]!
|
||||
"Get album by id, user must own the album or be admin"
|
||||
album(id: ID): Album!
|
||||
|
||||
"List of photos owned by the logged in user"
|
||||
myPhotos: [Photo!]!
|
||||
myPhotos(filter: Filter): [Photo!]!
|
||||
"Get photo by id, user must own the photo or be admin"
|
||||
photo(id: ID!): Photo!
|
||||
}
|
||||
@@ -75,7 +87,7 @@ type User {
|
||||
type Album {
|
||||
id: ID!
|
||||
title: String!
|
||||
photos: [Photo!]!
|
||||
photos(filter: Filter): [Photo!]!
|
||||
subAlbums: [Album!]!
|
||||
parentAlbum: Album
|
||||
owner: User!
|
||||
|
||||
@@ -120,8 +120,6 @@ func scan(database *sql.DB, user *models.User) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Content type: %s\n", *content_type)
|
||||
|
||||
if err := ProcessImage(tx, photoPath, albumId, *content_type); err != nil {
|
||||
log.Printf("ERROR: processing image %s: %s", photoPath, err)
|
||||
tx.Rollback()
|
||||
|
||||
Reference in New Issue
Block a user