Skip to content

Unable to download metadata from certain file aggregations (e.g., model program aggregations) #98

@abnerbog

Description

@abnerbog

Within certain resources, I am unable to use this library to extract the file aggregation level metadata.

For example, running this code block

from hsclient import HydroShare

hs = HydroShare()
hs.sign_in()

# metadata extraction fails for this resource ID
resource_id = 'e992c4484f864ef8bccdc2924ed6e9ba' 
# metadata extraction works for this resource ID
# resource_id = '7bd7b3f4c91741b9bf22bfff717ec286'

res = hs.resource(resource_id)

for agg in res.aggregations():
    # try to extract one of the metadata fields
    print(agg.metadata.operating_systems)
returns this error message:
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
Cell In[1], line 13
      8 # metadata extraction works for this resource ID
      9 # resource_id = '7bd7b3f4c91741b9bf22bfff717ec286'
     11 res = hs.resource(resource_id)
---> 13 for agg in res.aggregations():
     14     # try to extract one of the metadata fields
     15     print(agg.metadata.operating_systems)

File /opt/conda/lib/python3.12/site-packages/hsclient/hydroshare.py:345, in Aggregation.aggregations(self, **kwargs)
    337 def aggregations(self, **kwargs) -> List[BaseMetadata]:
    338     """
    339     List the aggregations in the resource.  Filter by properties on the metadata object using kwargs.  If you need
    340     to filter on nested properties, use __ (double underscore) to separate the properties.  For example, to filter
   (...)    343     :return: a List of Aggregation objects matching the filter parameters
    344     """
--> 345     aggregations = self._aggregations
    347     for key, value in kwargs.items():
    348         if key.startswith('file__'):

File /opt/conda/lib/python3.12/site-packages/hsclient/hydroshare.py:210, in Aggregation._aggregations(self)
    203 typed_aggregation_classes = {AggregationType.MultidimensionalAggregation: NetCDFAggregation,
    204                              AggregationType.TimeSeriesAggregation: TimeseriesAggregation,
    205                              AggregationType.GeographicRasterAggregation: GeoRasterAggregation,
    206                              AggregationType.GeographicFeatureAggregation: GeoFeatureAggregation,
    207                              AggregationType.CSVFileAggregation: CSVAggregation
    208                              }
    209 for aggr in aggregations_copy:
--> 210     typed_aggr_cls = typed_aggregation_classes.get(aggr.metadata.type, None)
    211     if typed_aggr_cls:
    212         typed_aggr = typed_aggr_cls.create(base_aggr=aggr)

File /opt/conda/lib/python3.12/site-packages/hsclient/hydroshare.py:275, in Aggregation.metadata(self)
    272 @property
    273 def metadata(self) -> BaseMetadata:
    274     """A metadata object for reading and updating metadata values"""
--> 275     return self._metadata

File /opt/conda/lib/python3.12/site-packages/hsclient/hydroshare.py:158, in Aggregation._metadata(self)
    155 @property
    156 def _metadata(self):
    157     if not self._retrieved_metadata:
--> 158         self._retrieved_metadata = self._retrieve_and_parse(self.metadata_path)
    159     return self._retrieved_metadata

File /opt/conda/lib/python3.12/site-packages/hsclient/hydroshare.py:237, in Aggregation._retrieve_and_parse(self, path)
    236 def _retrieve_and_parse(self, path):
--> 237     file_str = self._hs_session.retrieve_string(path)
    238     instance = load_rdf(file_str)
    239     return instance

File /opt/conda/lib/python3.12/site-packages/hsclient/hydroshare.py:1360, in HydroShareSession.retrieve_string(self, path)
   1359 def retrieve_string(self, path):
-> 1360     file = self.get(path, status_code=200, allow_redirects=True)
   1361     return file.content.decode()

File /opt/conda/lib/python3.12/site-packages/hsclient/hydroshare.py:1450, in HydroShareSession.get(self, path, status_code, **kwargs)
   1448 response = self._session.get(url, **kwargs)
   1449 if response.status_code != status_code:
-> 1450     raise Exception(
   1451         "Failed GET {}, status_code {}, message {}".format(url, response.status_code, response.content)
   1452     )
   1453 return response

Exception: Failed GET https://www.hydroshare.org:443/resource/e992c4484f864ef8bccdc2924ed6e9ba/data/contents/Watershed%2520scale%2520model/Model%2520Instances/Model%2520Instances_meta.xml/, status_code 500, message b'<!doctype html>\n<html lang="en">\n\n\n<head>\n\n<meta http-equiv="Content-type" content="text/html; charset=utf-8">\n<meta name="viewport" content="width=device-width">\n<meta name="keywords" content="">\n<meta name="description" content="">\n<title>\nError\n | CUAHSI HydroShare</title>\n<link rel="shortcut icon" href="https://storage.googleapis.com/hydroshare-prod-static-media/static/img/favicon.287fbaa9587d.png">\n\n\n<link rel="alternate" type="application/rss+xml" title="RSS" href="/blog/feeds/rss/">\n<link rel="alternate" type="application/atom+xml" title="Atom" href="/blog/feeds/atom/">\n\n\n<link rel="stylesheet" type="text/css" href="https://storage.googleapis.com/hydroshare-prod-static-media/static/css/hydroshare_fonts.1f75a454d3dd.css">\n<link rel="stylesheet" type="text/css" href="//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.css">\n\n\n<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">\n<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">\n<link rel="stylesheet" type="text/css" href="https://storage.googleapis.com/hydroshare-prod-static-media/static/css/elements.92a6064e64e2.css">\n<link rel=\'stylesheet\' type=\'text/css\' href="https://storage.googleapis.com/hydroshare-prod-static-media/static/css/jquery-ui/smoothness/jquery-ui.caac42ce7954.css">\n<link rel="stylesheet" type="text/css" href="https://storage.googleapis.com/hydroshare-prod-static-media/static/css/hydroshare_core.4b2e74527778.css">\n<link rel="stylesheet" type="text/css" href="https://storage.googleapis.com/hydroshare-prod-static-media/static/css/identifiers.373282463ada.css">\n<link rel="stylesheet" type="text/css" href="https://storage.googleapis.com/hydroshare-prod-static-media/static/css/hydroshare_extends.c8b6d2666967.css">\n\n\n\n\n\n\n<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>\n<!-- https://jquery.com/upgrade-guide/1.9/#jquery-browser-removed -->\n<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-migrate/1.4.1/jquery-migrate.min.js" integrity="sha512-t0ovA8ZOiDuaNN5DaQQpMn37SqIwp6avyoFQoW49hOmEYSRf8mTCY2jZkEVizDT+IZ9x+VHTZPpcaMA5t2d2zQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>\n<script type="text/javascript" src="https://storage.googleapis.com/hydroshare-prod-static-media/static/js/custom.82ab36bbffee.js"></script>\n\n\n<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>\n\n<script type="text/javascript" src="https://storage.googleapis.com/hydroshare-prod-static-media/static/js/scrolltopcontrol.06bf71b23ccb.js"></script>\n<script type="text/javascript" src="https://storage.googleapis.com/hydroshare-prod-static-media/static/js/jqcsrf.8de901449162.js"></script>\n<script type="text/javascript" src="https://storage.googleapis.com/hydroshare-prod-static-media/static/js/jquery-ui.02b6ad1ad954.js"></script>\n<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>\n<script type="text/javascript" src="https://storage.googleapis.com/hydroshare-prod-static-media/static/js/bootstrap-extras.d365e05874fe.js"></script>\n\n\n<script>\n    const ROUTE_NAME = "rest_download";\n</script>\n\n\n\n\n\n\n\n<script type="text/javascript">\n    window.heap=window.heap||[],heap.load=function(e,t){window.heap.appid=e,window.heap.config=t=t||{};var r=t.forceSSL||"https:"===document.location.protocol,a=document.createElement("script");a.type="text/javascript",a.async=!0,a.src=(r?"https:":"http:")+"//cdn.heapanalytics.com/js/heap-"+e+".js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(a,n);for(var o=function(e){return function(){heap.push([e].concat(Array.prototype.slice.call(arguments,0)))}},p=["addEventProperties","addUserProperties","clearEventProperties","identify","resetIdentity","removeEventProperty","setEventProperties","track","unsetEventProperty"],c=0;c<p.length;c++)heap[p[c]]=o(p[c])};\n      heap.load("1320547260");\n</script>\n\n<script>\n    const STATIC_URL = "https://storage.googleapis.com/hydroshare-prod-static-media/static/" || "/static/static/";\n</script>\n</head>\n\n<body id="body">\n\n<link rel="stylesheet" type="text/css" href="https://storage.googleapis.com/hydroshare-prod-static-media/static/css/notifications-app.91a3cb642dbc.css">\n\n<style>\n    /* Navbar */\n    .dropdown-menu .divider {\n        height: 1px;\n        margin: 9px 0;\n        overflow: hidden;\n        background-color: #999\n    }\n    .navbar-brand {\n        padding: 0;\n        padding-top: 10px;\n    }\n\n    #img-brand-logo {\n        width: 145px;\n    }\n\n    .container>.navbar-header, .container>.navbar-collapse {\n        padding-left: 15px;\n        padding-right: 15px;\n    }\n\n    .navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {\n        border-color: #DDD;\n    }\n\n    .navbar-toggle {\n        background: #B5B5B5;\n        border-color: #8C8C8C !important;\n    }\n\n    .navbar-inverse {\n      background-color: #FFF;\n      border: none;\n    }\n\n    .navbar>.container .navbar-brand {\n        margin-right: 10px;\n    }\n\n    .navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus {\n        color: #333;\n        background-color: #FFF !important\n    }\n\n    .navbar-inverse .navbar-brand {\n        color: #EEEEEE;\n    }\n\n    .navbar-inverse .resource-type-name,\n    .navbar-inverse .navbar-nav > li > a,\n    .navbar-inverse .navbar-nav > .open > a,\n    .navbar-inverse .navbar-nav > .open > a:hover,\n    .navbar-inverse .navbar-nav > .open > a:focus {\n        color: #777;\n        font: 13px/18px \'Open Sans\', arial, sans-serif;\n    }\n\n    .navbar-nav > li > .dropdown-menu.arrow_box, .dropdown-menu.profile-card {\n        margin-top: 18px;\n        margin-right: -12px;\n        width: 300px;\n        height: 160px;\n        padding: 0;\n        background: #FFF;\n        -webkit-border-radius: 4px;\n        -moz-border-radius: 4px;\n        border-radius: 4px;\n        box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2);\n        -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2);\n        -moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2)\n    }\n\n    .res-dropdown {\n        padding: 7px;\n        padding-right: 40px;\n    }\n\n    .dropdown-menu.profile-card {\n        width: 350px;\n        height: auto;\n        margin: unset;\n        margin-bottom: 40px;\n    }\n\n    .profile-card .flex > div {\n        padding: 15px;\n    }\n\n    .profile-card .flex > div:first-child {\n        border-right: 1px solid #DDD;\n        width: 110px;\n    }\n\n    .profile-card .dropdown-profile-pic-thumbnail{\n        margin-right: 0;\n    }\n\n    .profile-card table .fa {\n        margin-right: 4px;\n    }\n\n    .navbar-inverse .navbar-nav > .open > a:hover,\n    .navbar-inverse .navbar-nav > li > a:hover,\n    .navbar-inverse .navbar-nav > li > a:focus {\n        color: #333;\n        -webkit-transition: color 100ms linear;\n        -moz-transition: color 100ms linear;\n        -o-transition: color 100ms linear;\n        transition: color 100ms linear;\n    }\n\n    .navbar-inverse {\n        text-transform: uppercase;\n        border-bottom: 1px solid #DDD;\n        box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);\n        -moz-box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);\n        -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);\n    }\n\n    .navbar-inverse .tooltip {\n        text-transform: none;\n    }\n\n    .navbar-inverse .navbar-nav > .open > a,\n    .navbar-inverse .navbar-nav > .open > a:hover,\n    .navbar-inverse .navbar-nav > .open > a:focus {\n        background-color: unset;\n    }\n\n    .dropdown-menu {\n        border: 1px solid #D6D6D6;\n        border-top-color: #EEEEEE;\n        border-radius: 0;\n        box-shadow: none;\n        -webkit-box-shadow: none;\n        -moz-box-shadow: none;\n    }\n    .dropdown-menu > li > a {\n      color: #000;\n      padding: 10px 20px;\n      font-size: 12px;\n    }\n    .dropdown-menu > li > a:hover,\n    .dropdown-menu > li > a:focus {\n      color: #333;\n      background-color: #eaeaea;\n    }\n</style>\n<div id="hs-nav-bar" class="navbar navbar-inverse navbar-fixed-top">\n    <div id="toplevel-nav-container" class="container">\n        <div class="navbar-header">\n            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">\n                <span class="icon-bar"></span>\n                <span class="icon-bar"></span>\n                <span class="icon-bar"></span>\n            </button>\n            <a class="navbar-brand" href="/landingPage">\n                <img id="img-brand-logo" src="https://storage.googleapis.com/hydroshare-prod-static-media/static/img/logo-lg.cf4395806c8e.png" alt="CUAHSI HydroShare"/>\n            </a>\n        </div>\n        <div class="collapse navbar-collapse">\n            <ul class="nav navbar-nav navbar-right hidden-xs">\n                \n                    \n                        <li id="profile-menu" class="display-block">\n                            \n                                <a href="#" class="dropdown-toggle" data-toggle="dropdown">\n                                    <div class="profile-pic-thumbnail-small round-image pull-left"></div>\n                                </a>\n                            \n                            <ul class="dropdown-menu arrow_box">\n                                <li class="account">\n                                    <div class="row">\n                                        <div class="col-sm-4">\n                                            \n                                                <div class="dropdown-profile-pic-thumbnail round-image dropdown-user-icon pull-left"></div>\n                                            \n                                        </div>\n                                        <div class="col-sm-8">\n                                            <strong id="profile-menu-fullname"\n                                                    title="Abner Bogan">Abner Bogan</strong>\n                                            \n                                                <div id="profile-menu-email" class="text-muted"\n                                                     title="[email protected]">[email protected]</div>\n                                            \n                                        </div>\n                                    </div>\n\n                                    <div class="dropdown-footer has-background-light-gray">\n                                        <a href="/user/23526/" class="btn btn-primary">Profile</a>\n                                        <a href="/accounts/logout/" id="signout-menu" class="btn btn-default">\n                                            <span class="glyphicon glyphicon-log-out"></span> Sign out\n                                        </a>\n                                    </div>\n                                </li>\n                            </ul>\n                        </li>\n                        <li id="notifications-dropdown">\n    <a href="#" class="dropdown-toggle" data-toggle="dropdown" style="padding-top:14px;padding-bottom:14px;"\n       role="button" aria-haspopup="true" aria-expanded="false">\n        <span class="glyphicon glyphicon-bell"></span>\n    </a>\n    <ul class="dropdown-menu arrow_box" style="position:absolute;">\n        <li class="notifications">\n            <div id="app-notifications">\n                <div class="notifications--header">\n                    <h4>Notifications <span v-if="tasks.length">(${tasks.length})</span></h4>\n                    <a role="button" id="btn-notifications-clear" v-on:click="clear">Clear</a>\n                </div>\n\n                <div v-if="loading" class="default-content">\n                    <i class="fa fa-spinner fa-pulse fa-2x fa-fw icon-blue"></i>\n                </div>\n                <div v-if="!loading">\n                    <div v-if="tasks.length">\n                        <div class="task" v-for="task in tasks">\n                            <div class="notification--content">\n                                <div class="notification--name">${taskMessages[task.name].title}\n                                    <div class="notification--status">\n                                        <span :class="statusIcons[task.status]"></span>\n\n                                        <small v-if="canNotifyDownload(task)">\n                                            Your download will start in a few seconds. If it does not start click <a\n                                                :href="task.payload">here</a>\n                                            to download your files directly.\n                                        </small>\n                                        <small v-else>${taskMessages[task.name].status[task.status]}.\n                                            <span v-if="task.payload && (task.status === \'delivered\' || task.status === \'completed\')">\n                                            Click <a :href="task.payload">here</a> to refresh user interface.\n                                            </span>\n                                            <span v-else-if="task.payload.includes(\'FileOverrideException\') && task.status === \'failed\'">\n                                            <a id=\'btn-file-override\' v-on:click="showFileOverrideDialog(task.payload)">Select whether to allow file override</a>\n                                            </span>\n                                            <span v-else-if="task.status === \'failed\'">${task.payload}</span>\n                                        </small>\n                                    </div>\n                                </div>\n                            </div>\n                            <div class="notification--controls">\n                                <button type="button" v-if="canBeDismissed(task)" v-on:click="dismissTask(task)" class="close" aria-label="Dismiss"\n                                    title="Dismiss">\n                                    <span aria-hidden="true">\xc3\x97</span>\n                                </button>\n\n                                <button type="button" v-if="canBeAborted(task)" v-on:click="abortTask(task)" class="close" title="Abort"\n                                    aria-label="Abort">\n                                    <span class="glyphicon glyphicon-ban-circle"></span>\n                                </button>\n                            </div>\n                        </div>\n                    </div>\n                    <div v-else class="default-content">You don\'t have any notifications.</div>\n                </div>\n            </div>\n        </li>\n    </ul>\n</li>\n                    \n                \n            </ul>\n            \n\n            <ul class="nav navbar-nav">\n                <li  id="dropdown-menu-home">\n                    <a href="/home/">Home</a>\n                </li>\n                <li  id="dropdown-menu-my-resources">\n                    <a href="/my-resources/">My Resources</a>\n                </li>\n                <li  id="dropdown-menu-search">\n                    <a href="/search/">Discover</a>\n                </li>\n                <li  id="dropdown-menu-collaborate">\n                    <a href="/collaborate/">Collaborate</a>\n                </li>\n                <li class="" id="dropdown-menu-https:--www.hydroshare.org-apps-">\n                    <a href="https://www.hydroshare.org/apps/" target="_self">Apps</a>\n                </li>\n                <li class="" id="dropdown-menu-https:--help.hydroshare.org">\n                    <a href="http://help.hydroshare.org">Help</a>\n                </li>\n            </ul>\n\n            <ul id="resource-dropdown" class="nav navbar-nav navbar-right">\n                \n                    <li class="res-dropdown" style="padding-right:35px;">\n                        <button id="select-resource-type" data-toggle="dropdown"\n                                class="dropdown-toggle btn btn-primary"\n                                role="button" aria-haspopup="true" aria-expanded="false">Create\n                        </button>\n                        \n                            <ul id="res-menu-contents" class="dropdown-menu" role="menu" aria-labelledby="select-resource-type">\n                                <li>\n                                    <a data-toggle="tooltip" data-placement="left"\n                                       title="A resource which can include multiple files without file format limitations."\n                                       data-modal-title="Create a Resource"\n                                       data-modal-input-title="Enter the title for the new resource."\n                                       data-value="CompositeResource">\n                                        <img src="https://storage.googleapis.com/hydroshare-prod-static-media/static/img/resource-icons/composite48x48.9d90905ebe96.png"\n                                             alt="Resource Icon" class="resource-type-icon"/>\n                                        <div class="resource-type-name">&nbsp;Resource</div>\n                                    </a>\n                                </li>\n                                <li>\n                                    <a data-toggle="tooltip" data-placement="left"\n                                       title="A resource that holds a list of other resources in HydroShare."\n                                       data-modal-title="Create a Collection"\n                                       data-modal-input-title="Enter the title for the new collection of HydroShare resources."\n                                       data-value="CollectionResource">\n                                        <img src="https://storage.googleapis.com/hydroshare-prod-static-media/static/img/resource-icons/collection48x48.8a917b585442.png"\n                                             alt="Collection Resource Icon" class="resource-type-icon"/>\n                                        <div class="resource-type-name">&nbsp;Collection</div>\n                                    </a>\n                                </li>\n                                <li>\n                                    <a data-toggle="tooltip" data-placement="left"\n                                       title="A shortcut (or reference) to an external web application that functions with HydroShare data resources."\n                                       data-modal-title="Create an App Connector"\n                                       data-modal-input-title="Enter the name for the new app connector."\n                                       data-value="ToolResource">\n                                        <img src="https://storage.googleapis.com/hydroshare-prod-static-media/static/img/resource-icons/webapp48x48.e86745eff3fa.png"\n                                             alt="Web App Resource Icon" class="resource-type-icon"/>\n                                        <div class="resource-type-name">&nbsp;App Connector</div>\n                                    </a>\n                                </li>\n                            </ul>\n                        \n                    </li>\n                \n\n                \n                    <li class="visible-xs"><a href="/user/23526/">Profile</a></li>\n                \n\n                \n                    <!-- Profile links for extra small screens -->\n                    \n                        <li class="visible-xs"><a href="/accounts/logout/"><span\n                                class="glyphicon glyphicon-log-out"></span> Sign Out</a></li>\n                    \n                \n            </ul>\n\n        </div>\n    </div>\n</div>\n\n<div class="modal fade" id="submit-title-dialog" tabindex="-1" role="dialog"\n     aria-labelledby="myModalLabel" aria-hidden="true">\n    <div class="modal-dialog">\n        <div class="modal-content">\n            <div class="modal-header">\n                <button type="button" class="close" data-dismiss="modal"\n                        aria-hidden="true">&times;\n                </button>\n                <h4 class="modal-title">Create a Resource</h4>\n            </div>\n            <div class="modal-body">\n                <div class="warnings-list">\n                    <div class="modal-input-title">Enter the title for the new resource.\n                    </div>\n                    <br>\n                    <input id="input-title" class="form-control textinput textInput" maxlength="300"\n                           name="value" type="text" placeholder="Title" value="">\n                </div>\n            </div>\n            <div class="modal-footer">\n                <button type="button" class="btn btn-default" data-dismiss="modal">Cancel\n                </button>\n                <button id="btn-resource-create" type="button" data-value="" class="btn btn-primary"\n                        data-dismiss="modal">Create\n                </button>\n            </div>\n        </div>\n    </div>\n</div>\n\n\n\n<script>\n    $("#hs-nav-bar .res-dropdown ul > li>  a").on("click", function () {\n        $(\'#btn-resource-create\').attr("data-value", $(this).attr("data-value"));\n        let title = $(this).attr("data-modal-title");\n        let inputTitle = $(this).attr("data-modal-input-title");\n\n        $(\'#submit-title-dialog .modal-title\').text(title);\n        $(\'#submit-title-dialog .modal-input-title\').text(inputTitle);\n        $(\'#submit-title-dialog\').modal(\'show\');\n    });\n\n    $("#btn-resource-create").on("click", function () {\n        let resourceType = $(this).attr("data-value");\n        let title = $(\'#input-title\').val();\n\n        createResource(resourceType, title);\n    });\n\n    function getCookie(name) {\n      let cookieValue = null;\n      if (document.cookie && document.cookie !== \'\') {\n        const cookies = document.cookie.split(\';\');\n        for (let i=0; i < cookies.length; i++) {\n          const cookie = cookies[i].trim();\n          if (cookie.substring(0, name.length + 1) === (name + \'=\')) {\n            cookieValue = decodeURIComponent(cookie.substring(name.length +1));\n            break;\n          }\n        }\n      }\n      return cookieValue;\n    }\n\n    function createResource(type, title) {\n        // Disable dropdown items while we process the request\n        $(".navbar-inverse .res-dropdown .dropdown-menu").toggleClass("disabled", true);\n\n        var formData = new FormData();\n        if (!title) {\n            title = "Untitled Resource";\n        }\n        const csrftoken = getCookie(\'csrftoken\');\n        formData.append("csrfmiddlewaretoken", csrftoken);\n        formData.append("title", title);\n        formData.append("resource-type", type);\n        let contentType;\n        if (type === "CompositeResource") {\n            contentType = "resource";\n        }\n        else if (type === "CollectionResource") {\n            contentType = "collection";\n        }\n        else {\n            contentType = "app connector";\n        }\n\n        const alertTitle = "Creating your " + contentType;\n        customAlert(alertTitle, "Please wait...", "success", -1); // Persistent alert\n        $("html").css("cursor", "progress");\n\n        let errorMsg = "Failed to create " + contentType + ".";\n\n        $.ajax({\n            type: "POST",\n            data: formData,\n            processData: false,\n            contentType: false,\n            url: "/hsapi/_internal/create-resource/do/",\n            success: function (response) {\n                if (response.status === "success") {\n                    window.location = response[\'resource_url\'];\n                }\n                else {\n                    console.log(response);\n                    if (response.hasOwnProperty(\'message\')) {\n                        errorMsg = `${errorMsg} ${response.message}`;\n                    }\n                    $(".custom-alert").alert(\'close\');  // Dismiss previous alert\n                    customAlert("Error", errorMsg, "error", -1, dismissable=true);\n                    $("html").css("cursor", "initial");\n                    $(".navbar-inverse .res-dropdown").toggleClass("disabled", false);\n                }\n            },\n            error: function (response) {\n                console.log(response);\n                $(".custom-alert").alert(\'close\');  // Dismiss previous alert\n                customAlert("Error", errorMsg, "error", 6000);\n                $("html").css("cursor", "initial");\n                $(".navbar-inverse .res-dropdown").toggleClass("disabled", false);\n            }\n        });\n    }\n\n    const checkDelay = 10000; // ms\n    // TODO: this hard ping rate could be modified to check more frequently when the tasks are newer\n\n    $(\'#notifications-dropdown\').on(\'show.bs.dropdown\', function () {\n        notificationsApp.fetchTasks();\n    });\n\n    notificationsApp = new Vue({\n        el: \'#app-notifications\',\n        delimiters: [\'${\', \'}\'],\n        data: {\n            tasks: [],\n            loading: true,\n            isCheckingStatus: false,\n            taskMessages: {\n                "bag download": {\n                    title: "Download all content as Zipped BagIt Archive",\n                    status: {\n                        "progress": "Getting your files ready for download...",\n                        "aborted": "Aborted",\n                        "failed": "Download failed",\n                        "delivered": "Download delivered"\n                    }\n                },\n                "file unzip": {\n                    title: "File Unzipping",\n                    status: {\n                        "progress": "Unzipping your file...",\n                        "completed": "Completed",\n                        "failed": "Unzip failed",\n                        "delivered": "Unzipping completed"\n                    }\n                },\n                "zip download": {\n                    title: "File download",\n                    status: {\n                        "progress": "Getting your files ready for download...",\n                        "aborted": "Aborted",\n                        "failed": "Download failed",\n                        "delivered": "Download delivered"\n                    }\n                },\n                "resource copy": {\n                    title: "Resource copy",\n                    status: {\n                        "progress": "In progress...",\n                        "aborted": "Aborted",\n                        "completed": "Completed",\n                        "failed": "Failed",\n                        "delivered": "Delivered"\n                    }\n                },\n                "resource version": {\n                    title: "Resource versioning",\n                    status: {\n                        "progress": "In progress...",\n                        "completed": "Completed",\n                        "failed": "Failed",\n                        "delivered": "Delivered"\n                    }\n                },\n                "resource delete": {\n                    title: "Resource delete",\n                    status: {\n                        "progress": "In progress...",\n                        "completed": "Completed",\n                        "failed": "Failed",\n                        "delivered": "Delivered"\n                    }\n                },\n                "aggregation move": {\n                    title: "Aggregation move",\n                    status: {\n                        "progress": "In progress...",\n                        "completed": "Completed",\n                        "failed": "Failed",\n                        "delivered": "Delivered"\n                    }\n                }\n            },\n            statusIcons: {\n                "aborted": "glyphicon glyphicon-ban-circle",\n                "failed": "glyphicon glyphicon-remove-sign",\n                "completed": "glyphicon glyphicon-ok-sign",\n                "progress": "fa fa-spinner fa-pulse fa-2x fa-fw icon-blue",\n                "delivered": "glyphicon glyphicon-ok-sign"\n            }\n        },\n        computed: {\n            someInProgress: function () {\n                return this.tasks.find(function (task) {\n                    return task.status === "progress";\n                });\n            }\n        },\n        methods: {\n            showFileOverrideDialog: function (message) {\n              let msg_start_pos = message.indexOf("\'");\n              if (msg_start_pos >= 0) {\n                  let msg_end_pos = message.indexOf("\'", msg_start_pos+1);\n                  if (msg_end_pos > 0) {\n                      message = message.slice(msg_start_pos + 1, msg_end_pos);\n                      message = message.charAt(0).toUpperCase() + message.slice(1);\n                  }\n              }\n              $(\'#unzip-resp-message\').text(message);\n              $(\'#unzip-override-confirm-dialog\').modal(\'show\');\n            },\n            // Shows the tasks dropdown\n            show: function () {\n                $(\'#notifications-dropdown\').addClass(\'open\');\n            },\n            getUpdatedTask: function(in_task) {\n                return this.tasks.find(function(task) {\n                    return task.id === in_task.id\n                });\n            },\n            fetchTasks: function () {\n                let vue = this;\n                vue.loading = true;\n                $.ajax({\n                    type: "GET",\n                    url: \'/hsapi/_internal/get_tasks_by_user/\',\n                    success: function (ret_data) {\n                        vue.loading = false;\n                        tasks = ret_data[\'tasks\']\n                        for (let i = 0; i < tasks.length; i++) {\n                            vue.registerTask(tasks[i]);\n                        }\n                        vue.scheduleCheck();\n                    },\n                    error: function (response) {\n                        console.log(response);\n                        vue.loading = false;\n                    }\n                });\n            },\n            dismissTask: function (task) {\n                let vue = this;\n                if (vue.canBeDismissed(task)) {\n                    $.ajax({\n                        type: "GET",\n                        url: \'/hsapi/_internal/dismiss_task/\' + task.id,\n                        success: function (task) {\n                            vue.tasks = vue.tasks.filter(function(t) {\n                                return t.id !== task.id;\n                            });\n                        },\n                        error: function (response) {\n                            console.log(response);\n                        }\n                    });\n                }\n            },\n            canBeDismissed: function (task) {\n                return task.status === \'completed\'\n                    || task.status === \'failed\'\n                    || task.status === \'aborted\'\n                    || task.status === \'delivered\'\n            },\n            deliverTask: function(task) {\n                let vue = this;\n                if (vue.canBeDelivered(task)) {\n                    $.ajax({\n                        type: "GET",\n                        url: \'/hsapi/_internal/set_task_delivered/\' + task.id,\n                        success: function (task) {\n                            $("html").css("cursor", "default");\n                        },\n                        error: function (response) {\n                            console.log(response);\n                        }\n                    });\n                }\n            },\n            canBeDelivered: function (task) {\n                return task.status === \'completed\'\n            },\n            abortTask: function(task) {\n                let vue = this;\n                if (vue.canBeAborted(task)) {\n                    $.ajax({\n                        type: "GET",\n                        url: \'/hsapi/_internal/abort_task/\' + task.id,\n                        success: function (task) {\n                            vue.registerTask(task);\n                        },\n                        error: function (response) {\n                            console.log(response);\n                        }\n                    });\n                }\n            },\n            canBeAborted: function (task) {\n                let vue = this;\n                return "aborted" in vue.taskMessages[task.name].status && (task.status === \'progress\')\n            },\n            clear: function () {\n                let vue = this;\n                vue.tasks = vue.tasks.filter(function(task) {\n                    if (vue.canBeDismissed(task))\n                        vue.dismissTask(task);\n                    return !vue.canBeDismissed(task);\n                });\n            },\n            scheduleCheck: function() {\n                let vue = this;\n                if (vue.someInProgress && !vue.isCheckingStatus) {\n                    vue.isCheckingStatus = true;\n\n                    // check in 10s\n                    setTimeout(function() {\n                        vue.checkStatus();\n                    }, checkDelay);\n                }\n                else {\n                    vue.isCheckingStatus = false;\n                }\n            },\n            // Checks every 10s for every task in progress\n            checkStatus: function () {\n                let vue = this;\n\n                if (vue.someInProgress) {\n                    const tasksInProgress = vue.tasks.filter(function (task) {\n                        return task.status === "progress";\n                    });\n\n                    let calls = tasksInProgress.map(function (task) {\n                        return vue.checkTaskStatus(task);\n                    });\n\n                    // wait for all of task checks to finish and recall self after 1s\n                    $.when.apply($, calls).done(function () {\n                        setTimeout(function() {\n                            vue.checkStatus();\n                        }, checkDelay);\n                    });\n                }\n                else {\n                    vue.isCheckingStatus = false;\n                }\n            },\n            checkTaskStatus: function(task) {\n                let vue = this;\n\n                return $.ajax({\n                    type: "GET",\n                    url: \'/hsapi/_internal/get_task/\' + task.id,\n                    success: function (task) {\n                        vue.registerTask(task);\n                    },\n                    error: function (response) {\n                        console.log(response);\n                    }\n                });\n            },\n            downloadFile: function (url, taskId) {\n                // Remove previous temporary download frames\n                $(".temp-download-frame").remove();\n\n                $("body").append("<iframe class=\'temp-download-frame\' id=\'task-"\n                    + taskId + "\' style=\'display:none;\' src=\'" + url + "\'></iframe>");\n            },\n            processTask: function (task) {\n                let vue = this;\n                switch (task.name) {\n                    case "bag download":\n                        // Check if bag creation is finished\n                        if (task.status === "completed" && task.payload) {\n                            const bagUrl = task.payload;\n                            vue.downloadFile(bagUrl, task.id);\n                            vue.deliverTask(task);\n                        }\n                        break;\n                    case "zip download":\n                        // Check if zip creation is finished\n                        if (task.status === "completed" && task.payload) {\n                            const zipUrl = task.payload;\n                            vue.downloadFile(zipUrl, task.id);\n                            vue.deliverTask(task);\n                        }\n                        break;\n                    case "resource copy":\n                        if (task.status === "completed" && task.payload) {\n                            vue.deliverTask(task);\n                        }\n                        break;\n                    case "resource version":\n                        if (task.status === "completed" && task.payload) {\n                            vue.deliverTask(task);\n                        }\n                        break;\n                    case "resource delete":\n                        if (task.status === "completed" && task.payload) {\n                            vue.deliverTask(task);\n                        }\n                        break;\n                    case "aggregation move":\n                        if (task.status === "completed" && task.payload) {\n                            vue.deliverTask(task);\n                        }\n                        break;\n                    case "file unzip":\n                        if (task.status === "completed" && task.payload) {\n                            vue.deliverTask(task);\n                        }\n                        break;\n                    default:\n                        break;\n                }\n                if (task.status === \'progress\')\n                    vue.scheduleCheck();\n            },\n            registerTask: function (task) {\n                let vue = this;\n                let targetTask = null;\n\n                // Minor type checking\n                if (!task.hasOwnProperty(\'id\') || !task.hasOwnProperty(\'name\')) {\n                    return  // Object passed is not a task\n                }\n\n                targetTask = vue.tasks.find(function (t) {\n                    return t.id === task.id;\n                });\n\n                if (targetTask) {\n                    // Update existing task only if values have changed to avoid Vue change detection\n                    if (task.status !== targetTask.status || task.payload !== targetTask.payload) {\n                        targetTask.status = task.status;\n                        targetTask.payload = task.payload;\n                        if (task.status !== \'delivered\')\n                            vue.processTask(targetTask);\n                    }\n                }\n                else {\n                    // Add new task\n                    targetTask = task;\n                    vue.tasks = [targetTask, ...vue.tasks];\n                    if (task.status !== \'delivered\')\n                        vue.processTask(targetTask);\n                }\n            },\n            // Used to know when a task should inform users of alternative way to download their files\n            canNotifyDownload: function (task) {\n                return task.status === \'completed\'\n                    && (task.name === \'bag download\' || task.name === \'zip download\')\n            }\n        },\n        mounted: function () {\n            let vue = this;\n            vue.fetchTasks();\n        }\n    });\n</script>\n\n    \n    \n    \n\n    \n        <div class="main-container">\n            \n<div class="panel panel-danger">\n\t<div class="panel-heading"><h3 class="panel-title">Error</h3></div>\n\t<div class="panel-body">Sorry, an error occurred.</div>\n</div>\n\n            \n            \n<div class="modal fade" id="submit-title-dialog" tabindex="-1" role="dialog"\n     aria-labelledby="myModalLabel" aria-hidden="true">\n    <div class="modal-dialog">\n        <div class="modal-content">\n            <div class="modal-header">\n                <button type="button" class="close" data-dismiss="modal"\n                        aria-hidden="true">&times;</button>\n                <h4 class="modal-title">Create a Resource</h4>\n            </div>\n            <div class="modal-body">\n                <div class="warnings-list">\n                    <div class="modal-input-title">Enter the title for the new resource.\n                    </div>\n                    <br>\n                    <input id="input-title" class="form-control textinput textInput" maxlength="300"\n                           name="value" type="text" placeholder="Resource Title" value="">\n                </div>\n            </div>\n            <div class="modal-footer">\n                <button type="button" class="btn btn-default" data-dismiss="modal">Cancel\n                </button>\n                <button id="btn-resource-create" type="button" data-value="" class="btn btn-primary"\n                        data-dismiss="modal">Create\n                </button>\n            </div>\n        </div>\n    </div>\n</div>\n\n\n            \n            \n\n\n    <link href="https://releases.transloadit.com/uppy/v4.13.0/uppy.min.css" rel="stylesheet">\n\n\n\n  <div id="uppy"></div>\n\n\n\n  <script>\n    const FILE_UPLOAD_MAX_SIZE = 26843545600;\n    const MAX_CHUNK_SIZE = 2621440;\n    const MAX_NUMBER_OF_FILES_IN_SINGLE_LOCAL_UPLOAD = 50;\n    const PARALLEL_UPLOADS_LIMIT = 10;\n    const COMPANION_URL = "";\n    const UPPY_UPLOAD_PATH = "";\n    const RES_ID = "";\n    const RES_TITLE = "";\n    const HS_S_ID = "";\n    const GOOGLE_PICKER_CLIENT_ID  = "";\n    const GOOGLE_PICKER_API_KEY = "";\n    const GOOGLE_PICKER_APP_ID = "";\n  </script>\n  <script type="module" src="https://storage.googleapis.com/hydroshare-prod-static-media/static/js/hs_uppy.8f8f1745f2f5.mjs"></script>\n\n        </div>\n    \n\n\n<style>\n    footer {\n        background: #093E54;\n        color: #FFF;\n    }\n    footer a {\n        color: #B5E655;\n    }\n    footer a:hover {\n        color: #81D685;\n        text-decoration: none;\n    }\n    footer .headline {\n        margin-bottom: 20px;\n    }\n    footer .headline h3{\n        text-transform: uppercase;\n        color: #FFF;\n    }\n    .legal {\n        padding: 40px 0;\n    }\n    .legal a {\n        color: #B5E655;\n        text-decoration: none;\n    }\n    .social ul {\n        background: #3E7A8C;\n        color: white;\n        font-size: 24px;\n        margin: 0;\n        padding: 0;\n    }\n    .social li {\n        float: left;\n        display: block;\n        list-style-type: none;\n        width: 28px;\n        height: 28px;\n        margin: 0 5px 5px 0;\n        text-align: center;\n        line-height: 28px;\n    }\n    .social li:hover {\n        background: none;\n    }\n    .social li a {\n        color: #FFF;\n    }\n    .social li:hover a {\n        transition: color 0.1s;\n        -webkit-transition: color 0.1s;\n        -moz-transition: color 0.1s;\n        -o-transition: color 0.1s;\n        color: #B5E655;\n    }\n    footer .hl-btn-default {\n        color: #fff;\n        background: none;\n    }\n    footer .hl-btn-default:hover {\n        color: #3E7A8C;\n        background: #fff;\n        font-weight: bold;\n        border: 1px solid #fff;\n    }\n    footer .form-control {\n        border: white;\n    }\n    footer .form-control:focus {\n        border: white;\n    }\n    footer .sbtn {\n        margin-bottom: 5px;\n    }\n</style>\n\n<footer>\n    <div class="container">\n        <div class="row">\n            <!-- Contact Us\n            =================  -->\n            <div class="col-md-4 col-sm-4">\n                \n                    <div class="headline">\n                        <h3>Contact us</h3>\n                    </div>\n                    <div class="content">\n                        <p class="p1"><a href="mailto:[email protected]">Email Support</a></p>\n<p class="p1">Visit <a href="https://www.cuahsi.org" target="_blank">cuahsi.org</a></p>\n                    </div>\n                \n            </div>\n            <!-- Social icons\n            ===================== -->\n            <div class="col-md-4 col-sm-4">\n                \n                    <div class="headline"><h3>Follow</h3></div>\n                \n                <div class="content social">\n                    \n                    \n                        <ul>\n                            <li>\n                                <a href="http://twitter.com/cuahsi" target="_blank"><i class="fa fa-twitter"></i></a>\n                            </li>\n                        \n                            \n                                <li>\n                                    <a href="https://www.facebook.com/pages/CUAHSI-Consortium-of-Universities-for-the-Advancement-of-Hydrologic-Science-Inc/179921902590" target="_blank"><i\n                                            class="fa fa-facebook"></i></a>\n                                </li>\n                            \n                            \n                            \n                                <li>\n                                    <a href="https://www.youtube.com/user/CUAHSI" target="_blank"><i class="fa fa-youtube"></i></a>\n                                </li>\n                            \n                            \n                                <li>\n                                    <a href="http://github.com/hydroshare" target="_blank"><i\n                                            class="fa fa-github"></i></a>\n                                </li>\n                            \n                            \n                                <li>\n                                    <a href="https://www.linkedin.com/company/2632114" target="_blank"><i\n                                            class="fa fa-linkedin"></i></a>\n                                </li>\n                            \n                            \n                            \n                        </ul>\n                    \n                    <div class="clearfix"></div>\n                </div>\n            </div>\n            <!-- Subscribe\n            =============== -->\n            <div class="col-md-4 col-sm-4">\n                \n                    <div class="headline"><h3>Open Source</h3></div>\n                    <div class="content">\n                        <p class="p1">HydroShare is Open Source. Find us on <a href="https://github.com/hydroshare/" target="_blank"><strong>Github</strong></a>.</p>\n<p class="p1">Report a bug <strong><a href="https://github.com/hydroshare/hydroshare/issues?state=open" target="_blank">here</a></strong></p>\n<p class="p1">This is HydroShare Version<b>&nbsp;3.9.0</b></p>\n                    </div>\n                \n            </div>\n        </div>\n    </div>\n    <!-- Legal\n    ============= -->\n    <div class="legal">\n        <div class="container">\n            <div class="row">\n                <div class="col-md-12">\n                    \n                        <p>&copy 2025 CUAHSI. This material is based upon work supported by the National Science Foundation (NSF) under awards 1148453, 1148090, 1664018, 1664061, 1338606, 1664119, and 1849458.  Any opinions, findings, conclusions, or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of the NSF. | <a href="/terms-of-use">Terms Of Use</a> | <a\n                                href="/privacy">Statement of Privacy</a> | <a href="/sitemap/">Site Map</a>\n                        </p>\n                    \n                </div>\n            </div>\n        </div>\n    </div>\n</footer>\n\n</body>\n</html>\n'

@sblack-usu mentioned that this error is due to issues with the encoded spaces in the metadata file not getting unencoded.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions