Add third-party self-referential relations
Introduce a self-referential many-to-many relation table so a third party can have child third parties. Each relation is directional (parent to child); both directions can coexist as independent rows. Add a first_level boolean on third_parties (default true) with a filter on the list page that defaults to showing only first-level third parties. Frontend adds a "Third Parties" tab on the detail page where users can link existing third parties or create new ones from the common third party catalog (created as non-first-level). The list page gets a First Level/All toggle filter. Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -331,6 +331,7 @@ type Organization implements Node {
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ThirdPartyOrder
|
||||
filter: ThirdPartyFilter
|
||||
): ThirdPartyConnection! @goField(forceResolver: true)
|
||||
|
||||
thirdPartiesDocument: Document @goField(forceResolver: true)
|
||||
|
||||
@@ -177,6 +177,10 @@ input ThirdPartyOrder
|
||||
field: ThirdPartyOrderField!
|
||||
}
|
||||
|
||||
input ThirdPartyFilter {
|
||||
firstLevel: Boolean
|
||||
}
|
||||
|
||||
input ThirdPartyComplianceReportOrder
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.ThirdPartyComplianceReportOrderBy"
|
||||
@@ -269,6 +273,16 @@ type ThirdParty implements Node {
|
||||
legalName: String
|
||||
websiteUrl: String
|
||||
showOnTrustCenter: Boolean!
|
||||
firstLevel: Boolean!
|
||||
|
||||
childThirdParties(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: ThirdPartyOrder
|
||||
): ThirdPartyConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
@@ -460,6 +474,12 @@ extend type Mutation {
|
||||
publishThirdPartyList(
|
||||
input: PublishThirdPartyListInput!
|
||||
): PublishThirdPartyListPayload!
|
||||
createThirdPartyThirdPartyMapping(
|
||||
input: CreateThirdPartyThirdPartyMappingInput!
|
||||
): CreateThirdPartyThirdPartyMappingPayload!
|
||||
deleteThirdPartyThirdPartyMapping(
|
||||
input: DeleteThirdPartyThirdPartyMappingInput!
|
||||
): DeleteThirdPartyThirdPartyMappingPayload!
|
||||
}
|
||||
|
||||
input PublishThirdPartyListInput {
|
||||
@@ -494,6 +514,7 @@ input CreateThirdPartyInput {
|
||||
termsOfServiceUrl: String
|
||||
businessOwnerId: ID
|
||||
securityOwnerId: ID
|
||||
firstLevel: Boolean
|
||||
}
|
||||
|
||||
input UpdateThirdPartyInput {
|
||||
@@ -518,6 +539,7 @@ input UpdateThirdPartyInput {
|
||||
businessOwnerId: ID @goField(omittable: true)
|
||||
securityOwnerId: ID @goField(omittable: true)
|
||||
showOnTrustCenter: Boolean
|
||||
firstLevel: Boolean
|
||||
}
|
||||
|
||||
input DeleteThirdPartyInput {
|
||||
@@ -709,3 +731,21 @@ type AssessThirdPartyPayload {
|
||||
report: String!
|
||||
subprocessors: [ThirdPartySubprocessor!]!
|
||||
}
|
||||
|
||||
input CreateThirdPartyThirdPartyMappingInput {
|
||||
parentThirdPartyId: ID!
|
||||
childThirdPartyId: ID!
|
||||
}
|
||||
|
||||
type CreateThirdPartyThirdPartyMappingPayload {
|
||||
thirdPartyEdge: ThirdPartyEdge!
|
||||
}
|
||||
|
||||
input DeleteThirdPartyThirdPartyMappingInput {
|
||||
parentThirdPartyId: ID!
|
||||
childThirdPartyId: ID!
|
||||
}
|
||||
|
||||
type DeleteThirdPartyThirdPartyMappingPayload {
|
||||
removedThirdPartyId: ID!
|
||||
}
|
||||
|
||||
@@ -1271,7 +1271,7 @@ func (r *organizationResolver) CookieBanners(ctx context.Context, obj *types.Org
|
||||
}
|
||||
|
||||
// ThirdParties is the resolver for the thirdParties field.
|
||||
func (r *organizationResolver) ThirdParties(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ThirdPartyOrderBy) (*types.ThirdPartyConnection, error) {
|
||||
func (r *organizationResolver) ThirdParties(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ThirdPartyOrderBy, filter *types.ThirdPartyFilter) (*types.ThirdPartyConnection, error) {
|
||||
scope, err := r.authorize(ctx, obj.ID, probo.ActionThirdPartyList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1291,7 +1291,12 @@ func (r *organizationResolver) ThirdParties(ctx context.Context, obj *types.Orga
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
thirdPartyFilter := coredata.NewThirdPartyFilter(nil)
|
||||
var firstLevel *bool
|
||||
if filter != nil {
|
||||
firstLevel = filter.FirstLevel
|
||||
}
|
||||
|
||||
thirdPartyFilter := coredata.NewThirdPartyFilter(nil, firstLevel)
|
||||
|
||||
page, err := r.probo.ThirdParties.ListForOrganizationID(ctx, scope, obj.ID, cursor, thirdPartyFilter)
|
||||
if err != nil {
|
||||
|
||||
@@ -55,6 +55,7 @@ func (r *mutationResolver) CreateThirdParty(ctx context.Context, input types.Cre
|
||||
BusinessOwnerID: input.BusinessOwnerID,
|
||||
SecurityOwnerID: input.SecurityOwnerID,
|
||||
Countries: input.Countries,
|
||||
FirstLevel: input.FirstLevel,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
@@ -106,6 +107,7 @@ func (r *mutationResolver) UpdateThirdParty(ctx context.Context, input types.Upd
|
||||
BusinessOwnerID: gqlutils.UnwrapOmittable(input.BusinessOwnerID),
|
||||
SecurityOwnerID: gqlutils.UnwrapOmittable(input.SecurityOwnerID),
|
||||
ShowOnTrustCenter: input.ShowOnTrustCenter,
|
||||
FirstLevel: input.FirstLevel,
|
||||
Countries: input.Countries,
|
||||
},
|
||||
)
|
||||
@@ -594,6 +596,46 @@ func (r *mutationResolver) PublishThirdPartyList(ctx context.Context, input type
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateThirdPartyThirdPartyMapping is the resolver for the linkThirdPartyThirdParty field.
|
||||
func (r *mutationResolver) CreateThirdPartyThirdPartyMapping(ctx context.Context, input types.CreateThirdPartyThirdPartyMappingInput) (*types.CreateThirdPartyThirdPartyMappingPayload, error) {
|
||||
scope, err := r.authorize(ctx, input.ParentThirdPartyID, probo.ActionThirdPartyRelationCreate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
childThirdParty, err := r.probo.ThirdParties.CreateThirdPartyMapping(ctx, scope, input.ParentThirdPartyID, input.ChildThirdPartyID)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
||||
return nil, gqlutils.NotFound(ctx, err)
|
||||
}
|
||||
|
||||
r.logger.ErrorCtx(ctx, "cannot create third party mapping", log.Error(err))
|
||||
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.CreateThirdPartyThirdPartyMappingPayload{
|
||||
ThirdPartyEdge: types.NewThirdPartyEdge(childThirdParty, coredata.ThirdPartyOrderFieldName),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteThirdPartyThirdPartyMapping is the resolver for the deleteThirdPartyThirdPartyMapping field.
|
||||
func (r *mutationResolver) DeleteThirdPartyThirdPartyMapping(ctx context.Context, input types.DeleteThirdPartyThirdPartyMappingInput) (*types.DeleteThirdPartyThirdPartyMappingPayload, error) {
|
||||
scope, err := r.authorize(ctx, input.ParentThirdPartyID, probo.ActionThirdPartyRelationDelete)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := r.probo.ThirdParties.DeleteThirdPartyMapping(ctx, scope, input.ParentThirdPartyID, input.ChildThirdPartyID); err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot delete third party mapping", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.DeleteThirdPartyThirdPartyMappingPayload{
|
||||
RemovedThirdPartyID: input.ChildThirdPartyID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *thirdPartyResolver) Organization(ctx context.Context, obj *types.ThirdParty) (*types.Organization, error) {
|
||||
if _, err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||
@@ -830,6 +872,35 @@ func (r *thirdPartyResolver) SecurityOwner(ctx context.Context, obj *types.Third
|
||||
return types.NewProfile(securityOwner), nil
|
||||
}
|
||||
|
||||
// ChildThirdParties is the resolver for the childThirdParties field.
|
||||
func (r *thirdPartyResolver) ChildThirdParties(ctx context.Context, obj *types.ThirdParty, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ThirdPartyOrderBy) (*types.ThirdPartyConnection, error) {
|
||||
scope, err := r.authorize(ctx, obj.ID, probo.ActionThirdPartyRelationList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ThirdPartyOrderField]{
|
||||
Field: coredata.ThirdPartyOrderFieldName,
|
||||
Direction: page.OrderDirectionAsc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.ThirdPartyOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := r.probo.ThirdParties.ListForParentThirdPartyID(ctx, scope, obj.ID, cursor)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot list child third parties", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewThirdPartyConnection(page, r, obj.ID), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *thirdPartyResolver) Permission(ctx context.Context, obj *types.ThirdParty, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
@@ -963,6 +1034,19 @@ func (r *thirdPartyConnectionResolver) TotalCount(ctx context.Context, obj *type
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
case *thirdPartyResolver:
|
||||
if _, err := r.authorize(ctx, obj.ParentID, probo.ActionThirdPartyRelationList); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
count, err := r.probo.ThirdParties.CountForParentThirdPartyID(ctx, scope, obj.ParentID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot count child third parties", log.Error(err))
|
||||
|
||||
return 0, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
@@ -1145,3 +1229,15 @@ type thirdPartyContactResolver struct{ *Resolver }
|
||||
type thirdPartyDataPrivacyAgreementResolver struct{ *Resolver }
|
||||
type thirdPartyRiskAssessmentResolver struct{ *Resolver }
|
||||
type thirdPartyServiceResolver struct{ *Resolver }
|
||||
|
||||
// !!! 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 *mutationResolver) UncreateThirdPartyThirdPartyMapping(ctx context.Context, input types.UncreateThirdPartyThirdPartyMappingInput) (*types.UncreateThirdPartyThirdPartyMappingPayload, error) {
|
||||
panic(fmt.Errorf("not implemented: UncreateThirdPartyThirdPartyMapping - uncreateThirdPartyThirdPartyMapping"))
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -84,6 +84,7 @@ func NewThirdParty(v *coredata.ThirdParty) *ThirdParty {
|
||||
WebsiteURL: v.WebsiteURL,
|
||||
Category: v.Category,
|
||||
ShowOnTrustCenter: v.ShowOnTrustCenter,
|
||||
FirstLevel: v.FirstLevel,
|
||||
Countries: v.Countries,
|
||||
UpdatedAt: v.UpdatedAt,
|
||||
CreatedAt: v.CreatedAt,
|
||||
|
||||
@@ -70,7 +70,7 @@ func (r *Resolver) ListThirdPartiesTool(ctx context.Context, req *mcp.CallToolRe
|
||||
|
||||
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
||||
|
||||
thirdPartyFilter := coredata.NewThirdPartyFilter(nil)
|
||||
thirdPartyFilter := coredata.NewThirdPartyFilter(nil, input.FirstLevel)
|
||||
|
||||
page, err := prb.ThirdParties.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor, thirdPartyFilter)
|
||||
if err != nil {
|
||||
@@ -6148,6 +6148,59 @@ func (r *Resolver) MoveTrackerResourceToCategoryTool(ctx context.Context, req *m
|
||||
return nil, types.MoveTrackerResourceToCategoryOutput{TrackerResource: types.NewTrackerResource(result.TrackerResource)}, nil
|
||||
}
|
||||
|
||||
func (r *Resolver) CreateThirdPartyThirdPartyMappingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateThirdPartyThirdPartyMappingInput) (*mcp.CallToolResult, types.CreateThirdPartyThirdPartyMappingOutput, error) {
|
||||
scope, err := r.Authorize(ctx, input.ParentThirdPartyID, probo.ActionThirdPartyRelationCreate)
|
||||
if err != nil {
|
||||
return nil, types.CreateThirdPartyThirdPartyMappingOutput{}, err
|
||||
}
|
||||
|
||||
if _, err := r.proboSvc.ThirdParties.CreateThirdPartyMapping(ctx, scope, input.ParentThirdPartyID, input.ChildThirdPartyID); err != nil {
|
||||
return nil, types.CreateThirdPartyThirdPartyMappingOutput{}, fmt.Errorf("cannot create third party mapping: %w", err)
|
||||
}
|
||||
|
||||
return nil, types.CreateThirdPartyThirdPartyMappingOutput{}, nil
|
||||
}
|
||||
|
||||
func (r *Resolver) DeleteThirdPartyThirdPartyMappingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteThirdPartyThirdPartyMappingInput) (*mcp.CallToolResult, types.DeleteThirdPartyThirdPartyMappingOutput, error) {
|
||||
scope, err := r.Authorize(ctx, input.ParentThirdPartyID, probo.ActionThirdPartyRelationDelete)
|
||||
if err != nil {
|
||||
return nil, types.DeleteThirdPartyThirdPartyMappingOutput{}, err
|
||||
}
|
||||
|
||||
if err := r.proboSvc.ThirdParties.DeleteThirdPartyMapping(ctx, scope, input.ParentThirdPartyID, input.ChildThirdPartyID); err != nil {
|
||||
return nil, types.DeleteThirdPartyThirdPartyMappingOutput{}, fmt.Errorf("cannot delete third party mapping: %w", err)
|
||||
}
|
||||
|
||||
return nil, types.DeleteThirdPartyThirdPartyMappingOutput{}, nil
|
||||
}
|
||||
|
||||
func (r *Resolver) ListChildThirdPartiesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListChildThirdPartiesInput) (*mcp.CallToolResult, types.ListChildThirdPartiesOutput, error) {
|
||||
scope, err := r.Authorize(ctx, input.ParentThirdPartyID, probo.ActionThirdPartyRelationList)
|
||||
if err != nil {
|
||||
return nil, types.ListChildThirdPartiesOutput{}, err
|
||||
}
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.ThirdPartyOrderField]{
|
||||
Field: coredata.ThirdPartyOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if input.OrderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.ThirdPartyOrderField]{
|
||||
Field: input.OrderBy.Field,
|
||||
Direction: input.OrderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
||||
|
||||
page, err := r.proboSvc.ThirdParties.ListForParentThirdPartyID(ctx, scope, input.ParentThirdPartyID, cursor)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot list child third parties: %w", err))
|
||||
}
|
||||
|
||||
return nil, types.NewListChildThirdPartiesOutput(page), nil
|
||||
}
|
||||
|
||||
func (r *Resolver) ListRiskAssessmentsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRiskAssessmentsInput) (*mcp.CallToolResult, types.ListRiskAssessmentsOutput, error) {
|
||||
scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionRiskAssessmentList)
|
||||
if err != nil {
|
||||
|
||||
@@ -627,6 +627,9 @@ components:
|
||||
organization_id:
|
||||
$ref: "#/components/schemas/GID"
|
||||
description: Organization ID
|
||||
first_level:
|
||||
type: boolean
|
||||
description: Filter by first-level status
|
||||
order_by:
|
||||
$ref: "#/components/schemas/ThirdPartyOrderBy"
|
||||
description: ThirdParty order by
|
||||
@@ -650,6 +653,69 @@ components:
|
||||
items:
|
||||
$ref: "#/components/schemas/ThirdParty"
|
||||
|
||||
CreateThirdPartyThirdPartyMappingInput:
|
||||
type: object
|
||||
required:
|
||||
- parent_third_party_id
|
||||
- child_third_party_id
|
||||
properties:
|
||||
parent_third_party_id:
|
||||
$ref: "#/components/schemas/GID"
|
||||
description: Parent third party ID
|
||||
child_third_party_id:
|
||||
$ref: "#/components/schemas/GID"
|
||||
description: Child third party ID
|
||||
|
||||
CreateThirdPartyThirdPartyMappingOutput:
|
||||
type: object
|
||||
|
||||
DeleteThirdPartyThirdPartyMappingInput:
|
||||
type: object
|
||||
required:
|
||||
- parent_third_party_id
|
||||
- child_third_party_id
|
||||
properties:
|
||||
parent_third_party_id:
|
||||
$ref: "#/components/schemas/GID"
|
||||
description: Parent third party ID
|
||||
child_third_party_id:
|
||||
$ref: "#/components/schemas/GID"
|
||||
description: Child third party ID
|
||||
|
||||
DeleteThirdPartyThirdPartyMappingOutput:
|
||||
type: object
|
||||
|
||||
ListChildThirdPartiesInput:
|
||||
type: object
|
||||
required:
|
||||
- parent_third_party_id
|
||||
properties:
|
||||
parent_third_party_id:
|
||||
$ref: "#/components/schemas/GID"
|
||||
description: Parent third party ID
|
||||
order_by:
|
||||
$ref: "#/components/schemas/ThirdPartyOrderBy"
|
||||
description: ThirdParty order by
|
||||
size:
|
||||
type: integer
|
||||
description: Page size
|
||||
cursor:
|
||||
$ref: "#/components/schemas/CursorKey"
|
||||
description: Page cursor
|
||||
|
||||
ListChildThirdPartiesOutput:
|
||||
type: object
|
||||
required:
|
||||
- thirdParties
|
||||
properties:
|
||||
next_cursor:
|
||||
$ref: "#/components/schemas/CursorKey"
|
||||
description: Next cursor
|
||||
thirdParties:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/ThirdParty"
|
||||
|
||||
ThirdParty:
|
||||
type: object
|
||||
required:
|
||||
@@ -657,6 +723,7 @@ components:
|
||||
- name
|
||||
- organization_id
|
||||
- category
|
||||
- first_level
|
||||
- created_at
|
||||
- updated_at
|
||||
properties:
|
||||
@@ -780,6 +847,9 @@ components:
|
||||
- string
|
||||
- "null"
|
||||
description: Trust page URL
|
||||
first_level:
|
||||
type: boolean
|
||||
description: Whether this is a first-level third party
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
@@ -11788,6 +11858,31 @@ tools:
|
||||
$ref: "#/components/schemas/ListThirdPartiesInput"
|
||||
outputSchema:
|
||||
$ref: "#/components/schemas/ListThirdPartiesOutput"
|
||||
- name: createThirdPartyThirdPartyMapping
|
||||
description: Link a child third party to a parent third party
|
||||
hints:
|
||||
readonly: false
|
||||
inputSchema:
|
||||
$ref: "#/components/schemas/CreateThirdPartyThirdPartyMappingInput"
|
||||
outputSchema:
|
||||
$ref: "#/components/schemas/CreateThirdPartyThirdPartyMappingOutput"
|
||||
- name: deleteThirdPartyThirdPartyMapping
|
||||
description: Unlink a child third party from a parent third party
|
||||
hints:
|
||||
readonly: false
|
||||
inputSchema:
|
||||
$ref: "#/components/schemas/DeleteThirdPartyThirdPartyMappingInput"
|
||||
outputSchema:
|
||||
$ref: "#/components/schemas/DeleteThirdPartyThirdPartyMappingOutput"
|
||||
- name: listChildThirdParties
|
||||
description: List child third parties linked to a parent third party
|
||||
hints:
|
||||
readonly: true
|
||||
idempotent: true
|
||||
inputSchema:
|
||||
$ref: "#/components/schemas/ListChildThirdPartiesInput"
|
||||
outputSchema:
|
||||
$ref: "#/components/schemas/ListChildThirdPartiesOutput"
|
||||
- name: listUsers
|
||||
description: List all users for the organization
|
||||
hints:
|
||||
|
||||
@@ -87,6 +87,7 @@ func NewThirdParty(v *coredata.ThirdParty) *ThirdParty {
|
||||
TermsOfServiceURL: v.TermsOfServiceURL,
|
||||
SecurityPageURL: v.SecurityPageURL,
|
||||
TrustPageURL: v.TrustPageURL,
|
||||
FirstLevel: v.FirstLevel,
|
||||
CreatedAt: v.CreatedAt,
|
||||
UpdatedAt: v.UpdatedAt,
|
||||
}
|
||||
@@ -111,6 +112,25 @@ func NewListThirdPartiesOutput(thirdPartyPage *page.Page[*coredata.ThirdParty, c
|
||||
}
|
||||
}
|
||||
|
||||
func NewListChildThirdPartiesOutput(thirdPartyPage *page.Page[*coredata.ThirdParty, coredata.ThirdPartyOrderField]) ListChildThirdPartiesOutput {
|
||||
thirdParties := make([]*ThirdParty, 0, len(thirdPartyPage.Data))
|
||||
for _, v := range thirdPartyPage.Data {
|
||||
thirdParties = append(thirdParties, NewThirdParty(v))
|
||||
}
|
||||
|
||||
var nextCursor *page.CursorKey
|
||||
|
||||
if len(thirdPartyPage.Data) > 0 {
|
||||
cursorKey := thirdPartyPage.Data[len(thirdPartyPage.Data)-1].CursorKey(thirdPartyPage.Cursor.OrderBy.Field)
|
||||
nextCursor = &cursorKey
|
||||
}
|
||||
|
||||
return ListChildThirdPartiesOutput{
|
||||
NextCursor: nextCursor,
|
||||
ThirdParties: thirdParties,
|
||||
}
|
||||
}
|
||||
|
||||
func NewAddThirdPartyOutput(v *coredata.ThirdParty) AddThirdPartyOutput {
|
||||
return AddThirdPartyOutput{
|
||||
ThirdParty: NewThirdParty(v),
|
||||
|
||||
Reference in New Issue
Block a user