From 53e69597ea5f996bf2628faa4789d42309739527 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 9 Aug 2023 09:17:36 -0600 Subject: [PATCH 1/7] WIP ObservingSystemDataProduct relationship --- usaon_vta_survey/routes/__init__.py | 1 + .../observing_system_data_product.py | 221 ++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 usaon_vta_survey/routes/response/relationships/observing_system_data_product.py diff --git a/usaon_vta_survey/routes/__init__.py b/usaon_vta_survey/routes/__init__.py index 208e81d7..990c4a07 100644 --- a/usaon_vta_survey/routes/__init__.py +++ b/usaon_vta_survey/routes/__init__.py @@ -3,6 +3,7 @@ import usaon_vta_survey.routes.response.data_products import usaon_vta_survey.routes.response.observing_systems import usaon_vta_survey.routes.response.relationships.data_product_application +import usaon_vta_survey.routes.response.relationships.observing_system_data_product import usaon_vta_survey.routes.login import usaon_vta_survey.routes.logout import usaon_vta_survey.routes.user diff --git a/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py b/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py new file mode 100644 index 00000000..80571fd4 --- /dev/null +++ b/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py @@ -0,0 +1,221 @@ +from flask import Request, redirect, render_template, request, url_for +from flask_wtf import FlaskForm +from wtforms import FormField + +from usaon_vta_survey import app, db +from usaon_vta_survey.forms import FORMS_BY_MODEL +from usaon_vta_survey.models.tables import ( + ResponseDataProduct, + ResponseObservingSystem, + ResponseObservingSystemDataProduct, + Survey, +) +from usaon_vta_survey.util.authorization import limit_response_editors + + +def _update_super_form( + super_form: type[FlaskForm], + /, + *, + data_product_id: int | None, + observing_system_id: int | None, +) -> None: + """Populate the form of forms with sub-forms depending on provided IDs. + + When an ID for an object is not provided, we need to gather information from the + user to create that object. + + TODO: Better function name. + """ + if observing_system_id is None: + super_form.observing_system = FormField(FORMS_BY_MODEL[ResponseObservingSystem]) + + if data_product_id is None: + super_form.data_product = FormField(FORMS_BY_MODEL[ResponseDataProduct]) + + +def _update_relationship( + relationship: ResponseObservingSystemDataProduct, + *, + observing_system_id: int | None, + data_product_id: int | None, +) -> None: + """Populate the relationship with any known identifiers. + + TODO: Better function name. + """ + if observing_system_id: + relationship.response_observing_system_id = observing_system_id + + if data_product_id: + relationship.response_data_product_id = data_product_id + + +def _response_data_product( + *, + data_product_id: int | None, + response_id: int, +) -> ResponseDataProduct: + """Return a data product db object (or 404), and do some mutations. + + TODO: Extract mutations to another function responsible for that. + """ + if data_product_id is not None: + response_data_product = db.get_or_404(ResponseDataProduct, data_product_id) + else: + response_data_product = ResponseDataProduct(response_id=response_id) + + return response_data_product + + +def _response_observing_system( + *, + observing_system_id: int | None, + response_id: int, +) -> ResponseObservingSystem: + """Return an observing system db object (or 404), and do some mutations.""" + if observing_system_id is not None: + response_observing_system = db.get_or_404( + ResponseObservingSystem, observing_system_id + ) + else: + response_observing_system = ResponseObservingSystem(response_id=response_id) + + return response_observing_system + + +def _response_observing_system_data_product( + *, + observing_system_id: int | None, + data_product_id: int | None, +) -> ResponseObservingSystemDataProduct: + """Return a relationship db object. + + Returned object may be transient or persistent depending on whether a match exists + in the db. + """ + if data_product_id and observing_system_id: + # If not found, will be `None` + response_observing_system_data_product = db.session.get( + ResponseObservingSystemDataProduct, + (data_product_id, observing_system_id), + ) + else: + response_observing_system_data_product = None + + if response_observing_system_data_product is not None: + return response_observing_system_data_product + else: + return ResponseObservingSystemDataProduct() + + +def _request_args(request: Request) -> tuple[int | None, int | None]: + data_product_id: int | str | None = request.args.get('data_product_id') + if data_product_id is not None: + data_product_id = int(data_product_id) + + observing_system_id: int | str | None = request.args.get('observing_system_id') + if observing_system_id is not None: + observing_system_id = int(observing_system_id) + + return data_product_id, observing_system_id + + +@app.route( + '/response//observing_system_data_product_relationships', + methods=['GET', 'POST'], +) +def view_response_observing_system_data_product_relationships(survey_id: str): + """View and add observing system/dataproduct relationships to a response. + + TODO: Refactor this whole pile of stuff. Less string magic. Less cyclomatic + complexity. + """ + data_product_id, observing_system_id = _request_args(request) + survey = db.get_or_404(Survey, survey_id) + + class SuperForm(FlaskForm): + """Combine all necessary forms into one super-form. + + NOTE: Additional class attributes are added dynamically below. + """ + + relationship = FormField(FORMS_BY_MODEL[ResponseObservingSystemDataProduct]) + + response_observing_system_data_product = _response_observing_system_data_product( + data_product_id=data_product_id, + observing_system_id=observing_system_id, + ) + + response_data_product = _response_data_product( + data_product_id=data_product_id, + response_id=survey.response_id, + ) + + response_observing_system = _response_observing_system( + observing_system_id=observing_system_id, + response_id=survey.response_id, + ) + + _update_super_form( + SuperForm, + observing_system_id=observing_system_id, + data_product_id=data_product_id, + ) + _update_relationship( + response_observing_system_data_product, + observing_system_id=observing_system_id, + data_product_id=data_product_id, + ) + + form_obj: dict[ + str, + ResponseObservingSystem + | ResponseDataProduct + | ResponseObservingSystemDataProduct, + ] = { + 'observing_system': response_observing_system, + 'data_product': response_data_product, + # NOTE: Logic below depends on relationship being last in this dict + 'relationship': response_observing_system_data_product, + } + + if request.method == 'POST': + limit_response_editors() + form = SuperForm(request.form, obj=form_obj) + + if form.validate(): + # Add only submitted sub-forms into the db session + for key, obj in form_obj.items(): + if hasattr(form, key): + form[key].form.populate_obj(obj) + db.session.add(obj) + + # Update the relationship object with the ids of any new entities + if type(obj) is not ResponseObservingSystemDataProduct: + # Get the db object's new ID + db.session.flush() + db.session.refresh(obj) + + # Update the relationship db object + setattr( + response_observing_system_data_product, + f'response_{key}_id', + obj.id, + ) + + db.session.commit() + + return redirect(url_for('view_response_data_products', survey_id=survey.id)) + + form = SuperForm(obj=form_obj) + return render_template( + 'response/relationships/observing_system_data_product.html', + form=form, + survey=survey, + observing_system=response_observing_system, + observing_systems=survey.response.observing_systems, + data_product=response_data_product, + data_products=survey.response.data_products, + relationship=response_observing_system_data_product, + ) From e92023e1c56513b846d23c351ff1a27bac32cf16 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 9 Aug 2023 11:16:45 -0600 Subject: [PATCH 2/7] Add template --- .../observing_system_data_product.py | 1 + .../templates/macros/forms/misc.j2 | 41 +++++++++ .../observing_system_data_product.html | 88 +++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 usaon_vta_survey/templates/response/relationships/observing_system_data_product.html diff --git a/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py b/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py index 80571fd4..a64eb1a9 100644 --- a/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py +++ b/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py @@ -51,6 +51,7 @@ def _update_relationship( relationship.response_data_product_id = data_product_id +# may not need to be internal def _response_data_product( *, data_product_id: int | None, diff --git a/usaon_vta_survey/templates/macros/forms/misc.j2 b/usaon_vta_survey/templates/macros/forms/misc.j2 index 72a9e560..de2581be 100644 --- a/usaon_vta_survey/templates/macros/forms/misc.j2 +++ b/usaon_vta_survey/templates/macros/forms/misc.j2 @@ -155,3 +155,44 @@ {% endif %} {%- endmacro -%} + +{% macro observing_system_data_product_fields(form) -%} + {{form.criticality_rating.label}} {{form.criticality_rating(size=5)}} + {% if form.criticality_rating.errors %} +
    + {% for error in form.criticality_rating.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +
+ + {{form.performance_rating.label}} {{form.performance_rating(size=50)}} + {% if form.performance_rating.errors %} +
    + {% for error in form.performance_rating.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +
+ + {{form.rationale.label}} {{form.rationale(size=50)}} + {% if form.rationale.errors %} +
    + {% for error in form.rationale.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +
+ + {{form.needed_improvements.label}} {{form.needed_improvements(size=50)}} + {% if form.needed_improvements.errors %} +
    + {% for error in form.needed_improvements.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +{%- endmacro -%} diff --git a/usaon_vta_survey/templates/response/relationships/observing_system_data_product.html b/usaon_vta_survey/templates/response/relationships/observing_system_data_product.html new file mode 100644 index 00000000..2b407bcd --- /dev/null +++ b/usaon_vta_survey/templates/response/relationships/observing_system_data_product.html @@ -0,0 +1,88 @@ +{% extends 'response/base.html' %} +{% from 'macros/forms/misc.j2' import + observing_system_fields, + data_product_fields, + observing_system_data_product_fields +%} + + +{% block content %} + + {{super()}} + +

Observing System <-> Data Product relationship

+ + +
+ +
+

Obserivng Systems

+ + +
+ + +
+

Data Product

+ + +
+
+ +
+ {{form.csrf_token}} + +
+
+ {% if sqla_inspect(observing_system).transient %} + {{ observing_system_fields(form.observing_system.form) }} + {% else %} +

Name: {{observing_system.name}}

+ {% endif %} +
+ +
+ {% if sqla_inspect(data_product).transient %} + {{ data_product_fields(form.data_product.form) }} + {% else %} +

Name: {{data_product.name}}

+ {% endif %} +
+
+ +

Relationship

+ {% if sqla_inspect(relationship).transient %} + {{ observing_system_data_product_fields(form.relationship.form) }} + {% else %} + {{relationship}} + {% endif %} + + +
+ + +{% endblock %} From 9c322a23d46378a6a4f4a380f111ce842d25d311 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Wed, 9 Aug 2023 12:15:16 -0600 Subject: [PATCH 3/7] WIP data product relationship button --- usaon_vta_survey/templates/response/data_products.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/usaon_vta_survey/templates/response/data_products.html b/usaon_vta_survey/templates/response/data_products.html index c28905fa..7b6f93d4 100644 --- a/usaon_vta_survey/templates/response/data_products.html +++ b/usaon_vta_survey/templates/response/data_products.html @@ -27,7 +27,13 @@

Data products


{% endfor %} - Add relationship + + Add relationship + {% endfor %} From c8865e898cea58e012f469235059f8cc0d6db3e9 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Mon, 14 Aug 2023 10:03:06 -0600 Subject: [PATCH 4/7] Fix iterable data_product typo --- .../response/relationships/observing_system_data_product.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usaon_vta_survey/templates/response/relationships/observing_system_data_product.html b/usaon_vta_survey/templates/response/relationships/observing_system_data_product.html index 2b407bcd..31e861a8 100644 --- a/usaon_vta_survey/templates/response/relationships/observing_system_data_product.html +++ b/usaon_vta_survey/templates/response/relationships/observing_system_data_product.html @@ -43,7 +43,7 @@

Data Product

Create new data product - {% for dp in data_product %} + {% for dp in data_products %} From fb38895eb98fc68b8a5be2a602fe59704c4fe490 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Mon, 14 Aug 2023 13:49:18 -0600 Subject: [PATCH 5/7] Remove observing systems related column --- .../templates/response/observing_systems.html | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/usaon_vta_survey/templates/response/observing_systems.html b/usaon_vta_survey/templates/response/observing_systems.html index 0a3d5cd7..531657ee 100644 --- a/usaon_vta_survey/templates/response/observing_systems.html +++ b/usaon_vta_survey/templates/response/observing_systems.html @@ -11,24 +11,10 @@

Observing systems

- {% for observing_system in response.observing_systems %} - {% endfor %}
NameObserving systems related
{{observing_system.name}} - {% if not observing_system.observing_system_relationships %} - None -
- {% endif %} - - {% for observing_system_relationship in observing_system.input_relationships %} - {{observing_system_relationship}} -
- {% endfor %} - - Add relationship -
From 69a99f179348d0b2fcc48b21c2e9e5500874592d Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 15 Aug 2023 11:35:42 -0600 Subject: [PATCH 6/7] remove do some mutations from docstrings --- .../response/relationships/data_product_application.py | 7 ++----- .../relationships/observing_system_data_product.py | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/usaon_vta_survey/routes/response/relationships/data_product_application.py b/usaon_vta_survey/routes/response/relationships/data_product_application.py index 1ec36206..b05a86af 100644 --- a/usaon_vta_survey/routes/response/relationships/data_product_application.py +++ b/usaon_vta_survey/routes/response/relationships/data_product_application.py @@ -56,10 +56,7 @@ def _response_data_product( data_product_id: int | None, response_id: int, ) -> ResponseDataProduct: - """Return a data product db object (or 404), and do some mutations. - - TODO: Extract mutations to another function responsible for that. - """ + """Return a data product db object (or 404).""" if data_product_id is not None: response_data_product = db.get_or_404(ResponseDataProduct, data_product_id) else: @@ -73,7 +70,7 @@ def _response_application( application_id: int | None, response_id: int, ) -> ResponseApplication: - """Return an application db object (or 404), and do some mutations.""" + """Return an application db object (or 404).""" if application_id is not None: response_application = db.get_or_404(ResponseApplication, application_id) else: diff --git a/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py b/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py index a64eb1a9..ce7a646a 100644 --- a/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py +++ b/usaon_vta_survey/routes/response/relationships/observing_system_data_product.py @@ -57,10 +57,7 @@ def _response_data_product( data_product_id: int | None, response_id: int, ) -> ResponseDataProduct: - """Return a data product db object (or 404), and do some mutations. - - TODO: Extract mutations to another function responsible for that. - """ + """Return a data product db object (or 404).""" if data_product_id is not None: response_data_product = db.get_or_404(ResponseDataProduct, data_product_id) else: @@ -74,7 +71,7 @@ def _response_observing_system( observing_system_id: int | None, response_id: int, ) -> ResponseObservingSystem: - """Return an observing system db object (or 404), and do some mutations.""" + """Return an observing system db object (or 404).""" if observing_system_id is not None: response_observing_system = db.get_or_404( ResponseObservingSystem, observing_system_id From e68221df4a76ed4bb481388d3bfc6f016c1cdf33 Mon Sep 17 00:00:00 2001 From: Robyn Marowitz Date: Tue, 15 Aug 2023 11:40:41 -0600 Subject: [PATCH 7/7] Update macro form location --- .../templates/macros/forms/misc.j2 | 83 ------------------- .../macros/forms/relationships/app_sba.j2 | 81 ++++++++++++++++++ .../data_product_application.html | 3 + .../observing_system_data_product.html | 3 + 4 files changed, 87 insertions(+), 83 deletions(-) create mode 100644 usaon_vta_survey/templates/macros/forms/relationships/app_sba.j2 diff --git a/usaon_vta_survey/templates/macros/forms/misc.j2 b/usaon_vta_survey/templates/macros/forms/misc.j2 index de2581be..3bc596a5 100644 --- a/usaon_vta_survey/templates/macros/forms/misc.j2 +++ b/usaon_vta_survey/templates/macros/forms/misc.j2 @@ -113,86 +113,3 @@ {% endif %} {%- endmacro -%} - - -{% macro data_product_application_fields(form) -%} - {{form.criticality_rating.label}} {{form.criticality_rating(size=5)}} - {% if form.criticality_rating.errors %} -
    - {% for error in form.criticality_rating.errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} -
- - {{form.performance_rating.label}} {{form.performance_rating(size=50)}} - {% if form.performance_rating.errors %} -
    - {% for error in form.performance_rating.errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} -
- - {{form.rationale.label}} {{form.rationale(size=50)}} - {% if form.rationale.errors %} -
    - {% for error in form.rationale.errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} -
- - {{form.needed_improvements.label}} {{form.needed_improvements(size=50)}} - {% if form.needed_improvements.errors %} -
    - {% for error in form.needed_improvements.errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} -{%- endmacro -%} - -{% macro observing_system_data_product_fields(form) -%} - {{form.criticality_rating.label}} {{form.criticality_rating(size=5)}} - {% if form.criticality_rating.errors %} -
    - {% for error in form.criticality_rating.errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} -
- - {{form.performance_rating.label}} {{form.performance_rating(size=50)}} - {% if form.performance_rating.errors %} -
    - {% for error in form.performance_rating.errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} -
- - {{form.rationale.label}} {{form.rationale(size=50)}} - {% if form.rationale.errors %} -
    - {% for error in form.rationale.errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} -
- - {{form.needed_improvements.label}} {{form.needed_improvements(size=50)}} - {% if form.needed_improvements.errors %} -
    - {% for error in form.needed_improvements.errors %} -
  • {{ error }}
  • - {% endfor %} -
- {% endif %} -{%- endmacro -%} diff --git a/usaon_vta_survey/templates/macros/forms/relationships/app_sba.j2 b/usaon_vta_survey/templates/macros/forms/relationships/app_sba.j2 new file mode 100644 index 00000000..75692694 --- /dev/null +++ b/usaon_vta_survey/templates/macros/forms/relationships/app_sba.j2 @@ -0,0 +1,81 @@ +{% macro data_product_application_fields(form) -%} + {{form.criticality_rating.label}} {{form.criticality_rating(size=5)}} + {% if form.criticality_rating.errors %} +
    + {% for error in form.criticality_rating.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +
+ + {{form.performance_rating.label}} {{form.performance_rating(size=50)}} + {% if form.performance_rating.errors %} +
    + {% for error in form.performance_rating.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +
+ + {{form.rationale.label}} {{form.rationale(size=50)}} + {% if form.rationale.errors %} +
    + {% for error in form.rationale.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +
+ + {{form.needed_improvements.label}} {{form.needed_improvements(size=50)}} + {% if form.needed_improvements.errors %} +
    + {% for error in form.needed_improvements.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +{%- endmacro -%} + +{% macro observing_system_data_product_fields(form) -%} + {{form.criticality_rating.label}} {{form.criticality_rating(size=5)}} + {% if form.criticality_rating.errors %} +
    + {% for error in form.criticality_rating.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +
+ + {{form.performance_rating.label}} {{form.performance_rating(size=50)}} + {% if form.performance_rating.errors %} +
    + {% for error in form.performance_rating.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +
+ + {{form.rationale.label}} {{form.rationale(size=50)}} + {% if form.rationale.errors %} +
    + {% for error in form.rationale.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +
+ + {{form.needed_improvements.label}} {{form.needed_improvements(size=50)}} + {% if form.needed_improvements.errors %} +
    + {% for error in form.needed_improvements.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +{%- endmacro -%} diff --git a/usaon_vta_survey/templates/response/relationships/data_product_application.html b/usaon_vta_survey/templates/response/relationships/data_product_application.html index 03e35d4c..28ba0b12 100644 --- a/usaon_vta_survey/templates/response/relationships/data_product_application.html +++ b/usaon_vta_survey/templates/response/relationships/data_product_application.html @@ -4,6 +4,9 @@ data_product_fields, data_product_application_fields %} +{% from 'macros/forms/relationships/app_sba.j2' import + data_product_application_fields +%} {% block content %} diff --git a/usaon_vta_survey/templates/response/relationships/observing_system_data_product.html b/usaon_vta_survey/templates/response/relationships/observing_system_data_product.html index 31e861a8..485a8027 100644 --- a/usaon_vta_survey/templates/response/relationships/observing_system_data_product.html +++ b/usaon_vta_survey/templates/response/relationships/observing_system_data_product.html @@ -4,6 +4,9 @@ data_product_fields, observing_system_data_product_fields %} +{% from 'macros/forms/relationships/app_sba.j2' import + observing_system_data_product_fields +%} {% block content %}