Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
jon-ide committed Oct 31, 2024
2 parents 2cfa962 + 03220f1 commit 92b71f7
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 39 deletions.
2 changes: 1 addition & 1 deletion webapp/home/home_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from metapype.model.node import Node

RELEASE_NUMBER = '2024.10.09'
RELEASE_NUMBER = '2024.10.30'


def extract_caller_module_name():
Expand Down
2 changes: 1 addition & 1 deletion webapp/home/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{% import '_macros.html' as macros %}

{# The following must agree with RELEASE_NUMBER in home_utils.py #}
{% set release_number = '2024.10.09' %}
{% set release_number = '2024.10.30' %}
{% set optional = 'Black' %}

{% block head %}
Expand Down
11 changes: 9 additions & 2 deletions webapp/home/templates/faq.html
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ <h4>Frequently Asked Questions</h4>
</div>
</div>
<div class="faq-item">
<div class="faq-question">How do I enter and preview Markdown?</div>
<div class="faq-question">How do I enter and preview Markdown and LaTeX?</div>
<div class="faq-answer">The EML standard allows certain metadata elements, such as Abstract and Method Step Description, to include Markdown formatting.<p></p>

In order to enter Markdown tags in ezEML, you need to enable "Complex Text Element Editing" on the <b>Settings</b> page, accessible via the <b>EML Documents</b> menu. For details on how complex text element editing works, see the associated <b>Help</b>
Expand All @@ -161,7 +161,14 @@ <h4>Frequently Asked Questions</h4>
- Goodbye<br>
\&lt;/markdown\&gt;<br>
\&lt;/abstract\&gt;
</code>
</code><p></p>
To enter equations via LaTeX, enable Complex Text Element Editing and enter the LaTeX code. No need to use Markdown. For example:<p></p>
<code>
\&lt;abstract\&gt;<br>
Equation 1: $$VWC = -5.3 \times 10^{-2} + 2.92 \times 10^{-2}K_a - 5.5 \times 10^{-4}K_a^2 + 4.3 \times 10^{-6}K_a^3$$<br>
\&lt;/abstract\&gt;
</code><p></p>
As in the Markdown case, preview the rendering of the LaTeX code by using <b>Preview Your Metadata in the EDI Data Portal</b> in the <b>Import/Export</b> menu.
</div>
</div>
{# <div class="faq-item">#}
Expand Down
11 changes: 11 additions & 0 deletions webapp/home/templates/news.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ <h4 align="left">What's New</h4>
<td style="vertical-align: top;">&nbsp;</td>
<td></td>
</tr>
<tr>
<td style="vertical-align: top;">2024.10.30</td>
<td>
<b>Added NSF Funding Award Lookup</b><br>
The <b>Funding Award</b> page for projects now includes an <b>NSF Award Lookup</b> button that retrieves the funding award's title from the National Science Foundation's public API.
</td>
</tr>
<tr>
<td style="vertical-align: top;">&nbsp;</td>
<td></td>
</tr>
<tr>
<td style="vertical-align: top;">2024.10.09</td>
<td>
Expand Down
4 changes: 2 additions & 2 deletions webapp/home/utils/load_and_save.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,15 +260,15 @@ def strip_elements_added_by_pasta(filename:str=None, eml_node:Node=None):
dataset_node = eml_node.find_child(names.DATASET)
alternate_id_nodes = dataset_node.find_all_children(names.ALTERNATEIDENTIFIER)
for alternate_id_node in alternate_id_nodes:
if alternate_id_node and 'pasta' in alternate_id_node.content:
if alternate_id_node and ('doi:10.6073/' in alternate_id_node.content or 'doi:10.0311/' in alternate_id_node.content):
node_utils.remove_child(alternate_id_node)
modified = True
distribution_nodes = dataset_node.find_all_children(names.DISTRIBUTION)
for distribution_node in distribution_nodes:
online_nodes = distribution_node.find_all_children(names.ONLINE)
for online_node in online_nodes:
url_node = online_node.find_child(names.URL)
if url_node and url_node.content and 'pasta' in url_node.content:
if url_node and url_node.content and ('doi:10.6073/' in url_node.content or 'doi:10.0311/' in url_node.content):
node_utils.remove_child(distribution_node)
modified = True
if modified:
Expand Down
12 changes: 12 additions & 0 deletions webapp/static/help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ The unique identifier used by the funder to uniquely identify an award.

These are typically alphanumeric values that are unique within the system used by a given funder. The number should be listed using the canonical form that each funder uses to express its award numbers and should not be prefixed or postfixed with extra text such as the acronym of the funder or the name of the funder, which is available instead in the Funder Name field.
--------------------
award_lookup
NSF Award Lookup
If the funding award is from the National Science Foundation (NSF), you can enter the Award Number and click <b>NSF Award Lookup</b> to have ezEML look up the Award Title for you. This lets you check that the award number you've entered correctly matches the award you intended.

The Award Number should be numeric. E.g., 1234567, not NSF-1234567 or #1234567.

If the award number is found, the Award Title field will be filled in with the title of the award. If it turns out that the award is not the one you intended, you can always click <b>Cancel</b> to leave the page without saving the award information.

Of course, you can manually enter the Award Title, instead of using <b>NSF Award Lookup</b>.

If the Award Number field is empty, the NSF Award Lookup button will be disabled.
--------------------
award_title
Award Title
The title of the award or grant. This field is required.
Expand Down
85 changes: 73 additions & 12 deletions webapp/views/project/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

import collections
import requests

import daiquiri
from flask import (
Expand Down Expand Up @@ -328,6 +329,42 @@ def funding_award_select_get(filename=None, form=None, project_node_id=None):
form=form, help=help, related_project=related_project)


def get_award_title(award_number):
"""
Fetch the title of an NSF award given its award number.
Args:
award_number (str): The NSF award number
Returns:
str: The title of the award
Raises:
requests.RequestException: If the API request fails
KeyError: If the response doesn't contain the expected data structure
"""
award_number = award_number.strip()
if not award_number or not award_number.isdigit():
raise ValueError(f'Not a valid award number: "{award_number}"')

url = f"http://api.nsf.gov/services/v1/awards/{award_number}.json"

try:
response = requests.get(url)
response.raise_for_status() # Raise an exception for bad status codes

data = response.json()
if not data["response"]["award"]:
raise ValueError(f'No award data found for award number "{award_number}"')
title = data["response"]["award"][0]["title"]
return title

except requests.RequestException as e:
raise requests.RequestException(f"Failed to fetch award data: {e}")
except (KeyError, IndexError) as e:
raise KeyError(f"Failed to extract title from response: {e}")


@proj_bp.route('/funding_award/<filename>/<node_id>', methods=['GET', 'POST'])
@proj_bp.route('/funding_award/<filename>/<node_id>/<project_node_id>', methods=['GET', 'POST'])
@login_required
Expand All @@ -347,6 +384,8 @@ def funding_award(filename=None, node_id=None, project_node_id=None):
else:
project_node = Node.get_node_instance(project_node_id)

submit_type = None

if request.method == 'POST':
form_value = request.form
form_dict = form_value.to_dict(flat=False)
Expand All @@ -357,12 +396,12 @@ def funding_award(filename=None, node_id=None, project_node_id=None):

# if request.method == 'POST' and form.validate_on_submit():
if request.method == 'POST':
next_page = PAGE_FUNDING_AWARD_SELECT
next_page = handle_hidden_buttons(PAGE_FUNDING_AWARD_SELECT)

submit_type = None
if is_dirty_form(form):
if 'Lookup' in form_dict:
submit_type = 'Lookup'
elif 'OK' in form_dict or is_hidden_button():
submit_type = 'Save Changes'
# flash(f'submit_type: {submit_type}')

if submit_type == 'Save Changes':
funder_name = form.funder_name.data
Expand Down Expand Up @@ -390,11 +429,25 @@ def funding_award(filename=None, node_id=None, project_node_id=None):

save_both_formats(filename=filename, eml_node=eml_node)

url = select_post(filename, form, form_dict,
'POST', PAGE_FUNDING_AWARD_SELECT, PAGE_PROJECT,
PAGE_FUNDING_AWARD_SELECT, PAGE_FUNDING_AWARD,
project_node_id=project_node_id, import_page=PAGE_IMPORT_PARTIES)
return redirect(url)
url = select_post(filename, form, form_dict,
'POST', PAGE_FUNDING_AWARD_SELECT, PAGE_PROJECT,
next_page, PAGE_FUNDING_AWARD,
project_node_id=project_node_id, import_page=PAGE_IMPORT_PARTIES)
return redirect(url)

if submit_type == 'Lookup':
award_number = form.award_number.data
try:
award_title = get_award_title(award_number)
form.award_title.data = award_title
form.funder_name.data = 'National Science Foundation (NSF)'

except requests.RequestException as e:
flash(e, 'error')
except ValueError as e:
flash(e, 'error')
except KeyError as e:
flash(f"Failed to extract title from response: {e}", 'error')

# Process GET
if not project_node_id:
Expand All @@ -404,7 +457,7 @@ def funding_award(filename=None, node_id=None, project_node_id=None):
title = 'Related Project Funding Award'
related_project = True

if node_id != '1':
if node_id != '1' and submit_type != 'Lookup':
award_nodes = project_node.find_all_children(names.AWARD)
if award_nodes:
for award_node in award_nodes:
Expand All @@ -414,18 +467,26 @@ def funding_award(filename=None, node_id=None, project_node_id=None):

init_form_md5(form)

if form.award_title.data and form.funder_name.data:
lookup_confirm = 'If the lookup succeeds, the Funder Name and Award Title fields will be overwritten. OK to continue?'
elif form.award_title.data:
lookup_confirm = 'If the lookup succeeds, the Award Title field will be overwritten. OK to continue?'
else:
lookup_confirm = None
set_current_page('project')
help = [get_help('award'),
get_help('funder_name'),
get_help('award_title'),
get_help('funder_identifiers'),
get_help('award_number'),
get_help('award_lookup'),
get_help('funder_identifiers'),
get_help('award_url')]
return render_template('award.html',
title=title,
form=form,
help=help,
related_project=related_project)
related_project=related_project,
lookup_confirm=lookup_confirm)


def populate_award_form(form: AwardForm, award_node: Node):
Expand Down
86 changes: 65 additions & 21 deletions webapp/views/project/templates/award.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% extends "base.html" %}
{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}

{% block app_content %}
Expand All @@ -16,13 +12,16 @@
{% set help_award_title_id, help_award_title_title, help_award_title_content = help[2] %}
{% set help_award_title_btn = help_award_title_id ~ '_btn' %}
{% set help_award_title_dialog = help_award_title_id ~ '_dialog' %}
{% set help_funder_identifiers_id, help_funder_identifiers_title, help_funder_identifiers_content = help[3] %}
{% set help_funder_identifiers_btn = help_funder_identifiers_id ~ '_btn' %}
{% set help_funder_identifiers_dialog = help_funder_identifiers_id ~ '_dialog' %}
{% set help_award_number_id, help_award_number_title, help_award_number_content = help[4] %}
{% set help_award_number_id, help_award_number_title, help_award_number_content = help[3] %}
{% set help_award_number_btn = help_award_number_id ~ '_btn' %}
{% set help_award_number_dialog = help_award_number_id ~ '_dialog' %}
{% set help_award_url_id, help_award_url_title, help_award_url_content = help[5] %}
{% set help_award_lookup_id, help_award_lookup_title, help_award_lookup_content = help[4] %}
{% set help_award_lookup_btn = help_award_lookup_id ~ '_btn' %}
{% set help_award_lookup_dialog = help_award_lookup_id ~ '_dialog' %}
{% set help_funder_identifiers_id, help_funder_identifiers_title, help_funder_identifiers_content = help[5] %}
{% set help_funder_identifiers_btn = help_funder_identifiers_id ~ '_btn' %}
{% set help_funder_identifiers_dialog = help_funder_identifiers_id ~ '_dialog' %}
{% set help_award_url_id, help_award_url_title, help_award_url_content = help[6] %}
{% set help_award_url_btn = help_award_url_id ~ '_btn' %}
{% set help_award_url_dialog = help_award_url_id ~ '_dialog' %}
{% endif %}
Expand All @@ -45,12 +44,30 @@ <h5>Enter the funding award information below:</h5>
<td valign="middle" style="padding-top: 15px;">{{ macros.help_button(help_award_title_btn) }}</td>
</table>
<table>
<td>{{ wtf.form_field(form.funder_identifier, size=100) }}</td>
<td valign="middle" style="padding-top: 15px;">{{ macros.help_button(help_funder_identifiers_btn) }}</td>
<tr>
<td>{{wtf.form_field(form.award_number, size=70) }}
</td>
<td valign="middle" style="padding-top: 15px;">{{ macros.help_button(help_award_number_btn) }}
</td>
<td>
<table>
<td>
{% if lookup_confirm %}
<input class="btn btn-primary" id="nsf_award_lookup" style="margin-left: 25px;margin-top: 6px;" name="Lookup" type="submit"
formnovalidate="formnovalidate" value="NSF Award Lookup"
onclick="confirm('{{ lookup_confirm }}');"/></td>
{% else %}
<input class="btn btn-primary" id="nsf_award_lookup" style="margin-left: 25px;margin-top: 6px;" name="Lookup" type="submit"
formnovalidate="formnovalidate" value="NSF Award Lookup"/></td>
{% endif %}
<td valign="middle" style="padding-top: 15px;">{{ macros.help_button(help_award_lookup_btn) }}</td>
</table>
</td>
</tr>
</table>
<table>
<td>{{wtf.form_field(form.award_number, size=100) }}</td>
<td valign="middle" style="padding-top: 15px;">{{ macros.help_button(help_award_number_btn) }}</td>
<td>{{ wtf.form_field(form.funder_identifier, size=100) }}</td>
<td valign="middle" style="padding-top: 15px;">{{ macros.help_button(help_funder_identifiers_btn) }}</td>
</table>
<table>
<td>{{ wtf.form_field(form.award_url, size=100) }}</td>
Expand All @@ -59,6 +76,8 @@ <h5>Enter the funding award information below:</h5>
<br/><br/>
<input class="btn btn-primary" name="OK" type="submit" value="Save and Continue"/>
<input class="btn btn-primary" name="Cancel" type="submit" formnovalidate="formnovalidate" value="Cancel"/>
<br/><br/>
<p></p>
{{ macros.hidden_buttons() }}
{{ form.csrf_token }}
{{ wtf.form_field(form.md5) }}
Expand All @@ -69,8 +88,9 @@ <h5>Enter the funding award information below:</h5>
{{ macros.help_dialog(help_award_dialog, help_award_title, help_award_content) }}
{{ macros.help_dialog(help_funder_name_dialog, help_funder_name_title, help_funder_name_content) }}
{{ macros.help_dialog(help_award_title_dialog, help_award_title_title, help_award_title_content) }}
{{ macros.help_dialog(help_funder_identifiers_dialog, help_funder_identifiers_title, help_funder_identifiers_content) }}
{{ macros.help_dialog(help_award_number_dialog, help_award_number_title, help_award_number_content) }}
{{ macros.help_dialog(help_award_lookup_dialog, help_award_lookup_title, help_award_lookup_content) }}
{{ macros.help_dialog(help_funder_identifiers_dialog, help_funder_identifiers_title, help_funder_identifiers_content) }}
{{ macros.help_dialog(help_award_url_dialog, help_award_url_title, help_award_url_content) }}
{% endblock %}

Expand All @@ -86,13 +106,16 @@ <h5>Enter the funding award information below:</h5>
{% set help_award_title_id, help_award_title_title, help_award_title_content = help[2] %}
{% set help_award_title_btn = help_award_title_id ~ '_btn' %}
{% set help_award_title_dialog = help_award_title_id ~ '_dialog' %}
{% set help_funder_identifiers_id, help_funder_identifiers_title, help_funder_identifiers_content = help[3] %}
{% set help_funder_identifiers_btn = help_funder_identifiers_id ~ '_btn' %}
{% set help_funder_identifiers_dialog = help_funder_identifiers_id ~ '_dialog' %}
{% set help_award_number_id, help_award_number_title, help_award_number_content = help[4] %}
{% set help_award_number_id, help_award_number_title, help_award_number_content = help[3] %}
{% set help_award_number_btn = help_award_number_id ~ '_btn' %}
{% set help_award_number_dialog = help_award_number_id ~ '_dialog' %}
{% set help_award_url_id, help_award_url_title, help_award_url_content = help[5] %}
{% set help_award_lookup_id, help_award_lookup_title, help_award_lookup_content = help[4] %}
{% set help_award_lookup_btn = help_award_lookup_id ~ '_btn' %}
{% set help_award_lookup_dialog = help_award_lookup_id ~ '_dialog' %}
{% set help_funder_identifiers_id, help_funder_identifiers_title, help_funder_identifiers_content = help[5] %}
{% set help_funder_identifiers_btn = help_funder_identifiers_id ~ '_btn' %}
{% set help_funder_identifiers_dialog = help_funder_identifiers_id ~ '_dialog' %}
{% set help_award_url_id, help_award_url_title, help_award_url_content = help[6] %}
{% set help_award_url_btn = help_award_url_id ~ '_btn' %}
{% set help_award_url_dialog = help_award_url_id ~ '_dialog' %}
{% endif %}
Expand All @@ -102,9 +125,30 @@ <h5>Enter the funding award information below:</h5>
{{ macros.help_script(help_award_dialog, help_award_btn) }}
{{ macros.help_script(help_funder_name_dialog, help_funder_name_btn) }}
{{ macros.help_script(help_award_title_dialog, help_award_title_btn) }}
{{ macros.help_script(help_funder_identifiers_dialog, help_funder_identifiers_btn) }}
{{ macros.help_script(help_award_number_dialog, help_award_number_btn) }}
{{ macros.help_script(help_award_lookup_dialog, help_award_lookup_btn) }}
{{ macros.help_script(help_funder_identifiers_dialog, help_funder_identifiers_btn) }}
{{ macros.help_script(help_award_url_dialog, help_award_url_btn) }}
});
</script>

<script>
document.addEventListener("DOMContentLoaded", function () {
const awardInput = document.getElementById('award_number');
const lookupButton = document.getElementById('nsf_award_lookup');

function toggleButtonState() {
const inputValue = awardInput.value.trim(); // Remove whitespace
lookupButton.disabled = inputValue === ""; // Enable if not empty
}

// Initialize button state on page load
toggleButtonState();

// Listen for input changes
awardInput.addEventListener('input', toggleButtonState);
});

</script>

{% endblock %}

0 comments on commit 92b71f7

Please sign in to comment.