diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 1d33daa0..30549e63 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -101,7 +101,6 @@ class RequestNew(BaseHandler): class JEDIRequestFlow(object): def __init__( self, - requests_repo, pe_numbers_repo, current_step, request=None, @@ -110,6 +109,8 @@ class JEDIRequestFlow(object): current_user=None, existing_request=None, ): + self.pe_numbers_repo = pe_numbers_repo + self.requests_repo = requests_repo self.pe_numbers_repo = pe_numbers_repo diff --git a/atst/routes/requests.py b/atst/routes/requests.py index 5903524c..565c268e 100644 --- a/atst/routes/requests.py +++ b/atst/routes/requests.py @@ -1,8 +1,14 @@ -from flask import Blueprint, g, render_template +from flask import Blueprint, g, render_template, url_for, redirect, request import pendulum +from collections import defaultdict from atst.domain.requests import Requests from atst.forms.financial import FinancialForm +from atst.forms.request import RequestForm +from atst.forms.org import OrgForm +from atst.forms.poc import POCForm +from atst.forms.review import ReviewForm + requests_bp = Blueprint("requests", __name__) @@ -34,13 +40,72 @@ def requests_index(): @requests_bp.route("/requests/new/", methods=["GET"]) -def requests_new(): +def requests_form_new(): pass @requests_bp.route("/requests/new//", methods=["GET"]) -def requests_form_update(): - pass +def requests_form_update(screen=1, request_id=None): + request = Requests.get(request_id) if request_id is not None else None + jedi_flow = JEDIRequestFlow(screen, request, request_id=request_id) + + return render_template( + "requests/screen-%d.html" % int(screen), + f=jedi_flow.form, + data=jedi_flow.current_step_data, + screens=jedi_flow.screens, + current=screen, + next_screen=screen + 1, + request_id=request_id, + can_submit=jedi_flow.can_submit + ) + +@requests_bp.route("/requests/new//", methods=["POST"]) +def requests_update(screen=1, request_id=None): + screen = int(screen) + post_data = str(request.data) + current_user = g.current_user + existing_request = Requests.get(request_id) if request_id is not None else None + jedi_flow = JEDIRequestFlow( + screen, + post_data=post_data, + request_id=request_id, + current_user=current_user, + existing_request=existing_request, + ) + + rerender_args = dict( + f=jedi_flow.form, + data=post_data, + screens=jedi_flow.screens, + current=screen, + next_screen=jedi_flow.next_screen, + request_id=jedi_flow.request_id, + ) + + if jedi_flow.validate(): + jedi_flow.create_or_update_request() + valid = jedi_flow.validate_warnings() + if valid: + if jedi_flow.next_screen > len(jedi_flow.screens): + where = "/requests" + else: + where = url_for( + "requests.requests_Form_update", screen=jedi_flow.next_screen, request_id=jedi_flow.request_id + ) + return redirect(where) + else: + return render_template( + "requests/screen-%d.html" % int(screen), + **rerender_args + ) + else: + return render_template( + "requests/screen-%d.html" % int(screen), + **rerender_args + ) + + @requests_bp.route("/requests/verify/", methods=["GET"]) @@ -53,3 +118,129 @@ def financial_verification(request_id=None): @requests_bp.route("/requests/verify/", methods=["POST"]) def update_financial_verification(): pass + + +class JEDIRequestFlow(object): + def __init__( + self, + current_step, + request=None, + post_data=None, + request_id=None, + current_user=None, + existing_request=None, + ): + self.current_step = current_step + self.request = request + + self.post_data = post_data + self.is_post = self.post_data is not None + + self.request_id = request_id + self.form = self._form() + + self.current_user = current_user + self.existing_request = existing_request + + def _form(self): + if self.is_post: + return self.form_class()(self.post_data) + elif self.request: + return self.form_class()(data=self.current_step_data) + else: + return self.form_class()() + + def validate(self): + return self.form.validate() + + def validate_warnings(self): + existing_request_data = ( + self.existing_request + and self.existing_request.body.get(self.form_section) + ) or None + + valid = self.form.perform_extra_validation( + existing_request_data, + ) + return valid + + @property + def current_screen(self): + return self.screens[self.current_step - 1] + + @property + def form_section(self): + return self.current_screen["section"] + + def form_class(self): + return self.current_screen["form"] + + @property + def current_step_data(self): + data = {} + + if self.is_post: + data = self.post_data + + if self.request: + if self.form_section == "review_submit": + data = self.request.body + else: + data = self.request.body.get(self.form_section, {}) + + return defaultdict(lambda: defaultdict(lambda: 'Input required'), data) + + @property + def can_submit(self): + return self.request and self.request.status != "incomplete" + + @property + def next_screen(self): + return self.current_step + 1 + + @property + def screens(self): + return [ + { + "title": "Details of Use", + "section": "details_of_use", + "form": RequestForm, + "subitems": [ + { + "title": "Overall request details", + "id": "overall-request-details", + }, + {"title": "Cloud Resources", "id": "cloud-resources"}, + {"title": "Support Staff", "id": "support-staff"}, + ], + "show": True, + }, + { + "title": "Information About You", + "section": "information_about_you", + "form": OrgForm, + "show": True, + }, + { + "title": "Primary Point of Contact", + "section": "primary_poc", + "form": POCForm, + "show": True, + }, + { + "title": "Review & Submit", + "section": "review_submit", + "form": ReviewForm, + "show":True, + }, + ] + + def create_or_update_request(self): + request_data = { + self.form_section: self.form.data + } + if self.request_id: + Requests.update(request_id, request_data) + else: + request = Requests.create(self.current_user["id"], request_data) + self.request_id = request.id diff --git a/templates/components.html b/templates/components.html index 04f6be36..027ede6f 100644 --- a/templates/components.html +++ b/templates/components.html @@ -90,3 +90,56 @@ {%- endmacro %} + +{% macro TextInput(field, placeholder='') -%} +
+ + + {{ field(placeholder=placeholder) | safe }} + + {% if field.errors %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + {% endif %} +
+{%- endmacro %} + +{% macro OptionsInput(field, inline=False) -%} +
+ +
+ + {{ field.label }} + + {% if field.description %} + {{ field.description | safe }} + {% endif %} + + {% if field.errors %} + {{ Icon('alert') }} + {% endif %} + + + {{ field() }} + + {% if field.errors %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + {% endif %} + +
+
+ +{%- endmacro %} diff --git a/templates/requests/menu.html b/templates/requests/menu.html new file mode 100644 index 00000000..f1642e46 --- /dev/null +++ b/templates/requests/menu.html @@ -0,0 +1,13 @@ +
+ +
diff --git a/templates/requests/menu.html.to b/templates/requests/menu.html.to deleted file mode 100644 index 4bc77431..00000000 --- a/templates/requests/menu.html.to +++ /dev/null @@ -1,13 +0,0 @@ -
- -
\ No newline at end of file diff --git a/templates/requests/screen-0.html b/templates/requests/screen-0.html new file mode 100644 index 00000000..19f57d2e --- /dev/null +++ b/templates/requests/screen-0.html @@ -0,0 +1,12 @@ +{% extends '../requests_new.html.to' %} + +{% block form %} +

New JEDI Request

+ +

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus error omnis a, tenetur similique quo officiis voluptates eum recusandae dolorem minus dignissimos, magni consequatur, maxime debitis reprehenderit sint non iusto?

+ +New Application +Existing Application +Sandbox Environment + +{% endblock %} diff --git a/templates/requests/screen-0.html.to b/templates/requests/screen-0.html.to deleted file mode 100644 index 6fe78374..00000000 --- a/templates/requests/screen-0.html.to +++ /dev/null @@ -1,12 +0,0 @@ -{% extends '../requests_new.html.to' %} - -{% block form %} -

New JEDI Request

- -

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Natus error omnis a, tenetur similique quo officiis voluptates eum recusandae dolorem minus dignissimos, magni consequatur, maxime debitis reprehenderit sint non iusto?

- -New Application -Existing Application -Sandbox Environment - -{% end %} diff --git a/templates/requests/screen-1.html b/templates/requests/screen-1.html new file mode 100644 index 00000000..da6c5ae0 --- /dev/null +++ b/templates/requests/screen-1.html @@ -0,0 +1,46 @@ +{% extends 'requests_new.html' %} + +{% from "components.html" import Alert, TextInput, OptionsInput %} + +{% block subtitle %} +

Details of Use

+{% endblock %} + +{% block form %} + +{% if f.errors %} + {{ Alert('There were some errors', + message="

Please see below.

", + level='error' + ) }} +{% endif %} + + +

We’d like to know a little about how you plan to use JEDI Cloud services to process your request. Please answer the following questions to the best of your ability. Note that the CCPO does not directly help with migrating systems to JEDI Cloud. These questions are for learning about your cloud readiness and financial usage of the JEDI Cloud; your estimates will not be used for any department level reporting.

+

All fields are required, unless specified optional.

+ +

General

+{{ TextInput(f.dod_component) }} +{{ TextInput(f.jedi_usage,placeholder="e.g. We are migrating XYZ application to the cloud so that...") }} + +

Cloud Readiness

+{{ TextInput(f.num_software_systems,placeholder="Number of systems") }} +{{ OptionsInput(f.jedi_migration) }} +{{ OptionsInput(f.rationalization_software_systems) }} +{{ OptionsInput(f.technical_support_team) }} +{{ OptionsInput(f.organization_providing_assistance) }} +{{ OptionsInput(f.engineering_assessment) }} +{{ TextInput(f.data_transfers) }} +{{ TextInput(f.expected_completion_date) }} +{{ OptionsInput(f.cloud_native) }} + +

Financial Usage

+{{ TextInput(f.estimated_monthly_spend) }} +

So this means you are spending approximately $X annually

+{{ TextInput(f.dollar_value) }} +{{ TextInput(f.number_user_sessions) }} +{{ TextInput(f.average_daily_traffic) }} +{{ TextInput(f.start_date) }} + + +{% endblock %} diff --git a/templates/requests/screen-1.html.to b/templates/requests/screen-1.html.to deleted file mode 100644 index a8ed7887..00000000 --- a/templates/requests/screen-1.html.to +++ /dev/null @@ -1,45 +0,0 @@ -{% extends '../requests_new.html.to' %} - -{% block subtitle %} -

Details of Use

-{% end %} - -{% block form %} - -{% autoescape None %} -{% if f.errors %} - {% module Alert('There were some errors', - message="

Please see below.

", - level='error' - ) %} -{% end %} - - -

We’d like to know a little about how you plan to use JEDI Cloud services to process your request. Please answer the following questions to the best of your ability. Note that the CCPO does not directly help with migrating systems to JEDI Cloud. These questions are for learning about your cloud readiness and financial usage of the JEDI Cloud; your estimates will not be used for any department level reporting.

-

All fields are required, unless specified optional.

- -

General

-{% module TextInput(f.dod_component) %} -{% module TextInput(f.jedi_usage,placeholder="e.g. We are migrating XYZ application to the cloud so that...") %} - -

Cloud Readiness

-{% module TextInput(f.num_software_systems,placeholder="Number of systems") %} -{% module OptionsInput(f.jedi_migration) %} -{% module OptionsInput(f.rationalization_software_systems) %} -{% module OptionsInput(f.technical_support_team) %} -{% module OptionsInput(f.organization_providing_assistance) %} -{% module OptionsInput(f.engineering_assessment) %} -{% module TextInput(f.data_transfers) %} -{% module TextInput(f.expected_completion_date) %} -{% module OptionsInput(f.cloud_native) %} - -

Financial Usage

-{% module TextInput(f.estimated_monthly_spend) %} -

So this means you are spending approximately $X annually

-{% module TextInput(f.dollar_value) %} -{% module TextInput(f.number_user_sessions) %} -{% module TextInput(f.average_daily_traffic) %} -{% module TextInput(f.start_date) %} - - -{% end %} diff --git a/templates/requests/screen-2.html b/templates/requests/screen-2.html new file mode 100644 index 00000000..24c8f749 --- /dev/null +++ b/templates/requests/screen-2.html @@ -0,0 +1,32 @@ +{% extends 'requests_new.html' %} + +{% from "components.html" import Alert, TextInput, OptionsInput %} + +{% block subtitle %} +

Information About You

+{% endblock %} + +{% block form %} + +{% if f.errors %} + {{ Alert('There were some errors', + message="

Please see below.

", + level='error' + ) }} +{% endif %} + +

Please tell us more about you.

+ +{{ TextInput(f.fname_request,placeholder='First Name') }} +{{ TextInput(f.lname_request,placeholder='Last Name') }} +{{ TextInput(f.email_request,placeholder='jane@mail.mil') }} +{{ TextInput(f.phone_number,placeholder='(123) 456-7890') }} + +

We want to collect the following information from you for security auditing and determining priviledged user access

+ +{{ TextInput(f.service_branch,placeholder='e.g. US Air Force, US Army, US Navy, Marine Corps, Defense Media Agency') }} +{{ OptionsInput(f.citizenship) }} +{{ OptionsInput(f.designation) }} +{{ TextInput(f.date_latest_training) }} + +{% endblock %} diff --git a/templates/requests/screen-2.html.to b/templates/requests/screen-2.html.to deleted file mode 100644 index fb667dc5..00000000 --- a/templates/requests/screen-2.html.to +++ /dev/null @@ -1,31 +0,0 @@ -{% extends '../requests_new.html.to' %} - -{% block subtitle %} -

Information About You

-{% end %} - -{% block form %} - -{% autoescape None %} -{% if f.errors %} - {% module Alert('There were some errors', - message="

Please see below.

", - level='error' - ) %} -{% end %} - -

Please tell us more about you.

- -{% module TextInput(f.fname_request,placeholder='First Name') %} -{% module TextInput(f.lname_request,placeholder='Last Name') %} -{% module TextInput(f.email_request,placeholder='jane@mail.mil') %} -{% module TextInput(f.phone_number,placeholder='(123) 456-7890') %} - -

We want to collect the following information from you for security auditing and determining priviledged user access

- -{% module TextInput(f.service_branch,placeholder='e.g. US Air Force, US Army, US Navy, Marine Corps, Defense Media Agency') %} -{% module OptionsInput(f.citizenship) %} -{% module OptionsInput(f.designation) %} -{% module TextInput(f.date_latest_training) %} - -{% end %} \ No newline at end of file diff --git a/templates/requests/screen-3.html.to b/templates/requests/screen-3.html similarity index 100% rename from templates/requests/screen-3.html.to rename to templates/requests/screen-3.html diff --git a/templates/requests/screen-4.html.to b/templates/requests/screen-4.html similarity index 100% rename from templates/requests/screen-4.html.to rename to templates/requests/screen-4.html diff --git a/templates/requests/screen-5.html.to b/templates/requests/screen-5.html similarity index 100% rename from templates/requests/screen-5.html.to rename to templates/requests/screen-5.html diff --git a/templates/requests/sidebar.html.to b/templates/requests/sidebar.html similarity index 100% rename from templates/requests/sidebar.html.to rename to templates/requests/sidebar.html diff --git a/templates/requests_new.html b/templates/requests_new.html new file mode 100644 index 00000000..559c2355 --- /dev/null +++ b/templates/requests_new.html @@ -0,0 +1,45 @@ +{% extends "base.html" %} + +{% block content %} + +
+ + {% include 'requests/menu.html' %} + +
+ +
+

New Request

+
{% block subtitle %}{% endblock %}
+
+ +
+ {% block form_action %} + {% if request_id %} +
+ {% else %} + + {% endif %} + {% endblock %} + + {{ f.csrf_token }} + {% block form %} + form goes here + {% endblock %} + +
+ +
+ + {% block next %} + +
+ +
+ + {% endblock %} + + +
+ +{% endblock %} diff --git a/templates/requests_new.html.to b/templates/requests_new.html.to deleted file mode 100644 index c5f96ed5..00000000 --- a/templates/requests_new.html.to +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "base.html.to" %} - -{% block content %} - -
- - {% include 'requests/menu.html.to' %} - -
- -
-

New Request

-
{% block subtitle %}{% end %}
-
- -
- {% block form_action %} - {% if request_id %} -
- {% else %} - - {% end %} - {% end %} - - {{ form.csrf_token }} - {% block form %} - form goes here - {% end %} - -
- -
- - {% block next %} - -
- -
- - {% end %} - - -
- -{% end %} -