diff --git a/atst/app.py b/atst/app.py index babaff7a..cd432ea9 100644 --- a/atst/app.py +++ b/atst/app.py @@ -46,7 +46,7 @@ def make_flask_callbacks(app): def set_globals(): g.navigationContext = 'workspace' if re.match('\/workspaces\/[A-Za-z0-9]*', request.url) else 'global' g.dev = os.getenv("TORNADO_ENV", "dev") == "dev" - g.matchesPath = lambda href: re.match('^'+href, request.url) + g.matchesPath = lambda href: re.match('^'+href, request.path) g.modalOpen = request.args.get("modal", False) g.current_user = { "id": "cce17030-4109-4719-b958-ed109dbb87c8", diff --git a/atst/routes/requests/__init__.py b/atst/routes/requests/__init__.py new file mode 100644 index 00000000..aa747e71 --- /dev/null +++ b/atst/routes/requests/__init__.py @@ -0,0 +1,126 @@ +from flask import Blueprint, g, render_template, url_for, redirect, request +import pendulum + +from atst.routes.requests.jedi_request_flow import JEDIRequestFlow +from atst.domain.requests import Requests + + +requests_bp = Blueprint("requests", __name__) + +def map_request(user, request): + time_created = pendulum.instance(request.time_created) + is_new = time_created.add(days=1) > pendulum.now() + + return { + "order_id": request.id, + "is_new": is_new, + "status": request.status, + "app_count": 1, + "date": time_created.format("M/DD/YYYY"), + "full_name": "{} {}".format(user["first_name"], user["last_name"]), + } + + +@requests_bp.route("/requests", methods=["GET"]) +def requests_index(): + requests = [] + if "review_and_approve_jedi_workspace_request" in g.current_user["atat_permissions"]: + requests = Requests.get_many() + else: + requests = Requests.get_many(creator_id=g.current_user["id"]) + + mapped_requests = [map_request(g.current_user, r) for r in requests] + + return render_template("requests.html", requests=mapped_requests) + + +@requests_bp.route("/requests/new/", methods=["GET"]) +def requests_form_new(): + pass + + +@requests_bp.route("/requests/new//", methods=["GET"]) +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 = request.form + 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"]) +def financial_verification(request_id=None): + request = Requests.get(request_id) + form = FinancialForm(data=request.body.get('financial_verification')) + return render_template("requests/financial_verification.html", f=form) + + +@requests_bp.route("/requests/verify/", methods=["POST"]) +def update_financial_verification(): + pass + + +@requests_bp.route("/requests/submit/", methods=["POST"]) +def requests_submit(request_id=None): + request = Requests.get(request_id) + Requests.submit(request) + + if request.status == "approved": + return redirect("/requests?modal=True") + else: + return redirect("/requests") diff --git a/atst/routes/requests/jedi_request_flow.py b/atst/routes/requests/jedi_request_flow.py new file mode 100644 index 00000000..4befe5f5 --- /dev/null +++ b/atst/routes/requests/jedi_request_flow.py @@ -0,0 +1,135 @@ +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 + + + +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(self.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 027ede6f..ea214631 100644 --- a/templates/components.html +++ b/templates/components.html @@ -7,11 +7,11 @@ {% macro SidenavItem(label, href, active=False, icon=None, subnav=None) -%}
  • - {% if icon %} + {% if icon %} {{ Icon(icon, classes="sidenav__link-icon") }} - {% endif %} + {% endif %} - {{label}} + {{label}} {% if subnav and active %} diff --git a/templates/requests/menu.html b/templates/requests/menu.html index f1642e46..24b28d4f 100644 --- a/templates/requests/menu.html +++ b/templates/requests/menu.html @@ -2,7 +2,7 @@