Merge pull request #63 from dod-ccpo/submit-request
Allow user to submit request
This commit is contained in:
commit
b685b478df
@ -10,6 +10,7 @@ from atst.handlers.login import Login
|
|||||||
from atst.handlers.workspace import Workspace
|
from atst.handlers.workspace import Workspace
|
||||||
from atst.handlers.request import Request
|
from atst.handlers.request import Request
|
||||||
from atst.handlers.request_new import RequestNew
|
from atst.handlers.request_new import RequestNew
|
||||||
|
from atst.handlers.request_submit import RequestsSubmit
|
||||||
from atst.handlers.dev import Dev
|
from atst.handlers.dev import Dev
|
||||||
from atst.home import home
|
from atst.home import home
|
||||||
from atst.api_client import ApiClient
|
from atst.api_client import ApiClient
|
||||||
@ -71,6 +72,12 @@ def make_app(config, deps, **kwargs):
|
|||||||
{"page": "requests_new", "requests_client": deps["requests_client"]},
|
{"page": "requests_new", "requests_client": deps["requests_client"]},
|
||||||
name="request_form_update",
|
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"/users", MainHandler, {"page": "users"}, name="users"),
|
||||||
url(r"/reports", MainHandler, {"page": "reports"}, name="reports"),
|
url(r"/reports", MainHandler, {"page": "reports"}, name="reports"),
|
||||||
url(r"/calculator", MainHandler, {"page": "calculator"}, name="calculator"),
|
url(r"/calculator", MainHandler, {"page": "calculator"}, name="calculator"),
|
||||||
|
@ -2,7 +2,7 @@ from wtforms.fields.html5 import IntegerField
|
|||||||
from wtforms.fields import RadioField, StringField, TextAreaField
|
from wtforms.fields import RadioField, StringField, TextAreaField
|
||||||
from wtforms.validators import NumberRange, InputRequired
|
from wtforms.validators import NumberRange, InputRequired
|
||||||
from wtforms_tornado import Form
|
from wtforms_tornado import Form
|
||||||
from .fields import DateField, NewlineListField
|
from .fields import DateField
|
||||||
from .validators import DateRange
|
from .validators import DateRange
|
||||||
import pendulum
|
import pendulum
|
||||||
|
|
||||||
|
@ -1,43 +1,14 @@
|
|||||||
import tornado
|
import tornado
|
||||||
|
|
||||||
from atst.handler import BaseHandler
|
from atst.handler import BaseHandler
|
||||||
from atst.forms.request import RequestForm
|
from atst.forms.request import RequestForm
|
||||||
from atst.forms.org import OrgForm
|
from atst.forms.org import OrgForm
|
||||||
from atst.forms.poc import POCForm
|
from atst.forms.poc import POCForm
|
||||||
from atst.forms.review import ReviewForm
|
from atst.forms.review import ReviewForm
|
||||||
from atst.forms.financial import FinancialForm
|
from atst.forms.financial import FinancialForm
|
||||||
import tornado.httputil
|
|
||||||
|
|
||||||
|
|
||||||
class RequestNew(BaseHandler):
|
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):
|
def initialize(self, page, requests_client):
|
||||||
self.page = page
|
self.page = page
|
||||||
self.requests_client = requests_client
|
self.requests_client = requests_client
|
||||||
@ -47,58 +18,62 @@ class RequestNew(BaseHandler):
|
|||||||
def post(self, screen=1, request_id=None):
|
def post(self, screen=1, request_id=None):
|
||||||
self.check_xsrf_cookie()
|
self.check_xsrf_cookie()
|
||||||
screen = int(screen)
|
screen = int(screen)
|
||||||
form_metadata = self.screens[screen - 1]
|
post_data = self.request.arguments
|
||||||
form_section = form_metadata["section"]
|
jedi_flow = JEDIRequestFlow(
|
||||||
form = form_metadata["form"](self.request.arguments)
|
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:
|
if response.ok:
|
||||||
where = self.application.default_router.reverse_url(
|
where = self.application.default_router.reverse_url(
|
||||||
"request_form_update",
|
"request_form_update", str(screen + 1), jedi_flow.request_id
|
||||||
str(screen + 1),
|
|
||||||
request_id or response.json["id"],
|
|
||||||
)
|
)
|
||||||
self.redirect(where)
|
self.redirect(where)
|
||||||
else:
|
else:
|
||||||
self.set_status(response.code)
|
self.set_status(response.code)
|
||||||
else:
|
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.web.authenticated
|
||||||
@tornado.gen.coroutine
|
@tornado.gen.coroutine
|
||||||
def get(self, screen=1, request_id=None):
|
def get(self, screen=1, request_id=None):
|
||||||
form = None
|
screen = int(screen)
|
||||||
form_data = None
|
request = None
|
||||||
is_review_section = screen == 4
|
|
||||||
|
|
||||||
if request_id:
|
if request_id:
|
||||||
request = yield self.get_request(request_id)
|
response = yield self.requests_client.get(
|
||||||
if request.ok:
|
"/users/{}/requests/{}".format(
|
||||||
if is_review_section:
|
self.get_current_user()["id"], request_id
|
||||||
form_data = request.json["body"]
|
),
|
||||||
else:
|
raise_error=False,
|
||||||
form_metadata = self.screens[int(screen) - 1]
|
)
|
||||||
section = form_metadata["section"]
|
if response.ok:
|
||||||
form_data = request.json["body"].get(section, request.json["body"])
|
request = response.json
|
||||||
form = form_metadata["form"](data=form_data)
|
|
||||||
|
|
||||||
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(
|
self.render(
|
||||||
"requests/screen-%d.html.to" % int(screen),
|
"requests/screen-%d.html.to" % int(screen),
|
||||||
f=form,
|
f=jedi_flow.form,
|
||||||
data=data,
|
data=jedi_flow.current_step_data,
|
||||||
page=self.page,
|
page=self.page,
|
||||||
screens=self.screens,
|
screens=jedi_flow.screens,
|
||||||
current=int(screen),
|
current=screen,
|
||||||
next_screen=int(screen) + 1,
|
next_screen=screen + 1,
|
||||||
request_id=request_id,
|
request_id=request_id,
|
||||||
|
can_submit=jedi_flow.can_submit
|
||||||
)
|
)
|
||||||
|
|
||||||
@tornado.gen.coroutine
|
@tornado.gen.coroutine
|
||||||
@ -109,16 +84,126 @@ class RequestNew(BaseHandler):
|
|||||||
)
|
)
|
||||||
return request
|
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
|
@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 = {
|
request_data = {
|
||||||
"creator_id": self.get_current_user()["id"],
|
"creator_id": user["id"],
|
||||||
"request": {form_section: form_data},
|
"request": {self.form_section: self.form.data},
|
||||||
}
|
}
|
||||||
if request_id:
|
if self.request_id:
|
||||||
response = yield self.requests_client.patch(
|
response = yield self.requests_client.patch(
|
||||||
"/requests/{}".format(request_id), json=request_data
|
"/requests/{}".format(self.request_id), json=request_data
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
response = yield self.requests_client.post("/requests", json=request_data)
|
response = yield self.requests_client.post("/requests", json=request_data)
|
||||||
|
self.request = response.json
|
||||||
|
self.request_id = self.request["id"]
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
17
atst/handlers/request_submit.py
Normal file
17
atst/handlers/request_submit.py
Normal file
@ -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")
|
@ -1,5 +1,9 @@
|
|||||||
{% extends '../requests_new.html.to' %}
|
{% extends '../requests_new.html.to' %}
|
||||||
|
|
||||||
|
{% block form_action %}
|
||||||
|
<form method='POST' action="{{ reverse_url('requests_submit', request_id) }}" autocomplete="off">
|
||||||
|
{% end %}
|
||||||
|
|
||||||
{% block form %}
|
{% block form %}
|
||||||
|
|
||||||
{% autoescape None %}
|
{% autoescape None %}
|
||||||
@ -8,9 +12,8 @@
|
|||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
<h2 id="review-submit">Review & Submit</h2>
|
<h2 id="review-submit">Review & Submit</h2>
|
||||||
<p>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?</p>
|
|
||||||
|
|
||||||
<h3>Details of Use <a href="">Edit</a></h3>
|
<h3>Details of Use <a href="{{ reverse_url('request_form_update', 1, request_id) }}">Edit</a></h3>
|
||||||
|
|
||||||
<h4>Overall Request Details</h4>
|
<h4>Overall Request Details</h4>
|
||||||
|
|
||||||
@ -29,12 +32,6 @@
|
|||||||
<label>What organizations are supported by these applications?</label>
|
<label>What organizations are supported by these applications?</label>
|
||||||
<b>{{ data.get('details_of_use', {}).get('supported_organizations') }}</b>
|
<b>{{ data.get('details_of_use', {}).get('supported_organizations') }}</b>
|
||||||
|
|
||||||
<label>Please enter the Unique Item Identifier (UII)s related to your application(s) if you already have them.</label>
|
|
||||||
<b>{{ data.get('details_of_use', {}).get('uii_ids') }}</b>
|
|
||||||
|
|
||||||
<label>Please provide the Program Element (PE) Numbers related to your request</label>
|
|
||||||
<b>{{ data.get('details_of_use', {}).get('pe_id') }}</b>
|
|
||||||
|
|
||||||
<h4>Cloud Resources</h4>
|
<h4>Cloud Resources</h4>
|
||||||
|
|
||||||
<label>Total Number of vCPU cores</label>
|
<label>Total Number of vCPU cores</label>
|
||||||
@ -68,7 +65,7 @@
|
|||||||
|
|
||||||
<br><br><hr>
|
<br><br><hr>
|
||||||
|
|
||||||
<h3>Information About You <a href="">Edit</a></h3>
|
<h3>Information About You <a href="{{ reverse_url('request_form_update', 2, request_id) }}">Edit</a></h3>
|
||||||
|
|
||||||
<label>First Name</label>
|
<label>First Name</label>
|
||||||
<b>{{ data.get('information_about_you', {}).get('fname_request') }}</b>
|
<b>{{ data.get('information_about_you', {}).get('fname_request') }}</b>
|
||||||
@ -97,7 +94,7 @@
|
|||||||
|
|
||||||
<br><br><hr>
|
<br><br><hr>
|
||||||
|
|
||||||
<h3>Primary Government/Military Point of Contact (POC) <a href="">Edit</a></h3>
|
<h3>Primary Government/Military Point of Contact (POC) <a href="{{ reverse_url('request_form_update', 3, request_id) }}">Edit</a></h3>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -119,5 +116,5 @@
|
|||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
{% block next %}
|
{% block next %}
|
||||||
<input type='submit' class='usa-button usa-button-primary' value='Submit' />
|
<input type='submit' class='usa-button usa-button-primary' value='Submit' {{ "disabled" if not can_submit else "" }} />
|
||||||
{% end %}
|
{% end %}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{% for i,s in enumerate(screens) %}
|
{% for i,s in enumerate(screens) %}
|
||||||
|
{% if s["show"] %}
|
||||||
<li>
|
<li>
|
||||||
{% if i+1==current %}
|
{% if i+1==current %}
|
||||||
<a class="sidenav__link sidenav__link--active" href="{{ reverse_url('request_form_update', i+1, request_id) if request_id else reverse_url('request_form_new',i+1) }}">
|
<a class="sidenav__link sidenav__link--active" href="{{ reverse_url('request_form_update', i+1, request_id) if request_id else reverse_url('request_form_new',i+1) }}">
|
||||||
@ -27,5 +28,6 @@
|
|||||||
{% end %}
|
{% end %}
|
||||||
</li>
|
</li>
|
||||||
{% end %}
|
{% end %}
|
||||||
|
{% end %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
@ -17,13 +17,13 @@
|
|||||||
<h1>New Request</h1>
|
<h1>New Request</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% block form_action %}
|
||||||
|
|
||||||
{% if request_id %}
|
{% if request_id %}
|
||||||
<form method='POST' action="{{ reverse_url('request_form_update', current, request_id) }}" autocomplete="off">
|
<form method='POST' action="{{ reverse_url('request_form_update', current, request_id) }}" autocomplete="off">
|
||||||
{% else %}
|
{% else %}
|
||||||
<form method='POST' action="{{ reverse_url('request_form_new', current) }}" autocomplete="off">
|
<form method='POST' action="{{ reverse_url('request_form_new', current) }}" autocomplete="off">
|
||||||
{% end %}
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
{% module xsrf_form_html() %}
|
{% module xsrf_form_html() %}
|
||||||
{% block form %}
|
{% block form %}
|
||||||
@ -34,18 +34,10 @@
|
|||||||
{% end %}
|
{% end %}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ class MockRequestsClient(MockApiClient):
|
|||||||
"id": "66b8ef71-86d3-48ef-abc2-51bfa1732b6b",
|
"id": "66b8ef71-86d3-48ef-abc2-51bfa1732b6b",
|
||||||
"creator": "49903ae7-da4a-49bf-a6dc-9dff5d004238",
|
"creator": "49903ae7-da4a-49bf-a6dc-9dff5d004238",
|
||||||
"body": {},
|
"body": {},
|
||||||
|
"status": "incomplete"
|
||||||
}
|
}
|
||||||
return self._get_response("GET", path, 200, json=json)
|
return self._get_response("GET", path, 200, json=json)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user