From 76af056945f8548349ff89c0820ba0d00a41e3df Mon Sep 17 00:00:00 2001 From: Spyros Date: Tue, 9 Jan 2024 19:45:55 +0000 Subject: [PATCH] Mv deeplink to server (#480) * move deeplink serverside * lint --- application/frontend/src/const.ts | 1 - .../frontend/src/pages/Deeplink/Deeplink.tsx | 90 ------------------- application/frontend/src/routes.tsx | 32 ------- application/tests/web_main_test.py | 84 +++++++++++++---- application/web/web_main.py | 18 +++- 5 files changed, 85 insertions(+), 140 deletions(-) delete mode 100644 application/frontend/src/pages/Deeplink/Deeplink.tsx diff --git a/application/frontend/src/const.ts b/application/frontend/src/const.ts index 3dd4890c..01e3896c 100644 --- a/application/frontend/src/const.ts +++ b/application/frontend/src/const.ts @@ -36,7 +36,6 @@ export const SUBSECTION = '/subsection'; export const SEARCH = '/search'; export const CRE = '/cre'; export const GRAPH = '/graph'; -export const DEEPLINK = '/deeplink'; export const BROWSEROOT = '/root_cres'; export const GAP_ANALYSIS = '/map_analysis'; export const EXPLORER = '/explorer'; diff --git a/application/frontend/src/pages/Deeplink/Deeplink.tsx b/application/frontend/src/pages/Deeplink/Deeplink.tsx deleted file mode 100644 index 03d10f7c..00000000 --- a/application/frontend/src/pages/Deeplink/Deeplink.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import axios from 'axios'; -import React, { useEffect, useState } from 'react'; -import { useLocation, useParams } from 'react-router-dom'; - -import { LoadingAndErrorIndicator } from '../../components/LoadingAndErrorIndicator'; -import { useEnvironment } from '../../hooks'; -import { Document } from '../../types'; - -export const Deeplink = () => { - let { type, nodeName, section, subsection, tooltype, sectionID, sectionid } = useParams(); - const { apiUrl } = useEnvironment(); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [data, setData] = useState(); - const search = useLocation().search; - section = section ? section : new URLSearchParams(search).get('section'); - subsection = subsection ? subsection : new URLSearchParams(search).get('subsection'); - tooltype = tooltype ? tooltype : new URLSearchParams(search).get('tooltype'); - sectionID = sectionID ? sectionID : new URLSearchParams(search).get('sectionID'); - sectionid = sectionID ? sectionID : new URLSearchParams(search).get('sectionid'); - if (!type) { - // Backwards compatible fix, the url used to be /deeplink/:nodename, new url is /deeplink/:type/:nodename - type = 'Standard'; - } - - var apiCall = new URL(`${apiUrl}/${type}/${nodeName}`); - - if (section != null) { - apiCall.searchParams.append('section', section); - } - if (subsection != null) { - apiCall.searchParams.append('subsection', subsection); - } - if (tooltype != null) { - apiCall.searchParams.append('tooltype', tooltype); - } - if (sectionID != null) { - apiCall.searchParams.append('sectionID', sectionID); - } else if (sectionid != null) { - apiCall.searchParams.append('sectionID', sectionid); - } - useEffect(() => { - window.scrollTo(0, 0); - setLoading(true); - axios - .get(apiCall.toString()) - .then(function (response) { - setError(null); - setData(response.data?.standards); - }) - .catch(function (axiosError) { - if (axiosError.response.status === 404) { - setError('Standard does not exist, please check your search parameters'); - } else { - setError(axiosError.response); - } - }) - .finally(() => { - setLoading(false); - }); - }, [type, nodeName]); - const documents = data || []; - - var redirectTo = window.location.href; - if (documents) { - for (const standard of documents) { - if (standard.hyperlink && standard.hyperlink?.length > 0) { - redirectTo = standard.hyperlink; - } - } - } - if (!error && !loading && redirectTo != window.location.href) { - return ( -
-

{nodeName}

- -

Redirecting to:

- {window.location.href} - {(window.location.href = redirectTo)} -
- ); - } else { - return ( -
-

{nodeName}

- -
- ); - } -}; diff --git a/application/frontend/src/routes.tsx b/application/frontend/src/routes.tsx index c7a1431f..b5c4c977 100644 --- a/application/frontend/src/routes.tsx +++ b/application/frontend/src/routes.tsx @@ -3,7 +3,6 @@ import { ReactNode } from 'react'; import { BROWSEROOT, CRE, - DEEPLINK, EXPLORER, GAP_ANALYSIS, GRAPH, @@ -16,7 +15,6 @@ import { import { CommonRequirementEnumeration, Graph, Search, Standard } from './pages'; import { BrowseRootCres } from './pages/BrowseRootCres/browseRootCres'; import { Chatbot } from './pages/chatbot/chatbot'; -import { Deeplink } from './pages/Deeplink/Deeplink'; import { Explorer } from './pages/Explorer/explorer'; import { ExplorerCircles } from './pages/Explorer/visuals/circles/circles'; import { ExplorerForceGraph } from './pages/Explorer/visuals/force-graph/forceGraph'; @@ -81,36 +79,6 @@ export const ROUTES: IRoute[] = [ showHeader: true, showFilter: true, }, - { - path: `${DEEPLINK}/node/:type/:nodeName/section/:section`, - component: Deeplink, - showHeader: true, - showFilter: false, - }, - { - path: `${DEEPLINK}/node/:type/:nodeName/section/:section/subsection/:subsection`, - component: Deeplink, - showHeader: true, - showFilter: false, - }, - { - path: `${DEEPLINK}/node/:type/:nodeName/tooltype/:tooltype`, - component: Deeplink, - showHeader: true, - showFilter: false, - }, - { - path: `${DEEPLINK}/node/:type/:nodeName`, - component: Deeplink, - showHeader: true, - showFilter: false, - }, - { - path: `${DEEPLINK}/:nodeName`, - component: Deeplink, - showHeader: true, - showFilter: false, - }, { path: `/chatbot`, component: Chatbot, diff --git a/application/tests/web_main_test.py b/application/tests/web_main_test.py index d1f144df..f3e722cc 100644 --- a/application/tests/web_main_test.py +++ b/application/tests/web_main_test.py @@ -726,6 +726,16 @@ def test_deeplink(self) -> None: ) self.assertEqual(404, response.status_code) + response = client.get( + f"/deeplink/{''.join(random.choice(string.ascii_letters) for i in range(10))}", + ) + self.assertEqual(404, response.status_code) + + response = client.get( + f"/deeplink/standard/{''.join(random.choice(string.ascii_letters) for i in range(10))}", + ) + self.assertEqual(404, response.status_code) + cres = { "ca": defs.CRE(id="1", description="CA", name="CA", tags=["ta"]), "cd": defs.CRE(id="2", description="CD", name="CD", tags=["td"]), @@ -771,38 +781,82 @@ def test_deeplink(self) -> None: response = client.get("/rest/v1/deeplink/CWE?sectionid=456") self.assertEqual(404, response.status_code) + # rest/v1 path works response = client.get("/rest/v1/deeplink/ASVS?sectionid=v0.1.2") - location = "" for head in response.headers: if head[0] == "Location": - location = head[1] - self.assertEqual(location, standards["ASVS"].hyperlink) + self.assertEqual(head[1], standards["ASVS"].hyperlink) self.assertEqual(302, response.status_code) - response = client.get("/rest/v1/deeplink/ASVS?sectionID=v0.1.2") - location = "" + # Can retrieve with sectionid + response = client.get("/deeplink/ASVS?sectionid=v0.1.2") for head in response.headers: if head[0] == "Location": - location = head[1] - self.assertEqual(location, standards["ASVS"].hyperlink) + self.assertEqual(head[1], standards["ASVS"].hyperlink) self.assertEqual(302, response.status_code) + # Can retrieve with sectionID + response = client.get("/deeplink/ASVS?sectionID=v0.1.2") + for head in response.headers: + if head[0] == "Location": + self.assertEqual(head[1], standards["ASVS"].hyperlink) + self.assertEqual(302, response.status_code) + + # Can retrieve with section + response = client.get(f'/deeplink/ASVS?section={standards["ASVS"].section}') + for head in response.headers: + if head[0] == "Location": + self.assertEqual(head[1], standards["ASVS"].hyperlink) + self.assertEqual(302, response.status_code) + + # Can retrieve with section and sectionID/sectionid response = client.get( - f'/rest/v1/deeplink/ASVS?section={standards["ASVS"].section}' + f'/deeplink/ASVS?section={standards["ASVS"].section}§ionID={standards["ASVS"].sectionID}' ) - location = "" for head in response.headers: if head[0] == "Location": - location = head[1] - self.assertEqual(location, standards["ASVS"].hyperlink) + self.assertEqual(head[1], standards["ASVS"].hyperlink) self.assertEqual(302, response.status_code) + # Can retrieve with sectionid in path params response = client.get( - f'/rest/v1/deeplink/ASVS?section={standards["ASVS"].section}§ionID={standards["ASVS"].sectionID}' + f'/deeplink/ASVS/sectionid/{standards["ASVS"].sectionID}' ) - location = "" for head in response.headers: if head[0] == "Location": - location = head[1] - self.assertEqual(location, standards["ASVS"].hyperlink) + self.assertEqual(head[1], standards["ASVS"].hyperlink) + self.assertEqual(302, response.status_code) + + # Can retrieve with sectionID in path params + response = client.get( + f'/deeplink/ASVS/sectionID/{standards["ASVS"].sectionID}' + ) + for head in response.headers: + if head[0] == "Location": + self.assertEqual(head[1], standards["ASVS"].hyperlink) + self.assertEqual(302, response.status_code) + + # Can retrieve with section in path params + response = client.get(f'/deeplink/ASVS/section/{standards["ASVS"].section}') + for head in response.headers: + if head[0] == "Location": + self.assertEqual(head[1], standards["ASVS"].hyperlink) + self.assertEqual(302, response.status_code) + + # Can retrieve with section and sectionid in path params + response = client.get( + f'/deeplink/ASVS/section/{standards["ASVS"].section}/sectionid/{standards["ASVS"].sectionID}' + ) + for head in response.headers: + if head[0] == "Location": + self.assertEqual(head[1], standards["ASVS"].hyperlink) + self.assertEqual(302, response.status_code) + + # Can retrieve with section and sectionID in path params + response = client.get( + f'/deeplink/ASVS/section/{standards["ASVS"].section}/sectionID/{standards["ASVS"].sectionID}' + ) + for head in response.headers: + if head[0] == "Location": + self.assertEqual(head[1], standards["ASVS"].hyperlink) self.assertEqual(302, response.status_code) diff --git a/application/web/web_main.py b/application/web/web_main.py index 6d3e35b7..49e43bb5 100644 --- a/application/web/web_main.py +++ b/application/web/web_main.py @@ -518,7 +518,16 @@ def smartlink( @app.route("/rest/v1/deeplink//", methods=["GET"]) @app.route("/rest/v1/deeplink/", methods=["GET"]) -def deeplink(name: str, ntype: str = "") -> Any: +@app.route("/deeplink//", methods=["GET"]) +@app.route("/deeplink/", methods=["GET"]) +@app.route("/deeplink//section/
", methods=["GET"]) +@app.route("/deeplink//section/
/sectionid/", methods=["GET"]) +@app.route("/deeplink//section/
/sectionID/", methods=["GET"]) +@app.route("/deeplink//sectionid/", methods=["GET"]) +@app.route("/deeplink//sectionID/", methods=["GET"]) +def deeplink( + name: str, ntype: str = "", section: str = "", section_id: str = "" +) -> Any: database = db.Node_collection() opt_section = request.args.get("section") opt_sectionID = request.args.get("sectionID") @@ -528,10 +537,15 @@ def deeplink(name: str, ntype: str = "") -> Any: if opt_section: opt_section = urllib.parse.unquote(opt_section) + elif section: + opt_section = urllib.parse.unquote(section) + if opt_sectionID: opt_sectionID = urllib.parse.unquote(opt_sectionID) elif opt_sectionid: opt_sectionID = urllib.parse.unquote(opt_sectionid) + elif section_id: + opt_sectionID = urllib.parse.unquote(section_id) nodes = None nodes = database.get_nodes( @@ -543,7 +557,7 @@ def deeplink(name: str, ntype: str = "") -> Any: ) for node in nodes: if len(node.hyperlink) > 0: - return redirect(node.hyperlink) + return redirect(location=node.hyperlink) return abort(404)