Add vendor services
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -342,6 +342,20 @@ enum VendorContactOrderField
|
||||
)
|
||||
}
|
||||
|
||||
enum VendorServiceOrderField
|
||||
@goModel(
|
||||
model: "github.com/getprobo/probo/pkg/coredata.VendorServiceOrderField"
|
||||
) {
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/coredata.VendorServiceOrderFieldCreatedAt"
|
||||
)
|
||||
NAME
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/coredata.VendorServiceOrderFieldName"
|
||||
)
|
||||
}
|
||||
|
||||
enum OrganizationOrderField
|
||||
@goModel(
|
||||
model: "github.com/getprobo/probo/pkg/coredata.OrganizationOrderField"
|
||||
@@ -801,6 +815,14 @@ input VendorContactOrder
|
||||
field: VendorContactOrderField!
|
||||
}
|
||||
|
||||
input VendorServiceOrder
|
||||
@goModel(
|
||||
model: "github.com/getprobo/probo/pkg/server/api/console/v1/types.VendorServiceOrderBy"
|
||||
) {
|
||||
direction: OrderDirection!
|
||||
field: VendorServiceOrderField!
|
||||
}
|
||||
|
||||
input OrganizationOrder {
|
||||
direction: OrderDirection!
|
||||
field: OrganizationOrderField!
|
||||
@@ -1064,6 +1086,14 @@ type Vendor implements Node {
|
||||
orderBy: VendorContactOrder
|
||||
): VendorContactConnection! @goField(forceResolver: true)
|
||||
|
||||
services(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: VendorServiceOrder
|
||||
): VendorServiceConnection! @goField(forceResolver: true)
|
||||
|
||||
riskAssessments(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
@@ -1128,6 +1158,15 @@ type VendorContact implements Node {
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type VendorService implements Node {
|
||||
id: ID!
|
||||
vendor: Vendor! @goField(forceResolver: true)
|
||||
name: String!
|
||||
description: String
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type VendorDataPrivacyAgreement implements Node {
|
||||
id: ID!
|
||||
vendor: Vendor! @goField(forceResolver: true)
|
||||
@@ -1652,6 +1691,16 @@ type VendorContactEdge {
|
||||
node: VendorContact!
|
||||
}
|
||||
|
||||
type VendorServiceConnection {
|
||||
edges: [VendorServiceEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type VendorServiceEdge {
|
||||
cursor: CursorKey!
|
||||
node: VendorService!
|
||||
}
|
||||
|
||||
type ConnectorConnection {
|
||||
edges: [ConnectorEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
@@ -1796,6 +1845,11 @@ type Mutation {
|
||||
updateVendorContact(input: UpdateVendorContactInput!): UpdateVendorContactPayload!
|
||||
deleteVendorContact(input: DeleteVendorContactInput!): DeleteVendorContactPayload!
|
||||
|
||||
# Vendor Service mutations
|
||||
createVendorService(input: CreateVendorServiceInput!): CreateVendorServicePayload!
|
||||
updateVendorService(input: UpdateVendorServiceInput!): UpdateVendorServicePayload!
|
||||
deleteVendorService(input: DeleteVendorServiceInput!): DeleteVendorServicePayload!
|
||||
|
||||
# Framework mutations
|
||||
createFramework(input: CreateFrameworkInput!): CreateFrameworkPayload!
|
||||
updateFramework(input: UpdateFrameworkInput!): UpdateFrameworkPayload!
|
||||
@@ -2089,6 +2143,26 @@ input DeleteVendorContactInput {
|
||||
vendorContactId: ID!
|
||||
}
|
||||
|
||||
input CreateVendorServiceInput {
|
||||
vendorId: ID!
|
||||
name: String!
|
||||
description: String
|
||||
url: String
|
||||
type: String
|
||||
}
|
||||
|
||||
input UpdateVendorServiceInput {
|
||||
id: ID!
|
||||
name: String
|
||||
description: String
|
||||
url: String
|
||||
type: String
|
||||
}
|
||||
|
||||
input DeleteVendorServiceInput {
|
||||
vendorServiceId: ID!
|
||||
}
|
||||
|
||||
input CreatePeopleInput {
|
||||
organizationId: ID!
|
||||
fullName: String!
|
||||
@@ -2570,6 +2644,18 @@ type DeleteVendorContactPayload {
|
||||
deletedVendorContactId: ID!
|
||||
}
|
||||
|
||||
type CreateVendorServicePayload {
|
||||
vendorServiceEdge: VendorServiceEdge!
|
||||
}
|
||||
|
||||
type UpdateVendorServicePayload {
|
||||
vendorService: VendorService!
|
||||
}
|
||||
|
||||
type DeleteVendorServicePayload {
|
||||
deletedVendorServiceId: ID!
|
||||
}
|
||||
|
||||
type CreatePeoplePayload {
|
||||
peopleEdge: PeopleEdge!
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -505,6 +505,18 @@ type CreateVendorRiskAssessmentPayload struct {
|
||||
VendorRiskAssessmentEdge *VendorRiskAssessmentEdge `json:"vendorRiskAssessmentEdge"`
|
||||
}
|
||||
|
||||
type CreateVendorServiceInput struct {
|
||||
VendorID gid.GID `json:"vendorId"`
|
||||
Name string `json:"name"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
URL *string `json:"url,omitempty"`
|
||||
Type *string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type CreateVendorServicePayload struct {
|
||||
VendorServiceEdge *VendorServiceEdge `json:"vendorServiceEdge"`
|
||||
}
|
||||
|
||||
type Datum struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -750,6 +762,14 @@ type DeleteVendorPayload struct {
|
||||
DeletedVendorID gid.GID `json:"deletedVendorId"`
|
||||
}
|
||||
|
||||
type DeleteVendorServiceInput struct {
|
||||
VendorServiceID gid.GID `json:"vendorServiceId"`
|
||||
}
|
||||
|
||||
type DeleteVendorServicePayload struct {
|
||||
DeletedVendorServiceID gid.GID `json:"deletedVendorServiceId"`
|
||||
}
|
||||
|
||||
type Document struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Title string `json:"title"`
|
||||
@@ -1519,6 +1539,18 @@ type UpdateVendorPayload struct {
|
||||
Vendor *Vendor `json:"vendor"`
|
||||
}
|
||||
|
||||
type UpdateVendorServiceInput struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
URL *string `json:"url,omitempty"`
|
||||
Type *string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateVendorServicePayload struct {
|
||||
VendorService *VendorService `json:"vendorService"`
|
||||
}
|
||||
|
||||
type UploadAuditReportInput struct {
|
||||
AuditID gid.GID `json:"auditId"`
|
||||
File graphql.Upload `json:"file"`
|
||||
@@ -1614,6 +1646,7 @@ type Vendor struct {
|
||||
BusinessAssociateAgreement *VendorBusinessAssociateAgreement `json:"businessAssociateAgreement,omitempty"`
|
||||
DataPrivacyAgreement *VendorDataPrivacyAgreement `json:"dataPrivacyAgreement,omitempty"`
|
||||
Contacts *VendorContactConnection `json:"contacts"`
|
||||
Services *VendorServiceConnection `json:"services"`
|
||||
RiskAssessments *VendorRiskAssessmentConnection `json:"riskAssessments"`
|
||||
BusinessOwner *People `json:"businessOwner,omitempty"`
|
||||
SecurityOwner *People `json:"securityOwner,omitempty"`
|
||||
@@ -1753,6 +1786,28 @@ type VendorRiskAssessmentOrder struct {
|
||||
Direction page.OrderDirection `json:"direction"`
|
||||
}
|
||||
|
||||
type VendorService struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Vendor *Vendor `json:"vendor"`
|
||||
Name string `json:"name"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (VendorService) IsNode() {}
|
||||
func (this VendorService) GetID() gid.GID { return this.ID }
|
||||
|
||||
type VendorServiceConnection struct {
|
||||
Edges []*VendorServiceEdge `json:"edges"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
type VendorServiceEdge struct {
|
||||
Cursor page.CursorKey `json:"cursor"`
|
||||
Node *VendorService `json:"node"`
|
||||
}
|
||||
|
||||
type Viewer struct {
|
||||
ID gid.GID `json:"id"`
|
||||
User *User `json:"user"`
|
||||
|
||||
54
pkg/server/api/console/v1/types/vendor_service.go
Normal file
54
pkg/server/api/console/v1/types/vendor_service.go
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/getprobo/probo/pkg/coredata"
|
||||
"github.com/getprobo/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
VendorServiceOrderBy OrderBy[coredata.VendorServiceOrderField]
|
||||
)
|
||||
|
||||
func NewVendorServiceConnection(p *page.Page[*coredata.VendorService, coredata.VendorServiceOrderField]) *VendorServiceConnection {
|
||||
var edges = make([]*VendorServiceEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewVendorServiceEdge(p.Data[i], p.Cursor.OrderBy.Field)
|
||||
}
|
||||
|
||||
return &VendorServiceConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewVendorServiceEdge(s *coredata.VendorService, orderBy coredata.VendorServiceOrderField) *VendorServiceEdge {
|
||||
return &VendorServiceEdge{
|
||||
Cursor: s.CursorKey(orderBy),
|
||||
Node: NewVendorService(s),
|
||||
}
|
||||
}
|
||||
|
||||
func NewVendorService(s *coredata.VendorService) *VendorService {
|
||||
return &VendorService{
|
||||
ID: s.ID,
|
||||
Name: s.Name,
|
||||
Description: s.Description,
|
||||
CreatedAt: s.CreatedAt,
|
||||
UpdatedAt: s.UpdatedAt,
|
||||
}
|
||||
}
|
||||
@@ -1430,6 +1430,60 @@ func (r *mutationResolver) DeleteVendorContact(ctx context.Context, input types.
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateVendorService is the resolver for the createVendorService field.
|
||||
func (r *mutationResolver) CreateVendorService(ctx context.Context, input types.CreateVendorServiceInput) (*types.CreateVendorServicePayload, error) {
|
||||
prb := r.ProboService(ctx, input.VendorID.TenantID())
|
||||
|
||||
req := probo.CreateVendorServiceRequest{
|
||||
VendorID: input.VendorID,
|
||||
Name: input.Name,
|
||||
Description: input.Description,
|
||||
}
|
||||
|
||||
vendorService, err := prb.VendorServices.Create(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create vendor service: %w", err)
|
||||
}
|
||||
|
||||
return &types.CreateVendorServicePayload{
|
||||
VendorServiceEdge: types.NewVendorServiceEdge(vendorService, coredata.VendorServiceOrderFieldCreatedAt),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateVendorService is the resolver for the updateVendorService field.
|
||||
func (r *mutationResolver) UpdateVendorService(ctx context.Context, input types.UpdateVendorServiceInput) (*types.UpdateVendorServicePayload, error) {
|
||||
prb := r.ProboService(ctx, input.ID.TenantID())
|
||||
|
||||
req := probo.UpdateVendorServiceRequest{
|
||||
ID: input.ID,
|
||||
Name: input.Name,
|
||||
Description: &input.Description,
|
||||
}
|
||||
|
||||
vendorService, err := prb.VendorServices.Update(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update vendor service: %w", err)
|
||||
}
|
||||
|
||||
return &types.UpdateVendorServicePayload{
|
||||
VendorService: types.NewVendorService(vendorService),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteVendorService is the resolver for the deleteVendorService field.
|
||||
func (r *mutationResolver) DeleteVendorService(ctx context.Context, input types.DeleteVendorServiceInput) (*types.DeleteVendorServicePayload, error) {
|
||||
prb := r.ProboService(ctx, input.VendorServiceID.TenantID())
|
||||
|
||||
err := prb.VendorServices.Delete(ctx, input.VendorServiceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to delete vendor service: %w", err)
|
||||
}
|
||||
|
||||
return &types.DeleteVendorServicePayload{
|
||||
DeletedVendorServiceID: input.VendorServiceID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateFramework is the resolver for the createFramework field.
|
||||
func (r *mutationResolver) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) {
|
||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||
@@ -3507,6 +3561,12 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
|
||||
panic(fmt.Errorf("cannot get vendor contact: %w", err))
|
||||
}
|
||||
return types.NewVendorContact(vendorContact), nil
|
||||
case coredata.VendorServiceEntityType:
|
||||
vendorService, err := prb.VendorServices.Get(ctx, id)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot get vendor service: %w", err))
|
||||
}
|
||||
return types.NewVendorService(vendorService), nil
|
||||
case coredata.DocumentVersionEntityType:
|
||||
documentVersion, err := prb.Documents.GetVersion(ctx, id)
|
||||
if err != nil {
|
||||
@@ -3993,6 +4053,31 @@ func (r *vendorResolver) Contacts(ctx context.Context, obj *types.Vendor, first
|
||||
return types.NewVendorContactConnection(page), nil
|
||||
}
|
||||
|
||||
// Services is the resolver for the services field.
|
||||
func (r *vendorResolver) Services(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorServiceOrderBy) (*types.VendorServiceConnection, error) {
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.VendorServiceOrderField]{
|
||||
Field: coredata.VendorServiceOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.VendorServiceOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.VendorServices.List(ctx, obj.ID, cursor)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to list vendor services: %w", err))
|
||||
}
|
||||
|
||||
return types.NewVendorServiceConnection(page), nil
|
||||
}
|
||||
|
||||
// RiskAssessments is the resolver for the riskAssessments field.
|
||||
func (r *vendorResolver) RiskAssessments(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) (*types.VendorRiskAssessmentConnection, error) {
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
@@ -4206,6 +4291,24 @@ func (r *vendorRiskAssessmentResolver) AssessedBy(ctx context.Context, obj *type
|
||||
return types.NewPeople(people), nil
|
||||
}
|
||||
|
||||
// Vendor is the resolver for the vendor field.
|
||||
func (r *vendorServiceResolver) Vendor(ctx context.Context, obj *types.VendorService) (*types.Vendor, error) {
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
// Get the vendor service to access the VendorID
|
||||
vendorService, err := prb.VendorServices.Get(ctx, obj.ID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to get vendor service: %w", err))
|
||||
}
|
||||
|
||||
vendor, err := prb.Vendors.Get(ctx, vendorService.VendorID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to get vendor: %w", err))
|
||||
}
|
||||
|
||||
return types.NewVendor(vendor), nil
|
||||
}
|
||||
|
||||
// Organizations is the resolver for the organizations field.
|
||||
func (r *viewerResolver) Organizations(ctx context.Context, obj *types.Viewer, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrganizationOrder, filter *types.OrganizationFilter) (*types.OrganizationConnection, error) {
|
||||
user := UserFromContext(ctx)
|
||||
@@ -4391,6 +4494,9 @@ func (r *Resolver) VendorRiskAssessment() schema.VendorRiskAssessmentResolver {
|
||||
return &vendorRiskAssessmentResolver{r}
|
||||
}
|
||||
|
||||
// VendorService returns schema.VendorServiceResolver implementation.
|
||||
func (r *Resolver) VendorService() schema.VendorServiceResolver { return &vendorServiceResolver{r} }
|
||||
|
||||
// Viewer returns schema.ViewerResolver implementation.
|
||||
func (r *Resolver) Viewer() schema.ViewerResolver { return &viewerResolver{r} }
|
||||
|
||||
@@ -4434,4 +4540,5 @@ type vendorConnectionResolver struct{ *Resolver }
|
||||
type vendorContactResolver struct{ *Resolver }
|
||||
type vendorDataPrivacyAgreementResolver struct{ *Resolver }
|
||||
type vendorRiskAssessmentResolver struct{ *Resolver }
|
||||
type vendorServiceResolver struct{ *Resolver }
|
||||
type viewerResolver struct{ *Resolver }
|
||||
|
||||
Reference in New Issue
Block a user