Received: from mail.netlandish.com (mail.netlandish.com [174.136.98.166]) by code.netlandish.com (Postfix) with ESMTP id DB5B6210 for <~netlandish/links-dev@lists.code.netlandish.com>; Wed, 12 Nov 2025 13:44:15 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.128.179; helo=mail-yw1-f179.google.com; envelope-from=peter@netlandish.com; receiver= Authentication-Results: mail.netlandish.com; dkim=pass (1024-bit key; unprotected) header.d=netlandish.com header.i=@netlandish.com header.b=YvsZ5Fx7 Received: from mail-yw1-f179.google.com (mail-yw1-f179.google.com [209.85.128.179]) by mail.netlandish.com (Postfix) with ESMTP id 76E7B1D640A for <~netlandish/links-dev@lists.code.netlandish.com>; Wed, 12 Nov 2025 13:45:42 +0000 (UTC) Received: by mail-yw1-f179.google.com with SMTP id 00721157ae682-7866bca6765so7541557b3.1 for <~netlandish/links-dev@lists.code.netlandish.com>; Wed, 12 Nov 2025 05:45:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netlandish.com; s=google; t=1762955142; x=1763559942; darn=lists.code.netlandish.com; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=j9JJMdjfX4tbuoM1cXsDr5WKVgV7sRv1rDqLSG05AEI=; b=YvsZ5Fx7Ug7WDnIy3ofTBE/4BHYYdaZA8j4KC7G2jLCFC9uXBLSVfwtXGgOh6g5E/3 reSmLalCdF9wpV8i2tIAs3hoNuPDAZ/ShI3vaj+GMd+NEzel3jfLUTNcd1IFHDPfjW/8 SZCBYnYyA+XPagR4HV5zew1y9GB3fL00v1iwY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1762955142; x=1763559942; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=j9JJMdjfX4tbuoM1cXsDr5WKVgV7sRv1rDqLSG05AEI=; b=jqJmjQUGJEpUEczIoaOcgzlhrTFuNo8fS87w12hSAI93MfDrsWoMQZckcKojdc2Rgr HHLibPdzbYh0IbGLokEH7FjpEpvaxIi4EvSujtRhdCgyCQwvZt3Rdu6mXXwkse1EAxcu EH+OPSwyMyCFbz8McXDhpLyQGQvHrKLqIp7QDVrD93ZPNDVkxFbEgXgSOp2NWB2pHBoS MwfyLVBRbY8DmLF7w+bByaVmlfdGn6zOsHBvUB2WHML4HMmBZyrbWaasxYXMphRGEBGW GHGXyyNisNPKcr7058YYHcx4LQ34Ypb/4zVMN3HmW5eXSDAnTD7rWhGRec6YNlP6sLk9 Zu/g== X-Gm-Message-State: AOJu0Yy7RWhJGQDkOJRgu2PimDRB5f9ROesrur/Ku6g709B0SoBVPeTY +X+pAs53djcnOxQcZCdubXujzLQclJWjEmaCs9lqq9p7j7LA/dQzhleBXa1RySNrgvLfUMGGQCj m+czQGAs= X-Gm-Gg: ASbGncuJHZXykPSJ6CQ8QmZQFQV4NjyKPY1Odcxiou6GPe90V6iI4FHsDJCF9hgeDK7 QGjo77ckW8mp3RwTAaJSzVj0hVYJJCrsE1xEerhyvAo8eZUliiru9CnIir6zzwGyAZyG2nMKcCW tuXa9Q4DmTsC2zOdIq7AWJFs9/5K6Sn7hKB2+ypP2L2oZzlGomH3u32EkokHKm48ECm1Pe6ysle KckOxLFUdNaHA7Oy59KNXFHVvF1AMQe+cBd8XZf7uVauASMRjZY9AA/5xmb7ci2DIOCuOYhHMSk kwHiDF1unAvnQ/r3MNn80WC8zs1FFP8DxHjL3LoEnh088q8ScvD+FeOeOMSuvteBuK14lC0O9tO NC4r/ZtSaZheklzIOyoZDIicCjrPNc2NhFD3ePunrSkJaa/fndHEUPC/lVfIu3W7vq1Uo9y8E8s Wt X-Google-Smtp-Source: AGHT+IGj8EBPLI5Xrxf3EZE/Ag+ON4R9QEK6XuC4VfprCuvvOEvl9F2TI42Ao0PpicnnNq+bNJ3X+A== X-Received: by 2002:a05:690c:7005:b0:784:8673:6f6f with SMTP id 00721157ae682-788136e5db4mr22354727b3.58.1762955141639; Wed, 12 Nov 2025 05:45:41 -0800 (PST) Received: from localhost ([2803:2d60:1107:87f:e68a:2c54:8a71:5fe9]) by smtp.gmail.com with UTF8SMTPSA id 00721157ae682-7880e1b68a9sm11152227b3.57.2025.11.12.05.45.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 12 Nov 2025 05:45:41 -0800 (PST) From: Peter Sanchez To: ~netlandish/links-dev@lists.code.netlandish.com Cc: Peter Sanchez Subject: [PATCH links] Adding `imageUrl` to relevant GraphQL types to make it easier to fetch images from their individual hosting environments. Date: Wed, 12 Nov 2025 07:45:31 -0600 Message-ID: <20251112134538.26395-1-peter@netlandish.com> X-Mailer: git-send-email 2.49.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changelog-added: `imageUrl` field to relevant GraphQL types --- api/gqlgen.yml | 12 ++ api/graph/generated.go | 289 +++++++++++++++++++++++++++++++--- api/graph/schema.graphqls | 5 +- api/graph/schema.resolvers.go | 41 ++++- 4 files changed, 321 insertions(+), 26 deletions(-) diff --git a/api/gqlgen.yml b/api/gqlgen.yml index 090a18f..6f9e4a4 100644 --- a/api/gqlgen.yml +++ b/api/gqlgen.yml @@ -67,3 +67,15 @@ models: AuditLog: model: - netlandish.com/x/gobwebs-auditlog.AuditLog + Organization: + fields: + imageUrl: + resolver: true + Listing: + fields: + imageUrl: + resolver: true + QRCode: + fields: + imageUrl: + resolver: true diff --git a/api/graph/generated.go b/api/graph/generated.go index b82dd28..1d880ed 100644 --- a/api/graph/generated.go +++ b/api/graph/generated.go @@ -46,6 +46,7 @@ type ResolverRoot interface { BaseURL() BaseURLResolver BillingSettings() BillingSettingsResolver Domain() DomainResolver + Listing() ListingResolver Mutation() MutationResolver OrgLink() OrgLinkResolver Organization() OrganizationResolver @@ -192,6 +193,7 @@ type ComplexityRoot struct { DomainID func(childComplexity int) int ID func(childComplexity int) int Image func(childComplexity int) int + ImageURL func(childComplexity int) int IsActive func(childComplexity int) int IsDefault func(childComplexity int) int LookupName func(childComplexity int) int @@ -319,6 +321,7 @@ type ComplexityRoot struct { CreatedOn func(childComplexity int) int ID func(childComplexity int) int Image func(childComplexity int) int + ImageURL func(childComplexity int) int IsActive func(childComplexity int) int Name func(childComplexity int) int OrgType func(childComplexity int) int @@ -384,6 +387,7 @@ type ComplexityRoot struct { HashID func(childComplexity int) int ID func(childComplexity int) int ImagePath func(childComplexity int) int + ImageURL func(childComplexity int) int OrgID func(childComplexity int) int Title func(childComplexity int) int URL func(childComplexity int) int @@ -496,6 +500,9 @@ type DomainResolver interface { Level(ctx context.Context, obj *models.Domain) (model.DomainLevel, error) Status(ctx context.Context, obj *models.Domain) (model.DomainStatus, error) } +type ListingResolver interface { + ImageURL(ctx context.Context, obj *models.Listing) (*string, error) +} type MutationResolver interface { AddOrganization(ctx context.Context, input model.OrganizationInput) (*models.Organization, error) UpdateOrganization(ctx context.Context, input *model.UpdateOrganizationInput) (*models.Organization, error) @@ -540,7 +547,7 @@ type OrgLinkResolver interface { type OrganizationResolver interface { OrgType(ctx context.Context, obj *models.Organization) (model.OrgType, error) - Image(ctx context.Context, obj *models.Organization) (*graphql.Upload, error) + ImageURL(ctx context.Context, obj *models.Organization) (*string, error) Visibility(ctx context.Context, obj *models.Organization) (model.PublicVisibility, error) } @@ -549,6 +556,8 @@ type OrganizationSettingsResolver interface { } type QRCodeResolver interface { CodeType(ctx context.Context, obj *models.QRCode) (model.QRCodeType, error) + + ImageURL(ctx context.Context, obj *models.QRCode) (*string, error) } type QueryResolver interface { Version(ctx context.Context) (*model.Version, error) @@ -1179,6 +1188,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Listing.Image(childComplexity), true + case "Listing.imageUrl": + if e.complexity.Listing.ImageURL == nil { + break + } + + return e.complexity.Listing.ImageURL(childComplexity), true + case "Listing.isActive": if e.complexity.Listing.IsActive == nil { break @@ -2007,6 +2023,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Organization.Image(childComplexity), true + case "Organization.imageUrl": + if e.complexity.Organization.ImageURL == nil { + break + } + + return e.complexity.Organization.ImageURL(childComplexity), true + case "Organization.isActive": if e.complexity.Organization.IsActive == nil { break @@ -2294,6 +2317,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.QRCode.ImagePath(childComplexity), true + case "QRCode.imageUrl": + if e.complexity.QRCode.ImageURL == nil { + break + } + + return e.complexity.QRCode.ImageURL(childComplexity), true + case "QRCode.orgId": if e.complexity.QRCode.OrgID == nil { break @@ -4703,6 +4733,8 @@ func (ec *executionContext) fieldContext_Analytics_qrList(_ context.Context, fie return ec.fieldContext_QRCode_url(ctx, field) case "imagePath": return ec.fieldContext_QRCode_imagePath(ctx, field) + case "imageUrl": + return ec.fieldContext_QRCode_imageUrl(ctx, field) case "hashId": return ec.fieldContext_QRCode_hashId(ctx, field) case "createdOn": @@ -8033,6 +8065,47 @@ func (ec *executionContext) fieldContext_Listing_image(_ context.Context, field return fc, nil } +func (ec *executionContext) _Listing_imageUrl(ctx context.Context, field graphql.CollectedField, obj *models.Listing) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Listing_imageUrl(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) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Listing().ImageURL(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Listing_imageUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Listing", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Listing_metadata(ctx context.Context, field graphql.CollectedField, obj *models.Listing) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Listing_metadata(ctx, field) if err != nil { @@ -8792,6 +8865,8 @@ func (ec *executionContext) fieldContext_ListingCursor_result(_ context.Context, return ec.fieldContext_Listing_slug(ctx, field) case "image": return ec.fieldContext_Listing_image(ctx, field) + case "imageUrl": + return ec.fieldContext_Listing_imageUrl(ctx, field) case "metadata": return ec.fieldContext_Listing_metadata(ctx, field) case "isActive": @@ -9480,6 +9555,8 @@ func (ec *executionContext) fieldContext_ListingLinkCursor_result(_ context.Cont return ec.fieldContext_Listing_slug(ctx, field) case "image": return ec.fieldContext_Listing_image(ctx, field) + case "imageUrl": + return ec.fieldContext_Listing_imageUrl(ctx, field) case "metadata": return ec.fieldContext_Listing_metadata(ctx, field) case "isActive": @@ -9765,6 +9842,8 @@ func (ec *executionContext) fieldContext_Mutation_addOrganization(ctx context.Co return ec.fieldContext_Organization_slug(ctx, field) case "image": return ec.fieldContext_Organization_image(ctx, field) + case "imageUrl": + return ec.fieldContext_Organization_imageUrl(ctx, field) case "timezone": return ec.fieldContext_Organization_timezone(ctx, field) case "settings": @@ -9880,6 +9959,8 @@ func (ec *executionContext) fieldContext_Mutation_updateOrganization(ctx context return ec.fieldContext_Organization_slug(ctx, field) case "image": return ec.fieldContext_Organization_image(ctx, field) + case "imageUrl": + return ec.fieldContext_Organization_imageUrl(ctx, field) case "timezone": return ec.fieldContext_Organization_timezone(ctx, field) case "settings": @@ -11580,6 +11661,8 @@ func (ec *executionContext) fieldContext_Mutation_addListing(ctx context.Context return ec.fieldContext_Listing_slug(ctx, field) case "image": return ec.fieldContext_Listing_image(ctx, field) + case "imageUrl": + return ec.fieldContext_Listing_imageUrl(ctx, field) case "metadata": return ec.fieldContext_Listing_metadata(ctx, field) case "isActive": @@ -11806,6 +11889,8 @@ func (ec *executionContext) fieldContext_Mutation_updateListing(ctx context.Cont return ec.fieldContext_Listing_slug(ctx, field) case "image": return ec.fieldContext_Listing_image(ctx, field) + case "imageUrl": + return ec.fieldContext_Listing_imageUrl(ctx, field) case "metadata": return ec.fieldContext_Listing_metadata(ctx, field) case "isActive": @@ -12226,6 +12311,8 @@ func (ec *executionContext) fieldContext_Mutation_addQRCode(ctx context.Context, return ec.fieldContext_QRCode_url(ctx, field) case "imagePath": return ec.fieldContext_QRCode_imagePath(ctx, field) + case "imageUrl": + return ec.fieldContext_QRCode_imageUrl(ctx, field) case "hashId": return ec.fieldContext_QRCode_hashId(ctx, field) case "createdOn": @@ -12792,6 +12879,8 @@ func (ec *executionContext) fieldContext_Mutation_updateAdminOrg(ctx context.Con return ec.fieldContext_Organization_slug(ctx, field) case "image": return ec.fieldContext_Organization_image(ctx, field) + case "imageUrl": + return ec.fieldContext_Organization_imageUrl(ctx, field) case "timezone": return ec.fieldContext_Organization_timezone(ctx, field) case "settings": @@ -15122,7 +15211,7 @@ func (ec *executionContext) _Organization_image(ctx context.Context, field graph }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Organization().Image(rctx, obj) + return obj.Image, nil }) if err != nil { ec.Error(ctx, err) @@ -15131,19 +15220,60 @@ func (ec *executionContext) _Organization_image(ctx context.Context, field graph if resTmp == nil { return graphql.Null } - res := resTmp.(*graphql.Upload) + res := resTmp.(string) fc.Result = res - return ec.marshalOUpload2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx, field.Selections, res) + return ec.marshalOString2string(ctx, field.Selections, res) } func (ec *executionContext) fieldContext_Organization_image(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Organization", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Organization_imageUrl(ctx context.Context, field graphql.CollectedField, obj *models.Organization) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Organization_imageUrl(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) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Organization().ImageURL(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Organization_imageUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Organization", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Upload does not have child fields") + return nil, errors.New("field of type String does not have child fields") }, } return fc, nil @@ -15644,6 +15774,8 @@ func (ec *executionContext) fieldContext_OrganizationCursor_result(_ context.Con return ec.fieldContext_Organization_slug(ctx, field) case "image": return ec.fieldContext_Organization_image(ctx, field) + case "imageUrl": + return ec.fieldContext_Organization_imageUrl(ctx, field) case "timezone": return ec.fieldContext_Organization_timezone(ctx, field) case "settings": @@ -17156,6 +17288,47 @@ func (ec *executionContext) fieldContext_QRCode_imagePath(_ context.Context, fie return fc, nil } +func (ec *executionContext) _QRCode_imageUrl(ctx context.Context, field graphql.CollectedField, obj *models.QRCode) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_QRCode_imageUrl(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) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.QRCode().ImageURL(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_QRCode_imageUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "QRCode", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _QRCode_hashId(ctx context.Context, field graphql.CollectedField, obj *models.QRCode) (ret graphql.Marshaler) { fc, err := ec.fieldContext_QRCode_hashId(ctx, field) if err != nil { @@ -17865,6 +18038,8 @@ func (ec *executionContext) fieldContext_Query_getOrganizations(ctx context.Cont return ec.fieldContext_Organization_slug(ctx, field) case "image": return ec.fieldContext_Organization_image(ctx, field) + case "imageUrl": + return ec.fieldContext_Organization_imageUrl(ctx, field) case "timezone": return ec.fieldContext_Organization_timezone(ctx, field) case "settings": @@ -17977,6 +18152,8 @@ func (ec *executionContext) fieldContext_Query_getOrganization(ctx context.Conte return ec.fieldContext_Organization_slug(ctx, field) case "image": return ec.fieldContext_Organization_image(ctx, field) + case "imageUrl": + return ec.fieldContext_Organization_imageUrl(ctx, field) case "timezone": return ec.fieldContext_Organization_timezone(ctx, field) case "settings": @@ -19622,6 +19799,8 @@ func (ec *executionContext) fieldContext_Query_getQRDetail(ctx context.Context, return ec.fieldContext_QRCode_url(ctx, field) case "imagePath": return ec.fieldContext_QRCode_imagePath(ctx, field) + case "imageUrl": + return ec.fieldContext_QRCode_imageUrl(ctx, field) case "hashId": return ec.fieldContext_QRCode_hashId(ctx, field) case "createdOn": @@ -19931,6 +20110,8 @@ func (ec *executionContext) fieldContext_Query_getFeedFollowing(_ context.Contex return ec.fieldContext_Organization_slug(ctx, field) case "image": return ec.fieldContext_Organization_image(ctx, field) + case "imageUrl": + return ec.fieldContext_Organization_imageUrl(ctx, field) case "timezone": return ec.fieldContext_Organization_timezone(ctx, field) case "settings": @@ -27577,72 +27758,105 @@ func (ec *executionContext) _Listing(ctx context.Context, sel ast.SelectionSet, case "id": out.Values[i] = ec._Listing_id(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "title": out.Values[i] = ec._Listing_title(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "slug": out.Values[i] = ec._Listing_slug(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "image": out.Values[i] = ec._Listing_image(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } + case "imageUrl": + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Listing_imageUrl(ctx, field, obj) + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "metadata": out.Values[i] = ec._Listing_metadata(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "isActive": out.Values[i] = ec._Listing_isActive(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "isDefault": out.Values[i] = ec._Listing_isDefault(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "tags": out.Values[i] = ec._Listing_tags(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "userId": out.Values[i] = ec._Listing_userId(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "orgId": out.Values[i] = ec._Listing_orgId(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "domainId": out.Values[i] = ec._Listing_domainId(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "lookupName": out.Values[i] = ec._Listing_lookupName(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "createdOn": out.Values[i] = ec._Listing_createdOn(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } case "updatedOn": out.Values[i] = ec._Listing_updatedOn(ctx, field, obj) if out.Values[i] == graphql.Null { - out.Invalids++ + atomic.AddUint32(&out.Invalids, 1) } default: panic("unknown field " + strconv.Quote(field.Name)) @@ -28597,6 +28811,8 @@ func (ec *executionContext) _Organization(ctx context.Context, sel ast.Selection atomic.AddUint32(&out.Invalids, 1) } case "image": + out.Values[i] = ec._Organization_image(ctx, field, obj) + case "imageUrl": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { @@ -28605,7 +28821,7 @@ func (ec *executionContext) _Organization(ctx context.Context, sel ast.Selection ec.Error(ctx, ec.Recover(ctx, r)) } }() - res = ec._Organization_image(ctx, field, obj) + res = ec._Organization_imageUrl(ctx, field, obj) return res } @@ -29169,6 +29385,39 @@ func (ec *executionContext) _QRCode(ctx context.Context, sel ast.SelectionSet, o if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } + case "imageUrl": + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._QRCode_imageUrl(ctx, field, obj) + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "hashId": out.Values[i] = ec._QRCode_hashId(ctx, field, obj) if out.Values[i] == graphql.Null { diff --git a/api/graph/schema.graphqls b/api/graph/schema.graphqls index afd08d5..9288fb7 100644 --- a/api/graph/schema.graphqls +++ b/api/graph/schema.graphqls @@ -182,7 +182,8 @@ type Organization { orgType: OrgType! name: String! slug: String! - image: Upload + image: String + imageUrl: String timezone: String! @access(scope: ORGS, kind: RO) settings: OrganizationSettings! @access(scope: ORGS, kind: RO) isActive: Boolean! @access(scope: ORGS, kind: RO) @@ -295,6 +296,7 @@ type Listing { title: String! slug: String! image: String! + imageUrl: String metadata: Metadata! isActive: Boolean! @access(scope: LISTS, kind: RO) isDefault: Boolean! @access(scope: LISTS, kind: RO) @@ -460,6 +462,7 @@ type QRCode { codeType: QRCodeType! url: String! imagePath: String! + imageUrl: String hashId: String! @access(scope: QRCODES, kind: RO) createdOn: Time! clicks: Int! diff --git a/api/graph/schema.resolvers.go b/api/graph/schema.resolvers.go index b49dcde..a1584ca 100644 --- a/api/graph/schema.resolvers.go +++ b/api/graph/schema.resolvers.go @@ -32,7 +32,6 @@ import ( "strings" "time" - "github.com/99designs/gqlgen/graphql" sq "github.com/Masterminds/squirrel" "github.com/segmentio/ksuid" qrcode "github.com/yeqown/go-qrcode/v2" @@ -93,6 +92,16 @@ func (r *domainResolver) Status(ctx context.Context, obj *models.Domain) (model. return model.DomainStatus(obj.Status), nil } +// ImageURL is the resolver for the imageUrl field. +func (r *listingResolver) ImageURL(ctx context.Context, obj *models.Listing) (*string, error) { + if obj.Image == "" { + return nil, nil + } + srv := server.ForContext(ctx) + fullURL, _ := url.JoinPath(srv.Config.MediaURL, obj.Image) + return &fullURL, nil +} + // AddOrganization is the resolver for the addOrganization field. func (r *mutationResolver) AddOrganization(ctx context.Context, input model.OrganizationInput) (*models.Organization, error) { tokenUser := oauth2.ForContext(ctx) @@ -4987,9 +4996,14 @@ func (r *organizationResolver) OrgType(ctx context.Context, obj *models.Organiza return model.OrgType(obj.OrgType), nil } -// Image is the resolver for the image field. -func (r *organizationResolver) Image(ctx context.Context, obj *models.Organization) (*graphql.Upload, error) { - panic(fmt.Errorf("not implemented: Image - image")) +// ImageURL is the resolver for the imageUrl field. +func (r *organizationResolver) ImageURL(ctx context.Context, obj *models.Organization) (*string, error) { + if obj.Image == "" { + return nil, nil + } + srv := server.ForContext(ctx) + fullURL, _ := url.JoinPath(srv.Config.MediaURL, obj.Image) + return &fullURL, nil } // Visibility is the resolver for the visibility field. @@ -5007,11 +5021,21 @@ func (r *qRCodeResolver) CodeType(ctx context.Context, obj *models.QRCode) (mode return model.QRCodeType(obj.CodeType), nil } +// ImageURL is the resolver for the imageUrl field. +func (r *qRCodeResolver) ImageURL(ctx context.Context, obj *models.QRCode) (*string, error) { + if obj.ImagePath == "" { + return nil, nil + } + srv := server.ForContext(ctx) + fullURL, _ := url.JoinPath(srv.Config.MediaURL, obj.ImagePath) + return &fullURL, nil +} + // Version is the resolver for the version field. func (r *queryResolver) Version(ctx context.Context) (*model.Version, error) { return &model.Version{ Major: 0, - Minor: 8, + Minor: 9, Patch: 0, DeprecationDate: nil, }, nil @@ -5026,6 +5050,9 @@ func (r *queryResolver) Me(ctx context.Context) (*models.User, error) { // GetOrganizations is the resolver for the getOrganizations field. func (r *queryResolver) GetOrganizations(ctx context.Context, input *model.GetOrganizationsInput) ([]*models.Organization, error) { + if input == nil { + input = &model.GetOrganizationsInput{} + } tokenUser := oauth2.ForContext(ctx) if tokenUser == nil { return nil, valid.ErrAuthorization @@ -7391,6 +7418,9 @@ func (r *Resolver) BillingSettings() BillingSettingsResolver { return &billingSe // Domain returns DomainResolver implementation. func (r *Resolver) Domain() DomainResolver { return &domainResolver{r} } +// Listing returns ListingResolver implementation. +func (r *Resolver) Listing() ListingResolver { return &listingResolver{r} } + // Mutation returns MutationResolver implementation. func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} } @@ -7418,6 +7448,7 @@ type auditLogResolver struct{ *Resolver } type baseURLResolver struct{ *Resolver } type billingSettingsResolver struct{ *Resolver } type domainResolver struct{ *Resolver } +type listingResolver struct{ *Resolver } type mutationResolver struct{ *Resolver } type orgLinkResolver struct{ *Resolver } type organizationResolver struct{ *Resolver } -- 2.49.1