diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 04772b63..2a665056 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,20 +1,22 @@ name: Docker builds on: - pull_request: - branches: [master] push: - branches: [master] + branches: ['*'] tags: - v* + pull_request: + branches: [master] schedule: # At 01:18 every Thursday. Details in https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule - cron: '18 1 * * 4' env: IS_PUSHING_IMAGES: ${{ github.event_name != 'pull_request' && github.repository == 'photoview/photoview' }} + # IS_PUSHING_IMAGES: true # Switch on when pushing images with forked repos. + DOCKER_REGISTRY: ${{ (github.repository == 'photoview/photoview' && '') || 'ghcr.io/' }} DOCKER_USERNAME: viktorstrate - DOCKER_IMAGE: viktorstrate/photoview + DOCKER_IMAGE: ${{ (github.repository == 'photoview/photoview' && 'viktorstrate/photoview') || github.repository }} DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} PLATFORMS: linux/amd64,linux/arm64,linux/arm/v7 @@ -82,7 +84,6 @@ jobs: with: platforms: ${{ env.PLATFORMS }} - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -90,15 +91,16 @@ jobs: if: ${{ env.IS_PUSHING_IMAGES == 'true' }} uses: docker/login-action@v3 with: - username: ${{ env.DOCKER_USERNAME }} - password: ${{ env.DOCKER_PASSWORD }} + registry: ${{ env.DOCKER_REGISTRY == 'ghcr.io/' && 'ghcr.io' }} + username: ${{ ( env.DOCKER_REGISTRY == 'ghcr.io/' && github.actor ) || env.DOCKER_USERNAME }} + password: ${{ ( env.DOCKER_REGISTRY == 'ghcr.io/' && github.token ) || env.DOCKER_PASSWORD }} - name: Docker meta id: docker_meta uses: docker/metadata-action@v5 with: # list of Docker images to use as base name for tags - images: ${{ env.DOCKER_IMAGE }} + images: ${{ env.DOCKER_REGISTRY }}${{ env.DOCKER_IMAGE }} # Docker tags based on the following events/attributes tags: | type=schedule @@ -152,13 +154,13 @@ jobs: username: ${{ env.DOCKER_USERNAME }} password: ${{ env.DOCKER_PASSWORD }} - - name: Run Dockle for '${{ env.DOCKER_IMAGE }}:${{ matrix.tags.tag }}' + - name: Run Dockle for '${{ env.DOCKER_REGISTRY }}${{ env.DOCKER_IMAGE }}:${{ matrix.tags.tag }}' id: dockle if: ${{ matrix.tags.tag != '' }} continue-on-error: true uses: erzz/dockle-action@v1 with: - image: '${{ env.DOCKER_IMAGE }}:${{ matrix.tags.tag }}' + image: '${{ env.DOCKER_REGISTRY }}${{ env.DOCKER_IMAGE }}:${{ matrix.tags.tag }}' report-name: dockle-results-${{ matrix.tags.tag }} report-format: sarif failure-threshold: fatal diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index eb6e01ab..b4018395 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,7 +2,7 @@ name: Tests on: push: - branches: [master] + branches: ['*'] pull_request: branches: [master] @@ -69,12 +69,13 @@ jobs: continue-on-error: true run: | docker run --name test --network host \ + -v "${{ github.workspace }}:/app" \ -e PHOTOVIEW_DATABASE_DRIVER=${{ matrix.database }} \ -e PHOTOVIEW_MYSQL_URL='photoview:photosecret@tcp(localhost:3306)/photoview_test' \ -e PHOTOVIEW_POSTGRES_URL='postgres://photoview:photosecret@localhost:5432/photoview_test' \ -e PHOTOVIEW_SQLITE_PATH=/tmp/photoview.db \ photoview/api \ - go test ./... -v -database -filesystem -p 1 -coverprofile=coverage.txt -covermode=atomic + /app/scripts/test_all.sh docker cp test:/app/api/coverage.txt ./api/ - name: Upload coverage diff --git a/Dockerfile b/Dockerfile index ba8f98a1..16f28c53 100644 --- a/Dockerfile +++ b/Dockerfile @@ -68,6 +68,7 @@ COPY --from=viktorstrate/dependencies /artifacts.tar.gz /dependencies/ # Split values in `/env` # hadolint ignore=SC2046 RUN export $(cat /env) \ + && git config --global --add safe.directory /app \ && cd /dependencies/ \ && tar xfv artifacts.tar.gz \ && cp -a include/* /usr/local/include/ \ diff --git a/api/gqlgen.yml b/api/gqlgen.yml index 1e4772b1..ac961d47 100644 --- a/api/gqlgen.yml +++ b/api/gqlgen.yml @@ -14,7 +14,7 @@ resolver: layout: follow-schema dir: graphql/resolvers package: resolvers - filename_template: "{name}.generated.go" + filename_template: "{name}.go" autobind: [] diff --git a/api/graphql/generated.go b/api/graphql/generated.go index f43434a0..4dbdbe97 100644 --- a/api/graphql/generated.go +++ b/api/graphql/generated.go @@ -314,23 +314,6 @@ type MediaResolver interface { Faces(ctx context.Context, obj *models.Media) ([]*models.ImageFace, error) } type MutationResolver interface { - AuthorizeUser(ctx context.Context, username string, password string) (*models.AuthorizeResult, error) - InitialSetupWizard(ctx context.Context, username string, password string, rootPath string) (*models.AuthorizeResult, error) - ScanAll(ctx context.Context) (*models.ScannerResult, error) - ScanUser(ctx context.Context, userID int) (*models.ScannerResult, error) - ShareAlbum(ctx context.Context, albumID int, expire *time.Time, password *string) (*models.ShareToken, error) - ShareMedia(ctx context.Context, mediaID int, expire *time.Time, password *string) (*models.ShareToken, error) - DeleteShareToken(ctx context.Context, token string) (*models.ShareToken, error) - ProtectShareToken(ctx context.Context, token string, password *string) (*models.ShareToken, error) - UpdateUser(ctx context.Context, id int, username *string, password *string, admin *bool) (*models.User, error) - CreateUser(ctx context.Context, username string, password *string, admin bool) (*models.User, error) - DeleteUser(ctx context.Context, id int) (*models.User, error) - UserAddRootPath(ctx context.Context, id int, rootPath string) (*models.Album, error) - UserRemoveRootAlbum(ctx context.Context, userID int, albumID int) (*models.Album, error) - SetPeriodicScanInterval(ctx context.Context, interval int) (int, error) - SetScannerConcurrentWorkers(ctx context.Context, workers int) (int, error) - SetThumbnailDownsampleMethod(ctx context.Context, method models.ThumbnailFilter) (models.ThumbnailFilter, error) - ChangeUserPreferences(ctx context.Context, language *string) (*models.UserPreferences, error) ResetAlbumCover(ctx context.Context, albumID int) (*models.Album, error) SetAlbumCover(ctx context.Context, coverID int) (*models.Album, error) SetFaceGroupLabel(ctx context.Context, faceGroupID int, label *string) (*models.FaceGroup, error) @@ -339,16 +322,25 @@ type MutationResolver interface { RecognizeUnlabeledFaces(ctx context.Context) ([]*models.ImageFace, error) DetachImageFaces(ctx context.Context, imageFaceIDs []int) (*models.FaceGroup, error) FavoriteMedia(ctx context.Context, mediaID int, favorite bool) (*models.Media, error) + ScanAll(ctx context.Context) (*models.ScannerResult, error) + ScanUser(ctx context.Context, userID int) (*models.ScannerResult, error) + SetPeriodicScanInterval(ctx context.Context, interval int) (int, error) + SetScannerConcurrentWorkers(ctx context.Context, workers int) (int, error) + ShareAlbum(ctx context.Context, albumID int, expire *time.Time, password *string) (*models.ShareToken, error) + ShareMedia(ctx context.Context, mediaID int, expire *time.Time, password *string) (*models.ShareToken, error) + DeleteShareToken(ctx context.Context, token string) (*models.ShareToken, error) + ProtectShareToken(ctx context.Context, token string, password *string) (*models.ShareToken, error) + SetThumbnailDownsampleMethod(ctx context.Context, method models.ThumbnailFilter) (models.ThumbnailFilter, error) + AuthorizeUser(ctx context.Context, username string, password string) (*models.AuthorizeResult, error) + InitialSetupWizard(ctx context.Context, username string, password string, rootPath string) (*models.AuthorizeResult, error) + UpdateUser(ctx context.Context, id int, username *string, password *string, admin *bool) (*models.User, error) + CreateUser(ctx context.Context, username string, password *string, admin bool) (*models.User, error) + DeleteUser(ctx context.Context, id int) (*models.User, error) + UserAddRootPath(ctx context.Context, id int, rootPath string) (*models.Album, error) + UserRemoveRootAlbum(ctx context.Context, userID int, albumID int) (*models.Album, error) + ChangeUserPreferences(ctx context.Context, language *string) (*models.UserPreferences, error) } type QueryResolver interface { - SiteInfo(ctx context.Context) (*models.SiteInfo, error) - User(ctx context.Context, order *models.Ordering, paginate *models.Pagination) ([]*models.User, error) - MyUser(ctx context.Context) (*models.User, error) - MyUserPreferences(ctx context.Context) (*models.UserPreferences, error) - MyTimeline(ctx context.Context, paginate *models.Pagination, onlyFavorites *bool, fromDate *time.Time) ([]*models.Media, error) - ShareToken(ctx context.Context, credentials models.ShareTokenCredentials) (*models.ShareToken, error) - ShareTokenValidatePassword(ctx context.Context, credentials models.ShareTokenCredentials) (bool, error) - Search(ctx context.Context, query string, limitMedia *int, limitAlbums *int) (*models.SearchResult, 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, tokenCredentials *models.ShareTokenCredentials) (*models.Album, error) MyFaceGroups(ctx context.Context, paginate *models.Pagination) ([]*models.FaceGroup, error) @@ -358,6 +350,14 @@ type QueryResolver interface { MediaList(ctx context.Context, ids []int) ([]*models.Media, error) MyMediaGeoJSON(ctx context.Context) (any, error) MapboxToken(ctx context.Context) (*string, error) + Search(ctx context.Context, query string, limitMedia *int, limitAlbums *int) (*models.SearchResult, error) + ShareToken(ctx context.Context, credentials models.ShareTokenCredentials) (*models.ShareToken, error) + ShareTokenValidatePassword(ctx context.Context, credentials models.ShareTokenCredentials) (bool, error) + SiteInfo(ctx context.Context) (*models.SiteInfo, error) + MyTimeline(ctx context.Context, paginate *models.Pagination, onlyFavorites *bool, fromDate *time.Time) ([]*models.Media, error) + User(ctx context.Context, order *models.Ordering, paginate *models.Pagination) ([]*models.User, error) + MyUser(ctx context.Context) (*models.User, error) + MyUserPreferences(ctx context.Context) (*models.UserPreferences, error) } type ShareTokenResolver interface { HasPassword(ctx context.Context, obj *models.ShareToken) (bool, error) @@ -1784,7 +1784,7 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil } -//go:embed "resolvers/album.graphql" "resolvers/faces.graphql" "resolvers/media.graphql" "resolvers/media_geo_json.graphql" "resolvers/schema.graphql" +//go:embed "resolvers/album.graphql" "resolvers/faces.graphql" "resolvers/media.graphql" "resolvers/media_geo_json.graphql" "resolvers/notification.graphql" "resolvers/root.graphql" "resolvers/scanner.graphql" "resolvers/search.graphql" "resolvers/share_token.graphql" "resolvers/site_info.graphql" "resolvers/thumbnails.graphql" "resolvers/timeline.graphql" "resolvers/user.graphql" var sourcesFS embed.FS func sourceData(filename string) string { @@ -1800,7 +1800,15 @@ var sources = []*ast.Source{ {Name: "resolvers/faces.graphql", Input: sourceData("resolvers/faces.graphql"), BuiltIn: false}, {Name: "resolvers/media.graphql", Input: sourceData("resolvers/media.graphql"), BuiltIn: false}, {Name: "resolvers/media_geo_json.graphql", Input: sourceData("resolvers/media_geo_json.graphql"), BuiltIn: false}, - {Name: "resolvers/schema.graphql", Input: sourceData("resolvers/schema.graphql"), BuiltIn: false}, + {Name: "resolvers/notification.graphql", Input: sourceData("resolvers/notification.graphql"), BuiltIn: false}, + {Name: "resolvers/root.graphql", Input: sourceData("resolvers/root.graphql"), BuiltIn: false}, + {Name: "resolvers/scanner.graphql", Input: sourceData("resolvers/scanner.graphql"), BuiltIn: false}, + {Name: "resolvers/search.graphql", Input: sourceData("resolvers/search.graphql"), BuiltIn: false}, + {Name: "resolvers/share_token.graphql", Input: sourceData("resolvers/share_token.graphql"), BuiltIn: false}, + {Name: "resolvers/site_info.graphql", Input: sourceData("resolvers/site_info.graphql"), BuiltIn: false}, + {Name: "resolvers/thumbnails.graphql", Input: sourceData("resolvers/thumbnails.graphql"), BuiltIn: false}, + {Name: "resolvers/timeline.graphql", Input: sourceData("resolvers/timeline.graphql"), BuiltIn: false}, + {Name: "resolvers/user.graphql", Input: sourceData("resolvers/user.graphql"), BuiltIn: false}, } var parsedSchema = gqlparser.MustLoadSchema(sources...) @@ -7197,1437 +7205,6 @@ func (ec *executionContext) fieldContext_MediaURL_fileSize(_ context.Context, fi return fc, nil } -func (ec *executionContext) _Mutation_authorizeUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_authorizeUser(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().AuthorizeUser(rctx, fc.Args["username"].(string), fc.Args["password"].(string)) - }) - 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.AuthorizeResult) - fc.Result = res - return ec.marshalNAuthorizeResult2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAuthorizeResult(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_authorizeUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "success": - return ec.fieldContext_AuthorizeResult_success(ctx, field) - case "status": - return ec.fieldContext_AuthorizeResult_status(ctx, field) - case "token": - return ec.fieldContext_AuthorizeResult_token(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type AuthorizeResult", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_authorizeUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_initialSetupWizard(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_initialSetupWizard(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().InitialSetupWizard(rctx, fc.Args["username"].(string), fc.Args["password"].(string), fc.Args["rootPath"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*models.AuthorizeResult) - fc.Result = res - return ec.marshalOAuthorizeResult2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAuthorizeResult(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_initialSetupWizard(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "success": - return ec.fieldContext_AuthorizeResult_success(ctx, field) - case "status": - return ec.fieldContext_AuthorizeResult_status(ctx, field) - case "token": - return ec.fieldContext_AuthorizeResult_token(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type AuthorizeResult", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_initialSetupWizard_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_scanAll(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_scanAll(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().ScanAll(rctx) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAdmin == nil { - var zeroVal *models.ScannerResult - return zeroVal, errors.New("directive isAdmin is not implemented") - } - return ec.directives.IsAdmin(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.(*models.ScannerResult); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ScannerResult`, tmp) - }) - 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.ScannerResult) - fc.Result = res - return ec.marshalNScannerResult2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐScannerResult(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_scanAll(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "finished": - return ec.fieldContext_ScannerResult_finished(ctx, field) - case "success": - return ec.fieldContext_ScannerResult_success(ctx, field) - case "progress": - return ec.fieldContext_ScannerResult_progress(ctx, field) - case "message": - return ec.fieldContext_ScannerResult_message(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type ScannerResult", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Mutation_scanUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_scanUser(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().ScanUser(rctx, fc.Args["userId"].(int)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAdmin == nil { - var zeroVal *models.ScannerResult - return zeroVal, errors.New("directive isAdmin is not implemented") - } - return ec.directives.IsAdmin(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.(*models.ScannerResult); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ScannerResult`, tmp) - }) - 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.ScannerResult) - fc.Result = res - return ec.marshalNScannerResult2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐScannerResult(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_scanUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "finished": - return ec.fieldContext_ScannerResult_finished(ctx, field) - case "success": - return ec.fieldContext_ScannerResult_success(ctx, field) - case "progress": - return ec.fieldContext_ScannerResult_progress(ctx, field) - case "message": - return ec.fieldContext_ScannerResult_message(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type ScannerResult", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_scanUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_shareAlbum(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_shareAlbum(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().ShareAlbum(rctx, fc.Args["albumId"].(int), fc.Args["expire"].(*time.Time), fc.Args["password"].(*string)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAuthorized == nil { - var zeroVal *models.ShareToken - return zeroVal, 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.(*models.ShareToken); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ShareToken`, tmp) - }) - 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.ShareToken) - fc.Result = res - return ec.marshalNShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_shareAlbum(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_ShareToken_id(ctx, field) - case "token": - return ec.fieldContext_ShareToken_token(ctx, field) - case "owner": - return ec.fieldContext_ShareToken_owner(ctx, field) - case "expire": - return ec.fieldContext_ShareToken_expire(ctx, field) - case "hasPassword": - return ec.fieldContext_ShareToken_hasPassword(ctx, field) - case "album": - return ec.fieldContext_ShareToken_album(ctx, field) - case "media": - return ec.fieldContext_ShareToken_media(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type ShareToken", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_shareAlbum_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_shareMedia(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_shareMedia(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().ShareMedia(rctx, fc.Args["mediaId"].(int), fc.Args["expire"].(*time.Time), fc.Args["password"].(*string)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAuthorized == nil { - var zeroVal *models.ShareToken - return zeroVal, 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.(*models.ShareToken); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ShareToken`, tmp) - }) - 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.ShareToken) - fc.Result = res - return ec.marshalNShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_shareMedia(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_ShareToken_id(ctx, field) - case "token": - return ec.fieldContext_ShareToken_token(ctx, field) - case "owner": - return ec.fieldContext_ShareToken_owner(ctx, field) - case "expire": - return ec.fieldContext_ShareToken_expire(ctx, field) - case "hasPassword": - return ec.fieldContext_ShareToken_hasPassword(ctx, field) - case "album": - return ec.fieldContext_ShareToken_album(ctx, field) - case "media": - return ec.fieldContext_ShareToken_media(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type ShareToken", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_shareMedia_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_deleteShareToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_deleteShareToken(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().DeleteShareToken(rctx, fc.Args["token"].(string)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAuthorized == nil { - var zeroVal *models.ShareToken - return zeroVal, 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.(*models.ShareToken); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ShareToken`, tmp) - }) - 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.ShareToken) - fc.Result = res - return ec.marshalNShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_deleteShareToken(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_ShareToken_id(ctx, field) - case "token": - return ec.fieldContext_ShareToken_token(ctx, field) - case "owner": - return ec.fieldContext_ShareToken_owner(ctx, field) - case "expire": - return ec.fieldContext_ShareToken_expire(ctx, field) - case "hasPassword": - return ec.fieldContext_ShareToken_hasPassword(ctx, field) - case "album": - return ec.fieldContext_ShareToken_album(ctx, field) - case "media": - return ec.fieldContext_ShareToken_media(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type ShareToken", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_deleteShareToken_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_protectShareToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_protectShareToken(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().ProtectShareToken(rctx, fc.Args["token"].(string), fc.Args["password"].(*string)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAuthorized == nil { - var zeroVal *models.ShareToken - return zeroVal, 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.(*models.ShareToken); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ShareToken`, tmp) - }) - 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.ShareToken) - fc.Result = res - return ec.marshalNShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_protectShareToken(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_ShareToken_id(ctx, field) - case "token": - return ec.fieldContext_ShareToken_token(ctx, field) - case "owner": - return ec.fieldContext_ShareToken_owner(ctx, field) - case "expire": - return ec.fieldContext_ShareToken_expire(ctx, field) - case "hasPassword": - return ec.fieldContext_ShareToken_hasPassword(ctx, field) - case "album": - return ec.fieldContext_ShareToken_album(ctx, field) - case "media": - return ec.fieldContext_ShareToken_media(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type ShareToken", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_protectShareToken_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_updateUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_updateUser(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().UpdateUser(rctx, fc.Args["id"].(int), fc.Args["username"].(*string), fc.Args["password"].(*string), fc.Args["admin"].(*bool)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAdmin == nil { - var zeroVal *models.User - return zeroVal, errors.New("directive isAdmin is not implemented") - } - return ec.directives.IsAdmin(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.(*models.User); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.User`, tmp) - }) - 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.User) - fc.Result = res - return ec.marshalNUser2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_updateUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "username": - return ec.fieldContext_User_username(ctx, field) - case "albums": - return ec.fieldContext_User_albums(ctx, field) - case "rootAlbums": - return ec.fieldContext_User_rootAlbums(ctx, field) - case "admin": - return ec.fieldContext_User_admin(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_updateUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_createUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_createUser(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().CreateUser(rctx, fc.Args["username"].(string), fc.Args["password"].(*string), fc.Args["admin"].(bool)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAdmin == nil { - var zeroVal *models.User - return zeroVal, errors.New("directive isAdmin is not implemented") - } - return ec.directives.IsAdmin(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.(*models.User); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.User`, tmp) - }) - 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.User) - fc.Result = res - return ec.marshalNUser2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_createUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "username": - return ec.fieldContext_User_username(ctx, field) - case "albums": - return ec.fieldContext_User_albums(ctx, field) - case "rootAlbums": - return ec.fieldContext_User_rootAlbums(ctx, field) - case "admin": - return ec.fieldContext_User_admin(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_createUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_deleteUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_deleteUser(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().DeleteUser(rctx, fc.Args["id"].(int)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAdmin == nil { - var zeroVal *models.User - return zeroVal, errors.New("directive isAdmin is not implemented") - } - return ec.directives.IsAdmin(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.(*models.User); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.User`, tmp) - }) - 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.User) - fc.Result = res - return ec.marshalNUser2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_deleteUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "username": - return ec.fieldContext_User_username(ctx, field) - case "albums": - return ec.fieldContext_User_albums(ctx, field) - case "rootAlbums": - return ec.fieldContext_User_rootAlbums(ctx, field) - case "admin": - return ec.fieldContext_User_admin(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_deleteUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_userAddRootPath(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_userAddRootPath(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().UserAddRootPath(rctx, fc.Args["id"].(int), fc.Args["rootPath"].(string)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAdmin == nil { - var zeroVal *models.Album - return zeroVal, errors.New("directive isAdmin is not implemented") - } - return ec.directives.IsAdmin(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.(*models.Album); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.Album`, tmp) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*models.Album) - fc.Result = res - return ec.marshalOAlbum2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_userAddRootPath(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Album_id(ctx, field) - case "title": - return ec.fieldContext_Album_title(ctx, field) - case "media": - return ec.fieldContext_Album_media(ctx, field) - case "subAlbums": - return ec.fieldContext_Album_subAlbums(ctx, field) - case "parentAlbum": - return ec.fieldContext_Album_parentAlbum(ctx, field) - case "owner": - return ec.fieldContext_Album_owner(ctx, field) - case "filePath": - return ec.fieldContext_Album_filePath(ctx, field) - case "thumbnail": - return ec.fieldContext_Album_thumbnail(ctx, field) - case "path": - return ec.fieldContext_Album_path(ctx, field) - case "shares": - return ec.fieldContext_Album_shares(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Album", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_userAddRootPath_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_userRemoveRootAlbum(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_userRemoveRootAlbum(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().UserRemoveRootAlbum(rctx, fc.Args["userId"].(int), fc.Args["albumId"].(int)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAdmin == nil { - var zeroVal *models.Album - return zeroVal, errors.New("directive isAdmin is not implemented") - } - return ec.directives.IsAdmin(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.(*models.Album); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.Album`, tmp) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*models.Album) - fc.Result = res - return ec.marshalOAlbum2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_userRemoveRootAlbum(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Album_id(ctx, field) - case "title": - return ec.fieldContext_Album_title(ctx, field) - case "media": - return ec.fieldContext_Album_media(ctx, field) - case "subAlbums": - return ec.fieldContext_Album_subAlbums(ctx, field) - case "parentAlbum": - return ec.fieldContext_Album_parentAlbum(ctx, field) - case "owner": - return ec.fieldContext_Album_owner(ctx, field) - case "filePath": - return ec.fieldContext_Album_filePath(ctx, field) - case "thumbnail": - return ec.fieldContext_Album_thumbnail(ctx, field) - case "path": - return ec.fieldContext_Album_path(ctx, field) - case "shares": - return ec.fieldContext_Album_shares(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Album", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_userRemoveRootAlbum_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_setPeriodicScanInterval(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_setPeriodicScanInterval(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().SetPeriodicScanInterval(rctx, fc.Args["interval"].(int)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAdmin == nil { - var zeroVal int - return zeroVal, errors.New("directive isAdmin is not implemented") - } - return ec.directives.IsAdmin(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.(int); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be int`, tmp) - }) - 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) fieldContext_Mutation_setPeriodicScanInterval(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_setPeriodicScanInterval_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_setScannerConcurrentWorkers(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_setScannerConcurrentWorkers(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().SetScannerConcurrentWorkers(rctx, fc.Args["workers"].(int)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAdmin == nil { - var zeroVal int - return zeroVal, errors.New("directive isAdmin is not implemented") - } - return ec.directives.IsAdmin(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.(int); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be int`, tmp) - }) - 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) fieldContext_Mutation_setScannerConcurrentWorkers(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_setScannerConcurrentWorkers_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_setThumbnailDownsampleMethod(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_setThumbnailDownsampleMethod(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().SetThumbnailDownsampleMethod(rctx, fc.Args["method"].(models.ThumbnailFilter)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAdmin == nil { - var zeroVal models.ThumbnailFilter - return zeroVal, errors.New("directive isAdmin is not implemented") - } - return ec.directives.IsAdmin(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.(models.ThumbnailFilter); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be github.com/photoview/photoview/api/graphql/models.ThumbnailFilter`, tmp) - }) - 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.ThumbnailFilter) - fc.Result = res - return ec.marshalNThumbnailFilter2githubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐThumbnailFilter(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_setThumbnailDownsampleMethod(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ThumbnailFilter does not have child fields") - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_setThumbnailDownsampleMethod_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Mutation_changeUserPreferences(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_changeUserPreferences(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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.Mutation().ChangeUserPreferences(rctx, fc.Args["language"].(*string)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAuthorized == nil { - var zeroVal *models.UserPreferences - return zeroVal, 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.(*models.UserPreferences); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.UserPreferences`, tmp) - }) - 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.UserPreferences) - fc.Result = res - return ec.marshalNUserPreferences2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUserPreferences(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_changeUserPreferences(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_UserPreferences_id(ctx, field) - case "language": - return ec.fieldContext_UserPreferences_language(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type UserPreferences", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_changeUserPreferences_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - func (ec *executionContext) _Mutation_resetAlbumCover(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Mutation_resetAlbumCover(ctx, field) if err != nil { @@ -9361,6 +7938,1437 @@ func (ec *executionContext) fieldContext_Mutation_favoriteMedia(ctx context.Cont return fc, nil } +func (ec *executionContext) _Mutation_scanAll(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_scanAll(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().ScanAll(rctx) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + var zeroVal *models.ScannerResult + return zeroVal, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(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.(*models.ScannerResult); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ScannerResult`, tmp) + }) + 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.ScannerResult) + fc.Result = res + return ec.marshalNScannerResult2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐScannerResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_scanAll(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "finished": + return ec.fieldContext_ScannerResult_finished(ctx, field) + case "success": + return ec.fieldContext_ScannerResult_success(ctx, field) + case "progress": + return ec.fieldContext_ScannerResult_progress(ctx, field) + case "message": + return ec.fieldContext_ScannerResult_message(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ScannerResult", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Mutation_scanUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_scanUser(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().ScanUser(rctx, fc.Args["userId"].(int)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + var zeroVal *models.ScannerResult + return zeroVal, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(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.(*models.ScannerResult); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ScannerResult`, tmp) + }) + 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.ScannerResult) + fc.Result = res + return ec.marshalNScannerResult2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐScannerResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_scanUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "finished": + return ec.fieldContext_ScannerResult_finished(ctx, field) + case "success": + return ec.fieldContext_ScannerResult_success(ctx, field) + case "progress": + return ec.fieldContext_ScannerResult_progress(ctx, field) + case "message": + return ec.fieldContext_ScannerResult_message(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ScannerResult", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_scanUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_setPeriodicScanInterval(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_setPeriodicScanInterval(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().SetPeriodicScanInterval(rctx, fc.Args["interval"].(int)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + var zeroVal int + return zeroVal, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(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.(int); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be int`, tmp) + }) + 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) fieldContext_Mutation_setPeriodicScanInterval(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_setPeriodicScanInterval_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_setScannerConcurrentWorkers(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_setScannerConcurrentWorkers(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().SetScannerConcurrentWorkers(rctx, fc.Args["workers"].(int)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + var zeroVal int + return zeroVal, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(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.(int); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be int`, tmp) + }) + 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) fieldContext_Mutation_setScannerConcurrentWorkers(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_setScannerConcurrentWorkers_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_shareAlbum(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_shareAlbum(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().ShareAlbum(rctx, fc.Args["albumId"].(int), fc.Args["expire"].(*time.Time), fc.Args["password"].(*string)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAuthorized == nil { + var zeroVal *models.ShareToken + return zeroVal, 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.(*models.ShareToken); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ShareToken`, tmp) + }) + 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.ShareToken) + fc.Result = res + return ec.marshalNShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_shareAlbum(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_ShareToken_id(ctx, field) + case "token": + return ec.fieldContext_ShareToken_token(ctx, field) + case "owner": + return ec.fieldContext_ShareToken_owner(ctx, field) + case "expire": + return ec.fieldContext_ShareToken_expire(ctx, field) + case "hasPassword": + return ec.fieldContext_ShareToken_hasPassword(ctx, field) + case "album": + return ec.fieldContext_ShareToken_album(ctx, field) + case "media": + return ec.fieldContext_ShareToken_media(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ShareToken", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_shareAlbum_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_shareMedia(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_shareMedia(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().ShareMedia(rctx, fc.Args["mediaId"].(int), fc.Args["expire"].(*time.Time), fc.Args["password"].(*string)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAuthorized == nil { + var zeroVal *models.ShareToken + return zeroVal, 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.(*models.ShareToken); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ShareToken`, tmp) + }) + 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.ShareToken) + fc.Result = res + return ec.marshalNShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_shareMedia(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_ShareToken_id(ctx, field) + case "token": + return ec.fieldContext_ShareToken_token(ctx, field) + case "owner": + return ec.fieldContext_ShareToken_owner(ctx, field) + case "expire": + return ec.fieldContext_ShareToken_expire(ctx, field) + case "hasPassword": + return ec.fieldContext_ShareToken_hasPassword(ctx, field) + case "album": + return ec.fieldContext_ShareToken_album(ctx, field) + case "media": + return ec.fieldContext_ShareToken_media(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ShareToken", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_shareMedia_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_deleteShareToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_deleteShareToken(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().DeleteShareToken(rctx, fc.Args["token"].(string)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAuthorized == nil { + var zeroVal *models.ShareToken + return zeroVal, 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.(*models.ShareToken); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ShareToken`, tmp) + }) + 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.ShareToken) + fc.Result = res + return ec.marshalNShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_deleteShareToken(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_ShareToken_id(ctx, field) + case "token": + return ec.fieldContext_ShareToken_token(ctx, field) + case "owner": + return ec.fieldContext_ShareToken_owner(ctx, field) + case "expire": + return ec.fieldContext_ShareToken_expire(ctx, field) + case "hasPassword": + return ec.fieldContext_ShareToken_hasPassword(ctx, field) + case "album": + return ec.fieldContext_ShareToken_album(ctx, field) + case "media": + return ec.fieldContext_ShareToken_media(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ShareToken", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_deleteShareToken_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_protectShareToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_protectShareToken(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().ProtectShareToken(rctx, fc.Args["token"].(string), fc.Args["password"].(*string)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAuthorized == nil { + var zeroVal *models.ShareToken + return zeroVal, 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.(*models.ShareToken); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.ShareToken`, tmp) + }) + 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.ShareToken) + fc.Result = res + return ec.marshalNShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_protectShareToken(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_ShareToken_id(ctx, field) + case "token": + return ec.fieldContext_ShareToken_token(ctx, field) + case "owner": + return ec.fieldContext_ShareToken_owner(ctx, field) + case "expire": + return ec.fieldContext_ShareToken_expire(ctx, field) + case "hasPassword": + return ec.fieldContext_ShareToken_hasPassword(ctx, field) + case "album": + return ec.fieldContext_ShareToken_album(ctx, field) + case "media": + return ec.fieldContext_ShareToken_media(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ShareToken", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_protectShareToken_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_setThumbnailDownsampleMethod(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_setThumbnailDownsampleMethod(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().SetThumbnailDownsampleMethod(rctx, fc.Args["method"].(models.ThumbnailFilter)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + var zeroVal models.ThumbnailFilter + return zeroVal, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(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.(models.ThumbnailFilter); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be github.com/photoview/photoview/api/graphql/models.ThumbnailFilter`, tmp) + }) + 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.ThumbnailFilter) + fc.Result = res + return ec.marshalNThumbnailFilter2githubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐThumbnailFilter(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_setThumbnailDownsampleMethod(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ThumbnailFilter does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_setThumbnailDownsampleMethod_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_authorizeUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_authorizeUser(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().AuthorizeUser(rctx, fc.Args["username"].(string), fc.Args["password"].(string)) + }) + 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.AuthorizeResult) + fc.Result = res + return ec.marshalNAuthorizeResult2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAuthorizeResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_authorizeUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "success": + return ec.fieldContext_AuthorizeResult_success(ctx, field) + case "status": + return ec.fieldContext_AuthorizeResult_status(ctx, field) + case "token": + return ec.fieldContext_AuthorizeResult_token(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type AuthorizeResult", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_authorizeUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_initialSetupWizard(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_initialSetupWizard(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().InitialSetupWizard(rctx, fc.Args["username"].(string), fc.Args["password"].(string), fc.Args["rootPath"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*models.AuthorizeResult) + fc.Result = res + return ec.marshalOAuthorizeResult2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAuthorizeResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_initialSetupWizard(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "success": + return ec.fieldContext_AuthorizeResult_success(ctx, field) + case "status": + return ec.fieldContext_AuthorizeResult_status(ctx, field) + case "token": + return ec.fieldContext_AuthorizeResult_token(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type AuthorizeResult", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_initialSetupWizard_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_updateUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_updateUser(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().UpdateUser(rctx, fc.Args["id"].(int), fc.Args["username"].(*string), fc.Args["password"].(*string), fc.Args["admin"].(*bool)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + var zeroVal *models.User + return zeroVal, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(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.(*models.User); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.User`, tmp) + }) + 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.User) + fc.Result = res + return ec.marshalNUser2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_updateUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "username": + return ec.fieldContext_User_username(ctx, field) + case "albums": + return ec.fieldContext_User_albums(ctx, field) + case "rootAlbums": + return ec.fieldContext_User_rootAlbums(ctx, field) + case "admin": + return ec.fieldContext_User_admin(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_updateUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_createUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_createUser(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().CreateUser(rctx, fc.Args["username"].(string), fc.Args["password"].(*string), fc.Args["admin"].(bool)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + var zeroVal *models.User + return zeroVal, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(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.(*models.User); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.User`, tmp) + }) + 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.User) + fc.Result = res + return ec.marshalNUser2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_createUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "username": + return ec.fieldContext_User_username(ctx, field) + case "albums": + return ec.fieldContext_User_albums(ctx, field) + case "rootAlbums": + return ec.fieldContext_User_rootAlbums(ctx, field) + case "admin": + return ec.fieldContext_User_admin(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_createUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_deleteUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_deleteUser(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().DeleteUser(rctx, fc.Args["id"].(int)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + var zeroVal *models.User + return zeroVal, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(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.(*models.User); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.User`, tmp) + }) + 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.User) + fc.Result = res + return ec.marshalNUser2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_deleteUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "username": + return ec.fieldContext_User_username(ctx, field) + case "albums": + return ec.fieldContext_User_albums(ctx, field) + case "rootAlbums": + return ec.fieldContext_User_rootAlbums(ctx, field) + case "admin": + return ec.fieldContext_User_admin(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_deleteUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_userAddRootPath(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_userAddRootPath(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().UserAddRootPath(rctx, fc.Args["id"].(int), fc.Args["rootPath"].(string)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + var zeroVal *models.Album + return zeroVal, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(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.(*models.Album); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.Album`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*models.Album) + fc.Result = res + return ec.marshalOAlbum2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_userAddRootPath(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Album_id(ctx, field) + case "title": + return ec.fieldContext_Album_title(ctx, field) + case "media": + return ec.fieldContext_Album_media(ctx, field) + case "subAlbums": + return ec.fieldContext_Album_subAlbums(ctx, field) + case "parentAlbum": + return ec.fieldContext_Album_parentAlbum(ctx, field) + case "owner": + return ec.fieldContext_Album_owner(ctx, field) + case "filePath": + return ec.fieldContext_Album_filePath(ctx, field) + case "thumbnail": + return ec.fieldContext_Album_thumbnail(ctx, field) + case "path": + return ec.fieldContext_Album_path(ctx, field) + case "shares": + return ec.fieldContext_Album_shares(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Album", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_userAddRootPath_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_userRemoveRootAlbum(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_userRemoveRootAlbum(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().UserRemoveRootAlbum(rctx, fc.Args["userId"].(int), fc.Args["albumId"].(int)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + var zeroVal *models.Album + return zeroVal, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(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.(*models.Album); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.Album`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*models.Album) + fc.Result = res + return ec.marshalOAlbum2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_userRemoveRootAlbum(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Album_id(ctx, field) + case "title": + return ec.fieldContext_Album_title(ctx, field) + case "media": + return ec.fieldContext_Album_media(ctx, field) + case "subAlbums": + return ec.fieldContext_Album_subAlbums(ctx, field) + case "parentAlbum": + return ec.fieldContext_Album_parentAlbum(ctx, field) + case "owner": + return ec.fieldContext_Album_owner(ctx, field) + case "filePath": + return ec.fieldContext_Album_filePath(ctx, field) + case "thumbnail": + return ec.fieldContext_Album_thumbnail(ctx, field) + case "path": + return ec.fieldContext_Album_path(ctx, field) + case "shares": + return ec.fieldContext_Album_shares(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Album", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_userRemoveRootAlbum_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_changeUserPreferences(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_changeUserPreferences(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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.Mutation().ChangeUserPreferences(rctx, fc.Args["language"].(*string)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAuthorized == nil { + var zeroVal *models.UserPreferences + return zeroVal, 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.(*models.UserPreferences); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.UserPreferences`, tmp) + }) + 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.UserPreferences) + fc.Result = res + return ec.marshalNUserPreferences2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUserPreferences(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_changeUserPreferences(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_UserPreferences_id(ctx, field) + case "language": + return ec.fieldContext_UserPreferences_language(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type UserPreferences", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_changeUserPreferences_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Notification_key(ctx context.Context, field graphql.CollectedField, obj *models.Notification) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Notification_key(ctx, field) if err != nil { @@ -9707,601 +9715,6 @@ func (ec *executionContext) fieldContext_Notification_timeout(_ context.Context, return fc, nil } -func (ec *executionContext) _Query_siteInfo(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_siteInfo(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().SiteInfo(rctx) - }) - 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.SiteInfo) - fc.Result = res - return ec.marshalNSiteInfo2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐSiteInfo(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_siteInfo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "initialSetup": - return ec.fieldContext_SiteInfo_initialSetup(ctx, field) - case "faceDetectionEnabled": - return ec.fieldContext_SiteInfo_faceDetectionEnabled(ctx, field) - case "periodicScanInterval": - return ec.fieldContext_SiteInfo_periodicScanInterval(ctx, field) - case "concurrentWorkers": - return ec.fieldContext_SiteInfo_concurrentWorkers(ctx, field) - case "thumbnailMethod": - return ec.fieldContext_SiteInfo_thumbnailMethod(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type SiteInfo", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_user(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_user(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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, fc.Args["order"].(*models.Ordering), fc.Args["paginate"].(*models.Pagination)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAdmin == nil { - var zeroVal []*models.User - return zeroVal, errors.New("directive isAdmin is not implemented") - } - return ec.directives.IsAdmin(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.([]*models.User); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be []*github.com/photoview/photoview/api/graphql/models.User`, tmp) - }) - 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.User) - fc.Result = res - return ec.marshalNUser2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUserᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "username": - return ec.fieldContext_User_username(ctx, field) - case "albums": - return ec.fieldContext_User_albums(ctx, field) - case "rootAlbums": - return ec.fieldContext_User_rootAlbums(ctx, field) - case "admin": - return ec.fieldContext_User_admin(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_user_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_myUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_myUser(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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().MyUser(rctx) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAuthorized == nil { - var zeroVal *models.User - return zeroVal, 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.(*models.User); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.User`, tmp) - }) - 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.User) - fc.Result = res - return ec.marshalNUser2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_myUser(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "username": - return ec.fieldContext_User_username(ctx, field) - case "albums": - return ec.fieldContext_User_albums(ctx, field) - case "rootAlbums": - return ec.fieldContext_User_rootAlbums(ctx, field) - case "admin": - return ec.fieldContext_User_admin(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_myUserPreferences(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_myUserPreferences(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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().MyUserPreferences(rctx) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAuthorized == nil { - var zeroVal *models.UserPreferences - return zeroVal, 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.(*models.UserPreferences); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.UserPreferences`, tmp) - }) - 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.UserPreferences) - fc.Result = res - return ec.marshalNUserPreferences2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUserPreferences(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_myUserPreferences(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_UserPreferences_id(ctx, field) - case "language": - return ec.fieldContext_UserPreferences_language(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type UserPreferences", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_myTimeline(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_myTimeline(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - 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().MyTimeline(rctx, fc.Args["paginate"].(*models.Pagination), fc.Args["onlyFavorites"].(*bool), fc.Args["fromDate"].(*time.Time)) - } - - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.IsAuthorized == nil { - var zeroVal []*models.Media - return zeroVal, 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.([]*models.Media); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be []*github.com/photoview/photoview/api/graphql/models.Media`, tmp) - }) - 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.Media) - fc.Result = res - return ec.marshalNMedia2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_myTimeline(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Media_id(ctx, field) - case "title": - return ec.fieldContext_Media_title(ctx, field) - case "path": - return ec.fieldContext_Media_path(ctx, field) - case "thumbnail": - return ec.fieldContext_Media_thumbnail(ctx, field) - case "highRes": - return ec.fieldContext_Media_highRes(ctx, field) - case "videoWeb": - return ec.fieldContext_Media_videoWeb(ctx, field) - case "album": - return ec.fieldContext_Media_album(ctx, field) - case "exif": - return ec.fieldContext_Media_exif(ctx, field) - case "videoMetadata": - return ec.fieldContext_Media_videoMetadata(ctx, field) - case "favorite": - return ec.fieldContext_Media_favorite(ctx, field) - case "type": - return ec.fieldContext_Media_type(ctx, field) - case "date": - return ec.fieldContext_Media_date(ctx, field) - case "blurhash": - return ec.fieldContext_Media_blurhash(ctx, field) - case "shares": - return ec.fieldContext_Media_shares(ctx, field) - case "downloads": - return ec.fieldContext_Media_downloads(ctx, field) - case "faces": - return ec.fieldContext_Media_faces(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Media", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_myTimeline_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_shareToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_shareToken(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().ShareToken(rctx, fc.Args["credentials"].(models.ShareTokenCredentials)) - }) - 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.ShareToken) - fc.Result = res - return ec.marshalNShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_shareToken(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_ShareToken_id(ctx, field) - case "token": - return ec.fieldContext_ShareToken_token(ctx, field) - case "owner": - return ec.fieldContext_ShareToken_owner(ctx, field) - case "expire": - return ec.fieldContext_ShareToken_expire(ctx, field) - case "hasPassword": - return ec.fieldContext_ShareToken_hasPassword(ctx, field) - case "album": - return ec.fieldContext_ShareToken_album(ctx, field) - case "media": - return ec.fieldContext_ShareToken_media(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type ShareToken", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_shareToken_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_shareTokenValidatePassword(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_shareTokenValidatePassword(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().ShareTokenValidatePassword(rctx, fc.Args["credentials"].(models.ShareTokenCredentials)) - }) - 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.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_shareTokenValidatePassword(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_shareTokenValidatePassword_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - -func (ec *executionContext) _Query_search(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_search(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Search(rctx, fc.Args["query"].(string), fc.Args["limitMedia"].(*int), fc.Args["limitAlbums"].(*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.SearchResult) - fc.Result = res - return ec.marshalNSearchResult2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐSearchResult(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_search(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "query": - return ec.fieldContext_SearchResult_query(ctx, field) - case "albums": - return ec.fieldContext_SearchResult_albums(ctx, field) - case "media": - return ec.fieldContext_SearchResult_media(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type SearchResult", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_search_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - func (ec *executionContext) _Query_myAlbums(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_myAlbums(ctx, field) if err != nil { @@ -11048,6 +10461,601 @@ func (ec *executionContext) fieldContext_Query_mapboxToken(_ context.Context, fi return fc, nil } +func (ec *executionContext) _Query_search(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_search(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Search(rctx, fc.Args["query"].(string), fc.Args["limitMedia"].(*int), fc.Args["limitAlbums"].(*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.SearchResult) + fc.Result = res + return ec.marshalNSearchResult2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐSearchResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_search(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "query": + return ec.fieldContext_SearchResult_query(ctx, field) + case "albums": + return ec.fieldContext_SearchResult_albums(ctx, field) + case "media": + return ec.fieldContext_SearchResult_media(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type SearchResult", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_search_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_shareToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_shareToken(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().ShareToken(rctx, fc.Args["credentials"].(models.ShareTokenCredentials)) + }) + 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.ShareToken) + fc.Result = res + return ec.marshalNShareToken2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_shareToken(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_ShareToken_id(ctx, field) + case "token": + return ec.fieldContext_ShareToken_token(ctx, field) + case "owner": + return ec.fieldContext_ShareToken_owner(ctx, field) + case "expire": + return ec.fieldContext_ShareToken_expire(ctx, field) + case "hasPassword": + return ec.fieldContext_ShareToken_hasPassword(ctx, field) + case "album": + return ec.fieldContext_ShareToken_album(ctx, field) + case "media": + return ec.fieldContext_ShareToken_media(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ShareToken", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_shareToken_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_shareTokenValidatePassword(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_shareTokenValidatePassword(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().ShareTokenValidatePassword(rctx, fc.Args["credentials"].(models.ShareTokenCredentials)) + }) + 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.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_shareTokenValidatePassword(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_shareTokenValidatePassword_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_siteInfo(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_siteInfo(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().SiteInfo(rctx) + }) + 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.SiteInfo) + fc.Result = res + return ec.marshalNSiteInfo2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐSiteInfo(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_siteInfo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "initialSetup": + return ec.fieldContext_SiteInfo_initialSetup(ctx, field) + case "faceDetectionEnabled": + return ec.fieldContext_SiteInfo_faceDetectionEnabled(ctx, field) + case "periodicScanInterval": + return ec.fieldContext_SiteInfo_periodicScanInterval(ctx, field) + case "concurrentWorkers": + return ec.fieldContext_SiteInfo_concurrentWorkers(ctx, field) + case "thumbnailMethod": + return ec.fieldContext_SiteInfo_thumbnailMethod(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type SiteInfo", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Query_myTimeline(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_myTimeline(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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().MyTimeline(rctx, fc.Args["paginate"].(*models.Pagination), fc.Args["onlyFavorites"].(*bool), fc.Args["fromDate"].(*time.Time)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAuthorized == nil { + var zeroVal []*models.Media + return zeroVal, 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.([]*models.Media); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be []*github.com/photoview/photoview/api/graphql/models.Media`, tmp) + }) + 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.Media) + fc.Result = res + return ec.marshalNMedia2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_myTimeline(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Media_id(ctx, field) + case "title": + return ec.fieldContext_Media_title(ctx, field) + case "path": + return ec.fieldContext_Media_path(ctx, field) + case "thumbnail": + return ec.fieldContext_Media_thumbnail(ctx, field) + case "highRes": + return ec.fieldContext_Media_highRes(ctx, field) + case "videoWeb": + return ec.fieldContext_Media_videoWeb(ctx, field) + case "album": + return ec.fieldContext_Media_album(ctx, field) + case "exif": + return ec.fieldContext_Media_exif(ctx, field) + case "videoMetadata": + return ec.fieldContext_Media_videoMetadata(ctx, field) + case "favorite": + return ec.fieldContext_Media_favorite(ctx, field) + case "type": + return ec.fieldContext_Media_type(ctx, field) + case "date": + return ec.fieldContext_Media_date(ctx, field) + case "blurhash": + return ec.fieldContext_Media_blurhash(ctx, field) + case "shares": + return ec.fieldContext_Media_shares(ctx, field) + case "downloads": + return ec.fieldContext_Media_downloads(ctx, field) + case "faces": + return ec.fieldContext_Media_faces(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Media", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_myTimeline_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_user(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_user(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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, fc.Args["order"].(*models.Ordering), fc.Args["paginate"].(*models.Pagination)) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + var zeroVal []*models.User + return zeroVal, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(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.([]*models.User); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be []*github.com/photoview/photoview/api/graphql/models.User`, tmp) + }) + 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.User) + fc.Result = res + return ec.marshalNUser2ᚕᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUserᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "username": + return ec.fieldContext_User_username(ctx, field) + case "albums": + return ec.fieldContext_User_albums(ctx, field) + case "rootAlbums": + return ec.fieldContext_User_rootAlbums(ctx, field) + case "admin": + return ec.fieldContext_User_admin(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_user_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_myUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_myUser(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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().MyUser(rctx) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAuthorized == nil { + var zeroVal *models.User + return zeroVal, 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.(*models.User); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.User`, tmp) + }) + 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.User) + fc.Result = res + return ec.marshalNUser2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_myUser(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_User_id(ctx, field) + case "username": + return ec.fieldContext_User_username(ctx, field) + case "albums": + return ec.fieldContext_User_albums(ctx, field) + case "rootAlbums": + return ec.fieldContext_User_rootAlbums(ctx, field) + case "admin": + return ec.fieldContext_User_admin(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Query_myUserPreferences(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_myUserPreferences(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + 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().MyUserPreferences(rctx) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAuthorized == nil { + var zeroVal *models.UserPreferences + return zeroVal, 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.(*models.UserPreferences); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.UserPreferences`, tmp) + }) + 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.UserPreferences) + fc.Result = res + return ec.marshalNUserPreferences2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUserPreferences(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_myUserPreferences(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_UserPreferences_id(ctx, field) + case "language": + return ec.fieldContext_UserPreferences_language(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type UserPreferences", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query___type(ctx, field) if err != nil { @@ -16459,116 +16467,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Mutation") - case "authorizeUser": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_authorizeUser(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "initialSetupWizard": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_initialSetupWizard(ctx, field) - }) - case "scanAll": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_scanAll(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "scanUser": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_scanUser(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "shareAlbum": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_shareAlbum(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "shareMedia": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_shareMedia(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "deleteShareToken": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_deleteShareToken(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "protectShareToken": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_protectShareToken(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "updateUser": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_updateUser(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "createUser": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_createUser(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "deleteUser": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_deleteUser(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "userAddRootPath": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_userAddRootPath(ctx, field) - }) - case "userRemoveRootAlbum": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_userRemoveRootAlbum(ctx, field) - }) - case "setPeriodicScanInterval": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_setPeriodicScanInterval(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "setScannerConcurrentWorkers": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_setScannerConcurrentWorkers(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "setThumbnailDownsampleMethod": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_setThumbnailDownsampleMethod(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "changeUserPreferences": - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_changeUserPreferences(ctx, field) - }) - if out.Values[i] == graphql.Null { - out.Invalids++ - } case "resetAlbumCover": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_resetAlbumCover(ctx, field) @@ -16625,6 +16523,116 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "scanAll": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_scanAll(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "scanUser": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_scanUser(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "setPeriodicScanInterval": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_setPeriodicScanInterval(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "setScannerConcurrentWorkers": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_setScannerConcurrentWorkers(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "shareAlbum": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_shareAlbum(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "shareMedia": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_shareMedia(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "deleteShareToken": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_deleteShareToken(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "protectShareToken": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_protectShareToken(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "setThumbnailDownsampleMethod": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_setThumbnailDownsampleMethod(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "authorizeUser": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_authorizeUser(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "initialSetupWizard": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_initialSetupWizard(ctx, field) + }) + case "updateUser": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_updateUser(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "createUser": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_createUser(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "deleteUser": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_deleteUser(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "userAddRootPath": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_userAddRootPath(ctx, field) + }) + case "userRemoveRootAlbum": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_userRemoveRootAlbum(ctx, field) + }) + case "changeUserPreferences": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_changeUserPreferences(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -16735,182 +16743,6 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Query") - case "siteInfo": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_siteInfo(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, - func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "user": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_user(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, - func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "myUser": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_myUser(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, - func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "myUserPreferences": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_myUserPreferences(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, - func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "myTimeline": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_myTimeline(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, - func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "shareToken": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_shareToken(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, - func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "shareTokenValidatePassword": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_shareTokenValidatePassword(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, - func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "search": - field := field - - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_search(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&fs.Invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, - func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - } - - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "myAlbums": field := field @@ -17105,6 +16937,182 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "search": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_search(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "shareToken": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_shareToken(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "shareTokenValidatePassword": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_shareTokenValidatePassword(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "siteInfo": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_siteInfo(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "myTimeline": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_myTimeline(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "user": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_user(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "myUser": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_myUser(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "myUserPreferences": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_myUserPreferences(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "__type": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { diff --git a/api/graphql/models/generated.go b/api/graphql/models/generated.go index 937b4482..e8f4d48a 100644 --- a/api/graphql/models/generated.go +++ b/api/graphql/models/generated.go @@ -95,6 +95,7 @@ type Subscription struct { } // A group of media from the same album and the same day, that is grouped together in a timeline view +// NOTE: It isn't used. Just copy from the old schema.graphql. type TimelineGroup struct { // The full album containing the media in this timeline group Album *Album `json:"album"` diff --git a/api/graphql/resolvers/album.generated.go b/api/graphql/resolvers/album.go similarity index 100% rename from api/graphql/resolvers/album.generated.go rename to api/graphql/resolvers/album.go diff --git a/api/graphql/resolvers/faces.generated.go b/api/graphql/resolvers/faces.generated.go deleted file mode 100644 index 238c0979..00000000 --- a/api/graphql/resolvers/faces.generated.go +++ /dev/null @@ -1,410 +0,0 @@ -package resolvers - -// This file will be automatically regenerated based on the schema, any resolver implementations -// will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.55 - -import ( - "context" - "errors" - - api "github.com/photoview/photoview/api/graphql" - "github.com/photoview/photoview/api/graphql/auth" - "github.com/photoview/photoview/api/graphql/models" - "github.com/photoview/photoview/api/scanner/face_detection" - "gorm.io/gorm" -) - -// ImageFaces is the resolver for the imageFaces field. -func (r *faceGroupResolver) ImageFaces(ctx context.Context, obj *models.FaceGroup, paginate *models.Pagination) ([]*models.ImageFace, error) { - db := r.DB(ctx) - user := auth.UserFromContext(ctx) - if user == nil { - return nil, errors.New("unauthorized") - } - - if face_detection.GlobalFaceDetector == nil { - return nil, ErrFaceDetectorNotInitialized - } - - if err := user.FillAlbums(db); err != nil { - return nil, err - } - - userAlbumIDs := make([]int, len(user.Albums)) - for i, album := range user.Albums { - userAlbumIDs[i] = album.ID - } - - query := db. - Joins("Media"). - Where(faceGroupIDIsQuestion, obj.ID). - Where("album_id IN (?)", userAlbumIDs) - - query = models.FormatSQL(query, nil, paginate) - - var imageFaces []*models.ImageFace - if err := query.Find(&imageFaces).Error; err != nil { - return nil, err - } - - return imageFaces, nil -} - -// ImageFaceCount is the resolver for the imageFaceCount field. -func (r *faceGroupResolver) ImageFaceCount(ctx context.Context, obj *models.FaceGroup) (int, error) { - db := r.DB(ctx) - user := auth.UserFromContext(ctx) - if user == nil { - return -1, errors.New("unauthorized") - } - - if face_detection.GlobalFaceDetector == nil { - return -1, ErrFaceDetectorNotInitialized - } - - if err := user.FillAlbums(db); err != nil { - return -1, err - } - - userAlbumIDs := make([]int, len(user.Albums)) - for i, album := range user.Albums { - userAlbumIDs[i] = album.ID - } - - query := db. - Model(&models.ImageFace{}). - Joins("Media"). - Where(faceGroupIDIsQuestion, obj.ID). - Where("album_id IN (?)", userAlbumIDs) - - var count int64 - if err := query.Count(&count).Error; err != nil { - return -1, err - } - - return int(count), nil -} - -// Media is the resolver for the media field. -func (r *imageFaceResolver) Media(ctx context.Context, obj *models.ImageFace) (*models.Media, error) { - if err := obj.FillMedia(r.DB(ctx)); err != nil { - return nil, err - } - - return &obj.Media, nil -} - -// FaceGroup is the resolver for the faceGroup field. -func (r *imageFaceResolver) FaceGroup(ctx context.Context, obj *models.ImageFace) (*models.FaceGroup, error) { - if obj.FaceGroup != nil { - return obj.FaceGroup, nil - } - - if face_detection.GlobalFaceDetector == nil { - return nil, ErrFaceDetectorNotInitialized - } - - var faceGroup models.FaceGroup - if err := r.DB(ctx).Model(&obj).Association("FaceGroup").Find(&faceGroup); err != nil { - return nil, err - } - - obj.FaceGroup = &faceGroup - - return &faceGroup, nil -} - -// SetFaceGroupLabel is the resolver for the setFaceGroupLabel field. -func (r *mutationResolver) SetFaceGroupLabel(ctx context.Context, faceGroupID int, label *string) (*models.FaceGroup, error) { - db := r.DB(ctx) - user := auth.UserFromContext(ctx) - if user == nil { - return nil, errors.New("unauthorized") - } - - if face_detection.GlobalFaceDetector == nil { - return nil, ErrFaceDetectorNotInitialized - } - - faceGroup, err := userOwnedFaceGroup(db, user, faceGroupID) - if err != nil { - return nil, err - } - - if err := db.Model(faceGroup).Update("label", label).Error; err != nil { - return nil, err - } - - return faceGroup, nil -} - -// CombineFaceGroups is the resolver for the combineFaceGroups field. -func (r *mutationResolver) CombineFaceGroups(ctx context.Context, destinationFaceGroupID int, sourceFaceGroupID int) (*models.FaceGroup, error) { - db := r.DB(ctx) - user := auth.UserFromContext(ctx) - if user == nil { - return nil, errors.New("unauthorized") - } - - if face_detection.GlobalFaceDetector == nil { - return nil, ErrFaceDetectorNotInitialized - } - - destinationFaceGroup, err := userOwnedFaceGroup(db, user, destinationFaceGroupID) - if err != nil { - return nil, err - } - - sourceFaceGroup, err := userOwnedFaceGroup(db, user, sourceFaceGroupID) - if err != nil { - return nil, err - } - - updateError := db.Transaction(func(tx *gorm.DB) error { - if err := tx.Model(&models.ImageFace{}). - Where(faceGroupIDIsQuestion, sourceFaceGroup.ID). - Update("face_group_id", destinationFaceGroup.ID).Error; err != nil { - return err - } - - if err := tx.Delete(&sourceFaceGroup).Error; err != nil { - return err - } - - return nil - }) - - if updateError != nil { - return nil, updateError - } - - face_detection.GlobalFaceDetector.MergeCategories(int32(sourceFaceGroupID), int32(destinationFaceGroupID)) - - return destinationFaceGroup, nil -} - -// MoveImageFaces is the resolver for the moveImageFaces field. -func (r *mutationResolver) MoveImageFaces(ctx context.Context, imageFaceIDs []int, destinationFaceGroupID int) (*models.FaceGroup, error) { - db := r.DB(ctx) - user := auth.UserFromContext(ctx) - if user == nil { - return nil, errors.New("unauthorized") - } - - if face_detection.GlobalFaceDetector == nil { - return nil, ErrFaceDetectorNotInitialized - } - - userOwnedImageFaceIDs := make([]int, 0) - var destFaceGroup *models.FaceGroup - - transErr := db.Transaction(func(tx *gorm.DB) error { - - var err error - destFaceGroup, err = userOwnedFaceGroup(tx, user, destinationFaceGroupID) - if err != nil { - return err - } - - userOwnedImageFaces, err := getUserOwnedImageFaces(tx, user, imageFaceIDs) - if err != nil { - return err - } - - for _, imageFace := range userOwnedImageFaces { - userOwnedImageFaceIDs = append(userOwnedImageFaceIDs, imageFace.ID) - } - - var sourceFaceGroups []*models.FaceGroup - if err := tx. - Joins("LEFT JOIN image_faces ON image_faces.face_group_id = face_groups.id"). - Where(imageFacesIDInQuestion, userOwnedImageFaceIDs). - Find(&sourceFaceGroups).Error; err != nil { - return err - } - - if err := tx. - Model(&models.ImageFace{}). - Where("id IN (?)", userOwnedImageFaceIDs). - Update("face_group_id", destFaceGroup.ID).Error; err != nil { - return err - } - - // delete face groups if they have become empty - if err := deleteEmptyFaceGroups(sourceFaceGroups, tx); err != nil { - return err - } - - return nil - }) - - if transErr != nil { - return nil, transErr - } - - face_detection.GlobalFaceDetector.MergeImageFaces(userOwnedImageFaceIDs, int32(destFaceGroup.ID)) - - return destFaceGroup, nil -} - -// RecognizeUnlabeledFaces is the resolver for the recognizeUnlabeledFaces field. -func (r *mutationResolver) RecognizeUnlabeledFaces(ctx context.Context) ([]*models.ImageFace, error) { - db := r.DB(ctx) - user := auth.UserFromContext(ctx) - if user == nil { - return nil, errors.New("unauthorized") - } - - if face_detection.GlobalFaceDetector == nil { - return nil, ErrFaceDetectorNotInitialized - } - - var updatedImageFaces []*models.ImageFace - - transactionError := db.Transaction(func(tx *gorm.DB) error { - var err error - updatedImageFaces, err = face_detection.GlobalFaceDetector.RecognizeUnlabeledFaces(tx, user) - - return err - }) - - if transactionError != nil { - return nil, transactionError - } - - return updatedImageFaces, nil -} - -// DetachImageFaces is the resolver for the detachImageFaces field. -func (r *mutationResolver) DetachImageFaces(ctx context.Context, imageFaceIDs []int) (*models.FaceGroup, error) { - db := r.DB(ctx) - user := auth.UserFromContext(ctx) - if user == nil { - return nil, errors.New("unauthorized") - } - - if face_detection.GlobalFaceDetector == nil { - return nil, ErrFaceDetectorNotInitialized - } - - userOwnedImageFaceIDs := make([]int, 0) - newFaceGroup := models.FaceGroup{} - - transactionError := db.Transaction(func(tx *gorm.DB) error { - - userOwnedImageFaces, err := getUserOwnedImageFaces(tx, user, imageFaceIDs) - if err != nil { - return err - } - - for _, imageFace := range userOwnedImageFaces { - userOwnedImageFaceIDs = append(userOwnedImageFaceIDs, imageFace.ID) - } - - if err := tx.Save(&newFaceGroup).Error; err != nil { - return err - } - - if err := tx. - Model(&models.ImageFace{}). - Where("id IN (?)", userOwnedImageFaceIDs). - Update("face_group_id", newFaceGroup.ID).Error; err != nil { - return err - } - - return nil - }) - - if transactionError != nil { - return nil, transactionError - } - - face_detection.GlobalFaceDetector.MergeImageFaces(userOwnedImageFaceIDs, int32(newFaceGroup.ID)) - - return &newFaceGroup, nil -} - -// MyFaceGroups is the resolver for the myFaceGroups field. -func (r *queryResolver) MyFaceGroups(ctx context.Context, paginate *models.Pagination) ([]*models.FaceGroup, error) { - db := r.DB(ctx) - user := auth.UserFromContext(ctx) - if user == nil { - return nil, errors.New("unauthorized") - } - - if face_detection.GlobalFaceDetector == nil { - return nil, ErrFaceDetectorNotInitialized - } - - if err := user.FillAlbums(db); err != nil { - return nil, err - } - - userAlbumIDs := make([]int, len(user.Albums)) - for i, album := range user.Albums { - userAlbumIDs[i] = album.ID - } - - faceGroupQuery := db. - Joins("JOIN image_faces ON image_faces.face_group_id = face_groups.id"). - Where("image_faces.media_id IN (?)", - db.Select("media.id").Table("media").Where(mediaAlbumIDInQuestion, userAlbumIDs)). - Group("image_faces.face_group_id"). - Group("face_groups.id"). - Order("CASE WHEN label IS NULL THEN 1 ELSE 0 END"). - Order("COUNT(image_faces.id) DESC") - - faceGroupQuery = models.FormatSQL(faceGroupQuery, nil, paginate) - - var faceGroups []*models.FaceGroup - if err := faceGroupQuery.Find(&faceGroups).Error; err != nil { - return nil, err - } - - return faceGroups, nil -} - -// FaceGroup is the resolver for the faceGroup field. -func (r *queryResolver) FaceGroup(ctx context.Context, id int) (*models.FaceGroup, error) { - db := r.DB(ctx) - user := auth.UserFromContext(ctx) - if user == nil { - return nil, errors.New("unauthorized") - } - - if face_detection.GlobalFaceDetector == nil { - return nil, ErrFaceDetectorNotInitialized - } - - if err := user.FillAlbums(db); err != nil { - return nil, err - } - - userAlbumIDs := make([]int, len(user.Albums)) - for i, album := range user.Albums { - userAlbumIDs[i] = album.ID - } - - faceGroupQuery := db. - Joins("LEFT JOIN image_faces ON image_faces.face_group_id = face_groups.id"). - Joins("LEFT JOIN media ON image_faces.media_id = media.id"). - Where("face_groups.id = ?", id). - Where(mediaAlbumIDInQuestion, userAlbumIDs) - - var faceGroup models.FaceGroup - if err := faceGroupQuery.Find(&faceGroup).Error; err != nil { - return nil, err - } - - return &faceGroup, nil -} - -// FaceGroup returns api.FaceGroupResolver implementation. -func (r *Resolver) FaceGroup() api.FaceGroupResolver { return &faceGroupResolver{r} } - -// ImageFace returns api.ImageFaceResolver implementation. -func (r *Resolver) ImageFace() api.ImageFaceResolver { return &imageFaceResolver{r} } - -type faceGroupResolver struct{ *Resolver } -type imageFaceResolver struct{ *Resolver } diff --git a/api/graphql/resolvers/faces.go b/api/graphql/resolvers/faces.go index 77af6206..238c0979 100644 --- a/api/graphql/resolvers/faces.go +++ b/api/graphql/resolvers/faces.go @@ -1,27 +1,30 @@ package resolvers -import ( - "errors" - "fmt" +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 +import ( + "context" + "errors" + + api "github.com/photoview/photoview/api/graphql" + "github.com/photoview/photoview/api/graphql/auth" "github.com/photoview/photoview/api/graphql/models" + "github.com/photoview/photoview/api/scanner/face_detection" "gorm.io/gorm" ) -const faceGroupIDIsQuestion = "face_group_id = ?" -const mediaAlbumIDInQuestion = "media.album_id IN (?)" -const imageFacesIDInQuestion = "image_faces.id IN (?)" +// ImageFaces is the resolver for the imageFaces field. +func (r *faceGroupResolver) ImageFaces(ctx context.Context, obj *models.FaceGroup, paginate *models.Pagination) ([]*models.ImageFace, error) { + db := r.DB(ctx) + user := auth.UserFromContext(ctx) + if user == nil { + return nil, errors.New("unauthorized") + } -var ErrFaceDetectorNotInitialized = errors.New("face detector not initialized") - -func userOwnedFaceGroup(db *gorm.DB, user *models.User, faceGroupID int) (*models.FaceGroup, error) { - if user.Admin { - var faceGroup models.FaceGroup - if err := db.Where("id = ?", faceGroupID).Find(&faceGroup).Error; err != nil { - return nil, err - } - - return &faceGroup, nil + if face_detection.GlobalFaceDetector == nil { + return nil, ErrFaceDetectorNotInitialized } if err := user.FillAlbums(db); err != nil { @@ -33,32 +36,308 @@ func userOwnedFaceGroup(db *gorm.DB, user *models.User, faceGroupID int) (*model userAlbumIDs[i] = album.ID } - // Verify that user owns at leat one of the images in the face group - imageFaceQuery := db. - Select("image_faces.id"). - Table("image_faces"). - Joins("JOIN media ON media.id = image_faces.media_id"). - Where(mediaAlbumIDInQuestion, userAlbumIDs) + query := db. + Joins("Media"). + Where(faceGroupIDIsQuestion, obj.ID). + Where("album_id IN (?)", userAlbumIDs) - faceGroupQuery := db. - Model(&models.FaceGroup{}). - Joins("JOIN image_faces ON face_groups.id = image_faces.face_group_id"). - Where("face_groups.id = ?", faceGroupID). - Where(imageFacesIDInQuestion, imageFaceQuery) + query = models.FormatSQL(query, nil, paginate) - var faceGroup models.FaceGroup - if err := faceGroupQuery.Find(&faceGroup).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return nil, fmt.Errorf("face group does not exist or is not owned by the user: %w", err) - } + var imageFaces []*models.ImageFace + if err := query.Find(&imageFaces).Error; err != nil { return nil, err } + return imageFaces, nil +} + +// ImageFaceCount is the resolver for the imageFaceCount field. +func (r *faceGroupResolver) ImageFaceCount(ctx context.Context, obj *models.FaceGroup) (int, error) { + db := r.DB(ctx) + user := auth.UserFromContext(ctx) + if user == nil { + return -1, errors.New("unauthorized") + } + + if face_detection.GlobalFaceDetector == nil { + return -1, ErrFaceDetectorNotInitialized + } + + if err := user.FillAlbums(db); err != nil { + return -1, err + } + + userAlbumIDs := make([]int, len(user.Albums)) + for i, album := range user.Albums { + userAlbumIDs[i] = album.ID + } + + query := db. + Model(&models.ImageFace{}). + Joins("Media"). + Where(faceGroupIDIsQuestion, obj.ID). + Where("album_id IN (?)", userAlbumIDs) + + var count int64 + if err := query.Count(&count).Error; err != nil { + return -1, err + } + + return int(count), nil +} + +// Media is the resolver for the media field. +func (r *imageFaceResolver) Media(ctx context.Context, obj *models.ImageFace) (*models.Media, error) { + if err := obj.FillMedia(r.DB(ctx)); err != nil { + return nil, err + } + + return &obj.Media, nil +} + +// FaceGroup is the resolver for the faceGroup field. +func (r *imageFaceResolver) FaceGroup(ctx context.Context, obj *models.ImageFace) (*models.FaceGroup, error) { + if obj.FaceGroup != nil { + return obj.FaceGroup, nil + } + + if face_detection.GlobalFaceDetector == nil { + return nil, ErrFaceDetectorNotInitialized + } + + var faceGroup models.FaceGroup + if err := r.DB(ctx).Model(&obj).Association("FaceGroup").Find(&faceGroup); err != nil { + return nil, err + } + + obj.FaceGroup = &faceGroup + return &faceGroup, nil } -func getUserOwnedImageFaces(tx *gorm.DB, user *models.User, imageFaceIDs []int) ([]*models.ImageFace, error) { - if err := user.FillAlbums(tx); err != nil { +// SetFaceGroupLabel is the resolver for the setFaceGroupLabel field. +func (r *mutationResolver) SetFaceGroupLabel(ctx context.Context, faceGroupID int, label *string) (*models.FaceGroup, error) { + db := r.DB(ctx) + user := auth.UserFromContext(ctx) + if user == nil { + return nil, errors.New("unauthorized") + } + + if face_detection.GlobalFaceDetector == nil { + return nil, ErrFaceDetectorNotInitialized + } + + faceGroup, err := userOwnedFaceGroup(db, user, faceGroupID) + if err != nil { + return nil, err + } + + if err := db.Model(faceGroup).Update("label", label).Error; err != nil { + return nil, err + } + + return faceGroup, nil +} + +// CombineFaceGroups is the resolver for the combineFaceGroups field. +func (r *mutationResolver) CombineFaceGroups(ctx context.Context, destinationFaceGroupID int, sourceFaceGroupID int) (*models.FaceGroup, error) { + db := r.DB(ctx) + user := auth.UserFromContext(ctx) + if user == nil { + return nil, errors.New("unauthorized") + } + + if face_detection.GlobalFaceDetector == nil { + return nil, ErrFaceDetectorNotInitialized + } + + destinationFaceGroup, err := userOwnedFaceGroup(db, user, destinationFaceGroupID) + if err != nil { + return nil, err + } + + sourceFaceGroup, err := userOwnedFaceGroup(db, user, sourceFaceGroupID) + if err != nil { + return nil, err + } + + updateError := db.Transaction(func(tx *gorm.DB) error { + if err := tx.Model(&models.ImageFace{}). + Where(faceGroupIDIsQuestion, sourceFaceGroup.ID). + Update("face_group_id", destinationFaceGroup.ID).Error; err != nil { + return err + } + + if err := tx.Delete(&sourceFaceGroup).Error; err != nil { + return err + } + + return nil + }) + + if updateError != nil { + return nil, updateError + } + + face_detection.GlobalFaceDetector.MergeCategories(int32(sourceFaceGroupID), int32(destinationFaceGroupID)) + + return destinationFaceGroup, nil +} + +// MoveImageFaces is the resolver for the moveImageFaces field. +func (r *mutationResolver) MoveImageFaces(ctx context.Context, imageFaceIDs []int, destinationFaceGroupID int) (*models.FaceGroup, error) { + db := r.DB(ctx) + user := auth.UserFromContext(ctx) + if user == nil { + return nil, errors.New("unauthorized") + } + + if face_detection.GlobalFaceDetector == nil { + return nil, ErrFaceDetectorNotInitialized + } + + userOwnedImageFaceIDs := make([]int, 0) + var destFaceGroup *models.FaceGroup + + transErr := db.Transaction(func(tx *gorm.DB) error { + + var err error + destFaceGroup, err = userOwnedFaceGroup(tx, user, destinationFaceGroupID) + if err != nil { + return err + } + + userOwnedImageFaces, err := getUserOwnedImageFaces(tx, user, imageFaceIDs) + if err != nil { + return err + } + + for _, imageFace := range userOwnedImageFaces { + userOwnedImageFaceIDs = append(userOwnedImageFaceIDs, imageFace.ID) + } + + var sourceFaceGroups []*models.FaceGroup + if err := tx. + Joins("LEFT JOIN image_faces ON image_faces.face_group_id = face_groups.id"). + Where(imageFacesIDInQuestion, userOwnedImageFaceIDs). + Find(&sourceFaceGroups).Error; err != nil { + return err + } + + if err := tx. + Model(&models.ImageFace{}). + Where("id IN (?)", userOwnedImageFaceIDs). + Update("face_group_id", destFaceGroup.ID).Error; err != nil { + return err + } + + // delete face groups if they have become empty + if err := deleteEmptyFaceGroups(sourceFaceGroups, tx); err != nil { + return err + } + + return nil + }) + + if transErr != nil { + return nil, transErr + } + + face_detection.GlobalFaceDetector.MergeImageFaces(userOwnedImageFaceIDs, int32(destFaceGroup.ID)) + + return destFaceGroup, nil +} + +// RecognizeUnlabeledFaces is the resolver for the recognizeUnlabeledFaces field. +func (r *mutationResolver) RecognizeUnlabeledFaces(ctx context.Context) ([]*models.ImageFace, error) { + db := r.DB(ctx) + user := auth.UserFromContext(ctx) + if user == nil { + return nil, errors.New("unauthorized") + } + + if face_detection.GlobalFaceDetector == nil { + return nil, ErrFaceDetectorNotInitialized + } + + var updatedImageFaces []*models.ImageFace + + transactionError := db.Transaction(func(tx *gorm.DB) error { + var err error + updatedImageFaces, err = face_detection.GlobalFaceDetector.RecognizeUnlabeledFaces(tx, user) + + return err + }) + + if transactionError != nil { + return nil, transactionError + } + + return updatedImageFaces, nil +} + +// DetachImageFaces is the resolver for the detachImageFaces field. +func (r *mutationResolver) DetachImageFaces(ctx context.Context, imageFaceIDs []int) (*models.FaceGroup, error) { + db := r.DB(ctx) + user := auth.UserFromContext(ctx) + if user == nil { + return nil, errors.New("unauthorized") + } + + if face_detection.GlobalFaceDetector == nil { + return nil, ErrFaceDetectorNotInitialized + } + + userOwnedImageFaceIDs := make([]int, 0) + newFaceGroup := models.FaceGroup{} + + transactionError := db.Transaction(func(tx *gorm.DB) error { + + userOwnedImageFaces, err := getUserOwnedImageFaces(tx, user, imageFaceIDs) + if err != nil { + return err + } + + for _, imageFace := range userOwnedImageFaces { + userOwnedImageFaceIDs = append(userOwnedImageFaceIDs, imageFace.ID) + } + + if err := tx.Save(&newFaceGroup).Error; err != nil { + return err + } + + if err := tx. + Model(&models.ImageFace{}). + Where("id IN (?)", userOwnedImageFaceIDs). + Update("face_group_id", newFaceGroup.ID).Error; err != nil { + return err + } + + return nil + }) + + if transactionError != nil { + return nil, transactionError + } + + face_detection.GlobalFaceDetector.MergeImageFaces(userOwnedImageFaceIDs, int32(newFaceGroup.ID)) + + return &newFaceGroup, nil +} + +// MyFaceGroups is the resolver for the myFaceGroups field. +func (r *queryResolver) MyFaceGroups(ctx context.Context, paginate *models.Pagination) ([]*models.FaceGroup, error) { + db := r.DB(ctx) + user := auth.UserFromContext(ctx) + if user == nil { + return nil, errors.New("unauthorized") + } + + if face_detection.GlobalFaceDetector == nil { + return nil, ErrFaceDetectorNotInitialized + } + + if err := user.FillAlbums(db); err != nil { return nil, err } @@ -67,30 +346,65 @@ func getUserOwnedImageFaces(tx *gorm.DB, user *models.User, imageFaceIDs []int) userAlbumIDs[i] = album.ID } - var userOwnedImageFaces []*models.ImageFace - if err := tx. - Joins("JOIN media ON media.id = image_faces.media_id"). - Where(mediaAlbumIDInQuestion, userAlbumIDs). - Where(imageFacesIDInQuestion, imageFaceIDs). - Find(&userOwnedImageFaces).Error; err != nil { + faceGroupQuery := db. + Joins("JOIN image_faces ON image_faces.face_group_id = face_groups.id"). + Where("image_faces.media_id IN (?)", + db.Select("media.id").Table("media").Where(mediaAlbumIDInQuestion, userAlbumIDs)). + Group("image_faces.face_group_id"). + Group("face_groups.id"). + Order("CASE WHEN label IS NULL THEN 1 ELSE 0 END"). + Order("COUNT(image_faces.id) DESC") + + faceGroupQuery = models.FormatSQL(faceGroupQuery, nil, paginate) + + var faceGroups []*models.FaceGroup + if err := faceGroupQuery.Find(&faceGroups).Error; err != nil { return nil, err } - return userOwnedImageFaces, nil + return faceGroups, nil } -func deleteEmptyFaceGroups(sourceFaceGroups []*models.FaceGroup, tx *gorm.DB) error { - for _, faceGroup := range sourceFaceGroups { - var count int64 - if err := tx.Model(&models.ImageFace{}).Where(faceGroupIDIsQuestion, faceGroup.ID).Count(&count).Error; err != nil { - return err - } - - if count == 0 { - if err := tx.Delete(&faceGroup).Error; err != nil { - return err - } - } +// FaceGroup is the resolver for the faceGroup field. +func (r *queryResolver) FaceGroup(ctx context.Context, id int) (*models.FaceGroup, error) { + db := r.DB(ctx) + user := auth.UserFromContext(ctx) + if user == nil { + return nil, errors.New("unauthorized") } - return nil + + if face_detection.GlobalFaceDetector == nil { + return nil, ErrFaceDetectorNotInitialized + } + + if err := user.FillAlbums(db); err != nil { + return nil, err + } + + userAlbumIDs := make([]int, len(user.Albums)) + for i, album := range user.Albums { + userAlbumIDs[i] = album.ID + } + + faceGroupQuery := db. + Joins("LEFT JOIN image_faces ON image_faces.face_group_id = face_groups.id"). + Joins("LEFT JOIN media ON image_faces.media_id = media.id"). + Where("face_groups.id = ?", id). + Where(mediaAlbumIDInQuestion, userAlbumIDs) + + var faceGroup models.FaceGroup + if err := faceGroupQuery.Find(&faceGroup).Error; err != nil { + return nil, err + } + + return &faceGroup, nil } + +// FaceGroup returns api.FaceGroupResolver implementation. +func (r *Resolver) FaceGroup() api.FaceGroupResolver { return &faceGroupResolver{r} } + +// ImageFace returns api.ImageFaceResolver implementation. +func (r *Resolver) ImageFace() api.ImageFaceResolver { return &imageFaceResolver{r} } + +type faceGroupResolver struct{ *Resolver } +type imageFaceResolver struct{ *Resolver } diff --git a/api/graphql/resolvers/faces.util.go b/api/graphql/resolvers/faces.util.go new file mode 100644 index 00000000..77af6206 --- /dev/null +++ b/api/graphql/resolvers/faces.util.go @@ -0,0 +1,96 @@ +package resolvers + +import ( + "errors" + "fmt" + + "github.com/photoview/photoview/api/graphql/models" + "gorm.io/gorm" +) + +const faceGroupIDIsQuestion = "face_group_id = ?" +const mediaAlbumIDInQuestion = "media.album_id IN (?)" +const imageFacesIDInQuestion = "image_faces.id IN (?)" + +var ErrFaceDetectorNotInitialized = errors.New("face detector not initialized") + +func userOwnedFaceGroup(db *gorm.DB, user *models.User, faceGroupID int) (*models.FaceGroup, error) { + if user.Admin { + var faceGroup models.FaceGroup + if err := db.Where("id = ?", faceGroupID).Find(&faceGroup).Error; err != nil { + return nil, err + } + + return &faceGroup, nil + } + + if err := user.FillAlbums(db); err != nil { + return nil, err + } + + userAlbumIDs := make([]int, len(user.Albums)) + for i, album := range user.Albums { + userAlbumIDs[i] = album.ID + } + + // Verify that user owns at leat one of the images in the face group + imageFaceQuery := db. + Select("image_faces.id"). + Table("image_faces"). + Joins("JOIN media ON media.id = image_faces.media_id"). + Where(mediaAlbumIDInQuestion, userAlbumIDs) + + faceGroupQuery := db. + Model(&models.FaceGroup{}). + Joins("JOIN image_faces ON face_groups.id = image_faces.face_group_id"). + Where("face_groups.id = ?", faceGroupID). + Where(imageFacesIDInQuestion, imageFaceQuery) + + var faceGroup models.FaceGroup + if err := faceGroupQuery.Find(&faceGroup).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, fmt.Errorf("face group does not exist or is not owned by the user: %w", err) + } + return nil, err + } + + return &faceGroup, nil +} + +func getUserOwnedImageFaces(tx *gorm.DB, user *models.User, imageFaceIDs []int) ([]*models.ImageFace, error) { + if err := user.FillAlbums(tx); err != nil { + return nil, err + } + + userAlbumIDs := make([]int, len(user.Albums)) + for i, album := range user.Albums { + userAlbumIDs[i] = album.ID + } + + var userOwnedImageFaces []*models.ImageFace + if err := tx. + Joins("JOIN media ON media.id = image_faces.media_id"). + Where(mediaAlbumIDInQuestion, userAlbumIDs). + Where(imageFacesIDInQuestion, imageFaceIDs). + Find(&userOwnedImageFaces).Error; err != nil { + return nil, err + } + + return userOwnedImageFaces, nil +} + +func deleteEmptyFaceGroups(sourceFaceGroups []*models.FaceGroup, tx *gorm.DB) error { + for _, faceGroup := range sourceFaceGroups { + var count int64 + if err := tx.Model(&models.ImageFace{}).Where(faceGroupIDIsQuestion, faceGroup.ID).Count(&count).Error; err != nil { + return err + } + + if count == 0 { + if err := tx.Delete(&faceGroup).Error; err != nil { + return err + } + } + } + return nil +} diff --git a/api/graphql/resolvers/media.generated.go b/api/graphql/resolvers/media.go similarity index 100% rename from api/graphql/resolvers/media.generated.go rename to api/graphql/resolvers/media.go diff --git a/api/graphql/resolvers/media.graphql b/api/graphql/resolvers/media.graphql index 01157dba..dd51f0c8 100644 --- a/api/graphql/resolvers/media.graphql +++ b/api/graphql/resolvers/media.graphql @@ -20,6 +20,14 @@ enum MediaType { Video } +type Coordinates { + "GPS latitude in degrees" + latitude: Float! + "GPS longitude in degrees" + longitude: Float! +} + + "EXIF metadata from the camera" type MediaEXIF { id: ID! @@ -49,6 +57,20 @@ type MediaEXIF { coordinates: Coordinates } +"Metadata specific to video media" +type VideoMetadata { + id: ID! + media: Media! + width: Int! + height: Int! + duration: Float! + codec: String + framerate: Float + bitrate: String + colorProfile: String + audio: String +} + type Media { id: ID! title: String! diff --git a/api/graphql/resolvers/media_geo_json.generated.go b/api/graphql/resolvers/media_geo_json.generated.go deleted file mode 100644 index 8b813a49..00000000 --- a/api/graphql/resolvers/media_geo_json.generated.go +++ /dev/null @@ -1,80 +0,0 @@ -package resolvers - -// This file will be automatically regenerated based on the schema, any resolver implementations -// will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.55 - -import ( - "context" - "os" - "path" - - "github.com/photoview/photoview/api/graphql/auth" - "github.com/photoview/photoview/api/utils" -) - -// MyMediaGeoJSON is the resolver for the myMediaGeoJson field. -func (r *queryResolver) MyMediaGeoJSON(ctx context.Context) (any, error) { - user := auth.UserFromContext(ctx) - if user == nil { - return nil, auth.ErrUnauthorized - } - - var media []*geoMedia - - err := r.DB(ctx).Table("media"). - Select("media.id AS media_id, media.title AS media_title, "+ - "media_urls.media_name AS thumbnail_name, media_urls.width AS thumbnail_width, "+ - "media_urls.height AS thumbnail_height, media_exif.gps_latitude AS latitude, "+ - "media_exif.gps_longitude AS longitude"). - Joins("INNER JOIN media_exif ON media.exif_id = media_exif.id"). - Joins("INNER JOIN media_urls ON media.id = media_urls.media_id"). - Joins("INNER JOIN user_albums ON media.album_id = user_albums.album_id"). - Where("media_exif.gps_latitude IS NOT NULL"). - Where("media_exif.gps_longitude IS NOT NULL"). - Where("media_urls.purpose = 'thumbnail'"). - Where("user_albums.user_id = ?", user.ID). - Scan(&media).Error - - if err != nil { - return nil, err - } - - features := make([]geoJSONFeature, 0) - - for _, item := range media { - geoPoint := makeGeoJSONFeatureGeometryPoint(item.Latitude, item.Longitude) - - thumbnailURL := utils.ApiEndpointUrl() - thumbnailURL.Path = path.Join(thumbnailURL.Path, "photo", item.ThumbnailName) - - properties := geoJSONMediaProperties{ - MediaID: item.MediaID, - MediaTitle: item.MediaTitle, - Thumbnail: struct { - URL string `json:"url"` - Width int `json:"width"` - Height int `json:"height"` - }{ - URL: thumbnailURL.String(), - Width: item.ThumbnailWidth, - Height: item.ThumbnailHeight, - }, - } - - features = append(features, makeGeoJSONFeature(properties, geoPoint)) - } - - featureCollection := makeGeoJSONFeatureCollection(features) - return featureCollection, nil -} - -// MapboxToken is the resolver for the mapboxToken field. -func (r *queryResolver) MapboxToken(ctx context.Context) (*string, error) { - mapboxTokenEnv := os.Getenv("MAPBOX_TOKEN") - if mapboxTokenEnv == "" { - return nil, nil - } - - return &mapboxTokenEnv, nil -} diff --git a/api/graphql/resolvers/media_geo_json.go b/api/graphql/resolvers/media_geo_json.go index 2016d9b1..8b813a49 100644 --- a/api/graphql/resolvers/media_geo_json.go +++ b/api/graphql/resolvers/media_geo_json.go @@ -1,61 +1,80 @@ package resolvers -type geoMedia struct { - MediaID int - MediaTitle string - ThumbnailName string - ThumbnailWidth int - ThumbnailHeight int - Latitude float64 - Longitude float64 -} +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 -type geoJSONFeatureCollection struct { - Type string `json:"type"` - Features []geoJSONFeature `json:"features"` -} +import ( + "context" + "os" + "path" -type geoJSONFeature struct { - Type string `json:"type"` - Properties interface{} `json:"properties"` - Geometry geoJSONFeatureGeometry `json:"geometry"` -} + "github.com/photoview/photoview/api/graphql/auth" + "github.com/photoview/photoview/api/utils" +) -type geoJSONMediaProperties struct { - MediaID int `json:"media_id"` - MediaTitle string `json:"media_title"` - Thumbnail struct { - URL string `json:"url"` - Width int `json:"width"` - Height int `json:"height"` - } `json:"thumbnail"` -} - -type geoJSONFeatureGeometry struct { - Type string `json:"type"` - Coordinates [2]float64 `json:"coordinates"` -} - -func makeGeoJSONFeatureCollection(features []geoJSONFeature) geoJSONFeatureCollection { - return geoJSONFeatureCollection{ - Type: "FeatureCollection", - Features: features, +// MyMediaGeoJSON is the resolver for the myMediaGeoJson field. +func (r *queryResolver) MyMediaGeoJSON(ctx context.Context) (any, error) { + user := auth.UserFromContext(ctx) + if user == nil { + return nil, auth.ErrUnauthorized } -} -func makeGeoJSONFeature(properties interface{}, geometry geoJSONFeatureGeometry) geoJSONFeature { - return geoJSONFeature{ - Type: "Feature", - Properties: properties, - Geometry: geometry, + var media []*geoMedia + + err := r.DB(ctx).Table("media"). + Select("media.id AS media_id, media.title AS media_title, "+ + "media_urls.media_name AS thumbnail_name, media_urls.width AS thumbnail_width, "+ + "media_urls.height AS thumbnail_height, media_exif.gps_latitude AS latitude, "+ + "media_exif.gps_longitude AS longitude"). + Joins("INNER JOIN media_exif ON media.exif_id = media_exif.id"). + Joins("INNER JOIN media_urls ON media.id = media_urls.media_id"). + Joins("INNER JOIN user_albums ON media.album_id = user_albums.album_id"). + Where("media_exif.gps_latitude IS NOT NULL"). + Where("media_exif.gps_longitude IS NOT NULL"). + Where("media_urls.purpose = 'thumbnail'"). + Where("user_albums.user_id = ?", user.ID). + Scan(&media).Error + + if err != nil { + return nil, err } -} -func makeGeoJSONFeatureGeometryPoint(lat float64, long float64) geoJSONFeatureGeometry { - coordinates := [2]float64{long, lat} + features := make([]geoJSONFeature, 0) - return geoJSONFeatureGeometry{ - Type: "Point", - Coordinates: coordinates, + for _, item := range media { + geoPoint := makeGeoJSONFeatureGeometryPoint(item.Latitude, item.Longitude) + + thumbnailURL := utils.ApiEndpointUrl() + thumbnailURL.Path = path.Join(thumbnailURL.Path, "photo", item.ThumbnailName) + + properties := geoJSONMediaProperties{ + MediaID: item.MediaID, + MediaTitle: item.MediaTitle, + Thumbnail: struct { + URL string `json:"url"` + Width int `json:"width"` + Height int `json:"height"` + }{ + URL: thumbnailURL.String(), + Width: item.ThumbnailWidth, + Height: item.ThumbnailHeight, + }, + } + + features = append(features, makeGeoJSONFeature(properties, geoPoint)) } + + featureCollection := makeGeoJSONFeatureCollection(features) + return featureCollection, nil +} + +// MapboxToken is the resolver for the mapboxToken field. +func (r *queryResolver) MapboxToken(ctx context.Context) (*string, error) { + mapboxTokenEnv := os.Getenv("MAPBOX_TOKEN") + if mapboxTokenEnv == "" { + return nil, nil + } + + return &mapboxTokenEnv, nil } diff --git a/api/graphql/resolvers/media_geo_json.util.go b/api/graphql/resolvers/media_geo_json.util.go new file mode 100644 index 00000000..2016d9b1 --- /dev/null +++ b/api/graphql/resolvers/media_geo_json.util.go @@ -0,0 +1,61 @@ +package resolvers + +type geoMedia struct { + MediaID int + MediaTitle string + ThumbnailName string + ThumbnailWidth int + ThumbnailHeight int + Latitude float64 + Longitude float64 +} + +type geoJSONFeatureCollection struct { + Type string `json:"type"` + Features []geoJSONFeature `json:"features"` +} + +type geoJSONFeature struct { + Type string `json:"type"` + Properties interface{} `json:"properties"` + Geometry geoJSONFeatureGeometry `json:"geometry"` +} + +type geoJSONMediaProperties struct { + MediaID int `json:"media_id"` + MediaTitle string `json:"media_title"` + Thumbnail struct { + URL string `json:"url"` + Width int `json:"width"` + Height int `json:"height"` + } `json:"thumbnail"` +} + +type geoJSONFeatureGeometry struct { + Type string `json:"type"` + Coordinates [2]float64 `json:"coordinates"` +} + +func makeGeoJSONFeatureCollection(features []geoJSONFeature) geoJSONFeatureCollection { + return geoJSONFeatureCollection{ + Type: "FeatureCollection", + Features: features, + } +} + +func makeGeoJSONFeature(properties interface{}, geometry geoJSONFeatureGeometry) geoJSONFeature { + return geoJSONFeature{ + Type: "Feature", + Properties: properties, + Geometry: geometry, + } +} + +func makeGeoJSONFeatureGeometryPoint(lat float64, long float64) geoJSONFeatureGeometry { + coordinates := [2]float64{long, lat} + + return geoJSONFeatureGeometry{ + Type: "Point", + Coordinates: coordinates, + } +} diff --git a/api/graphql/resolvers/notification.go b/api/graphql/resolvers/notification.go index 59d540bd..b3e7eeb5 100644 --- a/api/graphql/resolvers/notification.go +++ b/api/graphql/resolvers/notification.go @@ -1,15 +1,20 @@ package resolvers +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 + import ( "context" + api "github.com/photoview/photoview/api/graphql" "github.com/photoview/photoview/api/graphql/auth" "github.com/photoview/photoview/api/graphql/models" "github.com/photoview/photoview/api/graphql/notification" ) +// Notification is the resolver for the notification field. func (r *subscriptionResolver) Notification(ctx context.Context) (<-chan *models.Notification, error) { - user := auth.UserFromContext(ctx) if user == nil { return nil, auth.ErrUnauthorized @@ -26,3 +31,8 @@ func (r *subscriptionResolver) Notification(ctx context.Context) (<-chan *models return notificationChannel, nil } + +// Subscription returns api.SubscriptionResolver implementation. +func (r *Resolver) Subscription() api.SubscriptionResolver { return &subscriptionResolver{r} } + +type subscriptionResolver struct{ *Resolver } diff --git a/api/graphql/resolvers/notification.graphql b/api/graphql/resolvers/notification.graphql new file mode 100644 index 00000000..ffd044e0 --- /dev/null +++ b/api/graphql/resolvers/notification.graphql @@ -0,0 +1,31 @@ +type Notification { + "A key used to identify the notification, new notification updates with the same key, should replace the old notifications" + key: String! + type: NotificationType! + "The text for the title of the notification" + header: String! + "The text for the body of the notification" + content: String! + "A value between 0 and 1 when the notification type is `Progress`" + progress: Float + "Whether or not the message of the notification is positive, the UI might reflect this with a green color" + positive: Boolean! + "Whether or not the message of the notification is negative, the UI might reflect this with a red color" + negative: Boolean! + "Time in milliseconds before the notification should close" + timeout: Int +} + +type Subscription { + notification: Notification! +} + +"Specified the type a particular notification is of" +enum NotificationType { + "A regular message with no special additions" + Message + "A notification with an attached progress indicator" + Progress + "Close a notification with a given key" + Close +} diff --git a/api/graphql/resolvers/resolver.go b/api/graphql/resolvers/resolver.go index 2719a815..e28e7fb0 100644 --- a/api/graphql/resolvers/resolver.go +++ b/api/graphql/resolvers/resolver.go @@ -3,7 +3,6 @@ package resolvers import ( "context" - api "github.com/photoview/photoview/api/graphql" "gorm.io/gorm" ) @@ -23,25 +22,3 @@ func NewRootResolver(db *gorm.DB) Resolver { func (r *Resolver) DB(ctx context.Context) *gorm.DB { return r.database.WithContext(ctx) } - -func (r *Resolver) Mutation() api.MutationResolver { - return &mutationResolver{r} -} - -func (r *Resolver) Query() api.QueryResolver { - return &queryResolver{r} -} - -func (r *Resolver) Subscription() api.SubscriptionResolver { - return &subscriptionResolver{ - Resolver: r, - } -} - -type mutationResolver struct{ *Resolver } - -type queryResolver struct{ *Resolver } - -type subscriptionResolver struct { - Resolver *Resolver -} diff --git a/api/graphql/resolvers/root.go b/api/graphql/resolvers/root.go new file mode 100644 index 00000000..158d3d06 --- /dev/null +++ b/api/graphql/resolvers/root.go @@ -0,0 +1,18 @@ +package resolvers + +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 + +import ( + api "github.com/photoview/photoview/api/graphql" +) + +// Mutation returns api.MutationResolver implementation. +func (r *Resolver) Mutation() api.MutationResolver { return &mutationResolver{r} } + +// Query returns api.QueryResolver implementation. +func (r *Resolver) Query() api.QueryResolver { return &queryResolver{r} } + +type mutationResolver struct{ *Resolver } +type queryResolver struct{ *Resolver } diff --git a/api/graphql/resolvers/root.graphql b/api/graphql/resolvers/root.graphql new file mode 100644 index 00000000..e0b3f16d --- /dev/null +++ b/api/graphql/resolvers/root.graphql @@ -0,0 +1,47 @@ +directive @isAuthorized on FIELD_DEFINITION +directive @isAdmin on FIELD_DEFINITION + +scalar Time +scalar Any + +"Used to specify which order to sort items in" +enum OrderDirection { + "Sort accending A-Z" + ASC + "Sort decending Z-A" + DESC +} + +"Used to specify pagination on a list of items" +input Pagination { + "How many items to maximally fetch" + limit: Int + "How many items to skip from the beginning of the query, specified by the `Ordering`" + offset: Int +} + +"Used to specify how to sort items" +input Ordering { + "A column in the database to order by" + order_by: String + order_direction: OrderDirection +} + +type Query + +type Mutation + +""" +A group of media from the same album and the same day, that is grouped together in a timeline view +NOTE: It isn't used. Just copy from the old schema.graphql. +""" +type TimelineGroup { + "The full album containing the media in this timeline group" + album: Album! + "The media contained in this timeline group" + media: [Media!]! + "The total amount of media in this timeline group" + mediaTotal: Int! + "The day shared for all media in this timeline group" + date: Time! +} diff --git a/api/graphql/resolvers/scanner.go b/api/graphql/resolvers/scanner.go index 952724c9..6abf5ecf 100644 --- a/api/graphql/resolvers/scanner.go +++ b/api/graphql/resolvers/scanner.go @@ -1,17 +1,23 @@ package resolvers +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 + import ( "context" + "errors" + "fmt" "time" "github.com/photoview/photoview/api/database/drivers" "github.com/photoview/photoview/api/graphql/models" "github.com/photoview/photoview/api/scanner/periodic_scanner" "github.com/photoview/photoview/api/scanner/scanner_queue" - "github.com/pkg/errors" "gorm.io/gorm" ) +// ScanAll is the resolver for the scanAll field. func (r *mutationResolver) ScanAll(ctx context.Context) (*models.ScannerResult, error) { err := scanner_queue.AddAllToQueue() if err != nil { @@ -27,10 +33,11 @@ func (r *mutationResolver) ScanAll(ctx context.Context) (*models.ScannerResult, }, nil } +// ScanUser is the resolver for the scanUser field. func (r *mutationResolver) ScanUser(ctx context.Context, userID int) (*models.ScannerResult, error) { var user models.User if err := r.DB(ctx).First(&user, userID).Error; err != nil { - return nil, errors.Wrap(err, "get user from database") + return nil, fmt.Errorf("get user from database: %w", err) } scanner_queue.AddUserToQueue(&user) @@ -43,6 +50,7 @@ func (r *mutationResolver) ScanUser(ctx context.Context, userID int) (*models.Sc }, nil } +// SetPeriodicScanInterval is the resolver for the setPeriodicScanInterval field. func (r *mutationResolver) SetPeriodicScanInterval(ctx context.Context, interval int) (int, error) { db := r.DB(ctx) if interval < 0 { @@ -68,6 +76,7 @@ func (r *mutationResolver) SetPeriodicScanInterval(ctx context.Context, interval return siteInfo.PeriodicScanInterval, nil } +// SetScannerConcurrentWorkers is the resolver for the setScannerConcurrentWorkers field. func (r *mutationResolver) SetScannerConcurrentWorkers(ctx context.Context, workers int) (int, error) { db := r.DB(ctx) if workers < 1 { diff --git a/api/graphql/resolvers/scanner.graphql b/api/graphql/resolvers/scanner.graphql new file mode 100644 index 00000000..adc8fc79 --- /dev/null +++ b/api/graphql/resolvers/scanner.graphql @@ -0,0 +1,23 @@ +type ScannerResult { + finished: Boolean! + success: Boolean! + progress: Float + message: String +} + +extend type Mutation { + "Scan all users for new media" + scanAll: ScannerResult! @isAdmin + + "Scan a single user for new media" + scanUser(userId: ID!): ScannerResult! @isAdmin + + """ + Set how often, in seconds, the server should automatically scan for new media, + a value of 0 will disable periodic scans + """ + setPeriodicScanInterval(interval: Int!): Int! @isAdmin + + "Set max number of concurrent scanner jobs running at once" + setScannerConcurrentWorkers(workers: Int!): Int! @isAdmin +} diff --git a/api/graphql/resolvers/schema.graphql b/api/graphql/resolvers/schema.graphql deleted file mode 100644 index 56c8333d..00000000 --- a/api/graphql/resolvers/schema.graphql +++ /dev/null @@ -1,296 +0,0 @@ -directive @isAuthorized on FIELD_DEFINITION -directive @isAdmin on FIELD_DEFINITION - -scalar Time -scalar Any - -"Used to specify which order to sort items in" -enum OrderDirection { - "Sort accending A-Z" - ASC - "Sort decending Z-A" - DESC -} - -"Used to specify pagination on a list of items" -input Pagination { - "How many items to maximally fetch" - limit: Int - "How many items to skip from the beginning of the query, specified by the `Ordering`" - offset: Int -} - -"Used to specify how to sort items" -input Ordering { - "A column in the database to order by" - order_by: String - order_direction: OrderDirection -} - -"Credentials used to identify and authenticate a share token" -input ShareTokenCredentials { - token: String! - password: String -} - -type Query { - siteInfo: SiteInfo! - - "List of registered users, must be admin to call" - user(order: Ordering, paginate: Pagination): [User!]! @isAdmin - "Information about the currently logged in user" - myUser: User! @isAuthorized - - "User preferences for the logged in user" - myUserPreferences: UserPreferences! @isAuthorized - - """ - Get a list of media, ordered first by day, then by album if multiple media was found for the same day. - """ - myTimeline( - paginate: Pagination, - onlyFavorites: Boolean, - "Only fetch media that is older than this date" - fromDate: Time - ): [Media!]! @isAuthorized - - "Fetch a share token containing an `Album` or `Media`" - shareToken(credentials: ShareTokenCredentials!): ShareToken! - "Check if the `ShareToken` credentials are valid" - shareTokenValidatePassword(credentials: ShareTokenCredentials!): Boolean! - - "Perform a search query on the contents of the media library" - search(query: String!, limitMedia: Int, limitAlbums: Int): SearchResult! -} - -type Mutation { - "Authorizes a user and returns a token used to identify the new session" - authorizeUser(username: String!, password: String!): AuthorizeResult! - - "Registers the initial user, can only be called if initialSetup from SiteInfo is true" - initialSetupWizard( - username: String! - password: String! - rootPath: String! - ): AuthorizeResult - - "Scan all users for new media" - scanAll: ScannerResult! @isAdmin - "Scan a single user for new media" - scanUser(userId: ID!): ScannerResult! @isAdmin - - "Generate share token for album" - shareAlbum(albumId: ID!, expire: Time, password: String): ShareToken! @isAuthorized - "Generate share token for media" - shareMedia(mediaId: ID!, expire: Time, password: String): ShareToken! @isAuthorized - "Delete a share token by it's token value" - deleteShareToken(token: String!): ShareToken! @isAuthorized - "Set a password for a token, if null is passed for the password argument, the password will be cleared" - protectShareToken(token: String!, password: String): ShareToken! @isAuthorized - - "Update a user, fields left as `null` will not be changed" - updateUser( - id: ID! - username: String - password: String - admin: Boolean - ): User! @isAdmin - "Create a new user" - createUser( - username: String! - password: String - admin: Boolean! - ): User! @isAdmin - "Delete an existing user" - deleteUser(id: ID!): User! @isAdmin - - "Add a root path from where to look for media for the given user, specified by their user id." - userAddRootPath(id: ID!, rootPath: String!): Album @isAdmin - """ - Remove a root path from a user, specified by the id of the user and the top album representing the root path. - This album was returned when creating the path using `userAddRootPath`. - A list of root paths for a particular user can be retrived from the `User.rootAlbums` path. - """ - userRemoveRootAlbum(userId: ID!, albumId: ID!): Album @isAdmin - - """ - Set how often, in seconds, the server should automatically scan for new media, - a value of 0 will disable periodic scans - """ - setPeriodicScanInterval(interval: Int!): Int! @isAdmin - - "Set max number of concurrent scanner jobs running at once" - setScannerConcurrentWorkers(workers: Int!): Int! @isAdmin - - "Set the filter to be used when generating thumbnails" - setThumbnailDownsampleMethod(method: ThumbnailFilter!): ThumbnailFilter! @isAdmin - - "Change user preferences for the logged in user" - changeUserPreferences(language: String): UserPreferences! @isAuthorized -} - -type Subscription { - notification: Notification! -} - -"Specified the type a particular notification is of" -enum NotificationType { - "A regular message with no special additions" - Message - "A notification with an attached progress indicator" - Progress - "Close a notification with a given key" - Close -} - -type Notification { - "A key used to identify the notification, new notification updates with the same key, should replace the old notifications" - key: String! - type: NotificationType! - "The text for the title of the notification" - header: String! - "The text for the body of the notification" - content: String! - "A value between 0 and 1 when the notification type is `Progress`" - progress: Float - "Whether or not the message of the notification is positive, the UI might reflect this with a green color" - positive: Boolean! - "Whether or not the message of the notification is negative, the UI might reflect this with a red color" - negative: Boolean! - "Time in milliseconds before the notification should close" - timeout: Int -} - -type AuthorizeResult { - success: Boolean! - "A textual status message describing the result, can be used to show an error message when `success` is false" - status: String! - "An access token used to authenticate new API requests as the newly authorized user. Is present when success is true" - token: String -} - -type ScannerResult { - finished: Boolean! - success: Boolean! - progress: Float - message: String -} - -"A token used to publicly access an album or media" -type ShareToken { - id: ID! - token: String! - "The user who created the token" - owner: User! - "Optional expire date" - expire: Time - "Whether or not a password is needed to access the share" - hasPassword: Boolean! - - "The album this token shares" - album: Album - "The media this token shares" - media: Media -} - -"Supported downsampling filters for thumbnail generation" -enum ThumbnailFilter { - NearestNeighbor, - Box, - Linear, - MitchellNetravali, - CatmullRom, - Lanczos, -} - -"General information about the site" -type SiteInfo { - "Whether or not the initial setup wizard should be shown" - initialSetup: Boolean! - "Whether or not face detection is enabled and working" - faceDetectionEnabled: Boolean! - "How often automatic scans should be initiated in seconds" - periodicScanInterval: Int! @isAdmin - "How many max concurrent scanner jobs that should run at once" - concurrentWorkers: Int! @isAdmin - "The filter to use when generating thumbnails" - thumbnailMethod: ThumbnailFilter! @isAdmin -} - -type User { - id: ID! - username: String! - "All albums owned by this user" - albums: [Album!]! @isAdmin - "Top level albums owned by this user" - rootAlbums: [Album!]! @isAdmin - "Whether or not the user has admin privileges" - admin: Boolean! -} - -"Supported language translations of the user interface" -enum LanguageTranslation { - English, - French, - Italian, - Swedish, - Danish, - Spanish, - Polish, - Ukrainian, - German, - Russian, - TraditionalChinese, - SimplifiedChinese, - Portuguese, - Basque, - Turkish -} - -"Preferences for regular users" -type UserPreferences { - id: ID! - language: LanguageTranslation -} - -type Coordinates { - "GPS latitude in degrees" - latitude: Float! - "GPS longitude in degrees" - longitude: Float! -} - -"Metadata specific to video media" -type VideoMetadata { - id: ID! - media: Media! - width: Int! - height: Int! - duration: Float! - codec: String - framerate: Float - bitrate: String - colorProfile: String - audio: String -} - -type SearchResult { - "The string that was searched for" - query: String! - "A list of albums that matched the query" - albums: [Album!]! - "A list of media that matched the query" - media: [Media!]! -} - -"A group of media from the same album and the same day, that is grouped together in a timeline view" -type TimelineGroup { - "The full album containing the media in this timeline group" - album: Album! - "The media contained in this timeline group" - media: [Media!]! - "The total amount of media in this timeline group" - mediaTotal: Int! - "The day shared for all media in this timeline group" - date: Time! -} diff --git a/api/graphql/resolvers/search.go b/api/graphql/resolvers/search.go index 6e6d1d19..dedf2e13 100644 --- a/api/graphql/resolvers/search.go +++ b/api/graphql/resolvers/search.go @@ -1,16 +1,19 @@ package resolvers +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 + import ( "context" "github.com/photoview/photoview/api/graphql/auth" - "github.com/photoview/photoview/api/graphql/models/actions" - "github.com/photoview/photoview/api/graphql/models" + "github.com/photoview/photoview/api/graphql/models/actions" ) -func (r *Resolver) Search(ctx context.Context, query string, limitMedia *int, limitAlbums *int) (*models.SearchResult, error) { - +// Search is the resolver for the search field. +func (r *queryResolver) Search(ctx context.Context, query string, limitMedia *int, limitAlbums *int) (*models.SearchResult, error) { user := auth.UserFromContext(ctx) if user == nil { return nil, auth.ErrUnauthorized diff --git a/api/graphql/resolvers/search.graphql b/api/graphql/resolvers/search.graphql new file mode 100644 index 00000000..e6e2fb1f --- /dev/null +++ b/api/graphql/resolvers/search.graphql @@ -0,0 +1,13 @@ +type SearchResult { + "The string that was searched for" + query: String! + "A list of albums that matched the query" + albums: [Album!]! + "A list of media that matched the query" + media: [Media!]! +} + +extend type Query { + "Perform a search query on the contents of the media library" + search(query: String!, limitMedia: Int, limitAlbums: Int): SearchResult! +} diff --git a/api/graphql/resolvers/share_token.go b/api/graphql/resolvers/share_token.go index cadc12f6..790b1b45 100644 --- a/api/graphql/resolvers/share_token.go +++ b/api/graphql/resolvers/share_token.go @@ -1,53 +1,72 @@ package resolvers +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 + import ( "context" + "errors" + "fmt" "time" - "github.com/pkg/errors" - "gorm.io/gorm" - "gorm.io/gorm/clause" - api "github.com/photoview/photoview/api/graphql" "github.com/photoview/photoview/api/graphql/auth" "github.com/photoview/photoview/api/graphql/models" "github.com/photoview/photoview/api/graphql/models/actions" "golang.org/x/crypto/bcrypt" + "gorm.io/gorm" + "gorm.io/gorm/clause" ) -type shareTokenResolver struct { - *Resolver +// ShareAlbum is the resolver for the shareAlbum field. +func (r *mutationResolver) ShareAlbum(ctx context.Context, albumID int, expire *time.Time, password *string) (*models.ShareToken, error) { + user := auth.UserFromContext(ctx) + if user == nil { + return nil, auth.ErrUnauthorized + } + + return actions.AddAlbumShare(r.DB(ctx), user, albumID, expire, password) } -func (r *Resolver) ShareToken() api.ShareTokenResolver { - return &shareTokenResolver{r} +// ShareMedia is the resolver for the shareMedia field. +func (r *mutationResolver) ShareMedia(ctx context.Context, mediaID int, expire *time.Time, password *string) (*models.ShareToken, error) { + user := auth.UserFromContext(ctx) + if user == nil { + return nil, auth.ErrUnauthorized + } + + return actions.AddMediaShare(r.DB(ctx), user, mediaID, expire, password) } -func (r *shareTokenResolver) Owner(ctx context.Context, obj *models.ShareToken) (*models.User, error) { - return &obj.Owner, nil +// DeleteShareToken is the resolver for the deleteShareToken field. +func (r *mutationResolver) DeleteShareToken(ctx context.Context, token string) (*models.ShareToken, error) { + user := auth.UserFromContext(ctx) + if user == nil { + return nil, auth.ErrUnauthorized + } + + return actions.DeleteShareToken(r.DB(ctx), user.ID, token) } -func (r *shareTokenResolver) Album(ctx context.Context, obj *models.ShareToken) (*models.Album, error) { - return obj.Album, nil -} - -func (r *shareTokenResolver) Media(ctx context.Context, obj *models.ShareToken) (*models.Media, error) { - return obj.Media, nil -} - -func (r *shareTokenResolver) HasPassword(ctx context.Context, obj *models.ShareToken) (bool, error) { - hasPassword := obj.Password != nil - return hasPassword, nil +// ProtectShareToken is the resolver for the protectShareToken field. +func (r *mutationResolver) ProtectShareToken(ctx context.Context, token string, password *string) (*models.ShareToken, error) { + user := auth.UserFromContext(ctx) + if user == nil { + return nil, auth.ErrUnauthorized + } + + return actions.ProtectShareToken(r.DB(ctx), user.ID, token, password) } +// ShareToken is the resolver for the shareToken field. func (r *queryResolver) ShareToken(ctx context.Context, credentials models.ShareTokenCredentials) (*models.ShareToken, error) { - var token models.ShareToken if err := r.DB(ctx).Preload(clause.Associations).Where("value = ?", credentials.Token).First(&token).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("share not found") } else { - return nil, errors.Wrap(err, "failed to get share token from database") + return nil, fmt.Errorf("failed to get share token from database: %w", err) } } @@ -56,7 +75,7 @@ func (r *queryResolver) ShareToken(ctx context.Context, credentials models.Share if err == bcrypt.ErrMismatchedHashAndPassword { return nil, errors.New("unauthorized") } else { - return nil, errors.Wrap(err, "failed to compare token password hashes") + return nil, fmt.Errorf("failed to compare token password hashes: %w", err) } } } @@ -64,14 +83,14 @@ func (r *queryResolver) ShareToken(ctx context.Context, credentials models.Share return &token, nil } +// ShareTokenValidatePassword is the resolver for the shareTokenValidatePassword field. func (r *queryResolver) ShareTokenValidatePassword(ctx context.Context, credentials models.ShareTokenCredentials) (bool, error) { - var token models.ShareToken if err := r.DB(ctx).Where("value = ?", credentials.Token).First(&token).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return false, errors.New("share not found") } else { - return false, errors.Wrap(err, "failed to get share token from database") + return false, fmt.Errorf("failed to get share token from database: %w", err) } } @@ -87,50 +106,20 @@ func (r *queryResolver) ShareTokenValidatePassword(ctx context.Context, credenti if err == bcrypt.ErrMismatchedHashAndPassword { return false, nil } else { - return false, errors.Wrap(err, "could not compare token password hashes") + return false, fmt.Errorf("could not compare token password hashes: %w", err) } } return true, nil } -func (r *mutationResolver) ShareAlbum(ctx context.Context, albumID int, expire *time.Time, - password *string) (*models.ShareToken, error) { - - user := auth.UserFromContext(ctx) - if user == nil { - return nil, auth.ErrUnauthorized - } - - return actions.AddAlbumShare(r.DB(ctx), user, albumID, expire, password) +// HasPassword is the resolver for the hasPassword field. +func (r *shareTokenResolver) HasPassword(ctx context.Context, obj *models.ShareToken) (bool, error) { + hasPassword := obj.Password != nil + return hasPassword, nil } -func (r *mutationResolver) ShareMedia(ctx context.Context, mediaID int, expire *time.Time, - password *string) (*models.ShareToken, error) { +// ShareToken returns api.ShareTokenResolver implementation. +func (r *Resolver) ShareToken() api.ShareTokenResolver { return &shareTokenResolver{r} } - user := auth.UserFromContext(ctx) - if user == nil { - return nil, auth.ErrUnauthorized - } - - return actions.AddMediaShare(r.DB(ctx), user, mediaID, expire, password) -} - -func (r *mutationResolver) DeleteShareToken(ctx context.Context, tokenValue string) (*models.ShareToken, error) { - user := auth.UserFromContext(ctx) - if user == nil { - return nil, auth.ErrUnauthorized - } - - return actions.DeleteShareToken(r.DB(ctx), user.ID, tokenValue) -} - -func (r *mutationResolver) ProtectShareToken(ctx context.Context, tokenValue string, password *string) (*models.ShareToken, error) { - - user := auth.UserFromContext(ctx) - if user == nil { - return nil, auth.ErrUnauthorized - } - - return actions.ProtectShareToken(r.DB(ctx), user.ID, tokenValue, password) -} +type shareTokenResolver struct{ *Resolver } diff --git a/api/graphql/resolvers/share_token.graphql b/api/graphql/resolvers/share_token.graphql new file mode 100644 index 00000000..f40fafd6 --- /dev/null +++ b/api/graphql/resolvers/share_token.graphql @@ -0,0 +1,44 @@ +"Credentials used to identify and authenticate a share token" +input ShareTokenCredentials { + token: String! + password: String +} + +"A token used to publicly access an album or media" +type ShareToken { + id: ID! + token: String! + "The user who created the token" + owner: User! + "Optional expire date" + expire: Time + "Whether or not a password is needed to access the share" + hasPassword: Boolean! + + "The album this token shares" + album: Album + "The media this token shares" + media: Media +} + +extend type Query { + "Fetch a share token containing an `Album` or `Media`" + shareToken(credentials: ShareTokenCredentials!): ShareToken! + + "Check if the `ShareToken` credentials are valid" + shareTokenValidatePassword(credentials: ShareTokenCredentials!): Boolean! +} + +extend type Mutation { + "Generate share token for album" + shareAlbum(albumId: ID!, expire: Time, password: String): ShareToken! @isAuthorized + + "Generate share token for media" + shareMedia(mediaId: ID!, expire: Time, password: String): ShareToken! @isAuthorized + + "Delete a share token by it's token value" + deleteShareToken(token: String!): ShareToken! @isAuthorized + + "Set a password for a token, if null is passed for the password argument, the password will be cleared" + protectShareToken(token: String!, password: String): ShareToken! @isAuthorized +} diff --git a/api/graphql/resolvers/site_info.go b/api/graphql/resolvers/site_info.go index 0f7a6ef9..847fc525 100644 --- a/api/graphql/resolvers/site_info.go +++ b/api/graphql/resolvers/site_info.go @@ -1,5 +1,9 @@ package resolvers +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 + import ( "context" @@ -8,18 +12,17 @@ import ( "github.com/photoview/photoview/api/scanner/face_detection" ) +// SiteInfo is the resolver for the siteInfo field. func (r *queryResolver) SiteInfo(ctx context.Context) (*models.SiteInfo, error) { return models.GetSiteInfo(r.DB(ctx)) } -type SiteInfoResolver struct { - *Resolver -} - -func (r *Resolver) SiteInfo() api.SiteInfoResolver { - return &SiteInfoResolver{r} -} - -func (SiteInfoResolver) FaceDetectionEnabled(ctx context.Context, obj *models.SiteInfo) (bool, error) { +// FaceDetectionEnabled is the resolver for the faceDetectionEnabled field. +func (r *siteInfoResolver) FaceDetectionEnabled(ctx context.Context, obj *models.SiteInfo) (bool, error) { return face_detection.GlobalFaceDetector != nil, nil } + +// SiteInfo returns api.SiteInfoResolver implementation. +func (r *Resolver) SiteInfo() api.SiteInfoResolver { return &siteInfoResolver{r} } + +type siteInfoResolver struct{ *Resolver } diff --git a/api/graphql/resolvers/site_info.graphql b/api/graphql/resolvers/site_info.graphql new file mode 100644 index 00000000..4410d19e --- /dev/null +++ b/api/graphql/resolvers/site_info.graphql @@ -0,0 +1,17 @@ +"General information about the site" +type SiteInfo { + "Whether or not the initial setup wizard should be shown" + initialSetup: Boolean! + "Whether or not face detection is enabled and working" + faceDetectionEnabled: Boolean! + "How often automatic scans should be initiated in seconds" + periodicScanInterval: Int! @isAdmin + "How many max concurrent scanner jobs that should run at once" + concurrentWorkers: Int! @isAdmin + "The filter to use when generating thumbnails" + thumbnailMethod: ThumbnailFilter! @isAdmin +} + +extend type Query { + siteInfo: SiteInfo! +} diff --git a/api/graphql/resolvers/thumbnails.go b/api/graphql/resolvers/thumbnails.go index 18163f03..c449f246 100644 --- a/api/graphql/resolvers/thumbnails.go +++ b/api/graphql/resolvers/thumbnails.go @@ -1,16 +1,18 @@ package resolvers +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 + import ( "context" "github.com/photoview/photoview/api/graphql/models" - // "github.com/pkg/errors" "gorm.io/gorm" ) -func (r *mutationResolver) SetThumbnailDownsampleMethod(ctx context.Context, - method models.ThumbnailFilter) (models.ThumbnailFilter, error) { - +// SetThumbnailDownsampleMethod is the resolver for the setThumbnailDownsampleMethod field. +func (r *mutationResolver) SetThumbnailDownsampleMethod(ctx context.Context, method models.ThumbnailFilter) (models.ThumbnailFilter, error) { db := r.DB(ctx) // if method > 5 { @@ -38,5 +40,4 @@ func (r *mutationResolver) SetThumbnailDownsampleMethod(ctx context.Context, // lng := models.LanguageTranslation(*language) // langTrans = &lng // } - } diff --git a/api/graphql/resolvers/thumbnails.graphql b/api/graphql/resolvers/thumbnails.graphql new file mode 100644 index 00000000..04d16a87 --- /dev/null +++ b/api/graphql/resolvers/thumbnails.graphql @@ -0,0 +1,14 @@ +"Supported downsampling filters for thumbnail generation" +enum ThumbnailFilter { + NearestNeighbor, + Box, + Linear, + MitchellNetravali, + CatmullRom, + Lanczos, +} + +extend type Mutation { + "Set the filter to be used when generating thumbnails" + setThumbnailDownsampleMethod(method: ThumbnailFilter!): ThumbnailFilter! @isAdmin +} diff --git a/api/graphql/resolvers/timeline.go b/api/graphql/resolvers/timeline.go index 76922910..1302e66b 100644 --- a/api/graphql/resolvers/timeline.go +++ b/api/graphql/resolvers/timeline.go @@ -1,5 +1,9 @@ package resolvers +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 + import ( "context" "time" @@ -9,9 +13,8 @@ import ( "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) { - +// MyTimeline is the resolver for the myTimeline field. +func (r *queryResolver) MyTimeline(ctx context.Context, paginate *models.Pagination, onlyFavorites *bool, fromDate *time.Time) ([]*models.Media, error) { user := auth.UserFromContext(ctx) if user == nil { return nil, auth.ErrUnauthorized diff --git a/api/graphql/resolvers/timeline.graphql b/api/graphql/resolvers/timeline.graphql new file mode 100644 index 00000000..6e3f3f98 --- /dev/null +++ b/api/graphql/resolvers/timeline.graphql @@ -0,0 +1,11 @@ +extend type Query { + """ + Get a list of media, ordered first by day, then by album if multiple media was found for the same day. + """ + myTimeline( + paginate: Pagination, + onlyFavorites: Boolean, + "Only fetch media that is older than this date" + fromDate: Time + ): [Media!]! @isAuthorized +} diff --git a/api/graphql/resolvers/user.go b/api/graphql/resolvers/user.go index d0d20b49..ab64b2cf 100644 --- a/api/graphql/resolvers/user.go +++ b/api/graphql/resolvers/user.go @@ -1,80 +1,26 @@ package resolvers +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.55 + import ( "context" - "os" + "errors" + "fmt" "path" - "strconv" api "github.com/photoview/photoview/api/graphql" "github.com/photoview/photoview/api/graphql/auth" "github.com/photoview/photoview/api/graphql/models" "github.com/photoview/photoview/api/graphql/models/actions" "github.com/photoview/photoview/api/scanner" - "github.com/photoview/photoview/api/scanner/face_detection" - "github.com/photoview/photoview/api/utils" - "github.com/pkg/errors" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) -type userResolver struct { - *Resolver -} - -func (r *Resolver) User() api.UserResolver { - return &userResolver{r} -} - -func (r *queryResolver) User(ctx context.Context, order *models.Ordering, - paginate *models.Pagination) ([]*models.User, error) { - - var users []*models.User - - if err := models.FormatSQL(r.DB(ctx).Model(models.User{}), order, paginate).Find(&users).Error; err != nil { - return nil, err - } - - return users, nil -} - -func (r *userResolver) Albums(ctx context.Context, user *models.User) ([]*models.Album, error) { - user.FillAlbums(r.DB(ctx)) - - pointerAlbums := make([]*models.Album, len(user.Albums)) - for i, album := range user.Albums { - pointerAlbums[i] = &album - } - - return pointerAlbums, nil -} - -func (r *userResolver) RootAlbums(ctx context.Context, user *models.User) (albums []*models.Album, err error) { - db := r.DB(ctx) - - err = db.Model(&user). - Where("albums.parent_album_id NOT IN (?)", - db.Table("user_albums"). - Select("albums.id"). - Joins("JOIN albums ON albums.id = user_albums.album_id AND user_albums.user_id = ?", user.ID), - ).Or("albums.parent_album_id IS NULL").Order("path ASC"). - Association("Albums").Find(&albums) - - return -} - -func (r *queryResolver) MyUser(ctx context.Context) (*models.User, error) { - - user := auth.UserFromContext(ctx) - if user == nil { - return nil, auth.ErrUnauthorized - } - - return user, nil -} - -func (r *mutationResolver) AuthorizeUser(ctx context.Context, username string, - password string) (*models.AuthorizeResult, error) { +// AuthorizeUser is the resolver for the authorizeUser field. +func (r *mutationResolver) AuthorizeUser(ctx context.Context, username string, password string) (*models.AuthorizeResult, error) { db := r.DB(ctx) user, err := models.AuthorizeUser(db, username, password) if err != nil { @@ -106,8 +52,8 @@ func (r *mutationResolver) AuthorizeUser(ctx context.Context, username string, }, nil } -func (r *mutationResolver) InitialSetupWizard(ctx context.Context, username string, password string, - rootPath string) (*models.AuthorizeResult, error) { +// InitialSetupWizard is the resolver for the initialSetupWizard field. +func (r *mutationResolver) InitialSetupWizard(ctx context.Context, username string, password string, rootPath string) (*models.AuthorizeResult, error) { db := r.DB(ctx) siteInfo, err := models.GetSiteInfo(db) if err != nil { @@ -159,53 +105,8 @@ func (r *mutationResolver) InitialSetupWizard(ctx context.Context, username stri }, nil } -func (r *queryResolver) MyUserPreferences(ctx context.Context) (*models.UserPreferences, error) { - user := auth.UserFromContext(ctx) - if user == nil { - return nil, auth.ErrUnauthorized - } - - userPref := models.UserPreferences{ - UserID: user.ID, - } - if err := r.DB(ctx).Where("user_id = ?", user.ID).FirstOrCreate(&userPref).Error; err != nil { - return nil, err - } - - return &userPref, nil -} - -func (r *mutationResolver) ChangeUserPreferences(ctx context.Context, language *string) (*models.UserPreferences, error) { - db := r.DB(ctx) - user := auth.UserFromContext(ctx) - if user == nil { - return nil, auth.ErrUnauthorized - } - - var langTrans *models.LanguageTranslation = nil - if language != nil { - lng := models.LanguageTranslation(*language) - langTrans = &lng - } - - var userPref models.UserPreferences - if err := db.Where("user_id = ?", user.ID).FirstOrInit(&userPref).Error; err != nil { - return nil, err - } - - userPref.UserID = user.ID - userPref.Language = langTrans - - if err := db.Save(&userPref).Error; err != nil { - return nil, err - } - - return &userPref, nil -} - -// Admin queries -func (r *mutationResolver) UpdateUser(ctx context.Context, id int, username *string, password *string, - admin *bool) (*models.User, error) { +// UpdateUser is the resolver for the updateUser field. +func (r *mutationResolver) UpdateUser(ctx context.Context, id int, username *string, password *string, admin *bool) (*models.User, error) { db := r.DB(ctx) if username == nil && password == nil && admin == nil { @@ -236,15 +137,14 @@ func (r *mutationResolver) UpdateUser(ctx context.Context, id int, username *str } if err := db.Save(&user).Error; err != nil { - return nil, errors.Wrap(err, "failed to update user") + return nil, fmt.Errorf("failed to update user: %w", err) } return &user, nil } -func (r *mutationResolver) CreateUser(ctx context.Context, username string, password *string, - admin bool) (*models.User, error) { - +// CreateUser is the resolver for the createUser field. +func (r *mutationResolver) CreateUser(ctx context.Context, username string, password *string, admin bool) (*models.User, error) { var user *models.User transactionError := r.DB(ctx).Transaction(func(tx *gorm.DB) error { @@ -264,10 +164,12 @@ func (r *mutationResolver) CreateUser(ctx context.Context, username string, pass return user, nil } +// DeleteUser is the resolver for the deleteUser field. func (r *mutationResolver) DeleteUser(ctx context.Context, id int) (*models.User, error) { return actions.DeleteUser(r.DB(ctx), id) } +// UserAddRootPath is the resolver for the userAddRootPath field. func (r *mutationResolver) UserAddRootPath(ctx context.Context, id int, rootPath string) (*models.Album, error) { db := r.DB(ctx) @@ -286,6 +188,7 @@ func (r *mutationResolver) UserAddRootPath(ctx context.Context, id int, rootPath return newAlbum, nil } +// UserRemoveRootAlbum is the resolver for the userRemoveRootAlbum field. func (r *mutationResolver) UserRemoveRootAlbum(ctx context.Context, userID int, albumID int) (*models.Album, error) { db := r.DB(ctx) @@ -339,44 +242,101 @@ func (r *mutationResolver) UserRemoveRootAlbum(ctx context.Context, userID int, return &album, nil } -func cleanup(tx *gorm.DB, albumID int, childAlbumIDs []int) ([]int, error) { - var userAlbumCount int - var deletedAlbumIDs []int = nil +// ChangeUserPreferences is the resolver for the changeUserPreferences field. +func (r *mutationResolver) ChangeUserPreferences(ctx context.Context, language *string) (*models.UserPreferences, error) { + db := r.DB(ctx) + user := auth.UserFromContext(ctx) + if user == nil { + return nil, auth.ErrUnauthorized + } - if err := tx.Raw("SELECT COUNT(user_id) FROM user_albums WHERE album_id = ?", - albumID).Scan(&userAlbumCount).Error; err != nil { + var langTrans *models.LanguageTranslation = nil + if language != nil { + lng := models.LanguageTranslation(*language) + langTrans = &lng + } + var userPref models.UserPreferences + if err := db.Where("user_id = ?", user.ID).FirstOrInit(&userPref).Error; err != nil { return nil, err } - if userAlbumCount == 0 { - deletedAlbumIDs = append(childAlbumIDs, albumID) - childAlbumIDs = nil - // Delete albums from database - if err := tx.Delete(&models.Album{}, "id IN (?)", deletedAlbumIDs).Error; err != nil { - deletedAlbumIDs = nil - return nil, err - } + userPref.UserID = user.ID + userPref.Language = langTrans + + if err := db.Save(&userPref).Error; err != nil { + return nil, err } - return deletedAlbumIDs, nil + + return &userPref, nil } -func clearCacheAndReloadFaces(db *gorm.DB, deletedAlbumIDs []int) error { - if deletedAlbumIDs != nil { - // Delete albums from cache - for _, id := range deletedAlbumIDs { - cacheAlbumPath := path.Join(utils.MediaCachePath(), strconv.Itoa(id)) +// User is the resolver for the user field. +func (r *queryResolver) User(ctx context.Context, order *models.Ordering, paginate *models.Pagination) ([]*models.User, error) { + var users []*models.User - if err := os.RemoveAll(cacheAlbumPath); err != nil { - return err - } - } - // Reload faces as media might have been deleted - if face_detection.GlobalFaceDetector != nil { - if err := face_detection.GlobalFaceDetector.ReloadFacesFromDatabase(db); err != nil { - return err - } - } + if err := models.FormatSQL(r.DB(ctx).Model(models.User{}), order, paginate).Find(&users).Error; err != nil { + return nil, err } - return nil + + return users, nil } + +// MyUser is the resolver for the myUser field. +func (r *queryResolver) MyUser(ctx context.Context) (*models.User, error) { + user := auth.UserFromContext(ctx) + if user == nil { + return nil, auth.ErrUnauthorized + } + + return user, nil +} + +// MyUserPreferences is the resolver for the myUserPreferences field. +func (r *queryResolver) MyUserPreferences(ctx context.Context) (*models.UserPreferences, error) { + user := auth.UserFromContext(ctx) + if user == nil { + return nil, auth.ErrUnauthorized + } + + userPref := models.UserPreferences{ + UserID: user.ID, + } + if err := r.DB(ctx).Where("user_id = ?", user.ID).FirstOrCreate(&userPref).Error; err != nil { + return nil, err + } + + return &userPref, nil +} + +// Albums is the resolver for the albums field. +func (r *userResolver) Albums(ctx context.Context, obj *models.User) ([]*models.Album, error) { + obj.FillAlbums(r.DB(ctx)) + + pointerAlbums := make([]*models.Album, len(obj.Albums)) + for i, album := range obj.Albums { + pointerAlbums[i] = &album + } + + return pointerAlbums, nil +} + +// RootAlbums is the resolver for the rootAlbums field. +func (r *userResolver) RootAlbums(ctx context.Context, obj *models.User) (albums []*models.Album, err error) { + db := r.DB(ctx) + + err = db.Model(obj). + Where("albums.parent_album_id NOT IN (?)", + db.Table("user_albums"). + Select("albums.id"). + Joins("JOIN albums ON albums.id = user_albums.album_id AND user_albums.user_id = ?", obj.ID), + ).Or("albums.parent_album_id IS NULL").Order("path ASC"). + Association("Albums").Find(&albums) + + return +} + +// User returns api.UserResolver implementation. +func (r *Resolver) User() api.UserResolver { return &userResolver{r} } + +type userResolver struct{ *Resolver } diff --git a/api/graphql/resolvers/user.graphql b/api/graphql/resolvers/user.graphql new file mode 100644 index 00000000..821ac035 --- /dev/null +++ b/api/graphql/resolvers/user.graphql @@ -0,0 +1,97 @@ +type User { + id: ID! + username: String! + "All albums owned by this user" + albums: [Album!]! @isAdmin + "Top level albums owned by this user" + rootAlbums: [Album!]! @isAdmin + "Whether or not the user has admin privileges" + admin: Boolean! +} + +"Supported language translations of the user interface" +enum LanguageTranslation { + English, + French, + Italian, + Swedish, + Danish, + Spanish, + Polish, + Ukrainian, + German, + Russian, + TraditionalChinese, + SimplifiedChinese, + Portuguese, + Basque, + Turkish +} + +"Preferences for regular users" +type UserPreferences { + id: ID! + language: LanguageTranslation +} + +type AuthorizeResult { + success: Boolean! + + "A textual status message describing the result, can be used to show an error message when `success` is false" + status: String! + "An access token used to authenticate new API requests as the newly authorized user. Is present when success is true" + token: String +} + + +extend type Query { + "List of registered users, must be admin to call" + user(order: Ordering, paginate: Pagination): [User!]! @isAdmin + + "Information about the currently logged in user" + myUser: User! @isAuthorized + + "User preferences for the logged in user" + myUserPreferences: UserPreferences! @isAuthorized +} + +extend type Mutation { + "Authorizes a user and returns a token used to identify the new session" + authorizeUser(username: String!, password: String!): AuthorizeResult! + + "Registers the initial user, can only be called if initialSetup from SiteInfo is true" + initialSetupWizard( + username: String! + password: String! + rootPath: String! + ): AuthorizeResult + + "Update a user, fields left as `null` will not be changed" + updateUser( + id: ID! + username: String + password: String + admin: Boolean + ): User! @isAdmin + "Create a new user" + createUser( + username: String! + password: String + admin: Boolean! + ): User! @isAdmin + "Delete an existing user" + deleteUser(id: ID!): User! @isAdmin + + "Add a root path from where to look for media for the given user, specified by their user id." + userAddRootPath(id: ID!, rootPath: String!): Album @isAdmin + + """ + Remove a root path from a user, specified by the id of the user and the top album representing the root path. + This album was returned when creating the path using `userAddRootPath`. + A list of root paths for a particular user can be retrived from the `User.rootAlbums` path. + """ + userRemoveRootAlbum(userId: ID!, albumId: ID!): Album @isAdmin + + "Change user preferences for the logged in user" + changeUserPreferences(language: String): UserPreferences! @isAuthorized +} diff --git a/api/graphql/resolvers/user.util.go b/api/graphql/resolvers/user.util.go new file mode 100644 index 00000000..c1290b5a --- /dev/null +++ b/api/graphql/resolvers/user.util.go @@ -0,0 +1,54 @@ +package resolvers + +import ( + "os" + "path" + "strconv" + + "github.com/photoview/photoview/api/graphql/models" + "github.com/photoview/photoview/api/scanner/face_detection" + "github.com/photoview/photoview/api/utils" + "gorm.io/gorm" +) + +func cleanup(tx *gorm.DB, albumID int, childAlbumIDs []int) ([]int, error) { + var userAlbumCount int + var deletedAlbumIDs []int = nil + + if err := tx.Raw("SELECT COUNT(user_id) FROM user_albums WHERE album_id = ?", + albumID).Scan(&userAlbumCount).Error; err != nil { + + return nil, err + } + + if userAlbumCount == 0 { + deletedAlbumIDs = append(childAlbumIDs, albumID) + childAlbumIDs = nil + // Delete albums from database + if err := tx.Delete(&models.Album{}, "id IN (?)", deletedAlbumIDs).Error; err != nil { + deletedAlbumIDs = nil + return nil, err + } + } + return deletedAlbumIDs, nil +} + +func clearCacheAndReloadFaces(db *gorm.DB, deletedAlbumIDs []int) error { + if deletedAlbumIDs != nil { + // Delete albums from cache + for _, id := range deletedAlbumIDs { + cacheAlbumPath := path.Join(utils.MediaCachePath(), strconv.Itoa(id)) + + if err := os.RemoveAll(cacheAlbumPath); err != nil { + return err + } + } + // Reload faces as media might have been deleted + if face_detection.GlobalFaceDetector != nil { + if err := face_detection.GlobalFaceDetector.ReloadFacesFromDatabase(db); err != nil { + return err + } + } + } + return nil +} diff --git a/scripts/test_all.sh b/scripts/test_all.sh new file mode 100755 index 00000000..7270bc43 --- /dev/null +++ b/scripts/test_all.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu + +for test in $(dirname $0)/test_* +do + if [ "${test}" != "${test%%/scripts/test_all.sh}" ] + then + continue + fi + + echo Running ${test}... + ${test} +done diff --git a/scripts/test_api_coverage.sh b/scripts/test_api_coverage.sh new file mode 100755 index 00000000..8dbf8780 --- /dev/null +++ b/scripts/test_api_coverage.sh @@ -0,0 +1,5 @@ +#!/bin/sh +set -eu + +cd $(dirname $0)/../api +go test ./... -v -database -filesystem -p 1 -coverprofile=coverage.txt -covermode=atomic diff --git a/scripts/test_is_generated_code_in_sync.sh b/scripts/test_is_generated_code_in_sync.sh new file mode 100755 index 00000000..f040b3c5 --- /dev/null +++ b/scripts/test_is_generated_code_in_sync.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu + +cd $(dirname $0)/../api +go generate ./... +if [ "$(git status -s 2>/dev/null | head -1)" != "" ]; then + echo '--- FAIL: The generated API code is out of sync with the recent changes. Please run `go generate ./...` under `./api` to regenerate it and commit it to this branch.' + exit 1 +fi + +echo '--- PASS: All generated code is in sync with the project.'