From 7dadff74817043f76472060686583a1c854b1038 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Sun, 8 Jul 2018 14:30:49 -0400 Subject: [PATCH 1/8] Refactor JEDI request form logic into new class --- atst/handlers/request_new.py | 211 +++++++++++++++++++--------- templates/requests/screen-4.html.to | 6 - templates/requests/sidebar.html.to | 38 ++--- 3 files changed, 164 insertions(+), 91 deletions(-) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index fbf51f98..d38e6b8d 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,57 +18,60 @@ 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, ) @@ -109,16 +83,119 @@ 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 + + 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 + elif self.form_section == "review_submit": + return self.request["body"] + elif self.request: + return self.request["body"].get(self.form_section, {}) + else: + return {} + + @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": self.request and self.request["status"] == "pending_submission", + }, + { + "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/templates/requests/screen-4.html.to b/templates/requests/screen-4.html.to index 97b89859..469dff15 100644 --- a/templates/requests/screen-4.html.to +++ b/templates/requests/screen-4.html.to @@ -29,12 +29,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

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 + From 613db619486c56764f70d128ef39b71057f35750 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 9 Jul 2018 14:59:08 -0400 Subject: [PATCH 2/8] Add status attribute to mock request --- tests/mocks.py | 1 + 1 file changed, 1 insertion(+) 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) From 9f3012cdc3ff7df180b1ea57a1c626e66b62689a Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 9 Jul 2018 15:03:04 -0400 Subject: [PATCH 3/8] Save form instance in JEDIRequestFlow --- atst/handlers/request_new.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index d38e6b8d..a53ebf8b 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -35,7 +35,7 @@ class RequestNew(BaseHandler): else: self.render( "requests/screen-%d.html.to" % int(screen), - f=jedi_flow.form(), + f=jedi_flow.form, data=post_data, page=self.page, screens=jedi_flow.screens, @@ -66,7 +66,7 @@ class RequestNew(BaseHandler): self.render( "requests/screen-%d.html.to" % int(screen), - f=jedi_flow.form(), + f=jedi_flow.form, data=jedi_flow.current_step_data, page=self.page, screens=jedi_flow.screens, @@ -102,8 +102,9 @@ class JEDIRequestFlow(object): self.is_post = self.post_data is not None self.request_id = request_id + self.form = self._form() - def form(self): + def _form(self): if self.is_post: return self.form_class()(self.post_data) elif self.request: @@ -112,7 +113,7 @@ class JEDIRequestFlow(object): return self.form_class()() def validate(self): - return self.form().validate() + return self.form.validate() @property def current_screen(self): @@ -187,7 +188,7 @@ class JEDIRequestFlow(object): def create_or_update_request(self, user): request_data = { "creator_id": user["id"], - "request": {self.form_section: self.form().data}, + "request": {self.form_section: self.form.data}, } if self.request_id: response = yield self.requests_client.patch( From 405c34546b6af0fc7632f6cc92766bfbdd2d542f Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 9 Jul 2018 15:08:34 -0400 Subject: [PATCH 4/8] Remove unused import --- atst/forms/request.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 86d9db74c31c1827c59bd9d3131d0d2694924f65 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 10 Jul 2018 10:30:18 -0400 Subject: [PATCH 5/8] Allow user to submit request --- atst/app.py | 7 +++++++ atst/handlers/request_submit.py | 17 +++++++++++++++++ templates/requests/screen-4.html.to | 5 ++++- templates/requests_new.html.to | 22 +++++++--------------- 4 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 atst/handlers/request_submit.py 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/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 469dff15..a23fb68b 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,7 +12,6 @@ {% 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

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 %} From ab6af09d0546c1ab8f34540cfaace40321d8a662 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 10 Jul 2018 11:47:57 -0400 Subject: [PATCH 6/8] Fix edit links in "review and submit" --- templates/requests/screen-4.html.to | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/requests/screen-4.html.to b/templates/requests/screen-4.html.to index a23fb68b..1869aefd 100644 --- a/templates/requests/screen-4.html.to +++ b/templates/requests/screen-4.html.to @@ -13,7 +13,7 @@

Review & Submit

-

Details of Use Edit

+

Details of Use Edit

Overall Request Details

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


-

Information About You Edit

+

Information About You Edit

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


-

Primary Government/Military Point of Contact (POC) Edit

+

Primary Government/Military Point of Contact (POC) Edit

From 269f23d56c68bb773f79817d3a58606c8aadecb3 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 10 Jul 2018 14:05:27 -0400 Subject: [PATCH 7/8] Continue showing "review and submit" after request is approved --- atst/handlers/request_new.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index a53ebf8b..2aa6225d 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -174,7 +174,7 @@ class JEDIRequestFlow(object): "title": "Review & Submit", "section": "review_submit", "form": ReviewForm, - "show": self.request and self.request["status"] == "pending_submission", + "show": self.request and self.request["status"] != "incomplete", }, { "title": "Financial Verification", From 358aa6366c3358e666cd335b36f344ca28b1b370 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 10 Jul 2018 17:01:39 -0400 Subject: [PATCH 8/8] Always show submit screen, but disable button if form is incomplete --- atst/handlers/request_new.py | 17 ++++++++++++----- templates/requests/screen-4.html.to | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 2aa6225d..63e615af 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -73,6 +73,7 @@ class RequestNew(BaseHandler): current=screen, next_screen=screen + 1, request_id=request_id, + can_submit=jedi_flow.can_submit ) @tornado.gen.coroutine @@ -130,13 +131,19 @@ class JEDIRequestFlow(object): def current_step_data(self): if self.is_post: return self.post_data - elif self.form_section == "review_submit": - return self.request["body"] - elif self.request: - return self.request["body"].get(self.form_section, {}) + + 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 @@ -174,7 +181,7 @@ class JEDIRequestFlow(object): "title": "Review & Submit", "section": "review_submit", "form": ReviewForm, - "show": self.request and self.request["status"] != "incomplete", + "show":True, }, { "title": "Financial Verification", diff --git a/templates/requests/screen-4.html.to b/templates/requests/screen-4.html.to index 1869aefd..2d938a5d 100644 --- a/templates/requests/screen-4.html.to +++ b/templates/requests/screen-4.html.to @@ -116,5 +116,5 @@ {% end %} {% block next %} - + {% end %}