Add trust center access requests

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-08-20 11:29:18 +02:00
parent ccbd9e250c
commit 5db9b9f787
31 changed files with 1977 additions and 330 deletions

View File

@@ -8,10 +8,12 @@ import {
Th,
Button,
IconArrowDown,
IconLock,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { sprintf } from "@probo/helpers";
import { FrameworkLogo } from "/components/FrameworkLogo";
import { TrustCenterAccessRequestDialog } from "./TrustCenterAccessRequestDialog";
type Audit = {
id: string;
@@ -27,16 +29,21 @@ type Audit = {
filename: string;
downloadUrl: string | null;
} | null;
reportUrl: string | null;
};
type Props = {
audits: Audit[];
organizationName: string;
isAuthenticated: boolean;
trustCenterId: string;
};
export function PublicTrustCenterAudits({ audits, organizationName, isAuthenticated }: Props) {
export function PublicTrustCenterAudits({
audits,
organizationName,
isAuthenticated,
trustCenterId
}: Props) {
const { __ } = useTranslate();
if (audits.length === 0) {
@@ -74,8 +81,8 @@ export function PublicTrustCenterAudits({ audits, organizationName, isAuthentica
</Thead>
<Tbody>
{audits.map((audit) => {
const hasReport = audit.report || audit.reportUrl;
const downloadUrl = audit.report?.downloadUrl || audit.reportUrl;
const hasReport = audit.report !== null;
const downloadUrl = audit.report?.downloadUrl;
const reportName = audit.report?.filename || __("Compliance Report");
return (
@@ -98,9 +105,18 @@ export function PublicTrustCenterAudits({ audits, organizationName, isAuthentica
{__("No report")}
</span>
) : !isAuthenticated ? (
<span className="text-txt-tertiary text-sm">
{__("Not available")}
</span>
<TrustCenterAccessRequestDialog
trigger={
<Button
variant="secondary"
icon={IconLock}
>
{__("Request Access")}
</Button>
}
trustCenterId={trustCenterId}
organizationName={organizationName}
/>
) : downloadUrl ? (
<Button
variant="secondary"

View File

@@ -9,11 +9,13 @@ import {
DocumentTypeBadge,
Button,
IconArrowDown,
IconLock,
useToast,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { buildEndpoint } from "/providers/RelayProviders";
// Manual mutation for trust API (not processed by relay compiler)
import { TrustCenterAccessRequestDialog } from "./TrustCenterAccessRequestDialog";
const exportDocumentPDFMutation = {
params: {
name: "PublicTrustCenterDocumentsExportPDFMutation",
@@ -39,6 +41,8 @@ type Document = {
type Props = {
documents: Document[];
isAuthenticated: boolean;
trustCenterId: string;
organizationName: string;
};
type ExportDocumentPDFResponse = {
@@ -50,7 +54,12 @@ type ExportDocumentPDFResponse = {
errors?: Array<{ message: string }>;
};
export function PublicTrustCenterDocuments({ documents, isAuthenticated }: Props) {
export function PublicTrustCenterDocuments({
documents,
isAuthenticated,
trustCenterId,
organizationName
}: Props) {
const { __ } = useTranslate();
const { toast } = useToast();
@@ -141,9 +150,18 @@ export function PublicTrustCenterDocuments({ documents, isAuthenticated }: Props
</Td>
<Td>
{!isAuthenticated ? (
<span className="text-txt-tertiary text-sm">
{__("Not available")}
</span>
<TrustCenterAccessRequestDialog
trigger={
<Button
variant="secondary"
icon={IconLock}
>
{__("Request Access")}
</Button>
}
trustCenterId={trustCenterId}
organizationName={organizationName}
/>
) : (
<Button
variant="secondary"

View File

@@ -33,10 +33,10 @@ export function PublicTrustCenterVendors({ vendors, organizationName }: Props) {
<Card padded>
<div className="text-center py-8">
<h2 className="text-xl font-semibold text-txt-primary mb-2">
{__("Vendors")}
{__("Subcontractors")}
</h2>
<p className="text-txt-secondary">
{__("No vendor information is currently available.")}
{__("No subcontractor information is currently available.")}
</p>
</div>
</Card>

View File

@@ -0,0 +1,174 @@
import { useState } from "react";
import {
Dialog,
DialogFooter,
DialogContent,
Button,
Field,
useToast,
useDialogRef,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { sprintf } from "@probo/helpers";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { z } from "zod";
import { buildEndpoint } from "/providers/RelayProviders";
// Manual mutation for trust API (not processed by relay compiler)
const createTrustCenterAccessMutation = {
params: {
name: "CreateTrustCenterAccessMutation",
operationKind: "mutation",
text: `
mutation CreateTrustCenterAccessMutation(
$input: CreateTrustCenterAccessInput!
) {
createTrustCenterAccess(input: $input) {
trustCenterAccess {
id
email
name
}
}
}
`
}
};
type CreateTrustCenterAccessResponse = {
data?: {
createTrustCenterAccess?: {
trustCenterAccess: {
id: string;
email: string;
name: string;
};
};
};
errors?: Array<{ message: string }>;
};
type Props = {
trigger: React.ReactNode;
trustCenterId: string;
organizationName: string;
};
export function TrustCenterAccessRequestDialog({
trigger,
trustCenterId,
organizationName
}: Props) {
const { __ } = useTranslate();
const { toast } = useToast();
const [isSubmitting, setIsSubmitting] = useState(false);
const dialogRef = useDialogRef();
const schema = z.object({
name: z.string().min(1, __("Name is required")).min(2, __("Name must be at least 2 characters long")),
email: z.string().min(1, __("Email is required")).email(__("Please enter a valid email address")),
});
const { register, handleSubmit, formState, reset } = useFormWithSchema(schema, {
defaultValues: { name: "", email: "" },
});
const onSubmit = handleSubmit(async (data) => {
setIsSubmitting(true);
try {
const response = await fetch(buildEndpoint("/api/trust/v1/graphql"), {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
},
credentials: "include",
body: JSON.stringify({
operationName: createTrustCenterAccessMutation.params.name,
query: createTrustCenterAccessMutation.params.text,
variables: {
input: {
trustCenterId,
email: data.email,
name: data.name
}
},
}),
});
const result: CreateTrustCenterAccessResponse = await response.json();
if (result.errors) {
throw new Error(result.errors[0].message);
}
if (result.data?.createTrustCenterAccess) {
toast({
title: __("Request Submitted"),
description: __("Your access request has been submitted. You will receive an email if your request is approved."),
variant: "success",
});
reset();
dialogRef.current?.close();
}
} catch (error) {
const errorMessage = error instanceof Error
? error.message
: __("An error occurred while submitting your request.");
toast({
title: __("Request Failed"),
description: errorMessage,
variant: "error",
});
} finally {
setIsSubmitting(false);
}
});
return (
<Dialog
ref={dialogRef}
trigger={trigger}
title={__("Request Access")}
>
<form onSubmit={onSubmit}>
<DialogContent padded className="space-y-4">
<div className="text-sm text-txt-secondary">
{sprintf(__("Request access to %s's Trust Center. Your request will be reviewed and you will receive an email notification with access instructions if approved."), organizationName)}
</div>
<Field
label={__("Your Name")}
required
error={formState.errors.name?.message}
{...register("name")}
placeholder={__("Enter your full name")}
disabled={isSubmitting}
/>
<Field
label={__("Email Address")}
required
type="email"
error={formState.errors.email?.message}
{...register("email")}
placeholder={__("Enter your email address")}
disabled={isSubmitting}
/>
</DialogContent>
<DialogFooter>
<Button
type="submit"
disabled={isSubmitting}
>
{isSubmitting ? __("Submitting...") : __("Submit Request")}
</Button>
</DialogFooter>
</form>
</Dialog>
);
}

View File

@@ -35,7 +35,6 @@ export const publicTrustCenterQuery = {
filename
downloadUrl
}
reportUrl
}
}
}

View File

@@ -25,6 +25,7 @@ export const trustCenterAccessesQuery = graphql`
id
email
name
active
createdAt
}
}
@@ -46,6 +47,7 @@ export const createTrustCenterAccessMutation = graphql`
id
email
name
active
createdAt
}
}
@@ -53,6 +55,23 @@ export const createTrustCenterAccessMutation = graphql`
}
`;
export const updateTrustCenterAccessMutation = graphql`
mutation TrustCenterAccessGraphUpdateMutation(
$input: UpdateTrustCenterAccessInput!
) {
updateTrustCenterAccess(input: $input) {
trustCenterAccess {
id
email
name
active
createdAt
updatedAt
}
}
}
`;
export const deleteTrustCenterAccessMutation = graphql`
mutation TrustCenterAccessGraphDeleteMutation(
$input: DeleteTrustCenterAccessInput!

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<08687dbafb5515e9d2073b292a05ea0c>>
* @generated SignedSource<<ae95aed7bc22c95f8cc2ab591039c810>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,6 +10,7 @@
import { ConcreteRequest } from 'relay-runtime';
export type CreateTrustCenterAccessInput = {
active: boolean;
email: string;
name: string;
trustCenterId: string;
@@ -23,6 +24,7 @@ export type TrustCenterAccessGraphCreateMutation$data = {
readonly trustCenterAccessEdge: {
readonly cursor: any;
readonly node: {
readonly active: boolean;
readonly createdAt: any;
readonly email: string;
readonly id: string;
@@ -98,6 +100,13 @@ v3 = {
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -177,16 +186,16 @@ return {
]
},
"params": {
"cacheID": "86c21ac139bec74f2a4abad9caef68b1",
"cacheID": "eafddcd0263963235d3249c22eb50593",
"id": null,
"metadata": {},
"name": "TrustCenterAccessGraphCreateMutation",
"operationKind": "mutation",
"text": "mutation TrustCenterAccessGraphCreateMutation(\n $input: CreateTrustCenterAccessInput!\n) {\n createTrustCenterAccess(input: $input) {\n trustCenterAccessEdge {\n cursor\n node {\n id\n email\n name\n createdAt\n }\n }\n }\n}\n"
"text": "mutation TrustCenterAccessGraphCreateMutation(\n $input: CreateTrustCenterAccessInput!\n) {\n createTrustCenterAccess(input: $input) {\n trustCenterAccessEdge {\n cursor\n node {\n id\n email\n name\n active\n createdAt\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "59e0ab46fd6b68747566d666f5315292";
(node as any).hash = "99676fee0b2de06a92cdad66c577eee7";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<509cd7c9db3cbf15931c386b13a13987>>
* @generated SignedSource<<ed4ab6c79b848843012fc091a7eb325c>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,7 +10,7 @@
import { ConcreteRequest } from 'relay-runtime';
export type DeleteTrustCenterAccessInput = {
accessId: string;
id: string;
};
export type TrustCenterAccessGraphDeleteMutation$variables = {
connections: ReadonlyArray<string>;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<cbee2b0f0f7bc70f542094f32bd1b91b>>
* @generated SignedSource<<2333a6a7d5415f1a08a5612dcaceee8f>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -19,6 +19,7 @@ export type TrustCenterAccessGraphQuery$data = {
readonly edges: ReadonlyArray<{
readonly cursor: any;
readonly node: {
readonly active: boolean;
readonly createdAt: any;
readonly email: string;
readonly id: string;
@@ -155,6 +156,13 @@ v5 = [
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -282,7 +290,7 @@ return {
]
},
"params": {
"cacheID": "47681869f07fbe7df45ae3f663827c10",
"cacheID": "5b83cd4ae2434ce2e00de7230d264432",
"id": null,
"metadata": {
"connection": [
@@ -299,11 +307,11 @@ return {
},
"name": "TrustCenterAccessGraphQuery",
"operationKind": "query",
"text": "query TrustCenterAccessGraphQuery(\n $trustCenterId: ID!\n) {\n node(id: $trustCenterId) {\n __typename\n ... on TrustCenter {\n id\n accesses(first: 100, orderBy: {field: CREATED_AT, direction: DESC}) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n id\n email\n name\n createdAt\n __typename\n }\n }\n }\n }\n id\n }\n}\n"
"text": "query TrustCenterAccessGraphQuery(\n $trustCenterId: ID!\n) {\n node(id: $trustCenterId) {\n __typename\n ... on TrustCenter {\n id\n accesses(first: 100, orderBy: {field: CREATED_AT, direction: DESC}) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n id\n email\n name\n active\n createdAt\n __typename\n }\n }\n }\n }\n id\n }\n}\n"
}
};
})();
(node as any).hash = "06d7307ac23675de91ba2f9cb9d604bc";
(node as any).hash = "af598fd2af198e63ed84fd618857a985";
export default node;

View File

@@ -0,0 +1,147 @@
/**
* @generated SignedSource<<6de2ecb63a58c88c3008368061943b49>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type UpdateTrustCenterAccessInput = {
active?: boolean | null | undefined;
id: string;
name?: string | null | undefined;
};
export type TrustCenterAccessGraphUpdateMutation$variables = {
input: UpdateTrustCenterAccessInput;
};
export type TrustCenterAccessGraphUpdateMutation$data = {
readonly updateTrustCenterAccess: {
readonly trustCenterAccess: {
readonly active: boolean;
readonly createdAt: any;
readonly email: string;
readonly id: string;
readonly name: string;
readonly updatedAt: any;
};
};
};
export type TrustCenterAccessGraphUpdateMutation = {
response: TrustCenterAccessGraphUpdateMutation$data;
variables: TrustCenterAccessGraphUpdateMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "UpdateTrustCenterAccessPayload",
"kind": "LinkedField",
"name": "updateTrustCenterAccess",
"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
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "TrustCenterAccessGraphUpdateMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "TrustCenterAccessGraphUpdateMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "683ee01fb5173b49b0a7f3c2d99cf002",
"id": null,
"metadata": {},
"name": "TrustCenterAccessGraphUpdateMutation",
"operationKind": "mutation",
"text": "mutation TrustCenterAccessGraphUpdateMutation(\n $input: UpdateTrustCenterAccessInput!\n) {\n updateTrustCenterAccess(input: $input) {\n trustCenterAccess {\n id\n email\n name\n active\n createdAt\n updatedAt\n }\n }\n}\n"
}
};
})();
(node as any).hash = "cccd083b0047f6bc7b504b7494205e9d";
export default node;

View File

@@ -1,5 +1,5 @@
import { Outlet } from "react-router";
import { Logo, Button, IconArrowBoxLeft } from "@probo/ui";
import { Logo, Button, IconArrowBoxLeft, useToast } from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { buildEndpoint } from "/providers/RelayProviders";
import type { ReactNode } from "react";
@@ -8,10 +8,12 @@ type Props = {
organizationName: string;
organizationLogo?: string | null;
children?: ReactNode;
isAuthenticated?: boolean;
};
export function PublicTrustCenterLayout({ organizationName, organizationLogo, children }: Props) {
export function PublicTrustCenterLayout({ organizationName, organizationLogo, children, isAuthenticated }: Props) {
const { __ } = useTranslate();
const { toast } = useToast();
const handleLogout = async () => {
try {
@@ -22,10 +24,13 @@ export function PublicTrustCenterLayout({ organizationName, organizationLogo, ch
},
credentials: 'include',
});
window.location.reload();
} catch (error) {
console.error('Logout failed');
} finally {
window.location.href = "/";
toast({
title: __("Error"),
description: __("Logout failed"),
variant: "error",
});
}
};
@@ -67,13 +72,15 @@ export function PublicTrustCenterLayout({ organizationName, organizationLogo, ch
<span>Powered by Probo</span>
</a>
</div>
<Button
variant="tertiary"
icon={IconArrowBoxLeft}
onClick={handleLogout}
title={__("Logout")}
className="text-sm"
/>
{isAuthenticated && (
<Button
variant="tertiary"
icon={IconArrowBoxLeft}
onClick={handleLogout}
title={__("Logout")}
className="text-sm"
/>
)}
</div>
</div>
</div>

View File

@@ -63,7 +63,6 @@ interface Audit {
filename: string;
downloadUrl: string | null;
} | null;
reportUrl: string | null;
}
interface Vendor {
@@ -192,6 +191,7 @@ function PublicTrustCenterContent() {
<PublicTrustCenterLayout
organizationName={organization.name}
organizationLogo={organization.logoUrl}
isAuthenticated={isAuthenticated}
>
<div className="space-y-8">
<div className="text-center">
@@ -208,10 +208,13 @@ function PublicTrustCenterContent() {
audits={audits}
organizationName={organization.name}
isAuthenticated={isAuthenticated}
trustCenterId={trustCenterBySlug.id}
/>
<PublicTrustCenterDocuments
documents={documents}
isAuthenticated={isAuthenticated}
trustCenterId={trustCenterBySlug.id}
organizationName={organization.name}
/>
<PublicTrustCenterVendors
vendors={vendors}

View File

@@ -1,13 +1,34 @@
import { Button, Card, Dialog, DialogContent, DialogFooter, Field, Input, Spinner, Table, Tbody, Td, Th, Thead, Tr, useDialogRef, useToast, IconTrashCan } from "@probo/ui";
import {
Button,
Card,
Checkbox,
Dialog,
DialogContent,
DialogFooter,
Field,
Spinner,
Table,
Tbody,
Td,
Th,
Thead,
Tr,
useDialogRef,
IconTrashCan,
IconPencil,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { useOutletContext } from "react-router";
import { useState, useCallback } from "react";
import z from "zod";
import {
useTrustCenterAccesses,
createTrustCenterAccessMutation,
updateTrustCenterAccessMutation,
deleteTrustCenterAccessMutation
} from "/hooks/graph/TrustCenterAccessGraph";
import { useMutation } from "react-relay";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
type ContextType = {
organization: {
@@ -20,20 +41,50 @@ type ContextType = {
export default function TrustCenterAccessTab() {
const { __ } = useTranslate();
const { toast } = useToast();
const { organization } = useOutletContext<ContextType>();
const [createInvitation, isCreating] = useMutation(createTrustCenterAccessMutation);
const [deleteInvitation, isDeleting] = useMutation(deleteTrustCenterAccessMutation);
const inviteSchema = z.object({
name: z.string().min(1, __("Name is required")).min(2, __("Name must be at least 2 characters long")),
email: z.string().min(1, __("Email is required")).email(__("Please enter a valid email address")),
});
const editSchema = z.object({
name: z.string().min(1, __("Name is required")).min(2, __("Name must be at least 2 characters long")),
});
const [createInvitation, isCreating] = useMutationWithToasts(createTrustCenterAccessMutation, {
successMessage: __("Access invitation sent successfully"),
errorMessage: __("Failed to send invitation. Please try again."),
});
const [updateInvitation, isUpdating] = useMutationWithToasts(updateTrustCenterAccessMutation, {
successMessage: __("Access updated successfully"),
errorMessage: __("Failed to update access. Please try again."),
});
const [deleteInvitation, isDeleting] = useMutationWithToasts(deleteTrustCenterAccessMutation, {
successMessage: __("Access deleted successfully"),
errorMessage: __("Failed to delete access. Please try again."),
});
const dialogRef = useDialogRef();
const [email, setEmail] = useState("");
const [name, setName] = useState("");
const editDialogRef = useDialogRef();
const [editingAccess, setEditingAccess] = useState<{
id: string;
name: string;
} | null>(null);
const inviteForm = useFormWithSchema(inviteSchema, {
defaultValues: { name: "", email: "" },
});
const editForm = useFormWithSchema(editSchema, {
defaultValues: { name: "" },
});
type AccessType = {
id: string;
email: string;
name: string;
active: boolean;
createdAt: Date;
};
@@ -43,105 +94,78 @@ export default function TrustCenterAccessTab() {
id: edge.node.id,
email: edge.node.email,
name: edge.node.name,
active: edge.node.active,
createdAt: new Date(edge.node.createdAt)
})) ?? [];
const handleInvite = useCallback(async () => {
const handleInvite = inviteForm.handleSubmit(async (data) => {
if (!organization.trustCenter?.id) {
toast({
title: __("Error"),
description: __("Trust center not found"),
variant: "error",
});
return;
}
if (!email.trim() || !name.trim()) {
toast({
title: __("Error"),
description: __("Email and name are required"),
variant: "error",
});
return;
}
const connectionId = trustCenterData?.node?.accesses?.__id;
try {
createInvitation({
variables: {
input: {
trustCenterId: organization.trustCenter.id,
email: email.trim(),
name: name.trim(),
},
connections: connectionId ? [connectionId] : [],
},
onCompleted: (_, errors) => {
if (errors && errors.length > 0) {
toast({
title: __("Error"),
description: errors[0]?.message || __("Failed to send invitation"),
variant: "error",
});
return;
}
if (dialogRef.current) {
dialogRef.current.close();
}
setEmail("");
setName("");
toast({
title: __("Success"),
description: __("Access invitation sent successfully"),
variant: "success",
});
},
onError: (error) => {
toast({
title: __("Error"),
description: error.message || __("Failed to send invitation. Please try again."),
variant: "error",
});
},
});
} catch (error) {
toast({
title: __("Error"),
description: __("An unexpected error occurred. Please try again."),
variant: "error",
});
}
}, [organization.trustCenter?.id, email, name, trustCenterData, createInvitation, toast, __, dialogRef]);
const handleDelete = useCallback(async (accessId: string) => {
const connectionId = trustCenterData?.node?.accesses?.__id;
deleteInvitation({
await createInvitation({
variables: {
input: {
accessId,
trustCenterId: organization.trustCenter.id,
email: data.email.trim(),
name: data.name.trim(),
active: true,
},
connections: connectionId ? [connectionId] : [],
},
onCompleted: () => {
toast({
title: __("Success"),
description: __("Access deleted successfully"),
variant: "success",
});
},
onError: (error) => {
toast({
title: __("Error"),
description: error.message,
variant: "error",
});
onSuccess: () => {
dialogRef.current?.close();
inviteForm.reset();
},
});
}, [deleteInvitation, toast, __, trustCenterData]);
});
const handleDelete = useCallback(async (id: string) => {
const connectionId = trustCenterData?.node?.accesses?.__id;
await deleteInvitation({
variables: {
input: { id },
connections: connectionId ? [connectionId] : [],
},
});
}, [deleteInvitation, trustCenterData]);
const handleToggleActive = useCallback(async (id: string, active: boolean) => {
await updateInvitation({
variables: {
input: { id, active },
},
successMessage: active ? __("Access activated") : __("Access deactivated"),
});
}, [updateInvitation, __]);
const handleEditAccess = useCallback((access: AccessType) => {
setEditingAccess({ id: access.id, name: access.name });
editForm.reset({ name: access.name });
editDialogRef.current?.open();
}, [editDialogRef, editForm]);
const handleUpdateName = editForm.handleSubmit(async (data) => {
if (!editingAccess) return;
await updateInvitation({
variables: {
input: {
id: editingAccess.id,
name: data.name.trim(),
},
},
successMessage: __("Name updated successfully"),
onSuccess: () => {
editDialogRef.current?.close();
setEditingAccess(null);
editForm.reset();
},
});
});
return (
<div className="space-y-4">
@@ -153,7 +177,10 @@ export default function TrustCenterAccessTab() {
</p>
</div>
{organization.trustCenter?.id && (
<Button onClick={() => dialogRef.current?.open()}>
<Button onClick={() => {
inviteForm.reset();
dialogRef.current?.open();
}}>
{__("Invite")}
</Button>
)}
@@ -175,6 +202,7 @@ export default function TrustCenterAccessTab() {
<Th>{__("Name")}</Th>
<Th>{__("Email")}</Th>
<Th>{__("Date")}</Th>
<Th>{__("Active")}</Th>
<Th></Th>
</Tr>
</Thead>
@@ -186,8 +214,20 @@ export default function TrustCenterAccessTab() {
<Td>
{access.createdAt.toLocaleDateString()}
</Td>
<Td noLink width={120} className="text-end">
<Td>
<Checkbox
checked={access.active}
onChange={(active) => handleToggleActive(access.id, active)}
/>
</Td>
<Td noLink width={160} className="text-end">
<div className="flex gap-2 justify-end">
<Button
variant="secondary"
onClick={() => handleEditAccess(access)}
disabled={isUpdating}
icon={IconPencil}
/>
<Button
variant="secondary"
onClick={() => handleDelete(access.id)}
@@ -207,35 +247,65 @@ export default function TrustCenterAccessTab() {
ref={dialogRef}
title={__("Invite External Access")}
>
<DialogContent padded className="space-y-4">
<p className="text-txt-secondary text-sm">
{__("Send a 7-day access token to an external person to view your trust center")}
</p>
<form onSubmit={handleInvite}>
<DialogContent padded className="space-y-4">
<p className="text-txt-secondary text-sm">
{__("Send a 7-day access token to an external person to view your trust center")}
</p>
<Field label={__("Full Name")} required>
<Input
value={name}
onChange={(e) => setName(e.target.value)}
<Field
label={__("Full Name")}
required
error={inviteForm.formState.errors.name?.message}
{...inviteForm.register("name")}
placeholder={__("John Doe")}
/>
</Field>
<Field label={__("Email Address")} required>
<Input
<Field
label={__("Email Address")}
required
error={inviteForm.formState.errors.email?.message}
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
{...inviteForm.register("email")}
placeholder={__("john@example.com")}
/>
</Field>
</DialogContent>
</DialogContent>
<DialogFooter>
<Button onClick={handleInvite} disabled={isCreating}>
{isCreating && <Spinner />}
{__("Send Invitation")}
</Button>
</DialogFooter>
<DialogFooter>
<Button type="submit" disabled={isCreating}>
{isCreating && <Spinner />}
{__("Send Invitation")}
</Button>
</DialogFooter>
</form>
</Dialog>
<Dialog
ref={editDialogRef}
title={__("Edit Access Name")}
>
<form onSubmit={handleUpdateName}>
<DialogContent padded className="space-y-4">
<p className="text-txt-secondary text-sm">
{__("Update the display name for this access invitation")}
</p>
<Field
label={__("Full Name")}
required
error={editForm.formState.errors.name?.message}
{...editForm.register("name")}
placeholder={__("John Doe")}
/>
</DialogContent>
<DialogFooter>
<Button type="submit" disabled={isUpdating}>
{isUpdating && <Spinner />}
{__("Update Name")}
</Button>
</DialogFooter>
</form>
</Dialog>
</div>
);

View File

@@ -0,0 +1,7 @@
import type {IconProps} from "./type.ts";
export function IconLock({size = 24, className}: IconProps) {
return <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" className={className} xmlns="http://www.w3.org/2000/svg">
<path d="M6 10V8C6 5.79086 7.79086 4 10 4H14C16.2091 4 18 5.79086 18 8V10H19C19.5523 10 20 10.4477 20 11V19C20 19.5523 19.5523 20 19 20H5C4.44772 20 4 19.5523 4 19V11C4 10.4477 4.44772 10 5 10H6ZM8 8V10H16V8C16 6.89543 15.1046 6 14 6H10C8.89543 6 8 6.89543 8 8ZM6 12V18H18V12H6ZM12 13C12.5523 13 13 13.4477 13 14C13 14.5523 12.5523 15 12 15C11.4477 15 11 14.5523 11 14C11 13.4477 11.4477 13 12 13Z" fill="currentColor"/>
</svg>
}

View File

@@ -12,6 +12,7 @@ export { IconArrowCornerDownLeft } from "./IconArrowCornerDownLeft.tsx";
export { IconCrossLargeX } from "./IconCrossLargeX.tsx";
export { IconUpload } from "./IconUpload.tsx";
export { IconListStack } from "./IconListStack.tsx";
export { IconLock } from "./IconLock.tsx";
export { IconCircleCheck1 } from "./IconCircleCheck1.tsx";
export { IconClock } from "./IconClock.tsx";
export { IconImport2 } from "./IconImport2.tsx";

View File

@@ -0,0 +1,3 @@
ALTER TABLE trust_center_accesses ADD COLUMN active BOOLEAN NOT NULL DEFAULT TRUE;
ALTER TABLE trust_center_accesses ALTER COLUMN active DROP DEFAULT;

View File

@@ -33,6 +33,7 @@ type (
TrustCenterID gid.GID `db:"trust_center_id"`
Email string `db:"email"`
Name string `db:"name"`
Active bool `db:"active"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
@@ -62,6 +63,7 @@ SELECT
trust_center_id,
email,
name,
active,
created_at,
updated_at
FROM
@@ -106,6 +108,7 @@ SELECT
trust_center_id,
email,
name,
active,
created_at,
updated_at
FROM
@@ -152,6 +155,7 @@ INSERT INTO trust_center_accesses (
trust_center_id,
email,
name,
active,
created_at,
updated_at
) VALUES (
@@ -160,6 +164,7 @@ INSERT INTO trust_center_accesses (
@trust_center_id,
@email,
@name,
@active,
@created_at,
@updated_at
)
@@ -171,6 +176,7 @@ INSERT INTO trust_center_accesses (
"trust_center_id": tca.TrustCenterID,
"email": tca.Email,
"name": tca.Name,
"active": tca.Active,
"created_at": tca.CreatedAt,
"updated_at": tca.UpdatedAt,
}
@@ -183,6 +189,39 @@ INSERT INTO trust_center_accesses (
return nil
}
func (tca *TrustCenterAccess) Update(
ctx context.Context,
conn pg.Conn,
scope Scoper,
) error {
q := `
UPDATE trust_center_accesses SET
name = @name,
active = @active,
updated_at = @updated_at
WHERE
%s
AND id = @id
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"id": tca.ID,
"name": tca.Name,
"active": tca.Active,
"updated_at": tca.UpdatedAt,
}
maps.Copy(args, scope.SQLArguments())
_, err := conn.Exec(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot update trust center access: %w", err)
}
return nil
}
func (tca *TrustCenterAccess) Delete(
ctx context.Context,
conn pg.Conn,
@@ -224,6 +263,7 @@ SELECT
trust_center_id,
email,
name,
active,
created_at,
updated_at
FROM

View File

@@ -16,6 +16,7 @@ package probo
import (
"context"
"errors"
"fmt"
"net/url"
"strings"
@@ -26,6 +27,7 @@ import (
"github.com/getprobo/probo/pkg/page"
"github.com/getprobo/probo/pkg/statelesstoken"
"github.com/getprobo/probo/pkg/usrmgr"
"github.com/jackc/pgx/v5"
"go.gearno.de/kit/pg"
)
@@ -39,10 +41,17 @@ type (
TrustCenterID gid.GID
Email string
Name string
Active bool
}
UpdateTrustCenterAccessRequest struct {
ID gid.GID
Name *string
Active *bool
}
DeleteTrustCenterAccessRequest struct {
AccessID gid.GID
ID gid.GID
}
TrustCenterAccessData struct {
@@ -130,18 +139,22 @@ func (s TrustCenterAccessService) Create(
err := existingAccess.LoadByTrustCenterIDAndEmail(ctx, tx, s.svc.scope, req.TrustCenterID, req.Email)
if err == nil {
// Access already exists, delete it
if err := existingAccess.Delete(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot delete existing trust center access: %w", err)
}
}
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
return fmt.Errorf("cannot load trust center access: %w", err)
}
access = &coredata.TrustCenterAccess{
ID: gid.New(s.svc.scope.GetTenantID(), coredata.TrustCenterAccessEntityType),
TenantID: s.svc.scope.GetTenantID(),
TrustCenterID: req.TrustCenterID,
Email: req.Email,
Name: req.Name,
Active: req.Active,
CreatedAt: now,
UpdatedAt: now,
}
@@ -150,8 +163,58 @@ func (s TrustCenterAccessService) Create(
return fmt.Errorf("cannot insert trust center access: %w", err)
}
if err := s.sendAccessEmail(ctx, tx, access); err != nil {
return fmt.Errorf("failed to send access email: %w", err)
if req.Active {
if err := s.sendAccessEmail(ctx, tx, access); err != nil {
return fmt.Errorf("failed to send access email: %w", err)
}
}
return nil
})
if err != nil {
return nil, err
}
return access, nil
}
func (s TrustCenterAccessService) Update(
ctx context.Context,
req *UpdateTrustCenterAccessRequest,
) (*coredata.TrustCenterAccess, error) {
now := time.Now()
var access *coredata.TrustCenterAccess
if req.Name != nil && *req.Name == "" {
return nil, fmt.Errorf("name is required")
}
err := s.svc.pg.WithTx(ctx, func(tx pg.Conn) error {
access = &coredata.TrustCenterAccess{}
if err := access.LoadByID(ctx, tx, s.svc.scope, req.ID); err != nil {
return fmt.Errorf("cannot load trust center access: %w", err)
}
shouldSendEmail := req.Active != nil && *req.Active && !access.Active
if req.Name != nil {
access.Name = *req.Name
}
if req.Active != nil {
access.Active = *req.Active
}
access.UpdatedAt = now
if err := access.Update(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot update trust center access: %w", err)
}
if shouldSendEmail {
if err := s.sendAccessEmail(ctx, tx, access); err != nil {
return fmt.Errorf("failed to send access email: %w", err)
}
}
return nil
@@ -171,7 +234,7 @@ func (s TrustCenterAccessService) Delete(
err := s.svc.pg.WithTx(ctx, func(tx pg.Conn) error {
access := &coredata.TrustCenterAccess{}
if err := access.LoadByID(ctx, tx, s.svc.scope, req.AccessID); err != nil {
if err := access.LoadByID(ctx, tx, s.svc.scope, req.ID); err != nil {
return fmt.Errorf("cannot load trust center access: %w", err)
}

View File

@@ -1521,6 +1521,7 @@ type TrustCenterAccess implements Node {
id: ID!
email: String!
name: String!
active: Boolean!
createdAt: Datetime!
updatedAt: Datetime!
}
@@ -1821,6 +1822,10 @@ type Mutation {
input: CreateTrustCenterAccessInput!
): CreateTrustCenterAccessPayload!
updateTrustCenterAccess(
input: UpdateTrustCenterAccessInput!
): UpdateTrustCenterAccessPayload!
deleteTrustCenterAccess(
input: DeleteTrustCenterAccessInput!
): DeleteTrustCenterAccessPayload!
@@ -2068,10 +2073,17 @@ input CreateTrustCenterAccessInput {
trustCenterId: ID!
email: String!
name: String!
active: Boolean!
}
input UpdateTrustCenterAccessInput {
id: ID!
name: String
active: Boolean
}
input DeleteTrustCenterAccessInput {
accessId: ID!
id: ID!
}
input CreateVendorInput {
@@ -2604,6 +2616,10 @@ type CreateTrustCenterAccessPayload {
trustCenterAccessEdge: TrustCenterAccessEdge!
}
type UpdateTrustCenterAccessPayload {
trustCenterAccess: TrustCenterAccess!
}
type DeleteTrustCenterAccessPayload {
deletedTrustCenterAccessId: ID!
}

View File

@@ -749,6 +749,7 @@ type ComplexityRoot struct {
UpdateRisk func(childComplexity int, input types.UpdateRiskInput) int
UpdateTask func(childComplexity int, input types.UpdateTaskInput) int
UpdateTrustCenter func(childComplexity int, input types.UpdateTrustCenterInput) int
UpdateTrustCenterAccess func(childComplexity int, input types.UpdateTrustCenterAccessInput) int
UpdateVendor func(childComplexity int, input types.UpdateVendorInput) int
UpdateVendorBusinessAssociateAgreement func(childComplexity int, input types.UpdateVendorBusinessAssociateAgreementInput) int
UpdateVendorContact func(childComplexity int, input types.UpdateVendorContactInput) int
@@ -968,6 +969,7 @@ type ComplexityRoot struct {
}
TrustCenterAccess struct {
Active func(childComplexity int) int
CreatedAt func(childComplexity int) int
Email func(childComplexity int) int
ID func(childComplexity int) int
@@ -1055,6 +1057,10 @@ type ComplexityRoot struct {
Task func(childComplexity int) int
}
UpdateTrustCenterAccessPayload struct {
TrustCenterAccess func(childComplexity int) int
}
UpdateTrustCenterPayload struct {
TrustCenter func(childComplexity int) int
}
@@ -1385,6 +1391,7 @@ type MutationResolver interface {
DeleteOrganization(ctx context.Context, input types.DeleteOrganizationInput) (*types.DeleteOrganizationPayload, error)
UpdateTrustCenter(ctx context.Context, input types.UpdateTrustCenterInput) (*types.UpdateTrustCenterPayload, error)
CreateTrustCenterAccess(ctx context.Context, input types.CreateTrustCenterAccessInput) (*types.CreateTrustCenterAccessPayload, error)
UpdateTrustCenterAccess(ctx context.Context, input types.UpdateTrustCenterAccessInput) (*types.UpdateTrustCenterAccessPayload, error)
DeleteTrustCenterAccess(ctx context.Context, input types.DeleteTrustCenterAccessInput) (*types.DeleteTrustCenterAccessPayload, error)
ConfirmEmail(ctx context.Context, input types.ConfirmEmailInput) (*types.ConfirmEmailPayload, error)
InviteUser(ctx context.Context, input types.InviteUserInput) (*types.InviteUserPayload, error)
@@ -4557,6 +4564,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Mutation.UpdateTrustCenter(childComplexity, args["input"].(types.UpdateTrustCenterInput)), true
case "Mutation.updateTrustCenterAccess":
if e.complexity.Mutation.UpdateTrustCenterAccess == nil {
break
}
args, err := ec.field_Mutation_updateTrustCenterAccess_args(ctx, rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.UpdateTrustCenterAccess(childComplexity, args["input"].(types.UpdateTrustCenterAccessInput)), true
case "Mutation.updateVendor":
if e.complexity.Mutation.UpdateVendor == nil {
break
@@ -5709,6 +5728,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.TrustCenter.UpdatedAt(childComplexity), true
case "TrustCenterAccess.active":
if e.complexity.TrustCenterAccess.Active == nil {
break
}
return e.complexity.TrustCenterAccess.Active(childComplexity), true
case "TrustCenterAccess.createdAt":
if e.complexity.TrustCenterAccess.CreatedAt == nil {
break
@@ -5905,6 +5931,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.UpdateTaskPayload.Task(childComplexity), true
case "UpdateTrustCenterAccessPayload.trustCenterAccess":
if e.complexity.UpdateTrustCenterAccessPayload.TrustCenterAccess == nil {
break
}
return e.complexity.UpdateTrustCenterAccessPayload.TrustCenterAccess(childComplexity), true
case "UpdateTrustCenterPayload.trustCenter":
if e.complexity.UpdateTrustCenterPayload.TrustCenter == nil {
break
@@ -6937,6 +6970,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputUpdatePeopleInput,
ec.unmarshalInputUpdateRiskInput,
ec.unmarshalInputUpdateTaskInput,
ec.unmarshalInputUpdateTrustCenterAccessInput,
ec.unmarshalInputUpdateTrustCenterInput,
ec.unmarshalInputUpdateVendorBusinessAssociateAgreementInput,
ec.unmarshalInputUpdateVendorContactInput,
@@ -8575,6 +8609,7 @@ type TrustCenterAccess implements Node {
id: ID!
email: String!
name: String!
active: Boolean!
createdAt: Datetime!
updatedAt: Datetime!
}
@@ -8875,6 +8910,10 @@ type Mutation {
input: CreateTrustCenterAccessInput!
): CreateTrustCenterAccessPayload!
updateTrustCenterAccess(
input: UpdateTrustCenterAccessInput!
): UpdateTrustCenterAccessPayload!
deleteTrustCenterAccess(
input: DeleteTrustCenterAccessInput!
): DeleteTrustCenterAccessPayload!
@@ -9122,10 +9161,17 @@ input CreateTrustCenterAccessInput {
trustCenterId: ID!
email: String!
name: String!
active: Boolean!
}
input UpdateTrustCenterAccessInput {
id: ID!
name: String
active: Boolean
}
input DeleteTrustCenterAccessInput {
accessId: ID!
id: ID!
}
input CreateVendorInput {
@@ -9658,6 +9704,10 @@ type CreateTrustCenterAccessPayload {
trustCenterAccessEdge: TrustCenterAccessEdge!
}
type UpdateTrustCenterAccessPayload {
trustCenterAccess: TrustCenterAccess!
}
type DeleteTrustCenterAccessPayload {
deletedTrustCenterAccessId: ID!
}
@@ -13777,6 +13827,29 @@ func (ec *executionContext) field_Mutation_updateTask_argsInput(
return zeroVal, nil
}
func (ec *executionContext) field_Mutation_updateTrustCenterAccess_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
arg0, err := ec.field_Mutation_updateTrustCenterAccess_argsInput(ctx, rawArgs)
if err != nil {
return nil, err
}
args["input"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_updateTrustCenterAccess_argsInput(
ctx context.Context,
rawArgs map[string]any,
) (types.UpdateTrustCenterAccessInput, error) {
ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
if tmp, ok := rawArgs["input"]; ok {
return ec.unmarshalNUpdateTrustCenterAccessInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateTrustCenterAccessInput(ctx, tmp)
}
var zeroVal types.UpdateTrustCenterAccessInput
return zeroVal, nil
}
func (ec *executionContext) field_Mutation_updateTrustCenter_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
@@ -30399,6 +30472,65 @@ func (ec *executionContext) fieldContext_Mutation_createTrustCenterAccess(ctx co
return fc, nil
}
func (ec *executionContext) _Mutation_updateTrustCenterAccess(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_updateTrustCenterAccess(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().UpdateTrustCenterAccess(rctx, fc.Args["input"].(types.UpdateTrustCenterAccessInput))
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*types.UpdateTrustCenterAccessPayload)
fc.Result = res
return ec.marshalNUpdateTrustCenterAccessPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateTrustCenterAccessPayload(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Mutation_updateTrustCenterAccess(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Mutation",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "trustCenterAccess":
return ec.fieldContext_UpdateTrustCenterAccessPayload_trustCenterAccess(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type UpdateTrustCenterAccessPayload", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Mutation_updateTrustCenterAccess_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
return fc, nil
}
func (ec *executionContext) _Mutation_deleteTrustCenterAccess(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_deleteTrustCenterAccess(ctx, field)
if err != nil {
@@ -42810,6 +42942,50 @@ func (ec *executionContext) fieldContext_TrustCenterAccess_name(_ context.Contex
return fc, nil
}
func (ec *executionContext) _TrustCenterAccess_active(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_active(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.Active, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(bool)
fc.Result = res
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterAccess_active(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterAccess",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Boolean does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _TrustCenterAccess_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_createdAt(ctx, field)
if err != nil {
@@ -43091,6 +43267,8 @@ func (ec *executionContext) fieldContext_TrustCenterAccessEdge_node(_ context.Co
return ec.fieldContext_TrustCenterAccess_email(ctx, field)
case "name":
return ec.fieldContext_TrustCenterAccess_name(ctx, field)
case "active":
return ec.fieldContext_TrustCenterAccess_active(ctx, field)
case "createdAt":
return ec.fieldContext_TrustCenterAccess_createdAt(ctx, field)
case "updatedAt":
@@ -44380,6 +44558,64 @@ func (ec *executionContext) fieldContext_UpdateTaskPayload_task(_ context.Contex
return fc, nil
}
func (ec *executionContext) _UpdateTrustCenterAccessPayload_trustCenterAccess(ctx context.Context, field graphql.CollectedField, obj *types.UpdateTrustCenterAccessPayload) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_UpdateTrustCenterAccessPayload_trustCenterAccess(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.TrustCenterAccess, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*types.TrustCenterAccess)
fc.Result = res
return ec.marshalNTrustCenterAccess2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTrustCenterAccess(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_UpdateTrustCenterAccessPayload_trustCenterAccess(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "UpdateTrustCenterAccessPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_TrustCenterAccess_id(ctx, field)
case "email":
return ec.fieldContext_TrustCenterAccess_email(ctx, field)
case "name":
return ec.fieldContext_TrustCenterAccess_name(ctx, field)
case "active":
return ec.fieldContext_TrustCenterAccess_active(ctx, field)
case "createdAt":
return ec.fieldContext_TrustCenterAccess_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_TrustCenterAccess_updatedAt(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type TrustCenterAccess", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _UpdateTrustCenterPayload_trustCenter(ctx context.Context, field graphql.CollectedField, obj *types.UpdateTrustCenterPayload) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_UpdateTrustCenterPayload_trustCenter(ctx, field)
if err != nil {
@@ -54434,7 +54670,7 @@ func (ec *executionContext) unmarshalInputCreateTrustCenterAccessInput(ctx conte
asMap[k] = v
}
fieldsInOrder := [...]string{"trustCenterId", "email", "name"}
fieldsInOrder := [...]string{"trustCenterId", "email", "name", "active"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
@@ -54462,6 +54698,13 @@ func (ec *executionContext) unmarshalInputCreateTrustCenterAccessInput(ctx conte
return it, err
}
it.Name = data
case "active":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("active"))
data, err := ec.unmarshalNBoolean2bool(ctx, v)
if err != nil {
return it, err
}
it.Active = data
}
}
@@ -55436,20 +55679,20 @@ func (ec *executionContext) unmarshalInputDeleteTrustCenterAccessInput(ctx conte
asMap[k] = v
}
fieldsInOrder := [...]string{"accessId"}
fieldsInOrder := [...]string{"id"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "accessId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("accessId"))
case "id":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.AccessID = data
it.ID = data
}
}
@@ -57588,6 +57831,47 @@ func (ec *executionContext) unmarshalInputUpdateTaskInput(ctx context.Context, o
return it, nil
}
func (ec *executionContext) unmarshalInputUpdateTrustCenterAccessInput(ctx context.Context, obj any) (types.UpdateTrustCenterAccessInput, error) {
var it types.UpdateTrustCenterAccessInput
asMap := map[string]any{}
for k, v := range obj.(map[string]any) {
asMap[k] = v
}
fieldsInOrder := [...]string{"id", "name", "active"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "id":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.ID = data
case "name":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name"))
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.Name = data
case "active":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("active"))
data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
if err != nil {
return it, err
}
it.Active = data
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputUpdateTrustCenterInput(ctx context.Context, obj any) (types.UpdateTrustCenterInput, error) {
var it types.UpdateTrustCenterInput
asMap := map[string]any{}
@@ -64935,6 +65219,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "updateTrustCenterAccess":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_updateTrustCenterAccess(ctx, field)
})
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "deleteTrustCenterAccess":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_deleteTrustCenterAccess(ctx, field)
@@ -68257,6 +68548,11 @@ func (ec *executionContext) _TrustCenterAccess(ctx context.Context, sel ast.Sele
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "active":
out.Values[i] = ec._TrustCenterAccess_active(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "createdAt":
out.Values[i] = ec._TrustCenterAccess_createdAt(ctx, field, obj)
if out.Values[i] == graphql.Null {
@@ -69051,6 +69347,45 @@ func (ec *executionContext) _UpdateTaskPayload(ctx context.Context, sel ast.Sele
return out
}
var updateTrustCenterAccessPayloadImplementors = []string{"UpdateTrustCenterAccessPayload"}
func (ec *executionContext) _UpdateTrustCenterAccessPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateTrustCenterAccessPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, updateTrustCenterAccessPayloadImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("UpdateTrustCenterAccessPayload")
case "trustCenterAccess":
out.Values[i] = ec._UpdateTrustCenterAccessPayload_trustCenterAccess(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var updateTrustCenterPayloadImplementors = []string{"UpdateTrustCenterPayload"}
func (ec *executionContext) _UpdateTrustCenterPayload(ctx context.Context, sel ast.SelectionSet, obj *types.UpdateTrustCenterPayload) graphql.Marshaler {
@@ -76120,6 +76455,25 @@ func (ec *executionContext) marshalNUpdateTaskPayload2ᚖgithubᚗcomᚋgetprobo
return ec._UpdateTaskPayload(ctx, sel, v)
}
func (ec *executionContext) unmarshalNUpdateTrustCenterAccessInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateTrustCenterAccessInput(ctx context.Context, v any) (types.UpdateTrustCenterAccessInput, error) {
res, err := ec.unmarshalInputUpdateTrustCenterAccessInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNUpdateTrustCenterAccessPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateTrustCenterAccessPayload(ctx context.Context, sel ast.SelectionSet, v types.UpdateTrustCenterAccessPayload) graphql.Marshaler {
return ec._UpdateTrustCenterAccessPayload(ctx, sel, &v)
}
func (ec *executionContext) marshalNUpdateTrustCenterAccessPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateTrustCenterAccessPayload(ctx context.Context, sel ast.SelectionSet, v *types.UpdateTrustCenterAccessPayload) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._UpdateTrustCenterAccessPayload(ctx, sel, v)
}
func (ec *executionContext) unmarshalNUpdateTrustCenterInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐUpdateTrustCenterInput(ctx context.Context, v any) (types.UpdateTrustCenterInput, error) {
res, err := ec.unmarshalInputUpdateTrustCenterInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)

View File

@@ -26,6 +26,7 @@ func NewTrustCenterAccess(tca *coredata.TrustCenterAccess) *TrustCenterAccess {
ID: tca.ID,
Email: tca.Email,
Name: tca.Name,
Active: tca.Active,
CreatedAt: tca.CreatedAt,
UpdatedAt: tca.UpdatedAt,
}

View File

@@ -448,6 +448,7 @@ type CreateTrustCenterAccessInput struct {
TrustCenterID gid.GID `json:"trustCenterId"`
Email string `json:"email"`
Name string `json:"name"`
Active bool `json:"active"`
}
type CreateTrustCenterAccessPayload struct {
@@ -715,7 +716,7 @@ type DeleteTaskPayload struct {
}
type DeleteTrustCenterAccessInput struct {
AccessID gid.GID `json:"accessId"`
ID gid.GID `json:"id"`
}
type DeleteTrustCenterAccessPayload struct {
@@ -1240,6 +1241,7 @@ type TrustCenterAccess struct {
ID gid.GID `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
Active bool `json:"active"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
@@ -1470,6 +1472,16 @@ type UpdateTaskPayload struct {
Task *Task `json:"task"`
}
type UpdateTrustCenterAccessInput struct {
ID gid.GID `json:"id"`
Name *string `json:"name,omitempty"`
Active *bool `json:"active,omitempty"`
}
type UpdateTrustCenterAccessPayload struct {
TrustCenterAccess *TrustCenterAccess `json:"trustCenterAccess"`
}
type UpdateTrustCenterInput struct {
TrustCenterID gid.GID `json:"trustCenterId"`
Active *bool `json:"active,omitempty"`

View File

@@ -1143,6 +1143,7 @@ func (r *mutationResolver) CreateTrustCenterAccess(ctx context.Context, input ty
TrustCenterID: input.TrustCenterID,
Email: input.Email,
Name: input.Name,
Active: input.Active,
})
if err != nil {
return nil, fmt.Errorf("cannot create trust center access: %w", err)
@@ -1153,19 +1154,37 @@ func (r *mutationResolver) CreateTrustCenterAccess(ctx context.Context, input ty
}, nil
}
// UpdateTrustCenterAccess is the resolver for the updateTrustCenterAccess field.
func (r *mutationResolver) UpdateTrustCenterAccess(ctx context.Context, input types.UpdateTrustCenterAccessInput) (*types.UpdateTrustCenterAccessPayload, error) {
prb := r.ProboService(ctx, input.ID.TenantID())
access, err := prb.TrustCenterAccesses.Update(ctx, &probo.UpdateTrustCenterAccessRequest{
ID: input.ID,
Name: input.Name,
Active: input.Active,
})
if err != nil {
panic(fmt.Errorf("cannot update trust center access: %w", err))
}
return &types.UpdateTrustCenterAccessPayload{
TrustCenterAccess: types.NewTrustCenterAccess(access),
}, nil
}
// DeleteTrustCenterAccess is the resolver for the deleteTrustCenterAccess field.
func (r *mutationResolver) DeleteTrustCenterAccess(ctx context.Context, input types.DeleteTrustCenterAccessInput) (*types.DeleteTrustCenterAccessPayload, error) {
prb := r.ProboService(ctx, input.AccessID.TenantID())
prb := r.ProboService(ctx, input.ID.TenantID())
err := prb.TrustCenterAccesses.Delete(ctx, &probo.DeleteTrustCenterAccessRequest{
AccessID: input.AccessID,
ID: input.ID,
})
if err != nil {
return nil, fmt.Errorf("cannot delete trust center access: %w", err)
}
return &types.DeleteTrustCenterAccessPayload{
DeletedTrustCenterAccessID: input.AccessID,
DeletedTrustCenterAccessID: input.ID,
}, nil
}

View File

@@ -105,7 +105,7 @@ func NewMux(
r.Handle("/graphql", graphqlHandler(logger, usrmgrSvc, trustSvc, authCfg, trustAuthCfg))
r.Post("/auth/authenticate", authTokenHandler(trustSvc, trustAuthCfg))
r.Delete("/auth/logout", trustCenterLogoutHandler(trustAuthCfg))
r.Delete("/auth/logout", trustCenterLogoutHandler(authCfg, trustAuthCfg))
return r
}

View File

@@ -80,7 +80,6 @@ type Audit implements Node {
id: ID!
framework: Framework! @goField(forceResolver: true)
report: Report @goField(forceResolver: true)
reportUrl: String @goField(forceResolver: true) @mustBeAuthenticated(role: USER)
}
type AuditConnection {
@@ -224,6 +223,24 @@ type TrustCenter implements Node {
): VendorConnection! @goField(forceResolver: true)
}
type TrustCenterAccess implements Node {
id: ID!
email: String!
name: String!
createdAt: Datetime!
updatedAt: Datetime!
}
input CreateTrustCenterAccessInput {
trustCenterId: ID!
email: String!
name: String!
}
type CreateTrustCenterAccessPayload {
trustCenterAccess: TrustCenterAccess!
}
input ExportDocumentPDFInput {
documentId: ID!
}
@@ -237,6 +254,10 @@ type Query {
}
type Mutation {
createTrustCenterAccess(
input: CreateTrustCenterAccessInput!
): CreateTrustCenterAccessPayload! @mustBeAuthenticated(role: NONE)
exportDocumentPDF(
input: ExportDocumentPDFInput!
): ExportDocumentPDFPayload! @mustBeAuthenticated(role: USER)

View File

@@ -10,6 +10,7 @@ import (
"strconv"
"sync"
"sync/atomic"
"time"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/introspection"
@@ -60,7 +61,6 @@ type ComplexityRoot struct {
Framework func(childComplexity int) int
ID func(childComplexity int) int
Report func(childComplexity int) int
ReportURL func(childComplexity int) int
}
AuditConnection struct {
@@ -73,6 +73,10 @@ type ComplexityRoot struct {
Node func(childComplexity int) int
}
CreateTrustCenterAccessPayload struct {
TrustCenterAccess func(childComplexity int) int
}
Document struct {
DocumentType func(childComplexity int) int
ID func(childComplexity int) int
@@ -99,7 +103,8 @@ type ComplexityRoot struct {
}
Mutation struct {
ExportDocumentPDF func(childComplexity int, input types.ExportDocumentPDFInput) int
CreateTrustCenterAccess func(childComplexity int, input types.CreateTrustCenterAccessInput) int
ExportDocumentPDF func(childComplexity int, input types.ExportDocumentPDFInput) int
}
Organization struct {
@@ -135,6 +140,14 @@ type ComplexityRoot struct {
Vendors func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey) int
}
TrustCenterAccess struct {
CreatedAt func(childComplexity int) int
Email func(childComplexity int) int
ID func(childComplexity int) int
Name func(childComplexity int) int
UpdatedAt func(childComplexity int) int
}
Vendor struct {
Category func(childComplexity int) int
ID func(childComplexity int) int
@@ -157,9 +170,9 @@ type ComplexityRoot struct {
type AuditResolver interface {
Framework(ctx context.Context, obj *types.Audit) (*types.Framework, error)
Report(ctx context.Context, obj *types.Audit) (*types.Report, error)
ReportURL(ctx context.Context, obj *types.Audit) (*string, error)
}
type MutationResolver interface {
CreateTrustCenterAccess(ctx context.Context, input types.CreateTrustCenterAccessInput) (*types.CreateTrustCenterAccessPayload, error)
ExportDocumentPDF(ctx context.Context, input types.ExportDocumentPDFInput) (*types.ExportDocumentPDFPayload, error)
}
type OrganizationResolver interface {
@@ -218,13 +231,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Audit.Report(childComplexity), true
case "Audit.reportUrl":
if e.complexity.Audit.ReportURL == nil {
break
}
return e.complexity.Audit.ReportURL(childComplexity), true
case "AuditConnection.edges":
if e.complexity.AuditConnection.Edges == nil {
break
@@ -253,6 +259,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.AuditEdge.Node(childComplexity), true
case "CreateTrustCenterAccessPayload.trustCenterAccess":
if e.complexity.CreateTrustCenterAccessPayload.TrustCenterAccess == nil {
break
}
return e.complexity.CreateTrustCenterAccessPayload.TrustCenterAccess(childComplexity), true
case "Document.documentType":
if e.complexity.Document.DocumentType == nil {
break
@@ -323,6 +336,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Framework.Name(childComplexity), true
case "Mutation.createTrustCenterAccess":
if e.complexity.Mutation.CreateTrustCenterAccess == nil {
break
}
args, err := ec.field_Mutation_createTrustCenterAccess_args(ctx, rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.CreateTrustCenterAccess(childComplexity, args["input"].(types.CreateTrustCenterAccessInput)), true
case "Mutation.exportDocumentPDF":
if e.complexity.Mutation.ExportDocumentPDF == nil {
break
@@ -481,6 +506,41 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.TrustCenter.Vendors(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey)), true
case "TrustCenterAccess.createdAt":
if e.complexity.TrustCenterAccess.CreatedAt == nil {
break
}
return e.complexity.TrustCenterAccess.CreatedAt(childComplexity), true
case "TrustCenterAccess.email":
if e.complexity.TrustCenterAccess.Email == nil {
break
}
return e.complexity.TrustCenterAccess.Email(childComplexity), true
case "TrustCenterAccess.id":
if e.complexity.TrustCenterAccess.ID == nil {
break
}
return e.complexity.TrustCenterAccess.ID(childComplexity), true
case "TrustCenterAccess.name":
if e.complexity.TrustCenterAccess.Name == nil {
break
}
return e.complexity.TrustCenterAccess.Name(childComplexity), true
case "TrustCenterAccess.updatedAt":
if e.complexity.TrustCenterAccess.UpdatedAt == nil {
break
}
return e.complexity.TrustCenterAccess.UpdatedAt(childComplexity), true
case "Vendor.category":
if e.complexity.Vendor.Category == nil {
break
@@ -552,6 +612,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
opCtx := graphql.GetOperationContext(ctx)
ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)}
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
ec.unmarshalInputCreateTrustCenterAccessInput,
ec.unmarshalInputExportDocumentPDFInput,
)
first := true
@@ -732,7 +793,6 @@ type Audit implements Node {
id: ID!
framework: Framework! @goField(forceResolver: true)
report: Report @goField(forceResolver: true)
reportUrl: String @goField(forceResolver: true) @mustBeAuthenticated(role: USER)
}
type AuditConnection {
@@ -876,6 +936,24 @@ type TrustCenter implements Node {
): VendorConnection! @goField(forceResolver: true)
}
type TrustCenterAccess implements Node {
id: ID!
email: String!
name: String!
createdAt: Datetime!
updatedAt: Datetime!
}
input CreateTrustCenterAccessInput {
trustCenterId: ID!
email: String!
name: String!
}
type CreateTrustCenterAccessPayload {
trustCenterAccess: TrustCenterAccess!
}
input ExportDocumentPDFInput {
documentId: ID!
}
@@ -889,6 +967,10 @@ type Query {
}
type Mutation {
createTrustCenterAccess(
input: CreateTrustCenterAccessInput!
): CreateTrustCenterAccessPayload! @mustBeAuthenticated(role: NONE)
exportDocumentPDF(
input: ExportDocumentPDFInput!
): ExportDocumentPDFPayload! @mustBeAuthenticated(role: USER)
@@ -929,6 +1011,29 @@ func (ec *executionContext) dir_mustBeAuthenticated_argsRole(
return zeroVal, nil
}
func (ec *executionContext) field_Mutation_createTrustCenterAccess_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
arg0, err := ec.field_Mutation_createTrustCenterAccess_argsInput(ctx, rawArgs)
if err != nil {
return nil, err
}
args["input"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_createTrustCenterAccess_argsInput(
ctx context.Context,
rawArgs map[string]any,
) (types.CreateTrustCenterAccessInput, error) {
ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
if tmp, ok := rawArgs["input"]; ok {
return ec.unmarshalNCreateTrustCenterAccessInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐCreateTrustCenterAccessInput(ctx, tmp)
}
var zeroVal types.CreateTrustCenterAccessInput
return zeroVal, nil
}
func (ec *executionContext) field_Mutation_exportDocumentPDF_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
@@ -1472,74 +1577,6 @@ func (ec *executionContext) fieldContext_Audit_report(_ context.Context, field g
return fc, nil
}
func (ec *executionContext) _Audit_reportUrl(ctx context.Context, field graphql.CollectedField, obj *types.Audit) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Audit_reportUrl(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
directive0 := func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Audit().ReportURL(rctx, obj)
}
directive1 := func(ctx context.Context) (any, error) {
role, err := ec.unmarshalORole2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐRole(ctx, "USER")
if err != nil {
var zeroVal *string
return zeroVal, err
}
if ec.directives.MustBeAuthenticated == nil {
var zeroVal *string
return zeroVal, errors.New("directive mustBeAuthenticated is not implemented")
}
return ec.directives.MustBeAuthenticated(ctx, obj, directive0, role)
}
tmp, err := directive1(rctx)
if err != nil {
return nil, graphql.ErrorOnPath(ctx, err)
}
if tmp == nil {
return nil, nil
}
if data, ok := tmp.(*string); ok {
return data, nil
}
return nil, fmt.Errorf(`unexpected type %T from directive, should be *string`, tmp)
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Audit_reportUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Audit",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _AuditConnection_edges(ctx context.Context, field graphql.CollectedField, obj *types.AuditConnection) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_AuditConnection_edges(ctx, field)
if err != nil {
@@ -1733,8 +1770,6 @@ func (ec *executionContext) fieldContext_AuditEdge_node(_ context.Context, field
return ec.fieldContext_Audit_framework(ctx, field)
case "report":
return ec.fieldContext_Audit_report(ctx, field)
case "reportUrl":
return ec.fieldContext_Audit_reportUrl(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type Audit", field.Name)
},
@@ -1742,6 +1777,62 @@ func (ec *executionContext) fieldContext_AuditEdge_node(_ context.Context, field
return fc, nil
}
func (ec *executionContext) _CreateTrustCenterAccessPayload_trustCenterAccess(ctx context.Context, field graphql.CollectedField, obj *types.CreateTrustCenterAccessPayload) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_CreateTrustCenterAccessPayload_trustCenterAccess(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.TrustCenterAccess, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*types.TrustCenterAccess)
fc.Result = res
return ec.marshalNTrustCenterAccess2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐTrustCenterAccess(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_CreateTrustCenterAccessPayload_trustCenterAccess(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "CreateTrustCenterAccessPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_TrustCenterAccess_id(ctx, field)
case "email":
return ec.fieldContext_TrustCenterAccess_email(ctx, field)
case "name":
return ec.fieldContext_TrustCenterAccess_name(ctx, field)
case "createdAt":
return ec.fieldContext_TrustCenterAccess_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_TrustCenterAccess_updatedAt(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type TrustCenterAccess", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _Document_id(ctx context.Context, field graphql.CollectedField, obj *types.Document) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Document_id(ctx, field)
if err != nil {
@@ -2206,6 +2297,92 @@ func (ec *executionContext) fieldContext_Framework_name(_ context.Context, field
return fc, nil
}
func (ec *executionContext) _Mutation_createTrustCenterAccess(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_createTrustCenterAccess(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
directive0 := func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().CreateTrustCenterAccess(rctx, fc.Args["input"].(types.CreateTrustCenterAccessInput))
}
directive1 := func(ctx context.Context) (any, error) {
role, err := ec.unmarshalORole2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐRole(ctx, "NONE")
if err != nil {
var zeroVal *types.CreateTrustCenterAccessPayload
return zeroVal, err
}
if ec.directives.MustBeAuthenticated == nil {
var zeroVal *types.CreateTrustCenterAccessPayload
return zeroVal, errors.New("directive mustBeAuthenticated is not implemented")
}
return ec.directives.MustBeAuthenticated(ctx, nil, directive0, role)
}
tmp, err := directive1(rctx)
if err != nil {
return nil, graphql.ErrorOnPath(ctx, err)
}
if tmp == nil {
return nil, nil
}
if data, ok := tmp.(*types.CreateTrustCenterAccessPayload); ok {
return data, nil
}
return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/getprobo/probo/pkg/server/api/trust/v1/types.CreateTrustCenterAccessPayload`, tmp)
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*types.CreateTrustCenterAccessPayload)
fc.Result = res
return ec.marshalNCreateTrustCenterAccessPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐCreateTrustCenterAccessPayload(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Mutation_createTrustCenterAccess(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Mutation",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "trustCenterAccess":
return ec.fieldContext_CreateTrustCenterAccessPayload_trustCenterAccess(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type CreateTrustCenterAccessPayload", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Mutation_createTrustCenterAccess_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
return fc, nil
}
func (ec *executionContext) _Mutation_exportDocumentPDF(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_exportDocumentPDF(ctx, field)
if err != nil {
@@ -3340,6 +3517,226 @@ func (ec *executionContext) fieldContext_TrustCenter_vendors(ctx context.Context
return fc, nil
}
func (ec *executionContext) _TrustCenterAccess_id(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_id(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.ID, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(gid.GID)
fc.Result = res
return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterAccess_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterAccess",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type ID does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _TrustCenterAccess_email(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_email(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.Email, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
fc.Result = res
return ec.marshalNString2string(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterAccess_email(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterAccess",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _TrustCenterAccess_name(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_name(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.Name, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
fc.Result = res
return ec.marshalNString2string(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterAccess_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterAccess",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _TrustCenterAccess_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_createdAt(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.CreatedAt, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(time.Time)
fc.Result = res
return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterAccess_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterAccess",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Datetime does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _TrustCenterAccess_updatedAt(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_updatedAt(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.UpdatedAt, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(time.Time)
fc.Result = res
return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterAccess_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterAccess",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Datetime does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Vendor_id(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Vendor_id(ctx, field)
if err != nil {
@@ -5709,6 +6106,47 @@ func (ec *executionContext) fieldContext___Type_isOneOf(_ context.Context, field
// region **************************** input.gotpl *****************************
func (ec *executionContext) unmarshalInputCreateTrustCenterAccessInput(ctx context.Context, obj any) (types.CreateTrustCenterAccessInput, error) {
var it types.CreateTrustCenterAccessInput
asMap := map[string]any{}
for k, v := range obj.(map[string]any) {
asMap[k] = v
}
fieldsInOrder := [...]string{"trustCenterId", "email", "name"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "trustCenterId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("trustCenterId"))
data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.TrustCenterID = data
case "email":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email"))
data, err := ec.unmarshalNString2string(ctx, v)
if err != nil {
return it, err
}
it.Email = data
case "name":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name"))
data, err := ec.unmarshalNString2string(ctx, v)
if err != nil {
return it, err
}
it.Name = data
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputExportDocumentPDFInput(ctx context.Context, obj any) (types.ExportDocumentPDFInput, error) {
var it types.ExportDocumentPDFInput
asMap := map[string]any{}
@@ -5751,6 +6189,13 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj
return graphql.Null
}
return ec._Vendor(ctx, sel, obj)
case types.TrustCenterAccess:
return ec._TrustCenterAccess(ctx, sel, &obj)
case *types.TrustCenterAccess:
if obj == nil {
return graphql.Null
}
return ec._TrustCenterAccess(ctx, sel, obj)
case types.TrustCenter:
return ec._TrustCenter(ctx, sel, &obj)
case *types.TrustCenter:
@@ -5886,39 +6331,6 @@ func (ec *executionContext) _Audit(ctx context.Context, sel ast.SelectionSet, ob
continue
}
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
case "reportUrl":
field := field
innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._Audit_reportUrl(ctx, field, obj)
return res
}
if field.Deferrable != nil {
dfs, ok := deferred[field.Deferrable.Label]
di := 0
if ok {
dfs.AddField(field)
di = len(dfs.Values) - 1
} else {
dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
deferred[field.Deferrable.Label] = dfs
}
dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
return innerFunc(ctx, dfs)
})
// don't run the out.Concurrently() call below
out.Values[i] = graphql.Null
continue
}
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
default:
panic("unknown field " + strconv.Quote(field.Name))
@@ -6031,6 +6443,45 @@ func (ec *executionContext) _AuditEdge(ctx context.Context, sel ast.SelectionSet
return out
}
var createTrustCenterAccessPayloadImplementors = []string{"CreateTrustCenterAccessPayload"}
func (ec *executionContext) _CreateTrustCenterAccessPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreateTrustCenterAccessPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, createTrustCenterAccessPayloadImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("CreateTrustCenterAccessPayload")
case "trustCenterAccess":
out.Values[i] = ec._CreateTrustCenterAccessPayload_trustCenterAccess(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var documentImplementors = []string{"Document", "Node"}
func (ec *executionContext) _Document(ctx context.Context, sel ast.SelectionSet, obj *types.Document) graphql.Marshaler {
@@ -6270,6 +6721,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("Mutation")
case "createTrustCenterAccess":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_createTrustCenterAccess(ctx, field)
})
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "exportDocumentPDF":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_exportDocumentPDF(ctx, field)
@@ -6764,6 +7222,65 @@ func (ec *executionContext) _TrustCenter(ctx context.Context, sel ast.SelectionS
return out
}
var trustCenterAccessImplementors = []string{"TrustCenterAccess", "Node"}
func (ec *executionContext) _TrustCenterAccess(ctx context.Context, sel ast.SelectionSet, obj *types.TrustCenterAccess) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, trustCenterAccessImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("TrustCenterAccess")
case "id":
out.Values[i] = ec._TrustCenterAccess_id(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "email":
out.Values[i] = ec._TrustCenterAccess_email(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "name":
out.Values[i] = ec._TrustCenterAccess_name(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "createdAt":
out.Values[i] = ec._TrustCenterAccess_createdAt(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "updatedAt":
out.Values[i] = ec._TrustCenterAccess_updatedAt(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var vendorImplementors = []string{"Vendor", "Node"}
func (ec *executionContext) _Vendor(ctx context.Context, sel ast.SelectionSet, obj *types.Vendor) graphql.Marshaler {
@@ -7334,6 +7851,25 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se
return res
}
func (ec *executionContext) unmarshalNCreateTrustCenterAccessInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐCreateTrustCenterAccessInput(ctx context.Context, v any) (types.CreateTrustCenterAccessInput, error) {
res, err := ec.unmarshalInputCreateTrustCenterAccessInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNCreateTrustCenterAccessPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐCreateTrustCenterAccessPayload(ctx context.Context, sel ast.SelectionSet, v types.CreateTrustCenterAccessPayload) graphql.Marshaler {
return ec._CreateTrustCenterAccessPayload(ctx, sel, &v)
}
func (ec *executionContext) marshalNCreateTrustCenterAccessPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐCreateTrustCenterAccessPayload(ctx context.Context, sel ast.SelectionSet, v *types.CreateTrustCenterAccessPayload) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._CreateTrustCenterAccessPayload(ctx, sel, v)
}
func (ec *executionContext) unmarshalNCursorKey2githubᚗcomᚋgetproboᚋproboᚋpkgᚋpageᚐCursorKey(ctx context.Context, v any) (page.CursorKey, error) {
res, err := cursor.UnmarshalCursorKeyScalar(v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -7350,6 +7886,22 @@ func (ec *executionContext) marshalNCursorKey2githubᚗcomᚋgetproboᚋproboᚋ
return res
}
func (ec *executionContext) unmarshalNDatetime2timeᚐTime(ctx context.Context, v any) (time.Time, error) {
res, err := graphql.UnmarshalTime(v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNDatetime2timeᚐTime(ctx context.Context, sel ast.SelectionSet, v time.Time) graphql.Marshaler {
_ = sel
res := graphql.MarshalTime(v)
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
}
return res
}
func (ec *executionContext) marshalNDocument2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐDocument(ctx context.Context, sel ast.SelectionSet, v *types.Document) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
@@ -7547,6 +8099,16 @@ func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.S
return res
}
func (ec *executionContext) marshalNTrustCenterAccess2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐTrustCenterAccess(ctx context.Context, sel ast.SelectionSet, v *types.TrustCenterAccess) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._TrustCenterAccess(ctx, sel, v)
}
func (ec *executionContext) marshalNVendor2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋtrustᚋv1ᚋtypesᚐVendor(ctx context.Context, sel ast.SelectionSet, v *types.Vendor) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {

View File

@@ -22,6 +22,8 @@ import (
"time"
"github.com/getprobo/probo/pkg/probo"
console_v1 "github.com/getprobo/probo/pkg/server/api/console/v1"
"github.com/getprobo/probo/pkg/server/session"
"github.com/getprobo/probo/pkg/statelesstoken"
"github.com/getprobo/probo/pkg/trust"
"go.gearno.de/kit/httpserver"
@@ -110,12 +112,16 @@ func validateTrustCenterAccessToken(ctx context.Context, trustSvc *trust.Service
tenantID := token.Data.TrustCenterID.TenantID()
tenantSvc := trustSvc.WithTenant(tenantID)
return tenantSvc.TrustCenterAccesses.ValidateToken(ctx, tokenString)
accessData, err := tenantSvc.TrustCenterAccesses.ValidateToken(ctx, tokenString)
if err != nil {
return nil, fmt.Errorf("cannot validate trust center access token: %w", err)
}
return accessData, nil
}
func trustCenterLogoutHandler(trustAuthCfg TrustAuthConfig) http.HandlerFunc {
func trustCenterLogoutHandler(authCfg console_v1.AuthConfig, trustAuthCfg TrustAuthConfig) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Clear cookie directly
http.SetCookie(w, &http.Cookie{
Name: trustAuthCfg.CookieName,
Value: "",
@@ -127,6 +133,11 @@ func trustCenterLogoutHandler(trustAuthCfg TrustAuthConfig) http.HandlerFunc {
SameSite: http.SameSiteStrictMode,
})
session.ClearCookie(w, session.AuthConfig{
CookieName: authCfg.CookieName,
CookieSecret: authCfg.CookieSecret,
})
httpserver.RenderJSON(w, http.StatusOK, map[string]string{
"message": "Logged out successfully",
})

View File

@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"strconv"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
@@ -22,7 +23,6 @@ type Audit struct {
ID gid.GID `json:"id"`
Framework *Framework `json:"framework"`
Report *Report `json:"report,omitempty"`
ReportURL *string `json:"reportUrl,omitempty"`
}
func (Audit) IsNode() {}
@@ -38,6 +38,16 @@ type AuditEdge struct {
Node *Audit `json:"node"`
}
type CreateTrustCenterAccessInput struct {
TrustCenterID gid.GID `json:"trustCenterId"`
Email string `json:"email"`
Name string `json:"name"`
}
type CreateTrustCenterAccessPayload struct {
TrustCenterAccess *TrustCenterAccess `json:"trustCenterAccess"`
}
type Document struct {
ID gid.GID `json:"id"`
Title string `json:"title"`
@@ -117,6 +127,17 @@ type TrustCenter struct {
func (TrustCenter) IsNode() {}
func (this TrustCenter) GetID() gid.GID { return this.ID }
type TrustCenterAccess struct {
ID gid.GID `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
func (TrustCenterAccess) IsNode() {}
func (this TrustCenterAccess) GetID() gid.GID { return this.ID }
type Vendor struct {
ID gid.GID `json:"id"`
Name string `json:"name"`

View File

@@ -16,6 +16,7 @@ import (
"github.com/getprobo/probo/pkg/server/api/trust/v1/auth"
"github.com/getprobo/probo/pkg/server/api/trust/v1/schema"
"github.com/getprobo/probo/pkg/server/api/trust/v1/types"
"github.com/getprobo/probo/pkg/trust"
)
// Framework is the resolver for the framework field.
@@ -56,29 +57,28 @@ func (r *auditResolver) Report(ctx context.Context, obj *types.Audit) (*types.Re
return types.NewReport(report), nil
}
// ReportURL is the resolver for the reportUrl field.
func (r *auditResolver) ReportURL(ctx context.Context, obj *types.Audit) (*string, error) {
if err := auth.ValidateTenantAccess(ctx, r, userTenantContextKey, obj.ID.TenantID()); err != nil {
return nil, err
}
// CreateTrustCenterAccess is the resolver for the createTrustCenterAccess field.
func (r *mutationResolver) CreateTrustCenterAccess(ctx context.Context, input types.CreateTrustCenterAccessInput) (*types.CreateTrustCenterAccessPayload, error) {
trustSvc := r.trustCenterSvc.WithTenant(input.TrustCenterID.TenantID())
trust := r.TrustService(ctx, obj.ID.TenantID())
audit, err := trust.Audits.Get(ctx, obj.ID)
access, err := trustSvc.TrustCenterAccesses.Create(ctx, &trust.CreateTrustCenterAccessRequest{
TrustCenterID: input.TrustCenterID,
Email: input.Email,
Name: input.Name,
})
if err != nil {
return nil, fmt.Errorf("cannot load audit: %w", err)
panic(fmt.Errorf("cannot create trust center access: %w", err))
}
if audit.ReportID == nil {
return nil, nil
}
url, err := trust.Audits.GenerateReportURL(ctx, obj.ID, r.trustAuthCfg.ReportURLDuration)
if err != nil {
return nil, fmt.Errorf("cannot generate report URL: %w", err)
}
return url, nil
return &types.CreateTrustCenterAccessPayload{
TrustCenterAccess: &types.TrustCenterAccess{
ID: access.ID,
Email: access.Email,
Name: access.Name,
CreatedAt: access.CreatedAt,
UpdatedAt: access.UpdatedAt,
},
}, nil
}
// ExportDocumentPDF is the resolver for the exportDocumentPDF field.
@@ -140,7 +140,7 @@ func (r *reportResolver) DownloadURL(ctx context.Context, obj *types.Report) (*s
trust := r.TrustService(ctx, obj.ID.TenantID())
url, err := trust.Reports.GenerateDownloadURL(ctx, obj.ID, 5*time.Minute)
url, err := trust.Reports.GenerateDownloadURL(ctx, obj.ID, r.trustAuthCfg.ReportURLDuration)
if err != nil {
return nil, fmt.Errorf("cannot generate download URL: %w", err)
}

View File

@@ -17,7 +17,6 @@ package trust
import (
"context"
"fmt"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
@@ -80,25 +79,3 @@ func (s AuditService) ListForOrganizationId(
return page.NewPage(audits, cursor), nil
}
func (s AuditService) GenerateReportURL(
ctx context.Context,
auditID gid.GID,
expiresIn time.Duration,
) (*string, error) {
audit, err := s.Get(ctx, auditID)
if err != nil {
return nil, fmt.Errorf("cannot get audit: %w", err)
}
if audit.ReportID == nil {
return nil, fmt.Errorf("audit has no report")
}
url, err := s.svc.Reports.GenerateDownloadURL(ctx, *audit.ReportID, expiresIn)
if err != nil {
return nil, fmt.Errorf("cannot generate report download URL: %w", err)
}
return url, nil
}

View File

@@ -16,12 +16,17 @@ package trust
import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/probo"
"github.com/getprobo/probo/pkg/statelesstoken"
"github.com/getprobo/probo/pkg/usrmgr"
"github.com/jackc/pgx/v5"
"go.gearno.de/kit/pg"
)
@@ -30,6 +35,12 @@ type (
svc *TenantService
usrmgr *usrmgr.Service
}
CreateTrustCenterAccessRequest struct {
TrustCenterID gid.GID
Email string
Name string
}
)
const (
@@ -56,6 +67,10 @@ func (s TrustCenterAccessService) ValidateToken(
return fmt.Errorf("cannot load trust center access: %w", err)
}
if !access.Active {
return fmt.Errorf("trust center access is not active")
}
return nil
})
@@ -65,3 +80,57 @@ func (s TrustCenterAccessService) ValidateToken(
return &token.Data, nil
}
func (s TrustCenterAccessService) Create(
ctx context.Context,
req *CreateTrustCenterAccessRequest,
) (*coredata.TrustCenterAccess, error) {
if !strings.Contains(req.Email, "@") {
return nil, fmt.Errorf("invalid email address")
}
if req.Name == "" {
return nil, fmt.Errorf("name is required")
}
now := time.Now()
var access *coredata.TrustCenterAccess
err := s.svc.pg.WithTx(ctx, func(tx pg.Conn) error {
existingAccess := &coredata.TrustCenterAccess{}
err := existingAccess.LoadByTrustCenterIDAndEmail(ctx, tx, s.svc.scope, req.TrustCenterID, req.Email)
if err == nil {
if err := existingAccess.Delete(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot delete existing trust center access: %w", err)
}
}
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
return fmt.Errorf("cannot load trust center access: %w", err)
}
access = &coredata.TrustCenterAccess{
ID: gid.New(s.svc.scope.GetTenantID(), coredata.TrustCenterAccessEntityType),
TenantID: s.svc.scope.GetTenantID(),
TrustCenterID: req.TrustCenterID,
Email: req.Email,
Name: req.Name,
Active: false,
CreatedAt: now,
UpdatedAt: now,
}
if err := access.Insert(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert trust center access: %w", err)
}
return nil
})
if err != nil {
return nil, err
}
return access, nil
}