Expire vendor risk assement

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-04-22 16:02:05 -07:00
parent 61eb6dc8d0
commit ca1b7e8f42
14 changed files with 489 additions and 146 deletions

View File

@@ -94,6 +94,13 @@ const vendorViewQuery = graphql`
organization: node(id: $organizationId) { organization: node(id: $organizationId) {
...PeopleSelector_organization ...PeopleSelector_organization
} }
viewer {
user {
people(organizationId: $organizationId) {
id
}
}
}
} }
`; `;
@@ -675,6 +682,13 @@ function RiskAssessmentsTable({
}); });
}; };
// Check if assessment is expired
const isExpired = (expiresAt: string) => {
console.log(new Date(expiresAt) < new Date());
return new Date(expiresAt) < new Date();
};
// Get severity label based on data sensitivity and business impact // Get severity label based on data sensitivity and business impact
const getSeverityLabel = (dataSensitivity: string, businessImpact: string) => { const getSeverityLabel = (dataSensitivity: string, businessImpact: string) => {
// Simple logic to determine severity - can be adjusted based on requirements // Simple logic to determine severity - can be adjusted based on requirements
@@ -731,35 +745,67 @@ function RiskAssessmentsTable({
<tbody> <tbody>
{assessments.map((assessment) => { {assessments.map((assessment) => {
const severity = getSeverityLabel(assessment.dataSensitivity, assessment.businessImpact); const severity = getSeverityLabel(assessment.dataSensitivity, assessment.businessImpact);
const expired = isExpired(assessment.expiresAt);
return ( return (
<tr key={assessment.id} className="border-b border-[rgba(2,42,2,0.08)]"> <tr
key={assessment.id}
className={cn(
"border-b border-[rgba(2,42,2,0.08)]",
expired && "bg-[#F7F7F7] text-[#A0A5A0]"
)}
>
<td className="px-4 py-3"> <td className="px-4 py-3">
<span className="text-sm font-normal text-[#141E12]"> <span className={cn(
"text-sm font-normal",
expired ? "text-[#A0A5A0]" : "text-[#141E12]"
)}>
{formatDate(assessment.assessedAt)} {formatDate(assessment.assessedAt)}
</span> </span>
</td> </td>
<td className="px-4 py-3"> <td className="px-4 py-3">
<span className="text-sm font-normal text-[#141E12]"> <div className="flex items-center">
<span className={cn(
"text-sm font-normal",
expired ? "text-[#A0A5A0]" : "text-[#141E12]"
)}>
{formatDate(assessment.expiresAt)} {formatDate(assessment.expiresAt)}
</span> </span>
{expired && (
<span className="ml-2 text-xs py-0.5 px-1.5 bg-[#F0F0F0] text-[#818780] rounded">
Expired
</span>
)}
</div>
</td> </td>
<td className="px-4 py-3"> <td className="px-4 py-3">
<span className="text-sm font-normal text-[#141E12]"> <span className={cn(
"text-sm font-normal",
expired ? "text-[#A0A5A0]" : "text-[#141E12]"
)}>
{assessment.dataSensitivity.charAt(0) + assessment.dataSensitivity.slice(1).toLowerCase()} {assessment.dataSensitivity.charAt(0) + assessment.dataSensitivity.slice(1).toLowerCase()}
</span> </span>
</td> </td>
<td className="px-4 py-3"> <td className="px-4 py-3">
<span className="text-sm font-normal text-[#141E12]"> <span className={cn(
"text-sm font-normal",
expired ? "text-[#A0A5A0]" : "text-[#141E12]"
)}>
{assessment.businessImpact.charAt(0) + assessment.businessImpact.slice(1).toLowerCase()} {assessment.businessImpact.charAt(0) + assessment.businessImpact.slice(1).toLowerCase()}
</span> </span>
</td> </td>
<td className="px-4 py-3"> <td className="px-4 py-3">
<span className={`text-sm font-normal px-2 py-1 rounded-full ${severity.color}`}> <span className={cn(
"text-sm font-normal px-2 py-1 rounded-full",
expired ? "bg-[#F0F0F0] text-[#818780]" : severity.color
)}>
{severity.label} {severity.label}
</span> </span>
</td> </td>
<td className="px-4 py-3"> <td className="px-4 py-3">
<span className="text-sm font-normal text-[#141E12]"> <span className={cn(
"text-sm font-normal",
expired ? "text-[#A0A5A0]" : "text-[#141E12]"
)}>
{assessment.assessedBy?.fullName || 'N/A'} {assessment.assessedBy?.fullName || 'N/A'}
</span> </span>
</td> </td>
@@ -770,9 +816,9 @@ function RiskAssessmentsTable({
onClick={() => setShowDropdown(showDropdown === assessment.id ? null : assessment.id)} onClick={() => setShowDropdown(showDropdown === assessment.id ? null : assessment.id)}
> >
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 9.5C8.82843 9.5 9.5 8.82843 9.5 8C9.5 7.17157 8.82843 6.5 8 6.5C7.17157 6.5 6.5 7.17157 6.5 8C6.5 8.82843 7.17157 9.5 8 9.5Z" fill="#141E12"/> <path d="M8 9.5C8.82843 9.5 9.5 8.82843 9.5 8C9.5 7.17157 8.82843 6.5 8 6.5C7.17157 6.5 6.5 7.17157 6.5 8C6.5 8.82843 7.17157 9.5 8 9.5Z" fill={expired ? "#A0A5A0" : "#141E12"}/>
<path d="M3 9.5C3.82843 9.5 4.5 8.82843 4.5 8C4.5 7.17157 3.82843 6.5 3 6.5C2.17157 6.5 1.5 7.17157 1.5 8C1.5 8.82843 2.17157 9.5 3 9.5Z" fill="#141E12"/> <path d="M3 9.5C3.82843 9.5 4.5 8.82843 4.5 8C4.5 7.17157 3.82843 6.5 3 6.5C2.17157 6.5 1.5 7.17157 1.5 8C1.5 8.82843 2.17157 9.5 3 9.5Z" fill={expired ? "#A0A5A0" : "#141E12"}/>
<path d="M13 9.5C13.8284 9.5 14.5 8.82843 14.5 8C14.5 7.17157 13.8284 6.5 13 6.5C12.1716 6.5 11.5 7.17157 11.5 8C11.5 8.82843 12.1716 9.5 13 9.5Z" fill="#141E12"/> <path d="M13 9.5C13.8284 9.5 14.5 8.82843 14.5 8C14.5 7.17157 13.8284 6.5 13 6.5C12.1716 6.5 11.5 7.17157 11.5 8C11.5 8.82843 12.1716 9.5 13 9.5Z" fill={expired ? "#A0A5A0" : "#141E12"}/>
</svg> </svg>
</button> </button>
{showDropdown === assessment.id && ( {showDropdown === assessment.id && (
@@ -1270,27 +1316,9 @@ function VendorViewContent({
businessImpact: BusinessImpact; businessImpact: BusinessImpact;
notes: string; notes: string;
}) => { }) => {
// Close the modal const nextYear = new Date();
setShowRiskAssessmentModal(false);
// Current date for assessedAt, and 1 year later for expiresAt
const today = new Date();
const nextYear = new Date(today);
nextYear.setFullYear(nextYear.getFullYear() + 1); nextYear.setFullYear(nextYear.getFullYear() + 1);
// Check if there's a business owner assigned
const businessOwnerId = data.node.businessOwner?.id;
if (!businessOwnerId) {
// This check is now redundant as it's handled in the modal
// but keeping it as a safeguard
toast({
title: "Error",
description: "Please assign a Business Owner to the vendor before creating a risk assessment",
variant: "destructive",
});
return;
}
createRiskAssessment({ createRiskAssessment({
variables: { variables: {
connections: [ connections: [
@@ -1301,12 +1329,11 @@ function VendorViewContent({
], ],
input: { input: {
vendorId: data.node.id!, vendorId: data.node.id!,
assessedBy: businessOwnerId, assessedBy: data.viewer.user.people?.id!,
expiresAt: nextYear.toISOString(), expiresAt: nextYear.toISOString(),
dataSensitivity: formValues.dataSensitivity, dataSensitivity: formValues.dataSensitivity,
businessImpact: formValues.businessImpact, businessImpact: formValues.businessImpact,
notes: formValues.notes || "Risk assessment", notes: formValues.notes || "Risk assessment",
attachments: []
}, },
}, },
onCompleted: () => { onCompleted: () => {
@@ -1315,6 +1342,7 @@ function VendorViewContent({
description: "Risk assessment created successfully", description: "Risk assessment created successfully",
variant: "default", variant: "default",
}); });
setShowRiskAssessmentModal(false);
loadQuery({ loadQuery({
vendorId: data.node.id!, vendorId: data.node.id!,
organizationId: organizationId!, organizationId: organizationId!,
@@ -1328,7 +1356,7 @@ function VendorViewContent({
}); });
}, },
}); });
}, [createRiskAssessment, data.node.id, data.node.businessOwner?.id, loadQuery, toast, organizationId]); }, [createRiskAssessment, data.node.id, data.viewer.user.people?.id, loadQuery, toast, organizationId]);
const formatDate = (dateStr: string | null | undefined) => { const formatDate = (dateStr: string | null | undefined) => {
if (!dateStr) return "N/A"; if (!dateStr) return "N/A";

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<8372d50934049d43afb678c894f40dbd>> * @generated SignedSource<<08de2d8758474132b472d63f413b59a5>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -13,7 +13,6 @@ export type BusinessImpact = "CRITICAL" | "HIGH" | "LOW" | "MEDIUM";
export type DataSensitivity = "CRITICAL" | "HIGH" | "LOW" | "MEDIUM" | "NONE"; export type DataSensitivity = "CRITICAL" | "HIGH" | "LOW" | "MEDIUM" | "NONE";
export type CreateVendorRiskAssessmentInput = { export type CreateVendorRiskAssessmentInput = {
assessedBy: string; assessedBy: string;
attachments?: ReadonlyArray<string> | null | undefined;
businessImpact: BusinessImpact; businessImpact: BusinessImpact;
dataSensitivity: DataSensitivity; dataSensitivity: DataSensitivity;
expiresAt: string; expiresAt: string;

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<bbfa9d7b4ab300f8ab96380582d2d9b7>> * @generated SignedSource<<c189e0079d6d90c845d93a6a108a0b76>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -78,6 +78,13 @@ export type VendorViewQuery$data = {
readonly organization: { readonly organization: {
readonly " $fragmentSpreads": FragmentRefs<"PeopleSelector_organization">; readonly " $fragmentSpreads": FragmentRefs<"PeopleSelector_organization">;
}; };
readonly viewer: {
readonly user: {
readonly people: {
readonly id: string;
} | null | undefined;
};
};
}; };
export type VendorViewQuery = { export type VendorViewQuery = {
response: VendorViewQuery$data; response: VendorViewQuery$data;
@@ -444,15 +451,33 @@ v30 = [
} }
], ],
v31 = { v31 = {
"alias": null,
"args": [
{
"kind": "Variable",
"name": "organizationId",
"variableName": "organizationId"
}
],
"concreteType": "People",
"kind": "LinkedField",
"name": "people",
"plural": false,
"selections": [
(v3/*: any*/)
],
"storageKey": null
},
v32 = {
"kind": "Literal", "kind": "Literal",
"name": "first", "name": "first",
"value": 100 "value": 100
}, },
v32 = [
(v31/*: any*/)
],
v33 = [ v33 = [
(v31/*: any*/), (v32/*: any*/)
],
v34 = [
(v32/*: any*/),
{ {
"kind": "Literal", "kind": "Literal",
"name": "orderBy", "name": "orderBy",
@@ -545,6 +570,29 @@ return {
} }
], ],
"storageKey": null "storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Viewer",
"kind": "LinkedField",
"name": "viewer",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "User",
"kind": "LinkedField",
"name": "user",
"plural": false,
"selections": [
(v31/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
} }
], ],
"type": "Query", "type": "Query",
@@ -593,7 +641,7 @@ return {
(v24/*: any*/), (v24/*: any*/),
{ {
"alias": null, "alias": null,
"args": (v32/*: any*/), "args": (v33/*: any*/),
"concreteType": "VendorComplianceReportConnection", "concreteType": "VendorComplianceReportConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "complianceReports", "name": "complianceReports",
@@ -603,7 +651,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v32/*: any*/), "args": (v33/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "VendorView_complianceReports", "key": "VendorView_complianceReports",
@@ -612,7 +660,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v32/*: any*/), "args": (v33/*: any*/),
"concreteType": "VendorRiskAssessmentConnection", "concreteType": "VendorRiskAssessmentConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "riskAssessments", "name": "riskAssessments",
@@ -622,7 +670,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v32/*: any*/), "args": (v33/*: any*/),
"filters": null, "filters": null,
"handle": "connection", "handle": "connection",
"key": "VendorView_riskAssessments", "key": "VendorView_riskAssessments",
@@ -651,7 +699,7 @@ return {
"selections": [ "selections": [
{ {
"alias": null, "alias": null,
"args": (v33/*: any*/), "args": (v34/*: any*/),
"concreteType": "PeopleConnection", "concreteType": "PeopleConnection",
"kind": "LinkedField", "kind": "LinkedField",
"name": "peoples", "name": "peoples",
@@ -696,7 +744,7 @@ return {
}, },
{ {
"alias": null, "alias": null,
"args": (v33/*: any*/), "args": (v34/*: any*/),
"filters": [ "filters": [
"orderBy" "orderBy"
], ],
@@ -711,11 +759,36 @@ return {
} }
], ],
"storageKey": null "storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Viewer",
"kind": "LinkedField",
"name": "viewer",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "User",
"kind": "LinkedField",
"name": "user",
"plural": false,
"selections": [
(v31/*: any*/),
(v3/*: any*/)
],
"storageKey": null
},
(v3/*: any*/)
],
"storageKey": null
} }
] ]
}, },
"params": { "params": {
"cacheID": "5df12f781d305bd4bd6b6c0ccb4d947e", "cacheID": "9b2a625a96210e0168dceed7e4b98ed0",
"id": null, "id": null,
"metadata": { "metadata": {
"connection": [ "connection": [
@@ -741,11 +814,11 @@ return {
}, },
"name": "VendorViewQuery", "name": "VendorViewQuery",
"operationKind": "query", "operationKind": "query",
"text": "query VendorViewQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n description\n serviceStartAt\n serviceTerminationAt\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n businessOwner {\n id\n fullName\n }\n securityOwner {\n id\n fullName\n }\n createdAt\n updatedAt\n complianceReports(first: 100) {\n edges {\n node {\n id\n reportName\n reportDate\n validUntil\n fileUrl\n fileSize\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n riskAssessments(first: 100) {\n edges {\n node {\n id\n assessedAt\n expiresAt\n dataSensitivity\n businessImpact\n notes\n assessedBy {\n id\n fullName\n }\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n organization: node(id: $organizationId) {\n __typename\n ...PeopleSelector_organization\n id\n }\n}\n\nfragment PeopleSelector_organization on Organization {\n id\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n" "text": "query VendorViewQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n description\n serviceStartAt\n serviceTerminationAt\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n businessOwner {\n id\n fullName\n }\n securityOwner {\n id\n fullName\n }\n createdAt\n updatedAt\n complianceReports(first: 100) {\n edges {\n node {\n id\n reportName\n reportDate\n validUntil\n fileUrl\n fileSize\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n riskAssessments(first: 100) {\n edges {\n node {\n id\n assessedAt\n expiresAt\n dataSensitivity\n businessImpact\n notes\n assessedBy {\n id\n fullName\n }\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n organization: node(id: $organizationId) {\n __typename\n ...PeopleSelector_organization\n id\n }\n viewer {\n user {\n people(organizationId: $organizationId) {\n id\n }\n id\n }\n id\n }\n}\n\nfragment PeopleSelector_organization on Organization {\n id\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n"
} }
}; };
})(); })();
(node as any).hash = "2b856ea721d1bfb6b853fc281ee1aac6"; (node as any).hash = "7f9a178bd20cefd76440ea8d71c3b2fa";
export default node; export default node;

View File

@@ -0,0 +1,2 @@
ALTER TABLE vendor_risk_assessments ALTER COLUMN approved_at DROP NOT NULL;
ALTER TABLE vendor_risk_assessments ALTER COLUMN approved_by DROP NOT NULL;

View File

@@ -0,0 +1,3 @@
ALTER TABLE vendor_risk_assessments DROP COLUMN accessed_at;
ALTER TABLE vendor_risk_assessments DROP COLUMN accessed_by;

View File

@@ -98,6 +98,53 @@ LIMIT 1;
return nil return nil
} }
func (p *People) LoadByUserID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
organizationID gid.GID,
userID gid.GID,
) error {
q := `
SELECT
id,
organization_id,
kind,
user_id,
full_name,
primary_email_address,
additional_email_addresses,
created_at,
updated_at
FROM
peoples
WHERE
%s
AND organization_id = @organization_id
AND user_id = @user_id
LIMIT 1;
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{"organization_id": organizationID, "user_id": userID}
maps.Copy(args, scope.SQLArguments())
rows, err := conn.Query(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot query people: %w", err)
}
people, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[People])
if err != nil {
return fmt.Errorf("cannot collect people: %w", err)
}
*p = people
return nil
}
func (p People) Insert( func (p People) Insert(
ctx context.Context, ctx context.Context,
conn pg.Conn, conn pg.Conn,

View File

@@ -350,3 +350,37 @@ WHERE %s
_, err := conn.Exec(ctx, q, args) _, err := conn.Exec(ctx, q, args)
return err return err
} }
func (v Vendor) ExpireNonExpiredRiskAssessments(
ctx context.Context,
conn pg.Conn,
scope Scoper,
) error {
now := time.Now()
q := `
UPDATE vendor_risk_assessments
SET
expires_at = @now,
updated_at = @now
WHERE
%s
AND vendor_id = @vendor_id
AND expires_at > @now
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"vendor_id": v.ID,
"now": now,
}
maps.Copy(args, scope.SQLArguments())
_, err := conn.Exec(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot expire existing risk assessments: %w", err)
}
return nil
}

View File

@@ -33,9 +33,8 @@ type (
VendorID gid.GID `db:"vendor_id"` VendorID gid.GID `db:"vendor_id"`
AssessedAt time.Time `db:"assessed_at"` AssessedAt time.Time `db:"assessed_at"`
AssessedBy gid.GID `db:"assessed_by"` AssessedBy gid.GID `db:"assessed_by"`
AccessedAt time.Time `db:"accessed_at"` ApprovedBy *gid.GID `db:"approved_by"`
ApprovedBy gid.GID `db:"approved_by"` ApprovedAt *time.Time `db:"approved_at"`
ApprovedAt time.Time `db:"approved_at"`
ExpiresAt time.Time `db:"expires_at"` ExpiresAt time.Time `db:"expires_at"`
DataSensitivity DataSensitivity `db:"data_sensitivity"` DataSensitivity DataSensitivity `db:"data_sensitivity"`
BusinessImpact BusinessImpact `db:"business_impact"` BusinessImpact BusinessImpact `db:"business_impact"`
@@ -96,7 +95,6 @@ INSERT INTO
vendor_id, vendor_id,
assessed_at, assessed_at,
assessed_by, assessed_by,
accessed_at,
approved_by, approved_by,
approved_at, approved_at,
expires_at, expires_at,
@@ -112,11 +110,12 @@ VALUES (
@vendor_id, @vendor_id,
@assessed_at, @assessed_at,
@assessed_by, @assessed_by,
@approved_by,
@approved_at,
@expires_at, @expires_at,
@data_sensitivity, @data_sensitivity,
@business_impact, @business_impact,
@notes, @notes,
@attachments,
@created_at, @created_at,
@updated_at @updated_at
) )
@@ -128,7 +127,6 @@ VALUES (
"vendor_id": r.VendorID, "vendor_id": r.VendorID,
"assessed_at": r.AssessedAt, "assessed_at": r.AssessedAt,
"assessed_by": r.AssessedBy, "assessed_by": r.AssessedBy,
"accessed_at": r.AccessedAt,
"approved_by": r.ApprovedBy, "approved_by": r.ApprovedBy,
"approved_at": r.ApprovedAt, "approved_at": r.ApprovedAt,
"expires_at": r.ExpiresAt, "expires_at": r.ExpiresAt,
@@ -155,7 +153,6 @@ SELECT
vendor_id, vendor_id,
assessed_at, assessed_at,
assessed_by, assessed_by,
accessed_at,
approved_by, approved_by,
approved_at, approved_at,
expires_at, expires_at,
@@ -206,7 +203,6 @@ SELECT
vendor_id, vendor_id,
assessed_at, assessed_at,
assessed_by, assessed_by,
accessed_at,
approved_by, approved_by,
approved_at, approved_at,
expires_at, expires_at,
@@ -260,7 +256,6 @@ SELECT
vendor_id, vendor_id,
assessed_at, assessed_at,
assessed_by, assessed_by,
accessed_at,
approved_by, approved_by,
approved_at, approved_at,
expires_at, expires_at,

View File

@@ -69,6 +69,27 @@ func (s PeopleService) Get(
return people, nil return people, nil
} }
func (s PeopleService) GetByUserID(
ctx context.Context,
organizationID gid.GID,
userID gid.GID,
) (*coredata.People, error) {
people := &coredata.People{}
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return people.LoadByUserID(ctx, conn, s.svc.scope, organizationID, userID)
},
)
if err != nil {
return nil, err
}
return people, nil
}
func (s PeopleService) ListForOrganizationID( func (s PeopleService) ListForOrganizationID(
ctx context.Context, ctx context.Context,
organizationID gid.GID, organizationID gid.GID,

View File

@@ -359,6 +359,7 @@ func (s VendorService) CreateRiskAssessment(
ID: vendorRiskAssessmentID, ID: vendorRiskAssessmentID,
VendorID: req.VendorID, VendorID: req.VendorID,
AssessedBy: req.AssessedByID, AssessedBy: req.AssessedByID,
AssessedAt: now,
ExpiresAt: req.ExpiresAt, ExpiresAt: req.ExpiresAt,
DataSensitivity: req.DataSensitivity, DataSensitivity: req.DataSensitivity,
BusinessImpact: req.BusinessImpact, BusinessImpact: req.BusinessImpact,
@@ -369,11 +370,15 @@ func (s VendorService) CreateRiskAssessment(
err = s.svc.pg.WithTx( err = s.svc.pg.WithTx(
ctx, ctx,
func(conn pg.Conn) error { func(tx pg.Conn) error {
if err := vendorRiskAssessment.Insert(ctx, conn, s.svc.scope); err != nil { vendor := coredata.Vendor{ID: req.VendorID}
return fmt.Errorf("cannot insert vendor risk assessment: %w", err) if err := vendor.ExpireNonExpiredRiskAssessments(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot expire vendor risk assessments: %w", err)
} }
if err := vendorRiskAssessment.Insert(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert vendor risk assessment: %w", err)
}
return nil return nil
}, },
) )
@@ -384,3 +389,23 @@ func (s VendorService) CreateRiskAssessment(
return vendorRiskAssessment, nil return vendorRiskAssessment, nil
} }
func (s VendorService) GetRiskAssessment(
ctx context.Context,
vendorRiskAssessmentID gid.GID,
) (*coredata.VendorRiskAssessment, error) {
vendorRiskAssessment := &coredata.VendorRiskAssessment{}
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return vendorRiskAssessment.LoadByID(ctx, conn, s.svc.scope, vendorRiskAssessmentID)
},
)
if err != nil {
return nil, err
}
return vendorRiskAssessment, nil
}

View File

@@ -455,6 +455,8 @@ type User implements Node {
email: String! email: String!
createdAt: Datetime! createdAt: Datetime!
updatedAt: Datetime! updatedAt: Datetime!
people(organizationId: ID!): People @goField(forceResolver: true)
} }
type Connector implements Node { type Connector implements Node {
@@ -1463,7 +1465,6 @@ type VendorRiskAssessment implements Node {
dataSensitivity: DataSensitivity! dataSensitivity: DataSensitivity!
businessImpact: BusinessImpact! businessImpact: BusinessImpact!
notes: String notes: String
attachments: [String!]!
createdAt: Datetime! createdAt: Datetime!
updatedAt: Datetime! updatedAt: Datetime!
} }
@@ -1487,7 +1488,6 @@ input CreateVendorRiskAssessmentInput {
dataSensitivity: DataSensitivity! dataSensitivity: DataSensitivity!
businessImpact: BusinessImpact! businessImpact: BusinessImpact!
notes: String notes: String
attachments: [String!]
} }
type CreateVendorRiskAssessmentPayload { type CreateVendorRiskAssessmentPayload {

View File

@@ -52,6 +52,7 @@ type ResolverRoot interface {
Query() QueryResolver Query() QueryResolver
Risk() RiskResolver Risk() RiskResolver
Task() TaskResolver Task() TaskResolver
User() UserResolver
Vendor() VendorResolver Vendor() VendorResolver
VendorComplianceReport() VendorComplianceReportResolver VendorComplianceReport() VendorComplianceReportResolver
VendorRiskAssessment() VendorRiskAssessmentResolver VendorRiskAssessment() VendorRiskAssessmentResolver
@@ -538,6 +539,7 @@ type ComplexityRoot struct {
Email func(childComplexity int) int Email func(childComplexity int) int
FullName func(childComplexity int) int FullName func(childComplexity int) int
ID func(childComplexity int) int ID func(childComplexity int) int
People func(childComplexity int, organizationID gid.GID) int
UpdatedAt func(childComplexity int) int UpdatedAt func(childComplexity int) int
} }
@@ -611,7 +613,6 @@ type ComplexityRoot struct {
VendorRiskAssessment struct { VendorRiskAssessment struct {
AssessedAt func(childComplexity int) int AssessedAt func(childComplexity int) int
AssessedBy func(childComplexity int) int AssessedBy func(childComplexity int) int
Attachments func(childComplexity int) int
BusinessImpact func(childComplexity int) int BusinessImpact func(childComplexity int) int
CreatedAt func(childComplexity int) int CreatedAt func(childComplexity int) int
DataSensitivity func(childComplexity int) int DataSensitivity func(childComplexity int) int
@@ -730,6 +731,9 @@ type TaskResolver interface {
AssignedTo(ctx context.Context, obj *types.Task) (*types.People, error) AssignedTo(ctx context.Context, obj *types.Task) (*types.People, error)
Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error)
} }
type UserResolver interface {
People(ctx context.Context, obj *types.User, organizationID gid.GID) (*types.People, error)
}
type VendorResolver interface { type VendorResolver interface {
ComplianceReports(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) (*types.VendorComplianceReportConnection, error) ComplianceReports(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) (*types.VendorComplianceReportConnection, error)
RiskAssessments(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) (*types.VendorRiskAssessmentConnection, error) RiskAssessments(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) (*types.VendorRiskAssessmentConnection, error)
@@ -2760,6 +2764,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.User.ID(childComplexity), true return e.complexity.User.ID(childComplexity), true
case "User.people":
if e.complexity.User.People == nil {
break
}
args, err := ec.field_User_people_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.User.People(childComplexity, args["organizationId"].(gid.GID)), true
case "User.updatedAt": case "User.updatedAt":
if e.complexity.User.UpdatedAt == nil { if e.complexity.User.UpdatedAt == nil {
break break
@@ -3092,13 +3108,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.VendorRiskAssessment.AssessedBy(childComplexity), true return e.complexity.VendorRiskAssessment.AssessedBy(childComplexity), true
case "VendorRiskAssessment.attachments":
if e.complexity.VendorRiskAssessment.Attachments == nil {
break
}
return e.complexity.VendorRiskAssessment.Attachments(childComplexity), true
case "VendorRiskAssessment.businessImpact": case "VendorRiskAssessment.businessImpact":
if e.complexity.VendorRiskAssessment.BusinessImpact == nil { if e.complexity.VendorRiskAssessment.BusinessImpact == nil {
break break
@@ -3830,6 +3839,8 @@ type User implements Node {
email: String! email: String!
createdAt: Datetime! createdAt: Datetime!
updatedAt: Datetime! updatedAt: Datetime!
people(organizationId: ID!): People @goField(forceResolver: true)
} }
type Connector implements Node { type Connector implements Node {
@@ -4838,7 +4849,6 @@ type VendorRiskAssessment implements Node {
dataSensitivity: DataSensitivity! dataSensitivity: DataSensitivity!
businessImpact: BusinessImpact! businessImpact: BusinessImpact!
notes: String notes: String
attachments: [String!]!
createdAt: Datetime! createdAt: Datetime!
updatedAt: Datetime! updatedAt: Datetime!
} }
@@ -4862,7 +4872,6 @@ input CreateVendorRiskAssessmentInput {
dataSensitivity: DataSensitivity! dataSensitivity: DataSensitivity!
businessImpact: BusinessImpact! businessImpact: BusinessImpact!
notes: String notes: String
attachments: [String!]
} }
type CreateVendorRiskAssessmentPayload { type CreateVendorRiskAssessmentPayload {
@@ -7762,6 +7771,29 @@ func (ec *executionContext) field_Task_evidences_argsOrderBy(
return zeroVal, nil return zeroVal, nil
} }
func (ec *executionContext) field_User_people_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
arg0, err := ec.field_User_people_argsOrganizationID(ctx, rawArgs)
if err != nil {
return nil, err
}
args["organizationId"] = arg0
return args, nil
}
func (ec *executionContext) field_User_people_argsOrganizationID(
ctx context.Context,
rawArgs map[string]any,
) (gid.GID, error) {
ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("organizationId"))
if tmp, ok := rawArgs["organizationId"]; ok {
return ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, tmp)
}
var zeroVal gid.GID
return zeroVal, nil
}
func (ec *executionContext) field_Vendor_complianceReports_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { func (ec *executionContext) field_Vendor_complianceReports_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error var err error
args := map[string]any{} args := map[string]any{}
@@ -20538,6 +20570,74 @@ func (ec *executionContext) fieldContext_User_updatedAt(_ context.Context, field
return fc, nil return fc, nil
} }
func (ec *executionContext) _User_people(ctx context.Context, field graphql.CollectedField, obj *types.User) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_User_people(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.User().People(rctx, obj, fc.Args["organizationId"].(gid.GID))
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*types.People)
fc.Result = res
return ec.marshalOPeople2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐPeople(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_User_people(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "User",
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_People_id(ctx, field)
case "fullName":
return ec.fieldContext_People_fullName(ctx, field)
case "primaryEmailAddress":
return ec.fieldContext_People_primaryEmailAddress(ctx, field)
case "additionalEmailAddresses":
return ec.fieldContext_People_additionalEmailAddresses(ctx, field)
case "kind":
return ec.fieldContext_People_kind(ctx, field)
case "createdAt":
return ec.fieldContext_People_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_People_updatedAt(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type People", 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_User_people_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
return fc, nil
}
func (ec *executionContext) _UserConnection_edges(ctx context.Context, field graphql.CollectedField, obj *types.UserConnection) (ret graphql.Marshaler) { func (ec *executionContext) _UserConnection_edges(ctx context.Context, field graphql.CollectedField, obj *types.UserConnection) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_UserConnection_edges(ctx, field) fc, err := ec.fieldContext_UserConnection_edges(ctx, field)
if err != nil { if err != nil {
@@ -20735,6 +20835,8 @@ func (ec *executionContext) fieldContext_UserEdge_node(_ context.Context, field
return ec.fieldContext_User_createdAt(ctx, field) return ec.fieldContext_User_createdAt(ctx, field)
case "updatedAt": case "updatedAt":
return ec.fieldContext_User_updatedAt(ctx, field) return ec.fieldContext_User_updatedAt(ctx, field)
case "people":
return ec.fieldContext_User_people(ctx, field)
} }
return nil, fmt.Errorf("no field named %q was found under type User", field.Name) return nil, fmt.Errorf("no field named %q was found under type User", field.Name)
}, },
@@ -23034,50 +23136,6 @@ func (ec *executionContext) fieldContext_VendorRiskAssessment_notes(_ context.Co
return fc, nil return fc, nil
} }
func (ec *executionContext) _VendorRiskAssessment_attachments(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_VendorRiskAssessment_attachments(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.Attachments, 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.marshalNString2ᚕstringᚄ(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_VendorRiskAssessment_attachments(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "VendorRiskAssessment",
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) _VendorRiskAssessment_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { func (ec *executionContext) _VendorRiskAssessment_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_VendorRiskAssessment_createdAt(ctx, field) fc, err := ec.fieldContext_VendorRiskAssessment_createdAt(ctx, field)
if err != nil { if err != nil {
@@ -23369,8 +23427,6 @@ func (ec *executionContext) fieldContext_VendorRiskAssessmentEdge_node(_ context
return ec.fieldContext_VendorRiskAssessment_businessImpact(ctx, field) return ec.fieldContext_VendorRiskAssessment_businessImpact(ctx, field)
case "notes": case "notes":
return ec.fieldContext_VendorRiskAssessment_notes(ctx, field) return ec.fieldContext_VendorRiskAssessment_notes(ctx, field)
case "attachments":
return ec.fieldContext_VendorRiskAssessment_attachments(ctx, field)
case "createdAt": case "createdAt":
return ec.fieldContext_VendorRiskAssessment_createdAt(ctx, field) return ec.fieldContext_VendorRiskAssessment_createdAt(ctx, field)
case "updatedAt": case "updatedAt":
@@ -23475,6 +23531,8 @@ func (ec *executionContext) fieldContext_Viewer_user(_ context.Context, field gr
return ec.fieldContext_User_createdAt(ctx, field) return ec.fieldContext_User_createdAt(ctx, field)
case "updatedAt": case "updatedAt":
return ec.fieldContext_User_updatedAt(ctx, field) return ec.fieldContext_User_updatedAt(ctx, field)
case "people":
return ec.fieldContext_User_people(ctx, field)
} }
return nil, fmt.Errorf("no field named %q was found under type User", field.Name) return nil, fmt.Errorf("no field named %q was found under type User", field.Name)
}, },
@@ -26366,7 +26424,7 @@ func (ec *executionContext) unmarshalInputCreateVendorRiskAssessmentInput(ctx co
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"vendorId", "assessedBy", "expiresAt", "dataSensitivity", "businessImpact", "notes", "attachments"} fieldsInOrder := [...]string{"vendorId", "assessedBy", "expiresAt", "dataSensitivity", "businessImpact", "notes"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -26415,13 +26473,6 @@ func (ec *executionContext) unmarshalInputCreateVendorRiskAssessmentInput(ctx co
return it, err return it, err
} }
it.Notes = data it.Notes = data
case "attachments":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("attachments"))
data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v)
if err != nil {
return it, err
}
it.Attachments = data
} }
} }
@@ -32945,28 +32996,61 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj
case "id": case "id":
out.Values[i] = ec._User_id(ctx, field, obj) out.Values[i] = ec._User_id(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
out.Invalids++ atomic.AddUint32(&out.Invalids, 1)
} }
case "fullName": case "fullName":
out.Values[i] = ec._User_fullName(ctx, field, obj) out.Values[i] = ec._User_fullName(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
out.Invalids++ atomic.AddUint32(&out.Invalids, 1)
} }
case "email": case "email":
out.Values[i] = ec._User_email(ctx, field, obj) out.Values[i] = ec._User_email(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
out.Invalids++ atomic.AddUint32(&out.Invalids, 1)
} }
case "createdAt": case "createdAt":
out.Values[i] = ec._User_createdAt(ctx, field, obj) out.Values[i] = ec._User_createdAt(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
out.Invalids++ atomic.AddUint32(&out.Invalids, 1)
} }
case "updatedAt": case "updatedAt":
out.Values[i] = ec._User_updatedAt(ctx, field, obj) out.Values[i] = ec._User_updatedAt(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
out.Invalids++ atomic.AddUint32(&out.Invalids, 1)
} }
case "people":
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._User_people(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) })
default: default:
panic("unknown field " + strconv.Quote(field.Name)) panic("unknown field " + strconv.Quote(field.Name))
} }
@@ -33728,11 +33812,6 @@ func (ec *executionContext) _VendorRiskAssessment(ctx context.Context, sel ast.S
} }
case "notes": case "notes":
out.Values[i] = ec._VendorRiskAssessment_notes(ctx, field, obj) out.Values[i] = ec._VendorRiskAssessment_notes(ctx, field, obj)
case "attachments":
out.Values[i] = ec._VendorRiskAssessment_attachments(ctx, field, obj)
if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1)
}
case "createdAt": case "createdAt":
out.Values[i] = ec._VendorRiskAssessment_createdAt(ctx, field, obj) out.Values[i] = ec._VendorRiskAssessment_createdAt(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {

View File

@@ -252,7 +252,6 @@ type CreateVendorRiskAssessmentInput struct {
DataSensitivity coredata.DataSensitivity `json:"dataSensitivity"` DataSensitivity coredata.DataSensitivity `json:"dataSensitivity"`
BusinessImpact coredata.BusinessImpact `json:"businessImpact"` BusinessImpact coredata.BusinessImpact `json:"businessImpact"`
Notes *string `json:"notes,omitempty"` Notes *string `json:"notes,omitempty"`
Attachments []string `json:"attachments,omitempty"`
} }
type CreateVendorRiskAssessmentPayload struct { type CreateVendorRiskAssessmentPayload struct {
@@ -799,6 +798,7 @@ type User struct {
Email string `json:"email"` Email string `json:"email"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"` UpdatedAt time.Time `json:"updatedAt"`
People *People `json:"people,omitempty"`
} }
func (User) IsNode() {} func (User) IsNode() {}
@@ -886,7 +886,6 @@ type VendorRiskAssessment struct {
DataSensitivity coredata.DataSensitivity `json:"dataSensitivity"` DataSensitivity coredata.DataSensitivity `json:"dataSensitivity"`
BusinessImpact coredata.BusinessImpact `json:"businessImpact"` BusinessImpact coredata.BusinessImpact `json:"businessImpact"`
Notes *string `json:"notes,omitempty"` Notes *string `json:"notes,omitempty"`
Attachments []string `json:"attachments"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"` UpdatedAt time.Time `json:"updatedAt"`
} }

View File

@@ -1049,16 +1049,19 @@ func (r *mutationResolver) DeletePolicy(ctx context.Context, input types.DeleteP
// CreateVendorRiskAssessment is the resolver for the createVendorRiskAssessment field. // CreateVendorRiskAssessment is the resolver for the createVendorRiskAssessment field.
func (r *mutationResolver) CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error) { func (r *mutationResolver) CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error) {
svc := GetTenantService(ctx, r.proboSvc, input.VendorID.TenantID()) svc := GetTenantService(ctx, r.proboSvc, input.VendorID.TenantID())
user := UserFromContext(ctx)
expiresAt := time.Now().Add(time.Hour * 24 * 365) fmt.Println("input.AssessedBy", input.AssessedBy)
fmt.Println("input.ExpiresAt", input.ExpiresAt)
fmt.Println("input.DataSensitivity", input.DataSensitivity)
fmt.Println("input.BusinessImpact", input.BusinessImpact)
fmt.Println("input.Notes", input.Notes)
vendorRiskAssessment, err := svc.Vendors.CreateRiskAssessment( vendorRiskAssessment, err := svc.Vendors.CreateRiskAssessment(
ctx, ctx,
probo.CreateVendorRiskAssessmentRequest{ probo.CreateVendorRiskAssessmentRequest{
VendorID: input.VendorID, VendorID: input.VendorID,
AssessedByID: user.ID, AssessedByID: input.AssessedBy,
ExpiresAt: expiresAt, ExpiresAt: input.ExpiresAt,
DataSensitivity: input.DataSensitivity, DataSensitivity: input.DataSensitivity,
BusinessImpact: input.BusinessImpact, BusinessImpact: input.BusinessImpact,
Notes: input.Notes, Notes: input.Notes,
@@ -1558,6 +1561,18 @@ func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *in
return types.NewEvidenceConnection(page), nil return types.NewEvidenceConnection(page), nil
} }
// People is the resolver for the people field.
func (r *userResolver) People(ctx context.Context, obj *types.User, organizationID gid.GID) (*types.People, error) {
svc := GetTenantService(ctx, r.proboSvc, organizationID.TenantID())
people, err := svc.Peoples.GetByUserID(ctx, organizationID, obj.ID)
if err != nil {
panic(fmt.Errorf("failed to get people: %w", err))
}
return types.NewPeople(people), nil
}
// ComplianceReports is the resolver for the complianceReports field. // ComplianceReports is the resolver for the complianceReports field.
func (r *vendorResolver) ComplianceReports(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) (*types.VendorComplianceReportConnection, error) { func (r *vendorResolver) ComplianceReports(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) (*types.VendorComplianceReportConnection, error) {
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID()) svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
@@ -1676,12 +1691,31 @@ func (r *vendorComplianceReportResolver) FileURL(ctx context.Context, obj *types
// Vendor is the resolver for the vendor field. // Vendor is the resolver for the vendor field.
func (r *vendorRiskAssessmentResolver) Vendor(ctx context.Context, obj *types.VendorRiskAssessment) (*types.Vendor, error) { func (r *vendorRiskAssessmentResolver) Vendor(ctx context.Context, obj *types.VendorRiskAssessment) (*types.Vendor, error) {
panic(fmt.Errorf("not implemented: Vendor - vendor")) svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
vendor, err := svc.Vendors.Get(ctx, obj.ID)
if err != nil {
panic(fmt.Errorf("failed to get vendor: %w", err))
}
return types.NewVendor(vendor), nil
} }
// AssessedBy is the resolver for the assessedBy field. // AssessedBy is the resolver for the assessedBy field.
func (r *vendorRiskAssessmentResolver) AssessedBy(ctx context.Context, obj *types.VendorRiskAssessment) (*types.People, error) { func (r *vendorRiskAssessmentResolver) AssessedBy(ctx context.Context, obj *types.VendorRiskAssessment) (*types.People, error) {
panic(fmt.Errorf("not implemented: AssessedBy - assessedBy")) svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
vendorRiskAssessment, err := svc.Vendors.GetRiskAssessment(ctx, obj.ID)
if err != nil {
panic(fmt.Errorf("failed to get vendor risk assessment: %w", err))
}
people, err := svc.Peoples.Get(ctx, vendorRiskAssessment.AssessedBy)
if err != nil {
panic(fmt.Errorf("failed to get assessed by: %w", err))
}
return types.NewPeople(people), nil
} }
// Organizations is the resolver for the organizations field. // Organizations is the resolver for the organizations field.
@@ -1739,6 +1773,9 @@ func (r *Resolver) Risk() schema.RiskResolver { return &riskResolver{r} }
// Task returns schema.TaskResolver implementation. // Task returns schema.TaskResolver implementation.
func (r *Resolver) Task() schema.TaskResolver { return &taskResolver{r} } func (r *Resolver) Task() schema.TaskResolver { return &taskResolver{r} }
// User returns schema.UserResolver implementation.
func (r *Resolver) User() schema.UserResolver { return &userResolver{r} }
// Vendor returns schema.VendorResolver implementation. // Vendor returns schema.VendorResolver implementation.
func (r *Resolver) Vendor() schema.VendorResolver { return &vendorResolver{r} } func (r *Resolver) Vendor() schema.VendorResolver { return &vendorResolver{r} }
@@ -1765,6 +1802,7 @@ type policyResolver struct{ *Resolver }
type queryResolver struct{ *Resolver } type queryResolver struct{ *Resolver }
type riskResolver struct{ *Resolver } type riskResolver struct{ *Resolver }
type taskResolver struct{ *Resolver } type taskResolver struct{ *Resolver }
type userResolver struct{ *Resolver }
type vendorResolver struct{ *Resolver } type vendorResolver struct{ *Resolver }
type vendorComplianceReportResolver struct{ *Resolver } type vendorComplianceReportResolver struct{ *Resolver }
type vendorRiskAssessmentResolver struct{ *Resolver } type vendorRiskAssessmentResolver struct{ *Resolver }