diff --git a/backend/cms_plugins.py b/backend/cms_plugins.py index b1aaacb..1bd52a8 100644 --- a/backend/cms_plugins.py +++ b/backend/cms_plugins.py @@ -3,19 +3,7 @@ from django.utils.translation import gettext_lazy as _ from .models import ( HydroShareResource, - HydroShareResourceList, - ZoteroBibliographyResource, - HydroLearnModulesList, ) -from hs_restclient import HydroShare, HydroShareAuthBasic -import uuid -import requests -from bs4 import BeautifulSoup -from pyzotero import zotero - -# from datetime import datetime - -import datetime import logging @@ -32,265 +20,3 @@ class HydroShareResourcePlugin(CMSPluginBase): def render(self, context, instance, placeholder): context = super().render(context, instance, placeholder) return context - - -@plugin_pool.register_plugin -class HydroShareResourceListPlugin(CMSPluginBase): - model = HydroShareResourceList - name = _("HydroShare Resource List Plugin") - render_template = "hydroshare_list_resources.html" - cache = False - - def render(self, context, instance, placeholder): - create_hydroshare_resources(instance) - context = super().render(context, instance, placeholder) - return context - - -@plugin_pool.register_plugin -class HydroLearnPlugin(CMSPluginBase): - model = HydroLearnModulesList - name = _("HydroLearn Plugin") - render_template = "hydrolearn_list_modules.html" - cache = False - - def render(self, context, instance, placeholder): - instance.updated_version = instance.updated_version + 1 - instance.save(update_fields=["updated_version"]) - context = super().render(context, instance, placeholder) - return context - - -@plugin_pool.register_plugin -class ZoteroBibliographyResourcePlugin(CMSPluginBase): - model = ZoteroBibliographyResource - name = _("Zotero Citation Resource Plugin") - render_template = "zp.html" - cache = False - - # This is key in order to call the API every time the page renders - # The instance.save calls the pre_save signal which makes the call of the API - def render(self, context, instance, placeholder): - # logging.warning("rendering") - - instance.updated_version = instance.updated_version + 1 - instance.save(update_fields=["updated_version"]) - context = super().render(context, instance, placeholder) - # logging.warning("finish rendering") - - return context - - -def create_html_citations(instance): - logger.warning("creating_html_citations ") - params = { - "include": "bib,data", - "style": "apa", - "sort": "date", - "direction": "desc", - "linkwrap": 1, - } - try: - zot = zotero.Zotero( - instance.library_id, instance.library_type, instance.api_key - ) - if instance.collection_id: - items = zot.collection_items(instance.collection_id, **params) - else: - items = zot.items(**params) - # Initialize a dictionary to store publications by year - publications_by_year = {} - - # Iterate through the data and populate the dictionary - for item in items: - # Extract the year from "parsedDate" (if available) - parsed_date = item.get("meta", {}).get("parsedDate", "") - year = parsed_date.split("-")[0] if parsed_date else "More Publications" - - # Add the publication to the corresponding year's list - if year not in publications_by_year: - publications_by_year[year] = [] - publications_by_year[year].append(item["bib"]) - - instance.html = publications_by_year - instance.save(update_fields=["html"]) - - except Exception as e: - instance.html = {"Error": [f"The following error: {e}"]} - - -def create_hydroshare_resources(instance): - # logger.warning(instance.updated_version) - keywords = [] - json_resources = {"list_resources": []} - # logging.warning(instance.user,instance.password) - if instance.tags: - keywords = instance.tags.split(",") - # logging.warning(keywords) - if instance.user != "" and instance.password != "": - auth = HydroShareAuthBasic(username=instance.user, password=instance.password) - hs = HydroShare(auth=auth) - else: - hs = HydroShare(prompt_auth=False) - - try: - # let's call the resources - resources_api = hs.resources(subject=keywords) - - resources_model = instance.resources.get("list_resources", []) - # logging.warning(resources_model) - - for resource_api in resources_api: - # logging.warning(resource_api['resource_title']) - - matching_resource_model = get_dict_with_attribute( - resources_model, "resource_id", resource_api["resource_id"] - ) - # logging.warning("this is a matching_resource_model") - # logging.warning(matching_resource_model) - - # If resource found locally, then check last update date - if matching_resource_model: - is_recent_date = get_most_recent_date( - matching_resource_model["date_last_updated"], - resource_api["date_last_updated"], - ) - # logging.warning(is_recent_date) - if ( - is_recent_date - ): # If the resource retrieved from api is more recent, then update resource - # logging.warning("resource has a more recent version") - single_resource = update_resource(resource_api, hs, instance) - # logging.warning(single_resource) - json_resources["list_resources"].append(single_resource) - instance.resources = json_resources - - else: # resource is the same, then retrive the resource saved locally - # logging.warning("resource is the same") - - single_resource = matching_resource_model - json_resources["list_resources"].append(single_resource) - instance.resources = json_resources - # If the resource is not here then create one - else: - # logging.warning(resource) - # logging.warning("resource is new, creating now") - single_resource = update_resource(resource_api, hs, instance) - json_resources["list_resources"].append(single_resource) - - instance.resources = json_resources - # logging.warning(json_resources) - - instance.save(update_fields=["resources"]) - except Exception as e: - instance.resources = {"Error": [f"The following error: {e}"]} - - -def get_dict_with_attribute(list_of_dicts, attribute, value): - # Loop through each dictionary in the list - for dictionary in list_of_dicts: - # logging.warning(dictionary) - # if attribute in dictionary: - # logging.warning(dictionary[attribute]) - # Check if the attribute exists in the dictionary and has the specified value - if attribute in dictionary and dictionary[attribute] == value: - return dictionary # Return the dictionary if found - - return None # Return None if not found in any dictionary - - -def get_most_recent_date(date_local_resource, date_api): - # logging.warning(f'{date_local_resource} , {date_api}') - - # Convert strings to datetime objects - date_time_local_resource = datetime.datetime.fromisoformat(date_local_resource[:-1]) - date_time_api = datetime.datetime.fromisoformat(date_api[:-1]) - # logging.warning(f'{date_time_local_resource} , {date_time_api}') - # Compare the datetime objects - if date_time_local_resource > date_time_api: - return False - elif date_time_local_resource < date_time_api: - return True - else: - return False - - -def update_resource(resource, hs, instance): - # logging.warning(science_metadata_json) - single_resource = {} - if resource["resource_type"] == "ToolResource": - science_metadata_json = hs.getScienceMetadata(resource["resource_id"]) - # logging.warning(f'{science_metadata_json}') - image_url = science_metadata_json.get( - "app_icon", instance.placeholder_image - ).get("value", instance.placeholder_image) - web_site_url = ( - "" - if not science_metadata_json.get("app_home_page_url", "") - else science_metadata_json.get("app_home_page_url").get("value", "") - ) - github_url = ( - "" - if not science_metadata_json.get("source_code_url", "") - else science_metadata_json.get("source_code_url").get("value", "") - ) - help_page_url = ( - "" - if not science_metadata_json.get("help_page_url", "") - else science_metadata_json.get("help_page_url").get("value", "") - ) - if resource["resource_type"] == "CompositeResource": - resource_scrapping = requests.get(resource["resource_url"]) - image_url = ( - instance.placeholder_image - if not extract_value_by_name(resource_scrapping.content, "app_icon") - else extract_value_by_name(resource_scrapping.content, "app_icon") - ) - web_site_url = ( - "" - if not extract_value_by_name(resource_scrapping.content, "home_page_url") - else extract_value_by_name(resource_scrapping.content, "home_page_url") - ) - github_url = ( - "" - if not extract_value_by_name(resource_scrapping.content, "source_code_url") - else extract_value_by_name(resource_scrapping.content, "source_code_url") - ) - help_page_url = ( - "" - if not extract_value_by_name(resource_scrapping.content, "help_page_url") - else extract_value_by_name(resource_scrapping.content, "help_page_url") - ) - - if image_url == "": - image_url = instance.placeholder_image - - single_resource = { - "title": resource["resource_title"], - "abstract": resource["abstract"], - "github_url": github_url, - "image": image_url, - "web_site_url": web_site_url, - "documentation_url": help_page_url, - "unique_identifier": f"{uuid.uuid4()}", - "resource_id": resource["resource_id"], - "date_last_updated": resource["date_last_updated"], - "resource_type": resource["resource_type"], - "resource_url": resource["resource_url"], - } - # logging.warning(single_resource) - return single_resource - - -def extract_value_by_name(html, name): - soup = BeautifulSoup(html, "html.parser") - rows = soup.select("#extraMetaTable tbody tr") - - for row in rows: - name_cell = row.select_one("td:first-child") - value_cell = row.select_one("td:nth-child(2)") - - if name_cell and value_cell and name_cell.get_text(strip=True) == name: - return value_cell.get_text(strip=True) - - return None diff --git a/backend/models.py b/backend/models.py index 43c217e..3e40429 100644 --- a/backend/models.py +++ b/backend/models.py @@ -1,17 +1,9 @@ from cms.models.pluginmodel import CMSPlugin from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models -from pyzotero import zotero -from hs_restclient import HydroShare, HydroShareAuthBasic -import requests -# from datetime import datetime -import time - -import datetime import uuid -from django.db.models.signals import pre_save, post_save -from django.dispatch import receiver + import logging logger = logging.getLogger(__name__) @@ -32,127 +24,3 @@ class HydroShareResource(CMSPlugin): documentation_url = models.CharField(max_length=200, default="", blank=True) web_site_url = models.CharField(max_length=200, default="", blank=True) unique_identifier = models.UUIDField(default=uuid.uuid4, editable=False) - - -class HydroShareResourceList(CMSPlugin): - user = models.CharField(max_length=200, default="", blank=True) - password = models.CharField(max_length=200, default="", blank=True) - placeholder_image = models.CharField( - max_length=200, default="https://picsum.photos/200" - ) - # width= models.PositiveIntegerField(default=200, validators=[MinValueValidator(150), MaxValueValidator(400)]) - # height=models.PositiveIntegerField(default=200, validators=[MinValueValidator(150), MaxValueValidator(400)]) - tags = models.CharField(max_length=200, default="") - updated_version = models.IntegerField(default=0, editable=False) - resources = models.JSONField(editable=False, default=dict) - - -class HydroLearnModulesList(CMSPlugin): - organization = models.CharField(max_length=200, default="", blank=True) - placeholder_image = models.CharField( - max_length=200, default="https://picsum.photos/200" - ) - updated_version = models.IntegerField(default=0, editable=False) - modules = models.JSONField(editable=False, default=dict) - - -class ZoteroBibliographyResource(CMSPlugin): - api_key = models.CharField(max_length=200, default="") - library_type = models.CharField(max_length=200, default="") - library_id = models.CharField(max_length=200, default="") - collection_id = models.CharField(max_length=200, default="", blank=True) - style = models.CharField(max_length=200, default="apa") - html = models.JSONField(editable=False) - unique_identifier = models.UUIDField(default=uuid.uuid4, editable=False) - updated_version = models.IntegerField(default=0, editable=False) - link_of_library_or_collection = models.CharField(max_length=400, default="") - is_saving = models.BooleanField(default=False, editable=False) - - -@receiver(post_save, sender=ZoteroBibliographyResource) -def create_html_citations(sender, instance, *args, **kwargs): - logger.warning("creating_html_citations ") - params = { - "include": "bib,data", - "style": "apa", - "sort": "date", - "direction": "desc", - "linkwrap": 1, - } - try: - - zot = zotero.Zotero( - instance.library_id, instance.library_type, instance.api_key - ) - if instance.collection_id: - items = zot.collection_items(instance.collection_id, **params) - else: - items = zot.items(**params) - # Initialize a dictionary to store publications by year - publications_by_year = {} - - # Iterate through the data and populate the dictionary - for item in items: - # Extract the year from "parsedDate" (if available) - parsed_date = item.get("meta", {}).get("parsedDate", "") - year = parsed_date.split("-")[0] if parsed_date else "More Publications" - - # Add the publication to the corresponding year's list - if year not in publications_by_year: - publications_by_year[year] = [] - publications_by_year[year].append(item["bib"]) - - instance.html = publications_by_year - except Exception as e: - instance.html = {"Error": [f"The following error: {e}"]} - - -@receiver(post_save, sender=HydroLearnModulesList) -def fetch_hydrolearn_modules(sender, instance, *args, **kwargs): - modules_list = [] - try: - URL = "https://edx.hydrolearn.org" - client = requests.session() - client.get(URL) # sets cookie for CSRF - csrftoken = client.cookies.get("csrftoken", "") or client.cookies.get( - "csrf", "" - ) - courses_url = f"{URL}/search/course_discovery/" - - login_data = {"csrfmiddlewaretoken": csrftoken} - courses_response = client.post( - courses_url, data=login_data, headers={"Referer": courses_url} - ) - courses_list = courses_response.json()["results"] - - if instance.organization: - - def is_from_organization(course): - return course["data"]["org"] == instance.organization - - courses_list = filter(is_from_organization, courses_list) - for course in courses_list: - course_data = course["data"] - course_dict = { - "course_title": course_data["content"]["display_name"], - "course_url": f"{URL}/courses/{course_data.get('course')}/about", - "course_image_url": ( - f'{URL}{course_data.get("image_url")}' - if course_data.get("image_url", "") != "" - else "" - ), - "course_organization": course_data.get("org", ""), - "course_code": course_data.get("number", ""), - "course_weekly_effort": course_data.get("effort", ""), - "course_description_content": course_data.get("content").get( - "short_description", "" - ), - } - logger.warning(course_dict) - - modules_list.append(course_dict) - - instance.modules = modules_list - except Exception as e: - logger.warning(f"Error fetching HydroLearn modules: {e}") - instance.modules = modules_list diff --git a/backend/templates/hydrolearn_list_modules.html b/backend/templates/hydrolearn_list_modules.html deleted file mode 100644 index b61a7fd..0000000 --- a/backend/templates/hydrolearn_list_modules.html +++ /dev/null @@ -1,97 +0,0 @@ -{% load cms_tags sekizai_tags %} - -{% addtoblock "css" %} - -{% endaddtoblock %} -
- -
- - -
-
- {% for module in instance.modules %} - {% include "single_hydrolearn_module.html" with module=module %} - {% endfor %} -
-
\ No newline at end of file diff --git a/backend/templates/hydroshare_list_resources.html b/backend/templates/hydroshare_list_resources.html deleted file mode 100644 index 5d328d6..0000000 --- a/backend/templates/hydroshare_list_resources.html +++ /dev/null @@ -1,97 +0,0 @@ -{% load cms_tags sekizai_tags %} - -{% addtoblock "css" %} - -{% endaddtoblock %} -
- -
- - -
- {% for key, values in instance.resources.items %} -
- {% for resource in values %} - {% include "single_hs_resource.html" with resource=resource %} - {% endfor %} - -
- {% endfor %} -
\ No newline at end of file diff --git a/backend/templates/single_hs_resource.html b/backend/templates/single_hs_resource.html deleted file mode 100644 index ddd90f8..0000000 --- a/backend/templates/single_hs_resource.html +++ /dev/null @@ -1,71 +0,0 @@ -{% load cms_tags sekizai_tags %} - -{% addtoblock "js" %} - - -{% endaddtoblock %} - -
-
-
- {% if resource.web_site_url %} - - -
-
- - ... - - - -
-
- - - {% else %} - - ... - - {% endif %} -
-
-
-
-
{{ resource.title }}
-
-

- {% if resource.github_url %} - - {% endif %} - {% if resource.web_site_url %} - - {% endif %} - {% if resource.documentation_url %} - - {% endif %} - HydroShare -

-
-
- -

{{ resource.subtitle }}

-
-

- {{ resource.abstract }} -

-
-
-
-
-
- - diff --git a/backend/templates/single_hydrolearn_module.html b/backend/templates/single_hydrolearn_module.html deleted file mode 100644 index 4630a98..0000000 --- a/backend/templates/single_hydrolearn_module.html +++ /dev/null @@ -1,74 +0,0 @@ -{% load cms_tags sekizai_tags %} - -{% addtoblock "js" %} - -{% endaddtoblock %} - -
-
-
- - {% if module.course_url %} -
-
- - ... - - - -
-
- {% else %} -
-
- - ... - - - -
-
- - {% endif %} -
-
-
-
-
{{ module.course_title }}
-
-
-
-

- {% if module.course_organization %} - {{ module.course_organization }} - {% endif %} -

-
-
-

- {% if module.course_code %} - {{ module.course_code }} - {% endif %} -

-
-
- - {% if module.course_weekly_effort %} -

Effort: {{ module.course_weekly_effort }}

- {% endif %} - -
-

- {{ module.course_description_content }} -

-
-
-
-
-
- - diff --git a/backend/templates/zotero_bibliography.html b/backend/templates/zotero_bibliography.html deleted file mode 100644 index 1e82dce..0000000 --- a/backend/templates/zotero_bibliography.html +++ /dev/null @@ -1,67 +0,0 @@ -{% load sekizai_tags %} -{% load cms_tags %} - -{% addtoblock "js" %} - - -{% endaddtoblock %} - -{% addtoblock "css" %} - -{% endaddtoblock %} - -{% block content %} - -

No publications found

- - -{% endblock %} - - - - diff --git a/backend/templates/zp.html b/backend/templates/zp.html deleted file mode 100644 index c0f74b5..0000000 --- a/backend/templates/zp.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "zotero_bibliography.html" %} - - - - -{% block content %} - -
- {% for key, values in instance.html.items %} -
-

{{ key }}

- - {% for citation in values %} - - {{ citation | safe }} - - {% endfor %} - -
- {% endfor %} -
- -{% endblock %} - diff --git a/backend/templatetags/__init__.py b/backend/templatetags/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/backend/templatetags/loading_tag.py b/backend/templatetags/loading_tag.py deleted file mode 100644 index 42a4894..0000000 --- a/backend/templatetags/loading_tag.py +++ /dev/null @@ -1,79 +0,0 @@ -from django import template -from pyzotero import zotero -import logging -import time - -logger = logging.getLogger(__name__) -register = template.Library() - - -@register.simple_tag -def loading_indicator(instance): - # Assuming `instance` has a method or property to check if a field is being saved - logger.warning(instance._state.adding) - pubs = create_html_citations(instance) - # is_saving = getattr(instance, f"{field_name}", False) - - # if is_saving: - # Return HTML for the loading indicator - return pubs - # else: - # # Return an empty string or any other placeholder if not saving - # return "" - - -def create_html_citations(instance): - logger.warning("creating_html_citations ") - params = { - "include": "bib,data", - "style": "apa", - "sort": "date", - "direction": "desc", - "linkwrap": 1, - } - try: - time.sleep(5) - zot = zotero.Zotero( - instance.library_id, instance.library_type, instance.api_key - ) - if instance.collection_id: - items = zot.collection_items(instance.collection_id, **params) - else: - items = zot.items(**params) - # Initialize a dictionary to store publications by year - publications_by_year = {} - - # Iterate through the data and populate the dictionary - for item in items: - # Extract the year from "parsedDate" (if available) - parsed_date = item.get("meta", {}).get("parsedDate", "") - year = parsed_date.split("-")[0] if parsed_date else "More Publications" - - # Add the publication to the corresponding year's list - if year not in publications_by_year: - publications_by_year[year] = [] - publications_by_year[year].append(item["bib"]) - - return publications_by_year - except Exception as e: - return publications_by_year - - # {% load static %} - - # {% load loading_tag %} - - # {% loading_indicator instance as pubs %} - #
- # {% for key, values in pubs.items %} - #
- #

{{ key }}

- - # {% for citation in values %} - - # {{ citation | safe }} - - # {% endfor %} - - #
- # {% endfor %} - #
diff --git a/hydrolearn_modules_app/templates/single_hydrolearn_module.html b/hydrolearn_modules_app/templates/single_hydrolearn_module.html deleted file mode 100644 index 4630a98..0000000 --- a/hydrolearn_modules_app/templates/single_hydrolearn_module.html +++ /dev/null @@ -1,74 +0,0 @@ -{% load cms_tags sekizai_tags %} - -{% addtoblock "js" %} - -{% endaddtoblock %} - -
-
-
- - {% if module.course_url %} -
-
- - ... - - - -
-
- {% else %} -
-
- - ... - - - -
-
- - {% endif %} -
-
-
-
-
{{ module.course_title }}
-
-
-
-

- {% if module.course_organization %} - {{ module.course_organization }} - {% endif %} -

-
-
-

- {% if module.course_code %} - {{ module.course_code }} - {% endif %} -

-
-
- - {% if module.course_weekly_effort %} -

Effort: {{ module.course_weekly_effort }}

- {% endif %} - -
-

- {{ module.course_description_content }} -

-
-
-
-
-
- - diff --git a/hydroshare_resources_app/static/js/hs_resources.js b/hydroshare_resources_app/static/js/hs_resources.js index 200baf4..b0d1603 100644 --- a/hydroshare_resources_app/static/js/hs_resources.js +++ b/hydroshare_resources_app/static/js/hs_resources.js @@ -72,10 +72,10 @@ const fetchHydroShareResources = () => { if(resource.documentation_url){ resourcesHTML +=` ` } - resourcesHTML +=` HydroShare` + // resourcesHTML +=` HydroShare` resourcesHTML +=`

` - resourcesHTML +=`

${resource.subtitle}

` + resourcesHTML +=`

View on HydroShare

` resourcesHTML +=`