-
+ {% if request_id %} + + {% else %} + + {% end %} + {% module xsrf_form_html() %} {% block form %} form goes here From f6a2ddbd77c16a88e97c03ffbbb97e819ed5373e Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 19 Jun 2018 12:45:49 -0400 Subject: [PATCH 06/14] Fetch requests from requests-queue --- atst/app.py | 6 +++++- atst/handler.py | 2 +- atst/handlers/request.py | 21 +++++++++++++++++++-- atst/handlers/request_new.py | 2 +- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/atst/app.py b/atst/app.py index aa5d6f9c..22ec12bb 100644 --- a/atst/app.py +++ b/atst/app.py @@ -34,7 +34,11 @@ def make_app(config, deps, **kwargs): {"page": "workspaces", "authz_client": deps["authz_client"]}, name="workspaces", ), - url(r"/requests", Request, {"page": "requests"}, name="requests"), + url( + r"/requests", + Request, + {"page": "requests", 'requests_client': deps['requests_client']}, + name="requests"), url( r"/requests/new", RequestNew, diff --git a/atst/handler.py b/atst/handler.py index afe80fa8..011ae3e6 100644 --- a/atst/handler.py +++ b/atst/handler.py @@ -26,7 +26,7 @@ class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): if self.get_secure_cookie('atst'): - return True + return '9cb348f0-8102-4962-88c4-dac8180c904c' else: return False diff --git a/atst/handlers/request.py b/atst/handlers/request.py index 9ce3da34..50d89e57 100644 --- a/atst/handlers/request.py +++ b/atst/handlers/request.py @@ -28,10 +28,27 @@ mock_requests = [ }, ] +def map_request(request): + return { + 'order_id': request['id'], + 'is_new': False, + 'status': 'Pending', + 'app_count': 1, + 'is_new': False, + 'date': '', + 'full_name': 'Richard Howard' + } + class Request(BaseHandler): - def initialize(self, page): + def initialize(self, page, requests_client): self.page = page + self.requests_client = requests_client @tornado.web.authenticated + @tornado.gen.coroutine def get(self): - self.render('requests.html.to', page = self.page, requests = mock_requests ) + response = yield self.requests_client.get( + '/requests?creator_id={}'.format(self.get_current_user())) + requests = response.json['requests'] + mapped_requests = [map_request(request) for request in requests] + self.render('requests.html.to', page=self.page, requests=mapped_requests) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 97457ac5..2da23641 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -94,7 +94,7 @@ class RequestNew(BaseHandler): @tornado.gen.coroutine def create_or_update_request(self, form_data, request_id=None): request_data = { - 'creator_id': '9cb348f0-8102-4962-88c4-dac8180c904c', + 'creator_id': self.get_current_user(), 'request': form_data } if request_id: From 5e5abbe2548a34585687adabb5ceadce87ee03c4 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 19 Jun 2018 13:23:59 -0400 Subject: [PATCH 07/14] Fix Content-Type header in mock api client --- tests/mocks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mocks.py b/tests/mocks.py index 5561c5aa..7e82d182 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -32,5 +32,5 @@ class MockApiClient(ApiClient): response = HTTPResponse( request=HTTPRequest(path, verb), code=200, - headers={'Content-Type': 'application-json'}) + headers={'Content-Type': 'application/json'}) return self.adapt_response(response) From 26176bc0a2c620eb78bbc6805f4b9b4d46c77736 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 19 Jun 2018 14:03:16 -0400 Subject: [PATCH 08/14] Fix show_form call --- atst/handlers/request_new.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 2da23641..92f875be 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -70,9 +70,9 @@ class RequestNew(BaseHandler): request = yield self.get_request(request_id) form_data = request['body'] if request else {} form = self.screens[ int(screen) - 1 ]['form'](data=form_data) - self.show_form(screen=screen, request_id=request_id, form=form) + self.show_form(screen=screen, form=form, request_id=request_id) - def show_form(self, screen=1, request_id=None, form=None): + def show_form(self, screen=1, form=None, request_id=None): if not form: form = self.screens[ int(screen) - 1 ]['form'](self.request.arguments) self.render('requests/screen-%d.html.to' % int(screen), From 92086a898fd5c25a50fa6e2d3e90163dd29442d7 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 19 Jun 2018 14:03:42 -0400 Subject: [PATCH 09/14] Add MockRequestsClient --- tests/conftest.py | 4 ++-- tests/mocks.py | 32 +++++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 5f28746d..5ad43b74 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,14 +1,14 @@ import pytest from atst.app import make_app, make_deps, make_config -from tests.mocks import MockApiClient +from tests.mocks import MockApiClient, MockRequestsClient @pytest.fixture def app(): TEST_DEPS = { 'authz_client': MockApiClient('authz'), - 'requests_client': MockApiClient('requests'), + 'requests_client': MockRequestsClient('requests'), 'authnid_client': MockApiClient('authnid'), } diff --git a/tests/mocks.py b/tests/mocks.py index 7e82d182..e378a7ed 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -28,9 +28,35 @@ class MockApiClient(ApiClient): def delete(self, path, **kwargs): return self._get_response('DELETE', path) - def _get_response(self, verb, path): + def _get_response(self, verb, path, code=200, json=None): response = HTTPResponse( request=HTTPRequest(path, verb), - code=200, + code=code, headers={'Content-Type': 'application/json'}) - return self.adapt_response(response) + + setattr(response, 'ok', 200 <= code < 300) + if json: + setattr(response, 'json', json) + + return response + + +class MockRequestsClient(MockApiClient): + @tornado.gen.coroutine + def get(self, path, **kwargs): + json = { + 'id': '66b8ef71-86d3-48ef-abc2-51bfa1732b6b', + 'creator': '49903ae7-da4a-49bf-a6dc-9dff5d004238', + 'body': {} + } + return self._get_response('GET', path, 200, json=json) + + @tornado.gen.coroutine + def post(self, path, **kwargs): + json = { + 'id': '66b8ef71-86d3-48ef-abc2-51bfa1732b6b', + 'creator': '49903ae7-da4a-49bf-a6dc-9dff5d004238', + 'body': {} + } + return self._get_response('POST', path, 202, json=json) + From 5d171cd2c6c6c0991688f9485f66e7845dde8f72 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 19 Jun 2018 14:04:15 -0400 Subject: [PATCH 10/14] Fix new request test --- tests/handlers/test_request_new.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index 53ad9a25..175206df 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -32,4 +32,4 @@ def test_submit_valid_request_form(monkeypatch, http_client, base_url): headers={"Content-Type": "application/x-www-form-urlencoded"}, body="meaning=42", ) - assert response.effective_url == base_url + '/requests/new/2' + assert '/requests/new/2' in response.effective_url From ef4117ae11c247062c2ca9aca7db3c1673969287 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 19 Jun 2018 14:42:06 -0400 Subject: [PATCH 11/14] Use new requests API /users/requests endpoints --- atst/api_client.py | 3 ++- atst/handlers/request.py | 2 +- atst/handlers/request_new.py | 15 ++++++++------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/atst/api_client.py b/atst/api_client.py index 54b0df53..a481b363 100644 --- a/atst/api_client.py +++ b/atst/api_client.py @@ -40,7 +40,8 @@ class ApiClient(object): headers['Content-Type'] = 'application/json' kwargs['headers'] = headers - response = yield self.client.fetch(url, method=method, **kwargs) + response = yield self.client.fetch( + url, method=method, **kwargs) return self.adapt_response(response) def adapt_response(self, response): diff --git a/atst/handlers/request.py b/atst/handlers/request.py index 50d89e57..3636ae64 100644 --- a/atst/handlers/request.py +++ b/atst/handlers/request.py @@ -48,7 +48,7 @@ class Request(BaseHandler): @tornado.gen.coroutine def get(self): response = yield self.requests_client.get( - '/requests?creator_id={}'.format(self.get_current_user())) + '/users/{}/requests'.format(self.get_current_user())) requests = response.json['requests'] mapped_requests = [map_request(request) for request in requests] self.render('requests.html.to', page=self.page, requests=mapped_requests) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 92f875be..93ee57c8 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -68,8 +68,10 @@ class RequestNew(BaseHandler): form = None if request_id: request = yield self.get_request(request_id) - form_data = request['body'] if request else {} - form = self.screens[ int(screen) - 1 ]['form'](data=form_data) + if request.ok: + form_data = request.json['body'] if request else {} + form = self.screens[ int(screen) - 1 ]['form'](data=form_data) + self.show_form(screen=screen, form=form, request_id=request_id) def show_form(self, screen=1, form=None, request_id=None): @@ -85,11 +87,10 @@ class RequestNew(BaseHandler): @tornado.gen.coroutine def get_request(self, request_id): - try: - request = yield self.requests_client.get('/requests/{}'.format(request_id)) - except HTTPError: - request = None - return request.json + request = yield self.requests_client.get( + '/users/{}/requests/{}'.format(self.get_current_user(), request_id), + raise_error=False) + return request @tornado.gen.coroutine def create_or_update_request(self, form_data, request_id=None): From 1d2f481165cc96bf9044e68fe291026854a3af25 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 19 Jun 2018 15:36:32 -0400 Subject: [PATCH 12/14] Put DateForm in a FormField so it gets serialized --- atst/forms/request.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atst/forms/request.py b/atst/forms/request.py index 31e189ad..18ce5195 100644 --- a/atst/forms/request.py +++ b/atst/forms/request.py @@ -1,5 +1,5 @@ from wtforms.fields.html5 import IntegerField -from wtforms.fields import RadioField, StringField, SelectField, TextAreaField +from wtforms.fields import RadioField, StringField, SelectField, TextAreaField, FormField from wtforms.validators import Required, ValidationError from wtforms_tornado import Form from .date import DateForm @@ -14,7 +14,7 @@ class RequestForm(Form): ('B','Option B'), ('C','Option C') ]) # no way to apply a label to a whole nested form like this - date_start = DateForm() + date_start = FormField(DateForm) period_of_performance = SelectField('Desired period of performance', validators=[Required()], choices=[('','- Select -'), ('value1','30 days'), From 819ce48e41114a8556605e0aa8925a9f9eb76ae5 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 19 Jun 2018 15:44:51 -0400 Subject: [PATCH 13/14] Implement the rest of the request form --- atst/forms/request.py | 6 ++++++ templates/requests/screen-1.html.to | 28 ++++++++++++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/atst/forms/request.py b/atst/forms/request.py index 18ce5195..eae0e0a9 100644 --- a/atst/forms/request.py +++ b/atst/forms/request.py @@ -31,6 +31,12 @@ class RequestForm(Form): ('both', 'Both') ]) number_of_cores = IntegerField('Number of cores', validators=[Required()]) total_ram = IntegerField('Total RAM', validators=[Required()]) + object_storage = IntegerField('Total object storage', validators=[Required()]) + server_storage = IntegerField('Total server storage', validators=[Required()]) + total_active_users = IntegerField('Total active users', validators=[Required()]) + total_peak_users = IntegerField('Total peak users', validators=[Required()]) + total_requests = IntegerField('Total requests', validators=[Required()]) + total_environments = IntegerField('Total environments', validators=[Required()]) # this is just an example validation; obviously this is wrong. def validate_total_ram(self,field): diff --git a/templates/requests/screen-1.html.to b/templates/requests/screen-1.html.to index caa6e5b8..5c9149fc 100644 --- a/templates/requests/screen-1.html.to +++ b/templates/requests/screen-1.html.to @@ -92,29 +92,25 @@

Storage

The particulars of your body copy will be determined by the topic of your page. Regardless of topic, it’s a good practice to follow the inverted pyramid structure when writing copy: Begin with the information that’s most important to your users and then present information of less importance.

- - - - - - + {{ f.object_storage.label }} + {{ f.object_storage(placeholder="Total object storage") }} + {{ f.server_storage.label }} + {{ f.server_storage(placeholder="Total server storage") }}

Estimated Application Storage

The particulars of your body copy will be determined by the topic of your page. Regardless of topic, it’s a good practice to follow the inverted pyramid structure when writing copy: Begin with the information that’s most important to your users and then present information of less importance.

- - + {{ f.total_active_users.label }} + {{ f.total_active_users(placeholder="Total active users") }} - - - - - - - - + {{ f.total_peak_users.label }} + {{ f.total_peak_users(placeholder="Total peak users") }} + {{ f.total_requests.label }} + {{ f.total_requests(placeholder="Total requests") }} + {{ f.total_environments.label }} + {{ f.total_environments(placeholder="Total number of environments") }} {% end %} From 2c14498953e41fc36d10ff42ec184ad172c16350 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 19 Jun 2018 15:47:32 -0400 Subject: [PATCH 14/14] Add links for updating requests --- templates/requests.html.to | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/requests.html.to b/templates/requests.html.to index 0c5fe1cf..431d9175 100644 --- a/templates/requests.html.to +++ b/templates/requests.html.to @@ -20,7 +20,7 @@ {% for r in requests %} - #{{ r['order_id'] }} + {{ r['order_id'] }} {% if r['is_new'] %}New{% end %} {{ r['date'] }} {{ r['full_name'] }}