Skip to content

Commit

Permalink
Merge pull request #478 from datalad/relativity
Browse files Browse the repository at this point in the history
Allow serving catalog from a path relative to server root
  • Loading branch information
jsheunis authored Jun 12, 2024
2 parents b3771c5 + a19a631 commit b5985d9
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 39 deletions.
2 changes: 1 addition & 1 deletion datalad_catalog/catalog/assets/app_component_dataset.js
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ const datasetView = () =>
history.replaceState(
{},
null,
current_route.path + query_string
(router.options.base + current_route.path + query_string).replace("//", "/")
)
console.debug("- After: Vue Route query params: %s", JSON.stringify(Object.assign({}, this.$route.query)))
let url_qp2 = new URL(document.location.toString()).searchParams
Expand Down
8 changes: 4 additions & 4 deletions datalad_catalog/catalog/assets/app_globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// Data //
/********/

const template_dir = "/templates";
const config_file = "/config.json";
const metadata_dir = "/metadata";
const template_dir = "templates";
const config_file = "config.json";
const metadata_dir = "metadata";
const superdatasets_file = metadata_dir + "/super.json";
const SPLIT_INDEX = 3;
const SHORT_NAME_LENGTH = 0; // number of characters in name to display, zero if all
Expand All @@ -13,7 +13,7 @@ const default_config = {
catalog_url: "https://datalad-catalog.netlify.app/",
link_color: "#fba304",
link_hover_color: "#af7714",
logo_path: "/artwork/catalog_logo.svg",
logo_path: "artwork/catalog_logo.svg",
social_links: {
about: null,
documentation: "https://docs.datalad.org/projects/catalog/en/latest/",
Expand Down
2 changes: 1 addition & 1 deletion datalad_catalog/catalog/assets/app_router.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const routes = [
// Create router
const router = new VueRouter({
mode: 'history',
base: '/',
base: window.location.pathname.split('dataset/')[0],
routes: routes,
scrollBehavior(to, from, savedPosition) {
return { x: 0, y: 0, behavior: "auto" };
Expand Down
50 changes: 29 additions & 21 deletions datalad_catalog/catalog/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,34 @@
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">

<link rel="icon" href="/assets/favicon/favicon.ico" type="image/x-icon">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon/favicon-16x16.png">
<script>
// Dynamically set the base tag
const base = document.createElement('base');
const pathname = window.location.pathname.split('dataset/')[0];
base.href = pathname.endsWith('/') ? pathname : `${pathname}/`;
document.head.appendChild(base);
</script>

<link rel="icon" href="assets/favicon/favicon.ico" type="image/x-icon">
<link rel="icon" type="image/png" sizes="32x32" href="assets/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="assets/favicon/favicon-16x16.png">

<title>DataLad Catalog</title>

<!-- Required Stylesheets -->
<link rel="stylesheet" type="text/css" href="/assets/style.css"/>
<link rel="stylesheet" type="text/css" href="/assets/fontawesome.min.css"/>
<link rel="stylesheet" type="text/css" href="/assets/brands.min.css"/>
<link type="text/css" rel="stylesheet" href="/assets/bootstrap.5.1.3.min.css"/>
<link type="text/css" rel="stylesheet" href="/assets/bootstrap-vue.2.21.2.min.css"/>
<link rel="stylesheet" type="text/css" href="assets/style.css"/>
<link rel="stylesheet" type="text/css" href="assets/fontawesome.min.css"/>
<link rel="stylesheet" type="text/css" href="assets/brands.min.css"/>
<link type="text/css" rel="stylesheet" href="assets/bootstrap.5.1.3.min.css"/>
<link type="text/css" rel="stylesheet" href="assets/bootstrap-vue.2.21.2.min.css"/>

<!-- Required scripts -->
<!-- <script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script> -->
<script src="/assets/vue.2.6.14.min.js"></script>
<script src="/assets/bootstrap-vue.2.21.2.min.js"></script>
<script src="/assets/vue-router.3.5.3.min.js"></script>
<script src="/assets/md5-2.3.0.js"></script>
<script src="/assets/marked.4.0.17.min.js"></script>
<script src="assets/vue.2.6.14.min.js"></script>
<script src="assets/bootstrap-vue.2.21.2.min.js"></script>
<script src="assets/vue-router.3.5.3.min.js"></script>
<script src="assets/md5-2.3.0.js"></script>
<script src="assets/marked.4.0.17.min.js"></script>

</head>

Expand Down Expand Up @@ -74,13 +82,13 @@
<br>
</b-container>
<!-- Run the Vue app scripts - DO NOT CHANGE ORDER -->
<script src="/assets/app_globals.js"></script>
<script src="/assets/app_component_item.js"></script>
<script src="/assets/app_component_contexttab.js"></script>
<script src="/assets/app_component_dataset.js"></script>
<script src="/assets/app_component_about.js"></script>
<script src="/assets/app_component_notfound.js"></script>
<script src="/assets/app_router.js"></script>
<script src="/assets/app.js"></script>
<script src="assets/app_globals.js"></script>
<script src="assets/app_component_item.js"></script>
<script src="assets/app_component_contexttab.js"></script>
<script src="assets/app_component_dataset.js"></script>
<script src="assets/app_component_about.js"></script>
<script src="assets/app_component_notfound.js"></script>
<script src="assets/app_router.js"></script>
<script src="assets/app.js"></script>
</body>
</html>
4 changes: 2 additions & 2 deletions datalad_catalog/catalog/templates/dataset-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
alt="datalad_d" height="14em" class="mb-1"/>
Download with DataLad</b-button>&nbsp;</span>
<span v-show="displayData.show_github"><b-button variant="outline-dark" size="sm" @click="gotoURL(displayData.url)"><i class="fab fa-github"></i> View on GitHub</b-button>&nbsp;</span>
<span v-show="displayData.show_gin"><b-button variant="outline-dark" size="sm" @click="gotoURL(displayData.url)"><img src="/artwork/ginfavicon.png" style="height: 1em;"></img> View on GIN</b-button>&nbsp;</span>
<span v-show="displayData.show_gin"><b-button variant="outline-dark" size="sm" @click="gotoURL(displayData.url)"><img src="artwork/ginfavicon.png" style="height: 1em;"></img> View on GIN</b-button>&nbsp;</span>
<span v-show="displayData.show_gitlab"><b-button variant="outline-dark" size="sm" @click="gotoURL(displayData.url)"><i class="fab fa-gitlab"></i> View on GitLab</b-button>&nbsp;</span>
<span v-show="displayData.show_cite"><b-button variant="outline-dark" size="sm" v-b-modal.modal-2 @click="getCitationText(selectedDataset.doi)"><i class="fas fa-quote-right"></i> Cite</b-button>&nbsp;</span>
<span v-if="displayData.show_export"><b-button variant="outline-dark" size="sm" :href="displayData.file_path" :download="displayData.download_filename"><i class="fas fa-file-arrow-down"></i> Export metadata</b-button>&nbsp;</span>
Expand All @@ -61,7 +61,7 @@
ok-only>
<template #modal-header="{ close }">
<div class="d-block text-center">
<h3>Download with <img src="/artwork/datalad_logo_wide.svg" width="100em"></h3>
<h3>Download with <img src="artwork/datalad_logo_wide.svg" width="100em"></h3>
</div>
</template>
<h5>Step 1: Install DataLad</h5>
Expand Down
63 changes: 57 additions & 6 deletions datalad_catalog/serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,18 @@
WebCatalog,
)
from datalad_next.commands import (
EnsureCommandParameterization,
ValidatedInterface,
Parameter,
build_doc,
EnsureCommandParameterization,
eval_results,
get_status_dict,
ValidatedInterface,
Parameter,
ParameterConstraintContext,
)
from datalad_next.constraints import (
EnsureRange,
EnsureInt,
EnsurePath,
EnsureRange,
)
import logging
from pathlib import Path
Expand All @@ -40,13 +42,42 @@
class ServeParameterValidator(EnsureCommandParameterization):
""""""

def _validate_combinations(
self,
catalog,
port,
base,
):
""""""
# parameter combinations for catalog and base

if catalog and base:
if not catalog.location.resolve().is_relative_to(base.resolve()):
self.raise_for(
dict(
catalog=catalog,
port=port,
base=base,
),
(
f"the catalog location ({catalog.location.resolve()}) should be relative "
"to the base path"
),
)

def __init__(self):
all_params = ("catalog", "port", "base")
super().__init__(
param_constraints=dict(
catalog=CatalogRequired() & EnsureWebCatalog(),
port=EnsureInt() & EnsureRange(1025, 9999),
base=EnsurePath(),
),
joint_constraints=dict(),
joint_constraints={
ParameterConstraintContext(
all_params, "validate-parameter-combinations"
): self._validate_combinations,
},
)


Expand Down Expand Up @@ -75,6 +106,16 @@ class Serve(ValidatedInterface):
doc="""The port at which the content is served at
'localhost' (default 8000)""",
),
base=Parameter(
# cmdline argument definitions, incl aliases
args=("--base",),
# documentation
doc="""The base path that should be served as the 'localhost'
root, implying that the catalog will be served from a
subdirectory relative to the base path. Must be a parent
path of the catalog location.
""",
),
)

_examples_ = [
Expand All @@ -91,6 +132,14 @@ class Serve(ValidatedInterface):
code_py="catalog_serve(catalog='/tmp/my-cat/', port=8001)",
code_cmd="datalad catalog-serve -c /tmp/my-cat -p 8001",
),
dict(
text=(
"SERVE the content of the catalog via a local HTTP server "
"at a custom subdirectory, e.g. http://localhost:8000/my-cat"
),
code_py="catalog_serve(catalog='/tmp/my-cat/', base='/tmp')",
code_cmd="datalad catalog-serve -c /tmp/my-cat --base /tmp",
),
]

@staticmethod
Expand All @@ -101,13 +150,15 @@ class Serve(ValidatedInterface):
def __call__(
catalog: Union[Path, WebCatalog],
port: int = 8000,
base=None,
):
res_kwargs = dict(
action="catalog_serve",
path=catalog.location,
basepath=base,
)
try:
catalog.serve(port=port)
catalog.serve(port=port, base=base)
yield get_status_dict(
**res_kwargs,
status="ok",
Expand Down
22 changes: 18 additions & 4 deletions datalad_catalog/webcatalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,22 @@ def serve(
self,
host: str = "localhost",
port: int = 8000,
base: str = None,
):
"""Serve a catalog via a local http server"""
os.chdir(self.location)

if base and not self.location.resolve().is_relative_to(
Path(base).resolve()
):
error_msg = "The catalog location should be relative to the supplied base path "
raise ValueError(error_msg)
if base:
base_path = Path(base).resolve()
relpath = str(self.location.resolve().relative_to(base_path))
os.chdir(base_path)
else:
relpath = ""
os.chdir(self.location)

from http.server import SimpleHTTPRequestHandler
import socketserver
Expand All @@ -298,19 +311,20 @@ def serve(
class CustomHandler(SimpleHTTPRequestHandler):
# Redirect all '/dataset' URLs to '/index.html'
def do_GET(self):
if self.path.startswith("/dataset"):
self.path = "/index.html"
if self.path.startswith(f"/{relpath}/dataset"):
self.path = f"/{relpath}/index.html"
# Continue with the default behavior
return SimpleHTTPRequestHandler.do_GET(self)

try:
with socketserver.TCPServer((host, port), CustomHandler) as httpd:
ui.message(
"\nServing catalog at: http://{h}:{p}/ - navigate to this "
"\nServing catalog at: http://{h}:{p}/{s} - navigate to this "
"address in your browser to test the catalog locally - press "
"CTRL+C to stop local testing\n".format(
h=ac.color_word(host, ac.BOLD),
p=ac.color_word(port, ac.BOLD),
s=ac.color_word(relpath, ac.BOLD),
)
)
httpd.serve_forever()
Expand Down

0 comments on commit b5985d9

Please sign in to comment.