From 4ff89b0d27c57d27b3f0a039ccb27b3873ba7d16 Mon Sep 17 00:00:00 2001 From: Allyson-English Date: Thu, 22 May 2025 11:16:23 -0400 Subject: [PATCH 1/5] filter attestations by id --- go.mod | 2 +- go.sum | 4 +- internal/graph/attestation.resolvers.go | 8 +- internal/graph/generated.go | 255 +++++++++++++++++- internal/graph/model/models_gen.go | 2 + .../repositories/attestation/attestation.go | 66 ++++- .../attestation/attestation_test.go | 8 +- schema/attestation.graphqls | 33 +++ 8 files changed, 364 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index b1daf598..4c35c2be 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/DIMO-Network/attestation-api v0.0.11 github.com/DIMO-Network/clickhouse-infra v0.0.3 github.com/DIMO-Network/cloudevent v0.1.0 - github.com/DIMO-Network/fetch-api v0.0.10 + github.com/DIMO-Network/fetch-api v0.0.12 github.com/DIMO-Network/model-garage v0.6.0 github.com/DIMO-Network/shared v1.0.1 github.com/Khan/genqlient v0.7.0 diff --git a/go.sum b/go.sum index dd5be4ed..fdb2e4ca 100644 --- a/go.sum +++ b/go.sum @@ -80,8 +80,8 @@ github.com/DIMO-Network/clickhouse-infra v0.0.3 h1:B6/4IY9IxLcyydET14IjHUT+A5SDE github.com/DIMO-Network/clickhouse-infra v0.0.3/go.mod h1:NtpQ1btkPzebDvpYYygeqiiBmJ/q5oJb/T/JWzUVRlk= github.com/DIMO-Network/cloudevent v0.1.0 h1:ze0ngJQBXjSSyBnEAUO+YvClvkqM68kNko/czY3GfLo= github.com/DIMO-Network/cloudevent v0.1.0/go.mod h1:RS9Byb0ycb5b7OFe9y+xpF0nkR4pYYS6Om/ccs3N5Z4= -github.com/DIMO-Network/fetch-api v0.0.10 h1:TdB+cXEEdKYQejxgayx9YdEIOzEyp0++Si+w90DWF8g= -github.com/DIMO-Network/fetch-api v0.0.10/go.mod h1:xxtQJ0dKkyxJpOzGCH4EiTKdVCikum+p6DJTXzgzqug= +github.com/DIMO-Network/fetch-api v0.0.12 h1:pLUekaYNWHKmguoGAni+BtTWl1j1yOdpowN5T6bWZuo= +github.com/DIMO-Network/fetch-api v0.0.12/go.mod h1:9FtpOZR6kChy9x8cXN1z/0002ATh7R6yDo40pABAyNw= github.com/DIMO-Network/model-garage v0.6.0 h1:VtRjcEljCTffeDQbq5k8LP1Y01FBt5OpgwXRrH5QiPY= github.com/DIMO-Network/model-garage v0.6.0/go.mod h1:5xrWBU0Gr6l3szBtfwM76KbsQlT6GTX2XI+4s/ZD9O0= github.com/DIMO-Network/shared v1.0.1 h1:eN2KgoPitt4Ht8/yFu//CgUfaOhRUM5JksHLrNJV6ug= diff --git a/internal/graph/attestation.resolvers.go b/internal/graph/attestation.resolvers.go index 0cded5fa..48f66432 100644 --- a/internal/graph/attestation.resolvers.go +++ b/internal/graph/attestation.resolvers.go @@ -8,9 +8,15 @@ import ( "context" "github.com/DIMO-Network/telemetry-api/internal/graph/model" + "github.com/ethereum/go-ethereum/common" ) // Attestations is the resolver for the attestations field. func (r *queryResolver) Attestations(ctx context.Context, tokenID int, filter *model.AttestationFilter) ([]*model.Attestation, error) { - return r.AttestationRepo.GetAttestations(ctx, uint32(tokenID), filter) + return r.AttestationRepo.GetAttestations(ctx, tokenID, filter) +} + +// Attestation is the resolver for the attestation field. +func (r *queryResolver) Attestation(ctx context.Context, tokenID int, source common.Address, id string) (*model.Attestation, error) { + return r.AttestationRepo.GetAttestation(ctx, tokenID, source, id) } diff --git a/internal/graph/generated.go b/internal/graph/generated.go index 6c2e0dbd..226fc61d 100644 --- a/internal/graph/generated.go +++ b/internal/graph/generated.go @@ -79,6 +79,7 @@ type ComplexityRoot struct { } Query struct { + Attestation func(childComplexity int, tokenID int, source common.Address, id string) int Attestations func(childComplexity int, tokenID int, filter *model.AttestationFilter) int AvailableSignals func(childComplexity int, tokenID int, filter *model.SignalFilter) int DeviceActivity func(childComplexity int, by model.AftermarketDeviceBy) int @@ -280,6 +281,7 @@ type QueryResolver interface { SignalsLatest(ctx context.Context, tokenID int, filter *model.SignalFilter) (*model.SignalCollection, error) AvailableSignals(ctx context.Context, tokenID int, filter *model.SignalFilter) ([]string, error) Attestations(ctx context.Context, tokenID int, filter *model.AttestationFilter) ([]*model.Attestation, error) + Attestation(ctx context.Context, tokenID int, source common.Address, id string) (*model.Attestation, error) DeviceActivity(ctx context.Context, by model.AftermarketDeviceBy) (*model.DeviceActivity, error) VinVCLatest(ctx context.Context, tokenID int) (*model.Vinvc, error) PomVCLatest(ctx context.Context, tokenID int) (*model.Pomvc, error) @@ -489,6 +491,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.POMVC.VehicleTokenID(childComplexity), true + case "Query.attestation": + if e.complexity.Query.Attestation == nil { + break + } + + args, err := ec.field_Query_attestation_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Attestation(childComplexity, args["tokenId"].(int), args["source"].(common.Address), args["id"].(string)), true + case "Query.attestations": if e.complexity.Query.Attestations == nil { break @@ -2274,6 +2288,34 @@ var sources = []*ast.Source{ @requiresAllOfPrivileges(privileges: [VEHICLE_RAW_DATA]) } +extend type Query { + """ + attestation returns an individual attestation for a given vehicle token based on attestation source and id. + + Required Privileges: [VEHICLE_RAW_DATA] + """ + attestation( + """ + The token ID of the vehicle. + """ + tokenId: Int! + + """ + The source of the attestation. + """ + source: Address! + + """ + The attestation id. + """ + id: String! + + ): Attestation + @requiresVehicleToken + @requiresAllOfPrivileges(privileges: [VEHICLE_RAW_DATA]) +} + + type Attestation { """ ID is the ID of the attestation. @@ -2326,6 +2368,11 @@ type Attestation { AttestationFilter holds the filter parameters for the attestation querys. """ input AttestationFilter { + """ + id is the id of the attestation. + """ + id: String + """ The attesting party. """ @@ -3969,6 +4016,80 @@ func (ec *executionContext) field_Query___type_argsName( return zeroVal, nil } +func (ec *executionContext) field_Query_attestation_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Query_attestation_argsTokenID(ctx, rawArgs) + if err != nil { + return nil, err + } + args["tokenId"] = arg0 + arg1, err := ec.field_Query_attestation_argsSource(ctx, rawArgs) + if err != nil { + return nil, err + } + args["source"] = arg1 + arg2, err := ec.field_Query_attestation_argsID(ctx, rawArgs) + if err != nil { + return nil, err + } + args["id"] = arg2 + return args, nil +} +func (ec *executionContext) field_Query_attestation_argsTokenID( + ctx context.Context, + rawArgs map[string]any, +) (int, error) { + if _, ok := rawArgs["tokenId"]; !ok { + var zeroVal int + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("tokenId")) + if tmp, ok := rawArgs["tokenId"]; ok { + return ec.unmarshalNInt2int(ctx, tmp) + } + + var zeroVal int + return zeroVal, nil +} + +func (ec *executionContext) field_Query_attestation_argsSource( + ctx context.Context, + rawArgs map[string]any, +) (common.Address, error) { + if _, ok := rawArgs["source"]; !ok { + var zeroVal common.Address + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("source")) + if tmp, ok := rawArgs["source"]; ok { + return ec.unmarshalNAddress2githubᚗcomᚋethereumᚋgoᚑethereumᚋcommonᚐAddress(ctx, tmp) + } + + var zeroVal common.Address + return zeroVal, nil +} + +func (ec *executionContext) field_Query_attestation_argsID( + ctx context.Context, + rawArgs map[string]any, +) (string, error) { + if _, ok := rawArgs["id"]; !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + if tmp, ok := rawArgs["id"]; ok { + return ec.unmarshalNString2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} + func (ec *executionContext) field_Query_attestations_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -7920,6 +8041,112 @@ func (ec *executionContext) fieldContext_Query_attestations(ctx context.Context, return fc, nil } +func (ec *executionContext) _Query_attestation(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_attestation(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) { + directive0 := func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Attestation(rctx, fc.Args["tokenId"].(int), fc.Args["source"].(common.Address), fc.Args["id"].(string)) + } + + directive1 := func(ctx context.Context) (any, error) { + if ec.directives.RequiresVehicleToken == nil { + var zeroVal *model.Attestation + return zeroVal, errors.New("directive requiresVehicleToken is not implemented") + } + return ec.directives.RequiresVehicleToken(ctx, nil, directive0) + } + directive2 := func(ctx context.Context) (any, error) { + privileges, err := ec.unmarshalNPrivilege2ᚕgithubᚗcomᚋDIMOᚑNetworkᚋtelemetryᚑapiᚋinternalᚋgraphᚋmodelᚐPrivilegeᚄ(ctx, []any{"VEHICLE_RAW_DATA"}) + if err != nil { + var zeroVal *model.Attestation + return zeroVal, err + } + if ec.directives.RequiresAllOfPrivileges == nil { + var zeroVal *model.Attestation + return zeroVal, errors.New("directive requiresAllOfPrivileges is not implemented") + } + return ec.directives.RequiresAllOfPrivileges(ctx, nil, directive1, privileges) + } + + tmp, err := directive2(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*model.Attestation); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/DIMO-Network/telemetry-api/internal/graph/model.Attestation`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*model.Attestation) + fc.Result = res + return ec.marshalOAttestation2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋtelemetryᚑapiᚋinternalᚋgraphᚋmodelᚐAttestation(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_attestation(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "ID": + return ec.fieldContext_Attestation_ID(ctx, field) + case "vehicleTokenId": + return ec.fieldContext_Attestation_vehicleTokenId(ctx, field) + case "time": + return ec.fieldContext_Attestation_time(ctx, field) + case "attestation": + return ec.fieldContext_Attestation_attestation(ctx, field) + case "type": + return ec.fieldContext_Attestation_type(ctx, field) + case "source": + return ec.fieldContext_Attestation_source(ctx, field) + case "dataVersion": + return ec.fieldContext_Attestation_dataVersion(ctx, field) + case "producer": + return ec.fieldContext_Attestation_producer(ctx, field) + case "signature": + return ec.fieldContext_Attestation_signature(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Attestation", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_attestation_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Query_deviceActivity(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_deviceActivity(ctx, field) if err != nil { @@ -24549,13 +24776,20 @@ func (ec *executionContext) unmarshalInputAttestationFilter(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"source", "dataVersion", "producer", "before", "after", "limit"} + fieldsInOrder := [...]string{"id", "source", "dataVersion", "producer", "before", "after", "limit"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { + case "id": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.ID = data case "source": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("source")) data, err := ec.unmarshalOAddress2ᚖgithubᚗcomᚋethereumᚋgoᚑethereumᚋcommonᚐAddress(ctx, v) @@ -24892,6 +25126,25 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "attestation": + 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._Query_attestation(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "deviceActivity": field := field diff --git a/internal/graph/model/models_gen.go b/internal/graph/model/models_gen.go index 05aed6d9..851567b4 100644 --- a/internal/graph/model/models_gen.go +++ b/internal/graph/model/models_gen.go @@ -42,6 +42,8 @@ type Attestation struct { // AttestationFilter holds the filter parameters for the attestation querys. type AttestationFilter struct { + // id is the id of the attestation. + ID *string `json:"id,omitempty"` // The attesting party. Source *common.Address `json:"source,omitempty"` // Filter attestations by data version. diff --git a/internal/repositories/attestation/attestation.go b/internal/repositories/attestation/attestation.go index 32add535..a966d4a3 100644 --- a/internal/repositories/attestation/attestation.go +++ b/internal/repositories/attestation/attestation.go @@ -35,8 +35,8 @@ func New(indexService indexRepoService, chainID uint64, vehicleAddress common.Ad } // GetAttestations fetches attestations for the given vehicle. -func (r *Repository) GetAttestations(ctx context.Context, vehicleTokenID uint32, filter *model.AttestationFilter) ([]*model.Attestation, error) { - logger := r.getLogger(ctx) +func (r *Repository) GetAttestations(ctx context.Context, vehicleTokenID int, filter *model.AttestationFilter) ([]*model.Attestation, error) { + logger := r.getLogger(ctx, vehicleTokenID) vehicleDID := cloudevent.ERC721DID{ ChainID: r.chainID, ContractAddress: r.vehicleAddress, @@ -73,6 +73,10 @@ func (r *Repository) GetAttestations(ctx context.Context, vehicleTokenID uint32, if filter.Limit != nil { limit = *filter.Limit } + + if filter.ID != nil { + opts.Id = &wrapperspb.StringValue{Value: *filter.ID} + } } cloudEvents, err := r.indexService.GetAllCloudEvents(ctx, opts, int32(limit)) @@ -101,7 +105,7 @@ func (r *Repository) GetAttestations(ctx context.Context, vehicleTokenID uint32, signature, ok := ce.Extras["signature"].(string) if !ok { logger.Info().Str("id", attestation.ID).Str("source", attestation.Source.Hex()).Msg("failed to pull signature") - return nil, fmt.Errorf("invalid signature from %s on attestation %s", attestation.ID, attestation.Source) + return nil, fmt.Errorf("invalid format: attestation signature missing") } attestation.Signature = signature @@ -111,6 +115,58 @@ func (r *Repository) GetAttestations(ctx context.Context, vehicleTokenID uint32, return attestations, nil } -func (r *Repository) getLogger(ctx context.Context) zerolog.Logger { - return zerolog.Ctx(ctx).With().Str("component", "attestation").Logger() +// GetAttestations fetches attestations for the given vehicle. +func (r *Repository) GetAttestation(ctx context.Context, vehicleTokenID int, source common.Address, id string) (*model.Attestation, error) { + logger := r.getLogger(ctx, vehicleTokenID) + vehicleDID := cloudevent.ERC721DID{ + ChainID: r.chainID, + ContractAddress: r.vehicleAddress, + TokenID: new(big.Int).SetUint64(uint64(vehicleTokenID)), + }.String() + opts := &grpc.SearchOptions{ + Type: &wrapperspb.StringValue{Value: cloudevent.TypeAttestation}, + Subject: &wrapperspb.StringValue{Value: vehicleDID}, + } + + limit := 1 + opts.Source = &wrapperspb.StringValue{Value: source.Hex()} + opts.Id = &wrapperspb.StringValue{Value: id} + + cloudEvents, err := r.indexService.GetAllCloudEvents(ctx, opts, int32(limit)) + if err != nil || len(cloudEvents) == 0 { + logger.Error().Err(err).Msgf("failed to get cloudevent %s from source: %s", id, source) + return nil, errors.New("internal error") + } + + tknID := int(vehicleTokenID) + var att *model.Attestation + for _, ce := range cloudEvents { + att = &model.Attestation{ + ID: ce.ID, + VehicleTokenID: tknID, + Time: ce.Time, + Attestation: string(ce.Data), + Type: ce.Type, + Source: common.HexToAddress(ce.Source), + DataVersion: ce.DataVersion, + } + + if ce.Producer != "" { + att.Producer = &ce.Producer + } + + signature, ok := ce.Extras["signature"].(string) + if !ok { + logger.Info().Str("id", att.ID).Str("source", att.Source.Hex()).Msg("failed to pull signature") + return nil, fmt.Errorf("invalid format: attestation signature missing") + } + + att.Signature = signature + } + + return att, nil +} + +func (r *Repository) getLogger(ctx context.Context, vehicleTokenID int) zerolog.Logger { + return zerolog.Ctx(ctx).With().Str("component", "attestation").Int("vehicleTokenId", vehicleTokenID).Logger() } diff --git a/internal/repositories/attestation/attestation_test.go b/internal/repositories/attestation/attestation_test.go index cd6f63a2..78c21ea2 100644 --- a/internal/repositories/attestation/attestation_test.go +++ b/internal/repositories/attestation/attestation_test.go @@ -88,7 +88,7 @@ func TestAttestation(t *testing.T) { tests := []struct { name string mockSetup func() - vehTknID uint32 + vehTknID int filters *model.AttestationFilter expectedAtts []*model.Attestation expectedErr bool @@ -101,7 +101,7 @@ func TestAttestation(t *testing.T) { defaultEvent, }, nil) }, - vehTknID: uint32(validVehTknID), + vehTknID: validVehTknID, expectedAtts: []*model.Attestation{ &model.Attestation{ ID: id, @@ -130,7 +130,7 @@ func TestAttestation(t *testing.T) { Source: &validSigner, Limit: &limit, }, - vehTknID: uint32(validVehTknID), + vehTknID: validVehTknID, expectedAtts: []*model.Attestation{ &model.Attestation{ ID: id, @@ -149,7 +149,7 @@ func TestAttestation(t *testing.T) { mockSetup: func() { mockService.EXPECT().GetAllCloudEvents(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil) }, - vehTknID: uint32(invalidVehTknID), + vehTknID: invalidVehTknID, }, } diff --git a/schema/attestation.graphqls b/schema/attestation.graphqls index 26926c6f..542dd84b 100644 --- a/schema/attestation.graphqls +++ b/schema/attestation.graphqls @@ -19,6 +19,34 @@ extend type Query { @requiresAllOfPrivileges(privileges: [VEHICLE_RAW_DATA]) } +extend type Query { + """ + attestation returns an individual attestation for a given vehicle token based on attestation source and id. + + Required Privileges: [VEHICLE_RAW_DATA] + """ + attestation( + """ + The token ID of the vehicle. + """ + tokenId: Int! + + """ + The source of the attestation. + """ + source: Address! + + """ + The attestation id. + """ + id: String! + + ): Attestation + @requiresVehicleToken + @requiresAllOfPrivileges(privileges: [VEHICLE_RAW_DATA]) +} + + type Attestation { """ ID is the ID of the attestation. @@ -71,6 +99,11 @@ type Attestation { AttestationFilter holds the filter parameters for the attestation querys. """ input AttestationFilter { + """ + id is the id of the attestation. + """ + id: String + """ The attesting party. """ From 9e1fd6e591e4b8a46131ce9c413941a27169bb5a Mon Sep 17 00:00:00 2001 From: Allyson-English Date: Thu, 22 May 2025 11:31:31 -0400 Subject: [PATCH 2/5] test --- .../attestation/attestation_test.go | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/internal/repositories/attestation/attestation_test.go b/internal/repositories/attestation/attestation_test.go index 78c21ea2..2ac7c9a6 100644 --- a/internal/repositories/attestation/attestation_test.go +++ b/internal/repositories/attestation/attestation_test.go @@ -43,7 +43,7 @@ func (m *MockRow) ScanStruct(any) error { return nil } -func TestAttestation(t *testing.T) { +func TestGetAttestations(t *testing.T) { // Initialize variables ctx := context.Background() validVehTknID := int(123) @@ -182,3 +182,75 @@ func TestAttestation(t *testing.T) { }) } } + +func TestGetAttestation(t *testing.T) { + // Initialize variables + ctx := context.Background() + validVehTknID := int(123) + + validSigner := common.BigToAddress(big.NewInt(1)) + + // Create mock controller + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // Create mock services + mockService := NewMockindexRepoService(ctrl) + vehicleAddress := common.HexToAddress("0x123") + chainID := uint64(3) + + // Initialize the service with mock dependencies + att := attestation.New(mockService, chainID, vehicleAddress) + + vehicleDID := cloudevent.ERC721DID{ + ChainID: chainID, + ContractAddress: vehicleAddress, + TokenID: new(big.Int).SetUint64(uint64(validVehTknID)), + }.String() + + dataStr := `{"goodTires": true}` + defaultEvent := cloudevent.CloudEvent[json.RawMessage]{ + Data: json.RawMessage(dataStr), + } + defaultEvent.Time = time.Now() + defaultEvent.Source = validSigner.Hex() + defaultEvent.Subject = vehicleDID + defaultEvent.Extras = make(map[string]any) + defaultEvent.Extras["signature"] = "signature" + id := ksuid.New().String() + + // Test cases + tests := []struct { + name string + mockSetup func() + vehTknID int + filters *model.AttestationFilter + source common.Address + attID string + expectedErr bool + err error + }{ + { + name: "successful query, get attestation by id and source", + mockSetup: func() { + mockService.EXPECT().GetAllCloudEvents(gomock.Any(), gomock.Any(), gomock.Any()).Return([]cloudevent.CloudEvent[json.RawMessage]{ + defaultEvent, + }, nil) + }, + vehTknID: validVehTknID, + source: validSigner, + attID: id, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Set up the mock expectations + tt.mockSetup() + // Call the method + _, err := att.GetAttestation(ctx, tt.vehTknID, tt.source, tt.attID) + require.ErrorIs(t, err, tt.err) + + }) + } +} From e6de734ca2d64da415d87ea4cbb3413f712b8a8d Mon Sep 17 00:00:00 2001 From: Allyson-English Date: Tue, 27 May 2025 09:47:54 -0400 Subject: [PATCH 3/5] get latest cloud event method --- .../repositories/attestation/attestation.go | 42 ++++++++----------- .../attestation/attestation_mock_test.go | 15 +++++++ .../attestation/attestation_test.go | 4 +- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/internal/repositories/attestation/attestation.go b/internal/repositories/attestation/attestation.go index a966d4a3..9c2b9dee 100644 --- a/internal/repositories/attestation/attestation.go +++ b/internal/repositories/attestation/attestation.go @@ -18,6 +18,7 @@ import ( type indexRepoService interface { GetAllCloudEvents(ctx context.Context, filter *grpc.SearchOptions, limit int32) ([]cloudevent.CloudEvent[json.RawMessage], error) + GetLatestCloudEvent(ctx context.Context, filter *grpc.SearchOptions) (cloudevent.CloudEvent[json.RawMessage], error) } type Repository struct { indexService indexRepoService @@ -128,41 +129,32 @@ func (r *Repository) GetAttestation(ctx context.Context, vehicleTokenID int, sou Subject: &wrapperspb.StringValue{Value: vehicleDID}, } - limit := 1 opts.Source = &wrapperspb.StringValue{Value: source.Hex()} opts.Id = &wrapperspb.StringValue{Value: id} - cloudEvents, err := r.indexService.GetAllCloudEvents(ctx, opts, int32(limit)) - if err != nil || len(cloudEvents) == 0 { + cloudEvent, err := r.indexService.GetLatestCloudEvent(ctx, opts) + if err != nil { logger.Error().Err(err).Msgf("failed to get cloudevent %s from source: %s", id, source) return nil, errors.New("internal error") } tknID := int(vehicleTokenID) - var att *model.Attestation - for _, ce := range cloudEvents { - att = &model.Attestation{ - ID: ce.ID, - VehicleTokenID: tknID, - Time: ce.Time, - Attestation: string(ce.Data), - Type: ce.Type, - Source: common.HexToAddress(ce.Source), - DataVersion: ce.DataVersion, - } - - if ce.Producer != "" { - att.Producer = &ce.Producer - } - - signature, ok := ce.Extras["signature"].(string) - if !ok { - logger.Info().Str("id", att.ID).Str("source", att.Source.Hex()).Msg("failed to pull signature") - return nil, fmt.Errorf("invalid format: attestation signature missing") - } + att := &model.Attestation{ + ID: cloudEvent.ID, + VehicleTokenID: tknID, + Time: cloudEvent.Time, + Attestation: string(cloudEvent.Data), + Type: cloudEvent.Type, + Source: common.HexToAddress(cloudEvent.Source), + DataVersion: cloudEvent.DataVersion, + } - att.Signature = signature + signature, ok := cloudEvent.Extras["signature"].(string) + if !ok { + logger.Info().Str("id", cloudEvent.ID).Str("source", cloudEvent.Source).Msg("failed to pull signature") + return nil, fmt.Errorf("invalid format: attestation signature missing") } + att.Signature = signature return att, nil } diff --git a/internal/repositories/attestation/attestation_mock_test.go b/internal/repositories/attestation/attestation_mock_test.go index dcbc19df..bb7a3c47 100644 --- a/internal/repositories/attestation/attestation_mock_test.go +++ b/internal/repositories/attestation/attestation_mock_test.go @@ -57,3 +57,18 @@ func (mr *MockindexRepoServiceMockRecorder) GetAllCloudEvents(ctx, filter, limit mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllCloudEvents", reflect.TypeOf((*MockindexRepoService)(nil).GetAllCloudEvents), ctx, filter, limit) } + +// GetLatestCloudEvent mocks base method. +func (m *MockindexRepoService) GetLatestCloudEvent(ctx context.Context, filter *grpc.SearchOptions) (cloudevent.CloudEvent[json.RawMessage], error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLatestCloudEvent", ctx, filter) + ret0, _ := ret[0].(cloudevent.CloudEvent[json.RawMessage]) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLatestCloudEvent indicates an expected call of GetLatestCloudEvent. +func (mr *MockindexRepoServiceMockRecorder) GetLatestCloudEvent(ctx, filter any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestCloudEvent", reflect.TypeOf((*MockindexRepoService)(nil).GetLatestCloudEvent), ctx, filter) +} diff --git a/internal/repositories/attestation/attestation_test.go b/internal/repositories/attestation/attestation_test.go index 2ac7c9a6..055c7753 100644 --- a/internal/repositories/attestation/attestation_test.go +++ b/internal/repositories/attestation/attestation_test.go @@ -233,9 +233,7 @@ func TestGetAttestation(t *testing.T) { { name: "successful query, get attestation by id and source", mockSetup: func() { - mockService.EXPECT().GetAllCloudEvents(gomock.Any(), gomock.Any(), gomock.Any()).Return([]cloudevent.CloudEvent[json.RawMessage]{ - defaultEvent, - }, nil) + mockService.EXPECT().GetLatestCloudEvent(gomock.Any(), gomock.Any()).Return(defaultEvent, nil) }, vehTknID: validVehTknID, source: validSigner, From 334dd58302b2e7f6171572862b6e3f96ce1ddd9c Mon Sep 17 00:00:00 2001 From: Allyson-English Date: Thu, 29 May 2025 11:07:54 -0400 Subject: [PATCH 4/5] remove getAttestation (singular) --- internal/graph/attestation.resolvers.go | 12 +- internal/graph/generated.go | 241 ------------------ .../repositories/attestation/attestation.go | 44 ---- .../attestation/attestation_test.go | 70 ----- schema/attestation.graphqls | 28 -- 5 files changed, 9 insertions(+), 386 deletions(-) diff --git a/internal/graph/attestation.resolvers.go b/internal/graph/attestation.resolvers.go index 48f66432..e92720d3 100644 --- a/internal/graph/attestation.resolvers.go +++ b/internal/graph/attestation.resolvers.go @@ -8,7 +8,6 @@ import ( "context" "github.com/DIMO-Network/telemetry-api/internal/graph/model" - "github.com/ethereum/go-ethereum/common" ) // Attestations is the resolver for the attestations field. @@ -16,7 +15,14 @@ func (r *queryResolver) Attestations(ctx context.Context, tokenID int, filter *m return r.AttestationRepo.GetAttestations(ctx, tokenID, filter) } -// Attestation is the resolver for the attestation field. -func (r *queryResolver) Attestation(ctx context.Context, tokenID int, source common.Address, id string) (*model.Attestation, error) { +// !!! WARNING !!! +// The code below was going to be deleted when updating resolvers. It has been copied here so you have +// one last chance to move it out of harms way if you want. There are two reasons this happens: +// - When renaming or deleting a resolver the old code will be put in here. You can safely delete +// it when you're done. +// - You have helper methods in this file. Move them out to keep these resolver files clean. +/* + func (r *queryResolver) Attestation(ctx context.Context, tokenID int, source common.Address, id string) (*model.Attestation, error) { return r.AttestationRepo.GetAttestation(ctx, tokenID, source, id) } +*/ diff --git a/internal/graph/generated.go b/internal/graph/generated.go index 226fc61d..1a2c6759 100644 --- a/internal/graph/generated.go +++ b/internal/graph/generated.go @@ -79,7 +79,6 @@ type ComplexityRoot struct { } Query struct { - Attestation func(childComplexity int, tokenID int, source common.Address, id string) int Attestations func(childComplexity int, tokenID int, filter *model.AttestationFilter) int AvailableSignals func(childComplexity int, tokenID int, filter *model.SignalFilter) int DeviceActivity func(childComplexity int, by model.AftermarketDeviceBy) int @@ -281,7 +280,6 @@ type QueryResolver interface { SignalsLatest(ctx context.Context, tokenID int, filter *model.SignalFilter) (*model.SignalCollection, error) AvailableSignals(ctx context.Context, tokenID int, filter *model.SignalFilter) ([]string, error) Attestations(ctx context.Context, tokenID int, filter *model.AttestationFilter) ([]*model.Attestation, error) - Attestation(ctx context.Context, tokenID int, source common.Address, id string) (*model.Attestation, error) DeviceActivity(ctx context.Context, by model.AftermarketDeviceBy) (*model.DeviceActivity, error) VinVCLatest(ctx context.Context, tokenID int) (*model.Vinvc, error) PomVCLatest(ctx context.Context, tokenID int) (*model.Pomvc, error) @@ -491,18 +489,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.POMVC.VehicleTokenID(childComplexity), true - case "Query.attestation": - if e.complexity.Query.Attestation == nil { - break - } - - args, err := ec.field_Query_attestation_args(ctx, rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Query.Attestation(childComplexity, args["tokenId"].(int), args["source"].(common.Address), args["id"].(string)), true - case "Query.attestations": if e.complexity.Query.Attestations == nil { break @@ -2288,34 +2274,6 @@ var sources = []*ast.Source{ @requiresAllOfPrivileges(privileges: [VEHICLE_RAW_DATA]) } -extend type Query { - """ - attestation returns an individual attestation for a given vehicle token based on attestation source and id. - - Required Privileges: [VEHICLE_RAW_DATA] - """ - attestation( - """ - The token ID of the vehicle. - """ - tokenId: Int! - - """ - The source of the attestation. - """ - source: Address! - - """ - The attestation id. - """ - id: String! - - ): Attestation - @requiresVehicleToken - @requiresAllOfPrivileges(privileges: [VEHICLE_RAW_DATA]) -} - - type Attestation { """ ID is the ID of the attestation. @@ -4016,80 +3974,6 @@ func (ec *executionContext) field_Query___type_argsName( return zeroVal, nil } -func (ec *executionContext) field_Query_attestation_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { - var err error - args := map[string]any{} - arg0, err := ec.field_Query_attestation_argsTokenID(ctx, rawArgs) - if err != nil { - return nil, err - } - args["tokenId"] = arg0 - arg1, err := ec.field_Query_attestation_argsSource(ctx, rawArgs) - if err != nil { - return nil, err - } - args["source"] = arg1 - arg2, err := ec.field_Query_attestation_argsID(ctx, rawArgs) - if err != nil { - return nil, err - } - args["id"] = arg2 - return args, nil -} -func (ec *executionContext) field_Query_attestation_argsTokenID( - ctx context.Context, - rawArgs map[string]any, -) (int, error) { - if _, ok := rawArgs["tokenId"]; !ok { - var zeroVal int - return zeroVal, nil - } - - ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("tokenId")) - if tmp, ok := rawArgs["tokenId"]; ok { - return ec.unmarshalNInt2int(ctx, tmp) - } - - var zeroVal int - return zeroVal, nil -} - -func (ec *executionContext) field_Query_attestation_argsSource( - ctx context.Context, - rawArgs map[string]any, -) (common.Address, error) { - if _, ok := rawArgs["source"]; !ok { - var zeroVal common.Address - return zeroVal, nil - } - - ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("source")) - if tmp, ok := rawArgs["source"]; ok { - return ec.unmarshalNAddress2githubᚗcomᚋethereumᚋgoᚑethereumᚋcommonᚐAddress(ctx, tmp) - } - - var zeroVal common.Address - return zeroVal, nil -} - -func (ec *executionContext) field_Query_attestation_argsID( - ctx context.Context, - rawArgs map[string]any, -) (string, error) { - if _, ok := rawArgs["id"]; !ok { - var zeroVal string - return zeroVal, nil - } - - ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) - if tmp, ok := rawArgs["id"]; ok { - return ec.unmarshalNString2string(ctx, tmp) - } - - var zeroVal string - return zeroVal, nil -} - func (ec *executionContext) field_Query_attestations_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -8041,112 +7925,6 @@ func (ec *executionContext) fieldContext_Query_attestations(ctx context.Context, return fc, nil } -func (ec *executionContext) _Query_attestation(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_attestation(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) { - directive0 := func(rctx context.Context) (any, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Attestation(rctx, fc.Args["tokenId"].(int), fc.Args["source"].(common.Address), fc.Args["id"].(string)) - } - - directive1 := func(ctx context.Context) (any, error) { - if ec.directives.RequiresVehicleToken == nil { - var zeroVal *model.Attestation - return zeroVal, errors.New("directive requiresVehicleToken is not implemented") - } - return ec.directives.RequiresVehicleToken(ctx, nil, directive0) - } - directive2 := func(ctx context.Context) (any, error) { - privileges, err := ec.unmarshalNPrivilege2ᚕgithubᚗcomᚋDIMOᚑNetworkᚋtelemetryᚑapiᚋinternalᚋgraphᚋmodelᚐPrivilegeᚄ(ctx, []any{"VEHICLE_RAW_DATA"}) - if err != nil { - var zeroVal *model.Attestation - return zeroVal, err - } - if ec.directives.RequiresAllOfPrivileges == nil { - var zeroVal *model.Attestation - return zeroVal, errors.New("directive requiresAllOfPrivileges is not implemented") - } - return ec.directives.RequiresAllOfPrivileges(ctx, nil, directive1, privileges) - } - - tmp, err := directive2(rctx) - if err != nil { - return nil, graphql.ErrorOnPath(ctx, err) - } - if tmp == nil { - return nil, nil - } - if data, ok := tmp.(*model.Attestation); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/DIMO-Network/telemetry-api/internal/graph/model.Attestation`, tmp) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*model.Attestation) - fc.Result = res - return ec.marshalOAttestation2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋtelemetryᚑapiᚋinternalᚋgraphᚋmodelᚐAttestation(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_attestation(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "ID": - return ec.fieldContext_Attestation_ID(ctx, field) - case "vehicleTokenId": - return ec.fieldContext_Attestation_vehicleTokenId(ctx, field) - case "time": - return ec.fieldContext_Attestation_time(ctx, field) - case "attestation": - return ec.fieldContext_Attestation_attestation(ctx, field) - case "type": - return ec.fieldContext_Attestation_type(ctx, field) - case "source": - return ec.fieldContext_Attestation_source(ctx, field) - case "dataVersion": - return ec.fieldContext_Attestation_dataVersion(ctx, field) - case "producer": - return ec.fieldContext_Attestation_producer(ctx, field) - case "signature": - return ec.fieldContext_Attestation_signature(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Attestation", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_attestation_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } - return fc, nil -} - func (ec *executionContext) _Query_deviceActivity(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_deviceActivity(ctx, field) if err != nil { @@ -25126,25 +24904,6 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) - case "attestation": - 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._Query_attestation(ctx, field) - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, - func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) - } - out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "deviceActivity": field := field diff --git a/internal/repositories/attestation/attestation.go b/internal/repositories/attestation/attestation.go index 9c2b9dee..c8c49a34 100644 --- a/internal/repositories/attestation/attestation.go +++ b/internal/repositories/attestation/attestation.go @@ -18,7 +18,6 @@ import ( type indexRepoService interface { GetAllCloudEvents(ctx context.Context, filter *grpc.SearchOptions, limit int32) ([]cloudevent.CloudEvent[json.RawMessage], error) - GetLatestCloudEvent(ctx context.Context, filter *grpc.SearchOptions) (cloudevent.CloudEvent[json.RawMessage], error) } type Repository struct { indexService indexRepoService @@ -116,49 +115,6 @@ func (r *Repository) GetAttestations(ctx context.Context, vehicleTokenID int, fi return attestations, nil } -// GetAttestations fetches attestations for the given vehicle. -func (r *Repository) GetAttestation(ctx context.Context, vehicleTokenID int, source common.Address, id string) (*model.Attestation, error) { - logger := r.getLogger(ctx, vehicleTokenID) - vehicleDID := cloudevent.ERC721DID{ - ChainID: r.chainID, - ContractAddress: r.vehicleAddress, - TokenID: new(big.Int).SetUint64(uint64(vehicleTokenID)), - }.String() - opts := &grpc.SearchOptions{ - Type: &wrapperspb.StringValue{Value: cloudevent.TypeAttestation}, - Subject: &wrapperspb.StringValue{Value: vehicleDID}, - } - - opts.Source = &wrapperspb.StringValue{Value: source.Hex()} - opts.Id = &wrapperspb.StringValue{Value: id} - - cloudEvent, err := r.indexService.GetLatestCloudEvent(ctx, opts) - if err != nil { - logger.Error().Err(err).Msgf("failed to get cloudevent %s from source: %s", id, source) - return nil, errors.New("internal error") - } - - tknID := int(vehicleTokenID) - att := &model.Attestation{ - ID: cloudEvent.ID, - VehicleTokenID: tknID, - Time: cloudEvent.Time, - Attestation: string(cloudEvent.Data), - Type: cloudEvent.Type, - Source: common.HexToAddress(cloudEvent.Source), - DataVersion: cloudEvent.DataVersion, - } - - signature, ok := cloudEvent.Extras["signature"].(string) - if !ok { - logger.Info().Str("id", cloudEvent.ID).Str("source", cloudEvent.Source).Msg("failed to pull signature") - return nil, fmt.Errorf("invalid format: attestation signature missing") - } - att.Signature = signature - - return att, nil -} - func (r *Repository) getLogger(ctx context.Context, vehicleTokenID int) zerolog.Logger { return zerolog.Ctx(ctx).With().Str("component", "attestation").Int("vehicleTokenId", vehicleTokenID).Logger() } diff --git a/internal/repositories/attestation/attestation_test.go b/internal/repositories/attestation/attestation_test.go index 055c7753..130d5f72 100644 --- a/internal/repositories/attestation/attestation_test.go +++ b/internal/repositories/attestation/attestation_test.go @@ -182,73 +182,3 @@ func TestGetAttestations(t *testing.T) { }) } } - -func TestGetAttestation(t *testing.T) { - // Initialize variables - ctx := context.Background() - validVehTknID := int(123) - - validSigner := common.BigToAddress(big.NewInt(1)) - - // Create mock controller - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - // Create mock services - mockService := NewMockindexRepoService(ctrl) - vehicleAddress := common.HexToAddress("0x123") - chainID := uint64(3) - - // Initialize the service with mock dependencies - att := attestation.New(mockService, chainID, vehicleAddress) - - vehicleDID := cloudevent.ERC721DID{ - ChainID: chainID, - ContractAddress: vehicleAddress, - TokenID: new(big.Int).SetUint64(uint64(validVehTknID)), - }.String() - - dataStr := `{"goodTires": true}` - defaultEvent := cloudevent.CloudEvent[json.RawMessage]{ - Data: json.RawMessage(dataStr), - } - defaultEvent.Time = time.Now() - defaultEvent.Source = validSigner.Hex() - defaultEvent.Subject = vehicleDID - defaultEvent.Extras = make(map[string]any) - defaultEvent.Extras["signature"] = "signature" - id := ksuid.New().String() - - // Test cases - tests := []struct { - name string - mockSetup func() - vehTknID int - filters *model.AttestationFilter - source common.Address - attID string - expectedErr bool - err error - }{ - { - name: "successful query, get attestation by id and source", - mockSetup: func() { - mockService.EXPECT().GetLatestCloudEvent(gomock.Any(), gomock.Any()).Return(defaultEvent, nil) - }, - vehTknID: validVehTknID, - source: validSigner, - attID: id, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Set up the mock expectations - tt.mockSetup() - // Call the method - _, err := att.GetAttestation(ctx, tt.vehTknID, tt.source, tt.attID) - require.ErrorIs(t, err, tt.err) - - }) - } -} diff --git a/schema/attestation.graphqls b/schema/attestation.graphqls index 542dd84b..22d1c9c8 100644 --- a/schema/attestation.graphqls +++ b/schema/attestation.graphqls @@ -19,34 +19,6 @@ extend type Query { @requiresAllOfPrivileges(privileges: [VEHICLE_RAW_DATA]) } -extend type Query { - """ - attestation returns an individual attestation for a given vehicle token based on attestation source and id. - - Required Privileges: [VEHICLE_RAW_DATA] - """ - attestation( - """ - The token ID of the vehicle. - """ - tokenId: Int! - - """ - The source of the attestation. - """ - source: Address! - - """ - The attestation id. - """ - id: String! - - ): Attestation - @requiresVehicleToken - @requiresAllOfPrivileges(privileges: [VEHICLE_RAW_DATA]) -} - - type Attestation { """ ID is the ID of the attestation. From 23fce985788123226e321e3a239a655f7930e4b8 Mon Sep 17 00:00:00 2001 From: Allyson-English Date: Thu, 29 May 2025 11:12:35 -0400 Subject: [PATCH 5/5] make generate --- internal/graph/attestation.resolvers.go | 12 ------------ .../attestation/attestation_mock_test.go | 15 --------------- 2 files changed, 27 deletions(-) diff --git a/internal/graph/attestation.resolvers.go b/internal/graph/attestation.resolvers.go index e92720d3..438adc13 100644 --- a/internal/graph/attestation.resolvers.go +++ b/internal/graph/attestation.resolvers.go @@ -14,15 +14,3 @@ import ( func (r *queryResolver) Attestations(ctx context.Context, tokenID int, filter *model.AttestationFilter) ([]*model.Attestation, error) { return r.AttestationRepo.GetAttestations(ctx, tokenID, filter) } - -// !!! WARNING !!! -// The code below was going to be deleted when updating resolvers. It has been copied here so you have -// one last chance to move it out of harms way if you want. There are two reasons this happens: -// - When renaming or deleting a resolver the old code will be put in here. You can safely delete -// it when you're done. -// - You have helper methods in this file. Move them out to keep these resolver files clean. -/* - func (r *queryResolver) Attestation(ctx context.Context, tokenID int, source common.Address, id string) (*model.Attestation, error) { - return r.AttestationRepo.GetAttestation(ctx, tokenID, source, id) -} -*/ diff --git a/internal/repositories/attestation/attestation_mock_test.go b/internal/repositories/attestation/attestation_mock_test.go index bb7a3c47..dcbc19df 100644 --- a/internal/repositories/attestation/attestation_mock_test.go +++ b/internal/repositories/attestation/attestation_mock_test.go @@ -57,18 +57,3 @@ func (mr *MockindexRepoServiceMockRecorder) GetAllCloudEvents(ctx, filter, limit mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllCloudEvents", reflect.TypeOf((*MockindexRepoService)(nil).GetAllCloudEvents), ctx, filter, limit) } - -// GetLatestCloudEvent mocks base method. -func (m *MockindexRepoService) GetLatestCloudEvent(ctx context.Context, filter *grpc.SearchOptions) (cloudevent.CloudEvent[json.RawMessage], error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetLatestCloudEvent", ctx, filter) - ret0, _ := ret[0].(cloudevent.CloudEvent[json.RawMessage]) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetLatestCloudEvent indicates an expected call of GetLatestCloudEvent. -func (mr *MockindexRepoServiceMockRecorder) GetLatestCloudEvent(ctx, filter any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestCloudEvent", reflect.TypeOf((*MockindexRepoService)(nil).GetLatestCloudEvent), ctx, filter) -}