Trust center access management - get rid of access token

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-01-15 16:16:06 +04:00
committed by Bryan Frimin
parent 8b3bda56e6
commit 44d85a2b12
39 changed files with 582 additions and 1800 deletions

View File

@@ -7,7 +7,6 @@ import {
IconMedal,
useToast,
} from "@probo/ui";
import type { TrustGraphQuery$data } from "/queries/__generated__/TrustGraphQuery.graphql";
import { use, type PropsWithChildren } from "react";
import { domain, formatError } from "@probo/helpers";
import { AuditRowAvatar } from "./AuditRow";
@@ -16,6 +15,7 @@ import { MagicLinkDialog } from "./MagicLinkDialog";
import { graphql } from "relay-runtime";
import { useMutation } from "react-relay";
import type { OrganizationSidebar_requestAllAccessesMutation } from "./__generated__/OrganizationSidebar_requestAllAccessesMutation.graphql";
import type { TrustGraphCurrentQuery$data } from "/queries/__generated__/TrustGraphCurrentQuery.graphql";
const requestAllAccessesMutation = graphql`
mutation OrganizationSidebar_requestAllAccessesMutation {
@@ -30,7 +30,7 @@ const requestAllAccessesMutation = graphql`
export function OrganizationSidebar({
trustCenter,
}: {
trustCenter: TrustGraphQuery$data["currentTrustCenter"];
trustCenter: TrustGraphCurrentQuery$data["currentTrustCenter"];
}) {
const { __ } = useTranslate();
const isAuthenticated = !!use(Viewer);

View File

@@ -1,105 +0,0 @@
/**
* @generated SignedSource<<2ea33498f7101d861d940b9c52ed3283>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type RequestDocumentAccessInput = {
documentId: string;
};
export type RequestAccessDialogDocumentMutation$variables = {
input: RequestDocumentAccessInput;
};
export type RequestAccessDialogDocumentMutation$data = {
readonly requestDocumentAccess: {
readonly trustCenterAccess: {
readonly id: string;
};
};
};
export type RequestAccessDialogDocumentMutation = {
response: RequestAccessDialogDocumentMutation$data;
variables: RequestAccessDialogDocumentMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "RequestAccessesPayload",
"kind": "LinkedField",
"name": "requestDocumentAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterAccess",
"kind": "LinkedField",
"name": "trustCenterAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "RequestAccessDialogDocumentMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "RequestAccessDialogDocumentMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "2ed1f0d19711a9f22acdc6251dbfca8f",
"id": null,
"metadata": {},
"name": "RequestAccessDialogDocumentMutation",
"operationKind": "mutation",
"text": "mutation RequestAccessDialogDocumentMutation(\n $input: RequestDocumentAccessInput!\n) {\n requestDocumentAccess(input: $input) {\n trustCenterAccess {\n id\n }\n }\n}\n"
}
};
})();
(node as any).hash = "c3ebabe2f3fac32e5035cc7acfd54799";
export default node;

View File

@@ -1,87 +0,0 @@
/**
* @generated SignedSource<<b06c18474ea9953c2fb496b919b8e247>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type RequestAccessDialogMutation$variables = Record<PropertyKey, never>;
export type RequestAccessDialogMutation$data = {
readonly requestAllAccesses: {
readonly trustCenterAccess: {
readonly id: string;
};
};
};
export type RequestAccessDialogMutation = {
response: RequestAccessDialogMutation$data;
variables: RequestAccessDialogMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"alias": null,
"args": null,
"concreteType": "RequestAccessesPayload",
"kind": "LinkedField",
"name": "requestAllAccesses",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterAccess",
"kind": "LinkedField",
"name": "trustCenterAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "RequestAccessDialogMutation",
"selections": (v0/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [],
"kind": "Operation",
"name": "RequestAccessDialogMutation",
"selections": (v0/*: any*/)
},
"params": {
"cacheID": "b48847e88c57289efc120745c743c8f6",
"id": null,
"metadata": {},
"name": "RequestAccessDialogMutation",
"operationKind": "mutation",
"text": "mutation RequestAccessDialogMutation {\n requestAllAccesses {\n trustCenterAccess {\n id\n }\n }\n}\n"
}
};
})();
(node as any).hash = "44c3538831968b7146fbf2c9e027a778";
export default node;

View File

@@ -1,105 +0,0 @@
/**
* @generated SignedSource<<3e5433cc33d54bff9511d01eb4c65b00>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type RequestReportAccessInput = {
reportId: string;
};
export type RequestAccessDialogReportMutation$variables = {
input: RequestReportAccessInput;
};
export type RequestAccessDialogReportMutation$data = {
readonly requestReportAccess: {
readonly trustCenterAccess: {
readonly id: string;
};
};
};
export type RequestAccessDialogReportMutation = {
response: RequestAccessDialogReportMutation$data;
variables: RequestAccessDialogReportMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "RequestAccessesPayload",
"kind": "LinkedField",
"name": "requestReportAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterAccess",
"kind": "LinkedField",
"name": "trustCenterAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "RequestAccessDialogReportMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "RequestAccessDialogReportMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "da69c3e370244e4a9a7793b06b2abdd5",
"id": null,
"metadata": {},
"name": "RequestAccessDialogReportMutation",
"operationKind": "mutation",
"text": "mutation RequestAccessDialogReportMutation(\n $input: RequestReportAccessInput!\n) {\n requestReportAccess(input: $input) {\n trustCenterAccess {\n id\n }\n }\n}\n"
}
};
})();
(node as any).hash = "3ef2b6424ba751f15f91ad7f4bd28fc5";
export default node;

View File

@@ -1,105 +0,0 @@
/**
* @generated SignedSource<<447bd664ebefbd6a672ccde86c63c028>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type RequestTrustCenterFileAccessInput = {
trustCenterFileId: string;
};
export type RequestAccessDialogTrustCenterFileMutation$variables = {
input: RequestTrustCenterFileAccessInput;
};
export type RequestAccessDialogTrustCenterFileMutation$data = {
readonly requestTrustCenterFileAccess: {
readonly trustCenterAccess: {
readonly id: string;
};
};
};
export type RequestAccessDialogTrustCenterFileMutation = {
response: RequestAccessDialogTrustCenterFileMutation$data;
variables: RequestAccessDialogTrustCenterFileMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "RequestAccessesPayload",
"kind": "LinkedField",
"name": "requestTrustCenterFileAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterAccess",
"kind": "LinkedField",
"name": "trustCenterAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "RequestAccessDialogTrustCenterFileMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "RequestAccessDialogTrustCenterFileMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "73b3007ef1a45f6dc6d31be0c627e482",
"id": null,
"metadata": {},
"name": "RequestAccessDialogTrustCenterFileMutation",
"operationKind": "mutation",
"text": "mutation RequestAccessDialogTrustCenterFileMutation(\n $input: RequestTrustCenterFileAccessInput!\n) {\n requestTrustCenterFileAccess(input: $input) {\n trustCenterAccess {\n id\n }\n }\n}\n"
}
};
})();
(node as any).hash = "a97eb6c4ec94c79a293d1cc51bf18e66";
export default node;

View File

@@ -22,7 +22,7 @@ export function MainLayout(props: Props) {
return null;
}
const showNDADialog =
trustCenter.isUserAuthenticated &&
trustCenter.isViewerMember &&
!trustCenter.hasAcceptedNonDisclosureAgreement &&
trustCenter.ndaFileUrl;
return (

View File

@@ -11,7 +11,6 @@ import {
sprintf,
getTrustCenterUrl,
} from "@probo/helpers";
import type { TrustGraphQuery$data } from "/queries/__generated__/TrustGraphQuery.graphql";
import { useTranslate } from "@probo/i18n";
import { Card, IconChevronRight } from "@probo/ui";
import { AuditRow } from "/components/AuditRow";
@@ -22,6 +21,7 @@ import { TrustCenterFileRow } from "/components/TrustCenterFileRow";
import { VendorRow } from "/components/VendorRow";
import { RowHeader } from "/components/RowHeader.tsx";
import { Rows } from "/components/Rows.tsx";
import type { TrustGraphCurrentQuery$data } from "/queries/__generated__/TrustGraphCurrentQuery.graphql";
const overviewFragment = graphql`
fragment OverviewPageFragment on TrustCenter {
@@ -68,7 +68,7 @@ const overviewFragment = graphql`
export function OverviewPage() {
const { trustCenter } = useOutletContext<{
trustCenter: OverviewPageFragment$key &
TrustGraphQuery$data["currentTrustCenter"];
TrustGraphCurrentQuery$data["currentTrustCenter"];
}>();
const fragment = useFragment(overviewFragment, trustCenter);
return (
@@ -100,7 +100,7 @@ function Documents({
documents: OverviewPageFragment$data["documents"]["edges"];
files: OverviewPageFragment$data["trustCenterFiles"]["edges"];
audits: NonNullable<
TrustGraphQuery$data["currentTrustCenter"]
TrustGraphCurrentQuery$data["currentTrustCenter"]
>["audits"]["edges"];
url: string;
}) {

View File

@@ -1,8 +1,8 @@
import { createContext, type ReactNode } from "react";
import type { TrustGraphQuery$data } from "/queries/__generated__/TrustGraphQuery.graphql";
import type { TrustGraphCurrentQuery$data } from "/queries/__generated__/TrustGraphCurrentQuery.graphql";
export const TrustCenterContext = createContext<
TrustGraphQuery$data["currentTrustCenter"] | null
TrustGraphCurrentQuery$data["currentTrustCenter"] | null
>(null);
export const TrustCenterProvider = ({
@@ -10,7 +10,7 @@ export const TrustCenterProvider = ({
trustCenter,
}: {
children: ReactNode;
trustCenter: TrustGraphQuery$data["currentTrustCenter"];
trustCenter: TrustGraphCurrentQuery$data["currentTrustCenter"];
}) => {
return (
<TrustCenterContext.Provider value={trustCenter}>

View File

@@ -1,84 +1,5 @@
import { graphql } from "relay-runtime";
export const trustGraphQuery = graphql`
query TrustGraphQuery {
currentTrustCenter {
id
slug
isUserAuthenticated
hasAcceptedNonDisclosureAgreement
ndaFileName
ndaFileUrl
organization {
name
description
websiteUrl
logoUrl
email
headquarterAddress
}
...OverviewPageFragment
audits(first: 50) {
edges {
node {
id
...AuditRowFragment
}
}
}
}
}
`;
export const trustDocumentsQuery = graphql`
query TrustGraphDocumentsQuery {
currentTrustCenter {
id
organization {
name
}
documents(first: 50) {
edges {
node {
id
documentType
...DocumentRowFragment
}
}
}
trustCenterFiles(first: 50) {
edges {
node {
id
category
...TrustCenterFileRowFragment
}
}
}
}
}
`;
export const trustVendorsQuery = graphql`
query TrustGraphVendorsQuery {
currentTrustCenter {
id
organization {
name
}
vendors(first: 50) {
edges {
node {
id
countries
...VendorRowFragment
}
}
}
}
}
`;
// Queries for custom domain (subdomain) approach
export const currentTrustGraphQuery = graphql`
query TrustGraphCurrentQuery {
@@ -89,7 +10,7 @@ export const currentTrustGraphQuery = graphql`
currentTrustCenter {
id
slug
isUserAuthenticated
isViewerMember
hasAcceptedNonDisclosureAgreement
ndaFileName
ndaFileUrl

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<1f5a4da3a77a893daebeceb249612a72>>
* @generated SignedSource<<c77a16a1b448cd1630bdf025193ad94f>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -23,7 +23,7 @@ export type TrustGraphCurrentQuery$data = {
};
readonly hasAcceptedNonDisclosureAgreement: boolean;
readonly id: string;
readonly isUserAuthenticated: boolean;
readonly isViewerMember: boolean;
readonly ndaFileName: string | null | undefined;
readonly ndaFileUrl: string | null | undefined;
readonly organization: {
@@ -80,7 +80,7 @@ v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "isUserAuthenticated",
"name": "isViewerMember",
"storageKey": null
},
v5 = {
@@ -604,16 +604,16 @@ return {
]
},
"params": {
"cacheID": "9d22288e0159409cf43bece191e3dc47",
"cacheID": "c76b7662b00ed20e82ed9333792e396b",
"id": null,
"metadata": {},
"name": "TrustGraphCurrentQuery",
"operationKind": "query",
"text": "query TrustGraphCurrentQuery {\n viewer {\n email\n fullName\n id\n }\n currentTrustCenter {\n id\n slug\n isUserAuthenticated\n hasAcceptedNonDisclosureAgreement\n ndaFileName\n ndaFileUrl\n organization {\n name\n description\n websiteUrl\n logoUrl\n email\n headquarterAddress\n id\n }\n ...OverviewPageFragment\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n report {\n id\n filename\n isUserAuthorized\n hasUserRequestedAccess\n }\n framework {\n id\n name\n lightLogoURL\n darkLogoURL\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment OverviewPageFragment on TrustCenter {\n references(first: 14) {\n edges {\n node {\n id\n name\n logoUrl\n websiteUrl\n }\n }\n }\n vendors(first: 3) {\n edges {\n node {\n id\n countries\n ...VendorRowFragment\n }\n }\n }\n documents(first: 5) {\n edges {\n node {\n id\n ...DocumentRowFragment\n documentType\n }\n }\n }\n trustCenterFiles(first: 5) {\n edges {\n node {\n id\n category\n ...TrustCenterFileRowFragment\n }\n }\n }\n}\n\nfragment TrustCenterFileRowFragment on TrustCenterFile {\n id\n name\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n"
"text": "query TrustGraphCurrentQuery {\n viewer {\n email\n fullName\n id\n }\n currentTrustCenter {\n id\n slug\n isViewerMember\n hasAcceptedNonDisclosureAgreement\n ndaFileName\n ndaFileUrl\n organization {\n name\n description\n websiteUrl\n logoUrl\n email\n headquarterAddress\n id\n }\n ...OverviewPageFragment\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n report {\n id\n filename\n isUserAuthorized\n hasUserRequestedAccess\n }\n framework {\n id\n name\n lightLogoURL\n darkLogoURL\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment OverviewPageFragment on TrustCenter {\n references(first: 14) {\n edges {\n node {\n id\n name\n logoUrl\n websiteUrl\n }\n }\n }\n vendors(first: 3) {\n edges {\n node {\n id\n countries\n ...VendorRowFragment\n }\n }\n }\n documents(first: 5) {\n edges {\n node {\n id\n ...DocumentRowFragment\n documentType\n }\n }\n }\n trustCenterFiles(first: 5) {\n edges {\n node {\n id\n category\n ...TrustCenterFileRowFragment\n }\n }\n }\n}\n\nfragment TrustCenterFileRowFragment on TrustCenterFile {\n id\n name\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n"
}
};
})();
(node as any).hash = "dd2040667d5cc7b9af9659e993ba6a5b";
(node as any).hash = "e8ad7c480c3fac7346ea7d2be6ea5c9f";
export default node;

View File

@@ -1,339 +0,0 @@
/**
* @generated SignedSource<<7b9033da420b208f17d993bee5023358>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type DocumentType = "ISMS" | "OTHER" | "POLICY" | "PROCEDURE";
export type TrustGraphDocumentsQuery$variables = Record<PropertyKey, never>;
export type TrustGraphDocumentsQuery$data = {
readonly currentTrustCenter: {
readonly documents: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly documentType: DocumentType;
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"DocumentRowFragment">;
};
}>;
};
readonly id: string;
readonly organization: {
readonly name: string;
};
readonly trustCenterFiles: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly category: string;
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"TrustCenterFileRowFragment">;
};
}>;
};
} | null | undefined;
};
export type TrustGraphDocumentsQuery = {
response: TrustGraphDocumentsQuery$data;
variables: TrustGraphDocumentsQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v2 = [
{
"kind": "Literal",
"name": "first",
"value": 50
}
],
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
},
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"storageKey": null
},
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "isUserAuthorized",
"storageKey": null
},
v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasUserRequestedAccess",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "TrustGraphDocumentsQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenter",
"kind": "LinkedField",
"name": "currentTrustCenter",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Organization",
"kind": "LinkedField",
"name": "organization",
"plural": false,
"selections": [
(v1/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "documents",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
(v3/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "DocumentRowFragment"
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "documents(first:50)"
},
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "TrustCenterFileConnection",
"kind": "LinkedField",
"name": "trustCenterFiles",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterFileEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterFile",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
(v4/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "TrustCenterFileRowFragment"
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "trustCenterFiles(first:50)"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [],
"kind": "Operation",
"name": "TrustGraphDocumentsQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenter",
"kind": "LinkedField",
"name": "currentTrustCenter",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Organization",
"kind": "LinkedField",
"name": "organization",
"plural": false,
"selections": [
(v1/*: any*/),
(v0/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "documents",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
(v3/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
(v5/*: any*/),
(v6/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "documents(first:50)"
},
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "TrustCenterFileConnection",
"kind": "LinkedField",
"name": "trustCenterFiles",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterFileEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterFile",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
(v4/*: any*/),
(v1/*: any*/),
(v5/*: any*/),
(v6/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "trustCenterFiles(first:50)"
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "cf917e2efd7c2f644d222385443fd923",
"id": null,
"metadata": {},
"name": "TrustGraphDocumentsQuery",
"operationKind": "query",
"text": "query TrustGraphDocumentsQuery {\n currentTrustCenter {\n id\n organization {\n name\n id\n }\n documents(first: 50) {\n edges {\n node {\n id\n documentType\n ...DocumentRowFragment\n }\n }\n }\n trustCenterFiles(first: 50) {\n edges {\n node {\n id\n category\n ...TrustCenterFileRowFragment\n }\n }\n }\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment TrustCenterFileRowFragment on TrustCenterFile {\n id\n name\n isUserAuthorized\n hasUserRequestedAccess\n}\n"
}
};
})();
(node as any).hash = "32ee5adbf1a5cf44f836f45990a95732";
export default node;

View File

@@ -1,581 +0,0 @@
/**
* @generated SignedSource<<1a198d80eadc34edf67fd0f757c6f120>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type TrustGraphQuery$variables = Record<PropertyKey, never>;
export type TrustGraphQuery$data = {
readonly currentTrustCenter: {
readonly audits: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"AuditRowFragment">;
};
}>;
};
readonly hasAcceptedNonDisclosureAgreement: boolean;
readonly id: string;
readonly isUserAuthenticated: boolean;
readonly ndaFileName: string | null | undefined;
readonly ndaFileUrl: string | null | undefined;
readonly organization: {
readonly description: string | null | undefined;
readonly email: string | null | undefined;
readonly headquarterAddress: string | null | undefined;
readonly logoUrl: string | null | undefined;
readonly name: string;
readonly websiteUrl: string | null | undefined;
};
readonly slug: string;
readonly " $fragmentSpreads": FragmentRefs<"OverviewPageFragment">;
} | null | undefined;
};
export type TrustGraphQuery = {
response: TrustGraphQuery$data;
variables: TrustGraphQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "slug",
"storageKey": null
},
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "isUserAuthenticated",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasAcceptedNonDisclosureAgreement",
"storageKey": null
},
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "ndaFileName",
"storageKey": null
},
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "ndaFileUrl",
"storageKey": null
},
v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
v8 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "websiteUrl",
"storageKey": null
},
v9 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "logoUrl",
"storageKey": null
},
v10 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"storageKey": null
},
v11 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "headquarterAddress",
"storageKey": null
},
v12 = [
{
"kind": "Literal",
"name": "first",
"value": 50
}
],
v13 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"storageKey": null
},
v14 = [
{
"kind": "Literal",
"name": "first",
"value": 5
}
],
v15 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "isUserAuthorized",
"storageKey": null
},
v16 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasUserRequestedAccess",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "TrustGraphQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenter",
"kind": "LinkedField",
"name": "currentTrustCenter",
"plural": false,
"selections": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Organization",
"kind": "LinkedField",
"name": "organization",
"plural": false,
"selections": [
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
(v11/*: any*/)
],
"storageKey": null
},
{
"args": null,
"kind": "FragmentSpread",
"name": "OverviewPageFragment"
},
{
"alias": null,
"args": (v12/*: any*/),
"concreteType": "AuditConnection",
"kind": "LinkedField",
"name": "audits",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "AuditEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "AuditRowFragment"
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "audits(first:50)"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [],
"kind": "Operation",
"name": "TrustGraphQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenter",
"kind": "LinkedField",
"name": "currentTrustCenter",
"plural": false,
"selections": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Organization",
"kind": "LinkedField",
"name": "organization",
"plural": false,
"selections": [
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
(v11/*: any*/),
(v0/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 14
}
],
"concreteType": "TrustCenterReferenceConnection",
"kind": "LinkedField",
"name": "references",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterReferenceEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterReference",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
(v6/*: any*/),
(v9/*: any*/),
(v8/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "references(first:14)"
},
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 3
}
],
"concreteType": "VendorConnection",
"kind": "LinkedField",
"name": "vendors",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "VendorEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Vendor",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "countries",
"storageKey": null
},
(v6/*: any*/),
(v13/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "privacyPolicyUrl",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "vendors(first:3)"
},
{
"alias": null,
"args": (v14/*: any*/),
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "documents",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
(v15/*: any*/),
(v16/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "documents(first:5)"
},
{
"alias": null,
"args": (v14/*: any*/),
"concreteType": "TrustCenterFileConnection",
"kind": "LinkedField",
"name": "trustCenterFiles",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterFileEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterFile",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
(v13/*: any*/),
(v6/*: any*/),
(v15/*: any*/),
(v16/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "trustCenterFiles(first:5)"
},
{
"alias": null,
"args": (v12/*: any*/),
"concreteType": "AuditConnection",
"kind": "LinkedField",
"name": "audits",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "AuditEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Report",
"kind": "LinkedField",
"name": "report",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "filename",
"storageKey": null
},
(v15/*: any*/),
(v16/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v0/*: any*/),
(v6/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lightLogoURL",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "darkLogoURL",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "audits(first:50)"
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "86e2d66de7f28486d0a0b649661c2d43",
"id": null,
"metadata": {},
"name": "TrustGraphQuery",
"operationKind": "query",
"text": "query TrustGraphQuery {\n currentTrustCenter {\n id\n slug\n isUserAuthenticated\n hasAcceptedNonDisclosureAgreement\n ndaFileName\n ndaFileUrl\n organization {\n name\n description\n websiteUrl\n logoUrl\n email\n headquarterAddress\n id\n }\n ...OverviewPageFragment\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n report {\n id\n filename\n isUserAuthorized\n hasUserRequestedAccess\n }\n framework {\n id\n name\n lightLogoURL\n darkLogoURL\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment OverviewPageFragment on TrustCenter {\n references(first: 14) {\n edges {\n node {\n id\n name\n logoUrl\n websiteUrl\n }\n }\n }\n vendors(first: 3) {\n edges {\n node {\n id\n countries\n ...VendorRowFragment\n }\n }\n }\n documents(first: 5) {\n edges {\n node {\n id\n ...DocumentRowFragment\n documentType\n }\n }\n }\n trustCenterFiles(first: 5) {\n edges {\n node {\n id\n category\n ...TrustCenterFileRowFragment\n }\n }\n }\n}\n\nfragment TrustCenterFileRowFragment on TrustCenterFile {\n id\n name\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n"
}
};
})();
(node as any).hash = "03abd3f1a77fe3d8799cdf69d0b30fad";
export default node;

View File

@@ -1,244 +0,0 @@
/**
* @generated SignedSource<<72173b053a11fc1da7712cc7167c8d31>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type CountryCode = "AD" | "AE" | "AF" | "AG" | "AI" | "AL" | "AM" | "AO" | "AQ" | "AR" | "AS" | "AT" | "AU" | "AW" | "AX" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BL" | "BM" | "BN" | "BO" | "BQ" | "BR" | "BS" | "BT" | "BV" | "BW" | "BY" | "BZ" | "CA" | "CC" | "CD" | "CF" | "CG" | "CH" | "CI" | "CK" | "CL" | "CM" | "CN" | "CO" | "CR" | "CU" | "CV" | "CW" | "CX" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "EH" | "ER" | "ES" | "ET" | "EU" | "FI" | "FJ" | "FK" | "FM" | "FO" | "FR" | "GA" | "GB" | "GD" | "GE" | "GF" | "GG" | "GH" | "GI" | "GL" | "GM" | "GN" | "GP" | "GQ" | "GR" | "GT" | "GU" | "GW" | "GY" | "HK" | "HM" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IM" | "IN" | "IO" | "IQ" | "IR" | "IS" | "IT" | "JE" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KP" | "KR" | "KW" | "KY" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MF" | "MG" | "MH" | "MK" | "ML" | "MM" | "MN" | "MO" | "MP" | "MQ" | "MR" | "MS" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NC" | "NE" | "NF" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NU" | "NZ" | "OM" | "PA" | "PE" | "PF" | "PG" | "PH" | "PK" | "PL" | "PM" | "PN" | "PR" | "PS" | "PT" | "PW" | "PY" | "QA" | "RE" | "RO" | "RS" | "RU" | "RW" | "SA" | "SB" | "SC" | "SD" | "SE" | "SG" | "SH" | "SI" | "SJ" | "SK" | "SL" | "SM" | "SN" | "SO" | "SR" | "SS" | "ST" | "SV" | "SX" | "SY" | "SZ" | "TC" | "TD" | "TF" | "TG" | "TH" | "TJ" | "TK" | "TL" | "TM" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "UM" | "US" | "UY" | "UZ" | "VA" | "VC" | "VE" | "VG" | "VI" | "VN" | "VU" | "WF" | "WS" | "YE" | "YT" | "ZA" | "ZM" | "ZW";
export type TrustGraphVendorsQuery$variables = Record<PropertyKey, never>;
export type TrustGraphVendorsQuery$data = {
readonly currentTrustCenter: {
readonly id: string;
readonly organization: {
readonly name: string;
};
readonly vendors: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly countries: ReadonlyArray<CountryCode>;
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"VendorRowFragment">;
};
}>;
};
} | null | undefined;
};
export type TrustGraphVendorsQuery = {
response: TrustGraphVendorsQuery$data;
variables: TrustGraphVendorsQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v2 = [
{
"kind": "Literal",
"name": "first",
"value": 50
}
],
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "countries",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "TrustGraphVendorsQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenter",
"kind": "LinkedField",
"name": "currentTrustCenter",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Organization",
"kind": "LinkedField",
"name": "organization",
"plural": false,
"selections": [
(v1/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "VendorConnection",
"kind": "LinkedField",
"name": "vendors",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "VendorEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Vendor",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
(v3/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "VendorRowFragment"
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "vendors(first:50)"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [],
"kind": "Operation",
"name": "TrustGraphVendorsQuery",
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenter",
"kind": "LinkedField",
"name": "currentTrustCenter",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Organization",
"kind": "LinkedField",
"name": "organization",
"plural": false,
"selections": [
(v1/*: any*/),
(v0/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "VendorConnection",
"kind": "LinkedField",
"name": "vendors",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "VendorEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Vendor",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
(v3/*: any*/),
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "websiteUrl",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "privacyPolicyUrl",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "vendors(first:50)"
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "ab7e606f23e33445efbccc09a91e4c95",
"id": null,
"metadata": {},
"name": "TrustGraphVendorsQuery",
"operationKind": "query",
"text": "query TrustGraphVendorsQuery {\n currentTrustCenter {\n id\n organization {\n name\n id\n }\n vendors(first: 50) {\n edges {\n node {\n id\n countries\n ...VendorRowFragment\n }\n }\n }\n }\n}\n\nfragment VendorRowFragment on Vendor {\n id\n name\n category\n websiteUrl\n privacyPolicyUrl\n countries\n}\n"
}
};
})();
(node as any).hash = "c38f80f339187ccce1c0dec76e9a9bd2";
export default node;

View File

@@ -4,7 +4,7 @@ import EmailLayout, { bodyText, button, buttonContainer, footerText } from './co
export const DocumentSigning = () => {
return (
<EmailLayout subject={'Action Required – Please review and sign {{.OrganizationName}} compliance documents'} organizationName={'{{.OrganizationName}}'}>
<EmailLayout subject={'Action Required – Please review and sign {{.OrganizationName}} compliance documents'}>
<Text style={bodyText}>
You're receiving this message because your company, <strong>{'{{.OrganizationName}}'}</strong>, has shared a new compliance document that requires your review and signature.
</Text>

View File

@@ -4,7 +4,7 @@ import EmailLayout, { bodyText, button, buttonContainer, footerText } from './co
export const Invitation = () => {
return (
<EmailLayout subject={'Invitation to join {{.OrganizationName}} on Probo'} organizationName={'{{.OrganizationName}}'}>
<EmailLayout subject={'Invitation to join {{.OrganizationName}} on Probo'}>
<Text style={bodyText}>
You have been invited to join organization <strong>{'{{.OrganizationName}}'}</strong> on Probo. Click the button below to accept the invitation:
</Text>

View File

@@ -23,10 +23,6 @@ export const TrustCenterAccess = () => {
Access Trust Center
</Button>
</Section>
<Text style={footerText}>
This link will expire in {"{{.DurationInDays}}"} days.
</Text>
</EmailLayout>
);
};

View File

@@ -6,6 +6,4 @@ You have been granted access to {{.OrganizationName}}'s Trust Center! Click the
{{.AccessUrl}}
This link will expire in {{.DurationInDays}} days.
Probo Inc, 490 Post St, STE 640, San Francisco, CA, 94102, US

View File

@@ -308,6 +308,10 @@ LIMIT 1
customDomain, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[CustomDomain])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrResourceNotFound
}
return fmt.Errorf("cannot collect custom domain: %w", err)
}

View File

@@ -102,6 +102,10 @@ LIMIT 1;
trustCenter, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[TrustCenter])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrResourceNotFound
}
return fmt.Errorf("cannot collect trust center: %w", err)
}
@@ -146,6 +150,10 @@ LIMIT 1;
trustCenter, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[TrustCenter])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrResourceNotFound
}
return fmt.Errorf("cannot collect trust center: %w", err)
}
@@ -186,6 +194,10 @@ LIMIT 1;
trustCenter, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[TrustCenter])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrResourceNotFound
}
return fmt.Errorf("cannot collect trust center: %w", err)
}

View File

@@ -290,6 +290,7 @@ func (t *TrustCenterFiles) LoadByOrganizationID(
scope Scoper,
organizationID gid.GID,
cursor *page.Cursor[TrustCenterFileOrderField],
filter *TrustCenterFileFilter,
) error {
q := `
SELECT
@@ -307,12 +308,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)

View File

@@ -24,9 +24,9 @@ type (
}
)
type TrustCenterFileOption func(f *TrustCenterFileFilter)
type TrustCenterFileFilterOption func(f *TrustCenterFileFilter)
func NewTrustCenterFileFilter(opts ...TrustCenterFileOption) *TrustCenterFileFilter {
func NewTrustCenterFileFilter(opts ...TrustCenterFileFilterOption) *TrustCenterFileFilter {
f := &TrustCenterFileFilter{}
for _, opt := range opts {
@@ -36,7 +36,7 @@ func NewTrustCenterFileFilter(opts ...TrustCenterFileOption) *TrustCenterFileFil
return f
}
func WithTrustCenterFileVisibilities(visibilities ...TrustCenterVisibility) TrustCenterFileOption {
func WithTrustCenterFileVisibilities(visibilities ...TrustCenterVisibility) TrustCenterFileFilterOption {
return func(f *TrustCenterFileFilter) {
f.trustCenterVisibilities = visibilities
}

View File

@@ -24,7 +24,7 @@ import (
type ErrInvalidToken struct{ message string }
func NewInvalidTokenError() error {
return &ErrInvalidToken{"invalid invitation token"}
return &ErrInvalidToken{"invalid token"}
}
func (e ErrInvalidToken) Error() string {

View File

@@ -28,7 +28,6 @@ import (
"go.probo.inc/probo/pkg/mail"
"go.probo.inc/probo/pkg/page"
"go.probo.inc/probo/pkg/slack"
"go.probo.inc/probo/pkg/statelesstoken"
"go.probo.inc/probo/pkg/validator"
)
@@ -402,28 +401,14 @@ func (s TrustCenterAccessService) Delete(
}
func (s TrustCenterAccessService) sendAccessEmail(ctx context.Context, tx pg.Conn, access *coredata.TrustCenterAccess) error {
accessToken, err := statelesstoken.NewToken(
s.svc.trustConfig.TokenSecret,
s.svc.trustConfig.TokenType,
s.svc.trustConfig.TokenDuration,
TrustCenterAccessData{
TrustCenterID: access.TrustCenterID,
Email: access.Email,
},
)
if err != nil {
return fmt.Errorf("cannot generate access token: %w", err)
}
trustCenter := &coredata.TrustCenter{}
err = trustCenter.LoadByID(ctx, tx, s.svc.scope, access.TrustCenterID)
if err != nil {
if err := trustCenter.LoadByID(ctx, tx, s.svc.scope, access.TrustCenterID); err != nil {
return fmt.Errorf("cannot load trust center: %w", err)
}
organization := &coredata.Organization{}
err = organization.LoadByID(ctx, tx, s.svc.scope, trustCenter.OrganizationID)
if err != nil {
if err := organization.LoadByID(ctx, tx, s.svc.scope, trustCenter.OrganizationID); err != nil {
return fmt.Errorf("cannot load organization: %w", err)
}
@@ -434,7 +419,7 @@ func (s TrustCenterAccessService) sendAccessEmail(ctx context.Context, tx pg.Con
hostname := baseURLParsed.Host
scheme := baseURLParsed.Scheme
path := "/trust/" + trustCenter.Slug + "/access"
path := "/trust/" + trustCenter.Slug
if organization.CustomDomainID != nil {
customDomain, err := s.svc.CustomDomains.GetOrganizationCustomDomain(ctx, organization.ID)
@@ -448,16 +433,13 @@ func (s TrustCenterAccessService) sendAccessEmail(ctx context.Context, tx pg.Con
hostname = customDomain.Domain
scheme = "https"
path = "/access"
path = ""
}
accessURL := url.URL{
Scheme: scheme,
Host: hostname,
Path: path,
RawQuery: url.Values{
"token": []string{accessToken},
}.Encode(),
}
now := time.Now()

View File

@@ -83,13 +83,14 @@ func (s TrustCenterFileService) ListForOrganizationID(
ctx context.Context,
organizationID gid.GID,
cursor *page.Cursor[coredata.TrustCenterFileOrderField],
filter *coredata.TrustCenterFileFilter,
) (*page.Page[*coredata.TrustCenterFile, coredata.TrustCenterFileOrderField], error) {
var files coredata.TrustCenterFiles
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
if err := files.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor); err != nil {
if err := files.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor, filter); err != nil {
return fmt.Errorf("cannot load trust center files: %w", err)
}

View File

@@ -23,10 +23,16 @@ import (
type ctxKey struct{ name string }
var (
compliancePageKey = &ctxKey{name: "compliance_page"}
compliancePageKey = &ctxKey{name: "compliance_page"}
complianceMembershipKey = &ctxKey{name: "compliance_membership"}
)
func CompliancePageFromContext(ctx context.Context) *coredata.TrustCenter {
trustCenter, _ := ctx.Value(compliancePageKey).(*coredata.TrustCenter)
return trustCenter
}
func ComplianceMembershipFromContext(ctx context.Context) *coredata.TrustCenterAccess {
membership, _ := ctx.Value(complianceMembershipKey).(*coredata.TrustCenterAccess)
return membership
}

View File

@@ -16,10 +16,15 @@ package compliancepage
import (
"context"
"errors"
"net/http"
"github.com/99designs/gqlgen/graphql"
"github.com/go-chi/chi/v5"
"github.com/vektah/gqlparser/v2/gqlerror"
"go.gearno.de/kit/httpserver"
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/server/gqlutils"
"go.probo.inc/probo/pkg/trust"
)
@@ -33,7 +38,25 @@ func NewIDMiddleware(trustSvc *trust.Service) func(next http.Handler) http.Handl
if id, err := gid.ParseGID(value); err == nil {
compliancePage, err := trustSvc.Get(ctx, id)
if err != nil || !compliancePage.Active {
if err != nil {
if errors.Is(err, trust.ErrPageNotFound) {
next.ServeHTTP(w, r)
return
}
httpserver.RenderJSON(
w,
http.StatusInternalServerError,
&graphql.Response{
Errors: gqlerror.List{
gqlutils.Internal(ctx),
},
},
)
return
}
if !compliancePage.Active {
next.ServeHTTP(w, r)
return
}
@@ -43,7 +66,26 @@ func NewIDMiddleware(trustSvc *trust.Service) func(next http.Handler) http.Handl
return
}
if compliancePage, err := trustSvc.GetBySlug(ctx, value); err == nil && compliancePage.Active {
compliancePage, err := trustSvc.GetBySlug(ctx, value)
if err != nil {
if errors.Is(err, trust.ErrPageNotFound) {
next.ServeHTTP(w, r)
return
}
httpserver.RenderJSON(
w,
http.StatusInternalServerError,
&graphql.Response{
Errors: gqlerror.List{
gqlutils.Internal(ctx),
},
},
)
return
}
if compliancePage.Active {
ctx = context.WithValue(ctx, compliancePageKey, compliancePage)
next.ServeHTTP(w, r.WithContext(ctx))
return

View File

@@ -0,0 +1,74 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package compliancepage
import (
"context"
"errors"
"net/http"
"github.com/99designs/gqlgen/graphql"
"github.com/vektah/gqlparser/v2/gqlerror"
"go.gearno.de/kit/httpserver"
"go.gearno.de/kit/log"
"go.probo.inc/probo/pkg/server/api/authn"
"go.probo.inc/probo/pkg/server/gqlutils"
"go.probo.inc/probo/pkg/trust"
)
func NewMembershipMiddleware(trustSvc *trust.Service, logger *log.Logger) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
identity := authn.IdentityFromContext(r.Context())
if identity == nil {
next.ServeHTTP(w, r)
return
}
compliancePage := CompliancePageFromContext(ctx)
membership, err := trustSvc.GetMembershipByCompliancePageIDAndEmail(ctx, compliancePage.ID, identity.EmailAddress)
if err != nil {
if errors.Is(err, trust.ErrMembershipNotFound) {
next.ServeHTTP(w, r)
return
}
logger.ErrorCtx(ctx, "cannot get membership by page id and email", log.Error(err))
httpserver.RenderJSON(
w,
http.StatusInternalServerError,
&graphql.Response{
Errors: gqlerror.List{
gqlutils.Internal(ctx),
},
},
)
return
}
if membership.Active {
ctx = context.WithValue(ctx, complianceMembershipKey, membership)
next.ServeHTTP(w, r.WithContext(ctx))
return
}
next.ServeHTTP(w, r)
},
)
}
}

View File

@@ -16,8 +16,13 @@ package compliancepage
import (
"context"
"errors"
"net/http"
"github.com/99designs/gqlgen/graphql"
"github.com/vektah/gqlparser/v2/gqlerror"
"go.gearno.de/kit/httpserver"
"go.probo.inc/probo/pkg/server/gqlutils"
"go.probo.inc/probo/pkg/trust"
)
@@ -32,13 +37,31 @@ func NewSNIMiddleware(trustSvc *trust.Service) func(next http.Handler) http.Hand
}
compliancePage, err := trustSvc.GetByDomainName(ctx, r.TLS.ServerName)
if err != nil || !compliancePage.Active {
next.ServeHTTP(w, r)
if err != nil {
if errors.Is(err, trust.ErrPageNotFound) {
next.ServeHTTP(w, r)
return
}
httpserver.RenderJSON(
w,
http.StatusInternalServerError,
&graphql.Response{
Errors: gqlerror.List{
gqlutils.Internal(ctx),
},
},
)
return
}
ctx = context.WithValue(ctx, compliancePageKey, compliancePage)
next.ServeHTTP(w, r.WithContext(ctx))
if compliancePage.Active {
ctx = context.WithValue(ctx, compliancePageKey, compliancePage)
next.ServeHTTP(w, r.WithContext(ctx))
return
}
next.ServeHTTP(w, r)
})
}
}

View File

@@ -6169,7 +6169,7 @@ func (r *organizationResolver) TrustCenterFiles(ctx context.Context, obj *types.
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
pageResult, err := prb.TrustCenterFiles.ListForOrganizationID(ctx, obj.ID, cursor)
pageResult, err := prb.TrustCenterFiles.ListForOrganizationID(ctx, obj.ID, cursor, &coredata.TrustCenterFileFilter{})
if err != nil {
// TODO no panic use gqlutils.InternalError
panic(fmt.Errorf("cannot list organization trust center files: %w", err))

View File

@@ -0,0 +1,63 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package trust_v1
import (
"context"
"net/http"
"github.com/99designs/gqlgen/graphql"
"go.gearno.de/kit/log"
"go.probo.inc/probo/pkg/baseurl"
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/securecookie"
"go.probo.inc/probo/pkg/server/api/authn"
"go.probo.inc/probo/pkg/server/api/compliancepage"
"go.probo.inc/probo/pkg/server/api/trust/v1/schema"
"go.probo.inc/probo/pkg/server/gqlutils"
"go.probo.inc/probo/pkg/server/gqlutils/directives/session"
"go.probo.inc/probo/pkg/trust"
)
func MembersOnlyDirective(ctx context.Context, obj any, next graphql.Resolver) (any, error) {
membership := compliancepage.ComplianceMembershipFromContext(ctx)
if membership == nil {
return nil, gqlutils.Forbiddenf(ctx, "insufficient permission to access this resource")
}
return next(ctx)
}
func NewGraphQLHandler(iamSvc *iam.Service, trustSvc *trust.Service, logger *log.Logger, baseURL *baseurl.BaseURL, cookieConfig securecookie.Config) http.Handler {
config := schema.Config{
Resolvers: &Resolver{
iam: iamSvc,
trust: trustSvc,
logger: logger,
baseURL: baseURL,
sessionCookie: authn.NewCookie(&cookieConfig),
},
Directives: schema.DirectiveRoot{
Session: session.Directive,
MembersOnly: MembersOnlyDirective,
},
}
es := schema.NewExecutableSchema(config)
gqlh := gqlutils.NewHandler(es, logger)
return gqlh
}

View File

@@ -28,9 +28,6 @@ import (
"go.probo.inc/probo/pkg/securecookie"
"go.probo.inc/probo/pkg/server/api/authn"
"go.probo.inc/probo/pkg/server/api/compliancepage"
"go.probo.inc/probo/pkg/server/api/trust/v1/schema"
"go.probo.inc/probo/pkg/server/gqlutils"
"go.probo.inc/probo/pkg/server/gqlutils/directives/session"
"go.probo.inc/probo/pkg/trust"
)
@@ -85,21 +82,9 @@ func NewMux(
r.Use(compliancepage.NewCompliancePagePresenceMiddleware())
r.Use(authn.NewSessionMiddleware(iamSvc, cookieConfig))
r.Use(compliancepage.NewMembershipMiddleware(trustSvc, logger))
config := schema.Config{
Resolvers: &Resolver{
iam: iamSvc,
trust: trustSvc,
logger: logger,
sessionCookie: authn.NewCookie(&cookieConfig),
baseURL: baseURL,
},
Directives: schema.DirectiveRoot{
Session: session.Directive,
},
}
es := schema.NewExecutableSchema(config)
graphqlHandler := gqlutils.NewHandler(es, logger)
graphqlHandler := NewGraphQLHandler(iamSvc, trustSvc, logger, baseURL, cookieConfig)
r.Handle("/graphql", graphqlHandler)

View File

@@ -12,6 +12,8 @@ directive @goModel(
directive @goEnum(value: String) on ENUM_VALUE
directive @membersOnly on FIELD_DEFINITION
enum Role {
NONE
USER
@@ -495,7 +497,7 @@ type TrustCenter implements Node {
ndaFileName: String
ndaFileUrl: String @goField(forceResolver: true)
organization: Organization! @goField(forceResolver: true)
isUserAuthenticated: Boolean! @goField(forceResolver: true)
isViewerMember: Boolean! @goField(forceResolver: true)
hasAcceptedNonDisclosureAgreement: Boolean! @goField(forceResolver: true)
documents(
@@ -610,30 +612,37 @@ type Query {
type Mutation {
sendMagicLink(input: SendMagicLinkInput!): SendMagicLinkPayload
@session(required: OPTIONAL)
verifyMagicLink(input: VerifyMagicLinkInput!): VerifyMagicLinkPayload
@session(required: OPTIONAL)
requestAllAccesses: RequestAccessesPayload!
requestAllAccesses: RequestAccessesPayload! @session(required: PRESENT)
exportDocumentPDF(input: ExportDocumentPDFInput!): ExportDocumentPDFPayload!
@session(required: NONE)
@session(required: PRESENT)
@membersOnly
exportReportPDF(input: ExportReportPDFInput!): ExportReportPDFPayload!
@session(required: NONE)
@session(required: PRESENT)
@membersOnly
acceptNonDisclosureAgreement: AcceptNonDisclosureAgreementPayload!
@session(required: PRESENT)
@membersOnly
requestDocumentAccess(
input: RequestDocumentAccessInput!
): RequestAccessesPayload!
): RequestAccessesPayload! @session(required: PRESENT)
requestReportAccess(input: RequestReportAccessInput!): RequestAccessesPayload!
requestReportAccess(
input: RequestReportAccessInput!
): RequestAccessesPayload! @session(required: PRESENT)
requestTrustCenterFileAccess(
input: RequestTrustCenterFileAccessInput!
): RequestAccessesPayload!
): RequestAccessesPayload! @session(required: PRESENT)
exportTrustCenterFile(
input: ExportTrustCenterFileInput!
): ExportTrustCenterFilePayload!
): ExportTrustCenterFilePayload! @session(required: PRESENT) @membersOnly
}

View File

@@ -60,7 +60,8 @@ type ResolverRoot interface {
}
type DirectiveRoot struct {
Session func(ctx context.Context, obj any, next graphql.Resolver, required session.SessionRequirement) (res any, err error)
MembersOnly func(ctx context.Context, obj any, next graphql.Resolver) (res any, err error)
Session func(ctx context.Context, obj any, next graphql.Resolver, required session.SessionRequirement) (res any, err error)
}
type ComplexityRoot struct {
@@ -187,7 +188,7 @@ type ComplexityRoot struct {
Documents func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey) int
HasAcceptedNonDisclosureAgreement func(childComplexity int) int
ID func(childComplexity int) int
IsUserAuthenticated func(childComplexity int) int
IsViewerMember func(childComplexity int) int
NdaFileName func(childComplexity int) int
NdaFileURL func(childComplexity int) int
Organization func(childComplexity int) int
@@ -304,7 +305,7 @@ type ReportResolver interface {
type TrustCenterResolver interface {
NdaFileURL(ctx context.Context, obj *types.TrustCenter) (*string, error)
Organization(ctx context.Context, obj *types.TrustCenter) (*types.Organization, error)
IsUserAuthenticated(ctx context.Context, obj *types.TrustCenter) (bool, error)
IsViewerMember(ctx context.Context, obj *types.TrustCenter) (bool, error)
HasAcceptedNonDisclosureAgreement(ctx context.Context, obj *types.TrustCenter) (bool, error)
Documents(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.DocumentConnection, error)
Audits(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.AuditConnection, error)
@@ -803,12 +804,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
}
return e.complexity.TrustCenter.ID(childComplexity), true
case "TrustCenter.isUserAuthenticated":
if e.complexity.TrustCenter.IsUserAuthenticated == nil {
case "TrustCenter.isViewerMember":
if e.complexity.TrustCenter.IsViewerMember == nil {
break
}
return e.complexity.TrustCenter.IsUserAuthenticated(childComplexity), true
return e.complexity.TrustCenter.IsViewerMember(childComplexity), true
case "TrustCenter.ndaFileName":
if e.complexity.TrustCenter.NdaFileName == nil {
break
@@ -1209,6 +1210,8 @@ directive @goModel(
directive @goEnum(value: String) on ENUM_VALUE
directive @membersOnly on FIELD_DEFINITION
enum Role {
NONE
USER
@@ -1692,7 +1695,7 @@ type TrustCenter implements Node {
ndaFileName: String
ndaFileUrl: String @goField(forceResolver: true)
organization: Organization! @goField(forceResolver: true)
isUserAuthenticated: Boolean! @goField(forceResolver: true)
isViewerMember: Boolean! @goField(forceResolver: true)
hasAcceptedNonDisclosureAgreement: Boolean! @goField(forceResolver: true)
documents(
@@ -1807,32 +1810,39 @@ type Query {
type Mutation {
sendMagicLink(input: SendMagicLinkInput!): SendMagicLinkPayload
@session(required: OPTIONAL)
verifyMagicLink(input: VerifyMagicLinkInput!): VerifyMagicLinkPayload
@session(required: OPTIONAL)
requestAllAccesses: RequestAccessesPayload!
requestAllAccesses: RequestAccessesPayload! @session(required: PRESENT)
exportDocumentPDF(input: ExportDocumentPDFInput!): ExportDocumentPDFPayload!
@session(required: NONE)
@session(required: PRESENT)
@membersOnly
exportReportPDF(input: ExportReportPDFInput!): ExportReportPDFPayload!
@session(required: NONE)
@session(required: PRESENT)
@membersOnly
acceptNonDisclosureAgreement: AcceptNonDisclosureAgreementPayload!
@session(required: PRESENT)
@membersOnly
requestDocumentAccess(
input: RequestDocumentAccessInput!
): RequestAccessesPayload!
): RequestAccessesPayload! @session(required: PRESENT)
requestReportAccess(input: RequestReportAccessInput!): RequestAccessesPayload!
requestReportAccess(
input: RequestReportAccessInput!
): RequestAccessesPayload! @session(required: PRESENT)
requestTrustCenterFileAccess(
input: RequestTrustCenterFileAccessInput!
): RequestAccessesPayload!
): RequestAccessesPayload! @session(required: PRESENT)
exportTrustCenterFile(
input: ExportTrustCenterFileInput!
): ExportTrustCenterFilePayload!
): ExportTrustCenterFilePayload! @session(required: PRESENT) @membersOnly
}
`, BuiltIn: false},
{Name: "../../../../gqlutils/directives/session/schema.graphql", Input: `# Session directive for GraphQL APIs
@@ -3136,7 +3146,25 @@ func (ec *executionContext) _Mutation_sendMagicLink(ctx context.Context, field g
fc := graphql.GetFieldContext(ctx)
return ec.resolvers.Mutation().SendMagicLink(ctx, fc.Args["input"].(types.SendMagicLinkInput))
},
nil,
func(ctx context.Context, next graphql.Resolver) graphql.Resolver {
directive0 := next
directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "OPTIONAL")
if err != nil {
var zeroVal *types.SendMagicLinkPayload
return zeroVal, err
}
if ec.directives.Session == nil {
var zeroVal *types.SendMagicLinkPayload
return zeroVal, errors.New("directive session is not implemented")
}
return ec.directives.Session(ctx, nil, directive0, required)
}
next = directive1
return next
},
ec.marshalOSendMagicLinkPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐSendMagicLinkPayload,
true,
false,
@@ -3181,7 +3209,25 @@ func (ec *executionContext) _Mutation_verifyMagicLink(ctx context.Context, field
fc := graphql.GetFieldContext(ctx)
return ec.resolvers.Mutation().VerifyMagicLink(ctx, fc.Args["input"].(types.VerifyMagicLinkInput))
},
nil,
func(ctx context.Context, next graphql.Resolver) graphql.Resolver {
directive0 := next
directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "OPTIONAL")
if err != nil {
var zeroVal *types.VerifyMagicLinkPayload
return zeroVal, err
}
if ec.directives.Session == nil {
var zeroVal *types.VerifyMagicLinkPayload
return zeroVal, errors.New("directive session is not implemented")
}
return ec.directives.Session(ctx, nil, directive0, required)
}
next = directive1
return next
},
ec.marshalOVerifyMagicLinkPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐVerifyMagicLinkPayload,
true,
false,
@@ -3225,7 +3271,25 @@ func (ec *executionContext) _Mutation_requestAllAccesses(ctx context.Context, fi
func(ctx context.Context) (any, error) {
return ec.resolvers.Mutation().RequestAllAccesses(ctx)
},
nil,
func(ctx context.Context, next graphql.Resolver) graphql.Resolver {
directive0 := next
directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "PRESENT")
if err != nil {
var zeroVal *types.RequestAccessesPayload
return zeroVal, err
}
if ec.directives.Session == nil {
var zeroVal *types.RequestAccessesPayload
return zeroVal, errors.New("directive session is not implemented")
}
return ec.directives.Session(ctx, nil, directive0, required)
}
next = directive1
return next
},
ec.marshalNRequestAccessesPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐRequestAccessesPayload,
true,
true,
@@ -3263,7 +3327,7 @@ func (ec *executionContext) _Mutation_exportDocumentPDF(ctx context.Context, fie
directive0 := next
directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "NONE")
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "PRESENT")
if err != nil {
var zeroVal *types.ExportDocumentPDFPayload
return zeroVal, err
@@ -3274,8 +3338,15 @@ func (ec *executionContext) _Mutation_exportDocumentPDF(ctx context.Context, fie
}
return ec.directives.Session(ctx, nil, directive0, required)
}
directive2 := func(ctx context.Context) (any, error) {
if ec.directives.MembersOnly == nil {
var zeroVal *types.ExportDocumentPDFPayload
return zeroVal, errors.New("directive membersOnly is not implemented")
}
return ec.directives.MembersOnly(ctx, nil, directive1)
}
next = directive1
next = directive2
return next
},
ec.marshalNExportDocumentPDFPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐExportDocumentPDFPayload,
@@ -3326,7 +3397,7 @@ func (ec *executionContext) _Mutation_exportReportPDF(ctx context.Context, field
directive0 := next
directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "NONE")
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "PRESENT")
if err != nil {
var zeroVal *types.ExportReportPDFPayload
return zeroVal, err
@@ -3337,8 +3408,15 @@ func (ec *executionContext) _Mutation_exportReportPDF(ctx context.Context, field
}
return ec.directives.Session(ctx, nil, directive0, required)
}
directive2 := func(ctx context.Context) (any, error) {
if ec.directives.MembersOnly == nil {
var zeroVal *types.ExportReportPDFPayload
return zeroVal, errors.New("directive membersOnly is not implemented")
}
return ec.directives.MembersOnly(ctx, nil, directive1)
}
next = directive1
next = directive2
return next
},
ec.marshalNExportReportPDFPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐExportReportPDFPayload,
@@ -3399,8 +3477,15 @@ func (ec *executionContext) _Mutation_acceptNonDisclosureAgreement(ctx context.C
}
return ec.directives.Session(ctx, nil, directive0, required)
}
directive2 := func(ctx context.Context) (any, error) {
if ec.directives.MembersOnly == nil {
var zeroVal *types.AcceptNonDisclosureAgreementPayload
return zeroVal, errors.New("directive membersOnly is not implemented")
}
return ec.directives.MembersOnly(ctx, nil, directive1)
}
next = directive1
next = directive2
return next
},
ec.marshalNAcceptNonDisclosureAgreementPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐAcceptNonDisclosureAgreementPayload,
@@ -3436,7 +3521,25 @@ func (ec *executionContext) _Mutation_requestDocumentAccess(ctx context.Context,
fc := graphql.GetFieldContext(ctx)
return ec.resolvers.Mutation().RequestDocumentAccess(ctx, fc.Args["input"].(types.RequestDocumentAccessInput))
},
nil,
func(ctx context.Context, next graphql.Resolver) graphql.Resolver {
directive0 := next
directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "PRESENT")
if err != nil {
var zeroVal *types.RequestAccessesPayload
return zeroVal, err
}
if ec.directives.Session == nil {
var zeroVal *types.RequestAccessesPayload
return zeroVal, errors.New("directive session is not implemented")
}
return ec.directives.Session(ctx, nil, directive0, required)
}
next = directive1
return next
},
ec.marshalNRequestAccessesPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐRequestAccessesPayload,
true,
true,
@@ -3481,7 +3584,25 @@ func (ec *executionContext) _Mutation_requestReportAccess(ctx context.Context, f
fc := graphql.GetFieldContext(ctx)
return ec.resolvers.Mutation().RequestReportAccess(ctx, fc.Args["input"].(types.RequestReportAccessInput))
},
nil,
func(ctx context.Context, next graphql.Resolver) graphql.Resolver {
directive0 := next
directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "PRESENT")
if err != nil {
var zeroVal *types.RequestAccessesPayload
return zeroVal, err
}
if ec.directives.Session == nil {
var zeroVal *types.RequestAccessesPayload
return zeroVal, errors.New("directive session is not implemented")
}
return ec.directives.Session(ctx, nil, directive0, required)
}
next = directive1
return next
},
ec.marshalNRequestAccessesPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐRequestAccessesPayload,
true,
true,
@@ -3526,7 +3647,25 @@ func (ec *executionContext) _Mutation_requestTrustCenterFileAccess(ctx context.C
fc := graphql.GetFieldContext(ctx)
return ec.resolvers.Mutation().RequestTrustCenterFileAccess(ctx, fc.Args["input"].(types.RequestTrustCenterFileAccessInput))
},
nil,
func(ctx context.Context, next graphql.Resolver) graphql.Resolver {
directive0 := next
directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "PRESENT")
if err != nil {
var zeroVal *types.RequestAccessesPayload
return zeroVal, err
}
if ec.directives.Session == nil {
var zeroVal *types.RequestAccessesPayload
return zeroVal, errors.New("directive session is not implemented")
}
return ec.directives.Session(ctx, nil, directive0, required)
}
next = directive1
return next
},
ec.marshalNRequestAccessesPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐRequestAccessesPayload,
true,
true,
@@ -3571,7 +3710,32 @@ func (ec *executionContext) _Mutation_exportTrustCenterFile(ctx context.Context,
fc := graphql.GetFieldContext(ctx)
return ec.resolvers.Mutation().ExportTrustCenterFile(ctx, fc.Args["input"].(types.ExportTrustCenterFileInput))
},
nil,
func(ctx context.Context, next graphql.Resolver) graphql.Resolver {
directive0 := next
directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "PRESENT")
if err != nil {
var zeroVal *types.ExportTrustCenterFilePayload
return zeroVal, err
}
if ec.directives.Session == nil {
var zeroVal *types.ExportTrustCenterFilePayload
return zeroVal, errors.New("directive session is not implemented")
}
return ec.directives.Session(ctx, nil, directive0, required)
}
directive2 := func(ctx context.Context) (any, error) {
if ec.directives.MembersOnly == nil {
var zeroVal *types.ExportTrustCenterFilePayload
return zeroVal, errors.New("directive membersOnly is not implemented")
}
return ec.directives.MembersOnly(ctx, nil, directive1)
}
next = directive2
return next
},
ec.marshalNExportTrustCenterFilePayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐExportTrustCenterFilePayload,
true,
true,
@@ -4045,8 +4209,8 @@ func (ec *executionContext) fieldContext_Query_currentTrustCenter(_ context.Cont
return ec.fieldContext_TrustCenter_ndaFileUrl(ctx, field)
case "organization":
return ec.fieldContext_TrustCenter_organization(ctx, field)
case "isUserAuthenticated":
return ec.fieldContext_TrustCenter_isUserAuthenticated(ctx, field)
case "isViewerMember":
return ec.fieldContext_TrustCenter_isViewerMember(ctx, field)
case "hasAcceptedNonDisclosureAgreement":
return ec.fieldContext_TrustCenter_hasAcceptedNonDisclosureAgreement(ctx, field)
case "documents":
@@ -4550,14 +4714,14 @@ func (ec *executionContext) fieldContext_TrustCenter_organization(_ context.Cont
return fc, nil
}
func (ec *executionContext) _TrustCenter_isUserAuthenticated(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenter) (ret graphql.Marshaler) {
func (ec *executionContext) _TrustCenter_isViewerMember(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenter) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_TrustCenter_isUserAuthenticated,
ec.fieldContext_TrustCenter_isViewerMember,
func(ctx context.Context) (any, error) {
return ec.resolvers.TrustCenter().IsUserAuthenticated(ctx, obj)
return ec.resolvers.TrustCenter().IsViewerMember(ctx, obj)
},
nil,
ec.marshalNBoolean2bool,
@@ -4566,7 +4730,7 @@ func (ec *executionContext) _TrustCenter_isUserAuthenticated(ctx context.Context
)
}
func (ec *executionContext) fieldContext_TrustCenter_isUserAuthenticated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
func (ec *executionContext) fieldContext_TrustCenter_isViewerMember(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenter",
Field: field,
@@ -9046,7 +9210,7 @@ func (ec *executionContext) _TrustCenter(ctx context.Context, sel ast.SelectionS
}
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
case "isUserAuthenticated":
case "isViewerMember":
field := field
innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
@@ -9055,7 +9219,7 @@ func (ec *executionContext) _TrustCenter(ctx context.Context, sel ast.SelectionS
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._TrustCenter_isUserAuthenticated(ctx, field, obj)
res = ec._TrustCenter_isViewerMember(ctx, field, obj)
if res == graphql.Null {
atomic.AddUint32(&fs.Invalids, 1)
}

View File

@@ -177,7 +177,7 @@ type TrustCenter struct {
NdaFileName *string `json:"ndaFileName,omitempty"`
NdaFileURL *string `json:"ndaFileUrl,omitempty"`
Organization *Organization `json:"organization"`
IsUserAuthenticated bool `json:"isUserAuthenticated"`
IsViewerMember bool `json:"isViewerMember"`
HasAcceptedNonDisclosureAgreement bool `json:"hasAcceptedNonDisclosureAgreement"`
Documents *DocumentConnection `json:"documents"`
Audits *AuditConnection `json:"audits"`

View File

@@ -166,11 +166,12 @@ func (r *mutationResolver) SendMagicLink(ctx context.Context, input types.SendMa
customDomain, err := r.trust.GetCustomDomainByOrganizationID(ctx, organization.ID)
if err != nil {
var errNotFound *iam.ErrOrganizationNotFound
if !errors.As(err, &errNotFound) {
r.logger.ErrorCtx(ctx, "cannot get custom domain", log.Error(err))
return nil, gqlutils.Internal(ctx)
if errors.Is(err, trust.ErrCustomDomainNotFound) {
return nil, gqlutils.NotFoundf(ctx, "custom domain not found")
}
r.logger.ErrorCtx(ctx, "cannot get custom domain", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
req := &iam.SendMagicLinkRequest{
@@ -874,11 +875,11 @@ func (r *trustCenterResolver) Organization(ctx context.Context, obj *types.Trust
return obj.Organization, nil
}
// IsUserAuthenticated is the resolver for the isUserAuthenticated field.
func (r *trustCenterResolver) IsUserAuthenticated(ctx context.Context, obj *types.TrustCenter) (bool, error) {
identity := authn.IdentityFromContext(ctx)
// IsViewerMember is the resolver for the isViewerMember field.
func (r *trustCenterResolver) IsViewerMember(ctx context.Context, obj *types.TrustCenter) (bool, error) {
membership := compliancepage.ComplianceMembershipFromContext(ctx)
return identity != nil, nil
return membership != nil, nil
}
// HasAcceptedNonDisclosureAgreement is the resolver for the hasAcceptedNonDisclosureAgreement field.
@@ -985,7 +986,13 @@ func (r *trustCenterResolver) TrustCenterFiles(ctx context.Context, obj *types.T
}
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
trustCenterFilePage, err := trustService.TrustCenterFiles.ListForOrganizationId(ctx, obj.Organization.ID, cursor)
filter := coredata.NewTrustCenterFileFilter(
coredata.WithTrustCenterFileVisibilities(
coredata.TrustCenterVisibilityPublic,
coredata.TrustCenterVisibilityPrivate,
),
)
trustCenterFilePage, err := trustService.TrustCenterFiles.ListForOrganizationId(ctx, obj.Organization.ID, cursor, filter)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot list public trust center files", log.Error(err))
return nil, gqlutils.Internal(ctx)

23
pkg/trust/errors.go Normal file
View File

@@ -0,0 +1,23 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package trust
import "errors"
var (
ErrCustomDomainNotFound = errors.New("custom domain not found")
ErrPageNotFound = errors.New("page not found")
ErrMembershipNotFound = errors.New("membership not found")
)

View File

@@ -16,6 +16,7 @@ package trust
import (
"context"
"errors"
"fmt"
"time"
@@ -28,6 +29,7 @@ import (
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/html2pdf"
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/mail"
"go.probo.inc/probo/pkg/probo"
"go.probo.inc/probo/pkg/slack"
)
@@ -159,6 +161,9 @@ func (s *Service) Get(
func(conn pg.Conn) error {
err := trustCenter.LoadByID(ctx, conn, coredata.NewNoScope(), id)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return ErrPageNotFound
}
return fmt.Errorf("cannot load trust center: %w", err)
}
@@ -184,6 +189,9 @@ func (s *Service) GetBySlug(
func(conn pg.Conn) error {
err := trustCenter.LoadBySlug(ctx, conn, slug)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return ErrPageNotFound
}
return fmt.Errorf("cannot load trust center: %w", err)
}
@@ -206,16 +214,28 @@ func (s *Service) GetByDomainName(ctx context.Context, domain string) (*coredata
func(conn pg.Conn) error {
var customDomain coredata.CustomDomain
if err := customDomain.LoadByDomain(ctx, conn, coredata.NewNoScope(), s.encryptionKey, domain); err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return ErrPageNotFound
}
return fmt.Errorf("cannot load custom domain: %w", err)
}
var org coredata.Organization
if err := org.LoadByCustomDomainID(ctx, conn, coredata.NewNoScope(), customDomain.ID); err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return ErrPageNotFound
}
return fmt.Errorf("cannot load organization: %w", err)
}
trustCenter = &coredata.TrustCenter{}
if err := trustCenter.LoadByOrganizationID(ctx, conn, coredata.NewNoScope(), org.ID); err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return ErrPageNotFound
}
return fmt.Errorf("cannot load trust center: %w", err)
}
@@ -239,6 +259,39 @@ func (s *Service) GetCustomDomainByOrganizationID(ctx context.Context, organizat
return customDomain.LoadByOrganizationID(ctx, conn, coredata.NewNoScope(), s.encryptionKey, organizationID)
},
)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, ErrCustomDomainNotFound
}
return nil, err
}
return customDomain, err
}
func (s *Service) GetMembershipByCompliancePageIDAndEmail(ctx context.Context, compliancePageID gid.GID, email mail.Addr) (*coredata.TrustCenterAccess, error) {
membership := &coredata.TrustCenterAccess{}
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return membership.LoadByTrustCenterIDAndEmail(
ctx,
conn,
coredata.NewScopeFromObjectID(compliancePageID),
compliancePageID,
email,
)
},
)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, ErrMembershipNotFound
}
return nil, err
}
return membership, nil
}

View File

@@ -29,8 +29,6 @@ import (
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/mail"
"go.probo.inc/probo/pkg/probo"
"go.probo.inc/probo/pkg/statelesstoken"
"go.probo.inc/probo/pkg/validator"
)
@@ -445,28 +443,14 @@ func (s *TrustCenterAccessService) GrantByIDs(
}
func (s *TrustCenterAccessService) sendAccessEmail(ctx context.Context, tx pg.Conn, access *coredata.TrustCenterAccess) error {
accessToken, err := statelesstoken.NewToken(
s.svc.trustConfig.TokenSecret,
s.svc.trustConfig.TokenType,
s.svc.trustConfig.TokenDuration,
probo.TrustCenterAccessData{
TrustCenterID: access.TrustCenterID,
Email: access.Email,
},
)
if err != nil {
return fmt.Errorf("cannot generate access token: %w", err)
}
trustCenter := &coredata.TrustCenter{}
err = trustCenter.LoadByID(ctx, tx, s.svc.scope, access.TrustCenterID)
if err != nil {
if err := trustCenter.LoadByID(ctx, tx, s.svc.scope, access.TrustCenterID); err != nil {
return fmt.Errorf("cannot load trust center: %w", err)
}
organization := &coredata.Organization{}
err = organization.LoadByID(ctx, tx, s.svc.scope, trustCenter.OrganizationID)
if err != nil {
if err := organization.LoadByID(ctx, tx, s.svc.scope, trustCenter.OrganizationID); err != nil {
return fmt.Errorf("cannot load organization: %w", err)
}
@@ -477,7 +461,7 @@ func (s *TrustCenterAccessService) sendAccessEmail(ctx context.Context, tx pg.Co
hostname := baseURLParsed.Host
scheme := baseURLParsed.Scheme
path := "/trust/" + trustCenter.Slug + "/access"
path := "/trust/" + trustCenter.Slug
if organization.CustomDomainID != nil {
customDomain, err := s.svc.Organizations.GetOrganizationCustomDomain(ctx, organization.ID)
@@ -491,16 +475,13 @@ func (s *TrustCenterAccessService) sendAccessEmail(ctx context.Context, tx pg.Co
hostname = customDomain.Domain
scheme = "https"
path = "/access"
path = ""
}
accessURL := url.URL{
Scheme: scheme,
Host: hostname,
Path: path,
RawQuery: url.Values{
"token": []string{accessToken},
}.Encode(),
}
now := time.Now()

View File

@@ -62,13 +62,14 @@ func (s *TrustCenterFileService) ListForOrganizationId(
ctx context.Context,
organizationID gid.GID,
cursor *page.Cursor[coredata.TrustCenterFileOrderField],
filter *coredata.TrustCenterFileFilter,
) (*page.Page[*coredata.TrustCenterFile, coredata.TrustCenterFileOrderField], error) {
var trustCenterFiles coredata.TrustCenterFiles
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
err := trustCenterFiles.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor)
err := trustCenterFiles.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor, filter)
if err != nil {
return fmt.Errorf("cannot load trust center files: %w", err)
}