Repository: hydroshare/hydroshare

Issue:
Task for updating geospatial relations from Geoconnex API fails when custom relation
**Description of the bug**
Task for updating geospatial relations from Geoconnex API fails when custom relation:
We allow for custom (user typed value w no validation) GeospatialRelation metada.
We have a task [update_from_geoconnex_task](https://github.com/hydroshare/hydroshare/blob/5032_geoconnex_isurl/hs_core/tasks.py#L250) that runs periodically.
That task checks the Geoconnex API for updates to the Geospatial Features.
The issue is that: the task attempts to find custom items in the Geoconnex API.

Steps to reproduce the bug:
You can see this bug occurring in the Celery Flower panel:
![image](https://user-images.githubusercontent.com/17934193/229533516-8a2ca05d-0ad8-4d95-b3c4-06d37d7c67b3.png)

```
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/celery/app/trace.py", line 451, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/celery/app/trace.py", line 734, in __protected_call__
    return self.run(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/celery/app/autoretry.py", line 54, in run
    ret = task.retry(exc=exc, **retry_kwargs)
  File "/usr/local/lib/python3.9/site-packages/celery/app/task.py", line 717, in retry
    raise_with_context(exc)
  File "/usr/local/lib/python3.9/site-packages/celery/app/autoretry.py", line 34, in run
    return task._orig_run(*args, **kwargs)
  File "/hydroshare/hs_core/tasks.py", line 252, in update_from_geoconnex_task
    loop.run_until_complete(utils.update_geoconnex_texts())
  File "/usr/local/lib/python3.9/asyncio/base_events.py", line 647, in run_until_complete
    return future.result()
  File "/hydroshare/hs_core/hydroshare/utils.py", line 475, in update_geoconnex_texts
    await asyncio.gather(*[
  File "/hydroshare/hs_core/hydroshare/utils.py", line 462, in get_jsonld_from_geoconnex
    id = relative_id.split("/")[1]
IndexError: list index out of range
```

To recreate this locally:
1. Create a resource and add a CUSTOM geospatial relation by typing it in and hitting enter: 
![image](https://user-images.githubusercontent.com/17934193/229535400-46afc9cf-86da-4a42-a267-c3ce503ec08e.png)
2. Open a shell and run the [update_from_geoconnex_task](https://github.com/hydroshare/hydroshare/blob/5032_geoconnex_isurl/hs_core/tasks.py#L250)
3. The task fails with `  File "/hydroshare/hs_core/hydroshare/utils.py", line 462, in get_jsonld_from_geoconnex
    id = relative_id.split("/")[1]
IndexError: list index out of range`

**Expected behavior**
We shouldnt make calls to the Geoconnex api for custom text relations

**Additional information**
HS v2.4.2



Discussion:

Resolving patch:
diff --git a/hs_core/hydroshare/utils.py b/hs_core/hydroshare/utils.py
--- a/hs_core/hydroshare/utils.py
+++ b/hs_core/hydroshare/utils.py
@@ -23,7 +23,7 @@
 from django.core.files import File
 from django.core.files.uploadedfile import UploadedFile
 from django.core.files.storage import DefaultStorage
-from django.core.validators import validate_email
+from django.core.validators import validate_email, URLValidator
 
 from mezzanine.conf import settings
 
@@ -471,6 +471,8 @@ async def update_geoconnex_texts(relations=[]):
     # Task to update Relations from Geoconnex API
     if not relations:
         relations = await _get_relations()
+    validator = URLValidator(regex="geoconnex")
+    relations = [r for r in relations if isGeoconnexUrl(r.value, validator)]
     async with aiohttp.ClientSession("https://reference.geoconnex.us") as client:
         await asyncio.gather(*[
             get_jsonld_from_geoconnex(relation, client)
@@ -479,6 +481,16 @@ async def update_geoconnex_texts(relations=[]):
     logger.debug("DONE CHECKING RELATIONS")
 
 
+def isGeoconnexUrl(text, validator=None):
+    if not validator:
+        validator = URLValidator(regex="geoconnex")
+    try:
+        validator(text)
+        return True
+    except ValidationError:
+        return False
+
+
 def copy_and_create_metadata(src_res, dest_res):
     """
     Copy metadata from source resource to target resource except identifier, publisher, and date


Test patch: