From eb04780442f07a6f17bfa68029eec1cc330e25a5 Mon Sep 17 00:00:00 2001 From: WerLaj Date: Sat, 3 Feb 2024 00:17:36 +0100 Subject: [PATCH 01/11] Draft PR --- pkg_client/package.json | 4 +- pkg_client/src/App.css | 7 +- pkg_client/src/App.tsx | 6 +- pkg_client/src/components/APIHandler.tsx | 66 +++++++---------- pkg_client/src/components/Layout.tsx | 47 ++++++++++++ .../src/components/PKGVisualization.tsx | 72 +++++++++++++++++++ pkg_client/src/components/QueryForm.tsx | 66 +++++++++++++++++ pkg_client/src/contexts/UserContext.tsx | 11 ++- 8 files changed, 228 insertions(+), 51 deletions(-) create mode 100644 pkg_client/src/components/Layout.tsx create mode 100644 pkg_client/src/components/PKGVisualization.tsx create mode 100644 pkg_client/src/components/QueryForm.tsx diff --git a/pkg_client/package.json b/pkg_client/package.json index bd4b27d..ccc2cfb 100644 --- a/pkg_client/package.json +++ b/pkg_client/package.json @@ -15,6 +15,8 @@ "react": "^18.2.0", "react-bootstrap": "^2.9.1", "react-dom": "^18.2.0", + "react-icons": "^4.12.0", + "react-router-dom": "^6.21.0", "react-scripts": "5.0.1", "typescript": "^4.9.5", "web-vitals": "^2.1.4" @@ -43,4 +45,4 @@ "last 1 safari version" ] } -} +} \ No newline at end of file diff --git a/pkg_client/src/App.css b/pkg_client/src/App.css index 74b5e05..482d15b 100644 --- a/pkg_client/src/App.css +++ b/pkg_client/src/App.css @@ -1,7 +1,3 @@ -.App { - text-align: center; -} - .App-logo { height: 40vmin; pointer-events: none; @@ -32,7 +28,8 @@ from { transform: rotate(0deg); } + to { transform: rotate(360deg); } -} +} \ No newline at end of file diff --git a/pkg_client/src/App.tsx b/pkg_client/src/App.tsx index baae969..f3cb36a 100644 --- a/pkg_client/src/App.tsx +++ b/pkg_client/src/App.tsx @@ -2,7 +2,7 @@ import React, { useContext } from "react"; import "./App.css"; import APIHandler from "./components/APIHandler"; import LoginForm from "./components/LoginForm"; -import Container from 'react-bootstrap/Container' +import Container from 'react-bootstrap/Container'; import { UserContext } from "./contexts/UserContext"; function App() { @@ -13,9 +13,7 @@ function App() { return ( -
- {content} -
+
{content}
); diff --git a/pkg_client/src/components/APIHandler.tsx b/pkg_client/src/components/APIHandler.tsx index 4f2f070..3c2ee1e 100644 --- a/pkg_client/src/components/APIHandler.tsx +++ b/pkg_client/src/components/APIHandler.tsx @@ -1,50 +1,38 @@ -import React, { useContext, useEffect, useState } from "react"; -import axios from "axios"; +import React, { useContext } from "react"; import { UserContext } from "../contexts/UserContext"; import Container from "react-bootstrap/Container"; +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import Layout from "./Layout"; +import PKGVisualization from "./PKGVisualization"; const APIHandler: React.FC = () => { const { user } = useContext(UserContext); - // State tracker for service management data. - const [serviceData, setServiceData] = useState(null); - // State tracker for personal facts data. - const [factsData, setFactsData] = useState(null); - // State tracker for PKG exploration data. Data presentation, graphs, etc. - const [exploreData, setExploreData] = useState(null); - - useEffect(() => { - const baseURL = - (window as any)["PKG_API_BASE_URL"] || "http://localhost:5000"; - - axios - .get(`${baseURL}/service`) - .then((response) => setServiceData(response.data)); - axios - .get(`${baseURL}/facts`) - .then((response) => setFactsData(response.data)); - axios - .get(`${baseURL}/explore`) - .then((response) => setExploreData(response.data)); - }, []); return ( -

Personal Knowledge Graph API

-
-

Welcome {JSON.stringify(user, null, 2)}

-
-
-

Service Management Data

-
{JSON.stringify(serviceData, null, 2)}
-
-
-

Personal Facts Data

-
{JSON.stringify(factsData, null, 2)}
-
-
-

PKG Exploration Data

-
{JSON.stringify(exploreData, null, 2)}
-
+

Personal Knowledge Graph

+ + + + }> + +
Welcome {user?.username}.
+ + } + /> + Service Management} /> + Population form} /> + Personal Preferences} + /> + } /> + +
+
); }; diff --git a/pkg_client/src/components/Layout.tsx b/pkg_client/src/components/Layout.tsx new file mode 100644 index 0000000..30208aa --- /dev/null +++ b/pkg_client/src/components/Layout.tsx @@ -0,0 +1,47 @@ +// Layout component for the application includes a navigation bar and content +// of the current tab. +import { Outlet, Link } from "react-router-dom"; +import Nav from "react-bootstrap/Nav"; +import { useState } from "react"; + +const Layout = () => { + const [activeKey, setActiveKey] = useState("/"); + + const handleSelect = (eventKey: string | null) => { + if (eventKey !== null) { + setActiveKey(eventKey); + } + }; + + return ( + <> + + +
+ + + ); +}; + +export default Layout; \ No newline at end of file diff --git a/pkg_client/src/components/PKGVisualization.tsx b/pkg_client/src/components/PKGVisualization.tsx new file mode 100644 index 0000000..e75c8bd --- /dev/null +++ b/pkg_client/src/components/PKGVisualization.tsx @@ -0,0 +1,72 @@ +// Natural language to PKG component + +import { Container } from "react-bootstrap"; +import { UserContext } from "../contexts/UserContext"; +import { useContext, useState } from "react"; +import axios from "axios"; +import QueryForm from "./QueryForm"; +import Button from 'react-bootstrap/Button'; + +const PKGVisualization = () => { + const { user } = useContext(UserContext); + const [error, setError] = useState(""); + const [image_path, setImagePath] = useState(""); + const [image_info, setImageInfo] = useState(""); + const [query_info, setQueryInfo] = useState(""); + const [result, setResult] = useState(""); + const baseURL = + (window as any)["PKG_API_BASE_URL"] || "http://127.0.0.1:5000"; + + const getImagePath = () => { + axios.get(`${baseURL}/explore`, {}) + .then((response) => { + setError(""); + console.log(response.data.message); + setImageInfo(response.data.message); + setImagePath(response.data.img_path); + }) + .catch((error) => { + setError(error.message); + throw error; + }); + }; + + const executeQuery = (query: string) => { + return axios + .post(`${baseURL}/execute`, { + query: query, + username: user?.username, + user_uri: user?.uri, + }) + .then((response) => { + setError(""); + console.log(response.data.message); + setQueryInfo(response.data.message); + setResult(response.data.result); + }) + .catch((error) => { + setError(error.message); + throw error; + }); + }; + + return ( + +
+ Here you can execute your own SPARQL queries to manage your PKG. +
{image_info}
+
+ +
Query execution status: {query_info}
+
Query execution result: {result}
+
+ This is your current PKG: +
+
[Only for testing] Local path to the image: {image_path}
+ PKG +
+ ); + +}; + +export default PKGVisualization; \ No newline at end of file diff --git a/pkg_client/src/components/QueryForm.tsx b/pkg_client/src/components/QueryForm.tsx new file mode 100644 index 0000000..65c66f5 --- /dev/null +++ b/pkg_client/src/components/QueryForm.tsx @@ -0,0 +1,66 @@ +// Form comprising a single text input and a submit button. + +import { useState } from "react"; +import { Alert, Button, Spinner } from "react-bootstrap"; +import Form from "react-bootstrap/Form"; + +interface QueryFormProps { + handleSubmit: (query: string) => Promise; + error: string; +} + +const QueryForm: React.FC = ({ handleSubmit, error = "" }) => { + const [query, setQuery] = useState(""); + const [isSubmitting, setIsSubmitting] = useState(false); + + const handleClick = async (query: string) => { + try { + setIsSubmitting(true); + await handleSubmit(query); + setQuery(""); + } catch (error) { + } finally { + setIsSubmitting(false); + } + }; + + return ( +
+ {error && {error}} +
+
+ setQuery(e.target.value)} + /> + +
+
+
+ ); +}; + +export default QueryForm; \ No newline at end of file diff --git a/pkg_client/src/contexts/UserContext.tsx b/pkg_client/src/contexts/UserContext.tsx index 0e00073..15fb0f2 100644 --- a/pkg_client/src/contexts/UserContext.tsx +++ b/pkg_client/src/contexts/UserContext.tsx @@ -9,9 +9,16 @@ type UserProviderProps = { children: React.ReactNode; }; -export const UserContext = React.createContext<{ user: User | null; setUser: React.Dispatch>; }>({ user: null, setUser: () => { } }); +export const UserContext = React.createContext<{ + user: User | null; + setUser: React.Dispatch>; +}>({ user: null, setUser: () => { } }); -export const UserProvider: React.FC = ({ children, }: { children: React.ReactNode }) => { +export const UserProvider: React.FC = ({ + children, +}: { + children: React.ReactNode +}) => { const [user, setUser] = useState(null); return ( From 899debc08d11f5157bdf6aeae18608edd1537c9f Mon Sep 17 00:00:00 2001 From: WerLaj Date: Sat, 3 Feb 2024 09:24:26 +0100 Subject: [PATCH 02/11] Fix typo --- pkg_client/src/components/PKGVisualization.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg_client/src/components/PKGVisualization.tsx b/pkg_client/src/components/PKGVisualization.tsx index e75c8bd..de707be 100644 --- a/pkg_client/src/components/PKGVisualization.tsx +++ b/pkg_client/src/components/PKGVisualization.tsx @@ -33,7 +33,7 @@ const PKGVisualization = () => { const executeQuery = (query: string) => { return axios - .post(`${baseURL}/execute`, { + .post(`${baseURL}/explore`, { query: query, username: user?.username, user_uri: user?.uri, From 9548c334b52f29b554121c8df9886b9741e99651 Mon Sep 17 00:00:00 2001 From: Nolwenn <28621493+NoB0@users.noreply.github.com> Date: Sun, 4 Feb 2024 22:10:04 +0100 Subject: [PATCH 03/11] Small fixes --- pkg_api/server/pkg_exploration.py | 16 +-- .../src/components/PKGVisualization.tsx | 127 ++++++++++-------- 2 files changed, 77 insertions(+), 66 deletions(-) diff --git a/pkg_api/server/pkg_exploration.py b/pkg_api/server/pkg_exploration.py index bc16f67..90ecb2f 100644 --- a/pkg_api/server/pkg_exploration.py +++ b/pkg_api/server/pkg_exploration.py @@ -1,20 +1,21 @@ """PKG Exploration Resource.""" from typing import Any, Dict, Tuple -from flask import request +import flask +from flask import Response, request from flask_restful import Resource from pkg_api.server.utils import open_pkg, parse_query_request_data class PKGExplorationResource(Resource): - def get(self) -> Tuple[Dict[str, Any], int]: + def get(self) -> Response: """Returns the PKG visualization. Returns: - A dictionary with the path to PKG visualization and the status code. + A response containing the image of the PKG graph. """ - data = request.json + data = dict(request.args) try: pkg = open_pkg(data) except Exception as e: @@ -23,10 +24,7 @@ def get(self) -> Tuple[Dict[str, Any], int]: graph_img_path = pkg.visualize_graph() pkg.close() - return { - "message": "PKG visualized successfully.", - "img_path": graph_img_path, - }, 200 + return flask.send_file(graph_img_path, mimetype="image/png") def post(self) -> Tuple[Dict[str, Any], int]: """Executes the SPARQL query. @@ -45,6 +43,8 @@ def post(self) -> Tuple[Dict[str, Any], int]: if "SELECT" in sparql_query: result = str(pkg.execute_sparql_query(sparql_query)) + # TODO: Update pkg.visualize_graph() to return partial graph based + # on the query result else: return { "message": ( diff --git a/pkg_client/src/components/PKGVisualization.tsx b/pkg_client/src/components/PKGVisualization.tsx index de707be..57f3825 100644 --- a/pkg_client/src/components/PKGVisualization.tsx +++ b/pkg_client/src/components/PKGVisualization.tsx @@ -2,71 +2,82 @@ import { Container } from "react-bootstrap"; import { UserContext } from "../contexts/UserContext"; -import { useContext, useState } from "react"; +import { useContext, useEffect, useState } from "react"; import axios from "axios"; import QueryForm from "./QueryForm"; -import Button from 'react-bootstrap/Button'; +import Button from "react-bootstrap/Button"; const PKGVisualization = () => { - const { user } = useContext(UserContext); - const [error, setError] = useState(""); - const [image_path, setImagePath] = useState(""); - const [image_info, setImageInfo] = useState(""); - const [query_info, setQueryInfo] = useState(""); - const [result, setResult] = useState(""); - const baseURL = - (window as any)["PKG_API_BASE_URL"] || "http://127.0.0.1:5000"; + const { user } = useContext(UserContext); + const [error, setError] = useState(""); + const [image_path, setImagePath] = useState(""); + const [query_info, setQueryInfo] = useState(""); + const [result, setResult] = useState(""); + const baseURL = + (window as any)["PKG_API_BASE_URL"] || "http://127.0.0.1:5000"; - const getImagePath = () => { - axios.get(`${baseURL}/explore`, {}) - .then((response) => { - setError(""); - console.log(response.data.message); - setImageInfo(response.data.message); - setImagePath(response.data.img_path); - }) - .catch((error) => { - setError(error.message); - throw error; - }); - }; + useEffect(() => { + getImage(); + }, []); - const executeQuery = (query: string) => { - return axios - .post(`${baseURL}/explore`, { - query: query, - username: user?.username, - user_uri: user?.uri, - }) - .then((response) => { - setError(""); - console.log(response.data.message); - setQueryInfo(response.data.message); - setResult(response.data.result); - }) - .catch((error) => { - setError(error.message); - throw error; - }); - }; + const getImage = () => { + axios + .get(`${baseURL}/explore`, { + params: { + owner_username: user?.username, + owner_uri: user?.uri, + }, + responseType: "blob", + }) + .then((response) => { + setError(""); + const imageURL = URL.createObjectURL( + new Blob([response.data], { + type: "image/png", + }) + ); + setImagePath(imageURL); + }) + .catch((error) => { + setError(error.message); + throw error; + }); + }; - return ( - -
- Here you can execute your own SPARQL queries to manage your PKG. -
{image_info}
-
- -
Query execution status: {query_info}
-
Query execution result: {result}
-
- This is your current PKG: -
-
[Only for testing] Local path to the image: {image_path}
- PKG -
- ); + const executeQuery = (query: string) => { + return axios + .post(`${baseURL}/explore`, { + sparql_query: query, + owner_username: user?.username, + owner_uri: user?.uri, + }) + .then((response) => { + setError(""); + console.log(response.data); + setQueryInfo(response.data.message); + setResult(response.data.result); + }) + .catch((error) => { + setError(error.message); + throw error; + }); + }; + return ( + +
+ Here you can execute your own SPARQL queries to manage your PKG. +
+ +
Query execution status: {query_info}
+
Query execution result: {result}
+
+ This is your current PKG: +
+
[Only for testing] Local path to the image: {image_path}
+ PKG +
+ ); }; -export default PKGVisualization; \ No newline at end of file +export default PKGVisualization; From 9fb18f64fc1ce4a08e892a778244ec40012f152a Mon Sep 17 00:00:00 2001 From: WerLaj Date: Mon, 5 Feb 2024 05:37:09 +0100 Subject: [PATCH 04/11] Fixes in image path --- pkg_api/core/namespaces.py | 2 +- pkg_api/pkg.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg_api/core/namespaces.py b/pkg_api/core/namespaces.py index d5c29f6..93d65b7 100644 --- a/pkg_api/core/namespaces.py +++ b/pkg_api/core/namespaces.py @@ -15,7 +15,7 @@ class PKGPrefixes(Enum): DCAT = "http://www.w3.org/ns/dcat#" DOAP = "http://usefulinc.com/ns/doap#" EVENT = "http://purl.org/NET/c4dm/event.owl#" - EX = "http://example.com#" + EX = "http://example.org/pkg#" FOAF = "http://xmlns.com/foaf/0.1/" GEO = "http://www.w3.org/2003/01/geo/wgs84_pos#" OWL = "http://www.w3.org/2002/07/owl#" diff --git a/pkg_api/pkg.py b/pkg_api/pkg.py index 81135cd..a27c121 100644 --- a/pkg_api/pkg.py +++ b/pkg_api/pkg.py @@ -161,8 +161,8 @@ def visualize_graph(self) -> str: owner_name = "" for _, namespace in PKGPrefixes.__members__.items(): - if namespace.value in str(self._owner_uri): - owner_name = self._owner_uri.replace(str(namespace.value), "") + if namespace.value.replace("#", "") in str(self._owner_uri): + owner_name = self._owner_uri.replace(str(namespace.value.replace("#", "")), "") path = self._visualization_path + "/" + owner_name + ".png" From 1742a73756f3a2a7c8a5b040701cb142b8adc12b Mon Sep 17 00:00:00 2001 From: WerLaj Date: Mon, 5 Feb 2024 06:33:10 +0100 Subject: [PATCH 05/11] Query execution fixed and image path fixed --- pkg_api/pkg.py | 6 +- pkg_api/server/pkg_exploration.py | 4 +- .../src/components/PKGVisualization.tsx | 132 +++++++++--------- 3 files changed, 72 insertions(+), 70 deletions(-) diff --git a/pkg_api/pkg.py b/pkg_api/pkg.py index a27c121..270ccdb 100644 --- a/pkg_api/pkg.py +++ b/pkg_api/pkg.py @@ -9,6 +9,7 @@ """ import io +import os from typing import Dict, Optional import pydotplus @@ -22,7 +23,8 @@ from pkg_api.core.namespaces import PKGPrefixes from pkg_api.core.pkg_types import URI -DEFAULT_VISUALIZATION_PATH = "data/pkg_visualizations" +ROOT_DIR = os.path.dirname(os.path.abspath(os.path.dirname(os.path.abspath(__file__)))) +DEFAULT_VISUALIZATION_PATH = ROOT_DIR + "/data/pkg_visualizations" class PKG: @@ -162,7 +164,7 @@ def visualize_graph(self) -> str: for _, namespace in PKGPrefixes.__members__.items(): if namespace.value.replace("#", "") in str(self._owner_uri): - owner_name = self._owner_uri.replace(str(namespace.value.replace("#", "")), "") + owner_name = self._owner_uri.replace(str(namespace.value.replace("#", "")), "").replace("/", "") path = self._visualization_path + "/" + owner_name + ".png" diff --git a/pkg_api/server/pkg_exploration.py b/pkg_api/server/pkg_exploration.py index 90ecb2f..7c49b33 100644 --- a/pkg_api/server/pkg_exploration.py +++ b/pkg_api/server/pkg_exploration.py @@ -42,7 +42,7 @@ def post(self) -> Tuple[Dict[str, Any], int]: sparql_query = parse_query_request_data(data) if "SELECT" in sparql_query: - result = str(pkg.execute_sparql_query(sparql_query)) + result = pkg.execute_sparql_query(sparql_query) # TODO: Update pkg.visualize_graph() to return partial graph based # on the query result else: @@ -57,5 +57,5 @@ def post(self) -> Tuple[Dict[str, Any], int]: return { "message": "SPARQL query executed successfully.", - "data": result, + "result": str(result.bindings), }, 200 diff --git a/pkg_client/src/components/PKGVisualization.tsx b/pkg_client/src/components/PKGVisualization.tsx index 57f3825..3b4e79d 100644 --- a/pkg_client/src/components/PKGVisualization.tsx +++ b/pkg_client/src/components/PKGVisualization.tsx @@ -8,76 +8,76 @@ import QueryForm from "./QueryForm"; import Button from "react-bootstrap/Button"; const PKGVisualization = () => { - const { user } = useContext(UserContext); - const [error, setError] = useState(""); - const [image_path, setImagePath] = useState(""); - const [query_info, setQueryInfo] = useState(""); - const [result, setResult] = useState(""); - const baseURL = - (window as any)["PKG_API_BASE_URL"] || "http://127.0.0.1:5000"; + const { user } = useContext(UserContext); + const [error, setError] = useState(""); + const [image_path, setImagePath] = useState(""); + const [query_info, setQueryInfo] = useState(""); + const [result, setResult] = useState(""); + const baseURL = + (window as any)["PKG_API_BASE_URL"] || "http://127.0.0.1:5000"; - useEffect(() => { - getImage(); - }, []); + useEffect(() => { + getImage(); + }, []); - const getImage = () => { - axios - .get(`${baseURL}/explore`, { - params: { - owner_username: user?.username, - owner_uri: user?.uri, - }, - responseType: "blob", - }) - .then((response) => { - setError(""); - const imageURL = URL.createObjectURL( - new Blob([response.data], { - type: "image/png", - }) - ); - setImagePath(imageURL); - }) - .catch((error) => { - setError(error.message); - throw error; - }); - }; + const getImage = () => { + axios + .get(`${baseURL}/explore`, { + params: { + owner_username: user?.username, + owner_uri: user?.uri, + }, + responseType: "blob", + }) + .then((response) => { + setError(""); + const imageURL = URL.createObjectURL( + new Blob([response.data], { + type: "image/png", + }) + ); + setImagePath(imageURL); + }) + .catch((error) => { + setError(error.message); + throw error; + }); + }; - const executeQuery = (query: string) => { - return axios - .post(`${baseURL}/explore`, { - sparql_query: query, - owner_username: user?.username, - owner_uri: user?.uri, - }) - .then((response) => { - setError(""); - console.log(response.data); - setQueryInfo(response.data.message); - setResult(response.data.result); - }) - .catch((error) => { - setError(error.message); - throw error; - }); - }; + const executeQuery = (query: string) => { + return axios + .post(`${baseURL}/explore`, { + sparql_query: query, + owner_username: user?.username, + owner_uri: user?.uri, + }) + .then((response) => { + setError(""); + console.log(response.data); + setQueryInfo(response.data.message); + setResult(response.data.result); + }) + .catch((error) => { + setError(error.message); + throw error; + }); + }; - return ( - -
- Here you can execute your own SPARQL queries to manage your PKG. -
- -
Query execution status: {query_info}
-
Query execution result: {result}
-
- This is your current PKG: -
-
[Only for testing] Local path to the image: {image_path}
- PKG -
- ); + return ( + +
+ Here you can execute your own SPARQL queries to manage your PKG. +
+ +
Query execution status: {query_info}
+
Query execution result: {result}
+
+ This is your current PKG: +
+ {/*
[Only for testing] Local path to the image: {image_path}
*/} + PKG +
+ ); }; export default PKGVisualization; From aab37c6df871c92fe04e7432f424cf1a1ee0afe8 Mon Sep 17 00:00:00 2001 From: WerLaj Date: Mon, 5 Feb 2024 11:00:22 +0100 Subject: [PATCH 06/11] Example namespace fixed --- pkg_api/core/namespaces.py | 2 +- pkg_api/pkg.py | 6 ++++-- pkg_api/server/auth.py | 2 +- pkg_api/server/pkg_exploration.py | 4 ++-- pkg_client/src/components/PKGVisualization.tsx | 2 +- tests/pkg_api/server/test_auth.py | 4 ++-- tests/pkg_api/server/test_pkg_exploration.py | 11 ++++++++--- 7 files changed, 19 insertions(+), 12 deletions(-) diff --git a/pkg_api/core/namespaces.py b/pkg_api/core/namespaces.py index 93d65b7..d5c29f6 100644 --- a/pkg_api/core/namespaces.py +++ b/pkg_api/core/namespaces.py @@ -15,7 +15,7 @@ class PKGPrefixes(Enum): DCAT = "http://www.w3.org/ns/dcat#" DOAP = "http://usefulinc.com/ns/doap#" EVENT = "http://purl.org/NET/c4dm/event.owl#" - EX = "http://example.org/pkg#" + EX = "http://example.com#" FOAF = "http://xmlns.com/foaf/0.1/" GEO = "http://www.w3.org/2003/01/geo/wgs84_pos#" OWL = "http://www.w3.org/2002/07/owl#" diff --git a/pkg_api/pkg.py b/pkg_api/pkg.py index 270ccdb..97982ef 100644 --- a/pkg_api/pkg.py +++ b/pkg_api/pkg.py @@ -163,8 +163,10 @@ def visualize_graph(self) -> str: owner_name = "" for _, namespace in PKGPrefixes.__members__.items(): - if namespace.value.replace("#", "") in str(self._owner_uri): - owner_name = self._owner_uri.replace(str(namespace.value.replace("#", "")), "").replace("/", "") + if namespace.value in str(self._owner_uri): + owner_name = self._owner_uri.replace( + str(namespace.value), "" + ) path = self._visualization_path + "/" + owner_name + ".png" diff --git a/pkg_api/server/auth.py b/pkg_api/server/auth.py index 28a4623..48ae802 100644 --- a/pkg_api/server/auth.py +++ b/pkg_api/server/auth.py @@ -10,7 +10,7 @@ # TODO: Retrieve namespace from the mapping class # See issue: https://github.com/iai-group/pkg-api/issues/13 -NS = "http://example.org/pkg/" +NS = "http://example.com#" def create_user_uri(username: str) -> str: diff --git a/pkg_api/server/pkg_exploration.py b/pkg_api/server/pkg_exploration.py index 7c49b33..85a8da8 100644 --- a/pkg_api/server/pkg_exploration.py +++ b/pkg_api/server/pkg_exploration.py @@ -1,5 +1,5 @@ """PKG Exploration Resource.""" -from typing import Any, Dict, Tuple +from typing import Any, Dict, Tuple, Union import flask from flask import Response, request @@ -9,7 +9,7 @@ class PKGExplorationResource(Resource): - def get(self) -> Response: + def get(self) -> Union[Response, Tuple[Dict[str, Any], int]]: """Returns the PKG visualization. Returns: diff --git a/pkg_client/src/components/PKGVisualization.tsx b/pkg_client/src/components/PKGVisualization.tsx index 3b4e79d..346d28b 100644 --- a/pkg_client/src/components/PKGVisualization.tsx +++ b/pkg_client/src/components/PKGVisualization.tsx @@ -75,7 +75,7 @@ const PKGVisualization = () => { This is your current PKG: {/*
[Only for testing] Local path to the image: {image_path}
*/} - PKG + PKG ); }; diff --git a/tests/pkg_api/server/test_auth.py b/tests/pkg_api/server/test_auth.py index 93d446f..6aac06d 100644 --- a/tests/pkg_api/server/test_auth.py +++ b/tests/pkg_api/server/test_auth.py @@ -20,7 +20,7 @@ def test_auth_endpoint_register(client) -> None: ) assert response.status_code == 200 assert response.get_json() == { - "user": {"username": "user1", "uri": "http://example.org/pkg/user1"}, + "user": {"username": "user1", "uri": "http://example.com#user1"}, "message": "Login successful", } @@ -51,7 +51,7 @@ def test_auth_endpoint_login(client) -> None: ) assert response.status_code == 200 assert response.get_json() == { - "user": {"username": "user1", "uri": "http://example.org/pkg/user1"}, + "user": {"username": "user1", "uri": "http://example.com#user1"}, "message": "Login successful", } diff --git a/tests/pkg_api/server/test_pkg_exploration.py b/tests/pkg_api/server/test_pkg_exploration.py index 5cffe0d..02e5a98 100644 --- a/tests/pkg_api/server/test_pkg_exploration.py +++ b/tests/pkg_api/server/test_pkg_exploration.py @@ -1,6 +1,7 @@ """Tests for the pkg exploration endpoints.""" import os +from io import StringIO from flask import Flask @@ -56,6 +57,7 @@ def test_pkg_visualization(client: Flask) -> None: os.makedirs("tests/data/pkg_visualizations/", exist_ok=True) if not os.path.exists("tests/data/RDFStore/"): os.makedirs("tests/data/RDFStore/", exist_ok=True) + response = client.get( "/explore", json={ @@ -63,9 +65,12 @@ def test_pkg_visualization(client: Flask) -> None: "owner_username": "test", }, ) - assert response.status_code == 200 - assert response.json["message"] == "PKG visualized successfully." - assert response.json["img_path"] == "tests/data/pkg_visualizations/test.png" + + with open("tests/data/pkg_visualizations/test.png", "rb") as img: + test_image = StringIO(img.read()) + test_image.seek(0) + + assert response.data == test_image.read() def test_pkg_sparql_query(client: Flask) -> None: From a91614f4705f49deac29c7cf6a4335daaba05481 Mon Sep 17 00:00:00 2001 From: WerLaj Date: Mon, 5 Feb 2024 11:09:11 +0100 Subject: [PATCH 07/11] Fix black issues --- pkg_api/pkg.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg_api/pkg.py b/pkg_api/pkg.py index 97982ef..5340909 100644 --- a/pkg_api/pkg.py +++ b/pkg_api/pkg.py @@ -23,7 +23,9 @@ from pkg_api.core.namespaces import PKGPrefixes from pkg_api.core.pkg_types import URI -ROOT_DIR = os.path.dirname(os.path.abspath(os.path.dirname(os.path.abspath(__file__)))) +ROOT_DIR = os.path.dirname( + os.path.abspath(os.path.dirname(os.path.abspath(__file__))) +) DEFAULT_VISUALIZATION_PATH = ROOT_DIR + "/data/pkg_visualizations" @@ -164,9 +166,7 @@ def visualize_graph(self) -> str: for _, namespace in PKGPrefixes.__members__.items(): if namespace.value in str(self._owner_uri): - owner_name = self._owner_uri.replace( - str(namespace.value), "" - ) + owner_name = self._owner_uri.replace(str(namespace.value), "") path = self._visualization_path + "/" + owner_name + ".png" From a7eeeaa91f2893f5042ad62755986d313df08981 Mon Sep 17 00:00:00 2001 From: WerLaj Date: Thu, 8 Feb 2024 09:41:33 +0100 Subject: [PATCH 08/11] Fixes in visualization test --- tests/pkg_api/server/test_pkg_exploration.py | 39 ++++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/tests/pkg_api/server/test_pkg_exploration.py b/tests/pkg_api/server/test_pkg_exploration.py index 02e5a98..a4d79f8 100644 --- a/tests/pkg_api/server/test_pkg_exploration.py +++ b/tests/pkg_api/server/test_pkg_exploration.py @@ -3,8 +3,26 @@ import os from io import StringIO +import pytest from flask import Flask +from pkg_api.connector import RDFStore +from pkg_api.core.annotation import PKGData, Triple, TripleElement +from pkg_api.core.pkg_types import URI +from pkg_api.pkg import PKG +from pkg_api.server import create_app + + +@pytest.fixture +def user_pkg() -> PKG: + """Returns a PKG instance.""" + return PKG( + "http://example.com#test", + RDFStore.MEMORY, + "tests/data/RDFStore/test", + "tests/data/pkg_visualizations", + ) + def test_pkg_exploration_endpoint_errors(client: Flask) -> None: """Tests /explore endpoints with invalid data.""" @@ -51,16 +69,29 @@ def test_pkg_exploration_endpoint_errors(client: Flask) -> None: ) -def test_pkg_visualization(client: Flask) -> None: +def test_pkg_visualization(client: Flask, user_pkg: PKG) -> None: """Tests the GET /explore endpoint.""" if not os.path.exists("tests/data/pkg_visualizations/"): os.makedirs("tests/data/pkg_visualizations/", exist_ok=True) - if not os.path.exists("tests/data/RDFStore/"): - os.makedirs("tests/data/RDFStore/", exist_ok=True) + + pkg_data = PKGData( + statement="I live in Stavanger.", + triple=Triple( + TripleElement("I", URI("http://example.com#test")), + TripleElement("live", "live"), + TripleElement( + "Stavanger", URI("https://dbpedia.org/page/Stavanger") + ), + ), + logging_data={"authoredBy": URI("http://example.com#test")}, + ) + + user_pkg.add_statement(pkg_data) + user_pkg._connector.save_graph() response = client.get( "/explore", - json={ + query_string={ "owner_uri": "http://example.com#test", "owner_username": "test", }, From f0a9bf51cb77737564ad7aa86278b4b1862c0380 Mon Sep 17 00:00:00 2001 From: WerLaj Date: Thu, 8 Feb 2024 09:44:19 +0100 Subject: [PATCH 09/11] Fixes in visualization test --- tests/pkg_api/server/test_pkg_exploration.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/pkg_api/server/test_pkg_exploration.py b/tests/pkg_api/server/test_pkg_exploration.py index a4d79f8..7fd504f 100644 --- a/tests/pkg_api/server/test_pkg_exploration.py +++ b/tests/pkg_api/server/test_pkg_exploration.py @@ -10,7 +10,6 @@ from pkg_api.core.annotation import PKGData, Triple, TripleElement from pkg_api.core.pkg_types import URI from pkg_api.pkg import PKG -from pkg_api.server import create_app @pytest.fixture From ff155dc199f59a4a3a900057359738332dbe7201 Mon Sep 17 00:00:00 2001 From: WerLaj Date: Thu, 8 Feb 2024 09:48:12 +0100 Subject: [PATCH 10/11] Fixes in visualization test --- tests/pkg_api/server/test_pkg_exploration.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/pkg_api/server/test_pkg_exploration.py b/tests/pkg_api/server/test_pkg_exploration.py index 7fd504f..34309df 100644 --- a/tests/pkg_api/server/test_pkg_exploration.py +++ b/tests/pkg_api/server/test_pkg_exploration.py @@ -74,6 +74,7 @@ def test_pkg_visualization(client: Flask, user_pkg: PKG) -> None: os.makedirs("tests/data/pkg_visualizations/", exist_ok=True) pkg_data = PKGData( + id="f47ac10b-34fd-4372-a567-0e02b2c3d479", statement="I live in Stavanger.", triple=Triple( TripleElement("I", URI("http://example.com#test")), From ff2fa8b5a58cfedeb5267c981499871881292703 Mon Sep 17 00:00:00 2001 From: WerLaj Date: Thu, 8 Feb 2024 09:53:13 +0100 Subject: [PATCH 11/11] Fixes in visualization test --- tests/pkg_api/server/test_pkg_exploration.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/pkg_api/server/test_pkg_exploration.py b/tests/pkg_api/server/test_pkg_exploration.py index 34309df..6640d49 100644 --- a/tests/pkg_api/server/test_pkg_exploration.py +++ b/tests/pkg_api/server/test_pkg_exploration.py @@ -72,6 +72,8 @@ def test_pkg_visualization(client: Flask, user_pkg: PKG) -> None: """Tests the GET /explore endpoint.""" if not os.path.exists("tests/data/pkg_visualizations/"): os.makedirs("tests/data/pkg_visualizations/", exist_ok=True) + if not os.path.exists("tests/data/RDFStore/"): + os.makedirs("tests/data/RDFStore/", exist_ok=True) pkg_data = PKGData( id="f47ac10b-34fd-4372-a567-0e02b2c3d479",