diff --git a/apps/console/src/hooks/graph/ProcessingActivityGraph.ts b/apps/console/src/hooks/graph/ProcessingActivityGraph.ts index b4ca02733..cb42a60e1 100644 --- a/apps/console/src/hooks/graph/ProcessingActivityGraph.ts +++ b/apps/console/src/hooks/graph/ProcessingActivityGraph.ts @@ -13,8 +13,8 @@ export const processingActivitiesQuery = graphql` node(id: $organizationId) { ... on Organization { ...ProcessingActivitiesPageFragment @arguments(snapshotId: $snapshotId) - ...ProcessingActivitiesPageDPIAFragment - ...ProcessingActivitiesPageTIAFragment + ...ProcessingActivitiesPageDPIAFragment @arguments(snapshotId: $snapshotId) + ...ProcessingActivitiesPageTIAFragment @arguments(snapshotId: $snapshotId) } } } diff --git a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphListQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphListQuery.graphql.ts index ebe4f44f7..ac6b793fc 100644 --- a/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphListQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/ProcessingActivityGraphListQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<7fccb352f5aa5b305542aad0fd9fe406>> * @lightSyntaxTransform * @nogrep */ @@ -65,55 +65,54 @@ v4 = { "name": "id", "storageKey": null }, -v5 = { - "kind": "Literal", - "name": "first", - "value": 10 -}, -v6 = [ +v5 = [ { "fields": (v2/*: any*/), "kind": "ObjectValue", "name": "filter" }, - (v5/*: any*/) + { + "kind": "Literal", + "name": "first", + "value": 10 + } ], -v7 = { +v6 = { "alias": null, "args": null, "kind": "ScalarField", "name": "totalCount", "storageKey": null }, -v8 = { +v7 = { "alias": null, "args": null, "kind": "ScalarField", "name": "name", "storageKey": null }, -v9 = { +v8 = { "alias": null, "args": null, "kind": "ScalarField", "name": "createdAt", "storageKey": null }, -v10 = { +v9 = { "alias": null, "args": null, "kind": "ScalarField", "name": "updatedAt", "storageKey": null }, -v11 = { +v10 = { "alias": null, "args": null, "kind": "ScalarField", "name": "cursor", "storageKey": null }, -v12 = { +v11 = { "alias": null, "args": null, "concreteType": "PageInfo", @@ -138,7 +137,7 @@ v12 = { ], "storageKey": null }, -v13 = { +v12 = { "kind": "ClientExtension", "selections": [ { @@ -150,10 +149,10 @@ v13 = { } ] }, -v14 = [ - (v5/*: any*/) +v13 = [ + "filter" ], -v15 = { +v14 = { "alias": null, "args": null, "concreteType": "ProcessingActivity", @@ -162,7 +161,7 @@ v15 = { "plural": false, "selections": [ (v4/*: any*/), - (v8/*: any*/) + (v7/*: any*/) ], "storageKey": null }; @@ -190,12 +189,12 @@ return { "name": "ProcessingActivitiesPageFragment" }, { - "args": null, + "args": (v2/*: any*/), "kind": "FragmentSpread", "name": "ProcessingActivitiesPageDPIAFragment" }, { - "args": null, + "args": (v2/*: any*/), "kind": "FragmentSpread", "name": "ProcessingActivitiesPageTIAFragment" } @@ -231,13 +230,13 @@ return { "selections": [ { "alias": null, - "args": (v6/*: any*/), + "args": (v5/*: any*/), "concreteType": "ProcessingActivityConnection", "kind": "LinkedField", "name": "processingActivities", "plural": false, "selections": [ - (v7/*: any*/), + (v6/*: any*/), { "alias": null, "args": null, @@ -269,7 +268,7 @@ return { "name": "sourceId", "storageKey": null }, - (v8/*: any*/), + (v7/*: any*/), { "alias": null, "args": null, @@ -312,27 +311,25 @@ return { "name": "internationalTransfers", "storageKey": null }, + (v8/*: any*/), (v9/*: any*/), - (v10/*: any*/), (v3/*: any*/) ], "storageKey": null }, - (v11/*: any*/) + (v10/*: any*/) ], "storageKey": null }, - (v12/*: any*/), - (v13/*: any*/) + (v11/*: any*/), + (v12/*: any*/) ], "storageKey": null }, { "alias": null, - "args": (v6/*: any*/), - "filters": [ - "filter" - ], + "args": (v5/*: any*/), + "filters": (v13/*: any*/), "handle": "connection", "key": "ProcessingActivitiesPage_processingActivities", "kind": "LinkedHandle", @@ -340,13 +337,13 @@ return { }, { "alias": null, - "args": (v14/*: any*/), + "args": (v5/*: any*/), "concreteType": "ProcessingActivityDPIAConnection", "kind": "LinkedField", "name": "dataProtectionImpactAssessments", "plural": false, "selections": [ - (v7/*: any*/), + (v6/*: any*/), { "alias": null, "args": null, @@ -385,26 +382,26 @@ return { "name": "residualRisk", "storageKey": null }, - (v15/*: any*/), + (v14/*: any*/), + (v8/*: any*/), (v9/*: any*/), - (v10/*: any*/), (v3/*: any*/) ], "storageKey": null }, - (v11/*: any*/) + (v10/*: any*/) ], "storageKey": null }, - (v12/*: any*/), - (v13/*: any*/) + (v11/*: any*/), + (v12/*: any*/) ], - "storageKey": "dataProtectionImpactAssessments(first:10)" + "storageKey": null }, { "alias": null, - "args": (v14/*: any*/), - "filters": null, + "args": (v5/*: any*/), + "filters": (v13/*: any*/), "handle": "connection", "key": "ProcessingActivitiesPage_dataProtectionImpactAssessments", "kind": "LinkedHandle", @@ -412,13 +409,13 @@ return { }, { "alias": null, - "args": (v14/*: any*/), + "args": (v5/*: any*/), "concreteType": "ProcessingActivityTIAConnection", "kind": "LinkedField", "name": "transferImpactAssessments", "plural": false, "selections": [ - (v7/*: any*/), + (v6/*: any*/), { "alias": null, "args": null, @@ -457,26 +454,26 @@ return { "name": "localLawRisk", "storageKey": null }, - (v15/*: any*/), + (v14/*: any*/), + (v8/*: any*/), (v9/*: any*/), - (v10/*: any*/), (v3/*: any*/) ], "storageKey": null }, - (v11/*: any*/) + (v10/*: any*/) ], "storageKey": null }, - (v12/*: any*/), - (v13/*: any*/) + (v11/*: any*/), + (v12/*: any*/) ], - "storageKey": "transferImpactAssessments(first:10)" + "storageKey": null }, { "alias": null, - "args": (v14/*: any*/), - "filters": null, + "args": (v5/*: any*/), + "filters": (v13/*: any*/), "handle": "connection", "key": "ProcessingActivitiesPage_transferImpactAssessments", "kind": "LinkedHandle", @@ -492,16 +489,16 @@ return { ] }, "params": { - "cacheID": "e518b4737308d2e7528a2f68e26d0e32", + "cacheID": "5901fa4af27b039bd50a1c97cdcb54d4", "id": null, "metadata": {}, "name": "ProcessingActivityGraphListQuery", "operationKind": "query", - "text": "query ProcessingActivityGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ProcessingActivitiesPageFragment_3iomuz\n ...ProcessingActivitiesPageDPIAFragment\n ...ProcessingActivitiesPageTIAFragment\n }\n id\n }\n}\n\nfragment ProcessingActivitiesPageDPIAFragment on Organization {\n id\n dataProtectionImpactAssessments(first: 10) {\n totalCount\n edges {\n node {\n id\n description\n potentialRisk\n residualRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment ProcessingActivitiesPageFragment_3iomuz on Organization {\n id\n processingActivities(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n lawfulBasis\n location\n internationalTransfers\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment ProcessingActivitiesPageTIAFragment on Organization {\n id\n transferImpactAssessments(first: 10) {\n totalCount\n edges {\n node {\n id\n dataSubjects\n transfer\n localLawRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" + "text": "query ProcessingActivityGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ProcessingActivitiesPageFragment_3iomuz\n ...ProcessingActivitiesPageDPIAFragment_3iomuz\n ...ProcessingActivitiesPageTIAFragment_3iomuz\n }\n id\n }\n}\n\nfragment ProcessingActivitiesPageDPIAFragment_3iomuz on Organization {\n id\n dataProtectionImpactAssessments(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n description\n potentialRisk\n residualRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment ProcessingActivitiesPageFragment_3iomuz on Organization {\n id\n processingActivities(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n lawfulBasis\n location\n internationalTransfers\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n\nfragment ProcessingActivitiesPageTIAFragment_3iomuz on Organization {\n id\n transferImpactAssessments(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n dataSubjects\n transfer\n localLawRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" } }; })(); -(node as any).hash = "bbd2c1907bd9e4607a0beb1bb12d0f11"; +(node as any).hash = "b92a7dc2b38a5ae25c9a47a975fb718b"; export default node; diff --git a/apps/console/src/pages/organizations/processingActivities/ProcessingActivitiesPage.tsx b/apps/console/src/pages/organizations/processingActivities/ProcessingActivitiesPage.tsx index c22ac2d00..8b4755a85 100644 --- a/apps/console/src/pages/organizations/processingActivities/ProcessingActivitiesPage.tsx +++ b/apps/console/src/pages/organizations/processingActivities/ProcessingActivitiesPage.tsx @@ -102,13 +102,15 @@ const dpiaListPageFragment = graphql` @argumentDefinitions( first: { type: "Int", defaultValue: 10 } after: { type: "CursorKey" } + snapshotId: { type: "ID", defaultValue: null } ) { id dataProtectionImpactAssessments( first: $first after: $after + filter: { snapshotId: $snapshotId } ) - @connection(key: "ProcessingActivitiesPage_dataProtectionImpactAssessments") { + @connection(key: "ProcessingActivitiesPage_dataProtectionImpactAssessments", filters: ["filter"]) { __id totalCount edges { @@ -139,13 +141,15 @@ const tiaListPageFragment = graphql` @argumentDefinitions( first: { type: "Int", defaultValue: 10 } after: { type: "CursorKey" } + snapshotId: { type: "ID", defaultValue: null } ) { id transferImpactAssessments( first: $first after: $after + filter: { snapshotId: $snapshotId } ) - @connection(key: "ProcessingActivitiesPage_transferImpactAssessments") { + @connection(key: "ProcessingActivitiesPage_transferImpactAssessments", filters: ["filter"]) { __id totalCount edges { diff --git a/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageDPIAFragment.graphql.ts b/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageDPIAFragment.graphql.ts index 689b570b9..c518f7db0 100644 --- a/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageDPIAFragment.graphql.ts +++ b/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageDPIAFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<50ed487333de3127b16c6bd5f1c051b1>> * @lightSyntaxTransform * @nogrep */ @@ -66,6 +66,11 @@ return { "defaultValue": 10, "kind": "LocalArgument", "name": "first" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "snapshotId" } ], "kind": "Fragment", @@ -102,7 +107,19 @@ return { (v1/*: any*/), { "alias": "dataProtectionImpactAssessments", - "args": null, + "args": [ + { + "fields": [ + { + "kind": "Variable", + "name": "snapshotId", + "variableName": "snapshotId" + } + ], + "kind": "ObjectValue", + "name": "filter" + } + ], "concreteType": "ProcessingActivityDPIAConnection", "kind": "LinkedField", "name": "__ProcessingActivitiesPage_dataProtectionImpactAssessments_connection", @@ -252,6 +269,6 @@ return { }; })(); -(node as any).hash = "e49266b9c7b8a8b00dc43813ce499f67"; +(node as any).hash = "67339e0fd7610409cba00791361c51a2"; export default node; diff --git a/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageDPIARefetchQuery.graphql.ts b/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageDPIARefetchQuery.graphql.ts index 6330c23f0..278554a3d 100644 --- a/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageDPIARefetchQuery.graphql.ts +++ b/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageDPIARefetchQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<026a23e95a9115022526fa5d6f0cb999>> + * @generated SignedSource<<0ecca0ba0b410bf09fe2b0c62d003d0c>> * @lightSyntaxTransform * @nogrep */ @@ -14,6 +14,7 @@ export type ProcessingActivitiesPageDPIARefetchQuery$variables = { after?: any | null | undefined; first?: number | null | undefined; id: string; + snapshotId?: string | null | undefined; }; export type ProcessingActivitiesPageDPIARefetchQuery$data = { readonly node: { @@ -26,73 +27,99 @@ export type ProcessingActivitiesPageDPIARefetchQuery = { }; const node: ConcreteRequest = (function(){ -var v0 = [ - { - "defaultValue": null, - "kind": "LocalArgument", - "name": "after" - }, - { - "defaultValue": 10, - "kind": "LocalArgument", - "name": "first" - }, - { - "defaultValue": null, - "kind": "LocalArgument", - "name": "id" - } -], -v1 = [ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "after" +}, +v1 = { + "defaultValue": 10, + "kind": "LocalArgument", + "name": "first" +}, +v2 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" +}, +v3 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "snapshotId" +}, +v4 = [ { "kind": "Variable", "name": "id", "variableName": "id" } ], -v2 = [ - { - "kind": "Variable", - "name": "after", - "variableName": "after" - }, - { - "kind": "Variable", - "name": "first", - "variableName": "first" - } -], -v3 = { +v5 = { + "kind": "Variable", + "name": "after", + "variableName": "after" +}, +v6 = { + "kind": "Variable", + "name": "first", + "variableName": "first" +}, +v7 = { + "kind": "Variable", + "name": "snapshotId", + "variableName": "snapshotId" +}, +v8 = { "alias": null, "args": null, "kind": "ScalarField", "name": "__typename", "storageKey": null }, -v4 = { +v9 = { "alias": null, "args": null, "kind": "ScalarField", "name": "id", "storageKey": null -}; +}, +v10 = [ + (v5/*: any*/), + { + "fields": [ + (v7/*: any*/) + ], + "kind": "ObjectValue", + "name": "filter" + }, + (v6/*: any*/) +]; return { "fragment": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v2/*: any*/), + (v3/*: any*/) + ], "kind": "Fragment", "metadata": null, "name": "ProcessingActivitiesPageDPIARefetchQuery", "selections": [ { "alias": null, - "args": (v1/*: any*/), + "args": (v4/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", "plural": false, "selections": [ { - "args": (v2/*: any*/), + "args": [ + (v5/*: any*/), + (v6/*: any*/), + (v7/*: any*/) + ], "kind": "FragmentSpread", "name": "ProcessingActivitiesPageDPIAFragment" } @@ -105,26 +132,31 @@ return { }, "kind": "Request", "operation": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v3/*: any*/), + (v2/*: any*/) + ], "kind": "Operation", "name": "ProcessingActivitiesPageDPIARefetchQuery", "selections": [ { "alias": null, - "args": (v1/*: any*/), + "args": (v4/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", "plural": false, "selections": [ - (v3/*: any*/), - (v4/*: any*/), + (v8/*: any*/), + (v9/*: any*/), { "kind": "InlineFragment", "selections": [ { "alias": null, - "args": (v2/*: any*/), + "args": (v10/*: any*/), "concreteType": "ProcessingActivityDPIAConnection", "kind": "LinkedField", "name": "dataProtectionImpactAssessments", @@ -153,7 +185,7 @@ return { "name": "node", "plural": false, "selections": [ - (v4/*: any*/), + (v9/*: any*/), { "alias": null, "args": null, @@ -183,7 +215,7 @@ return { "name": "processingActivity", "plural": false, "selections": [ - (v4/*: any*/), + (v9/*: any*/), { "alias": null, "args": null, @@ -208,7 +240,7 @@ return { "name": "updatedAt", "storageKey": null }, - (v3/*: any*/) + (v8/*: any*/) ], "storageKey": null }, @@ -264,8 +296,10 @@ return { }, { "alias": null, - "args": (v2/*: any*/), - "filters": null, + "args": (v10/*: any*/), + "filters": [ + "filter" + ], "handle": "connection", "key": "ProcessingActivitiesPage_dataProtectionImpactAssessments", "kind": "LinkedHandle", @@ -281,16 +315,16 @@ return { ] }, "params": { - "cacheID": "8e3896e68907df53052a3418bf646240", + "cacheID": "c1f38ecede914f3c444f313e593baac9", "id": null, "metadata": {}, "name": "ProcessingActivitiesPageDPIARefetchQuery", "operationKind": "query", - "text": "query ProcessingActivitiesPageDPIARefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ProcessingActivitiesPageDPIAFragment_2HEEH6\n id\n }\n}\n\nfragment ProcessingActivitiesPageDPIAFragment_2HEEH6 on Organization {\n id\n dataProtectionImpactAssessments(first: $first, after: $after) {\n totalCount\n edges {\n node {\n id\n description\n potentialRisk\n residualRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" + "text": "query ProcessingActivitiesPageDPIARefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ProcessingActivitiesPageDPIAFragment_35e0S5\n id\n }\n}\n\nfragment ProcessingActivitiesPageDPIAFragment_35e0S5 on Organization {\n id\n dataProtectionImpactAssessments(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n description\n potentialRisk\n residualRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" } }; })(); -(node as any).hash = "e49266b9c7b8a8b00dc43813ce499f67"; +(node as any).hash = "67339e0fd7610409cba00791361c51a2"; export default node; diff --git a/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageTIAFragment.graphql.ts b/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageTIAFragment.graphql.ts index 21290dda3..28cd38405 100644 --- a/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageTIAFragment.graphql.ts +++ b/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageTIAFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<7f0d0a852bdb0ca1fdd8a49252654563>> + * @generated SignedSource<<4674be4782e5b88c71dab59ab04105df>> * @lightSyntaxTransform * @nogrep */ @@ -65,6 +65,11 @@ return { "defaultValue": 10, "kind": "LocalArgument", "name": "first" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "snapshotId" } ], "kind": "Fragment", @@ -101,7 +106,19 @@ return { (v1/*: any*/), { "alias": "transferImpactAssessments", - "args": null, + "args": [ + { + "fields": [ + { + "kind": "Variable", + "name": "snapshotId", + "variableName": "snapshotId" + } + ], + "kind": "ObjectValue", + "name": "filter" + } + ], "concreteType": "ProcessingActivityTIAConnection", "kind": "LinkedField", "name": "__ProcessingActivitiesPage_transferImpactAssessments_connection", @@ -251,6 +268,6 @@ return { }; })(); -(node as any).hash = "0262ad5df883e750870f63e6d18d2c93"; +(node as any).hash = "2c6575fe24698cc6b14d9d7a88cf434b"; export default node; diff --git a/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageTIARefetchQuery.graphql.ts b/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageTIARefetchQuery.graphql.ts index 859dd8c14..4e51c6a35 100644 --- a/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageTIARefetchQuery.graphql.ts +++ b/apps/console/src/pages/organizations/processingActivities/__generated__/ProcessingActivitiesPageTIARefetchQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -14,6 +14,7 @@ export type ProcessingActivitiesPageTIARefetchQuery$variables = { after?: any | null | undefined; first?: number | null | undefined; id: string; + snapshotId?: string | null | undefined; }; export type ProcessingActivitiesPageTIARefetchQuery$data = { readonly node: { @@ -26,73 +27,99 @@ export type ProcessingActivitiesPageTIARefetchQuery = { }; const node: ConcreteRequest = (function(){ -var v0 = [ - { - "defaultValue": null, - "kind": "LocalArgument", - "name": "after" - }, - { - "defaultValue": 10, - "kind": "LocalArgument", - "name": "first" - }, - { - "defaultValue": null, - "kind": "LocalArgument", - "name": "id" - } -], -v1 = [ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "after" +}, +v1 = { + "defaultValue": 10, + "kind": "LocalArgument", + "name": "first" +}, +v2 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" +}, +v3 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "snapshotId" +}, +v4 = [ { "kind": "Variable", "name": "id", "variableName": "id" } ], -v2 = [ - { - "kind": "Variable", - "name": "after", - "variableName": "after" - }, - { - "kind": "Variable", - "name": "first", - "variableName": "first" - } -], -v3 = { +v5 = { + "kind": "Variable", + "name": "after", + "variableName": "after" +}, +v6 = { + "kind": "Variable", + "name": "first", + "variableName": "first" +}, +v7 = { + "kind": "Variable", + "name": "snapshotId", + "variableName": "snapshotId" +}, +v8 = { "alias": null, "args": null, "kind": "ScalarField", "name": "__typename", "storageKey": null }, -v4 = { +v9 = { "alias": null, "args": null, "kind": "ScalarField", "name": "id", "storageKey": null -}; +}, +v10 = [ + (v5/*: any*/), + { + "fields": [ + (v7/*: any*/) + ], + "kind": "ObjectValue", + "name": "filter" + }, + (v6/*: any*/) +]; return { "fragment": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v2/*: any*/), + (v3/*: any*/) + ], "kind": "Fragment", "metadata": null, "name": "ProcessingActivitiesPageTIARefetchQuery", "selections": [ { "alias": null, - "args": (v1/*: any*/), + "args": (v4/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", "plural": false, "selections": [ { - "args": (v2/*: any*/), + "args": [ + (v5/*: any*/), + (v6/*: any*/), + (v7/*: any*/) + ], "kind": "FragmentSpread", "name": "ProcessingActivitiesPageTIAFragment" } @@ -105,26 +132,31 @@ return { }, "kind": "Request", "operation": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v3/*: any*/), + (v2/*: any*/) + ], "kind": "Operation", "name": "ProcessingActivitiesPageTIARefetchQuery", "selections": [ { "alias": null, - "args": (v1/*: any*/), + "args": (v4/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", "plural": false, "selections": [ - (v3/*: any*/), - (v4/*: any*/), + (v8/*: any*/), + (v9/*: any*/), { "kind": "InlineFragment", "selections": [ { "alias": null, - "args": (v2/*: any*/), + "args": (v10/*: any*/), "concreteType": "ProcessingActivityTIAConnection", "kind": "LinkedField", "name": "transferImpactAssessments", @@ -153,7 +185,7 @@ return { "name": "node", "plural": false, "selections": [ - (v4/*: any*/), + (v9/*: any*/), { "alias": null, "args": null, @@ -183,7 +215,7 @@ return { "name": "processingActivity", "plural": false, "selections": [ - (v4/*: any*/), + (v9/*: any*/), { "alias": null, "args": null, @@ -208,7 +240,7 @@ return { "name": "updatedAt", "storageKey": null }, - (v3/*: any*/) + (v8/*: any*/) ], "storageKey": null }, @@ -264,8 +296,10 @@ return { }, { "alias": null, - "args": (v2/*: any*/), - "filters": null, + "args": (v10/*: any*/), + "filters": [ + "filter" + ], "handle": "connection", "key": "ProcessingActivitiesPage_transferImpactAssessments", "kind": "LinkedHandle", @@ -281,16 +315,16 @@ return { ] }, "params": { - "cacheID": "339dd59f375bcb83665bb36d05950916", + "cacheID": "2dfe163e2a769f6a428b3e259cd6dc39", "id": null, "metadata": {}, "name": "ProcessingActivitiesPageTIARefetchQuery", "operationKind": "query", - "text": "query ProcessingActivitiesPageTIARefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ProcessingActivitiesPageTIAFragment_2HEEH6\n id\n }\n}\n\nfragment ProcessingActivitiesPageTIAFragment_2HEEH6 on Organization {\n id\n transferImpactAssessments(first: $first, after: $after) {\n totalCount\n edges {\n node {\n id\n dataSubjects\n transfer\n localLawRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" + "text": "query ProcessingActivitiesPageTIARefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ProcessingActivitiesPageTIAFragment_35e0S5\n id\n }\n}\n\nfragment ProcessingActivitiesPageTIAFragment_35e0S5 on Organization {\n id\n transferImpactAssessments(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n dataSubjects\n transfer\n localLawRisk\n processingActivity {\n id\n name\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n" } }; })(); -(node as any).hash = "0262ad5df883e750870f63e6d18d2c93"; +(node as any).hash = "2c6575fe24698cc6b14d9d7a88cf434b"; export default node; diff --git a/e2e/console/processing_activity_test.go b/e2e/console/processing_activity_test.go index 30b43c65d..87d1fb565 100644 --- a/e2e/console/processing_activity_test.go +++ b/e2e/console/processing_activity_test.go @@ -2308,3 +2308,291 @@ func TestProcessingActivity_TIA_RBAC(t *testing.T) { testutil.RequireForbiddenError(t, err, "viewer should not be able to delete TIA") }) } + +func TestProcessingActivity_Snapshot_DPIA_TIA(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + + t.Run("snapshot includes DPIA and TIA", func(t *testing.T) { + paID := factory.NewProcessingActivity(owner). + WithName("Snapshot DPIA TIA Test"). + Create() + + var dpiaResult struct { + CreateProcessingActivityDPIA struct { + ProcessingActivityDpia struct { + ID string `json:"id"` + } `json:"processingActivityDpia"` + } `json:"createProcessingActivityDPIA"` + } + err := owner.Execute(` + mutation($input: CreateProcessingActivityDPIAInput!) { + createProcessingActivityDPIA(input: $input) { + processingActivityDpia { id } + } + } + `, map[string]any{ + "input": map[string]any{ + "processingActivityId": paID, + "description": "DPIA for snapshot", + "residualRisk": "MEDIUM", + }, + }, &dpiaResult) + require.NoError(t, err) + + var tiaResult struct { + CreateProcessingActivityTIA struct { + ProcessingActivityTia struct { + ID string `json:"id"` + } `json:"processingActivityTia"` + } `json:"createProcessingActivityTIA"` + } + err = owner.Execute(` + mutation($input: CreateProcessingActivityTIAInput!) { + createProcessingActivityTIA(input: $input) { + processingActivityTia { id } + } + } + `, map[string]any{ + "input": map[string]any{ + "processingActivityId": paID, + "dataSubjects": "TIA subjects for snapshot", + "transfer": "EU to US", + }, + }, &tiaResult) + require.NoError(t, err) + + var snapshotResult struct { + CreateSnapshot struct { + SnapshotEdge struct { + Node struct { + ID string `json:"id"` + } `json:"node"` + } `json:"snapshotEdge"` + } `json:"createSnapshot"` + } + err = owner.Execute(` + mutation($input: CreateSnapshotInput!) { + createSnapshot(input: $input) { + snapshotEdge { + node { id } + } + } + } + `, map[string]any{ + "input": map[string]any{ + "organizationId": owner.GetOrganizationID().String(), + "name": fmt.Sprintf("PA Snapshot Test %d", time.Now().UnixNano()), + "type": "PROCESSING_ACTIVITIES", + }, + }, &snapshotResult) + require.NoError(t, err) + snapshotID := snapshotResult.CreateSnapshot.SnapshotEdge.Node.ID + + var queryResult struct { + Node struct { + ProcessingActivities struct { + Edges []struct { + Node struct { + ID string `json:"id"` + Name string `json:"name"` + Dpia *struct { + ID string `json:"id"` + Description *string `json:"description"` + ResidualRisk *string `json:"residualRisk"` + } `json:"dpia"` + Tia *struct { + ID string `json:"id"` + DataSubjects *string `json:"dataSubjects"` + Transfer *string `json:"transfer"` + } `json:"tia"` + } `json:"node"` + } `json:"edges"` + } `json:"processingActivities"` + } `json:"node"` + } + err = owner.Execute(` + query($orgId: ID!, $snapshotId: ID!) { + node(id: $orgId) { + ... on Organization { + processingActivities(first: 100, filter: { snapshotId: $snapshotId }) { + edges { + node { + id + name + dpia { + id + description + residualRisk + } + tia { + id + dataSubjects + transfer + } + } + } + } + } + } + } + `, map[string]any{ + "orgId": owner.GetOrganizationID().String(), + "snapshotId": snapshotID, + }, &queryResult) + require.NoError(t, err) + + var foundPA bool + for _, edge := range queryResult.Node.ProcessingActivities.Edges { + if edge.Node.Name == "Snapshot DPIA TIA Test" { + foundPA = true + require.NotNil(t, edge.Node.Dpia, "DPIA should be included in snapshot") + assert.Equal(t, "DPIA for snapshot", *edge.Node.Dpia.Description) + assert.Equal(t, "MEDIUM", *edge.Node.Dpia.ResidualRisk) + + require.NotNil(t, edge.Node.Tia, "TIA should be included in snapshot") + assert.Equal(t, "TIA subjects for snapshot", *edge.Node.Tia.DataSubjects) + assert.Equal(t, "EU to US", *edge.Node.Tia.Transfer) + break + } + } + assert.True(t, foundPA, "Processing activity should be found in snapshot") + }) + + t.Run("snapshot DPIA and TIA are independent of source", func(t *testing.T) { + paID := factory.NewProcessingActivity(owner). + WithName("Snapshot Independence Test"). + Create() + + err := owner.Execute(` + mutation($input: CreateProcessingActivityDPIAInput!) { + createProcessingActivityDPIA(input: $input) { + processingActivityDpia { id } + } + } + `, map[string]any{ + "input": map[string]any{ + "processingActivityId": paID, + "description": "Original DPIA", + "residualRisk": "LOW", + }, + }, nil) + require.NoError(t, err) + + var snapshotResult struct { + CreateSnapshot struct { + SnapshotEdge struct { + Node struct { + ID string `json:"id"` + } `json:"node"` + } `json:"snapshotEdge"` + } `json:"createSnapshot"` + } + err = owner.Execute(` + mutation($input: CreateSnapshotInput!) { + createSnapshot(input: $input) { + snapshotEdge { + node { id } + } + } + } + `, map[string]any{ + "input": map[string]any{ + "organizationId": owner.GetOrganizationID().String(), + "name": fmt.Sprintf("PA Independence Test %d", time.Now().UnixNano()), + "type": "PROCESSING_ACTIVITIES", + }, + }, &snapshotResult) + require.NoError(t, err) + snapshotID := snapshotResult.CreateSnapshot.SnapshotEdge.Node.ID + + var sourceResult struct { + Node struct { + Dpia *struct { + ID string `json:"id"` + Description *string `json:"description"` + ResidualRisk *string `json:"residualRisk"` + } `json:"dpia"` + } `json:"node"` + } + err = owner.Execute(` + query($id: ID!) { + node(id: $id) { + ... on ProcessingActivity { + dpia { + id + description + residualRisk + } + } + } + } + `, map[string]any{"id": paID}, &sourceResult) + require.NoError(t, err) + require.NotNil(t, sourceResult.Node.Dpia) + sourceDpiaID := sourceResult.Node.Dpia.ID + + _, err = owner.Do(` + mutation($input: UpdateProcessingActivityDPIAInput!) { + updateProcessingActivityDPIA(input: $input) { + processingActivityDpia { id } + } + } + `, map[string]any{ + "input": map[string]any{ + "id": sourceDpiaID, + "description": "Updated after snapshot", + "residualRisk": "HIGH", + }, + }) + require.NoError(t, err) + + var snapshotQueryResult struct { + Node struct { + ProcessingActivities struct { + Edges []struct { + Node struct { + Name string `json:"name"` + Dpia *struct { + Description *string `json:"description"` + ResidualRisk *string `json:"residualRisk"` + } `json:"dpia"` + } `json:"node"` + } `json:"edges"` + } `json:"processingActivities"` + } `json:"node"` + } + err = owner.Execute(` + query($orgId: ID!, $snapshotId: ID!) { + node(id: $orgId) { + ... on Organization { + processingActivities(first: 100, filter: { snapshotId: $snapshotId }) { + edges { + node { + name + dpia { + description + residualRisk + } + } + } + } + } + } + } + `, map[string]any{ + "orgId": owner.GetOrganizationID().String(), + "snapshotId": snapshotID, + }, &snapshotQueryResult) + require.NoError(t, err) + + for _, edge := range snapshotQueryResult.Node.ProcessingActivities.Edges { + if edge.Node.Name == "Snapshot Independence Test" { + require.NotNil(t, edge.Node.Dpia) + assert.Equal(t, "Original DPIA", *edge.Node.Dpia.Description, "Snapshot DPIA should retain original value") + assert.Equal(t, "LOW", *edge.Node.Dpia.ResidualRisk, "Snapshot DPIA should retain original value") + break + } + } + }) +} diff --git a/pkg/coredata/migrations/20251216T153357Z.sql b/pkg/coredata/migrations/20251216T153357Z.sql index e5b532417..47e895a03 100644 --- a/pkg/coredata/migrations/20251216T153357Z.sql +++ b/pkg/coredata/migrations/20251216T153357Z.sql @@ -12,6 +12,8 @@ CREATE TYPE processing_activity_dpia_residual_risk AS ENUM ('LOW', 'MEDIUM', 'HI CREATE TABLE processing_activity_data_protection_impact_assessments ( id TEXT PRIMARY KEY, tenant_id TEXT NOT NULL, + snapshot_id TEXT REFERENCES snapshots(id) ON UPDATE CASCADE ON DELETE CASCADE, + source_id TEXT, organization_id TEXT NOT NULL, processing_activity_id TEXT NOT NULL, description TEXT, @@ -32,12 +34,17 @@ CREATE TABLE processing_activity_data_protection_impact_assessments ( FOREIGN KEY (processing_activity_id) REFERENCES processing_activities(id) ON UPDATE CASCADE - ON DELETE CASCADE + ON DELETE CASCADE, + + CONSTRAINT processing_activity_dpias_source_id_snapshot_id_key + UNIQUE (source_id, snapshot_id) ); CREATE TABLE processing_activity_transfer_impact_assessments ( id TEXT PRIMARY KEY, tenant_id TEXT NOT NULL, + snapshot_id TEXT REFERENCES snapshots(id) ON UPDATE CASCADE ON DELETE CASCADE, + source_id TEXT, organization_id TEXT NOT NULL, processing_activity_id TEXT NOT NULL, data_subjects TEXT, @@ -58,5 +65,8 @@ CREATE TABLE processing_activity_transfer_impact_assessments ( FOREIGN KEY (processing_activity_id) REFERENCES processing_activities(id) ON UPDATE CASCADE - ON DELETE CASCADE + ON DELETE CASCADE, + + CONSTRAINT processing_activity_tias_source_id_snapshot_id_key + UNIQUE (source_id, snapshot_id) ); diff --git a/pkg/coredata/processing_activities.go b/pkg/coredata/processing_activities.go index c22f30152..73d73e58b 100644 --- a/pkg/coredata/processing_activities.go +++ b/pkg/coredata/processing_activities.go @@ -427,7 +427,7 @@ WHERE } func (pas ProcessingActivities) Snapshot(ctx context.Context, conn pg.Conn, scope Scoper, organizationID, snapshotID gid.GID) error { - snapshotters := []ProcessingActivitySnapshotter{ProcessingActivities{}, Vendors{}, ProcessingActivityVendors{}} + snapshotters := []ProcessingActivitySnapshotter{ProcessingActivities{}, Vendors{}, ProcessingActivityVendors{}, ProcessingActivityDPIAs{}, ProcessingActivityTIAs{}} for _, snapshotter := range snapshotters { if err := snapshotter.InsertProcessingActivitySnapshots(ctx, conn, scope, organizationID, snapshotID); err != nil { diff --git a/pkg/coredata/processing_activity_dpia.go b/pkg/coredata/processing_activity_dpia.go index e07d9709c..290f1e93c 100644 --- a/pkg/coredata/processing_activity_dpia.go +++ b/pkg/coredata/processing_activity_dpia.go @@ -38,6 +38,8 @@ func (e ErrProcessingActivityDPIANotFound) Error() string { type ( ProcessingActivityDPIA struct { ID gid.GID `db:"id"` + SnapshotID *gid.GID `db:"snapshot_id"` + SourceID *gid.GID `db:"source_id"` OrganizationID gid.GID `db:"organization_id"` ProcessingActivityID gid.GID `db:"processing_activity_id"` Description *string `db:"description"` @@ -66,6 +68,7 @@ func (dpias *ProcessingActivityDPIAs) CountByOrganizationID( conn pg.Conn, scope Scoper, organizationID gid.GID, + filter *ProcessingActivityDPIAFilter, ) (int, error) { q := ` SELECT @@ -75,12 +78,14 @@ FROM WHERE %s AND organization_id = @organization_id + AND %s ` - q = fmt.Sprintf(q, scope.SQLFragment()) + q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment()) args := pgx.StrictNamedArgs{"organization_id": organizationID} maps.Copy(args, scope.SQLArguments()) + maps.Copy(args, filter.SQLArguments()) row := conn.QueryRow(ctx, q, args) @@ -99,10 +104,13 @@ func (dpias *ProcessingActivityDPIAs) LoadByOrganizationID( scope Scoper, organizationID gid.GID, cursor *page.Cursor[ProcessingActivityDPIAOrderField], + filter *ProcessingActivityDPIAFilter, ) error { q := ` SELECT id, + snapshot_id, + source_id, organization_id, processing_activity_id, description, @@ -118,12 +126,14 @@ WHERE %s AND organization_id = @organization_id AND %s + AND %s ` - q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment()) + q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment(), cursor.SQLFragment()) args := pgx.StrictNamedArgs{"organization_id": organizationID} maps.Copy(args, scope.SQLArguments()) + maps.Copy(args, filter.SQLArguments()) maps.Copy(args, cursor.SQLArguments()) rows, err := conn.Query(ctx, q, args) @@ -150,6 +160,8 @@ func (dpia *ProcessingActivityDPIA) LoadByID( q := ` SELECT id, + snapshot_id, + source_id, organization_id, processing_activity_id, description, @@ -199,6 +211,8 @@ func (dpia *ProcessingActivityDPIA) LoadByProcessingActivityID( q := ` SELECT id, + snapshot_id, + source_id, organization_id, processing_activity_id, description, @@ -357,3 +371,61 @@ WHERE return nil } + +func (dpias ProcessingActivityDPIAs) InsertProcessingActivitySnapshots( + ctx context.Context, + conn pg.Conn, + scope Scoper, + organizationID gid.GID, + snapshotID gid.GID, +) error { + query := ` +INSERT INTO processing_activity_data_protection_impact_assessments ( + id, + tenant_id, + snapshot_id, + source_id, + organization_id, + processing_activity_id, + description, + necessity_and_proportionality, + potential_risk, + mitigations, + residual_risk, + created_at, + updated_at +) +SELECT + generate_gid(decode_base64_unpadded(@tenant_id), @dpia_entity_type), + @tenant_id, + @snapshot_id, + dpia.id, + dpia.organization_id, + pa_snapshot.id, + dpia.description, + dpia.necessity_and_proportionality, + dpia.potential_risk, + dpia.mitigations, + dpia.residual_risk, + dpia.created_at, + dpia.updated_at +FROM processing_activity_data_protection_impact_assessments dpia +INNER JOIN processing_activities pa_source ON dpia.processing_activity_id = pa_source.id AND pa_source.snapshot_id IS NULL +INNER JOIN processing_activities pa_snapshot ON pa_source.id = pa_snapshot.source_id AND pa_snapshot.snapshot_id = @snapshot_id +WHERE dpia.tenant_id = @tenant_id AND dpia.organization_id = @organization_id AND dpia.snapshot_id IS NULL + ` + + args := pgx.StrictNamedArgs{ + "tenant_id": scope.GetTenantID(), + "snapshot_id": snapshotID, + "organization_id": organizationID, + "dpia_entity_type": ProcessingActivityDPIAEntityType, + } + + _, err := conn.Exec(ctx, query, args) + if err != nil { + return fmt.Errorf("cannot insert processing activity dpia snapshots: %w", err) + } + + return nil +} diff --git a/pkg/coredata/processing_activity_dpia_filter.go b/pkg/coredata/processing_activity_dpia_filter.go new file mode 100644 index 000000000..af34c7dc4 --- /dev/null +++ b/pkg/coredata/processing_activity_dpia_filter.go @@ -0,0 +1,54 @@ +// 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 ( + "github.com/jackc/pgx/v5" + "go.probo.inc/probo/pkg/gid" +) + +type ( + ProcessingActivityDPIAFilter struct { + snapshotID **gid.GID + } +) + +func NewProcessingActivityDPIAFilter(snapshotID **gid.GID) *ProcessingActivityDPIAFilter { + return &ProcessingActivityDPIAFilter{ + snapshotID: snapshotID, + } +} + +func (f *ProcessingActivityDPIAFilter) SQLArguments() pgx.NamedArgs { + args := pgx.NamedArgs{} + + if f.snapshotID != nil && *f.snapshotID != nil { + args["filter_snapshot_id"] = **f.snapshotID + } + + return args +} + +func (f *ProcessingActivityDPIAFilter) SQLFragment() string { + if f.snapshotID == nil { + return "TRUE" + } + + if *f.snapshotID == nil { + return "snapshot_id IS NULL" + } else { + return "snapshot_id = @filter_snapshot_id" + } +} diff --git a/pkg/coredata/processing_activity_tia.go b/pkg/coredata/processing_activity_tia.go index 714866ccc..35d28ba43 100644 --- a/pkg/coredata/processing_activity_tia.go +++ b/pkg/coredata/processing_activity_tia.go @@ -38,6 +38,8 @@ func (e ErrProcessingActivityTIANotFound) Error() string { type ( ProcessingActivityTIA struct { ID gid.GID `db:"id"` + SnapshotID *gid.GID `db:"snapshot_id"` + SourceID *gid.GID `db:"source_id"` OrganizationID gid.GID `db:"organization_id"` ProcessingActivityID gid.GID `db:"processing_activity_id"` DataSubjects *string `db:"data_subjects"` @@ -66,6 +68,7 @@ func (tias *ProcessingActivityTIAs) CountByOrganizationID( conn pg.Conn, scope Scoper, organizationID gid.GID, + filter *ProcessingActivityTIAFilter, ) (int, error) { q := ` SELECT @@ -75,12 +78,14 @@ FROM WHERE %s AND organization_id = @organization_id + AND %s ` - q = fmt.Sprintf(q, scope.SQLFragment()) + q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment()) args := pgx.StrictNamedArgs{"organization_id": organizationID} maps.Copy(args, scope.SQLArguments()) + maps.Copy(args, filter.SQLArguments()) row := conn.QueryRow(ctx, q, args) @@ -99,10 +104,13 @@ func (tias *ProcessingActivityTIAs) LoadByOrganizationID( scope Scoper, organizationID gid.GID, cursor *page.Cursor[ProcessingActivityTIAOrderField], + filter *ProcessingActivityTIAFilter, ) error { q := ` SELECT id, + snapshot_id, + source_id, organization_id, processing_activity_id, data_subjects, @@ -118,12 +126,14 @@ WHERE %s AND organization_id = @organization_id AND %s + AND %s ` - q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment()) + q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment(), cursor.SQLFragment()) args := pgx.StrictNamedArgs{"organization_id": organizationID} maps.Copy(args, scope.SQLArguments()) + maps.Copy(args, filter.SQLArguments()) maps.Copy(args, cursor.SQLArguments()) rows, err := conn.Query(ctx, q, args) @@ -150,6 +160,8 @@ func (tia *ProcessingActivityTIA) LoadByID( q := ` SELECT id, + snapshot_id, + source_id, organization_id, processing_activity_id, data_subjects, @@ -199,6 +211,8 @@ func (tia *ProcessingActivityTIA) LoadByProcessingActivityID( q := ` SELECT id, + snapshot_id, + source_id, organization_id, processing_activity_id, data_subjects, @@ -357,3 +371,61 @@ WHERE return nil } + +func (tias ProcessingActivityTIAs) InsertProcessingActivitySnapshots( + ctx context.Context, + conn pg.Conn, + scope Scoper, + organizationID gid.GID, + snapshotID gid.GID, +) error { + query := ` +INSERT INTO processing_activity_transfer_impact_assessments ( + id, + tenant_id, + snapshot_id, + source_id, + organization_id, + processing_activity_id, + data_subjects, + legal_mechanism, + transfer, + local_law_risk, + supplementary_measures, + created_at, + updated_at +) +SELECT + generate_gid(decode_base64_unpadded(@tenant_id), @tia_entity_type), + @tenant_id, + @snapshot_id, + tia.id, + tia.organization_id, + pa_snapshot.id, + tia.data_subjects, + tia.legal_mechanism, + tia.transfer, + tia.local_law_risk, + tia.supplementary_measures, + tia.created_at, + tia.updated_at +FROM processing_activity_transfer_impact_assessments tia +INNER JOIN processing_activities pa_source ON tia.processing_activity_id = pa_source.id AND pa_source.snapshot_id IS NULL +INNER JOIN processing_activities pa_snapshot ON pa_source.id = pa_snapshot.source_id AND pa_snapshot.snapshot_id = @snapshot_id +WHERE tia.tenant_id = @tenant_id AND tia.organization_id = @organization_id AND tia.snapshot_id IS NULL + ` + + args := pgx.StrictNamedArgs{ + "tenant_id": scope.GetTenantID(), + "snapshot_id": snapshotID, + "organization_id": organizationID, + "tia_entity_type": ProcessingActivityTIAEntityType, + } + + _, err := conn.Exec(ctx, query, args) + if err != nil { + return fmt.Errorf("cannot insert processing activity tia snapshots: %w", err) + } + + return nil +} diff --git a/pkg/coredata/processing_activity_tia_filter.go b/pkg/coredata/processing_activity_tia_filter.go new file mode 100644 index 000000000..55b31119a --- /dev/null +++ b/pkg/coredata/processing_activity_tia_filter.go @@ -0,0 +1,54 @@ +// 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 ( + "github.com/jackc/pgx/v5" + "go.probo.inc/probo/pkg/gid" +) + +type ( + ProcessingActivityTIAFilter struct { + snapshotID **gid.GID + } +) + +func NewProcessingActivityTIAFilter(snapshotID **gid.GID) *ProcessingActivityTIAFilter { + return &ProcessingActivityTIAFilter{ + snapshotID: snapshotID, + } +} + +func (f *ProcessingActivityTIAFilter) SQLArguments() pgx.NamedArgs { + args := pgx.NamedArgs{} + + if f.snapshotID != nil && *f.snapshotID != nil { + args["filter_snapshot_id"] = **f.snapshotID + } + + return args +} + +func (f *ProcessingActivityTIAFilter) SQLFragment() string { + if f.snapshotID == nil { + return "TRUE" + } + + if *f.snapshotID == nil { + return "snapshot_id IS NULL" + } else { + return "snapshot_id = @filter_snapshot_id" + } +} diff --git a/pkg/probo/processing_activity_dpia_service.go b/pkg/probo/processing_activity_dpia_service.go index e5e524cee..5c169df4b 100644 --- a/pkg/probo/processing_activity_dpia_service.go +++ b/pkg/probo/processing_activity_dpia_service.go @@ -128,13 +128,14 @@ func (s ProcessingActivityDPIAService) ListForOrganizationID( ctx context.Context, organizationID gid.GID, cursor *page.Cursor[coredata.ProcessingActivityDPIAOrderField], + filter *coredata.ProcessingActivityDPIAFilter, ) (*page.Page[*coredata.ProcessingActivityDPIA, coredata.ProcessingActivityDPIAOrderField], error) { var dpias coredata.ProcessingActivityDPIAs err := s.svc.pg.WithConn( ctx, func(conn pg.Conn) error { - err := dpias.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor) + err := dpias.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor, filter) if err != nil { return fmt.Errorf("cannot load processing activity dpias: %w", err) } @@ -153,6 +154,7 @@ func (s ProcessingActivityDPIAService) ListForOrganizationID( func (s ProcessingActivityDPIAService) CountForOrganizationID( ctx context.Context, organizationID gid.GID, + filter *coredata.ProcessingActivityDPIAFilter, ) (int, error) { var count int @@ -160,7 +162,7 @@ func (s ProcessingActivityDPIAService) CountForOrganizationID( ctx, func(conn pg.Conn) (err error) { dpias := coredata.ProcessingActivityDPIAs{} - count, err = dpias.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID) + count, err = dpias.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID, filter) return err }, ) diff --git a/pkg/probo/processing_activity_tia_service.go b/pkg/probo/processing_activity_tia_service.go index c87f19221..8825ff3e0 100644 --- a/pkg/probo/processing_activity_tia_service.go +++ b/pkg/probo/processing_activity_tia_service.go @@ -128,13 +128,14 @@ func (s ProcessingActivityTIAService) ListForOrganizationID( ctx context.Context, organizationID gid.GID, cursor *page.Cursor[coredata.ProcessingActivityTIAOrderField], + filter *coredata.ProcessingActivityTIAFilter, ) (*page.Page[*coredata.ProcessingActivityTIA, coredata.ProcessingActivityTIAOrderField], error) { var tias coredata.ProcessingActivityTIAs err := s.svc.pg.WithConn( ctx, func(conn pg.Conn) error { - err := tias.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor) + err := tias.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor, filter) if err != nil { return fmt.Errorf("cannot load processing activity tias: %w", err) } @@ -153,6 +154,7 @@ func (s ProcessingActivityTIAService) ListForOrganizationID( func (s ProcessingActivityTIAService) CountForOrganizationID( ctx context.Context, organizationID gid.GID, + filter *coredata.ProcessingActivityTIAFilter, ) (int, error) { var count int @@ -160,7 +162,7 @@ func (s ProcessingActivityTIAService) CountForOrganizationID( ctx, func(conn pg.Conn) (err error) { tias := coredata.ProcessingActivityTIAs{} - count, err = tias.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID) + count, err = tias.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID, filter) return err }, ) diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index cdf7bc22f..a0817e0bd 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -1517,6 +1517,14 @@ input ProcessingActivityFilter { snapshotId: ID } +input ProcessingActivityDPIAFilter { + snapshotId: ID +} + +input ProcessingActivityTIAFilter { + snapshotId: ID +} + input AssetFilter { snapshotId: ID } @@ -1734,6 +1742,7 @@ type Organization implements Node { last: Int before: CursorKey orderBy: ProcessingActivityDPIAOrder + filter: ProcessingActivityDPIAFilter = { snapshotId: null } ): ProcessingActivityDPIAConnection! @goField(forceResolver: true) transferImpactAssessments( @@ -1742,6 +1751,7 @@ type Organization implements Node { last: Int before: CursorKey orderBy: ProcessingActivityTIAOrder + filter: ProcessingActivityTIAFilter = { snapshotId: null } ): ProcessingActivityTIAConnection! @goField(forceResolver: true) snapshots( diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go index 7f0c7f469..a01f4c172 100644 --- a/pkg/server/api/console/v1/schema/schema.go +++ b/pkg/server/api/console/v1/schema/schema.go @@ -1134,7 +1134,7 @@ type ComplexityRoot struct { CreatedAt func(childComplexity int) int CustomDomain func(childComplexity int) int Data func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DatumOrderBy, filter *types.DatumFilter) int - DataProtectionImpactAssessments func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityDPIAOrderBy) int + DataProtectionImpactAssessments func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityDPIAOrderBy, filter *types.ProcessingActivityDPIAFilter) int Description func(childComplexity int) int Documents func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) int Email func(childComplexity int) int @@ -1157,7 +1157,7 @@ type ComplexityRoot struct { SlackConnections func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey) int Snapshots func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) int Tasks func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) int - TransferImpactAssessments func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityTIAOrderBy) int + TransferImpactAssessments func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityTIAOrderBy, filter *types.ProcessingActivityTIAFilter) int TrustCenter func(childComplexity int) int TrustCenterFiles func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterFileOrderField]) int UpdatedAt func(childComplexity int) int @@ -2247,8 +2247,8 @@ type OrganizationResolver interface { Obligations(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) (*types.ObligationConnection, error) ContinualImprovements(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ContinualImprovementOrderBy, filter *types.ContinualImprovementFilter) (*types.ContinualImprovementConnection, error) ProcessingActivities(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityOrderBy, filter *types.ProcessingActivityFilter) (*types.ProcessingActivityConnection, error) - DataProtectionImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityDPIAOrderBy) (*types.ProcessingActivityDPIAConnection, error) - TransferImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityTIAOrderBy) (*types.ProcessingActivityTIAConnection, error) + DataProtectionImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityDPIAOrderBy, filter *types.ProcessingActivityDPIAFilter) (*types.ProcessingActivityDPIAConnection, error) + TransferImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityTIAOrderBy, filter *types.ProcessingActivityTIAFilter) (*types.ProcessingActivityTIAConnection, error) Snapshots(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) (*types.SnapshotConnection, error) TrustCenterFiles(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterFileOrderField]) (*types.TrustCenterFileConnection, error) TrustCenter(ctx context.Context, obj *types.Organization) (*types.TrustCenter, error) @@ -6715,7 +6715,7 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return 0, false } - return e.complexity.Organization.DataProtectionImpactAssessments(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.ProcessingActivityDPIAOrderBy)), true + return e.complexity.Organization.DataProtectionImpactAssessments(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.ProcessingActivityDPIAOrderBy), args["filter"].(*types.ProcessingActivityDPIAFilter)), true case "Organization.description": if e.complexity.Organization.Description == nil { break @@ -6928,7 +6928,7 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return 0, false } - return e.complexity.Organization.TransferImpactAssessments(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.ProcessingActivityTIAOrderBy)), true + return e.complexity.Organization.TransferImpactAssessments(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.ProcessingActivityTIAOrderBy), args["filter"].(*types.ProcessingActivityTIAFilter)), true case "Organization.trustCenter": if e.complexity.Organization.TrustCenter == nil { break @@ -9883,9 +9883,11 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputOrganizationOrder, ec.unmarshalInputPeopleFilter, ec.unmarshalInputPeopleOrder, + ec.unmarshalInputProcessingActivityDPIAFilter, ec.unmarshalInputProcessingActivityDPIAOrder, ec.unmarshalInputProcessingActivityFilter, ec.unmarshalInputProcessingActivityOrder, + ec.unmarshalInputProcessingActivityTIAFilter, ec.unmarshalInputProcessingActivityTIAOrder, ec.unmarshalInputPublishDocumentVersionInput, ec.unmarshalInputRemoveMemberInput, @@ -11564,6 +11566,14 @@ input ProcessingActivityFilter { snapshotId: ID } +input ProcessingActivityDPIAFilter { + snapshotId: ID +} + +input ProcessingActivityTIAFilter { + snapshotId: ID +} + input AssetFilter { snapshotId: ID } @@ -11781,6 +11791,7 @@ type Organization implements Node { last: Int before: CursorKey orderBy: ProcessingActivityDPIAOrder + filter: ProcessingActivityDPIAFilter = { snapshotId: null } ): ProcessingActivityDPIAConnection! @goField(forceResolver: true) transferImpactAssessments( @@ -11789,6 +11800,7 @@ type Organization implements Node { last: Int before: CursorKey orderBy: ProcessingActivityTIAOrder + filter: ProcessingActivityTIAFilter = { snapshotId: null } ): ProcessingActivityTIAConnection! @goField(forceResolver: true) snapshots( @@ -17552,6 +17564,11 @@ func (ec *executionContext) field_Organization_dataProtectionImpactAssessments_a return nil, err } args["orderBy"] = arg4 + arg5, err := graphql.ProcessArgField(ctx, rawArgs, "filter", ec.unmarshalOProcessingActivityDPIAFilter2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐProcessingActivityDPIAFilter) + if err != nil { + return nil, err + } + args["filter"] = arg5 return args, nil } @@ -18088,6 +18105,11 @@ func (ec *executionContext) field_Organization_transferImpactAssessments_args(ct return nil, err } args["orderBy"] = arg4 + arg5, err := graphql.ProcessArgField(ctx, rawArgs, "filter", ec.unmarshalOProcessingActivityTIAFilter2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐProcessingActivityTIAFilter) + if err != nil { + return nil, err + } + args["filter"] = arg5 return args, nil } @@ -41067,7 +41089,7 @@ func (ec *executionContext) _Organization_dataProtectionImpactAssessments(ctx co ec.fieldContext_Organization_dataProtectionImpactAssessments, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.resolvers.Organization().DataProtectionImpactAssessments(ctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.ProcessingActivityDPIAOrderBy)) + return ec.resolvers.Organization().DataProtectionImpactAssessments(ctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.ProcessingActivityDPIAOrderBy), fc.Args["filter"].(*types.ProcessingActivityDPIAFilter)) }, nil, ec.marshalNProcessingActivityDPIAConnection2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐProcessingActivityDPIAConnection, @@ -41116,7 +41138,7 @@ func (ec *executionContext) _Organization_transferImpactAssessments(ctx context. ec.fieldContext_Organization_transferImpactAssessments, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) - return ec.resolvers.Organization().TransferImpactAssessments(ctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.ProcessingActivityTIAOrderBy)) + return ec.resolvers.Organization().TransferImpactAssessments(ctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.ProcessingActivityTIAOrderBy), fc.Args["filter"].(*types.ProcessingActivityTIAFilter)) }, nil, ec.marshalNProcessingActivityTIAConnection2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐProcessingActivityTIAConnection, @@ -64622,6 +64644,33 @@ func (ec *executionContext) unmarshalInputPeopleOrder(ctx context.Context, obj a return it, nil } +func (ec *executionContext) unmarshalInputProcessingActivityDPIAFilter(ctx context.Context, obj any) (types.ProcessingActivityDPIAFilter, error) { + var it types.ProcessingActivityDPIAFilter + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"snapshotId"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "snapshotId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("snapshotId")) + data, err := ec.unmarshalOID2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.SnapshotID = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputProcessingActivityDPIAOrder(ctx context.Context, obj any) (types.ProcessingActivityDPIAOrderBy, error) { var it types.ProcessingActivityDPIAOrderBy asMap := map[string]any{} @@ -64717,6 +64766,33 @@ func (ec *executionContext) unmarshalInputProcessingActivityOrder(ctx context.Co return it, nil } +func (ec *executionContext) unmarshalInputProcessingActivityTIAFilter(ctx context.Context, obj any) (types.ProcessingActivityTIAFilter, error) { + var it types.ProcessingActivityTIAFilter + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"snapshotId"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "snapshotId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("snapshotId")) + data, err := ec.unmarshalOID2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.SnapshotID = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputProcessingActivityTIAOrder(ctx context.Context, obj any) (types.ProcessingActivityTIAOrderBy, error) { var it types.ProcessingActivityTIAOrderBy asMap := map[string]any{} @@ -98053,6 +98129,14 @@ func (ec *executionContext) marshalOProcessingActivityDPIA2ᚖgoᚗproboᚗinc return ec._ProcessingActivityDPIA(ctx, sel, v) } +func (ec *executionContext) unmarshalOProcessingActivityDPIAFilter2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐProcessingActivityDPIAFilter(ctx context.Context, v any) (*types.ProcessingActivityDPIAFilter, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputProcessingActivityDPIAFilter(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalOProcessingActivityDPIAOrder2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐProcessingActivityDPIAOrderBy(ctx context.Context, v any) (*types.ProcessingActivityDPIAOrderBy, error) { if v == nil { return nil, nil @@ -98246,6 +98330,14 @@ func (ec *executionContext) marshalOProcessingActivityTIA2ᚖgoᚗproboᚗincᚋ return ec._ProcessingActivityTIA(ctx, sel, v) } +func (ec *executionContext) unmarshalOProcessingActivityTIAFilter2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐProcessingActivityTIAFilter(ctx context.Context, v any) (*types.ProcessingActivityTIAFilter, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputProcessingActivityTIAFilter(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalOProcessingActivityTIAOrder2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐProcessingActivityTIAOrderBy(ctx context.Context, v any) (*types.ProcessingActivityTIAOrderBy, error) { if v == nil { return nil, nil diff --git a/pkg/server/api/console/v1/types/processing_activity_dpia.go b/pkg/server/api/console/v1/types/processing_activity_dpia.go index 3e8dca6e4..71d011784 100644 --- a/pkg/server/api/console/v1/types/processing_activity_dpia.go +++ b/pkg/server/api/console/v1/types/processing_activity_dpia.go @@ -30,6 +30,7 @@ type ( Resolver any ParentID gid.GID + Filter *coredata.ProcessingActivityDPIAFilter } ) @@ -37,6 +38,7 @@ func NewProcessingActivityDPIAConnection( p *page.Page[*coredata.ProcessingActivityDPIA, coredata.ProcessingActivityDPIAOrderField], parentType any, parentID gid.GID, + filter *coredata.ProcessingActivityDPIAFilter, ) *ProcessingActivityDPIAConnection { edges := make([]*ProcessingActivityDPIAEdge, len(p.Data)) for i, dpia := range p.Data { @@ -49,6 +51,7 @@ func NewProcessingActivityDPIAConnection( Resolver: parentType, ParentID: parentID, + Filter: filter, } } diff --git a/pkg/server/api/console/v1/types/processing_activity_tia.go b/pkg/server/api/console/v1/types/processing_activity_tia.go index 8d7b09659..79e722d5d 100644 --- a/pkg/server/api/console/v1/types/processing_activity_tia.go +++ b/pkg/server/api/console/v1/types/processing_activity_tia.go @@ -30,6 +30,7 @@ type ( Resolver any ParentID gid.GID + Filter *coredata.ProcessingActivityTIAFilter } ) @@ -37,6 +38,7 @@ func NewProcessingActivityTIAConnection( p *page.Page[*coredata.ProcessingActivityTIA, coredata.ProcessingActivityTIAOrderField], parentType any, parentID gid.GID, + filter *coredata.ProcessingActivityTIAFilter, ) *ProcessingActivityTIAConnection { edges := make([]*ProcessingActivityTIAEdge, len(p.Data)) for i, tia := range p.Data { @@ -49,6 +51,7 @@ func NewProcessingActivityTIAConnection( Resolver: parentType, ParentID: parentID, + Filter: filter, } } diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go index ce71a1cd8..dd15bd7d9 100644 --- a/pkg/server/api/console/v1/types/types.go +++ b/pkg/server/api/console/v1/types/types.go @@ -1621,6 +1621,10 @@ type ProcessingActivityDPIAEdge struct { Node *ProcessingActivityDpia `json:"node"` } +type ProcessingActivityDPIAFilter struct { + SnapshotID *gid.GID `json:"snapshotId,omitempty"` +} + type ProcessingActivityEdge struct { Cursor page.CursorKey `json:"cursor"` Node *ProcessingActivity `json:"node"` @@ -1651,6 +1655,10 @@ type ProcessingActivityTIAEdge struct { Node *ProcessingActivityTia `json:"node"` } +type ProcessingActivityTIAFilter struct { + SnapshotID *gid.GID `json:"snapshotId,omitempty"` +} + type PublishDocumentVersionInput struct { DocumentID gid.GID `json:"documentId"` Changelog *string `json:"changelog,omitempty"` diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index d492ce516..1c69baa6a 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -5531,7 +5531,7 @@ func (r *organizationResolver) ProcessingActivities(ctx context.Context, obj *ty } // DataProtectionImpactAssessments is the resolver for the dataProtectionImpactAssessments field. -func (r *organizationResolver) DataProtectionImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityDPIAOrderBy) (*types.ProcessingActivityDPIAConnection, error) { +func (r *organizationResolver) DataProtectionImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityDPIAOrderBy, filter *types.ProcessingActivityDPIAFilter) (*types.ProcessingActivityDPIAConnection, error) { r.MustBeAuthorized(ctx, obj.ID, authz.ActionListProcessingActivities) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5550,16 +5550,21 @@ func (r *organizationResolver) DataProtectionImpactAssessments(ctx context.Conte cursor := types.NewCursor(first, after, last, before, pageOrderBy) - page, err := prb.ProcessingActivityDPIAs.ListForOrganizationID(ctx, obj.ID, cursor) + dpiaFilter := coredata.NewProcessingActivityDPIAFilter(nil) + if filter != nil { + dpiaFilter = coredata.NewProcessingActivityDPIAFilter(&filter.SnapshotID) + } + + page, err := prb.ProcessingActivityDPIAs.ListForOrganizationID(ctx, obj.ID, cursor, dpiaFilter) if err != nil { panic(fmt.Errorf("cannot list organization data protection impact assessments: %w", err)) } - return types.NewProcessingActivityDPIAConnection(page, r, obj.ID), nil + return types.NewProcessingActivityDPIAConnection(page, r, obj.ID, dpiaFilter), nil } // TransferImpactAssessments is the resolver for the transferImpactAssessments field. -func (r *organizationResolver) TransferImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityTIAOrderBy) (*types.ProcessingActivityTIAConnection, error) { +func (r *organizationResolver) TransferImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityTIAOrderBy, filter *types.ProcessingActivityTIAFilter) (*types.ProcessingActivityTIAConnection, error) { r.MustBeAuthorized(ctx, obj.ID, authz.ActionListProcessingActivities) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5578,12 +5583,17 @@ func (r *organizationResolver) TransferImpactAssessments(ctx context.Context, ob cursor := types.NewCursor(first, after, last, before, pageOrderBy) - page, err := prb.ProcessingActivityTIAs.ListForOrganizationID(ctx, obj.ID, cursor) + tiaFilter := coredata.NewProcessingActivityTIAFilter(nil) + if filter != nil { + tiaFilter = coredata.NewProcessingActivityTIAFilter(&filter.SnapshotID) + } + + page, err := prb.ProcessingActivityTIAs.ListForOrganizationID(ctx, obj.ID, cursor, tiaFilter) if err != nil { panic(fmt.Errorf("cannot list organization transfer impact assessments: %w", err)) } - return types.NewProcessingActivityTIAConnection(page, r, obj.ID), nil + return types.NewProcessingActivityTIAConnection(page, r, obj.ID, tiaFilter), nil } // Snapshots is the resolver for the snapshots field. @@ -5896,7 +5906,7 @@ func (r *processingActivityDPIAConnectionResolver) TotalCount(ctx context.Contex switch obj.Resolver.(type) { case *organizationResolver: - count, err := prb.ProcessingActivityDPIAs.CountForOrganizationID(ctx, obj.ParentID) + count, err := prb.ProcessingActivityDPIAs.CountForOrganizationID(ctx, obj.ParentID, obj.Filter) if err != nil { panic(fmt.Errorf("cannot count organization data protection impact assessments: %w", err)) } @@ -5956,7 +5966,7 @@ func (r *processingActivityTIAConnectionResolver) TotalCount(ctx context.Context switch obj.Resolver.(type) { case *organizationResolver: - count, err := prb.ProcessingActivityTIAs.CountForOrganizationID(ctx, obj.ParentID) + count, err := prb.ProcessingActivityTIAs.CountForOrganizationID(ctx, obj.ParentID, obj.Filter) if err != nil { panic(fmt.Errorf("cannot count organization transfer impact assessments: %w", err)) }