Use black for formatting

This commit is contained in:
richard-dds 2018-06-26 10:31:39 -04:00
parent 3599440ee6
commit f9335c7a4e
28 changed files with 362 additions and 255 deletions

View File

@ -15,6 +15,7 @@ pytest-tornado = "==0.5.0"
ipython = "*" ipython = "*"
ipdb = "*" ipdb = "*"
pylint = "*" pylint = "*"
black = "*"
[requires] [requires]
python_version = "3.6" python_version = "3.6"

72
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "3ee82a3d0081be8881d2c211c6d0333b179e78754e953b609e10a51a4ab87c88" "sha256": "4792f21af3f461ea6eb1c7c2f7387a545cb5cfaedaf5f27694e16b6ba0a042fd"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -58,6 +58,13 @@
} }
}, },
"develop": { "develop": {
"appdirs": {
"hashes": [
"sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92",
"sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"
],
"version": "==1.4.3"
},
"appnope": { "appnope": {
"hashes": [ "hashes": [
"sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0", "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0",
@ -68,10 +75,10 @@
}, },
"astroid": { "astroid": {
"hashes": [ "hashes": [
"sha256:0ef2bf9f07c3150929b25e8e61b5198c27b0dca195e156f0e4d5bdd89185ca1a", "sha256:ae61ddd0290963f4cf3bd74e6dffce807466bfe25438b2b3598471a1ce40a635",
"sha256:fc9b582dba0366e63540982c3944a9230cbc6f303641c51483fa547dcc22393a" "sha256:f447b5c8b7bd5cba229fb73890ea8088380c8c37ff33417c29a53a553f857419"
], ],
"version": "==1.6.5" "version": "==2.0.0.dev3"
}, },
"atomicwrites": { "atomicwrites": {
"hashes": [ "hashes": [
@ -94,6 +101,21 @@
], ],
"version": "==0.1.0" "version": "==0.1.0"
}, },
"black": {
"hashes": [
"sha256:22158b89c1a6b4eb333a1e65e791a3f8b998cf3b11ae094adb2570f31f769a44",
"sha256:4b475bbd528acce094c503a3d2dbc2d05a4075f6d0ef7d9e7514518e14cc5191"
],
"index": "pypi",
"version": "==18.6b4"
},
"click": {
"hashes": [
"sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
"sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
],
"version": "==6.7"
},
"decorator": { "decorator": {
"hashes": [ "hashes": [
"sha256:2c51dff8ef3c447388fe5e4453d24a2bf128d3a4c32af3fabef1f01c6851ab82", "sha256:2c51dff8ef3c447388fe5e4453d24a2bf128d3a4c32af3fabef1f01c6851ab82",
@ -227,10 +249,10 @@
}, },
"ptyprocess": { "ptyprocess": {
"hashes": [ "hashes": [
"sha256:e64193f0047ad603b71f202332ab5527c5e52aa7c8b609704fc28c0dc20c4365", "sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0",
"sha256:e8c43b5eee76b2083a9badde89fd1bbce6c8942d1045146e100b7b5e014f4f1a" "sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"
], ],
"version": "==0.5.2" "version": "==0.6.0"
}, },
"py": { "py": {
"hashes": [ "hashes": [
@ -248,11 +270,11 @@
}, },
"pylint": { "pylint": {
"hashes": [ "hashes": [
"sha256:a48070545c12430cfc4e865bf62f5ad367784765681b3db442d8230f0960aa3c", "sha256:0990347c0f605927fadb2a9366a0b3d40bd19eb44e4312f0a1ef729a389b2f40",
"sha256:fff220bcb996b4f7e2b0f6812fd81507b72ca4d8c4d05daf2655c333800cb9b3" "sha256:19b902f93f2dc3fa45565e54b88702b28379be40107f509a8516dde152460d1f"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.9.2" "version": "==2.0.0.dev1"
}, },
"pytest": { "pytest": {
"hashes": [ "hashes": [
@ -283,6 +305,12 @@
], ],
"version": "==1.11.0" "version": "==1.11.0"
}, },
"toml": {
"hashes": [
"sha256:8e86bd6ce8cc11b9620cb637466453d94f5d57ad86f17e98a98d1f73e3baab2d"
],
"version": "==0.9.4"
},
"tornado": { "tornado": {
"hashes": [ "hashes": [
"sha256:1b83d5c10550f2653380b4c77331d6f8850f287c4f67d7ce1e1c639d9222fbc7", "sha256:1b83d5c10550f2653380b4c77331d6f8850f287c4f67d7ce1e1c639d9222fbc7",
@ -301,6 +329,30 @@
], ],
"version": "==4.3.2" "version": "==4.3.2"
}, },
"typed-ast": {
"hashes": [
"sha256:0948004fa228ae071054f5208840a1e88747a357ec1101c17217bfe99b299d58",
"sha256:25d8feefe27eb0303b73545416b13d108c6067b846b543738a25ff304824ed9a",
"sha256:29464a177d56e4e055b5f7b629935af7f49c196be47528cc94e0a7bf83fbc2b9",
"sha256:2e214b72168ea0275efd6c884b114ab42e316de3ffa125b267e732ed2abda892",
"sha256:3e0d5e48e3a23e9a4d1a9f698e32a542a4a288c871d33ed8df1b092a40f3a0f9",
"sha256:519425deca5c2b2bdac49f77b2c5625781abbaf9a809d727d3a5596b30bb4ded",
"sha256:57fe287f0cdd9ceaf69e7b71a2e94a24b5d268b35df251a88fef5cc241bf73aa",
"sha256:668d0cec391d9aed1c6a388b0d5b97cd22e6073eaa5fbaa6d2946603b4871efe",
"sha256:68ba70684990f59497680ff90d18e756a47bf4863c604098f10de9716b2c0bdd",
"sha256:6de012d2b166fe7a4cdf505eee3aaa12192f7ba365beeefaca4ec10e31241a85",
"sha256:79b91ebe5a28d349b6d0d323023350133e927b4de5b651a8aa2db69c761420c6",
"sha256:8550177fa5d4c1f09b5e5f524411c44633c80ec69b24e0e98906dd761941ca46",
"sha256:a8034021801bc0440f2e027c354b4eafd95891b573e12ff0418dec385c76785c",
"sha256:bc978ac17468fe868ee589c795d06777f75496b1ed576d308002c8a5756fb9ea",
"sha256:c05b41bc1deade9f90ddc5d988fe506208019ebba9f2578c622516fd201f5863",
"sha256:c9b060bd1e5a26ab6e8267fd46fc9e02b54eb15fffb16d112d4c7b1c12987559",
"sha256:edb04bdd45bfd76c8292c4d9654568efaedf76fe78eb246dde69bdb13b2dad87",
"sha256:f19f2a4f547505fe9072e15f6f4ae714af51b5a681a97f187971f50c283193b6"
],
"markers": "python_version < '3.7' and implementation_name == 'cpython'",
"version": "==1.1.0"
},
"wcwidth": { "wcwidth": {
"hashes": [ "hashes": [
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",

4
app.py
View File

@ -8,8 +8,8 @@ config = make_config()
deps = make_deps(config) deps = make_deps(config)
app = make_app(config, deps) app = make_app(config, deps)
if __name__ == '__main__': if __name__ == "__main__":
port = int(config['default']['PORT']) port = int(config["default"]["PORT"])
app.listen(port) app.listen(port)
print("Listening on http://localhost:%i" % port) print("Listening on http://localhost:%i" % port)
tornado.ioloop.IOLoop.current().start() tornado.ioloop.IOLoop.current().start()

View File

@ -4,54 +4,52 @@ from json import dumps, loads
class ApiClient(object): class ApiClient(object):
def __init__(self, base_url, api_version=None, validate_cert=True): def __init__(self, base_url, api_version=None, validate_cert=True):
self.base_url = base_url self.base_url = base_url
if api_version: if api_version:
self.base_url = f'{base_url}/api/{api_version}' self.base_url = f"{base_url}/api/{api_version}"
self.client = AsyncHTTPClient() self.client = AsyncHTTPClient()
self.validate_cert = validate_cert self.validate_cert = validate_cert
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self, path, **kwargs): def get(self, path, **kwargs):
return (yield self.make_request('GET', self.base_url + path, **kwargs)) return (yield self.make_request("GET", self.base_url + path, **kwargs))
@tornado.gen.coroutine @tornado.gen.coroutine
def put(self, path, **kwargs): def put(self, path, **kwargs):
return (yield self.make_request('PUT', self.base_url + path, **kwargs)) return (yield self.make_request("PUT", self.base_url + path, **kwargs))
@tornado.gen.coroutine @tornado.gen.coroutine
def post(self, path, **kwargs): def post(self, path, **kwargs):
return (yield self.make_request('POST', self.base_url + path, **kwargs)) return (yield self.make_request("POST", self.base_url + path, **kwargs))
@tornado.gen.coroutine @tornado.gen.coroutine
def patch(self, path, **kwargs): def patch(self, path, **kwargs):
return (yield self.make_request('PATCH', self.base_url + path, **kwargs)) return (yield self.make_request("PATCH", self.base_url + path, **kwargs))
@tornado.gen.coroutine @tornado.gen.coroutine
def delete(self, path, **kwargs): def delete(self, path, **kwargs):
return (yield self.make_request('DELETE', self.base_url + path, **kwargs)) return (yield self.make_request("DELETE", self.base_url + path, **kwargs))
@tornado.gen.coroutine @tornado.gen.coroutine
def make_request(self, method, url, **kwargs): def make_request(self, method, url, **kwargs):
# If 'json' kwarg is specified, serialize it to 'body' and update # If 'json' kwarg is specified, serialize it to 'body' and update
# the Content-Type. # the Content-Type.
if 'json' in kwargs: if "json" in kwargs:
kwargs['body'] = dumps(kwargs['json']) kwargs["body"] = dumps(kwargs["json"])
del kwargs['json'] del kwargs["json"]
headers = kwargs.get('headers', {}) headers = kwargs.get("headers", {})
headers['Content-Type'] = 'application/json' headers["Content-Type"] = "application/json"
kwargs['headers'] = headers kwargs["headers"] = headers
if not 'validate_cert' in kwargs: if not "validate_cert" in kwargs:
kwargs['validate_cert'] = self.validate_cert kwargs["validate_cert"] = self.validate_cert
response = yield self.client.fetch( response = yield self.client.fetch(url, method=method, **kwargs)
url, method=method, **kwargs)
return self.adapt_response(response) return self.adapt_response(response)
def adapt_response(self, response): def adapt_response(self, response):
if 'application/json' in response.headers['Content-Type']: if "application/json" in response.headers["Content-Type"]:
json = loads(response.body) json = loads(response.body)
setattr(response, 'json', json) setattr(response, "json", json)
setattr(response, 'ok', 200 <= response.code < 300) setattr(response, "ok", 200 <= response.code < 300)
return response return response

View File

@ -20,14 +20,14 @@ def make_app(config, deps, **kwargs):
routes = [ routes = [
url(r"/", Home, {"page": "login"}, name="main"), url(r"/", Home, {"page": "login"}, name="main"),
url( url(r"/login", Login, {"authnid_client": deps["authnid_client"]}, name="login"),
r"/login",
Login,
{"authnid_client": deps["authnid_client"]},
name="login",
),
url(r"/home", MainHandler, {"page": "home"}, name="home"), url(r"/home", MainHandler, {"page": "home"}, name="home"),
url( r"/workspaces/blank", MainHandler, {'page': 'workspaces_blank'}, name='workspaces_blank' ), url(
r"/workspaces/blank",
MainHandler,
{"page": "workspaces_blank"},
name="workspaces_blank",
),
url( url(
r"/workspaces", r"/workspaces",
Workspace, Workspace,
@ -37,13 +37,15 @@ def make_app(config, deps, **kwargs):
url( url(
r"/requests", r"/requests",
Request, Request,
{"page": "requests", 'requests_client': deps['requests_client']}, {"page": "requests", "requests_client": deps["requests_client"]},
name="requests"), name="requests",
),
url( url(
r"/requests/new", r"/requests/new",
RequestNew, RequestNew,
{"page": "requests_new", "requests_client": deps["requests_client"]}, {"page": "requests_new", "requests_client": deps["requests_client"]},
name="request_new"), name="request_new",
),
url( url(
r"/requests/new/([0-9])", r"/requests/new/([0-9])",
RequestNew, RequestNew,
@ -67,12 +69,11 @@ def make_app(config, deps, **kwargs):
app = tornado.web.Application( app = tornado.web.Application(
routes, routes,
login_url="/", login_url="/",
template_path=home.child("templates"),
template_path = home.child('templates'), static_path=home.child("static"),
static_path = home.child('static'),
cookie_secret=config["default"]["COOKIE_SECRET"], cookie_secret=config["default"]["COOKIE_SECRET"],
debug=config['default'].getboolean('DEBUG'), debug=config["default"].getboolean("DEBUG"),
**kwargs **kwargs,
) )
app.config = config app.config = config
return app return app
@ -80,23 +81,30 @@ def make_app(config, deps, **kwargs):
def make_deps(config): def make_deps(config):
# we do not want to do SSL verify services in test and development # we do not want to do SSL verify services in test and development
validate_cert = ENV == 'production' validate_cert = ENV == "production"
return { return {
'authz_client': ApiClient(config["default"]["AUTHZ_BASE_URL"], api_version='v1', validate_cert=validate_cert), "authz_client": ApiClient(
'authnid_client': ApiClient(config["default"]["AUTHNID_BASE_URL"], api_version='v1', validate_cert=validate_cert), config["default"]["AUTHZ_BASE_URL"],
'requests_client': ApiClient(config["default"]["REQUESTS_QUEUE_BASE_URL"], api_version='v1', validate_cert=validate_cert) api_version="v1",
validate_cert=validate_cert,
),
"authnid_client": ApiClient(
config["default"]["AUTHNID_BASE_URL"],
api_version="v1",
validate_cert=validate_cert,
),
"requests_client": ApiClient(
config["default"]["REQUESTS_QUEUE_BASE_URL"],
api_version="v1",
validate_cert=validate_cert,
),
} }
def make_config(): def make_config():
BASE_CONFIG_FILENAME = os.path.join( BASE_CONFIG_FILENAME = os.path.join(os.path.dirname(__file__), "../config/base.ini")
os.path.dirname(__file__),
"../config/base.ini"
)
ENV_CONFIG_FILENAME = os.path.join( ENV_CONFIG_FILENAME = os.path.join(
os.path.dirname(__file__), os.path.dirname(__file__), "../config/", "{}.ini".format(ENV.lower())
"../config/",
"{}.ini".format(ENV.lower())
) )
config = ConfigParser() config = ConfigParser()

View File

@ -2,7 +2,8 @@ from wtforms.fields.html5 import IntegerField
from wtforms.validators import Required, ValidationError from wtforms.validators import Required, ValidationError
from wtforms_tornado import Form from wtforms_tornado import Form
class DateForm(Form): class DateForm(Form):
month = IntegerField('Month', validators=[Required()]) month = IntegerField("Month", validators=[Required()])
day = IntegerField('Day', validators=[Required()]) day = IntegerField("Day", validators=[Required()])
year = IntegerField('Year', validators=[Required()]) year = IntegerField("Year", validators=[Required()])

View File

@ -1,4 +1,5 @@
from wtforms_tornado import Form from wtforms_tornado import Form
class FundingForm(Form): class FundingForm(Form):
pass pass

View File

@ -1,4 +1,5 @@
from wtforms_tornado import Form from wtforms_tornado import Form
class OrganizationInfoForm(Form): class OrganizationInfoForm(Form):
pass pass

View File

@ -1,4 +1,5 @@
from wtforms_tornado import Form from wtforms_tornado import Form
class ReadinessForm(Form): class ReadinessForm(Form):
pass pass

View File

@ -1,44 +1,73 @@
from wtforms.fields.html5 import IntegerField from wtforms.fields.html5 import IntegerField
from wtforms.fields import RadioField, StringField, SelectField, TextAreaField, FormField from wtforms.fields import (
RadioField,
StringField,
SelectField,
TextAreaField,
FormField,
)
from wtforms.validators import Required, ValidationError from wtforms.validators import Required, ValidationError
from wtforms_tornado import Form from wtforms_tornado import Form
from .date import DateForm from .date import DateForm
class RequestForm(Form): class RequestForm(Form):
application_name = StringField('Application name', validators=[Required()]) application_name = StringField("Application name", validators=[Required()])
application_description = TextAreaField('Application description', validators=[Required()]) application_description = TextAreaField(
dollar_value = IntegerField('Estimated dollar value of use', validators=[Required()]) "Application description", validators=[Required()]
input_estimate = SelectField('How did you arrive at this estimate?', validators=[Required()], )
choices=[('','- Select -'), dollar_value = IntegerField(
('calculator','CSP usage calculator'), "Estimated dollar value of use", validators=[Required()]
('B','Option B'), )
('C','Option C') ]) input_estimate = SelectField(
"How did you arrive at this estimate?",
validators=[Required()],
choices=[
("", "- Select -"),
("calculator", "CSP usage calculator"),
("B", "Option B"),
("C", "Option C"),
],
)
# no way to apply a label to a whole nested form like this # no way to apply a label to a whole nested form like this
date_start = FormField(DateForm) date_start = FormField(DateForm)
period_of_performance = SelectField('Desired period of performance', validators=[Required()], period_of_performance = SelectField(
choices=[('','- Select -'), "Desired period of performance",
('value1','30 days'), validators=[Required()],
('value2','60 days'), choices=[
('value3','90 days') ]) ("", "- Select -"),
classification_level = RadioField('Classification level', validators=[Required()], ("value1", "30 days"),
choices=[('unclassified', 'Unclassified'), ("value2", "60 days"),
('secret', 'Secret'), ("value3", "90 days"),
('top-secret', 'Top Secret') ]) ],
primary_service_branch = StringField('Primary service branch usage', validators=[Required()]) )
cloud_model = RadioField('Cloud model service', validators=[Required()], classification_level = RadioField(
choices=[('iaas', 'IaaS'), "Classification level",
('paas', 'PaaS'), validators=[Required()],
('both', 'Both') ]) choices=[
number_of_cores = IntegerField('Number of cores', validators=[Required()]) ("unclassified", "Unclassified"),
total_ram = IntegerField('Total RAM', validators=[Required()]) ("secret", "Secret"),
object_storage = IntegerField('Total object storage', validators=[Required()]) ("top-secret", "Top Secret"),
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()]) primary_service_branch = StringField(
total_requests = IntegerField('Total requests', validators=[Required()]) "Primary service branch usage", validators=[Required()]
total_environments = IntegerField('Total environments', validators=[Required()]) )
cloud_model = RadioField(
"Cloud model service",
validators=[Required()],
choices=[("iaas", "IaaS"), ("paas", "PaaS"), ("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. # this is just an example validation; obviously this is wrong.
def validate_total_ram(self,field): def validate_total_ram(self, field):
if (field.data % 2) != 0: if (field.data % 2) != 0:
raise ValidationError("RAM must be in increments of 2.") raise ValidationError("RAM must be in increments of 2.")

View File

@ -1,4 +1,5 @@
from wtforms_tornado import Form from wtforms_tornado import Form
class ReviewForm(Form): class ReviewForm(Form):
pass pass

View File

@ -2,34 +2,31 @@ from webassets import Environment, Bundle
import tornado.web import tornado.web
from atst.home import home from atst.home import home
assets = Environment( assets = Environment(directory=home.child("scss"), url="/static")
directory = home.child('scss'), css = Bundle(
url = '/static') "atat.scss",
css = Bundle( filters="scss",
'atat.scss', output="../static/assets/out.css",
filters = 'scss', depends=("**/*.scss"),
output = '../static/assets/out.css', )
depends = ('**/*.scss'))
assets.register( 'css', css ) assets.register("css", css)
helpers = { helpers = {"assets": assets}
'assets': assets,
}
class BaseHandler(tornado.web.RequestHandler): class BaseHandler(tornado.web.RequestHandler):
def get_template_namespace(self): def get_template_namespace(self):
ns = super(BaseHandler, self).get_template_namespace() ns = super(BaseHandler, self).get_template_namespace()
helpers['config'] = self.application.config helpers["config"] = self.application.config
ns.update(helpers) ns.update(helpers)
return ns return ns
def get_current_user(self): def get_current_user(self):
if self.get_secure_cookie('atst'): if self.get_secure_cookie("atst"):
return '9cb348f0-8102-4962-88c4-dac8180c904c' return "9cb348f0-8102-4962-88c4-dac8180c904c"
else: else:
return False return False
# this is a temporary implementation until we have real sessions # this is a temporary implementation until we have real sessions
def _start_session(self): def _start_session(self):
self.set_secure_cookie('atst', 'valid-user-session') self.set_secure_cookie("atst", "valid-user-session")

View File

@ -1,11 +1,12 @@
from atst.handler import BaseHandler from atst.handler import BaseHandler
class Dev(BaseHandler): class Dev(BaseHandler):
def initialize(self, action): def initialize(self, action):
self.action = action self.action = action
def get(self): def get(self):
if self.action == 'login': if self.action == "login":
self._login() self._login()
def _login(self): def _login(self):

View File

@ -1,9 +1,9 @@
from atst.handler import BaseHandler from atst.handler import BaseHandler
class Home(BaseHandler):
class Home(BaseHandler):
def initialize(self, page): def initialize(self, page):
self.page = page self.page = page
def get(self): def get(self):
self.render( '%s.html.to' % self.page, page = self.page ) self.render("%s.html.to" % self.page, page=self.page)

View File

@ -3,7 +3,6 @@ from atst.handler import BaseHandler
class Login(BaseHandler): class Login(BaseHandler):
def initialize(self, authnid_client): def initialize(self, authnid_client):
self.authnid_client = authnid_client self.authnid_client = authnid_client

View File

@ -1,11 +1,11 @@
import tornado import tornado
from atst.handler import BaseHandler from atst.handler import BaseHandler
class MainHandler(BaseHandler):
class MainHandler(BaseHandler):
def initialize(self, page): def initialize(self, page):
self.page = page self.page = page
@tornado.web.authenticated @tornado.web.authenticated
def get(self): def get(self):
self.render( '%s.html.to' % self.page, page = self.page ) self.render("%s.html.to" % self.page, page=self.page)

View File

@ -2,43 +2,45 @@ import tornado
from atst.handler import BaseHandler from atst.handler import BaseHandler
mock_requests = [ mock_requests = [
{ {
'order_id' : 36552612, "order_id": 36552612,
'date' : '5/17/2018', "date": "5/17/2018",
'is_new' : True, "is_new": True,
'full_name' : 'Friedrich Straat', "full_name": "Friedrich Straat",
'app_count' : 2, "app_count": 2,
'status' : 'Pending' "status": "Pending",
}, },
{ {
'order_id' : 87362910, "order_id": 87362910,
'date' : '10/2/2017', "date": "10/2/2017",
'is_new' : False, "is_new": False,
'full_name' : 'Pietro Quirinis', "full_name": "Pietro Quirinis",
'app_count' : 1, "app_count": 1,
'status' : 'Complete' "status": "Complete",
}, },
{ {
'order_id' : 29938172, "order_id": 29938172,
'date' : '1/7/2017', "date": "1/7/2017",
'is_new' : False, "is_new": False,
'full_name' : 'Marina Borsetti', "full_name": "Marina Borsetti",
'app_count' : 1, "app_count": 1,
'status' : 'Denied' "status": "Denied",
}, },
] ]
def map_request(request): def map_request(request):
return { return {
'order_id': request['id'], "order_id": request["id"],
'is_new': False, "is_new": False,
'status': 'Pending', "status": "Pending",
'app_count': 1, "app_count": 1,
'is_new': False, "is_new": False,
'date': '', "date": "",
'full_name': 'Richard Howard' "full_name": "Richard Howard",
} }
class Request(BaseHandler): class Request(BaseHandler):
def initialize(self, page, requests_client): def initialize(self, page, requests_client):
self.page = page self.page = page
@ -48,7 +50,8 @@ class Request(BaseHandler):
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self): def get(self):
response = yield self.requests_client.get( response = yield self.requests_client.get(
'/users/{}/requests'.format(self.get_current_user())) "/users/{}/requests".format(self.get_current_user())
requests = response.json['requests'] )
requests = response.json["requests"]
mapped_requests = [map_request(request) for request in requests] mapped_requests = [map_request(request) for request in requests]
self.render('requests.html.to', page=self.page, requests=mapped_requests) self.render("requests.html.to", page=self.page, requests=mapped_requests)

View File

@ -11,35 +11,21 @@ from tornado.httpclient import HTTPError
class RequestNew(BaseHandler): class RequestNew(BaseHandler):
screens = [ screens = [
{ 'title' : 'Details of Use', {
'form' : RequestForm, "title": "Details of Use",
'subitems' : [ "form": RequestForm,
{'title' : 'Application Details', "subitems": [
'id' : 'application-details'}, {"title": "Application Details", "id": "application-details"},
{'title' : 'Computation', {"title": "Computation", "id": "computation"},
'id' : 'computation' }, {"title": "Storage", "id": "storage"},
{'title' : 'Storage', {"title": "Usage", "id": "usage"},
'id' : 'storage' }, ],
{'title' : 'Usage', },
'id' : 'usage' }, {"title": "Organizational Info", "form": OrganizationInfoForm},
]}, {"title": "Funding/Contracting", "form": FundingForm},
{ {"title": "Readiness Survey", "form": ReadinessForm},
'title' : 'Organizational Info', {"title": "Review & Submit", "form": ReviewForm},
'form' : OrganizationInfoForm, ]
},
{
'title' : 'Funding/Contracting',
'form' : FundingForm,
},
{
'title' : 'Readiness Survey',
'form' : ReadinessForm,
},
{
'title' : 'Review & Submit',
'form' : ReviewForm,
}
]
def initialize(self, page, requests_client): def initialize(self, page, requests_client):
self.page = page self.page = page
@ -50,12 +36,15 @@ 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 = self.screens[ screen - 1 ]['form'](self.request.arguments) form = self.screens[screen - 1]["form"](self.request.arguments)
if form.validate(): if form.validate():
response = yield self.create_or_update_request(form.data, request_id) response = yield self.create_or_update_request(form.data, request_id)
if response.ok: if response.ok:
where = self.application.default_router.reverse_url( 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),
request_id or response.json["id"],
)
self.redirect(where) self.redirect(where)
else: else:
self.set_status(response.code) self.set_status(response.code)
@ -69,39 +58,39 @@ class RequestNew(BaseHandler):
if request_id: if request_id:
request = yield self.get_request(request_id) request = yield self.get_request(request_id)
if request.ok: if request.ok:
form_data = request.json['body'] if request else {} form_data = request.json["body"] if request else {}
form = self.screens[ int(screen) - 1 ]['form'](data=form_data) form = self.screens[int(screen) - 1]["form"](data=form_data)
self.show_form(screen=screen, form=form, request_id=request_id) self.show_form(screen=screen, form=form, request_id=request_id)
def show_form(self, screen=1, form=None, request_id=None): def show_form(self, screen=1, form=None, request_id=None):
if not form: if not form:
form = self.screens[ int(screen) - 1 ]['form'](self.request.arguments) form = self.screens[int(screen) - 1]["form"](self.request.arguments)
self.render('requests/screen-%d.html.to' % int(screen), self.render(
f=form, "requests/screen-%d.html.to" % int(screen),
page=self.page, f=form,
screens=self.screens, page=self.page,
current=int(screen), screens=self.screens,
next_screen=int(screen) + 1, current=int(screen),
request_id=request_id) next_screen=int(screen) + 1,
request_id=request_id,
)
@tornado.gen.coroutine @tornado.gen.coroutine
def get_request(self, request_id): def get_request(self, request_id):
request = yield self.requests_client.get( request = yield self.requests_client.get(
'/users/{}/requests/{}'.format(self.get_current_user(), request_id), "/users/{}/requests/{}".format(self.get_current_user(), request_id),
raise_error=False) raise_error=False,
)
return request return request
@tornado.gen.coroutine @tornado.gen.coroutine
def create_or_update_request(self, form_data, request_id=None): def create_or_update_request(self, form_data, request_id=None):
request_data = { request_data = {"creator_id": self.get_current_user(), "request": form_data}
'creator_id': self.get_current_user(),
'request': form_data
}
if request_id: if request_id:
response = yield self.requests_client.patch( response = yield self.requests_client.patch(
'/requests/{}'.format(request_id), json=request_data) "/requests/{}".format(request_id), json=request_data
)
else: else:
response = yield self.requests_client.post( response = yield self.requests_client.post("/requests", json=request_data)
'/requests', json=request_data)
return response return response

View File

@ -3,17 +3,15 @@ import tornado
mock_workspaces = [ mock_workspaces = [
{ {
'name' : 'Unclassified IaaS and PaaS for Defense Digital Service (DDS)', "name": "Unclassified IaaS and PaaS for Defense Digital Service (DDS)",
'id': '5966187a-eff9-44c3-aa15-4de7a65ac7ff', "id": "5966187a-eff9-44c3-aa15-4de7a65ac7ff",
'task_order' : { "task_order": {"number": 123456},
'number' : 123456, "user_count": 23,
},
'user_count' : 23,
} }
] ]
class Workspace(BaseHandler):
class Workspace(BaseHandler):
def initialize(self, page, authz_client): def initialize(self, page, authz_client):
self.page = page self.page = page
self.authz_client = authz_client self.authz_client = authz_client
@ -21,4 +19,4 @@ class Workspace(BaseHandler):
@tornado.gen.coroutine @tornado.gen.coroutine
@tornado.web.authenticated @tornado.web.authenticated
def get(self): def get(self):
self.render( 'workspaces.html.to', page = self.page, workspaces = mock_workspaces ) self.render("workspaces.html.to", page=self.page, workspaces=mock_workspaces)

View File

@ -1,3 +1,3 @@
from unipath import Path from unipath import Path
home = Path( __file__ ).parent.parent home = Path(__file__).parent.parent

18
pyproject.toml Normal file
View File

@ -0,0 +1,18 @@
[tool.black]
line-length = 88
py36 = true
include = '\.pyi?$'
exclude = '''
/(
\.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
| node_modules
)/
'''

View File

@ -7,9 +7,9 @@ from tests.mocks import MockApiClient, MockRequestsClient
@pytest.fixture @pytest.fixture
def app(): def app():
TEST_DEPS = { TEST_DEPS = {
'authz_client': MockApiClient('authz'), "authz_client": MockApiClient("authz"),
'requests_client': MockRequestsClient('requests'), "requests_client": MockRequestsClient("requests"),
'authnid_client': MockApiClient('authnid'), "authnid_client": MockApiClient("authnid"),
} }
config = make_config() config = make_config()

View File

@ -4,9 +4,11 @@ from atst.forms.request import RequestForm
form = RequestForm() form = RequestForm()
def test_form_has_expected_fields(): def test_form_has_expected_fields():
label = form.application_name.label label = form.application_name.label
assert label.text == 'Application name' assert label.text == "Application name"
def test_form_can_validate_total_ram(): def test_form_can_validate_total_ram():
form.application_name.data = 5 form.application_name.data = 5

View File

@ -1,13 +1,17 @@
import re import re
import pytest import pytest
ERROR_CLASS = 'usa-input-error-message' ERROR_CLASS = "usa-input-error-message"
@pytest.mark.gen_test @pytest.mark.gen_test
def test_submit_invalid_request_form(monkeypatch, http_client, base_url): def test_submit_invalid_request_form(monkeypatch, http_client, base_url):
monkeypatch.setattr('atst.handlers.request_new.RequestNew.get_current_user', lambda s: True) monkeypatch.setattr(
monkeypatch.setattr('atst.handlers.request_new.RequestNew.check_xsrf_cookie', lambda s: True) "atst.handlers.request_new.RequestNew.get_current_user", lambda s: True
)
monkeypatch.setattr(
"atst.handlers.request_new.RequestNew.check_xsrf_cookie", lambda s: True
)
# this just needs to send a known invalid form value # this just needs to send a known invalid form value
response = yield http_client.fetch( response = yield http_client.fetch(
base_url + "/requests/new", base_url + "/requests/new",
@ -15,15 +19,19 @@ def test_submit_invalid_request_form(monkeypatch, http_client, base_url):
headers={"Content-Type": "application/x-www-form-urlencoded"}, headers={"Content-Type": "application/x-www-form-urlencoded"},
body="total_ram=5", body="total_ram=5",
) )
assert response.effective_url == base_url + '/requests/new' assert response.effective_url == base_url + "/requests/new"
assert re.search(ERROR_CLASS, response.body.decode()) assert re.search(ERROR_CLASS, response.body.decode())
@pytest.mark.gen_test @pytest.mark.gen_test
def test_submit_valid_request_form(monkeypatch, http_client, base_url): def test_submit_valid_request_form(monkeypatch, http_client, base_url):
monkeypatch.setattr('atst.handlers.request_new.RequestNew.get_current_user', lambda s: True) monkeypatch.setattr(
monkeypatch.setattr('atst.handlers.request_new.RequestNew.check_xsrf_cookie', lambda s: True) "atst.handlers.request_new.RequestNew.get_current_user", lambda s: True
monkeypatch.setattr('atst.forms.request.RequestForm.validate', lambda s: True) )
monkeypatch.setattr(
"atst.handlers.request_new.RequestNew.check_xsrf_cookie", lambda s: True
)
monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s: True)
# this just needs to send a known invalid form value # this just needs to send a known invalid form value
response = yield http_client.fetch( response = yield http_client.fetch(
@ -32,4 +40,4 @@ def test_submit_valid_request_form(monkeypatch, http_client, base_url):
headers={"Content-Type": "application/x-www-form-urlencoded"}, headers={"Content-Type": "application/x-www-form-urlencoded"},
body="meaning=42", body="meaning=42",
) )
assert '/requests/new/2' in response.effective_url assert "/requests/new/2" in response.effective_url

View File

@ -10,33 +10,34 @@ class MockApiClient(ApiClient):
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self, path, **kwargs): def get(self, path, **kwargs):
return self._get_response('GET', path) return self._get_response("GET", path)
@tornado.gen.coroutine @tornado.gen.coroutine
def put(self, path, **kwargs): def put(self, path, **kwargs):
return self._get_response('PUT', path) return self._get_response("PUT", path)
@tornado.gen.coroutine @tornado.gen.coroutine
def patch(self, path, **kwargs): def patch(self, path, **kwargs):
return self._get_response('PATCH', path) return self._get_response("PATCH", path)
@tornado.gen.coroutine @tornado.gen.coroutine
def post(self, path, **kwargs): def post(self, path, **kwargs):
return self._get_response('POST', path) return self._get_response("POST", path)
@tornado.gen.coroutine @tornado.gen.coroutine
def delete(self, path, **kwargs): def delete(self, path, **kwargs):
return self._get_response('DELETE', path) return self._get_response("DELETE", path)
def _get_response(self, verb, path, code=200, json=None): def _get_response(self, verb, path, code=200, json=None):
response = HTTPResponse( response = HTTPResponse(
request=HTTPRequest(path, verb), request=HTTPRequest(path, verb),
code=code, code=code,
headers={'Content-Type': 'application/json'}) headers={"Content-Type": "application/json"},
)
setattr(response, 'ok', 200 <= code < 300) setattr(response, "ok", 200 <= code < 300)
if json: if json:
setattr(response, 'json', json) setattr(response, "json", json)
return response return response
@ -45,18 +46,17 @@ class MockRequestsClient(MockApiClient):
@tornado.gen.coroutine @tornado.gen.coroutine
def get(self, path, **kwargs): def get(self, path, **kwargs):
json = { json = {
'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": {},
} }
return self._get_response('GET', path, 200, json=json) return self._get_response("GET", path, 200, json=json)
@tornado.gen.coroutine @tornado.gen.coroutine
def post(self, path, **kwargs): def post(self, path, **kwargs):
json = { json = {
'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": {},
} }
return self._get_response('POST', path, 202, json=json) return self._get_response("POST", path, 202, json=json)

View File

@ -6,5 +6,5 @@ from atst.api_client import ApiClient
@pytest.mark.gen_test @pytest.mark.gen_test
def test_api_client(http_client, base_url): def test_api_client(http_client, base_url):
client = ApiClient(base_url) client = ApiClient(base_url)
response = yield client.get('') response = yield client.get("")
assert response.code == 200 assert response.code == 200

View File

@ -9,10 +9,10 @@ def test_redirects_when_not_logged_in(http_client, base_url):
response = yield http_client.fetch( response = yield http_client.fetch(
base_url + "/home", raise_error=False, follow_redirects=False base_url + "/home", raise_error=False, follow_redirects=False
) )
location = response.headers['Location'] location = response.headers["Location"]
assert response.code == 302 assert response.code == 302
assert response.error assert response.error
assert re.match('/\??', location) assert re.match("/\??", location)
@pytest.mark.gen_test @pytest.mark.gen_test
@ -22,16 +22,15 @@ def test_login_with_valid_bearer_token(app, monkeypatch, http_client, base_url):
return True return True
monkeypatch.setattr( monkeypatch.setattr(
"atst.handlers.login.Login._validate_login_token", "atst.handlers.login.Login._validate_login_token", _validate_login_token
_validate_login_token
) )
response = yield http_client.fetch( response = yield http_client.fetch(
base_url + "/login?bearer-token=abc-123", base_url + "/login?bearer-token=abc-123",
follow_redirects=False, follow_redirects=False,
raise_error=False raise_error=False,
) )
assert response.headers["Set-Cookie"].startswith("atst") assert response.headers["Set-Cookie"].startswith("atst")
assert response.headers['Location'] == '/home' assert response.headers["Location"] == "/home"
assert response.code == 302 assert response.code == 302

View File

@ -4,15 +4,15 @@ import pytest
@pytest.mark.gen_test @pytest.mark.gen_test
def test_routes(http_client, base_url): def test_routes(http_client, base_url):
for path in ( for path in (
'/', "/",
'/home', "/home",
'/workspaces', "/workspaces",
'/requests', "/requests",
'/requests/new', "/requests/new",
'/requests/new/1', "/requests/new/1",
'/users', "/users",
'/reports', "/reports",
'/calculator' "/calculator",
): ):
response = yield http_client.fetch(base_url + path) response = yield http_client.fetch(base_url + path)
assert response.code == 200 assert response.code == 200