From 8b41efad6c124cb0a8b7a12e550b231a71301d22 Mon Sep 17 00:00:00 2001 From: Kyle Anderson Date: Tue, 26 Nov 2024 16:25:28 -0500 Subject: [PATCH] Pull store lists from store API * Newest, cancer resources, and clinical relevance sections are pulled from store.opencravat.org * If the store API can't be reached, it will revert back to organizing those sections as before * newest - 10 most recently updated annotators * cancer and clinical relevance - all annotators with those terms as tags --- cravat/store_utils.py | 16 ++++++ cravat/webstore/nocache/webstore.js | 89 +++++++++++++++++++---------- cravat/webstore/webstore.py | 8 +++ cravat/websubmit/nocache/index.html | 4 -- 4 files changed, 82 insertions(+), 35 deletions(-) diff --git a/cravat/store_utils.py b/cravat/store_utils.py index 9131b223..6c3cf16a 100644 --- a/cravat/store_utils.py +++ b/cravat/store_utils.py @@ -99,6 +99,9 @@ def manifest_nover(self): def download_counts(self): return self._build_path(self.base(), "download-counts.yml") + def featured_module_list(self): + return self._build_path(self.base(), "store.json") + def blank_stage_handler(*args, **kwargs): pass @@ -200,6 +203,19 @@ def get_file_to_string(url): raise HTTPError(url, r.status_code, "", None, None) +def get_file_to_json(url): + """ + Sends a GET request to the given url and returns the response body as a dict + + Errors during the GET request are unhandled by this method + """ + r = requests.get(url, timeout=(3, None)) + if r.status_code == 200: + return r.json() + else: + raise HTTPError(url, r.status_code, "", None, None) + + def file_checksum(path): """ Get the md5 checksum of a file. diff --git a/cravat/webstore/nocache/webstore.js b/cravat/webstore/nocache/webstore.js index 7fc39b3e..59bbc71f 100644 --- a/cravat/webstore/nocache/webstore.js +++ b/cravat/webstore/nocache/webstore.js @@ -332,7 +332,33 @@ function getMostDownloadedModuleNames() { return top10ModuleNames; } +function fetchCuratedStoreList() { + // fetch('/store/nocache/store.json') + fetch('/store/lists') + .then(response => { + if (!response.ok) { + console.warn('Could not load OpenCRAVAT store featured list.', response); + return null; + } + return response.json(); + }) + .then(data => { + OC.storeModuleList = data; + }) + .catch(function() { + console.warn('Could not load OpenCRAVAT store featured list.'); + OC.storeModuleList = null; + }); +} + function getNewestModuleNames() { + // if we have a curated list, return the list of module names + if (OC.storeModuleList && OC.storeModuleList?.latest) { + return OC.storeModuleList.latest + .map(m => m.module) + .filter(name => Object.hasOwn(OC.remoteModuleInfo, name)); + } + // else fall back to returning the 10 most recently published var moduleNames = Object.keys(OC.remoteModuleInfo); for (var i = 0; i < moduleNames.length; i++) { for (var j = i + 1; j < moduleNames.length - 1; j++) { @@ -379,6 +405,30 @@ function getNewestModuleNames() { return top10ModuleNames; } +function getModuleListByCategory(category) { + // if we have a curated list, return the list of module names + if (OC.storeModuleList && OC.storeModuleList[category]) { + return OC.storeModuleList[category] + .map(m => m.module) + .filter(name => Object.hasOwn(OC.remoteModuleInfo, name)); + } + + // fallback to searching for remote modules with 'category' as a tag + var modules = []; + var remoteModuleNames = Object.keys(OC.remoteModuleInfo); + for (var i = 0; i < remoteModuleNames.length; i++) { + var remoteModuleName = remoteModuleNames[i]; + var remoteModule = OC.remoteModuleInfo[remoteModuleName]; + if (remoteModule['groups'].length > 0) { + continue; + } + if (remoteModule['tags'].includes(category)) { + modules.push(remoteModuleName); + } + } + return modules; +} + function getHomeCarouselContent (modules, type) { var sdiv = getEl('div'); sdiv.style.width = (Math.ceil(modules.length / OC.numModulesInHomeSectionRow) * OC.storeTileWidthStep) + 'px' @@ -417,39 +467,13 @@ function populateStoreHome() { var div = document.getElementById('store-home-cancerdiv'); $(div).empty(); var sdiv = getEl('div'); - var cancerModules = []; - var remoteModuleNames = Object.keys(OC.remoteModuleInfo); - for (var i = 0; i < remoteModuleNames.length; i++) { - var remoteModuleName = remoteModuleNames[i]; - var remoteModule = OC.remoteModuleInfo[remoteModuleName]; - if (remoteModule['groups'].length > 0) { - continue; - } - if (remoteModule['tags'].includes('cancer')) { - cancerModules.push(remoteModuleName); - } - } - OC.moduleLists['cancer'] = cancerModules; - var sdiv = getHomeCarouselContent(cancerModules, 'cancer') + OC.moduleLists['cancer'] = getModuleListByCategory('cancer'); + var sdiv = getHomeCarouselContent(OC.moduleLists['cancer'], 'cancer') addEl(div, sdiv); // Clinical Relevance var div = document.getElementById('store-home-clinicaldiv'); - $(div).empty(); - var sdiv = getEl('div'); - var clinicalModules = []; - var remoteModuleNames = Object.keys(OC.remoteModuleInfo); - for (var i = 0; i < remoteModuleNames.length; i++) { - var remoteModuleName = remoteModuleNames[i]; - var remoteModule = OC.remoteModuleInfo[remoteModuleName]; - if (remoteModule['groups'].length > 0) { - continue; - } - if (remoteModule['tags'].includes('clinical relevance')) { - clinicalModules.push(remoteModuleName); - } - } - OC.moduleLists['clinical'] = clinicalModules; - var sdiv = getHomeCarouselContent(clinicalModules, 'clinical') + OC.moduleLists['clinical'] = getModuleListByCategory('clinical'); + var sdiv = getHomeCarouselContent(OC.moduleLists['clinical'], 'clinical'); addEl(div, sdiv); } @@ -1872,7 +1896,10 @@ function addWebstoreEventHandlers() { } -$(document).ready(() => addWebstoreEventHandlers()); +$(document).ready(() => { + addWebstoreEventHandlers(); + fetchCuratedStoreList(); +}); export { addWebstoreEventHandlers, diff --git a/cravat/webstore/webstore.py b/cravat/webstore/webstore.py index 0a553449..04455a59 100644 --- a/cravat/webstore/webstore.py +++ b/cravat/webstore/webstore.py @@ -399,6 +399,13 @@ async def get_module_dependencies (request): deps = au.get_install_deps(module) return web.json_response(deps) +async def get_featured_module_lists(request): + pb = su.PathBuilder(au.get_system_conf()['store_url'], "url") + list_url = pb.featured_module_list() + featured_list = su.get_file_to_json(list_url) + return web.json_response(featured_list) + + routes = [] routes.append(['GET', '/store/remote', get_remote_manifest]) routes.append(['GET', '/store/installwidgetsformodule', install_widgets_for_module]) @@ -421,3 +428,4 @@ async def get_module_dependencies (request): routes.append(['GET', '/store/localasremote', get_remote_manifest_from_local]) routes.append(['GET', '/store/locallogo', get_local_module_logo]) routes.append(['GET', '/store/moduledependencies', get_module_dependencies]) +routes.append(['GET', '/store/lists', get_featured_module_lists]) diff --git a/cravat/websubmit/nocache/index.html b/cravat/websubmit/nocache/index.html index c75e117c..f2637660 100644 --- a/cravat/websubmit/nocache/index.html +++ b/cravat/websubmit/nocache/index.html @@ -235,28 +235,24 @@
Most Downloaded
-
The most downloaded modules to date!
Newest
-
The newest and greatest!
Cancer Resources
-
Cutting edge resources for cancer research!
Clinical Relevance
-
Our curation of clinically-relevant resources!