From 679dc70340698c03b62e9f0a1f74c8dfc727b67f Mon Sep 17 00:00:00 2001 From: viktorstrate Date: Sun, 20 Sep 2020 22:19:25 +0200 Subject: [PATCH 1/5] Prepare for periodic scan intervals Add setting to database, and to graphql api --- .../migrations/001_initial_setup.up.sql | 2 +- .../002_site_info_more_settings.up.sql | 3 + api/graphql/generated.go | 285 +++++++++++------- api/graphql/models/generated.go | 4 +- api/graphql/models/site_info.go | 17 +- api/graphql/schema.graphql | 4 +- 6 files changed, 194 insertions(+), 121 deletions(-) create mode 100644 api/database/migrations/002_site_info_more_settings.up.sql diff --git a/api/database/migrations/001_initial_setup.up.sql b/api/database/migrations/001_initial_setup.up.sql index 0a65d8b..9d57a8a 100644 --- a/api/database/migrations/001_initial_setup.up.sql +++ b/api/database/migrations/001_initial_setup.up.sql @@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS access_token ( ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS site_info ( - initial_setup boolean NOT NULL DEFAULT TRUE + initial_setup boolean NOT NULL DEFAULT TRUE, ) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- Video related diff --git a/api/database/migrations/002_site_info_more_settings.up.sql b/api/database/migrations/002_site_info_more_settings.up.sql new file mode 100644 index 0000000..47db816 --- /dev/null +++ b/api/database/migrations/002_site_info_more_settings.up.sql @@ -0,0 +1,3 @@ + +ALTER TABLE site_info + ADD COLUMN IF NOT EXISTS periodic_scan_interval int(8) NOT NULL DEFAULT 0; diff --git a/api/graphql/generated.go b/api/graphql/generated.go index e93dcfe..e4cb634 100644 --- a/api/graphql/generated.go +++ b/api/graphql/generated.go @@ -177,7 +177,8 @@ type ComplexityRoot struct { } SiteInfo struct { - InitialSetup func(childComplexity int) int + InitialSetup func(childComplexity int) int + PeriodicScanInterval func(childComplexity int) int } Subscription struct { @@ -1019,6 +1020,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.SiteInfo.InitialSetup(childComplexity), true + case "SiteInfo.periodicScanInterval": + if e.complexity.SiteInfo.PeriodicScanInterval == nil { + break + } + + return e.complexity.SiteInfo.PeriodicScanInterval(childComplexity), true + case "Subscription.notification": if e.complexity.Subscription.Notification == nil { break @@ -1205,7 +1213,7 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er } var sources = []*ast.Source{ - &ast.Source{Name: "graphql/schema.graphql", Input: `directive @isAdmin on FIELD_DEFINITION + {Name: "graphql/schema.graphql", Input: `directive @isAdmin on FIELD_DEFINITION scalar Time @@ -1354,9 +1362,11 @@ type ShareToken { media: Media } -"General public information about the site" +"General information about the site" type SiteInfo { initialSetup: Boolean! + "How often automatic scans should be initiated in seconds" + periodicScanInterval: Int! @isAdmin } type User { @@ -1488,6 +1498,7 @@ func (ec *executionContext) field_Album_media_args(ctx context.Context, rawArgs args := map[string]interface{}{} var arg0 *models.Filter if tmp, ok := rawArgs["filter"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("filter")) arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp) if err != nil { return nil, err @@ -1502,6 +1513,7 @@ func (ec *executionContext) field_Album_subAlbums_args(ctx context.Context, rawA args := map[string]interface{}{} var arg0 *models.Filter if tmp, ok := rawArgs["filter"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("filter")) arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp) if err != nil { return nil, err @@ -1516,6 +1528,7 @@ func (ec *executionContext) field_Mutation_authorizeUser_args(ctx context.Contex args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["username"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("username")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1524,6 +1537,7 @@ func (ec *executionContext) field_Mutation_authorizeUser_args(ctx context.Contex args["username"] = arg0 var arg1 string if tmp, ok := rawArgs["password"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("password")) arg1, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1538,6 +1552,7 @@ func (ec *executionContext) field_Mutation_createUser_args(ctx context.Context, args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["username"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("username")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1546,6 +1561,7 @@ func (ec *executionContext) field_Mutation_createUser_args(ctx context.Context, args["username"] = arg0 var arg1 string if tmp, ok := rawArgs["rootPath"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("rootPath")) arg1, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1554,6 +1570,7 @@ func (ec *executionContext) field_Mutation_createUser_args(ctx context.Context, args["rootPath"] = arg1 var arg2 *string if tmp, ok := rawArgs["password"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("password")) arg2, err = ec.unmarshalOString2ᚖstring(ctx, tmp) if err != nil { return nil, err @@ -1562,6 +1579,7 @@ func (ec *executionContext) field_Mutation_createUser_args(ctx context.Context, args["password"] = arg2 var arg3 bool if tmp, ok := rawArgs["admin"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("admin")) arg3, err = ec.unmarshalNBoolean2bool(ctx, tmp) if err != nil { return nil, err @@ -1576,6 +1594,7 @@ func (ec *executionContext) field_Mutation_deleteShareToken_args(ctx context.Con args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["token"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("token")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1590,6 +1609,7 @@ func (ec *executionContext) field_Mutation_deleteUser_args(ctx context.Context, args := map[string]interface{}{} var arg0 int if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("id")) arg0, err = ec.unmarshalNInt2int(ctx, tmp) if err != nil { return nil, err @@ -1604,6 +1624,7 @@ func (ec *executionContext) field_Mutation_favoriteMedia_args(ctx context.Contex args := map[string]interface{}{} var arg0 int if tmp, ok := rawArgs["mediaId"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("mediaId")) arg0, err = ec.unmarshalNInt2int(ctx, tmp) if err != nil { return nil, err @@ -1612,6 +1633,7 @@ func (ec *executionContext) field_Mutation_favoriteMedia_args(ctx context.Contex args["mediaId"] = arg0 var arg1 bool if tmp, ok := rawArgs["favorite"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("favorite")) arg1, err = ec.unmarshalNBoolean2bool(ctx, tmp) if err != nil { return nil, err @@ -1626,6 +1648,7 @@ func (ec *executionContext) field_Mutation_initialSetupWizard_args(ctx context.C args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["username"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("username")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1634,6 +1657,7 @@ func (ec *executionContext) field_Mutation_initialSetupWizard_args(ctx context.C args["username"] = arg0 var arg1 string if tmp, ok := rawArgs["password"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("password")) arg1, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1642,6 +1666,7 @@ func (ec *executionContext) field_Mutation_initialSetupWizard_args(ctx context.C args["password"] = arg1 var arg2 string if tmp, ok := rawArgs["rootPath"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("rootPath")) arg2, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1656,6 +1681,7 @@ func (ec *executionContext) field_Mutation_protectShareToken_args(ctx context.Co args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["token"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("token")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1664,6 +1690,7 @@ func (ec *executionContext) field_Mutation_protectShareToken_args(ctx context.Co args["token"] = arg0 var arg1 *string if tmp, ok := rawArgs["password"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("password")) arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) if err != nil { return nil, err @@ -1678,6 +1705,7 @@ func (ec *executionContext) field_Mutation_registerUser_args(ctx context.Context args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["username"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("username")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1686,6 +1714,7 @@ func (ec *executionContext) field_Mutation_registerUser_args(ctx context.Context args["username"] = arg0 var arg1 string if tmp, ok := rawArgs["password"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("password")) arg1, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1694,6 +1723,7 @@ func (ec *executionContext) field_Mutation_registerUser_args(ctx context.Context args["password"] = arg1 var arg2 string if tmp, ok := rawArgs["rootPath"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("rootPath")) arg2, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1708,6 +1738,7 @@ func (ec *executionContext) field_Mutation_scanUser_args(ctx context.Context, ra args := map[string]interface{}{} var arg0 int if tmp, ok := rawArgs["userId"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("userId")) arg0, err = ec.unmarshalNInt2int(ctx, tmp) if err != nil { return nil, err @@ -1722,6 +1753,7 @@ func (ec *executionContext) field_Mutation_shareAlbum_args(ctx context.Context, args := map[string]interface{}{} var arg0 int if tmp, ok := rawArgs["albumId"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("albumId")) arg0, err = ec.unmarshalNInt2int(ctx, tmp) if err != nil { return nil, err @@ -1730,6 +1762,7 @@ func (ec *executionContext) field_Mutation_shareAlbum_args(ctx context.Context, args["albumId"] = arg0 var arg1 *time.Time if tmp, ok := rawArgs["expire"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("expire")) arg1, err = ec.unmarshalOTime2ᚖtimeᚐTime(ctx, tmp) if err != nil { return nil, err @@ -1738,6 +1771,7 @@ func (ec *executionContext) field_Mutation_shareAlbum_args(ctx context.Context, args["expire"] = arg1 var arg2 *string if tmp, ok := rawArgs["password"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("password")) arg2, err = ec.unmarshalOString2ᚖstring(ctx, tmp) if err != nil { return nil, err @@ -1752,6 +1786,7 @@ func (ec *executionContext) field_Mutation_shareMedia_args(ctx context.Context, args := map[string]interface{}{} var arg0 int if tmp, ok := rawArgs["mediaId"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("mediaId")) arg0, err = ec.unmarshalNInt2int(ctx, tmp) if err != nil { return nil, err @@ -1760,6 +1795,7 @@ func (ec *executionContext) field_Mutation_shareMedia_args(ctx context.Context, args["mediaId"] = arg0 var arg1 *time.Time if tmp, ok := rawArgs["expire"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("expire")) arg1, err = ec.unmarshalOTime2ᚖtimeᚐTime(ctx, tmp) if err != nil { return nil, err @@ -1768,6 +1804,7 @@ func (ec *executionContext) field_Mutation_shareMedia_args(ctx context.Context, args["expire"] = arg1 var arg2 *string if tmp, ok := rawArgs["password"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("password")) arg2, err = ec.unmarshalOString2ᚖstring(ctx, tmp) if err != nil { return nil, err @@ -1782,6 +1819,7 @@ func (ec *executionContext) field_Mutation_updateUser_args(ctx context.Context, args := map[string]interface{}{} var arg0 int if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("id")) arg0, err = ec.unmarshalNInt2int(ctx, tmp) if err != nil { return nil, err @@ -1790,6 +1828,7 @@ func (ec *executionContext) field_Mutation_updateUser_args(ctx context.Context, args["id"] = arg0 var arg1 *string if tmp, ok := rawArgs["username"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("username")) arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) if err != nil { return nil, err @@ -1798,6 +1837,7 @@ func (ec *executionContext) field_Mutation_updateUser_args(ctx context.Context, args["username"] = arg1 var arg2 *string if tmp, ok := rawArgs["rootPath"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("rootPath")) arg2, err = ec.unmarshalOString2ᚖstring(ctx, tmp) if err != nil { return nil, err @@ -1806,6 +1846,7 @@ func (ec *executionContext) field_Mutation_updateUser_args(ctx context.Context, args["rootPath"] = arg2 var arg3 *string if tmp, ok := rawArgs["password"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("password")) arg3, err = ec.unmarshalOString2ᚖstring(ctx, tmp) if err != nil { return nil, err @@ -1814,6 +1855,7 @@ func (ec *executionContext) field_Mutation_updateUser_args(ctx context.Context, args["password"] = arg3 var arg4 *bool if tmp, ok := rawArgs["admin"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("admin")) arg4, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp) if err != nil { return nil, err @@ -1828,6 +1870,7 @@ func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("name")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1842,6 +1885,7 @@ func (ec *executionContext) field_Query_album_args(ctx context.Context, rawArgs args := map[string]interface{}{} var arg0 int if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("id")) arg0, err = ec.unmarshalNInt2int(ctx, tmp) if err != nil { return nil, err @@ -1856,6 +1900,7 @@ func (ec *executionContext) field_Query_media_args(ctx context.Context, rawArgs args := map[string]interface{}{} var arg0 int if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("id")) arg0, err = ec.unmarshalNInt2int(ctx, tmp) if err != nil { return nil, err @@ -1870,6 +1915,7 @@ func (ec *executionContext) field_Query_myAlbums_args(ctx context.Context, rawAr args := map[string]interface{}{} var arg0 *models.Filter if tmp, ok := rawArgs["filter"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("filter")) arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp) if err != nil { return nil, err @@ -1878,6 +1924,7 @@ func (ec *executionContext) field_Query_myAlbums_args(ctx context.Context, rawAr args["filter"] = arg0 var arg1 *bool if tmp, ok := rawArgs["onlyRoot"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("onlyRoot")) arg1, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp) if err != nil { return nil, err @@ -1886,6 +1933,7 @@ func (ec *executionContext) field_Query_myAlbums_args(ctx context.Context, rawAr args["onlyRoot"] = arg1 var arg2 *bool if tmp, ok := rawArgs["showEmpty"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("showEmpty")) arg2, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp) if err != nil { return nil, err @@ -1900,6 +1948,7 @@ func (ec *executionContext) field_Query_myMedia_args(ctx context.Context, rawArg args := map[string]interface{}{} var arg0 *models.Filter if tmp, ok := rawArgs["filter"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("filter")) arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp) if err != nil { return nil, err @@ -1914,6 +1963,7 @@ func (ec *executionContext) field_Query_search_args(ctx context.Context, rawArgs args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["query"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("query")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1922,6 +1972,7 @@ func (ec *executionContext) field_Query_search_args(ctx context.Context, rawArgs args["query"] = arg0 var arg1 *int if tmp, ok := rawArgs["limitMedia"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("limitMedia")) arg1, err = ec.unmarshalOInt2ᚖint(ctx, tmp) if err != nil { return nil, err @@ -1930,6 +1981,7 @@ func (ec *executionContext) field_Query_search_args(ctx context.Context, rawArgs args["limitMedia"] = arg1 var arg2 *int if tmp, ok := rawArgs["limitAlbums"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("limitAlbums")) arg2, err = ec.unmarshalOInt2ᚖint(ctx, tmp) if err != nil { return nil, err @@ -1944,6 +1996,7 @@ func (ec *executionContext) field_Query_shareTokenValidatePassword_args(ctx cont args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["token"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("token")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1952,6 +2005,7 @@ func (ec *executionContext) field_Query_shareTokenValidatePassword_args(ctx cont args["token"] = arg0 var arg1 *string if tmp, ok := rawArgs["password"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("password")) arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) if err != nil { return nil, err @@ -1966,6 +2020,7 @@ func (ec *executionContext) field_Query_shareToken_args(ctx context.Context, raw args := map[string]interface{}{} var arg0 string if tmp, ok := rawArgs["token"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("token")) arg0, err = ec.unmarshalNString2string(ctx, tmp) if err != nil { return nil, err @@ -1974,6 +2029,7 @@ func (ec *executionContext) field_Query_shareToken_args(ctx context.Context, raw args["token"] = arg0 var arg1 *string if tmp, ok := rawArgs["password"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("password")) arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) if err != nil { return nil, err @@ -1988,6 +2044,7 @@ func (ec *executionContext) field_Query_user_args(ctx context.Context, rawArgs m args := map[string]interface{}{} var arg0 *models.Filter if tmp, ok := rawArgs["filter"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("filter")) arg0, err = ec.unmarshalOFilter2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, tmp) if err != nil { return nil, err @@ -2002,6 +2059,7 @@ func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, ra args := map[string]interface{}{} var arg0 bool if tmp, ok := rawArgs["includeDeprecated"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("includeDeprecated")) arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) if err != nil { return nil, err @@ -2016,6 +2074,7 @@ func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArg args := map[string]interface{}{} var arg0 bool if tmp, ok := rawArgs["includeDeprecated"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("includeDeprecated")) arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) if err != nil { return nil, err @@ -5314,6 +5373,60 @@ func (ec *executionContext) _SiteInfo_initialSetup(ctx context.Context, field gr return ec.marshalNBoolean2bool(ctx, field.Selections, res) } +func (ec *executionContext) _SiteInfo_periodicScanInterval(ctx context.Context, field graphql.CollectedField, obj *models.SiteInfo) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "SiteInfo", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + 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 obj.PeriodicScanInterval, nil + } + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.IsAdmin == nil { + return nil, errors.New("directive isAdmin is not implemented") + } + return ec.directives.IsAdmin(ctx, obj, directive0) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, 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) _Subscription_notification(ctx context.Context, field graphql.CollectedField) (ret func() graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -6902,24 +7015,32 @@ func (ec *executionContext) unmarshalInputFilter(ctx context.Context, obj interf switch k { case "order_by": var err error + + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("order_by")) it.OrderBy, err = ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } case "order_direction": var err error + + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("order_direction")) it.OrderDirection, err = ec.unmarshalOOrderDirection2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx, v) if err != nil { return it, err } case "limit": var err error + + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("limit")) it.Limit, err = ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } case "offset": var err error + + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("offset")) it.Offset, err = ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err @@ -7834,6 +7955,11 @@ func (ec *executionContext) _SiteInfo(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { invalids++ } + case "periodicScanInterval": + out.Values[i] = ec._SiteInfo_periodicScanInterval(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -8275,7 +8401,8 @@ func (ec *executionContext) marshalNAuthorizeResult2ᚖgithubᚗcomᚋviktorstra } func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { - return graphql.UnmarshalBoolean(v) + res, err := graphql.UnmarshalBoolean(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { @@ -8289,7 +8416,8 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se } func (ec *executionContext) unmarshalNFloat2float64(ctx context.Context, v interface{}) (float64, error) { - return graphql.UnmarshalFloat(v) + res, err := graphql.UnmarshalFloat(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalNFloat2float64(ctx context.Context, sel ast.SelectionSet, v float64) graphql.Marshaler { @@ -8303,7 +8431,8 @@ func (ec *executionContext) marshalNFloat2float64(ctx context.Context, sel ast.S } func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) { - return graphql.UnmarshalInt(v) + res, err := graphql.UnmarshalInt(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler { @@ -8367,10 +8496,6 @@ func (ec *executionContext) marshalNMedia2ᚖgithubᚗcomᚋviktorstrateᚋphoto return ec._Media(ctx, sel, v) } -func (ec *executionContext) marshalNMediaDownload2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaDownload(ctx context.Context, sel ast.SelectionSet, v models.MediaDownload) graphql.Marshaler { - return ec._MediaDownload(ctx, sel, &v) -} - func (ec *executionContext) marshalNMediaDownload2ᚕᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaDownloadᚄ(ctx context.Context, sel ast.SelectionSet, v []*models.MediaDownload) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup @@ -8420,7 +8545,8 @@ func (ec *executionContext) marshalNMediaDownload2ᚖgithubᚗcomᚋviktorstrate func (ec *executionContext) unmarshalNMediaType2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaType(ctx context.Context, v interface{}) (models.MediaType, error) { var res models.MediaType - return res, res.UnmarshalGQL(v) + err := res.UnmarshalGQL(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalNMediaType2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaType(ctx context.Context, sel ast.SelectionSet, v models.MediaType) graphql.Marshaler { @@ -8457,7 +8583,8 @@ func (ec *executionContext) marshalNNotification2ᚖgithubᚗcomᚋviktorstrate func (ec *executionContext) unmarshalNNotificationType2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐNotificationType(ctx context.Context, v interface{}) (models.NotificationType, error) { var res models.NotificationType - return res, res.UnmarshalGQL(v) + err := res.UnmarshalGQL(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalNNotificationType2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐNotificationType(ctx context.Context, sel ast.SelectionSet, v models.NotificationType) graphql.Marshaler { @@ -8558,7 +8685,8 @@ func (ec *executionContext) marshalNSiteInfo2ᚖgithubᚗcomᚋviktorstrateᚋph } func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { - return graphql.UnmarshalString(v) + res, err := graphql.UnmarshalString(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { @@ -8664,7 +8792,8 @@ func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgq } func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) { - return graphql.UnmarshalString(v) + res, err := graphql.UnmarshalString(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { @@ -8689,9 +8818,10 @@ func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx conte var err error res := make([]string, len(vSlice)) for i := range vSlice { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithIndex(i)) res[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i]) if err != nil { - return nil, err + return nil, graphql.WrapErrorWithInputPath(ctx, err) } } return res, nil @@ -8835,7 +8965,8 @@ func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgen } func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) { - return graphql.UnmarshalString(v) + res, err := graphql.UnmarshalString(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { @@ -8848,10 +8979,6 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a return res } -func (ec *executionContext) marshalOAlbum2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx context.Context, sel ast.SelectionSet, v models.Album) graphql.Marshaler { - return ec._Album(ctx, sel, &v) -} - func (ec *executionContext) marshalOAlbum2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx context.Context, sel ast.SelectionSet, v *models.Album) graphql.Marshaler { if v == nil { return graphql.Null @@ -8859,10 +8986,6 @@ func (ec *executionContext) marshalOAlbum2ᚖgithubᚗcomᚋviktorstrateᚋphoto return ec._Album(ctx, sel, v) } -func (ec *executionContext) marshalOAuthorizeResult2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAuthorizeResult(ctx context.Context, sel ast.SelectionSet, v models.AuthorizeResult) graphql.Marshaler { - return ec._AuthorizeResult(ctx, sel, &v) -} - func (ec *executionContext) marshalOAuthorizeResult2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAuthorizeResult(ctx context.Context, sel ast.SelectionSet, v *models.AuthorizeResult) graphql.Marshaler { if v == nil { return graphql.Null @@ -8871,7 +8994,8 @@ func (ec *executionContext) marshalOAuthorizeResult2ᚖgithubᚗcomᚋviktorstra } func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { - return graphql.UnmarshalBoolean(v) + res, err := graphql.UnmarshalBoolean(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { @@ -8882,77 +9006,53 @@ func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v int if v == nil { return nil, nil } - res, err := ec.unmarshalOBoolean2bool(ctx, v) - return &res, err + res, err := graphql.UnmarshalBoolean(v) + return &res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler { if v == nil { return graphql.Null } - return ec.marshalOBoolean2bool(ctx, sel, *v) -} - -func (ec *executionContext) unmarshalOFilter2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx context.Context, v interface{}) (models.Filter, error) { - return ec.unmarshalInputFilter(ctx, v) + return graphql.MarshalBoolean(*v) } func (ec *executionContext) unmarshalOFilter2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx context.Context, v interface{}) (*models.Filter, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalOFilter2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐFilter(ctx, v) - return &res, err -} - -func (ec *executionContext) unmarshalOFloat2float64(ctx context.Context, v interface{}) (float64, error) { - return graphql.UnmarshalFloat(v) -} - -func (ec *executionContext) marshalOFloat2float64(ctx context.Context, sel ast.SelectionSet, v float64) graphql.Marshaler { - return graphql.MarshalFloat(v) + res, err := ec.unmarshalInputFilter(ctx, v) + return &res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) unmarshalOFloat2ᚖfloat64(ctx context.Context, v interface{}) (*float64, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalOFloat2float64(ctx, v) - return &res, err + res, err := graphql.UnmarshalFloat(v) + return &res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalOFloat2ᚖfloat64(ctx context.Context, sel ast.SelectionSet, v *float64) graphql.Marshaler { if v == nil { return graphql.Null } - return ec.marshalOFloat2float64(ctx, sel, *v) -} - -func (ec *executionContext) unmarshalOInt2int(ctx context.Context, v interface{}) (int, error) { - return graphql.UnmarshalInt(v) -} - -func (ec *executionContext) marshalOInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler { - return graphql.MarshalInt(v) + return graphql.MarshalFloat(*v) } func (ec *executionContext) unmarshalOInt2ᚖint(ctx context.Context, v interface{}) (*int, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalOInt2int(ctx, v) - return &res, err + res, err := graphql.UnmarshalInt(v) + return &res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.SelectionSet, v *int) graphql.Marshaler { if v == nil { return graphql.Null } - return ec.marshalOInt2int(ctx, sel, *v) -} - -func (ec *executionContext) marshalOMedia2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMedia(ctx context.Context, sel ast.SelectionSet, v models.Media) graphql.Marshaler { - return ec._Media(ctx, sel, &v) + return graphql.MarshalInt(*v) } func (ec *executionContext) marshalOMedia2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMedia(ctx context.Context, sel ast.SelectionSet, v *models.Media) graphql.Marshaler { @@ -8962,10 +9062,6 @@ func (ec *executionContext) marshalOMedia2ᚖgithubᚗcomᚋviktorstrateᚋphoto return ec._Media(ctx, sel, v) } -func (ec *executionContext) marshalOMediaEXIF2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaEXIF(ctx context.Context, sel ast.SelectionSet, v models.MediaEXIF) graphql.Marshaler { - return ec._MediaEXIF(ctx, sel, &v) -} - func (ec *executionContext) marshalOMediaEXIF2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaEXIF(ctx context.Context, sel ast.SelectionSet, v *models.MediaEXIF) graphql.Marshaler { if v == nil { return graphql.Null @@ -8973,10 +9069,6 @@ func (ec *executionContext) marshalOMediaEXIF2ᚖgithubᚗcomᚋviktorstrateᚋp return ec._MediaEXIF(ctx, sel, v) } -func (ec *executionContext) marshalOMediaURL2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaURL(ctx context.Context, sel ast.SelectionSet, v models.MediaURL) graphql.Marshaler { - return ec._MediaURL(ctx, sel, &v) -} - func (ec *executionContext) marshalOMediaURL2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaURL(ctx context.Context, sel ast.SelectionSet, v *models.MediaURL) graphql.Marshaler { if v == nil { return graphql.Null @@ -8984,21 +9076,13 @@ func (ec *executionContext) marshalOMediaURL2ᚖgithubᚗcomᚋviktorstrateᚋph return ec._MediaURL(ctx, sel, v) } -func (ec *executionContext) unmarshalOOrderDirection2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx context.Context, v interface{}) (models.OrderDirection, error) { - var res models.OrderDirection - return res, res.UnmarshalGQL(v) -} - -func (ec *executionContext) marshalOOrderDirection2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx context.Context, sel ast.SelectionSet, v models.OrderDirection) graphql.Marshaler { - return v -} - func (ec *executionContext) unmarshalOOrderDirection2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx context.Context, v interface{}) (*models.OrderDirection, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalOOrderDirection2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx, v) - return &res, err + var res = new(models.OrderDirection) + err := res.UnmarshalGQL(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalOOrderDirection2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐOrderDirection(ctx context.Context, sel ast.SelectionSet, v *models.OrderDirection) graphql.Marshaler { @@ -9008,10 +9092,6 @@ func (ec *executionContext) marshalOOrderDirection2ᚖgithubᚗcomᚋviktorstrat return v } -func (ec *executionContext) marshalOShareToken2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx context.Context, sel ast.SelectionSet, v models.ShareToken) graphql.Marshaler { - return ec._ShareToken(ctx, sel, &v) -} - func (ec *executionContext) marshalOShareToken2ᚕᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx context.Context, sel ast.SelectionSet, v []*models.ShareToken) graphql.Marshaler { if v == nil { return graphql.Null @@ -9060,7 +9140,8 @@ func (ec *executionContext) marshalOShareToken2ᚖgithubᚗcomᚋviktorstrateᚋ } func (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) { - return graphql.UnmarshalString(v) + res, err := graphql.UnmarshalString(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalOString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { @@ -9071,42 +9152,30 @@ func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v in if v == nil { return nil, nil } - res, err := ec.unmarshalOString2string(ctx, v) - return &res, err + res, err := graphql.UnmarshalString(v) + return &res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { if v == nil { return graphql.Null } - return ec.marshalOString2string(ctx, sel, *v) -} - -func (ec *executionContext) unmarshalOTime2timeᚐTime(ctx context.Context, v interface{}) (time.Time, error) { - return graphql.UnmarshalTime(v) -} - -func (ec *executionContext) marshalOTime2timeᚐTime(ctx context.Context, sel ast.SelectionSet, v time.Time) graphql.Marshaler { - return graphql.MarshalTime(v) + return graphql.MarshalString(*v) } func (ec *executionContext) unmarshalOTime2ᚖtimeᚐTime(ctx context.Context, v interface{}) (*time.Time, error) { if v == nil { return nil, nil } - res, err := ec.unmarshalOTime2timeᚐTime(ctx, v) - return &res, err + res, err := graphql.UnmarshalTime(v) + return &res, graphql.WrapErrorWithInputPath(ctx, err) } func (ec *executionContext) marshalOTime2ᚖtimeᚐTime(ctx context.Context, sel ast.SelectionSet, v *time.Time) graphql.Marshaler { if v == nil { return graphql.Null } - return ec.marshalOTime2timeᚐTime(ctx, sel, *v) -} - -func (ec *executionContext) marshalOUser2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx context.Context, sel ast.SelectionSet, v models.User) graphql.Marshaler { - return ec._User(ctx, sel, &v) + return graphql.MarshalTime(*v) } func (ec *executionContext) marshalOUser2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx context.Context, sel ast.SelectionSet, v *models.User) graphql.Marshaler { @@ -9116,10 +9185,6 @@ func (ec *executionContext) marshalOUser2ᚖgithubᚗcomᚋviktorstrateᚋphotov return ec._User(ctx, sel, v) } -func (ec *executionContext) marshalOVideoMetadata2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐVideoMetadata(ctx context.Context, sel ast.SelectionSet, v models.VideoMetadata) graphql.Marshaler { - return ec._VideoMetadata(ctx, sel, &v) -} - func (ec *executionContext) marshalOVideoMetadata2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐVideoMetadata(ctx context.Context, sel ast.SelectionSet, v *models.VideoMetadata) graphql.Marshaler { if v == nil { return graphql.Null @@ -9247,10 +9312,6 @@ func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋg return ret } -func (ec *executionContext) marshalO__Schema2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v introspection.Schema) graphql.Marshaler { - return ec.___Schema(ctx, sel, &v) -} - func (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v *introspection.Schema) graphql.Marshaler { if v == nil { return graphql.Null @@ -9258,10 +9319,6 @@ func (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlge return ec.___Schema(ctx, sel, v) } -func (ec *executionContext) marshalO__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v introspection.Type) graphql.Marshaler { - return ec.___Type(ctx, sel, &v) -} - func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/api/graphql/models/generated.go b/api/graphql/models/generated.go index 6db2264..ca31bbb 100644 --- a/api/graphql/models/generated.go +++ b/api/graphql/models/generated.go @@ -51,9 +51,11 @@ type SearchResult struct { Media []*Media `json:"media"` } -// General public information about the site +// General information about the site type SiteInfo struct { InitialSetup bool `json:"initialSetup"` + // How often automatic scans should be initiated in seconds + PeriodicScanInterval int `json:"periodicScanInterval"` } type MediaType string diff --git a/api/graphql/models/site_info.go b/api/graphql/models/site_info.go index 8668339..ea362bd 100644 --- a/api/graphql/models/site_info.go +++ b/api/graphql/models/site_info.go @@ -4,6 +4,14 @@ import ( "database/sql" ) +func InitializeSiteInfoRow(db *sql.DB) error { + _, err := db.Exec("INSERT INTO site_info (initial_setup) VALUES (true)") + if err != nil { + return err + } + return nil +} + func GetSiteInfo(db *sql.DB) (*SiteInfo, error) { rows, err := db.Query("SELECT * FROM site_info") defer rows.Close() @@ -12,21 +20,22 @@ func GetSiteInfo(db *sql.DB) (*SiteInfo, error) { } var initialSetup bool + var periodicScanInterval int = 0 if !rows.Next() { // Entry does not exist - _, err := db.Exec("INSERT INTO site_info (initial_setup) VALUES (true)") - if err != nil { + if err := InitializeSiteInfoRow(db); err != nil { return nil, err } initialSetup = true } else { - if err := rows.Scan(&initialSetup); err != nil { + if err := rows.Scan(&initialSetup, &periodicScanInterval); err != nil { return nil, err } } return &SiteInfo{ - InitialSetup: initialSetup, + InitialSetup: initialSetup, + PeriodicScanInterval: periodicScanInterval, }, nil } diff --git a/api/graphql/schema.graphql b/api/graphql/schema.graphql index 2a781bf..b343efa 100644 --- a/api/graphql/schema.graphql +++ b/api/graphql/schema.graphql @@ -147,9 +147,11 @@ type ShareToken { media: Media } -"General public information about the site" +"General information about the site" type SiteInfo { initialSetup: Boolean! + "How often automatic scans should be initiated in seconds" + periodicScanInterval: Int! @isAdmin } type User { From 28749c44ac1048192fa1303543bc75e8b7e7c95f Mon Sep 17 00:00:00 2001 From: viktorstrate Date: Sun, 20 Sep 2020 22:49:50 +0200 Subject: [PATCH 2/5] Start on UI for periodic scanner settings --- ui/src/App.js | 1 + ui/src/Layout.js | 2 +- ui/src/Pages/LoginPage/LoginPage.js | 10 +- ui/src/Pages/SettingsPage/ScannerSection.js | 204 ++++++++++++++++++++ ui/src/Pages/SettingsPage/SettingsPage.js | 49 ++--- ui/src/Pages/SettingsPage/UsersTable.js | 111 +++++------ 6 files changed, 284 insertions(+), 93 deletions(-) create mode 100644 ui/src/Pages/SettingsPage/ScannerSection.js diff --git a/ui/src/App.js b/ui/src/App.js index f834678..f147f7c 100644 --- a/ui/src/App.js +++ b/ui/src/App.js @@ -26,6 +26,7 @@ import 'semantic-ui-css/components/site.css' import 'semantic-ui-css/components/transition.css' import 'semantic-ui-css/components/menu.css' import 'semantic-ui-css/components/dimmer.css' +import 'semantic-ui-css/components/label.css' class App extends Component { render() { diff --git a/ui/src/Layout.js b/ui/src/Layout.js index 37f8d17..f33f17a 100644 --- a/ui/src/Layout.js +++ b/ui/src/Layout.js @@ -45,7 +45,7 @@ const SideMenu = styled.div` ` const Content = styled.div` - margin-top: 60px; + margin-top: 70px; padding: 10px 12px 0; width: 100%; overflow-y: scroll; diff --git a/ui/src/Pages/LoginPage/LoginPage.js b/ui/src/Pages/LoginPage/LoginPage.js index f7abbf2..00d5f8d 100644 --- a/ui/src/Pages/LoginPage/LoginPage.js +++ b/ui/src/Pages/LoginPage/LoginPage.js @@ -112,13 +112,17 @@ class LoginPage extends Component { loading={loading || (data && data.authorizeUser.success)} > - - this.handleChange(e, 'username')} /> + + this.handleChange(e, 'username')} + /> - + this.handleChange(e, 'password')} /> diff --git a/ui/src/Pages/SettingsPage/ScannerSection.js b/ui/src/Pages/SettingsPage/ScannerSection.js new file mode 100644 index 0000000..6b32bc0 --- /dev/null +++ b/ui/src/Pages/SettingsPage/ScannerSection.js @@ -0,0 +1,204 @@ +import React, { useState } from 'react' + +import { Button, Checkbox, Dropdown, Icon, Input } from 'semantic-ui-react' +import { useMutation, useQuery } from 'react-apollo' +import gql from 'graphql-tag' +import styled from 'styled-components' +import { SectionTitle } from './SettingsPage' + +const SCAN_MUTATION = gql` + mutation scanAllMutation { + scanAll { + success + message + } + } +` + +const SCAN_INTERVAL_QUERY = gql` + query scanIntervalQuery { + siteInfo { + periodicScanInterval + } + } +` + +const timeUnits = [ + { + value: 'second', + multiplier: 1, + }, + { + value: 'minute', + multiplier: 60, + }, + { + value: 'hour', + multiplier: 60 * 60, + }, + { + value: 'day', + multiplier: 60 * 60 * 24, + }, + { + value: 'month', + multiplier: 60 * 60 * 24 * 30, + }, +] + +const convertToAppropriateUnit = ({ value, unit }) => { + if (value == 0) { + return { + unit: 'second', + value: 0, + } + } + + const seconds = value * timeUnits.find(x => x.value == unit).multiplier + + let resultingUnit = timeUnits.first + for (const unit of timeUnits) { + if (seconds / unit.multiplier >= 1) { + resultingUnit = unit + } else { + break + } + } + + return { + unit: resultingUnit.value, + value: seconds / resultingUnit.multiplier, + } +} + +const InputLabelTitle = styled.p` + font-size: 1.1em; + font-weight: 600; + margin: 1em 0 0 !important; +` + +const InputLabelDescription = styled.p` + font-size: 0.9em; + margin: 0 0 0.5em !important; +` + +const ScannerSection = () => { + const [startScanner, { called }] = useMutation(SCAN_MUTATION) + + const [enablePeriodicScanner, setEnablePeriodicScanner] = useState(false) + const [scanInterval, setScanInterval] = useState({ + value: 4, + unit: 'minute', + }) + + const scanIntervalQuery = useQuery(SCAN_INTERVAL_QUERY, { + onCompleted(data) { + const queryScanInterval = data.siteInfo.periodicScanInterval + + if (queryScanInterval == 0) { + setScanInterval({ + unit: 'second', + value: '', + }) + } else { + setScanInterval( + convertToAppropriateUnit({ + unit: 'second', + value: queryScanInterval, + }) + ) + } + + setEnablePeriodicScanner(queryScanInterval > 0) + }, + }) + + const scanIntervalUnits = [ + { + key: 'second', + text: 'Seconds', + value: 'second', + }, + { + key: 'minute', + text: 'Minutes', + value: 'minute', + }, + { + key: 'hour', + text: 'Hours', + value: 'hour', + }, + { + key: 'day', + text: 'Days', + value: 'day', + }, + { + key: 'month', + text: 'Months', + value: 'month', + }, + ] + + return ( +
+ Scanner + + +

Periodic scanner

+ +
+ setEnablePeriodicScanner(checked)} + /> +
+ + {enablePeriodicScanner && ( + <> + + + setScanInterval(x => ({ + ...x, + unit: value, + })) + } + value={scanInterval.unit} + options={scanIntervalUnits} + /> + } + loading={scanIntervalQuery.loading} + labelPosition="right" + style={{ maxWidth: 300 }} + id="periodic_scan_field" + value={scanInterval.value} + onChange={e => setScanInterval(e.target.value)} + /> + + )} +
+ ) +} + +export default ScannerSection diff --git a/ui/src/Pages/SettingsPage/SettingsPage.js b/ui/src/Pages/SettingsPage/SettingsPage.js index 340d3a4..11b9394 100644 --- a/ui/src/Pages/SettingsPage/SettingsPage.js +++ b/ui/src/Pages/SettingsPage/SettingsPage.js @@ -1,43 +1,24 @@ import React from 'react' +import styled from 'styled-components' + import Layout from '../../Layout' -import { Button, Icon } from 'semantic-ui-react' -import { Mutation } from 'react-apollo' -import gql from 'graphql-tag' +import ScannerSection from './ScannerSection' import UsersTable from './UsersTable' -const scanMutation = gql` - mutation scanAllMutation { - scanAll { - success - message - } - } +export const SectionTitle = styled.h2` + margin-top: ${({ nospace }) => (nospace ? '0' : '1.4em')} !important; + padding-bottom: 0.3em; + border-bottom: 1px solid #ddd; ` -const SettingsPage = () => ( - -

Settings

- - {(scan, { data, called }) => ( - <> -

Scanner

- - - )} -
- -
-) +const SettingsPage = () => { + return ( + + + + + ) +} export default SettingsPage diff --git a/ui/src/Pages/SettingsPage/UsersTable.js b/ui/src/Pages/SettingsPage/UsersTable.js index f509f66..b18ff69 100644 --- a/ui/src/Pages/SettingsPage/UsersTable.js +++ b/ui/src/Pages/SettingsPage/UsersTable.js @@ -1,12 +1,13 @@ import React, { useState } from 'react' import { Table, Loader, Button, Icon } from 'semantic-ui-react' -import { Query } from 'react-apollo' +import { useQuery } from 'react-apollo' import gql from 'graphql-tag' import UserRow from './UserRow' import AddUserRow from './AddUserRow' +import { SectionTitle } from './SettingsPage' -const usersQuery = gql` +const USERS_QUERY = gql` query settingsUsersQuery { user { id @@ -20,62 +21,62 @@ const usersQuery = gql` const UsersTable = () => { const [showAddUser, setShowAddUser] = useState(false) + const { loading, error, data, refetch } = useQuery(USERS_QUERY) + + if (error) { + return `Users table error: ${error.message}` + } + + let userRows = [] + if (data && data.user) { + userRows = data.user.map(user => ( + + )) + } + return ( - - {({ loading, error, data, refetch }) => { - let userRows = [] - if (data && data.user) { - userRows = data.user.map(user => ( - - )) - } +
+ Users + + + + + Username + Photo path + Admin + Action + + - return ( -
-

Users

- -
- - - Username - Photo path - Admin - Action - - + + {userRows} + { + setShowAddUser(false) + refetch() + }} + /> + - - {userRows} - { - setShowAddUser(false) - refetch() - }} - /> - - - - - - - - - -
-
- ) - }} -
+ + + + + + + + + ) } From 167ff4b8c4da08cdb725692c653e391e92585264 Mon Sep 17 00:00:00 2001 From: viktorstrate Date: Mon, 21 Sep 2020 11:50:39 +0200 Subject: [PATCH 3/5] Update periodic scanner value from UI --- api/graphql/generated.go | 107 +++++++++++++++++--- api/graphql/resolvers/scanner.go | 20 ++++ api/graphql/schema.graphql | 6 ++ ui/src/Pages/SettingsPage/ScannerSection.js | 76 ++++++++++++-- 4 files changed, 187 insertions(+), 22 deletions(-) diff --git a/api/graphql/generated.go b/api/graphql/generated.go index e4cb634..902ea53 100644 --- a/api/graphql/generated.go +++ b/api/graphql/generated.go @@ -114,19 +114,20 @@ type ComplexityRoot struct { } Mutation struct { - AuthorizeUser func(childComplexity int, username string, password string) int - CreateUser func(childComplexity int, username string, rootPath string, password *string, admin bool) int - DeleteShareToken func(childComplexity int, token string) int - DeleteUser func(childComplexity int, id int) int - FavoriteMedia func(childComplexity int, mediaID int, favorite bool) int - InitialSetupWizard func(childComplexity int, username string, password string, rootPath string) int - ProtectShareToken func(childComplexity int, token string, password *string) int - RegisterUser func(childComplexity int, username string, password string, rootPath string) int - ScanAll func(childComplexity int) int - ScanUser func(childComplexity int, userID int) int - ShareAlbum func(childComplexity int, albumID int, expire *time.Time, password *string) int - ShareMedia func(childComplexity int, mediaID int, expire *time.Time, password *string) int - UpdateUser func(childComplexity int, id int, username *string, rootPath *string, password *string, admin *bool) int + AuthorizeUser func(childComplexity int, username string, password string) int + CreateUser func(childComplexity int, username string, rootPath string, password *string, admin bool) int + DeleteShareToken func(childComplexity int, token string) int + DeleteUser func(childComplexity int, id int) int + FavoriteMedia func(childComplexity int, mediaID int, favorite bool) int + InitialSetupWizard func(childComplexity int, username string, password string, rootPath string) int + ProtectShareToken func(childComplexity int, token string, password *string) int + RegisterUser func(childComplexity int, username string, password string, rootPath string) int + ScanAll func(childComplexity int) int + ScanUser func(childComplexity int, userID int) int + SetPeriodicScanInterval func(childComplexity int, interval int) int + ShareAlbum func(childComplexity int, albumID int, expire *time.Time, password *string) int + ShareMedia func(childComplexity int, mediaID int, expire *time.Time, password *string) int + UpdateUser func(childComplexity int, id int, username *string, rootPath *string, password *string, admin *bool) int } Notification struct { @@ -241,6 +242,7 @@ type MutationResolver interface { UpdateUser(ctx context.Context, id int, username *string, rootPath *string, password *string, admin *bool) (*models.User, error) CreateUser(ctx context.Context, username string, rootPath string, password *string, admin bool) (*models.User, error) DeleteUser(ctx context.Context, id int) (*models.User, error) + SetPeriodicScanInterval(ctx context.Context, interval int) (int, error) } type QueryResolver interface { SiteInfo(ctx context.Context) (*models.SiteInfo, error) @@ -713,6 +715,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.ScanUser(childComplexity, args["userId"].(int)), true + case "Mutation.setPeriodicScanInterval": + if e.complexity.Mutation.SetPeriodicScanInterval == nil { + break + } + + args, err := ec.field_Mutation_setPeriodicScanInterval_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.SetPeriodicScanInterval(childComplexity, args["interval"].(int)), true + case "Mutation.shareAlbum": if e.complexity.Mutation.ShareAlbum == nil { break @@ -1307,6 +1321,12 @@ type Mutation { admin: Boolean! ): User @isAdmin deleteUser(id: Int!): User @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! } type Subscription { @@ -1748,6 +1768,21 @@ func (ec *executionContext) field_Mutation_scanUser_args(ctx context.Context, ra return args, nil } +func (ec *executionContext) field_Mutation_setPeriodicScanInterval_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 int + if tmp, ok := rawArgs["interval"]; ok { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("interval")) + arg0, err = ec.unmarshalNInt2int(ctx, tmp) + if err != nil { + return nil, err + } + } + args["interval"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation_shareAlbum_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -4127,6 +4162,47 @@ func (ec *executionContext) _Mutation_deleteUser(ctx context.Context, field grap return ec.marshalOUser2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res) } +func (ec *executionContext) _Mutation_setPeriodicScanInterval(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_setPeriodicScanInterval_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().SetPeriodicScanInterval(rctx, args["interval"].(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.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + func (ec *executionContext) _Notification_key(ctx context.Context, field graphql.CollectedField, obj *models.Notification) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -7545,6 +7621,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) out.Values[i] = ec._Mutation_createUser(ctx, field) case "deleteUser": out.Values[i] = ec._Mutation_deleteUser(ctx, field) + case "setPeriodicScanInterval": + out.Values[i] = ec._Mutation_setPeriodicScanInterval(ctx, field) + if out.Values[i] == graphql.Null { + invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } diff --git a/api/graphql/resolvers/scanner.go b/api/graphql/resolvers/scanner.go index e57105e..ee905ec 100644 --- a/api/graphql/resolvers/scanner.go +++ b/api/graphql/resolvers/scanner.go @@ -39,3 +39,23 @@ func (r *mutationResolver) ScanUser(ctx context.Context, userID int) (*models.Sc Message: &startMessage, }, nil } + +func (r *mutationResolver) SetPeriodicScanInterval(ctx context.Context, interval int) (int, error) { + if interval < 0 { + return 0, errors.New("interval must be 0 or above") + } + + _, err := r.Database.Exec("UPDATE site_info SET periodic_scan_interval = ?", interval) + if err != nil { + return 0, err + } + + var dbInterval int + + row := r.Database.QueryRow("SELECT periodic_scan_interval FROM site_info") + if err = row.Scan(&dbInterval); err != nil { + return 0, err + } + + return dbInterval, nil +} diff --git a/api/graphql/schema.graphql b/api/graphql/schema.graphql index b343efa..d3932e6 100644 --- a/api/graphql/schema.graphql +++ b/api/graphql/schema.graphql @@ -92,6 +92,12 @@ type Mutation { admin: Boolean! ): User @isAdmin deleteUser(id: Int!): User @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! } type Subscription { diff --git a/ui/src/Pages/SettingsPage/ScannerSection.js b/ui/src/Pages/SettingsPage/ScannerSection.js index 6b32bc0..834b731 100644 --- a/ui/src/Pages/SettingsPage/ScannerSection.js +++ b/ui/src/Pages/SettingsPage/ScannerSection.js @@ -1,6 +1,13 @@ import React, { useState } from 'react' -import { Button, Checkbox, Dropdown, Icon, Input } from 'semantic-ui-react' +import { + Button, + Checkbox, + Dropdown, + Icon, + Input, + Loader, +} from 'semantic-ui-react' import { useMutation, useQuery } from 'react-apollo' import gql from 'graphql-tag' import styled from 'styled-components' @@ -23,6 +30,12 @@ const SCAN_INTERVAL_QUERY = gql` } ` +const SCAN_INTERVAL_MUTATION = gql` + mutation changeScanIntervalMutation($interval: Int!) { + setPeriodicScanInterval(interval: $interval) + } +` + const timeUnits = [ { value: 'second', @@ -46,6 +59,10 @@ const timeUnits = [ }, ] +const convertToSeconds = ({ value, unit }) => { + return parseInt(value * timeUnits.find(x => x.value == unit).multiplier) +} + const convertToAppropriateUnit = ({ value, unit }) => { if (value == 0) { return { @@ -54,7 +71,7 @@ const convertToAppropriateUnit = ({ value, unit }) => { } } - const seconds = value * timeUnits.find(x => x.value == unit).multiplier + const seconds = convertToSeconds({ value, unit }) let resultingUnit = timeUnits.first for (const unit of timeUnits) { @@ -113,6 +130,29 @@ const ScannerSection = () => { }, }) + const [ + setScanIntervalMutation, + { loading: scanIntervalMutationLoading }, + ] = useMutation(SCAN_INTERVAL_MUTATION) + + const onScanIntervalCheckboxChange = checked => { + setEnablePeriodicScanner(checked) + + setScanIntervalMutation({ + variables: { + interval: checked ? convertToSeconds(scanInterval) : 0, + }, + }) + } + + const onScanIntervalUpdate = scanInterval => { + setScanIntervalMutation({ + variables: { + interval: convertToSeconds(scanInterval), + }, + }) + } + const scanIntervalUnits = [ { key: 'second', @@ -163,7 +203,7 @@ const ScannerSection = () => { label="Enable periodic scanner" disabled={scanIntervalQuery.loading} checked={enablePeriodicScanner} - onChange={(_, { checked }) => setEnablePeriodicScanner(checked)} + onChange={(_, { checked }) => onScanIntervalCheckboxChange(checked)} /> @@ -178,25 +218,43 @@ const ScannerSection = () => { - setScanInterval(x => ({ - ...x, + onChange={(_, { value }) => { + const newScanInterval = { + ...scanInterval, unit: value, - })) - } + } + + setScanInterval(newScanInterval) + onScanIntervalUpdate(newScanInterval) + }} value={scanInterval.unit} options={scanIntervalUnits} /> } + onBlur={() => onScanIntervalUpdate(scanInterval)} + onKeyDown={({ key }) => + key == 'Enter' && onScanIntervalUpdate(scanInterval) + } loading={scanIntervalQuery.loading} labelPosition="right" style={{ maxWidth: 300 }} id="periodic_scan_field" value={scanInterval.value} - onChange={e => setScanInterval(e.target.value)} + onChange={(_, { value }) => { + setScanInterval(x => ({ + ...x, + value, + })) + }} /> )} + ) } From 05380354e3d01599de2f77e1c78156a5f2ebaa7f Mon Sep 17 00:00:00 2001 From: viktorstrate Date: Mon, 21 Sep 2020 12:34:56 +0200 Subject: [PATCH 4/5] Setup periodic scan background runner --- api/graphql/resolvers/scanner.go | 3 + api/scanner/periodic_scanner.go | 90 +++++++++++++++++++++ api/server.go | 1 + ui/src/Pages/SettingsPage/ScannerSection.js | 5 +- 4 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 api/scanner/periodic_scanner.go diff --git a/api/graphql/resolvers/scanner.go b/api/graphql/resolvers/scanner.go index ee905ec..4d8bc3d 100644 --- a/api/graphql/resolvers/scanner.go +++ b/api/graphql/resolvers/scanner.go @@ -2,6 +2,7 @@ package resolvers import ( "context" + "time" "github.com/pkg/errors" "github.com/viktorstrate/photoview/api/graphql/models" @@ -57,5 +58,7 @@ func (r *mutationResolver) SetPeriodicScanInterval(ctx context.Context, interval return 0, err } + scanner.ChangePeriodicScanInterval(time.Duration(dbInterval) * time.Second) + return dbInterval, nil } diff --git a/api/scanner/periodic_scanner.go b/api/scanner/periodic_scanner.go new file mode 100644 index 0000000..671739c --- /dev/null +++ b/api/scanner/periodic_scanner.go @@ -0,0 +1,90 @@ +package scanner + +import ( + "database/sql" + "log" + "sync" + "time" +) + +type periodicScanner struct { + ticker *time.Ticker + ticker_changed chan bool + mutex *sync.Mutex + db *sql.DB +} + +var mainPeriodicScanner *periodicScanner = nil + +func getPeriodicScanInterval(db *sql.DB) (time.Duration, error) { + row := db.QueryRow("SELECT periodic_scan_interval FROM site_info") + var intervalSeconds int + + if err := row.Scan(&intervalSeconds); err != nil { + return 0, err + } + + return time.Duration(intervalSeconds) * time.Second, nil +} + +func InitializePeriodicScanner(db *sql.DB) error { + if mainPeriodicScanner != nil { + panic("periodic scanner has already been initialized") + } + + scanInterval, err := getPeriodicScanInterval(db) + if err != nil { + return err + } + + mainPeriodicScanner = &periodicScanner{ + db: db, + ticker_changed: make(chan bool), + mutex: &sync.Mutex{}, + } + + go scanIntervalRunner() + + ChangePeriodicScanInterval(scanInterval) + return nil +} + +func ChangePeriodicScanInterval(duration time.Duration) { + var new_ticker *time.Ticker = nil + if duration > 0 { + new_ticker = time.NewTicker(duration) + log.Printf("Periodic scan interval changed: %s", duration.String()) + } else { + log.Print("Periodic scan interval changed: disabled") + } + + { + mainPeriodicScanner.mutex.Lock() + defer mainPeriodicScanner.mutex.Unlock() + + if mainPeriodicScanner.ticker != nil { + mainPeriodicScanner.ticker.Stop() + } + + mainPeriodicScanner.ticker = new_ticker + mainPeriodicScanner.ticker_changed <- true + } +} + +func scanIntervalRunner() { + for { + log.Print("Scan interval runner: Waiting for signal") + if mainPeriodicScanner.ticker != nil { + select { + case <-mainPeriodicScanner.ticker_changed: + log.Print("Scan interval runner: New ticker detected") + case <-mainPeriodicScanner.ticker.C: + log.Print("Scan interval runner: Starting periodic scan") + AddAllToQueue() + } + } else { + <-mainPeriodicScanner.ticker_changed + log.Print("Scan interval runner: New ticker detected") + } + } +} diff --git a/api/server.go b/api/server.go index a764b7a..7155c87 100644 --- a/api/server.go +++ b/api/server.go @@ -42,6 +42,7 @@ func main() { } scanner.InitializeScannerQueue(db) + scanner.InitializePeriodicScanner(db) rootRouter := mux.NewRouter() diff --git a/ui/src/Pages/SettingsPage/ScannerSection.js b/ui/src/Pages/SettingsPage/ScannerSection.js index 834b731..30e8663 100644 --- a/ui/src/Pages/SettingsPage/ScannerSection.js +++ b/ui/src/Pages/SettingsPage/ScannerSection.js @@ -75,7 +75,10 @@ const convertToAppropriateUnit = ({ value, unit }) => { let resultingUnit = timeUnits.first for (const unit of timeUnits) { - if (seconds / unit.multiplier >= 1) { + if ( + seconds / unit.multiplier >= 1 && + (seconds / unit.multiplier) % 1 == 0 + ) { resultingUnit = unit } else { break From 74f1eb26f758b33812ed768fd95ce7e37edc9cb0 Mon Sep 17 00:00:00 2001 From: viktorstrate Date: Mon, 21 Sep 2020 12:41:58 +0200 Subject: [PATCH 5/5] Only update scan interval, when value differ --- ui/src/Pages/SettingsPage/ScannerSection.js | 25 ++++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/ui/src/Pages/SettingsPage/ScannerSection.js b/ui/src/Pages/SettingsPage/ScannerSection.js index 30e8663..5f1be8c 100644 --- a/ui/src/Pages/SettingsPage/ScannerSection.js +++ b/ui/src/Pages/SettingsPage/ScannerSection.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useRef, useState } from 'react' import { Button, @@ -111,6 +111,8 @@ const ScannerSection = () => { unit: 'minute', }) + const scanIntervalServerValue = useRef(null) + const scanIntervalQuery = useQuery(SCAN_INTERVAL_QUERY, { onCompleted(data) { const queryScanInterval = data.siteInfo.periodicScanInterval @@ -141,19 +143,20 @@ const ScannerSection = () => { const onScanIntervalCheckboxChange = checked => { setEnablePeriodicScanner(checked) - setScanIntervalMutation({ - variables: { - interval: checked ? convertToSeconds(scanInterval) : 0, - }, - }) + onScanIntervalUpdate(checked ? scanInterval : { value: 0, unit: 'second' }) } const onScanIntervalUpdate = scanInterval => { - setScanIntervalMutation({ - variables: { - interval: convertToSeconds(scanInterval), - }, - }) + const seconds = convertToSeconds(scanInterval) + + if (scanIntervalServerValue.current != seconds) { + setScanIntervalMutation({ + variables: { + interval: convertToSeconds(scanInterval), + }, + }) + scanIntervalServerValue.current = seconds + } } const scanIntervalUnits = [