From ee456aaa0f13951464ddaf78ed7e0a4c539fb951 Mon Sep 17 00:00:00 2001 From: Sacha Al Himdani Date: Wed, 13 Aug 2025 16:27:52 +0200 Subject: [PATCH] Add dpa on vendors Signed-off-by: Sacha Al Himdani --- apps/console/src/hooks/graph/VendorGraph.ts | 1 + .../VendorGraphNodeQuery.graphql.ts | 68 +- .../DeleteDataPrivacyAgreementDialog.tsx | 89 + .../EditDataPrivacyAgreementDialog.tsx | 135 ++ .../UploadDataPrivacyAgreementDialog.tsx | 178 ++ ...aPrivacyAgreementDialogMutation.graphql.ts | 92 + ...aPrivacyAgreementDialogMutation.graphql.ts | 139 ++ ...aPrivacyAgreementDialogMutation.graphql.ts | 149 ++ .../vendors/tabs/VendorOverviewTab.tsx | 88 +- ...TabDataPrivacyAgreementFragment.graphql.ts | 95 + pkg/coredata/entity_type_reg.go | 1 + pkg/coredata/migrations/20250813T141529Z.sql | 29 + pkg/coredata/vendor_data_privacy_agreement.go | 280 +++ ...ndor_data_privacy_agreement_order_field.go | 41 + pkg/probo/service.go | 2 + ...or_business_associate_agreement_service.go | 12 +- .../vendor_data_privacy_agreement_service.go | 346 ++++ pkg/server/api/console/v1/schema.graphql | 54 + pkg/server/api/console/v1/schema/schema.go | 1673 +++++++++++++++++ pkg/server/api/console/v1/types/types.go | 46 + .../v1/types/vendor_data_privacy_agreement.go | 31 + pkg/server/api/console/v1/v1_resolver.go | 104 + 22 files changed, 3618 insertions(+), 35 deletions(-) create mode 100644 apps/console/src/pages/organizations/vendors/dialogs/DeleteDataPrivacyAgreementDialog.tsx create mode 100644 apps/console/src/pages/organizations/vendors/dialogs/EditDataPrivacyAgreementDialog.tsx create mode 100644 apps/console/src/pages/organizations/vendors/dialogs/UploadDataPrivacyAgreementDialog.tsx create mode 100644 apps/console/src/pages/organizations/vendors/dialogs/__generated__/DeleteDataPrivacyAgreementDialogMutation.graphql.ts create mode 100644 apps/console/src/pages/organizations/vendors/dialogs/__generated__/EditDataPrivacyAgreementDialogMutation.graphql.ts create mode 100644 apps/console/src/pages/organizations/vendors/dialogs/__generated__/UploadDataPrivacyAgreementDialogMutation.graphql.ts create mode 100644 apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorOverviewTabDataPrivacyAgreementFragment.graphql.ts create mode 100644 pkg/coredata/migrations/20250813T141529Z.sql create mode 100644 pkg/coredata/vendor_data_privacy_agreement.go create mode 100644 pkg/coredata/vendor_data_privacy_agreement_order_field.go create mode 100644 pkg/probo/vendor_data_privacy_agreement_service.go create mode 100644 pkg/server/api/console/v1/types/vendor_data_privacy_agreement.go diff --git a/apps/console/src/hooks/graph/VendorGraph.ts b/apps/console/src/hooks/graph/VendorGraph.ts index a1689e57f..e42611062 100644 --- a/apps/console/src/hooks/graph/VendorGraph.ts +++ b/apps/console/src/hooks/graph/VendorGraph.ts @@ -155,6 +155,7 @@ export const vendorNodeQuery = graphql` ...VendorContactsTabFragment ...VendorRiskAssessmentTabFragment ...VendorOverviewTabBusinessAssociateAgreementFragment + ...VendorOverviewTabDataPrivacyAgreementFragment } } viewer { diff --git a/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts index 22cc41b4c..d38447519 100644 --- a/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/VendorGraphNodeQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -19,7 +19,7 @@ export type VendorGraphNodeQuery$data = { readonly id?: string; readonly name?: string; readonly websiteUrl?: string | null | undefined; - readonly " $fragmentSpreads": FragmentRefs<"VendorComplianceTabFragment" | "VendorContactsTabFragment" | "VendorOverviewTabBusinessAssociateAgreementFragment" | "VendorRiskAssessmentTabFragment" | "useVendorFormFragment">; + readonly " $fragmentSpreads": FragmentRefs<"VendorComplianceTabFragment" | "VendorContactsTabFragment" | "VendorOverviewTabBusinessAssociateAgreementFragment" | "VendorOverviewTabDataPrivacyAgreementFragment" | "VendorRiskAssessmentTabFragment" | "useVendorFormFragment">; }; readonly viewer: { readonly user: { @@ -198,7 +198,27 @@ v21 = { "kind": "ScalarField", "name": "createdAt", "storageKey": null -}; +}, +v22 = [ + (v3/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fileName", + "storageKey": null + }, + (v11/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "validFrom", + "storageKey": null + }, + (v10/*: any*/), + (v21/*: any*/) +]; return { "fragment": { "argumentDefinitions": [ @@ -247,6 +267,11 @@ return { "args": null, "kind": "FragmentSpread", "name": "VendorOverviewTabBusinessAssociateAgreementFragment" + }, + { + "args": null, + "kind": "FragmentSpread", + "name": "VendorOverviewTabDataPrivacyAgreementFragment" } ], "type": "Vendor", @@ -666,26 +691,17 @@ return { "kind": "LinkedField", "name": "businessAssociateAgreement", "plural": false, - "selections": [ - (v3/*: any*/), - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "fileName", - "storageKey": null - }, - (v11/*: any*/), - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "validFrom", - "storageKey": null - }, - (v10/*: any*/), - (v21/*: any*/) - ], + "selections": (v22/*: any*/), + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "VendorDataPrivacyAgreement", + "kind": "LinkedField", + "name": "dataPrivacyAgreement", + "plural": false, + "selections": (v22/*: any*/), "storageKey": null } ], @@ -723,16 +739,16 @@ return { ] }, "params": { - "cacheID": "506d89b503073e18cbf657aec5d62c71", + "cacheID": "5e87c78ed85f28f7390e2aada6c241e8", "id": null, "metadata": {}, "name": "VendorGraphNodeQuery", "operationKind": "query", - "text": "query VendorGraphNodeQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n websiteUrl\n ...useVendorFormFragment\n ...VendorComplianceTabFragment\n ...VendorContactsTabFragment\n ...VendorRiskAssessmentTabFragment\n ...VendorOverviewTabBusinessAssociateAgreementFragment\n }\n id\n }\n viewer {\n user {\n people(organizationId: $organizationId) {\n id\n }\n id\n }\n id\n }\n}\n\nfragment VendorComplianceTabFragment on Vendor {\n complianceReports(first: 50) {\n edges {\n node {\n id\n ...VendorComplianceTabFragment_report\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorComplianceTabFragment_report on VendorComplianceReport {\n id\n reportDate\n validUntil\n reportName\n fileUrl\n fileSize\n}\n\nfragment VendorContactsTabFragment on Vendor {\n contacts(first: 50) {\n edges {\n node {\n id\n ...VendorContactsTabFragment_contact\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorContactsTabFragment_contact on VendorContact {\n id\n fullName\n email\n phone\n role\n createdAt\n updatedAt\n}\n\nfragment VendorOverviewTabBusinessAssociateAgreementFragment on Vendor {\n businessAssociateAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorRiskAssessmentTabFragment on Vendor {\n id\n riskAssessments(first: 50) {\n edges {\n node {\n id\n ...VendorRiskAssessmentTabFragment_assessment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment VendorRiskAssessmentTabFragment_assessment on VendorRiskAssessment {\n id\n assessedAt\n assessedBy {\n id\n fullName\n }\n expiresAt\n dataSensitivity\n businessImpact\n notes\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n" + "text": "query VendorGraphNodeQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n websiteUrl\n ...useVendorFormFragment\n ...VendorComplianceTabFragment\n ...VendorContactsTabFragment\n ...VendorRiskAssessmentTabFragment\n ...VendorOverviewTabBusinessAssociateAgreementFragment\n ...VendorOverviewTabDataPrivacyAgreementFragment\n }\n id\n }\n viewer {\n user {\n people(organizationId: $organizationId) {\n id\n }\n id\n }\n id\n }\n}\n\nfragment VendorComplianceTabFragment on Vendor {\n complianceReports(first: 50) {\n edges {\n node {\n id\n ...VendorComplianceTabFragment_report\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorComplianceTabFragment_report on VendorComplianceReport {\n id\n reportDate\n validUntil\n reportName\n fileUrl\n fileSize\n}\n\nfragment VendorContactsTabFragment on Vendor {\n contacts(first: 50) {\n edges {\n node {\n id\n ...VendorContactsTabFragment_contact\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment VendorContactsTabFragment_contact on VendorContact {\n id\n fullName\n email\n phone\n role\n createdAt\n updatedAt\n}\n\nfragment VendorOverviewTabBusinessAssociateAgreementFragment on Vendor {\n businessAssociateAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorOverviewTabDataPrivacyAgreementFragment on Vendor {\n dataPrivacyAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n}\n\nfragment VendorRiskAssessmentTabFragment on Vendor {\n id\n riskAssessments(first: 50) {\n edges {\n node {\n id\n ...VendorRiskAssessmentTabFragment_assessment\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment VendorRiskAssessmentTabFragment_assessment on VendorRiskAssessment {\n id\n assessedAt\n assessedBy {\n id\n fullName\n }\n expiresAt\n dataSensitivity\n businessImpact\n notes\n}\n\nfragment useVendorFormFragment on Vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n websiteUrl\n legalName\n headquarterAddress\n certifications\n securityPageUrl\n trustPageUrl\n businessOwner {\n id\n }\n securityOwner {\n id\n }\n}\n" } }; })(); -(node as any).hash = "b5ea2120ec2f0f09ed29e19bbf232622"; +(node as any).hash = "82f82a56df0ea5b755937ebcc55c1382"; export default node; diff --git a/apps/console/src/pages/organizations/vendors/dialogs/DeleteDataPrivacyAgreementDialog.tsx b/apps/console/src/pages/organizations/vendors/dialogs/DeleteDataPrivacyAgreementDialog.tsx new file mode 100644 index 000000000..c03caee2c --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/dialogs/DeleteDataPrivacyAgreementDialog.tsx @@ -0,0 +1,89 @@ +import { + Button, + Dialog, + DialogContent, + DialogFooter, + Spinner, + useDialogRef, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { sprintf } from "@probo/helpers"; +import { graphql } from "react-relay"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; + +const deleteDataPrivacyAgreementMutation = graphql` + mutation DeleteDataPrivacyAgreementDialogMutation( + $input: DeleteVendorDataPrivacyAgreementInput! + ) { + deleteVendorDataPrivacyAgreement(input: $input) { + deletedVendorId + } + } +`; + +type Props = { + children: React.ReactNode; + vendorId: string; + fileName: string; + onSuccess?: () => void; +}; + +export function DeleteDataPrivacyAgreementDialog({ + children, + vendorId, + fileName, + onSuccess, +}: Props) { + const { __ } = useTranslate(); + const ref = useDialogRef(); + + const [mutate, isDeleting] = useMutationWithToasts(deleteDataPrivacyAgreementMutation, { + successMessage: __("Data Privacy Agreement deleted successfully"), + errorMessage: __("Failed to delete Data Privacy Agreement"), + }); + + const handleDelete = async () => { + await mutate({ + variables: { + input: { + vendorId, + }, + }, + }); + + onSuccess?.(); + ref.current?.close(); + }; + + return ( + + +

+ {sprintf( + __("Are you sure you want to delete the Data Privacy Agreement \"%s\"?"), + fileName + )} +

+

+ {__("This action cannot be undone.")} +

+
+ + + + +
+ ); +} diff --git a/apps/console/src/pages/organizations/vendors/dialogs/EditDataPrivacyAgreementDialog.tsx b/apps/console/src/pages/organizations/vendors/dialogs/EditDataPrivacyAgreementDialog.tsx new file mode 100644 index 000000000..defcab661 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/dialogs/EditDataPrivacyAgreementDialog.tsx @@ -0,0 +1,135 @@ +import { + Button, + Dialog, + DialogContent, + DialogFooter, + Field, + Input, + Spinner, + useDialogRef, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { graphql } from "react-relay"; +import { z } from "zod"; +import { useFormWithSchema } from "/hooks/useFormWithSchema"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; + +const updateDataPrivacyAgreementMutation = graphql` + mutation EditDataPrivacyAgreementDialogMutation( + $input: UpdateVendorDataPrivacyAgreementInput! + ) { + updateVendorDataPrivacyAgreement(input: $input) { + vendorDataPrivacyAgreement { + id + fileUrl + validFrom + validUntil + createdAt + } + } + } +`; + +const schema = z.object({ + validFrom: z.string().optional(), + validUntil: z.string().optional(), +}); + +type Props = { + children: React.ReactNode; + vendorId: string; + agreement: { + validFrom?: string | null; + validUntil?: string | null; + }; + onSuccess?: () => void; +}; + +export function EditDataPrivacyAgreementDialog({ + children, + vendorId, + agreement, + onSuccess, +}: Props) { + const { __ } = useTranslate(); + const ref = useDialogRef(); + + const formatDateForForm = (datetime?: string | null) => { + if (!datetime) return ""; + return datetime.split("T")[0]; + }; + + const { + register, + handleSubmit, + formState: { isSubmitting }, + reset, + } = useFormWithSchema(schema, { + defaultValues: { + validFrom: formatDateForForm(agreement.validFrom), + validUntil: formatDateForForm(agreement.validUntil), + }, + }); + + const [mutate] = useMutationWithToasts(updateDataPrivacyAgreementMutation, { + successMessage: __("Data Privacy Agreement updated successfully"), + errorMessage: __("Failed to update Data Privacy Agreement"), + }); + + const onSubmit = handleSubmit(async (data) => { + const formatDatetime = (dateString?: string) => { + if (!dateString) return null; + return `${dateString}T00:00:00Z`; + }; + + await mutate({ + variables: { + input: { + vendorId, + validFrom: formatDatetime(data.validFrom), + validUntil: formatDatetime(data.validUntil), + }, + }, + }); + + onSuccess?.(); + ref.current?.close(); + }); + + const handleClose = () => { + reset(); + }; + + return ( + +
+ +
+ + + + + + +
+
+ + + + +
+
+ ); +} diff --git a/apps/console/src/pages/organizations/vendors/dialogs/UploadDataPrivacyAgreementDialog.tsx b/apps/console/src/pages/organizations/vendors/dialogs/UploadDataPrivacyAgreementDialog.tsx new file mode 100644 index 000000000..c613d0ae0 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/dialogs/UploadDataPrivacyAgreementDialog.tsx @@ -0,0 +1,178 @@ +import { + Button, + Dialog, + DialogContent, + DialogFooter, + Dropzone, + Field, + Spinner, + Input, + useDialogRef, +} from "@probo/ui"; +import { useTranslate } from "@probo/i18n"; +import { graphql } from "react-relay"; +import { z } from "zod"; +import { useFormWithSchema } from "/hooks/useFormWithSchema"; +import { useMutationWithToasts } from "/hooks/useMutationWithToasts"; +import { useState } from "react"; + +const uploadDataPrivacyAgreementMutation = graphql` + mutation UploadDataPrivacyAgreementDialogMutation( + $input: UploadVendorDataPrivacyAgreementInput! + ) { + uploadVendorDataPrivacyAgreement(input: $input) { + vendorDataPrivacyAgreement { + id + fileName + fileUrl + validFrom + validUntil + createdAt + } + } + } +`; + +const schema = z.object({ + fileName: z.string().min(1, "File name is required"), + validFrom: z.string().optional(), + validUntil: z.string().optional(), +}); + +type Props = { + children: React.ReactNode; + vendorId: string; + onSuccess?: () => void; +}; + +export function UploadDataPrivacyAgreementDialog({ + children, + vendorId, + onSuccess, +}: Props) { + const { __ } = useTranslate(); + const [uploadedFile, setUploadedFile] = useState(null); + const ref = useDialogRef(); + + const { + register, + handleSubmit, + formState: { errors, isSubmitting }, + reset, + setValue, + } = useFormWithSchema(schema, { + defaultValues: { + fileName: "", + validFrom: "", + validUntil: "", + }, + }); + + const [mutate] = useMutationWithToasts(uploadDataPrivacyAgreementMutation, { + successMessage: __("Data Privacy Agreement uploaded successfully"), + errorMessage: __("Failed to upload Data Privacy Agreement"), + }); + + const handleDrop = (files: File[]) => { + if (files.length > 0) { + const file = files[0]; + setUploadedFile(file); + setValue("fileName", file.name); + } + }; + + const onSubmit = handleSubmit(async (data) => { + if (!uploadedFile) { + return; + } + + const formatDatetime = (dateString?: string) => { + if (!dateString) return null; + return `${dateString}T00:00:00Z`; + }; + + await mutate({ + variables: { + input: { + vendorId, + fileName: data.fileName, + validFrom: formatDatetime(data.validFrom), + validUntil: formatDatetime(data.validUntil), + file: null, + }, + }, + uploadables: { + "input.file": uploadedFile, + }, + }); + + reset(); + setUploadedFile(null); + onSuccess?.(); + ref.current?.close(); + }); + + const handleClose = () => { + reset(); + setUploadedFile(null); + }; + + return ( + +
+ + + + {uploadedFile && ( +
+

{__("Selected file")}:

+

{uploadedFile.name}

+
+ )} + + + +
+ + + + + + +
+
+ + + + +
+
+ ); +} diff --git a/apps/console/src/pages/organizations/vendors/dialogs/__generated__/DeleteDataPrivacyAgreementDialogMutation.graphql.ts b/apps/console/src/pages/organizations/vendors/dialogs/__generated__/DeleteDataPrivacyAgreementDialogMutation.graphql.ts new file mode 100644 index 000000000..a4a21e0a7 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/dialogs/__generated__/DeleteDataPrivacyAgreementDialogMutation.graphql.ts @@ -0,0 +1,92 @@ +/** + * @generated SignedSource<<4d1711d74f82bc8952b162a37dd8931e>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type DeleteVendorDataPrivacyAgreementInput = { + vendorId: string; +}; +export type DeleteDataPrivacyAgreementDialogMutation$variables = { + input: DeleteVendorDataPrivacyAgreementInput; +}; +export type DeleteDataPrivacyAgreementDialogMutation$data = { + readonly deleteVendorDataPrivacyAgreement: { + readonly deletedVendorId: string; + }; +}; +export type DeleteDataPrivacyAgreementDialogMutation = { + response: DeleteDataPrivacyAgreementDialogMutation$data; + variables: DeleteDataPrivacyAgreementDialogMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "DeleteVendorDataPrivacyAgreementPayload", + "kind": "LinkedField", + "name": "deleteVendorDataPrivacyAgreement", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "deletedVendorId", + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "DeleteDataPrivacyAgreementDialogMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "DeleteDataPrivacyAgreementDialogMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "683fac4979ff59534ce2acaa05d82063", + "id": null, + "metadata": {}, + "name": "DeleteDataPrivacyAgreementDialogMutation", + "operationKind": "mutation", + "text": "mutation DeleteDataPrivacyAgreementDialogMutation(\n $input: DeleteVendorDataPrivacyAgreementInput!\n) {\n deleteVendorDataPrivacyAgreement(input: $input) {\n deletedVendorId\n }\n}\n" + } +}; +})(); + +(node as any).hash = "38cb9bcb710db551eda7ed8cff9fca5a"; + +export default node; diff --git a/apps/console/src/pages/organizations/vendors/dialogs/__generated__/EditDataPrivacyAgreementDialogMutation.graphql.ts b/apps/console/src/pages/organizations/vendors/dialogs/__generated__/EditDataPrivacyAgreementDialogMutation.graphql.ts new file mode 100644 index 000000000..f4b117de5 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/dialogs/__generated__/EditDataPrivacyAgreementDialogMutation.graphql.ts @@ -0,0 +1,139 @@ +/** + * @generated SignedSource<<161930fef961066719e45ce1f899dd38>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type UpdateVendorDataPrivacyAgreementInput = { + validFrom?: any | null | undefined; + validUntil?: any | null | undefined; + vendorId: string; +}; +export type EditDataPrivacyAgreementDialogMutation$variables = { + input: UpdateVendorDataPrivacyAgreementInput; +}; +export type EditDataPrivacyAgreementDialogMutation$data = { + readonly updateVendorDataPrivacyAgreement: { + readonly vendorDataPrivacyAgreement: { + readonly createdAt: any; + readonly fileUrl: string; + readonly id: string; + readonly validFrom: any | null | undefined; + readonly validUntil: any | null | undefined; + }; + }; +}; +export type EditDataPrivacyAgreementDialogMutation = { + response: EditDataPrivacyAgreementDialogMutation$data; + variables: EditDataPrivacyAgreementDialogMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "UpdateVendorDataPrivacyAgreementPayload", + "kind": "LinkedField", + "name": "updateVendorDataPrivacyAgreement", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorDataPrivacyAgreement", + "kind": "LinkedField", + "name": "vendorDataPrivacyAgreement", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fileUrl", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "validFrom", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "validUntil", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "EditDataPrivacyAgreementDialogMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "EditDataPrivacyAgreementDialogMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "e84e9f9457d6e4dc295578e540aa3e64", + "id": null, + "metadata": {}, + "name": "EditDataPrivacyAgreementDialogMutation", + "operationKind": "mutation", + "text": "mutation EditDataPrivacyAgreementDialogMutation(\n $input: UpdateVendorDataPrivacyAgreementInput!\n) {\n updateVendorDataPrivacyAgreement(input: $input) {\n vendorDataPrivacyAgreement {\n id\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "b2caa3bc89953896a848ee77fd96a767"; + +export default node; diff --git a/apps/console/src/pages/organizations/vendors/dialogs/__generated__/UploadDataPrivacyAgreementDialogMutation.graphql.ts b/apps/console/src/pages/organizations/vendors/dialogs/__generated__/UploadDataPrivacyAgreementDialogMutation.graphql.ts new file mode 100644 index 000000000..5bad4da00 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/dialogs/__generated__/UploadDataPrivacyAgreementDialogMutation.graphql.ts @@ -0,0 +1,149 @@ +/** + * @generated SignedSource<<6d5f65677b0f86e7042fd5f7c58d6f08>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +export type UploadVendorDataPrivacyAgreementInput = { + file: any; + fileName: string; + validFrom?: any | null | undefined; + validUntil?: any | null | undefined; + vendorId: string; +}; +export type UploadDataPrivacyAgreementDialogMutation$variables = { + input: UploadVendorDataPrivacyAgreementInput; +}; +export type UploadDataPrivacyAgreementDialogMutation$data = { + readonly uploadVendorDataPrivacyAgreement: { + readonly vendorDataPrivacyAgreement: { + readonly createdAt: any; + readonly fileName: string; + readonly fileUrl: string; + readonly id: string; + readonly validFrom: any | null | undefined; + readonly validUntil: any | null | undefined; + }; + }; +}; +export type UploadDataPrivacyAgreementDialogMutation = { + response: UploadDataPrivacyAgreementDialogMutation$data; + variables: UploadDataPrivacyAgreementDialogMutation$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "UploadVendorDataPrivacyAgreementPayload", + "kind": "LinkedField", + "name": "uploadVendorDataPrivacyAgreement", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorDataPrivacyAgreement", + "kind": "LinkedField", + "name": "vendorDataPrivacyAgreement", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fileName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fileUrl", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "validFrom", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "validUntil", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "UploadDataPrivacyAgreementDialogMutation", + "selections": (v1/*: any*/), + "type": "Mutation", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "UploadDataPrivacyAgreementDialogMutation", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "c59302d882fc9406dd7f09072db552b5", + "id": null, + "metadata": {}, + "name": "UploadDataPrivacyAgreementDialogMutation", + "operationKind": "mutation", + "text": "mutation UploadDataPrivacyAgreementDialogMutation(\n $input: UploadVendorDataPrivacyAgreementInput!\n) {\n uploadVendorDataPrivacyAgreement(input: $input) {\n vendorDataPrivacyAgreement {\n id\n fileName\n fileUrl\n validFrom\n validUntil\n createdAt\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "8e4e70e111836cebd850061a75872980"; + +export default node; diff --git a/apps/console/src/pages/organizations/vendors/tabs/VendorOverviewTab.tsx b/apps/console/src/pages/organizations/vendors/tabs/VendorOverviewTab.tsx index a1b1283a1..cf6b4649a 100644 --- a/apps/console/src/pages/organizations/vendors/tabs/VendorOverviewTab.tsx +++ b/apps/console/src/pages/organizations/vendors/tabs/VendorOverviewTab.tsx @@ -11,8 +11,12 @@ import { useFragment, graphql } from "react-relay"; import { UploadBusinessAssociateAgreementDialog } from "../dialogs/UploadBusinessAssociateAgreementDialog"; import { DeleteBusinessAssociateAgreementDialog } from "../dialogs/DeleteBusinessAssociateAgreementDialog"; import { EditBusinessAssociateAgreementDialog } from "../dialogs/EditBusinessAssociateAgreementDialog"; +import { UploadDataPrivacyAgreementDialog } from "../dialogs/UploadDataPrivacyAgreementDialog"; +import { DeleteDataPrivacyAgreementDialog } from "../dialogs/DeleteDataPrivacyAgreementDialog"; +import { EditDataPrivacyAgreementDialog } from "../dialogs/EditDataPrivacyAgreementDialog"; import type { useVendorFormFragment$key } from "/hooks/forms/__generated__/useVendorFormFragment.graphql"; import type { VendorOverviewTabBusinessAssociateAgreementFragment$key } from "./__generated__/VendorOverviewTabBusinessAssociateAgreementFragment.graphql"; +import type { VendorOverviewTabDataPrivacyAgreementFragment$key } from "./__generated__/VendorOverviewTabDataPrivacyAgreementFragment.graphql"; const vendorBusinessAssociateAgreementFragment = graphql` fragment VendorOverviewTabBusinessAssociateAgreementFragment on Vendor { @@ -27,13 +31,26 @@ const vendorBusinessAssociateAgreementFragment = graphql` } `; +const vendorDataPrivacyAgreementFragment = graphql` + fragment VendorOverviewTabDataPrivacyAgreementFragment on Vendor { + dataPrivacyAgreement { + id + fileName + fileUrl + validFrom + validUntil + createdAt + } + } +`; + export default function VendorOverviewTab() { const { vendor } = useOutletContext<{ vendor: useVendorFormFragment$key & { id: string; name: string }; }>(); const { vendor: vendorForBAA } = useOutletContext<{ - vendor: VendorOverviewTabBusinessAssociateAgreementFragment$key; + vendor: VendorOverviewTabBusinessAssociateAgreementFragment$key & VendorOverviewTabDataPrivacyAgreementFragment$key; }>(); const { __ } = useTranslate(); @@ -52,6 +69,12 @@ export default function VendorOverviewTab() { ); const businessAssociateAgreement = vendorWithBAA.businessAssociateAgreement; + const vendorWithDPA = useFragment( + vendorDataPrivacyAgreementFragment, + vendorForBAA + ); + const dataPrivacyAgreement = vendorWithDPA.dataPrivacyAgreement; + const urls = useMemo( () => [ @@ -227,6 +250,69 @@ export default function VendorOverviewTab() { )} + +
+
+

+ {__("Data Privacy Agreement")} +

+

+ {dataPrivacyAgreement ? dataPrivacyAgreement.fileName : __("No data privacy agreement available")} +

+ {(dataPrivacyAgreement?.validFrom || dataPrivacyAgreement?.validUntil) && ( +

+ {__("Valid")} + {dataPrivacyAgreement.validFrom && + ` ${__("from")} ${new Date(dataPrivacyAgreement.validFrom).toLocaleDateString()}` + } + {dataPrivacyAgreement.validUntil && + ` ${__("until")} ${new Date(dataPrivacyAgreement.validUntil).toLocaleDateString()}` + } +

+ )} +
+
+ {dataPrivacyAgreement ? ( + <> + + window.location.reload()} + > + + + + )} +
+
diff --git a/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorOverviewTabDataPrivacyAgreementFragment.graphql.ts b/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorOverviewTabDataPrivacyAgreementFragment.graphql.ts new file mode 100644 index 000000000..ffb7b75d6 --- /dev/null +++ b/apps/console/src/pages/organizations/vendors/tabs/__generated__/VendorOverviewTabDataPrivacyAgreementFragment.graphql.ts @@ -0,0 +1,95 @@ +/** + * @generated SignedSource<<03e78d5a57f41471ed7099febe61e666>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ReaderFragment } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type VendorOverviewTabDataPrivacyAgreementFragment$data = { + readonly dataPrivacyAgreement: { + readonly createdAt: any; + readonly fileName: string; + readonly fileUrl: string; + readonly id: string; + readonly validFrom: any | null | undefined; + readonly validUntil: any | null | undefined; + } | null | undefined; + readonly " $fragmentType": "VendorOverviewTabDataPrivacyAgreementFragment"; +}; +export type VendorOverviewTabDataPrivacyAgreementFragment$key = { + readonly " $data"?: VendorOverviewTabDataPrivacyAgreementFragment$data; + readonly " $fragmentSpreads": FragmentRefs<"VendorOverviewTabDataPrivacyAgreementFragment">; +}; + +const node: ReaderFragment = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "VendorOverviewTabDataPrivacyAgreementFragment", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "VendorDataPrivacyAgreement", + "kind": "LinkedField", + "name": "dataPrivacyAgreement", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fileName", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fileUrl", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "validFrom", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "validUntil", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Vendor", + "abstractKey": null +}; + +(node as any).hash = "9a3e19e369a57ce4c1dd08760d244b74"; + +export default node; diff --git a/pkg/coredata/entity_type_reg.go b/pkg/coredata/entity_type_reg.go index 6566d2711..0adbaacc9 100644 --- a/pkg/coredata/entity_type_reg.go +++ b/pkg/coredata/entity_type_reg.go @@ -42,4 +42,5 @@ const ( VendorBusinessAssociateAgreementEntityType FileEntityType VendorContactEntityType + VendorDataPrivacyAgreementEntityType ) diff --git a/pkg/coredata/migrations/20250813T141529Z.sql b/pkg/coredata/migrations/20250813T141529Z.sql new file mode 100644 index 000000000..c2c27ee9c --- /dev/null +++ b/pkg/coredata/migrations/20250813T141529Z.sql @@ -0,0 +1,29 @@ +CREATE TABLE vendor_data_privacy_agreements ( + id TEXT PRIMARY KEY, + organization_id TEXT NOT NULL, + tenant_id TEXT NOT NULL, + vendor_id TEXT NOT NULL, + valid_from DATE, + valid_until DATE, + file_id TEXT NOT NULL, + created_at TIMESTAMP WITH TIME ZONE NOT NULL, + updated_at TIMESTAMP WITH TIME ZONE NOT NULL, + + CONSTRAINT vendor_data_privacy_agreements_organization_vendor_unique + UNIQUE (organization_id, vendor_id), + + CONSTRAINT vendor_data_privacy_agreements_file_id_unique + UNIQUE (file_id), + + CONSTRAINT vendor_data_privacy_agreements_organization_id_fkey + FOREIGN KEY (organization_id) + REFERENCES organizations(id) + ON UPDATE CASCADE + ON DELETE CASCADE, + + CONSTRAINT vendor_data_privacy_agreements_file_id_fkey + FOREIGN KEY (file_id) + REFERENCES files(id) + ON UPDATE CASCADE + ON DELETE CASCADE +); diff --git a/pkg/coredata/vendor_data_privacy_agreement.go b/pkg/coredata/vendor_data_privacy_agreement.go new file mode 100644 index 000000000..3a2b6d1d2 --- /dev/null +++ b/pkg/coredata/vendor_data_privacy_agreement.go @@ -0,0 +1,280 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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 coredata + +import ( + "context" + "fmt" + "maps" + "time" + + "github.com/getprobo/probo/pkg/gid" + "github.com/getprobo/probo/pkg/page" + "github.com/jackc/pgx/v5" + "go.gearno.de/kit/pg" +) + +type ( + VendorDataPrivacyAgreement struct { + ID gid.GID `db:"id"` + TenantID gid.TenantID `db:"tenant_id"` + OrganizationID gid.GID `db:"organization_id"` + VendorID gid.GID `db:"vendor_id"` + ValidFrom *time.Time `db:"valid_from"` + ValidUntil *time.Time `db:"valid_until"` + FileID gid.GID `db:"file_id"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` + } + + VendorDataPrivacyAgreements []*VendorDataPrivacyAgreement +) + +func (v VendorDataPrivacyAgreement) CursorKey(orderBy VendorDataPrivacyAgreementOrderField) page.CursorKey { + switch orderBy { + case VendorDataPrivacyAgreementOrderFieldValidFrom: + return page.NewCursorKey(v.ID, v.ValidFrom) + case VendorDataPrivacyAgreementOrderFieldCreatedAt: + return page.NewCursorKey(v.ID, v.CreatedAt) + } + + panic(fmt.Sprintf("unsupported order by: %s", orderBy)) +} + +func (vdpa *VendorDataPrivacyAgreement) LoadByVendorID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + vendorID gid.GID, +) error { + q := ` +SELECT + id, + tenant_id, + organization_id, + vendor_id, + valid_from, + valid_until, + file_id, + created_at, + updated_at +FROM + vendor_data_privacy_agreements +WHERE + %s + AND vendor_id = @vendor_id +LIMIT 1; +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.NamedArgs{"vendor_id": vendorID} + maps.Copy(args, scope.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query vendor data privacy agreement: %w", err) + } + + vendorDataPrivacyAgreement, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[VendorDataPrivacyAgreement]) + if err != nil { + return fmt.Errorf("cannot collect vendor data privacy agreement: %w", err) + } + + *vdpa = vendorDataPrivacyAgreement + + return nil +} + +func (vdpa *VendorDataPrivacyAgreement) LoadByID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + vendorDataPrivacyAgreementID gid.GID, +) error { + q := ` +SELECT + id, + tenant_id, + organization_id, + vendor_id, + valid_from, + valid_until, + file_id, + created_at, + updated_at +FROM + vendor_data_privacy_agreements +WHERE + %s + AND id = @id +LIMIT 1; +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.NamedArgs{"id": vendorDataPrivacyAgreementID} + maps.Copy(args, scope.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query vendor data privacy agreement: %w", err) + } + + vendorDataPrivacyAgreement, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[VendorDataPrivacyAgreement]) + if err != nil { + return fmt.Errorf("cannot collect vendor data privacy agreement: %w", err) + } + + *vdpa = vendorDataPrivacyAgreement + + return nil +} + +func (vdpa *VendorDataPrivacyAgreement) Update( + ctx context.Context, + conn pg.Conn, + scope Scoper, +) error { + q := ` +UPDATE + vendor_data_privacy_agreements +SET + valid_from = @valid_from, + valid_until = @valid_until, + file_id = @file_id, + updated_at = @updated_at +WHERE + %s + AND id = @id +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{ + "id": vdpa.ID, + "valid_from": vdpa.ValidFrom, + "valid_until": vdpa.ValidUntil, + "file_id": vdpa.FileID, + "updated_at": vdpa.UpdatedAt, + } + maps.Copy(args, scope.SQLArguments()) + + _, err := conn.Exec(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot update vendor data privacy agreement: %w", err) + } + + return nil +} + +func (vdpa *VendorDataPrivacyAgreement) Upsert( + ctx context.Context, + conn pg.Conn, + scope Scoper, +) error { + q := ` +INSERT INTO + vendor_data_privacy_agreements ( + id, + tenant_id, + organization_id, + vendor_id, + valid_from, + valid_until, + file_id, + created_at, + updated_at + ) +VALUES ( + @id, + @tenant_id, + @organization_id, + @vendor_id, + @valid_from, + @valid_until, + @file_id, + @created_at, + @updated_at +) +ON CONFLICT (organization_id, vendor_id) DO UPDATE SET + id = EXCLUDED.id, + valid_from = EXCLUDED.valid_from, + valid_until = EXCLUDED.valid_until, + file_id = EXCLUDED.file_id, + updated_at = EXCLUDED.updated_at +` + args := pgx.StrictNamedArgs{ + "id": vdpa.ID, + "tenant_id": scope.GetTenantID(), + "vendor_id": vdpa.VendorID, + "organization_id": vdpa.OrganizationID, + "valid_from": vdpa.ValidFrom, + "valid_until": vdpa.ValidUntil, + "file_id": vdpa.FileID, + "created_at": vdpa.CreatedAt, + "updated_at": vdpa.UpdatedAt, + } + + _, err := conn.Exec(ctx, q, args) + return err +} + +func (vdpa *VendorDataPrivacyAgreement) Delete( + ctx context.Context, + conn pg.Conn, + scope Scoper, +) error { + q := ` +DELETE +FROM + vendor_data_privacy_agreements +WHERE + %s + AND id = @id +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"id": vdpa.ID} + maps.Copy(args, scope.SQLArguments()) + + _, err := conn.Exec(ctx, q, args) + return err +} + +func (vdpa *VendorDataPrivacyAgreement) DeleteByVendorID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + vendorID gid.GID, +) error { + q := ` +DELETE +FROM + vendor_data_privacy_agreements +WHERE + %s + AND vendor_id = @vendor_id +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"vendor_id": vendorID} + maps.Copy(args, scope.SQLArguments()) + + _, err := conn.Exec(ctx, q, args) + return err +} diff --git a/pkg/coredata/vendor_data_privacy_agreement_order_field.go b/pkg/coredata/vendor_data_privacy_agreement_order_field.go new file mode 100644 index 000000000..0cd82bb05 --- /dev/null +++ b/pkg/coredata/vendor_data_privacy_agreement_order_field.go @@ -0,0 +1,41 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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 coredata + +type ( + VendorDataPrivacyAgreementOrderField string +) + +const ( + VendorDataPrivacyAgreementOrderFieldValidFrom VendorDataPrivacyAgreementOrderField = "VALID_FROM" + VendorDataPrivacyAgreementOrderFieldCreatedAt VendorDataPrivacyAgreementOrderField = "CREATED_AT" +) + +func (p VendorDataPrivacyAgreementOrderField) Column() string { + return string(p) +} + +func (p VendorDataPrivacyAgreementOrderField) String() string { + return string(p) +} + +func (p VendorDataPrivacyAgreementOrderField) MarshalText() ([]byte, error) { + return []byte(p.String()), nil +} + +func (p *VendorDataPrivacyAgreementOrderField) UnmarshalText(text []byte) error { + *p = VendorDataPrivacyAgreementOrderField(text) + return nil +} diff --git a/pkg/probo/service.go b/pkg/probo/service.go index 49998f70a..f33696658 100644 --- a/pkg/probo/service.go +++ b/pkg/probo/service.go @@ -73,6 +73,7 @@ type ( VendorComplianceReports *VendorComplianceReportService VendorBusinessAssociateAgreements *VendorBusinessAssociateAgreementService VendorContacts *VendorContactService + VendorDataPrivacyAgreements *VendorDataPrivacyAgreementService Connectors *ConnectorService Assets *AssetService Data *DatumService @@ -161,6 +162,7 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { tenantService.VendorComplianceReports = &VendorComplianceReportService{svc: tenantService} tenantService.VendorBusinessAssociateAgreements = &VendorBusinessAssociateAgreementService{svc: tenantService} tenantService.VendorContacts = &VendorContactService{svc: tenantService} + tenantService.VendorDataPrivacyAgreements = &VendorDataPrivacyAgreementService{svc: tenantService} tenantService.Connectors = &ConnectorService{svc: tenantService} tenantService.Assets = &AssetService{svc: tenantService} tenantService.Data = &DatumService{svc: tenantService} diff --git a/pkg/probo/vendor_business_associate_agreement_service.go b/pkg/probo/vendor_business_associate_agreement_service.go index 8f68f45a0..dc33a18be 100644 --- a/pkg/probo/vendor_business_associate_agreement_service.go +++ b/pkg/probo/vendor_business_associate_agreement_service.go @@ -261,10 +261,6 @@ func (s VendorBusinessAssociateAgreementService) Update( return fmt.Errorf("cannot load existing vendor business associate agreement: %w", err) } - if err := file.LoadByID(ctx, conn, s.svc.scope, existingAgreement.FileID); err != nil { - return fmt.Errorf("cannot load file: %w", err) - } - now := time.Now() if req.ValidFrom != nil { existingAgreement.ValidFrom = *req.ValidFrom @@ -275,14 +271,14 @@ func (s VendorBusinessAssociateAgreementService) Update( existingAgreement.UpdatedAt = now - if err := file.LoadByID(ctx, conn, s.svc.scope, existingAgreement.FileID); err != nil { - return fmt.Errorf("cannot load file: %w", err) - } - if err := existingAgreement.Update(ctx, conn, s.svc.scope); err != nil { return fmt.Errorf("cannot update vendor business associate agreement: %w", err) } + if err := file.LoadByID(ctx, conn, s.svc.scope, existingAgreement.FileID); err != nil { + return fmt.Errorf("cannot load file: %w", err) + } + return nil }, ) diff --git a/pkg/probo/vendor_data_privacy_agreement_service.go b/pkg/probo/vendor_data_privacy_agreement_service.go new file mode 100644 index 000000000..c67b03bd7 --- /dev/null +++ b/pkg/probo/vendor_data_privacy_agreement_service.go @@ -0,0 +1,346 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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 probo + +import ( + "context" + "fmt" + "io" + "mime" + "net/url" + "path/filepath" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/getprobo/probo/pkg/coredata" + "github.com/getprobo/probo/pkg/gid" + "go.gearno.de/crypto/uuid" + "go.gearno.de/kit/pg" +) + +type ( + VendorDataPrivacyAgreementService struct { + svc *TenantService + } + + VendorDataPrivacyAgreementCreateRequest struct { + File io.Reader + ValidFrom *time.Time + ValidUntil *time.Time + FileName string + } + + VendorDataPrivacyAgreementUpdateRequest struct { + ValidFrom **time.Time + ValidUntil **time.Time + } +) + +func (s VendorDataPrivacyAgreementService) GetByVendorID( + ctx context.Context, + vendorID gid.GID, +) (*coredata.VendorDataPrivacyAgreement, *coredata.File, error) { + var vendorDataPrivacyAgreement *coredata.VendorDataPrivacyAgreement + var file *coredata.File + + err := s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + vendorDataPrivacyAgreement = &coredata.VendorDataPrivacyAgreement{} + if err := vendorDataPrivacyAgreement.LoadByVendorID(ctx, conn, s.svc.scope, vendorID); err != nil { + return fmt.Errorf("cannot load vendor data privacy agreement: %w", err) + } + + file = &coredata.File{} + if err := file.LoadByID(ctx, conn, s.svc.scope, vendorDataPrivacyAgreement.FileID); err != nil { + return fmt.Errorf("cannot load file: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, nil, err + } + + return vendorDataPrivacyAgreement, file, nil +} + +func (s VendorDataPrivacyAgreementService) Upload( + ctx context.Context, + vendorID gid.GID, + req *VendorDataPrivacyAgreementCreateRequest, +) (*coredata.VendorDataPrivacyAgreement, *coredata.File, error) { + objectKey, err := uuid.NewV7() + if err != nil { + return nil, nil, fmt.Errorf("cannot generate object key: %w", err) + } + + mimeType := mime.TypeByExtension(filepath.Ext(req.FileName)) + + _, err = s.svc.s3.PutObject(ctx, &s3.PutObjectInput{ + Bucket: &s.svc.bucket, + Key: aws.String(objectKey.String()), + Body: req.File, + ContentType: &mimeType, + }) + if err != nil { + return nil, nil, fmt.Errorf("cannot upload file to S3: %w", err) + } + + headOutput, err := s.svc.s3.HeadObject(ctx, &s3.HeadObjectInput{ + Bucket: aws.String(s.svc.bucket), + Key: aws.String(objectKey.String()), + }) + if err != nil { + return nil, nil, fmt.Errorf("cannot get object metadata: %w", err) + } + + now := time.Now() + + fileID := gid.New(s.svc.scope.GetTenantID(), coredata.FileEntityType) + vendorDataPrivacyAgreementID := gid.New(s.svc.scope.GetTenantID(), coredata.VendorDataPrivacyAgreementEntityType) + + var vendorDataPrivacyAgreement *coredata.VendorDataPrivacyAgreement + var file *coredata.File + + err = s.svc.pg.WithTx( + ctx, + func(conn pg.Conn) error { + vendor := &coredata.Vendor{} + if err := vendor.LoadByID(ctx, conn, s.svc.scope, vendorID); err != nil { + return fmt.Errorf("cannot load vendor: %w", err) + } + + file = &coredata.File{ + ID: fileID, + BucketName: s.svc.bucket, + MimeType: mimeType, + FileName: req.FileName, + FileKey: objectKey.String(), + FileSize: int(*headOutput.ContentLength), + CreatedAt: now, + UpdatedAt: now, + } + + vendorDataPrivacyAgreement = &coredata.VendorDataPrivacyAgreement{ + ID: vendorDataPrivacyAgreementID, + TenantID: s.svc.scope.GetTenantID(), + OrganizationID: vendor.OrganizationID, + VendorID: vendorID, + ValidFrom: req.ValidFrom, + ValidUntil: req.ValidUntil, + FileID: fileID, + CreatedAt: now, + UpdatedAt: now, + } + + if err := file.Insert(ctx, conn, s.svc.scope); err != nil { + return fmt.Errorf("cannot insert file: %w", err) + } + + if err := vendorDataPrivacyAgreement.Upsert(ctx, conn, s.svc.scope); err != nil { + return fmt.Errorf("cannot insert vendor data privacy agreement: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, nil, err + } + + return vendorDataPrivacyAgreement, file, nil +} + +func (s VendorDataPrivacyAgreementService) Get( + ctx context.Context, + vendorDataPrivacyAgreementID gid.GID, +) (*coredata.VendorDataPrivacyAgreement, *coredata.File, error) { + var vendorDataPrivacyAgreement *coredata.VendorDataPrivacyAgreement + var file *coredata.File + + err := s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + vendorDataPrivacyAgreement = &coredata.VendorDataPrivacyAgreement{} + if err := vendorDataPrivacyAgreement.LoadByID(ctx, conn, s.svc.scope, vendorDataPrivacyAgreementID); err != nil { + return fmt.Errorf("cannot load vendor data privacy agreement: %w", err) + } + + file = &coredata.File{} + if err := file.LoadByID(ctx, conn, s.svc.scope, vendorDataPrivacyAgreement.FileID); err != nil { + return fmt.Errorf("cannot load file: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, nil, fmt.Errorf("cannot load vendor data privacy agreement: %w", err) + } + + return vendorDataPrivacyAgreement, file, nil +} + +func (s VendorDataPrivacyAgreementService) GenerateFileURL( + ctx context.Context, + vendorDataPrivacyAgreementID gid.GID, + expiresIn time.Duration, +) (string, error) { + var file *coredata.File + + err := s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + vendorDataPrivacyAgreement := &coredata.VendorDataPrivacyAgreement{} + if err := vendorDataPrivacyAgreement.LoadByID(ctx, conn, s.svc.scope, vendorDataPrivacyAgreementID); err != nil { + return fmt.Errorf("cannot load vendor data privacy agreement: %w", err) + } + + file = &coredata.File{} + if err := file.LoadByID(ctx, conn, s.svc.scope, vendorDataPrivacyAgreement.FileID); err != nil { + return fmt.Errorf("cannot load file: %w", err) + } + + return nil + }, + ) + if err != nil { + return "", err + } + + presignClient := s3.NewPresignClient(s.svc.s3) + + encodedFilename := url.QueryEscape(file.FileName) + contentDisposition := fmt.Sprintf("attachment; filename=\"%s\"; filename*=UTF-8''%s", + encodedFilename, encodedFilename) + + presignedReq, err := presignClient.PresignGetObject(ctx, &s3.GetObjectInput{ + Bucket: aws.String(s.svc.bucket), + Key: aws.String(file.FileKey), + ResponseCacheControl: aws.String("max-age=3600, public"), + ResponseContentDisposition: aws.String(contentDisposition), + }, func(opts *s3.PresignOptions) { + opts.Expires = expiresIn + }) + if err != nil { + return "", fmt.Errorf("cannot presign GetObject request: %w", err) + } + + return presignedReq.URL, nil +} + +func (s VendorDataPrivacyAgreementService) Update( + ctx context.Context, + vendorID gid.GID, + req *VendorDataPrivacyAgreementUpdateRequest, +) (*coredata.VendorDataPrivacyAgreement, *coredata.File, error) { + existingAgreement := &coredata.VendorDataPrivacyAgreement{} + file := &coredata.File{} + + err := s.svc.pg.WithTx( + ctx, + func(conn pg.Conn) error { + if err := existingAgreement.LoadByVendorID(ctx, conn, s.svc.scope, vendorID); err != nil { + return fmt.Errorf("cannot load existing vendor data privacy agreement: %w", err) + } + + now := time.Now() + if req.ValidFrom != nil { + existingAgreement.ValidFrom = *req.ValidFrom + } + if req.ValidUntil != nil { + existingAgreement.ValidUntil = *req.ValidUntil + } + + existingAgreement.UpdatedAt = now + + if err := existingAgreement.Update(ctx, conn, s.svc.scope); err != nil { + return fmt.Errorf("cannot update vendor data privacy agreement: %w", err) + } + + if err := file.LoadByID(ctx, conn, s.svc.scope, existingAgreement.FileID); err != nil { + return fmt.Errorf("cannot load file: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, nil, err + } + + return existingAgreement, file, nil +} + +func (s VendorDataPrivacyAgreementService) Delete( + ctx context.Context, + vendorDataPrivacyAgreementID gid.GID, +) error { + return s.svc.pg.WithTx( + ctx, + func(conn pg.Conn) error { + vendorDataPrivacyAgreement := &coredata.VendorDataPrivacyAgreement{} + if err := vendorDataPrivacyAgreement.LoadByID(ctx, conn, s.svc.scope, vendorDataPrivacyAgreementID); err != nil { + return fmt.Errorf("cannot load vendor data privacy agreement: %w", err) + } + + file := &coredata.File{ID: vendorDataPrivacyAgreement.FileID} + + if err := vendorDataPrivacyAgreement.Delete(ctx, conn, s.svc.scope); err != nil { + return fmt.Errorf("cannot delete vendor data privacy agreement: %w", err) + } + + if err := file.SoftDelete(ctx, conn, s.svc.scope); err != nil { + return fmt.Errorf("cannot soft delete file: %w", err) + } + + return nil + }, + ) +} + +func (s VendorDataPrivacyAgreementService) DeleteByVendorID( + ctx context.Context, + vendorID gid.GID, +) error { + return s.svc.pg.WithTx( + ctx, + func(conn pg.Conn) error { + vendorDataPrivacyAgreement := &coredata.VendorDataPrivacyAgreement{} + if err := vendorDataPrivacyAgreement.LoadByVendorID(ctx, conn, s.svc.scope, vendorID); err != nil { + return fmt.Errorf("cannot load vendor data privacy agreement: %w", err) + } + + file := &coredata.File{ID: vendorDataPrivacyAgreement.FileID} + + if err := vendorDataPrivacyAgreement.DeleteByVendorID(ctx, conn, s.svc.scope, vendorID); err != nil { + return fmt.Errorf("cannot delete vendor data privacy agreement: %w", err) + } + + if err := file.SoftDelete(ctx, conn, s.svc.scope); err != nil { + return fmt.Errorf("cannot soft delete file: %w", err) + } + + return nil + }, + ) +} diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index ac0945e5e..34587b294 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -942,6 +942,7 @@ type Vendor implements Node { ): VendorComplianceReportConnection! @goField(forceResolver: true) businessAssociateAgreement: VendorBusinessAssociateAgreement @goField(forceResolver: true) + dataPrivacyAgreement: VendorDataPrivacyAgreement @goField(forceResolver: true) contacts( first: Int @@ -1015,6 +1016,18 @@ type VendorContact implements Node { updatedAt: Datetime! } +type VendorDataPrivacyAgreement implements Node { + id: ID! + vendor: Vendor! @goField(forceResolver: true) + validFrom: Datetime + validUntil: Datetime + fileName: String! + fileUrl: String! @goField(forceResolver: true) + fileSize: Int! + createdAt: Datetime! + updatedAt: Datetime! +} + type Framework implements Node { id: ID! name: String! @@ -1678,6 +1691,17 @@ type Mutation { input: DeleteVendorBusinessAssociateAgreementInput! ): DeleteVendorBusinessAssociateAgreementPayload! + # Vendor Data Privacy Agreement mutations + uploadVendorDataPrivacyAgreement( + input: UploadVendorDataPrivacyAgreementInput! + ): UploadVendorDataPrivacyAgreementPayload! + updateVendorDataPrivacyAgreement( + input: UpdateVendorDataPrivacyAgreementInput! + ): UpdateVendorDataPrivacyAgreementPayload! + deleteVendorDataPrivacyAgreement( + input: DeleteVendorDataPrivacyAgreementInput! + ): DeleteVendorDataPrivacyAgreementPayload! + # Document mutations createDocument(input: CreateDocumentInput!): CreateDocumentPayload! updateDocument(input: UpdateDocumentInput!): UpdateDocumentPayload! @@ -2071,6 +2095,24 @@ input DeleteVendorBusinessAssociateAgreementInput { vendorId: ID! } +input UploadVendorDataPrivacyAgreementInput { + vendorId: ID! + validFrom: Datetime + validUntil: Datetime + fileName: String! + file: Upload! +} + +input UpdateVendorDataPrivacyAgreementInput { + vendorId: ID! + validFrom: Datetime + validUntil: Datetime +} + +input DeleteVendorDataPrivacyAgreementInput { + vendorId: ID! +} + input CreateDocumentInput { organizationId: ID! title: String! @@ -2375,6 +2417,18 @@ type DeleteVendorBusinessAssociateAgreementPayload { deletedVendorId: ID! } +type UploadVendorDataPrivacyAgreementPayload { + vendorDataPrivacyAgreement: VendorDataPrivacyAgreement! +} + +type UpdateVendorDataPrivacyAgreementPayload { + vendorDataPrivacyAgreement: VendorDataPrivacyAgreement! +} + +type DeleteVendorDataPrivacyAgreementPayload { + deletedVendorId: ID! +} + type CreateDocumentPayload { documentEdge: DocumentEdge! documentVersionEdge: DocumentVersionEdge! diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go index 84707eac4..11deb8d7c 100644 --- a/pkg/server/api/console/v1/schema/schema.go +++ b/pkg/server/api/console/v1/schema/schema.go @@ -78,6 +78,7 @@ type ResolverRoot interface { VendorComplianceReport() VendorComplianceReportResolver VendorConnection() VendorConnectionResolver VendorContact() VendorContactResolver + VendorDataPrivacyAgreement() VendorDataPrivacyAgreementResolver VendorRiskAssessment() VendorRiskAssessmentResolver Viewer() ViewerResolver } @@ -407,6 +408,10 @@ type ComplexityRoot struct { DeletedVendorContactID func(childComplexity int) int } + DeleteVendorDataPrivacyAgreementPayload struct { + DeletedVendorID func(childComplexity int) int + } + DeleteVendorPayload struct { DeletedVendorID func(childComplexity int) int } @@ -636,6 +641,7 @@ type ComplexityRoot struct { DeleteVendorBusinessAssociateAgreement func(childComplexity int, input types.DeleteVendorBusinessAssociateAgreementInput) int DeleteVendorComplianceReport func(childComplexity int, input types.DeleteVendorComplianceReportInput) int DeleteVendorContact func(childComplexity int, input types.DeleteVendorContactInput) int + DeleteVendorDataPrivacyAgreement func(childComplexity int, input types.DeleteVendorDataPrivacyAgreementInput) int ExportDocumentVersionPDF func(childComplexity int, input types.ExportDocumentVersionPDFInput) int FulfillEvidence func(childComplexity int, input types.FulfillEvidenceInput) int GenerateDocumentChangelog func(childComplexity int, input types.GenerateDocumentChangelogInput) int @@ -665,11 +671,13 @@ type ComplexityRoot struct { UpdateVendor func(childComplexity int, input types.UpdateVendorInput) int UpdateVendorBusinessAssociateAgreement func(childComplexity int, input types.UpdateVendorBusinessAssociateAgreementInput) int UpdateVendorContact func(childComplexity int, input types.UpdateVendorContactInput) int + UpdateVendorDataPrivacyAgreement func(childComplexity int, input types.UpdateVendorDataPrivacyAgreementInput) int UploadAuditReport func(childComplexity int, input types.UploadAuditReportInput) int UploadMeasureEvidence func(childComplexity int, input types.UploadMeasureEvidenceInput) int UploadTaskEvidence func(childComplexity int, input types.UploadTaskEvidenceInput) int UploadVendorBusinessAssociateAgreement func(childComplexity int, input types.UploadVendorBusinessAssociateAgreementInput) int UploadVendorComplianceReport func(childComplexity int, input types.UploadVendorComplianceReportInput) int + UploadVendorDataPrivacyAgreement func(childComplexity int, input types.UploadVendorDataPrivacyAgreementInput) int } Organization struct { @@ -939,6 +947,10 @@ type ComplexityRoot struct { VendorContact func(childComplexity int) int } + UpdateVendorDataPrivacyAgreementPayload struct { + VendorDataPrivacyAgreement func(childComplexity int) int + } + UpdateVendorPayload struct { Vendor func(childComplexity int) int } @@ -963,6 +975,10 @@ type ComplexityRoot struct { VendorComplianceReportEdge func(childComplexity int) int } + UploadVendorDataPrivacyAgreementPayload struct { + VendorDataPrivacyAgreement func(childComplexity int) int + } + User struct { CreatedAt func(childComplexity int) int Email func(childComplexity int) int @@ -991,6 +1007,7 @@ type ComplexityRoot struct { ComplianceReports func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) int Contacts func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorContactOrderBy) int CreatedAt func(childComplexity int) int + DataPrivacyAgreement func(childComplexity int) int DataProcessingAgreementURL func(childComplexity int) int Description func(childComplexity int) int HeadquarterAddress func(childComplexity int) int @@ -1073,6 +1090,18 @@ type ComplexityRoot struct { Node func(childComplexity int) int } + VendorDataPrivacyAgreement struct { + CreatedAt func(childComplexity int) int + FileName func(childComplexity int) int + FileSize func(childComplexity int) int + FileURL func(childComplexity int) int + ID func(childComplexity int) int + UpdatedAt func(childComplexity int) int + ValidFrom func(childComplexity int) int + ValidUntil func(childComplexity int) int + Vendor func(childComplexity int) int + } + VendorEdge struct { Cursor func(childComplexity int) int Node func(childComplexity int) int @@ -1250,6 +1279,9 @@ type MutationResolver interface { UploadVendorBusinessAssociateAgreement(ctx context.Context, input types.UploadVendorBusinessAssociateAgreementInput) (*types.UploadVendorBusinessAssociateAgreementPayload, error) UpdateVendorBusinessAssociateAgreement(ctx context.Context, input types.UpdateVendorBusinessAssociateAgreementInput) (*types.UpdateVendorBusinessAssociateAgreementPayload, error) DeleteVendorBusinessAssociateAgreement(ctx context.Context, input types.DeleteVendorBusinessAssociateAgreementInput) (*types.DeleteVendorBusinessAssociateAgreementPayload, error) + UploadVendorDataPrivacyAgreement(ctx context.Context, input types.UploadVendorDataPrivacyAgreementInput) (*types.UploadVendorDataPrivacyAgreementPayload, error) + UpdateVendorDataPrivacyAgreement(ctx context.Context, input types.UpdateVendorDataPrivacyAgreementInput) (*types.UpdateVendorDataPrivacyAgreementPayload, error) + DeleteVendorDataPrivacyAgreement(ctx context.Context, input types.DeleteVendorDataPrivacyAgreementInput) (*types.DeleteVendorDataPrivacyAgreementPayload, error) CreateDocument(ctx context.Context, input types.CreateDocumentInput) (*types.CreateDocumentPayload, error) UpdateDocument(ctx context.Context, input types.UpdateDocumentInput) (*types.UpdateDocumentPayload, error) DeleteDocument(ctx context.Context, input types.DeleteDocumentInput) (*types.DeleteDocumentPayload, error) @@ -1336,6 +1368,7 @@ type VendorResolver interface { Organization(ctx context.Context, obj *types.Vendor) (*types.Organization, error) ComplianceReports(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) (*types.VendorComplianceReportConnection, error) BusinessAssociateAgreement(ctx context.Context, obj *types.Vendor) (*types.VendorBusinessAssociateAgreement, error) + DataPrivacyAgreement(ctx context.Context, obj *types.Vendor) (*types.VendorDataPrivacyAgreement, error) Contacts(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorContactOrderBy) (*types.VendorContactConnection, error) RiskAssessments(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) (*types.VendorRiskAssessmentConnection, error) BusinessOwner(ctx context.Context, obj *types.Vendor) (*types.People, error) @@ -1357,6 +1390,11 @@ type VendorConnectionResolver interface { type VendorContactResolver interface { Vendor(ctx context.Context, obj *types.VendorContact) (*types.Vendor, error) } +type VendorDataPrivacyAgreementResolver interface { + Vendor(ctx context.Context, obj *types.VendorDataPrivacyAgreement) (*types.Vendor, error) + + FileURL(ctx context.Context, obj *types.VendorDataPrivacyAgreement) (string, error) +} type VendorRiskAssessmentResolver interface { Vendor(ctx context.Context, obj *types.VendorRiskAssessment) (*types.Vendor, error) @@ -2308,6 +2346,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.DeleteVendorContactPayload.DeletedVendorContactID(childComplexity), true + case "DeleteVendorDataPrivacyAgreementPayload.deletedVendorId": + if e.complexity.DeleteVendorDataPrivacyAgreementPayload.DeletedVendorID == nil { + break + } + + return e.complexity.DeleteVendorDataPrivacyAgreementPayload.DeletedVendorID(childComplexity), true + case "DeleteVendorPayload.deletedVendorId": if e.complexity.DeleteVendorPayload.DeletedVendorID == nil { break @@ -3643,6 +3688,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Mutation.DeleteVendorContact(childComplexity, args["input"].(types.DeleteVendorContactInput)), true + case "Mutation.deleteVendorDataPrivacyAgreement": + if e.complexity.Mutation.DeleteVendorDataPrivacyAgreement == nil { + break + } + + args, err := ec.field_Mutation_deleteVendorDataPrivacyAgreement_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.DeleteVendorDataPrivacyAgreement(childComplexity, args["input"].(types.DeleteVendorDataPrivacyAgreementInput)), true + case "Mutation.exportDocumentVersionPDF": if e.complexity.Mutation.ExportDocumentVersionPDF == nil { break @@ -3991,6 +4048,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Mutation.UpdateVendorContact(childComplexity, args["input"].(types.UpdateVendorContactInput)), true + case "Mutation.updateVendorDataPrivacyAgreement": + if e.complexity.Mutation.UpdateVendorDataPrivacyAgreement == nil { + break + } + + args, err := ec.field_Mutation_updateVendorDataPrivacyAgreement_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.UpdateVendorDataPrivacyAgreement(childComplexity, args["input"].(types.UpdateVendorDataPrivacyAgreementInput)), true + case "Mutation.uploadAuditReport": if e.complexity.Mutation.UploadAuditReport == nil { break @@ -4051,6 +4120,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Mutation.UploadVendorComplianceReport(childComplexity, args["input"].(types.UploadVendorComplianceReportInput)), true + case "Mutation.uploadVendorDataPrivacyAgreement": + if e.complexity.Mutation.UploadVendorDataPrivacyAgreement == nil { + break + } + + args, err := ec.field_Mutation_uploadVendorDataPrivacyAgreement_args(ctx, rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.UploadVendorDataPrivacyAgreement(childComplexity, args["input"].(types.UploadVendorDataPrivacyAgreementInput)), true + case "Organization.assets": if e.complexity.Organization.Assets == nil { break @@ -5117,6 +5198,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.UpdateVendorContactPayload.VendorContact(childComplexity), true + case "UpdateVendorDataPrivacyAgreementPayload.vendorDataPrivacyAgreement": + if e.complexity.UpdateVendorDataPrivacyAgreementPayload.VendorDataPrivacyAgreement == nil { + break + } + + return e.complexity.UpdateVendorDataPrivacyAgreementPayload.VendorDataPrivacyAgreement(childComplexity), true + case "UpdateVendorPayload.vendor": if e.complexity.UpdateVendorPayload.Vendor == nil { break @@ -5159,6 +5247,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.UploadVendorComplianceReportPayload.VendorComplianceReportEdge(childComplexity), true + case "UploadVendorDataPrivacyAgreementPayload.vendorDataPrivacyAgreement": + if e.complexity.UploadVendorDataPrivacyAgreementPayload.VendorDataPrivacyAgreement == nil { + break + } + + return e.complexity.UploadVendorDataPrivacyAgreementPayload.VendorDataPrivacyAgreement(childComplexity), true + case "User.createdAt": if e.complexity.User.CreatedAt == nil { break @@ -5300,6 +5395,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Vendor.CreatedAt(childComplexity), true + case "Vendor.dataPrivacyAgreement": + if e.complexity.Vendor.DataPrivacyAgreement == nil { + break + } + + return e.complexity.Vendor.DataPrivacyAgreement(childComplexity), true + case "Vendor.dataProcessingAgreementUrl": if e.complexity.Vendor.DataProcessingAgreementURL == nil { break @@ -5697,6 +5799,69 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.VendorContactEdge.Node(childComplexity), true + case "VendorDataPrivacyAgreement.createdAt": + if e.complexity.VendorDataPrivacyAgreement.CreatedAt == nil { + break + } + + return e.complexity.VendorDataPrivacyAgreement.CreatedAt(childComplexity), true + + case "VendorDataPrivacyAgreement.fileName": + if e.complexity.VendorDataPrivacyAgreement.FileName == nil { + break + } + + return e.complexity.VendorDataPrivacyAgreement.FileName(childComplexity), true + + case "VendorDataPrivacyAgreement.fileSize": + if e.complexity.VendorDataPrivacyAgreement.FileSize == nil { + break + } + + return e.complexity.VendorDataPrivacyAgreement.FileSize(childComplexity), true + + case "VendorDataPrivacyAgreement.fileUrl": + if e.complexity.VendorDataPrivacyAgreement.FileURL == nil { + break + } + + return e.complexity.VendorDataPrivacyAgreement.FileURL(childComplexity), true + + case "VendorDataPrivacyAgreement.id": + if e.complexity.VendorDataPrivacyAgreement.ID == nil { + break + } + + return e.complexity.VendorDataPrivacyAgreement.ID(childComplexity), true + + case "VendorDataPrivacyAgreement.updatedAt": + if e.complexity.VendorDataPrivacyAgreement.UpdatedAt == nil { + break + } + + return e.complexity.VendorDataPrivacyAgreement.UpdatedAt(childComplexity), true + + case "VendorDataPrivacyAgreement.validFrom": + if e.complexity.VendorDataPrivacyAgreement.ValidFrom == nil { + break + } + + return e.complexity.VendorDataPrivacyAgreement.ValidFrom(childComplexity), true + + case "VendorDataPrivacyAgreement.validUntil": + if e.complexity.VendorDataPrivacyAgreement.ValidUntil == nil { + break + } + + return e.complexity.VendorDataPrivacyAgreement.ValidUntil(childComplexity), true + + case "VendorDataPrivacyAgreement.vendor": + if e.complexity.VendorDataPrivacyAgreement.Vendor == nil { + break + } + + return e.complexity.VendorDataPrivacyAgreement.Vendor(childComplexity), true + case "VendorEdge.cursor": if e.complexity.VendorEdge.Cursor == nil { break @@ -5898,6 +6063,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputDeleteVendorBusinessAssociateAgreementInput, ec.unmarshalInputDeleteVendorComplianceReportInput, ec.unmarshalInputDeleteVendorContactInput, + ec.unmarshalInputDeleteVendorDataPrivacyAgreementInput, ec.unmarshalInputDeleteVendorInput, ec.unmarshalInputDocumentFilter, ec.unmarshalInputDocumentOrder, @@ -5945,12 +6111,14 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputUpdateTrustCenterInput, ec.unmarshalInputUpdateVendorBusinessAssociateAgreementInput, ec.unmarshalInputUpdateVendorContactInput, + ec.unmarshalInputUpdateVendorDataPrivacyAgreementInput, ec.unmarshalInputUpdateVendorInput, ec.unmarshalInputUploadAuditReportInput, ec.unmarshalInputUploadMeasureEvidenceInput, ec.unmarshalInputUploadTaskEvidenceInput, ec.unmarshalInputUploadVendorBusinessAssociateAgreementInput, ec.unmarshalInputUploadVendorComplianceReportInput, + ec.unmarshalInputUploadVendorDataPrivacyAgreementInput, ec.unmarshalInputUserOrder, ec.unmarshalInputVendorComplianceReportOrder, ec.unmarshalInputVendorContactOrder, @@ -6997,6 +7165,7 @@ type Vendor implements Node { ): VendorComplianceReportConnection! @goField(forceResolver: true) businessAssociateAgreement: VendorBusinessAssociateAgreement @goField(forceResolver: true) + dataPrivacyAgreement: VendorDataPrivacyAgreement @goField(forceResolver: true) contacts( first: Int @@ -7070,6 +7239,18 @@ type VendorContact implements Node { updatedAt: Datetime! } +type VendorDataPrivacyAgreement implements Node { + id: ID! + vendor: Vendor! @goField(forceResolver: true) + validFrom: Datetime + validUntil: Datetime + fileName: String! + fileUrl: String! @goField(forceResolver: true) + fileSize: Int! + createdAt: Datetime! + updatedAt: Datetime! +} + type Framework implements Node { id: ID! name: String! @@ -7733,6 +7914,17 @@ type Mutation { input: DeleteVendorBusinessAssociateAgreementInput! ): DeleteVendorBusinessAssociateAgreementPayload! + # Vendor Data Privacy Agreement mutations + uploadVendorDataPrivacyAgreement( + input: UploadVendorDataPrivacyAgreementInput! + ): UploadVendorDataPrivacyAgreementPayload! + updateVendorDataPrivacyAgreement( + input: UpdateVendorDataPrivacyAgreementInput! + ): UpdateVendorDataPrivacyAgreementPayload! + deleteVendorDataPrivacyAgreement( + input: DeleteVendorDataPrivacyAgreementInput! + ): DeleteVendorDataPrivacyAgreementPayload! + # Document mutations createDocument(input: CreateDocumentInput!): CreateDocumentPayload! updateDocument(input: UpdateDocumentInput!): UpdateDocumentPayload! @@ -8126,6 +8318,24 @@ input DeleteVendorBusinessAssociateAgreementInput { vendorId: ID! } +input UploadVendorDataPrivacyAgreementInput { + vendorId: ID! + validFrom: Datetime + validUntil: Datetime + fileName: String! + file: Upload! +} + +input UpdateVendorDataPrivacyAgreementInput { + vendorId: ID! + validFrom: Datetime + validUntil: Datetime +} + +input DeleteVendorDataPrivacyAgreementInput { + vendorId: ID! +} + input CreateDocumentInput { organizationId: ID! title: String! @@ -8430,6 +8640,18 @@ type DeleteVendorBusinessAssociateAgreementPayload { deletedVendorId: ID! } +type UploadVendorDataPrivacyAgreementPayload { + vendorDataPrivacyAgreement: VendorDataPrivacyAgreement! +} + +type UpdateVendorDataPrivacyAgreementPayload { + vendorDataPrivacyAgreement: VendorDataPrivacyAgreement! +} + +type DeleteVendorDataPrivacyAgreementPayload { + deletedVendorId: ID! +} + type CreateDocumentPayload { documentEdge: DocumentEdge! documentVersionEdge: DocumentVersionEdge! @@ -11243,6 +11465,29 @@ func (ec *executionContext) field_Mutation_deleteVendorContact_argsInput( return zeroVal, nil } +func (ec *executionContext) field_Mutation_deleteVendorDataPrivacyAgreement_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_deleteVendorDataPrivacyAgreement_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_deleteVendorDataPrivacyAgreement_argsInput( + ctx context.Context, + rawArgs map[string]any, +) (types.DeleteVendorDataPrivacyAgreementInput, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNDeleteVendorDataPrivacyAgreementInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorDataPrivacyAgreementInput(ctx, tmp) + } + + var zeroVal types.DeleteVendorDataPrivacyAgreementInput + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_deleteVendor_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -11910,6 +12155,29 @@ func (ec *executionContext) field_Mutation_updateVendorContact_argsInput( return zeroVal, nil } +func (ec *executionContext) field_Mutation_updateVendorDataPrivacyAgreement_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_updateVendorDataPrivacyAgreement_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_updateVendorDataPrivacyAgreement_argsInput( + ctx context.Context, + rawArgs map[string]any, +) (types.UpdateVendorDataPrivacyAgreementInput, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNUpdateVendorDataPrivacyAgreementInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorDataPrivacyAgreementInput(ctx, tmp) + } + + var zeroVal types.UpdateVendorDataPrivacyAgreementInput + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_updateVendor_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -12048,6 +12316,29 @@ func (ec *executionContext) field_Mutation_uploadVendorComplianceReport_argsInpu return zeroVal, nil } +func (ec *executionContext) field_Mutation_uploadVendorDataPrivacyAgreement_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_uploadVendorDataPrivacyAgreement_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_uploadVendorDataPrivacyAgreement_argsInput( + ctx context.Context, + rawArgs map[string]any, +) (types.UploadVendorDataPrivacyAgreementInput, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNUploadVendorDataPrivacyAgreementInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUploadVendorDataPrivacyAgreementInput(ctx, tmp) + } + + var zeroVal types.UploadVendorDataPrivacyAgreementInput + return zeroVal, nil +} + func (ec *executionContext) field_Organization_assets_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -14617,6 +14908,8 @@ func (ec *executionContext) fieldContext_AssessVendorPayload_vendor(_ context.Co return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "dataPrivacyAgreement": + return ec.fieldContext_Vendor_dataPrivacyAgreement(ctx, field) case "contacts": return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": @@ -20977,6 +21270,50 @@ func (ec *executionContext) fieldContext_DeleteVendorContactPayload_deletedVendo return fc, nil } +func (ec *executionContext) _DeleteVendorDataPrivacyAgreementPayload_deletedVendorId(ctx context.Context, field graphql.CollectedField, obj *types.DeleteVendorDataPrivacyAgreementPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_DeleteVendorDataPrivacyAgreementPayload_deletedVendorId(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 obj.DeletedVendorID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(gid.GID) + fc.Result = res + return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_DeleteVendorDataPrivacyAgreementPayload_deletedVendorId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DeleteVendorDataPrivacyAgreementPayload", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _DeleteVendorPayload_deletedVendorId(ctx context.Context, field graphql.CollectedField, obj *types.DeleteVendorPayload) (ret graphql.Marshaler) { fc, err := ec.fieldContext_DeleteVendorPayload_deletedVendorId(ctx, field) if err != nil { @@ -29418,6 +29755,183 @@ func (ec *executionContext) fieldContext_Mutation_deleteVendorBusinessAssociateA return fc, nil } +func (ec *executionContext) _Mutation_uploadVendorDataPrivacyAgreement(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_uploadVendorDataPrivacyAgreement(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.Mutation().UploadVendorDataPrivacyAgreement(rctx, fc.Args["input"].(types.UploadVendorDataPrivacyAgreementInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*types.UploadVendorDataPrivacyAgreementPayload) + fc.Result = res + return ec.marshalNUploadVendorDataPrivacyAgreementPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUploadVendorDataPrivacyAgreementPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_uploadVendorDataPrivacyAgreement(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "vendorDataPrivacyAgreement": + return ec.fieldContext_UploadVendorDataPrivacyAgreementPayload_vendorDataPrivacyAgreement(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type UploadVendorDataPrivacyAgreementPayload", 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_Mutation_uploadVendorDataPrivacyAgreement_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_updateVendorDataPrivacyAgreement(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_updateVendorDataPrivacyAgreement(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.Mutation().UpdateVendorDataPrivacyAgreement(rctx, fc.Args["input"].(types.UpdateVendorDataPrivacyAgreementInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*types.UpdateVendorDataPrivacyAgreementPayload) + fc.Result = res + return ec.marshalNUpdateVendorDataPrivacyAgreementPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorDataPrivacyAgreementPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_updateVendorDataPrivacyAgreement(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "vendorDataPrivacyAgreement": + return ec.fieldContext_UpdateVendorDataPrivacyAgreementPayload_vendorDataPrivacyAgreement(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type UpdateVendorDataPrivacyAgreementPayload", 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_Mutation_updateVendorDataPrivacyAgreement_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_deleteVendorDataPrivacyAgreement(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_deleteVendorDataPrivacyAgreement(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.Mutation().DeleteVendorDataPrivacyAgreement(rctx, fc.Args["input"].(types.DeleteVendorDataPrivacyAgreementInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*types.DeleteVendorDataPrivacyAgreementPayload) + fc.Result = res + return ec.marshalNDeleteVendorDataPrivacyAgreementPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorDataPrivacyAgreementPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_deleteVendorDataPrivacyAgreement(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "deletedVendorId": + return ec.fieldContext_DeleteVendorDataPrivacyAgreementPayload_deletedVendorId(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type DeleteVendorDataPrivacyAgreementPayload", 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_Mutation_deleteVendorDataPrivacyAgreement_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Mutation_createDocument(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Mutation_createDocument(ctx, field) if err != nil { @@ -38467,6 +38981,70 @@ func (ec *executionContext) fieldContext_UpdateVendorContactPayload_vendorContac return fc, nil } +func (ec *executionContext) _UpdateVendorDataPrivacyAgreementPayload_vendorDataPrivacyAgreement(ctx context.Context, field graphql.CollectedField, obj *types.UpdateVendorDataPrivacyAgreementPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_UpdateVendorDataPrivacyAgreementPayload_vendorDataPrivacyAgreement(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 obj.VendorDataPrivacyAgreement, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*types.VendorDataPrivacyAgreement) + fc.Result = res + return ec.marshalNVendorDataPrivacyAgreement2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorDataPrivacyAgreement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_UpdateVendorDataPrivacyAgreementPayload_vendorDataPrivacyAgreement(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "UpdateVendorDataPrivacyAgreementPayload", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_VendorDataPrivacyAgreement_id(ctx, field) + case "vendor": + return ec.fieldContext_VendorDataPrivacyAgreement_vendor(ctx, field) + case "validFrom": + return ec.fieldContext_VendorDataPrivacyAgreement_validFrom(ctx, field) + case "validUntil": + return ec.fieldContext_VendorDataPrivacyAgreement_validUntil(ctx, field) + case "fileName": + return ec.fieldContext_VendorDataPrivacyAgreement_fileName(ctx, field) + case "fileUrl": + return ec.fieldContext_VendorDataPrivacyAgreement_fileUrl(ctx, field) + case "fileSize": + return ec.fieldContext_VendorDataPrivacyAgreement_fileSize(ctx, field) + case "createdAt": + return ec.fieldContext_VendorDataPrivacyAgreement_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_VendorDataPrivacyAgreement_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorDataPrivacyAgreement", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _UpdateVendorPayload_vendor(ctx context.Context, field graphql.CollectedField, obj *types.UpdateVendorPayload) (ret graphql.Marshaler) { fc, err := ec.fieldContext_UpdateVendorPayload_vendor(ctx, field) if err != nil { @@ -38520,6 +39098,8 @@ func (ec *executionContext) fieldContext_UpdateVendorPayload_vendor(_ context.Co return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "dataPrivacyAgreement": + return ec.fieldContext_Vendor_dataPrivacyAgreement(ctx, field) case "contacts": return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": @@ -38849,6 +39429,70 @@ func (ec *executionContext) fieldContext_UploadVendorComplianceReportPayload_ven return fc, nil } +func (ec *executionContext) _UploadVendorDataPrivacyAgreementPayload_vendorDataPrivacyAgreement(ctx context.Context, field graphql.CollectedField, obj *types.UploadVendorDataPrivacyAgreementPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_UploadVendorDataPrivacyAgreementPayload_vendorDataPrivacyAgreement(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 obj.VendorDataPrivacyAgreement, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*types.VendorDataPrivacyAgreement) + fc.Result = res + return ec.marshalNVendorDataPrivacyAgreement2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorDataPrivacyAgreement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_UploadVendorDataPrivacyAgreementPayload_vendorDataPrivacyAgreement(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "UploadVendorDataPrivacyAgreementPayload", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_VendorDataPrivacyAgreement_id(ctx, field) + case "vendor": + return ec.fieldContext_VendorDataPrivacyAgreement_vendor(ctx, field) + case "validFrom": + return ec.fieldContext_VendorDataPrivacyAgreement_validFrom(ctx, field) + case "validUntil": + return ec.fieldContext_VendorDataPrivacyAgreement_validUntil(ctx, field) + case "fileName": + return ec.fieldContext_VendorDataPrivacyAgreement_fileName(ctx, field) + case "fileUrl": + return ec.fieldContext_VendorDataPrivacyAgreement_fileUrl(ctx, field) + case "fileSize": + return ec.fieldContext_VendorDataPrivacyAgreement_fileSize(ctx, field) + case "createdAt": + return ec.fieldContext_VendorDataPrivacyAgreement_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_VendorDataPrivacyAgreement_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorDataPrivacyAgreement", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _User_id(ctx context.Context, field graphql.CollectedField, obj *types.User) (ret graphql.Marshaler) { fc, err := ec.fieldContext_User_id(ctx, field) if err != nil { @@ -39728,6 +40372,67 @@ func (ec *executionContext) fieldContext_Vendor_businessAssociateAgreement(_ con return fc, nil } +func (ec *executionContext) _Vendor_dataPrivacyAgreement(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Vendor_dataPrivacyAgreement(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.Vendor().DataPrivacyAgreement(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*types.VendorDataPrivacyAgreement) + fc.Result = res + return ec.marshalOVendorDataPrivacyAgreement2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorDataPrivacyAgreement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Vendor_dataPrivacyAgreement(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Vendor", + 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_VendorDataPrivacyAgreement_id(ctx, field) + case "vendor": + return ec.fieldContext_VendorDataPrivacyAgreement_vendor(ctx, field) + case "validFrom": + return ec.fieldContext_VendorDataPrivacyAgreement_validFrom(ctx, field) + case "validUntil": + return ec.fieldContext_VendorDataPrivacyAgreement_validUntil(ctx, field) + case "fileName": + return ec.fieldContext_VendorDataPrivacyAgreement_fileName(ctx, field) + case "fileUrl": + return ec.fieldContext_VendorDataPrivacyAgreement_fileUrl(ctx, field) + case "fileSize": + return ec.fieldContext_VendorDataPrivacyAgreement_fileSize(ctx, field) + case "createdAt": + return ec.fieldContext_VendorDataPrivacyAgreement_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_VendorDataPrivacyAgreement_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorDataPrivacyAgreement", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Vendor_contacts(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Vendor_contacts(ctx, field) if err != nil { @@ -40741,6 +41446,8 @@ func (ec *executionContext) fieldContext_VendorBusinessAssociateAgreement_vendor return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "dataPrivacyAgreement": + return ec.fieldContext_Vendor_dataPrivacyAgreement(ctx, field) case "contacts": return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": @@ -41187,6 +41894,8 @@ func (ec *executionContext) fieldContext_VendorComplianceReport_vendor(_ context return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "dataPrivacyAgreement": + return ec.fieldContext_Vendor_dataPrivacyAgreement(ctx, field) case "contacts": return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": @@ -41996,6 +42705,8 @@ func (ec *executionContext) fieldContext_VendorContact_vendor(_ context.Context, return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "dataPrivacyAgreement": + return ec.fieldContext_Vendor_dataPrivacyAgreement(ctx, field) case "contacts": return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": @@ -42505,6 +43216,454 @@ func (ec *executionContext) fieldContext_VendorContactEdge_node(_ context.Contex return fc, nil } +func (ec *executionContext) _VendorDataPrivacyAgreement_id(ctx context.Context, field graphql.CollectedField, obj *types.VendorDataPrivacyAgreement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorDataPrivacyAgreement_id(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 obj.ID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(gid.GID) + fc.Result = res + return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorDataPrivacyAgreement_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorDataPrivacyAgreement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorDataPrivacyAgreement_vendor(ctx context.Context, field graphql.CollectedField, obj *types.VendorDataPrivacyAgreement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorDataPrivacyAgreement_vendor(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.VendorDataPrivacyAgreement().Vendor(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*types.Vendor) + fc.Result = res + return ec.marshalNVendor2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendor(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorDataPrivacyAgreement_vendor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorDataPrivacyAgreement", + 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_Vendor_id(ctx, field) + case "name": + return ec.fieldContext_Vendor_name(ctx, field) + case "category": + return ec.fieldContext_Vendor_category(ctx, field) + case "description": + return ec.fieldContext_Vendor_description(ctx, field) + case "organization": + return ec.fieldContext_Vendor_organization(ctx, field) + case "complianceReports": + return ec.fieldContext_Vendor_complianceReports(ctx, field) + case "businessAssociateAgreement": + return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "dataPrivacyAgreement": + return ec.fieldContext_Vendor_dataPrivacyAgreement(ctx, field) + case "contacts": + return ec.fieldContext_Vendor_contacts(ctx, field) + case "riskAssessments": + return ec.fieldContext_Vendor_riskAssessments(ctx, field) + case "businessOwner": + return ec.fieldContext_Vendor_businessOwner(ctx, field) + case "securityOwner": + return ec.fieldContext_Vendor_securityOwner(ctx, field) + case "statusPageUrl": + return ec.fieldContext_Vendor_statusPageUrl(ctx, field) + case "termsOfServiceUrl": + return ec.fieldContext_Vendor_termsOfServiceUrl(ctx, field) + case "privacyPolicyUrl": + return ec.fieldContext_Vendor_privacyPolicyUrl(ctx, field) + case "serviceLevelAgreementUrl": + return ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field) + case "dataProcessingAgreementUrl": + return ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field) + case "businessAssociateAgreementUrl": + return ec.fieldContext_Vendor_businessAssociateAgreementUrl(ctx, field) + case "subprocessorsListUrl": + return ec.fieldContext_Vendor_subprocessorsListUrl(ctx, field) + case "certifications": + return ec.fieldContext_Vendor_certifications(ctx, field) + case "securityPageUrl": + return ec.fieldContext_Vendor_securityPageUrl(ctx, field) + case "trustPageUrl": + return ec.fieldContext_Vendor_trustPageUrl(ctx, field) + case "headquarterAddress": + return ec.fieldContext_Vendor_headquarterAddress(ctx, field) + case "legalName": + return ec.fieldContext_Vendor_legalName(ctx, field) + case "websiteUrl": + return ec.fieldContext_Vendor_websiteUrl(ctx, field) + case "showOnTrustCenter": + return ec.fieldContext_Vendor_showOnTrustCenter(ctx, field) + case "createdAt": + return ec.fieldContext_Vendor_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_Vendor_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Vendor", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorDataPrivacyAgreement_validFrom(ctx context.Context, field graphql.CollectedField, obj *types.VendorDataPrivacyAgreement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorDataPrivacyAgreement_validFrom(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 obj.ValidFrom, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalODatetime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorDataPrivacyAgreement_validFrom(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorDataPrivacyAgreement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorDataPrivacyAgreement_validUntil(ctx context.Context, field graphql.CollectedField, obj *types.VendorDataPrivacyAgreement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorDataPrivacyAgreement_validUntil(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 obj.ValidUntil, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*time.Time) + fc.Result = res + return ec.marshalODatetime2ᚖtimeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorDataPrivacyAgreement_validUntil(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorDataPrivacyAgreement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorDataPrivacyAgreement_fileName(ctx context.Context, field graphql.CollectedField, obj *types.VendorDataPrivacyAgreement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorDataPrivacyAgreement_fileName(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 obj.FileName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorDataPrivacyAgreement_fileName(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorDataPrivacyAgreement", + 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) _VendorDataPrivacyAgreement_fileUrl(ctx context.Context, field graphql.CollectedField, obj *types.VendorDataPrivacyAgreement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorDataPrivacyAgreement_fileUrl(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.VendorDataPrivacyAgreement().FileURL(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorDataPrivacyAgreement_fileUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorDataPrivacyAgreement", + 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) _VendorDataPrivacyAgreement_fileSize(ctx context.Context, field graphql.CollectedField, obj *types.VendorDataPrivacyAgreement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorDataPrivacyAgreement_fileSize(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 obj.FileSize, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorDataPrivacyAgreement_fileSize(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorDataPrivacyAgreement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorDataPrivacyAgreement_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.VendorDataPrivacyAgreement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorDataPrivacyAgreement_createdAt(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 obj.CreatedAt, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorDataPrivacyAgreement_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorDataPrivacyAgreement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorDataPrivacyAgreement_updatedAt(ctx context.Context, field graphql.CollectedField, obj *types.VendorDataPrivacyAgreement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorDataPrivacyAgreement_updatedAt(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 obj.UpdatedAt, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorDataPrivacyAgreement_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorDataPrivacyAgreement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _VendorEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *types.VendorEdge) (ret graphql.Marshaler) { fc, err := ec.fieldContext_VendorEdge_cursor(ctx, field) if err != nil { @@ -42602,6 +43761,8 @@ func (ec *executionContext) fieldContext_VendorEdge_node(_ context.Context, fiel return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "dataPrivacyAgreement": + return ec.fieldContext_Vendor_dataPrivacyAgreement(ctx, field) case "contacts": return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": @@ -42746,6 +43907,8 @@ func (ec *executionContext) fieldContext_VendorRiskAssessment_vendor(_ context.C return ec.fieldContext_Vendor_complianceReports(ctx, field) case "businessAssociateAgreement": return ec.fieldContext_Vendor_businessAssociateAgreement(ctx, field) + case "dataPrivacyAgreement": + return ec.fieldContext_Vendor_dataPrivacyAgreement(ctx, field) case "contacts": return ec.fieldContext_Vendor_contacts(ctx, field) case "riskAssessments": @@ -47702,6 +48865,33 @@ func (ec *executionContext) unmarshalInputDeleteVendorContactInput(ctx context.C return it, nil } +func (ec *executionContext) unmarshalInputDeleteVendorDataPrivacyAgreementInput(ctx context.Context, obj any) (types.DeleteVendorDataPrivacyAgreementInput, error) { + var it types.DeleteVendorDataPrivacyAgreementInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"vendorId"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "vendorId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("vendorId")) + data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.VendorID = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputDeleteVendorInput(ctx context.Context, obj any) (types.DeleteVendorInput, error) { var it types.DeleteVendorInput asMap := map[string]any{} @@ -49594,6 +50784,47 @@ func (ec *executionContext) unmarshalInputUpdateVendorContactInput(ctx context.C return it, nil } +func (ec *executionContext) unmarshalInputUpdateVendorDataPrivacyAgreementInput(ctx context.Context, obj any) (types.UpdateVendorDataPrivacyAgreementInput, error) { + var it types.UpdateVendorDataPrivacyAgreementInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"vendorId", "validFrom", "validUntil"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "vendorId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("vendorId")) + data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.VendorID = data + case "validFrom": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("validFrom")) + data, err := ec.unmarshalODatetime2ᚖtimeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.ValidFrom = data + case "validUntil": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("validUntil")) + data, err := ec.unmarshalODatetime2ᚖtimeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.ValidUntil = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context, obj any) (types.UpdateVendorInput, error) { var it types.UpdateVendorInput asMap := map[string]any{} @@ -49966,6 +51197,61 @@ func (ec *executionContext) unmarshalInputUploadVendorComplianceReportInput(ctx return it, nil } +func (ec *executionContext) unmarshalInputUploadVendorDataPrivacyAgreementInput(ctx context.Context, obj any) (types.UploadVendorDataPrivacyAgreementInput, error) { + var it types.UploadVendorDataPrivacyAgreementInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"vendorId", "validFrom", "validUntil", "fileName", "file"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "vendorId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("vendorId")) + data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.VendorID = data + case "validFrom": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("validFrom")) + data, err := ec.unmarshalODatetime2ᚖtimeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.ValidFrom = data + case "validUntil": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("validUntil")) + data, err := ec.unmarshalODatetime2ᚖtimeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.ValidUntil = data + case "fileName": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fileName")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.FileName = data + case "file": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("file")) + data, err := ec.unmarshalNUpload2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx, v) + if err != nil { + return it, err + } + it.File = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputUserOrder(ctx context.Context, obj any) (types.UserOrderBy, error) { var it types.UserOrderBy asMap := map[string]any{} @@ -50151,6 +51437,13 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj return graphql.Null } return ec._VendorRiskAssessment(ctx, sel, obj) + case types.VendorDataPrivacyAgreement: + return ec._VendorDataPrivacyAgreement(ctx, sel, &obj) + case *types.VendorDataPrivacyAgreement: + if obj == nil { + return graphql.Null + } + return ec._VendorDataPrivacyAgreement(ctx, sel, obj) case types.VendorContact: return ec._VendorContact(ctx, sel, &obj) case *types.VendorContact: @@ -53685,6 +54978,45 @@ func (ec *executionContext) _DeleteVendorContactPayload(ctx context.Context, sel return out } +var deleteVendorDataPrivacyAgreementPayloadImplementors = []string{"DeleteVendorDataPrivacyAgreementPayload"} + +func (ec *executionContext) _DeleteVendorDataPrivacyAgreementPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteVendorDataPrivacyAgreementPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, deleteVendorDataPrivacyAgreementPayloadImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("DeleteVendorDataPrivacyAgreementPayload") + case "deletedVendorId": + out.Values[i] = ec._DeleteVendorDataPrivacyAgreementPayload_deletedVendorId(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var deleteVendorPayloadImplementors = []string{"DeleteVendorPayload"} func (ec *executionContext) _DeleteVendorPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteVendorPayload) graphql.Marshaler { @@ -56208,6 +57540,27 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "uploadVendorDataPrivacyAgreement": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_uploadVendorDataPrivacyAgreement(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "updateVendorDataPrivacyAgreement": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_updateVendorDataPrivacyAgreement(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "deleteVendorDataPrivacyAgreement": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_deleteVendorDataPrivacyAgreement(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } case "createDocument": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_createDocument(ctx, field) @@ -59530,6 +60883,45 @@ func (ec *executionContext) _UpdateVendorContactPayload(ctx context.Context, sel return out } +var updateVendorDataPrivacyAgreementPayloadImplementors = []string{"UpdateVendorDataPrivacyAgreementPayload"} + +func (ec *executionContext) _UpdateVendorDataPrivacyAgreementPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateVendorDataPrivacyAgreementPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, updateVendorDataPrivacyAgreementPayloadImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("UpdateVendorDataPrivacyAgreementPayload") + case "vendorDataPrivacyAgreement": + out.Values[i] = ec._UpdateVendorDataPrivacyAgreementPayload_vendorDataPrivacyAgreement(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var updateVendorPayloadImplementors = []string{"UpdateVendorPayload"} func (ec *executionContext) _UpdateVendorPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateVendorPayload) graphql.Marshaler { @@ -59764,6 +61156,45 @@ func (ec *executionContext) _UploadVendorComplianceReportPayload(ctx context.Con return out } +var uploadVendorDataPrivacyAgreementPayloadImplementors = []string{"UploadVendorDataPrivacyAgreementPayload"} + +func (ec *executionContext) _UploadVendorDataPrivacyAgreementPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UploadVendorDataPrivacyAgreementPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, uploadVendorDataPrivacyAgreementPayloadImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("UploadVendorDataPrivacyAgreementPayload") + case "vendorDataPrivacyAgreement": + out.Values[i] = ec._UploadVendorDataPrivacyAgreementPayload_vendorDataPrivacyAgreement(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var userImplementors = []string{"User", "Node"} func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *types.User) graphql.Marshaler { @@ -60076,6 +61507,39 @@ func (ec *executionContext) _Vendor(ctx context.Context, sel ast.SelectionSet, o continue } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + case "dataPrivacyAgreement": + 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._Vendor_dataPrivacyAgreement(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 "contacts": field := field @@ -60904,6 +62368,141 @@ func (ec *executionContext) _VendorContactEdge(ctx context.Context, sel ast.Sele return out } +var vendorDataPrivacyAgreementImplementors = []string{"VendorDataPrivacyAgreement", "Node"} + +func (ec *executionContext) _VendorDataPrivacyAgreement(ctx context.Context, sel ast.SelectionSet, obj *types.VendorDataPrivacyAgreement) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, vendorDataPrivacyAgreementImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("VendorDataPrivacyAgreement") + case "id": + out.Values[i] = ec._VendorDataPrivacyAgreement_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "vendor": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._VendorDataPrivacyAgreement_vendor(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + 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 "validFrom": + out.Values[i] = ec._VendorDataPrivacyAgreement_validFrom(ctx, field, obj) + case "validUntil": + out.Values[i] = ec._VendorDataPrivacyAgreement_validUntil(ctx, field, obj) + case "fileName": + out.Values[i] = ec._VendorDataPrivacyAgreement_fileName(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "fileUrl": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._VendorDataPrivacyAgreement_fileUrl(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + 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 "fileSize": + out.Values[i] = ec._VendorDataPrivacyAgreement_fileSize(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "createdAt": + out.Values[i] = ec._VendorDataPrivacyAgreement_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "updatedAt": + out.Values[i] = ec._VendorDataPrivacyAgreement_updatedAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var vendorEdgeImplementors = []string{"VendorEdge"} func (ec *executionContext) _VendorEdge(ctx context.Context, sel ast.SelectionSet, obj *types.VendorEdge) graphql.Marshaler { @@ -63310,6 +64909,25 @@ func (ec *executionContext) marshalNDeleteVendorContactPayload2ᚖgithubᚗcom return ec._DeleteVendorContactPayload(ctx, sel, v) } +func (ec *executionContext) unmarshalNDeleteVendorDataPrivacyAgreementInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorDataPrivacyAgreementInput(ctx context.Context, v any) (types.DeleteVendorDataPrivacyAgreementInput, error) { + res, err := ec.unmarshalInputDeleteVendorDataPrivacyAgreementInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNDeleteVendorDataPrivacyAgreementPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorDataPrivacyAgreementPayload(ctx context.Context, sel ast.SelectionSet, v types.DeleteVendorDataPrivacyAgreementPayload) graphql.Marshaler { + return ec._DeleteVendorDataPrivacyAgreementPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNDeleteVendorDataPrivacyAgreementPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorDataPrivacyAgreementPayload(ctx context.Context, sel ast.SelectionSet, v *types.DeleteVendorDataPrivacyAgreementPayload) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._DeleteVendorDataPrivacyAgreementPayload(ctx, sel, v) +} + func (ec *executionContext) unmarshalNDeleteVendorInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteVendorInput(ctx context.Context, v any) (types.DeleteVendorInput, error) { res, err := ec.unmarshalInputDeleteVendorInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -65541,6 +67159,25 @@ func (ec *executionContext) marshalNUpdateVendorContactPayload2ᚖgithubᚗcom return ec._UpdateVendorContactPayload(ctx, sel, v) } +func (ec *executionContext) unmarshalNUpdateVendorDataPrivacyAgreementInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorDataPrivacyAgreementInput(ctx context.Context, v any) (types.UpdateVendorDataPrivacyAgreementInput, error) { + res, err := ec.unmarshalInputUpdateVendorDataPrivacyAgreementInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNUpdateVendorDataPrivacyAgreementPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorDataPrivacyAgreementPayload(ctx context.Context, sel ast.SelectionSet, v types.UpdateVendorDataPrivacyAgreementPayload) graphql.Marshaler { + return ec._UpdateVendorDataPrivacyAgreementPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNUpdateVendorDataPrivacyAgreementPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorDataPrivacyAgreementPayload(ctx context.Context, sel ast.SelectionSet, v *types.UpdateVendorDataPrivacyAgreementPayload) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._UpdateVendorDataPrivacyAgreementPayload(ctx, sel, v) +} + func (ec *executionContext) unmarshalNUpdateVendorInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateVendorInput(ctx context.Context, v any) (types.UpdateVendorInput, error) { res, err := ec.unmarshalInputUpdateVendorInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -65671,6 +67308,25 @@ func (ec *executionContext) marshalNUploadVendorComplianceReportPayload2ᚖgithu return ec._UploadVendorComplianceReportPayload(ctx, sel, v) } +func (ec *executionContext) unmarshalNUploadVendorDataPrivacyAgreementInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUploadVendorDataPrivacyAgreementInput(ctx context.Context, v any) (types.UploadVendorDataPrivacyAgreementInput, error) { + res, err := ec.unmarshalInputUploadVendorDataPrivacyAgreementInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNUploadVendorDataPrivacyAgreementPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUploadVendorDataPrivacyAgreementPayload(ctx context.Context, sel ast.SelectionSet, v types.UploadVendorDataPrivacyAgreementPayload) graphql.Marshaler { + return ec._UploadVendorDataPrivacyAgreementPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNUploadVendorDataPrivacyAgreementPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUploadVendorDataPrivacyAgreementPayload(ctx context.Context, sel ast.SelectionSet, v *types.UploadVendorDataPrivacyAgreementPayload) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._UploadVendorDataPrivacyAgreementPayload(ctx, sel, v) +} + func (ec *executionContext) marshalNUser2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUser(ctx context.Context, sel ast.SelectionSet, v *types.User) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -66095,6 +67751,16 @@ var ( } ) +func (ec *executionContext) marshalNVendorDataPrivacyAgreement2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorDataPrivacyAgreement(ctx context.Context, sel ast.SelectionSet, v *types.VendorDataPrivacyAgreement) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._VendorDataPrivacyAgreement(ctx, sel, v) +} + func (ec *executionContext) marshalNVendorEdge2ᚕᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*types.VendorEdge) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup @@ -67464,6 +69130,13 @@ func (ec *executionContext) unmarshalOVendorContactOrder2ᚖgithubᚗcomᚋgetpr return &res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) marshalOVendorDataPrivacyAgreement2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorDataPrivacyAgreement(ctx context.Context, sel ast.SelectionSet, v *types.VendorDataPrivacyAgreement) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._VendorDataPrivacyAgreement(ctx, sel, v) +} + func (ec *executionContext) unmarshalOVendorOrder2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorOrderBy(ctx context.Context, v any) (*types.VendorOrderBy, error) { if v == nil { return nil, nil diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go index a0a3fd719..0d3876dab 100644 --- a/pkg/server/api/console/v1/types/types.go +++ b/pkg/server/api/console/v1/types/types.go @@ -631,6 +631,14 @@ type DeleteVendorContactPayload struct { DeletedVendorContactID gid.GID `json:"deletedVendorContactId"` } +type DeleteVendorDataPrivacyAgreementInput struct { + VendorID gid.GID `json:"vendorId"` +} + +type DeleteVendorDataPrivacyAgreementPayload struct { + DeletedVendorID gid.GID `json:"deletedVendorId"` +} + type DeleteVendorInput struct { VendorID gid.GID `json:"vendorId"` } @@ -1306,6 +1314,16 @@ type UpdateVendorContactPayload struct { VendorContact *VendorContact `json:"vendorContact"` } +type UpdateVendorDataPrivacyAgreementInput struct { + VendorID gid.GID `json:"vendorId"` + ValidFrom *time.Time `json:"validFrom,omitempty"` + ValidUntil *time.Time `json:"validUntil,omitempty"` +} + +type UpdateVendorDataPrivacyAgreementPayload struct { + VendorDataPrivacyAgreement *VendorDataPrivacyAgreement `json:"vendorDataPrivacyAgreement"` +} + type UpdateVendorInput struct { ID gid.GID `json:"id"` Name *string `json:"name,omitempty"` @@ -1384,6 +1402,18 @@ type UploadVendorComplianceReportPayload struct { VendorComplianceReportEdge *VendorComplianceReportEdge `json:"vendorComplianceReportEdge"` } +type UploadVendorDataPrivacyAgreementInput struct { + VendorID gid.GID `json:"vendorId"` + ValidFrom *time.Time `json:"validFrom,omitempty"` + ValidUntil *time.Time `json:"validUntil,omitempty"` + FileName string `json:"fileName"` + File graphql.Upload `json:"file"` +} + +type UploadVendorDataPrivacyAgreementPayload struct { + VendorDataPrivacyAgreement *VendorDataPrivacyAgreement `json:"vendorDataPrivacyAgreement"` +} + type User struct { ID gid.GID `json:"id"` FullName string `json:"fullName"` @@ -1414,6 +1444,7 @@ type Vendor struct { Organization *Organization `json:"organization"` ComplianceReports *VendorComplianceReportConnection `json:"complianceReports"` BusinessAssociateAgreement *VendorBusinessAssociateAgreement `json:"businessAssociateAgreement,omitempty"` + DataPrivacyAgreement *VendorDataPrivacyAgreement `json:"dataPrivacyAgreement,omitempty"` Contacts *VendorContactConnection `json:"contacts"` RiskAssessments *VendorRiskAssessmentConnection `json:"riskAssessments"` BusinessOwner *People `json:"businessOwner,omitempty"` @@ -1503,6 +1534,21 @@ type VendorContactEdge struct { Node *VendorContact `json:"node"` } +type VendorDataPrivacyAgreement struct { + ID gid.GID `json:"id"` + Vendor *Vendor `json:"vendor"` + ValidFrom *time.Time `json:"validFrom,omitempty"` + ValidUntil *time.Time `json:"validUntil,omitempty"` + FileName string `json:"fileName"` + FileURL string `json:"fileUrl"` + FileSize int `json:"fileSize"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + +func (VendorDataPrivacyAgreement) IsNode() {} +func (this VendorDataPrivacyAgreement) GetID() gid.GID { return this.ID } + type VendorEdge struct { Cursor page.CursorKey `json:"cursor"` Node *Vendor `json:"node"` diff --git a/pkg/server/api/console/v1/types/vendor_data_privacy_agreement.go b/pkg/server/api/console/v1/types/vendor_data_privacy_agreement.go new file mode 100644 index 000000000..76b315e1d --- /dev/null +++ b/pkg/server/api/console/v1/types/vendor_data_privacy_agreement.go @@ -0,0 +1,31 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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" +) + +func NewVendorDataPrivacyAgreement(v *coredata.VendorDataPrivacyAgreement, file *coredata.File) *VendorDataPrivacyAgreement { + return &VendorDataPrivacyAgreement{ + ID: v.ID, + ValidFrom: v.ValidFrom, + ValidUntil: v.ValidUntil, + FileName: file.FileName, + FileSize: file.FileSize, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + } +} diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index f56e259c8..7d3c62940 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -2022,6 +2022,64 @@ func (r *mutationResolver) DeleteVendorBusinessAssociateAgreement(ctx context.Co }, nil } +// UploadVendorDataPrivacyAgreement is the resolver for the uploadVendorDataPrivacyAgreement field. +func (r *mutationResolver) UploadVendorDataPrivacyAgreement(ctx context.Context, input types.UploadVendorDataPrivacyAgreementInput) (*types.UploadVendorDataPrivacyAgreementPayload, error) { + prb := r.ProboService(ctx, input.VendorID.TenantID()) + + vendorDataPrivacyAgreement, file, err := prb.VendorDataPrivacyAgreements.Upload( + ctx, + input.VendorID, + &probo.VendorDataPrivacyAgreementCreateRequest{ + File: input.File.File, + ValidFrom: input.ValidFrom, + ValidUntil: input.ValidUntil, + FileName: input.FileName, + }, + ) + if err != nil { + return nil, fmt.Errorf("failed to upload vendor data privacy agreement: %w", err) + } + + return &types.UploadVendorDataPrivacyAgreementPayload{ + VendorDataPrivacyAgreement: types.NewVendorDataPrivacyAgreement(vendorDataPrivacyAgreement, file), + }, nil +} + +// UpdateVendorDataPrivacyAgreement is the resolver for the updateVendorDataPrivacyAgreement field. +func (r *mutationResolver) UpdateVendorDataPrivacyAgreement(ctx context.Context, input types.UpdateVendorDataPrivacyAgreementInput) (*types.UpdateVendorDataPrivacyAgreementPayload, error) { + prb := r.ProboService(ctx, input.VendorID.TenantID()) + + vendorDataPrivacyAgreement, file, err := prb.VendorDataPrivacyAgreements.Update( + ctx, + input.VendorID, + &probo.VendorDataPrivacyAgreementUpdateRequest{ + ValidFrom: &input.ValidFrom, + ValidUntil: &input.ValidUntil, + }, + ) + if err != nil { + return nil, fmt.Errorf("failed to update vendor data privacy agreement: %w", err) + } + + return &types.UpdateVendorDataPrivacyAgreementPayload{ + VendorDataPrivacyAgreement: types.NewVendorDataPrivacyAgreement(vendorDataPrivacyAgreement, file), + }, nil +} + +// DeleteVendorDataPrivacyAgreement is the resolver for the deleteVendorDataPrivacyAgreement field. +func (r *mutationResolver) DeleteVendorDataPrivacyAgreement(ctx context.Context, input types.DeleteVendorDataPrivacyAgreementInput) (*types.DeleteVendorDataPrivacyAgreementPayload, error) { + prb := r.ProboService(ctx, input.VendorID.TenantID()) + + err := prb.VendorDataPrivacyAgreements.DeleteByVendorID(ctx, input.VendorID) + if err != nil { + return nil, fmt.Errorf("failed to delete vendor data privacy agreement: %w", err) + } + + return &types.DeleteVendorDataPrivacyAgreementPayload{ + DeletedVendorID: input.VendorID, + }, nil +} + // CreateDocument is the resolver for the createDocument field. func (r *mutationResolver) CreateDocument(ctx context.Context, input types.CreateDocumentInput) (*types.CreateDocumentPayload, error) { prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -3469,6 +3527,22 @@ func (r *vendorResolver) BusinessAssociateAgreement(ctx context.Context, obj *ty return types.NewVendorBusinessAssociateAgreement(vendorBusinessAssociateAgreement, file), nil } +// DataPrivacyAgreement is the resolver for the dataPrivacyAgreement field. +func (r *vendorResolver) DataPrivacyAgreement(ctx context.Context, obj *types.Vendor) (*types.VendorDataPrivacyAgreement, error) { + prb := r.ProboService(ctx, obj.ID.TenantID()) + + vendorDataPrivacyAgreement, file, err := prb.VendorDataPrivacyAgreements.GetByVendorID(ctx, obj.ID) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return nil, nil + } + + return nil, fmt.Errorf("failed to get vendor data privacy agreement: %w", err) + } + + return types.NewVendorDataPrivacyAgreement(vendorDataPrivacyAgreement, file), nil +} + // Contacts is the resolver for the contacts field. func (r *vendorResolver) Contacts(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorContactOrderBy) (*types.VendorContactConnection, error) { prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -3654,6 +3728,30 @@ func (r *vendorContactResolver) Vendor(ctx context.Context, obj *types.VendorCon return types.NewVendor(vendor), nil } +// Vendor is the resolver for the vendor field. +func (r *vendorDataPrivacyAgreementResolver) Vendor(ctx context.Context, obj *types.VendorDataPrivacyAgreement) (*types.Vendor, error) { + prb := r.ProboService(ctx, obj.ID.TenantID()) + + vendor, err := prb.Vendors.Get(ctx, obj.ID) + if err != nil { + return nil, fmt.Errorf("failed to get vendor: %w", err) + } + + return types.NewVendor(vendor), nil +} + +// FileURL is the resolver for the fileUrl field. +func (r *vendorDataPrivacyAgreementResolver) FileURL(ctx context.Context, obj *types.VendorDataPrivacyAgreement) (string, error) { + prb := r.ProboService(ctx, obj.ID.TenantID()) + + fileURL, err := prb.VendorDataPrivacyAgreements.GenerateFileURL(ctx, obj.ID, 1*time.Hour) + if err != nil { + return "", fmt.Errorf("failed to generate file URL: %w", err) + } + + return fileURL, nil +} + // Vendor is the resolver for the vendor field. func (r *vendorRiskAssessmentResolver) Vendor(ctx context.Context, obj *types.VendorRiskAssessment) (*types.Vendor, error) { prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -3838,6 +3936,11 @@ func (r *Resolver) VendorConnection() schema.VendorConnectionResolver { // VendorContact returns schema.VendorContactResolver implementation. func (r *Resolver) VendorContact() schema.VendorContactResolver { return &vendorContactResolver{r} } +// VendorDataPrivacyAgreement returns schema.VendorDataPrivacyAgreementResolver implementation. +func (r *Resolver) VendorDataPrivacyAgreement() schema.VendorDataPrivacyAgreementResolver { + return &vendorDataPrivacyAgreementResolver{r} +} + // VendorRiskAssessment returns schema.VendorRiskAssessmentResolver implementation. func (r *Resolver) VendorRiskAssessment() schema.VendorRiskAssessmentResolver { return &vendorRiskAssessmentResolver{r} @@ -3880,5 +3983,6 @@ type vendorBusinessAssociateAgreementResolver struct{ *Resolver } type vendorComplianceReportResolver struct{ *Resolver } type vendorConnectionResolver struct{ *Resolver } type vendorContactResolver struct{ *Resolver } +type vendorDataPrivacyAgreementResolver struct{ *Resolver } type vendorRiskAssessmentResolver struct{ *Resolver } type viewerResolver struct{ *Resolver }