From bc049b18b9c3c1fe75d4f46ebd2f4348163c707b Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Sat, 13 Jul 2024 00:46:40 +0200 Subject: [PATCH] Added a button to create a policy --- src/frontend/actions/api.ts | 29 +++++++ src/frontend/app/api/connector-functions.ts | 12 +-- src/frontend/app/api/createPolicy/route.ts | 4 +- src/frontend/app/api/getPolicies/route.ts | 2 +- src/frontend/app/dashboard/upload/page.tsx | 13 +++- .../app/dashboard/upload/policyModal.tsx | 75 +++++++++++++++++++ 6 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 src/frontend/app/dashboard/upload/policyModal.tsx diff --git a/src/frontend/actions/api.ts b/src/frontend/actions/api.ts index 824684f..19ad83d 100644 --- a/src/frontend/actions/api.ts +++ b/src/frontend/actions/api.ts @@ -185,6 +185,35 @@ export async function createAsset(file: FileInfo): Promise { } } +export async function createPolicy(name: string, description: string): Promise { + try { + const response = await fetch('/api/createPolicy', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + name: name, + description: description + }) + }); + + if (!response.ok) { + throw new Error(`API call failed with status ${response.status}`); + } + + const data = await response.json(); + + if (data.error) { + throw new Error(data.error); + } + + return true; + } catch (err) { + throw new Error("Error creating policy: ", err); + } +} + export async function createContractDefinition(contractId: string, policyId: string, assetId: string): Promise { try { const response = await fetch('/api/createContractDefinition', { diff --git a/src/frontend/app/api/connector-functions.ts b/src/frontend/app/api/connector-functions.ts index c0bac1c..3f5c53e 100644 --- a/src/frontend/app/api/connector-functions.ts +++ b/src/frontend/app/api/connector-functions.ts @@ -207,14 +207,16 @@ export async function registerDataplaneProvider(dataplaneId: string) { } }; -function generateCreatePolicy(policyId: string) { - // TODO: acutal policy with permission/prohibition/obligation +function generateCreatePolicy(name: string, description: string) { const createPolicy = { "@context": { "@vocab": "https://w3id.org/edc/v0.0.1/ns/", "odrl": "http://www.w3.org/ns/odrl/2/" }, - "@id": policyId, + "privateProperties": { + "name": name, + "description": description + }, "policy": { "@context": "http://www.w3.org/ns/odrl.jsonld", "@type": "Set", @@ -226,7 +228,7 @@ function generateCreatePolicy(policyId: string) { return createPolicy; }; -export async function createPolicy(policyId: string) { +export async function createPolicy(name: string, description: string) { try { const result = await fetch(connectorManagementUrl + "v2/policydefinitions", { method: 'POST', @@ -235,7 +237,7 @@ export async function createPolicy(policyId: string) { 'Content-Type': 'application/json', 'X-API-Key': authenticationPassword }, - body: JSON.stringify(generateCreatePolicy(policyId)), + body: JSON.stringify(generateCreatePolicy(name, description)), }); if (!result.ok) { throw new Error(`HTTP Error! Status: ${result.status}`); diff --git a/src/frontend/app/api/createPolicy/route.ts b/src/frontend/app/api/createPolicy/route.ts index 001e427..0953495 100644 --- a/src/frontend/app/api/createPolicy/route.ts +++ b/src/frontend/app/api/createPolicy/route.ts @@ -8,8 +8,8 @@ export const POST = auth(async function POST(req) { return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); } const body = await req.json(); - const { policyId } = body; - const result = await createPolicy(policyId); + const { name, description } = body; + const result = await createPolicy(name, description); return NextResponse.json(result); } catch (error) { return NextResponse.json({ error: error.message }, { status: 500 }); diff --git a/src/frontend/app/api/getPolicies/route.ts b/src/frontend/app/api/getPolicies/route.ts index 31149c3..de82039 100644 --- a/src/frontend/app/api/getPolicies/route.ts +++ b/src/frontend/app/api/getPolicies/route.ts @@ -9,7 +9,7 @@ export const GET = auth(async function GET(req) { } const data = await getPolicies(); const policies = data.map((item: any) => ({ - name: item.privateProperties?.name || 'Unnamed Policy', + name: item.privateProperties?.name || 'Default Policy', description: item.privateProperties?.description || 'No description provided', id: item["@id"] })); diff --git a/src/frontend/app/dashboard/upload/page.tsx b/src/frontend/app/dashboard/upload/page.tsx index 05b5adb..cf2ec7e 100644 --- a/src/frontend/app/dashboard/upload/page.tsx +++ b/src/frontend/app/dashboard/upload/page.tsx @@ -3,6 +3,7 @@ import React, { useState, useEffect } from 'react'; import { ArrowPathIcon, TrashIcon, CloudArrowDownIcon } from '@heroicons/react/24/outline'; import { createAsset, createContractDefinition, getAssets, uploadFile, getPolicies } from '@/actions/api'; import { FileInfo, Policy, Asset } from "@/data/interface/file"; +import PolicyModal from './policyModal'; const MAX_FILE_SIZE_MB = 10; @@ -11,6 +12,7 @@ const UploadPage: React.FC = () => { const [title, setTitle] = useState(''); const [policyId, setPolicyId] = useState(''); const [showModal, setShowModal] = useState(false); + const [showPolicyModal, setShowPolicyModal] = useState(false); const [errorMessage, setErrorMessage] = useState(''); const [files, setFiles] = useState([]); const [policies, setPolicies] = useState([]); @@ -112,16 +114,19 @@ const UploadPage: React.FC = () => { return (
-
+
+
@@ -157,6 +162,8 @@ const UploadPage: React.FC = () => {
+ setShowPolicyModal(false)} /> + {showModal && (
@@ -215,6 +222,8 @@ const UploadPage: React.FC = () => {
+ + )}
); diff --git a/src/frontend/app/dashboard/upload/policyModal.tsx b/src/frontend/app/dashboard/upload/policyModal.tsx new file mode 100644 index 0000000..11ad517 --- /dev/null +++ b/src/frontend/app/dashboard/upload/policyModal.tsx @@ -0,0 +1,75 @@ +'use client'; +import { createPolicy } from '@/actions/api'; +import React, { useState, useEffect, FormEvent } from 'react'; + +interface PolicyModalProps { + isOpen: boolean; + onClose: () => void; +} + +const PolicyModal: React.FC = ({ isOpen, onClose }) => { + const [name, setName] = useState(""); + const [description, setDescription] = useState(""); + const [errorMessage, setErrorMessage] = useState(""); + + const handleCreate = async (e: FormEvent) => { + e.preventDefault(); + try { + setErrorMessage(""); + await createPolicy(name, description); + onClose(); + } catch(err) { + setErrorMessage("There was a problem creating the policy."); + } + } + + if(!isOpen) { + return null; + } + + return ( +
+
+
+
+ + setName(e.target.value)} + className="border border-gray-300 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:border-gray-600 dark:placeholder-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500" + required + /> +
+
+ +