diff --git a/atst/app.py b/atst/app.py index 094a61b1..a0b3e491 100644 --- a/atst/app.py +++ b/atst/app.py @@ -10,6 +10,7 @@ from atst.handlers.login import Login from atst.handlers.workspace import Workspace from atst.handlers.request import Request from atst.handlers.request_new import RequestNew +from atst.handlers.request_submit import RequestsSubmit from atst.handlers.dev import Dev from atst.home import home from atst.api_client import ApiClient @@ -71,6 +72,12 @@ def make_app(config, deps, **kwargs): {"page": "requests_new", "requests_client": deps["requests_client"]}, name="request_form_update", ), + url( + r"/requests/submit/(\S+)", + RequestsSubmit, + {"requests_client": deps["requests_client"]}, + name="requests_submit", + ), url(r"/users", MainHandler, {"page": "users"}, name="users"), url(r"/reports", MainHandler, {"page": "reports"}, name="reports"), url(r"/calculator", MainHandler, {"page": "calculator"}, name="calculator"), diff --git a/atst/forms/request.py b/atst/forms/request.py index 36aa2043..d6aa1039 100644 --- a/atst/forms/request.py +++ b/atst/forms/request.py @@ -2,7 +2,7 @@ from wtforms.fields.html5 import IntegerField from wtforms.fields import RadioField, StringField, TextAreaField from wtforms.validators import NumberRange, InputRequired from wtforms_tornado import Form -from .fields import DateField, NewlineListField +from .fields import DateField from .validators import DateRange import pendulum diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index fbf51f98..63e615af 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -1,43 +1,14 @@ import tornado + from atst.handler import BaseHandler from atst.forms.request import RequestForm from atst.forms.org import OrgForm from atst.forms.poc import POCForm from atst.forms.review import ReviewForm from atst.forms.financial import FinancialForm -import tornado.httputil class RequestNew(BaseHandler): - screens = [ - { - "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"}, - ], - }, - { - "title": "Information About You", - "section": "information_about_you", - "form": OrgForm, - }, - { - "title": "Primary Point of Contact", - "section": "primary_poc", - "form": POCForm, - }, - {"title": "Review & Submit", "section": "review_submit", "form": ReviewForm}, - { - "title": "Financial Verification", - "section": "financial_verification", - "form": FinancialForm, - }, - ] - def initialize(self, page, requests_client): self.page = page self.requests_client = requests_client @@ -47,58 +18,62 @@ class RequestNew(BaseHandler): def post(self, screen=1, request_id=None): self.check_xsrf_cookie() screen = int(screen) - form_metadata = self.screens[screen - 1] - form_section = form_metadata["section"] - form = form_metadata["form"](self.request.arguments) + post_data = self.request.arguments + jedi_flow = JEDIRequestFlow( + self.requests_client, screen, post_data=post_data, request_id=request_id + ) - if form.validate(): - response = yield self.create_or_update_request( - form_section, form.data, request_id - ) + if jedi_flow.validate(): + response = yield jedi_flow.create_or_update_request(self.get_current_user()) if response.ok: where = self.application.default_router.reverse_url( - "request_form_update", - str(screen + 1), - request_id or response.json["id"], + "request_form_update", str(screen + 1), jedi_flow.request_id ) self.redirect(where) else: self.set_status(response.code) else: - self.show_form(screen, form) + self.render( + "requests/screen-%d.html.to" % int(screen), + f=jedi_flow.form, + data=post_data, + page=self.page, + screens=jedi_flow.screens, + current=screen, + next_screen=jedi_flow.next_screen, + request_id=jedi_flow.request_id, + ) @tornado.web.authenticated @tornado.gen.coroutine def get(self, screen=1, request_id=None): - form = None - form_data = None - is_review_section = screen == 4 + screen = int(screen) + request = None if request_id: - request = yield self.get_request(request_id) - if request.ok: - if is_review_section: - form_data = request.json["body"] - else: - form_metadata = self.screens[int(screen) - 1] - section = form_metadata["section"] - form_data = request.json["body"].get(section, request.json["body"]) - form = form_metadata["form"](data=form_data) + response = yield self.requests_client.get( + "/users/{}/requests/{}".format( + self.get_current_user()["id"], request_id + ), + raise_error=False, + ) + if response.ok: + request = response.json - self.show_form(screen=screen, form=form, request_id=request_id, data=form_data) + jedi_flow = JEDIRequestFlow( + self.requests_client, screen, request, request_id=request_id + ) - def show_form(self, screen=1, form=None, request_id=None, data=None): - if not form: - form = self.screens[int(screen) - 1]["form"](self.request.arguments) self.render( "requests/screen-%d.html.to" % int(screen), - f=form, - data=data, + f=jedi_flow.form, + data=jedi_flow.current_step_data, page=self.page, - screens=self.screens, - current=int(screen), - next_screen=int(screen) + 1, + screens=jedi_flow.screens, + current=screen, + next_screen=screen + 1, request_id=request_id, + can_submit=jedi_flow.can_submit ) @tornado.gen.coroutine @@ -109,16 +84,126 @@ class RequestNew(BaseHandler): ) return request + +class JEDIRequestFlow(object): + def __init__( + self, + requests_client, + current_step, + request=None, + post_data=None, + request_id=None, + ): + self.requests_client = requests_client + + 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() + + 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() + + @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): + if self.is_post: + return self.post_data + + if self.request: + if self.form_section == "review_submit": + return self.request["body"] + else: + return self.request["body"].get(self.form_section, {}) + else: + return {} + + @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, + }, + { + "title": "Financial Verification", + "section": "financial_verification", + "form": FinancialForm, + "show": self.request and self.request["status"] == "approved", + }, + ] + @tornado.gen.coroutine - def create_or_update_request(self, form_section, form_data, request_id=None): + def create_or_update_request(self, user): request_data = { - "creator_id": self.get_current_user()["id"], - "request": {form_section: form_data}, + "creator_id": user["id"], + "request": {self.form_section: self.form.data}, } - if request_id: + if self.request_id: response = yield self.requests_client.patch( - "/requests/{}".format(request_id), json=request_data + "/requests/{}".format(self.request_id), json=request_data ) else: response = yield self.requests_client.post("/requests", json=request_data) + self.request = response.json + self.request_id = self.request["id"] + return response diff --git a/atst/handlers/request_submit.py b/atst/handlers/request_submit.py new file mode 100644 index 00000000..ed842449 --- /dev/null +++ b/atst/handlers/request_submit.py @@ -0,0 +1,17 @@ +import tornado + +from atst.handler import BaseHandler + + +class RequestsSubmit(BaseHandler): + def initialize(self, requests_client): + self.requests_client = requests_client + + @tornado.web.authenticated + @tornado.gen.coroutine + def post(self, request_id): + yield self.requests_client.post( + "/requests/{}/submit".format(request_id), + allow_nonstandard_methods=True + ) + self.redirect("/requests") diff --git a/templates/requests/screen-4.html.to b/templates/requests/screen-4.html.to index 97b89859..2d938a5d 100644 --- a/templates/requests/screen-4.html.to +++ b/templates/requests/screen-4.html.to @@ -1,5 +1,9 @@ {% extends '../requests_new.html.to' %} +{% block form_action %} +
+{% end %} + {% block form %} {% autoescape None %} @@ -8,9 +12,8 @@ {% end %}

Review & Submit

-

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem ullam veritatis fuga non repellendus repellat dolorum labore nulla iure aspernatur ipsam recusandae saepe harum iste, dolorem adipisci dolores eum, doloribus?

-

Details of Use Edit

+

Details of Use Edit

Overall Request Details

@@ -29,12 +32,6 @@ {{ data.get('details_of_use', {}).get('supported_organizations') }} - -{{ data.get('details_of_use', {}).get('uii_ids') }} - - -{{ data.get('details_of_use', {}).get('pe_id') }} -

Cloud Resources

@@ -68,7 +65,7 @@


-

Information About You Edit

+

Information About You Edit

{{ data.get('information_about_you', {}).get('fname_request') }} @@ -97,7 +94,7 @@


-

Primary Government/Military Point of Contact (POC) Edit

+

Primary Government/Military Point of Contact (POC) Edit

@@ -119,5 +116,5 @@ {% end %} {% block next %} - + {% end %} diff --git a/templates/requests/sidebar.html.to b/templates/requests/sidebar.html.to index c9ed12f3..f8516917 100644 --- a/templates/requests/sidebar.html.to +++ b/templates/requests/sidebar.html.to @@ -7,25 +7,27 @@ - \ No newline at end of file + diff --git a/templates/requests_new.html.to b/templates/requests_new.html.to index 5437a8a6..25431889 100644 --- a/templates/requests_new.html.to +++ b/templates/requests_new.html.to @@ -9,20 +9,20 @@ {% block content %}
- +

New Request

- - - {% if request_id %} - - {% else %} - + {% block form_action %} + {% if request_id %} + + {% else %} + + {% end %} {% end %} {% module xsrf_form_html() %} @@ -34,18 +34,10 @@ {% end %} - - -
-
- - - - {% end %} diff --git a/tests/mocks.py b/tests/mocks.py index be8805c3..2fefbf64 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -49,6 +49,7 @@ class MockRequestsClient(MockApiClient): "id": "66b8ef71-86d3-48ef-abc2-51bfa1732b6b", "creator": "49903ae7-da4a-49bf-a6dc-9dff5d004238", "body": {}, + "status": "incomplete" } return self._get_response("GET", path, 200, json=json)