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 = "*"
ipdb = "*"
pylint = "*"
black = "*"
[requires]
python_version = "3.6"

72
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "3ee82a3d0081be8881d2c211c6d0333b179e78754e953b609e10a51a4ab87c88"
"sha256": "4792f21af3f461ea6eb1c7c2f7387a545cb5cfaedaf5f27694e16b6ba0a042fd"
},
"pipfile-spec": 6,
"requires": {
@ -58,6 +58,13 @@
}
},
"develop": {
"appdirs": {
"hashes": [
"sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92",
"sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"
],
"version": "==1.4.3"
},
"appnope": {
"hashes": [
"sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0",
@ -68,10 +75,10 @@
},
"astroid": {
"hashes": [
"sha256:0ef2bf9f07c3150929b25e8e61b5198c27b0dca195e156f0e4d5bdd89185ca1a",
"sha256:fc9b582dba0366e63540982c3944a9230cbc6f303641c51483fa547dcc22393a"
"sha256:ae61ddd0290963f4cf3bd74e6dffce807466bfe25438b2b3598471a1ce40a635",
"sha256:f447b5c8b7bd5cba229fb73890ea8088380c8c37ff33417c29a53a553f857419"
],
"version": "==1.6.5"
"version": "==2.0.0.dev3"
},
"atomicwrites": {
"hashes": [
@ -94,6 +101,21 @@
],
"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": {
"hashes": [
"sha256:2c51dff8ef3c447388fe5e4453d24a2bf128d3a4c32af3fabef1f01c6851ab82",
@ -227,10 +249,10 @@
},
"ptyprocess": {
"hashes": [
"sha256:e64193f0047ad603b71f202332ab5527c5e52aa7c8b609704fc28c0dc20c4365",
"sha256:e8c43b5eee76b2083a9badde89fd1bbce6c8942d1045146e100b7b5e014f4f1a"
"sha256:923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0",
"sha256:d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"
],
"version": "==0.5.2"
"version": "==0.6.0"
},
"py": {
"hashes": [
@ -248,11 +270,11 @@
},
"pylint": {
"hashes": [
"sha256:a48070545c12430cfc4e865bf62f5ad367784765681b3db442d8230f0960aa3c",
"sha256:fff220bcb996b4f7e2b0f6812fd81507b72ca4d8c4d05daf2655c333800cb9b3"
"sha256:0990347c0f605927fadb2a9366a0b3d40bd19eb44e4312f0a1ef729a389b2f40",
"sha256:19b902f93f2dc3fa45565e54b88702b28379be40107f509a8516dde152460d1f"
],
"index": "pypi",
"version": "==1.9.2"
"version": "==2.0.0.dev1"
},
"pytest": {
"hashes": [
@ -283,6 +305,12 @@
],
"version": "==1.11.0"
},
"toml": {
"hashes": [
"sha256:8e86bd6ce8cc11b9620cb637466453d94f5d57ad86f17e98a98d1f73e3baab2d"
],
"version": "==0.9.4"
},
"tornado": {
"hashes": [
"sha256:1b83d5c10550f2653380b4c77331d6f8850f287c4f67d7ce1e1c639d9222fbc7",
@ -301,6 +329,30 @@
],
"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": {
"hashes": [
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",

4
app.py
View File

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

View File

@ -4,54 +4,52 @@ from json import dumps, loads
class ApiClient(object):
def __init__(self, base_url, api_version=None, validate_cert=True):
self.base_url = base_url
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.validate_cert = validate_cert
@tornado.gen.coroutine
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
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
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
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
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
def make_request(self, method, url, **kwargs):
# If 'json' kwarg is specified, serialize it to 'body' and update
# the Content-Type.
if 'json' in kwargs:
kwargs['body'] = dumps(kwargs['json'])
del kwargs['json']
headers = kwargs.get('headers', {})
headers['Content-Type'] = 'application/json'
kwargs['headers'] = headers
if not 'validate_cert' in kwargs:
kwargs['validate_cert'] = self.validate_cert
if "json" in kwargs:
kwargs["body"] = dumps(kwargs["json"])
del kwargs["json"]
headers = kwargs.get("headers", {})
headers["Content-Type"] = "application/json"
kwargs["headers"] = headers
if not "validate_cert" in kwargs:
kwargs["validate_cert"] = self.validate_cert
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):
if 'application/json' in response.headers['Content-Type']:
if "application/json" in response.headers["Content-Type"]:
json = loads(response.body)
setattr(response, 'json', json)
setattr(response, 'ok', 200 <= response.code < 300)
setattr(response, "json", json)
setattr(response, "ok", 200 <= response.code < 300)
return response

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,44 +1,73 @@
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_tornado import Form
from .date import DateForm
class RequestForm(Form):
application_name = StringField('Application name', validators=[Required()])
application_description = TextAreaField('Application description', validators=[Required()])
dollar_value = IntegerField('Estimated dollar value of use', validators=[Required()])
input_estimate = SelectField('How did you arrive at this estimate?', validators=[Required()],
choices=[('','- Select -'),
('calculator','CSP usage calculator'),
('B','Option B'),
('C','Option C') ])
application_name = StringField("Application name", validators=[Required()])
application_description = TextAreaField(
"Application description", validators=[Required()]
)
dollar_value = IntegerField(
"Estimated dollar value of use", validators=[Required()]
)
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
date_start = FormField(DateForm)
period_of_performance = SelectField('Desired period of performance', validators=[Required()],
choices=[('','- Select -'),
('value1','30 days'),
('value2','60 days'),
('value3','90 days') ])
classification_level = RadioField('Classification level', validators=[Required()],
choices=[('unclassified', 'Unclassified'),
('secret', 'Secret'),
('top-secret', 'Top Secret') ])
primary_service_branch = StringField('Primary service branch usage', 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()])
period_of_performance = SelectField(
"Desired period of performance",
validators=[Required()],
choices=[
("", "- Select -"),
("value1", "30 days"),
("value2", "60 days"),
("value3", "90 days"),
],
)
classification_level = RadioField(
"Classification level",
validators=[Required()],
choices=[
("unclassified", "Unclassified"),
("secret", "Secret"),
("top-secret", "Top Secret"),
],
)
primary_service_branch = StringField(
"Primary service branch usage", 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.
def validate_total_ram(self,field):
def validate_total_ram(self, field):
if (field.data % 2) != 0:
raise ValidationError("RAM must be in increments of 2.")

View File

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

View File

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

View File

@ -1,9 +1,9 @@
from atst.handler import BaseHandler
class Home(BaseHandler):
class Home(BaseHandler):
def initialize(self, page):
self.page = page
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):
def initialize(self, authnid_client):
self.authnid_client = authnid_client

View File

@ -1,11 +1,11 @@
import tornado
from atst.handler import BaseHandler
class MainHandler(BaseHandler):
class MainHandler(BaseHandler):
def initialize(self, page):
self.page = page
@tornado.web.authenticated
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
mock_requests = [
{
'order_id' : 36552612,
'date' : '5/17/2018',
'is_new' : True,
'full_name' : 'Friedrich Straat',
'app_count' : 2,
'status' : 'Pending'
},
{
'order_id' : 87362910,
'date' : '10/2/2017',
'is_new' : False,
'full_name' : 'Pietro Quirinis',
'app_count' : 1,
'status' : 'Complete'
},
{
'order_id' : 29938172,
'date' : '1/7/2017',
'is_new' : False,
'full_name' : 'Marina Borsetti',
'app_count' : 1,
'status' : 'Denied'
},
]
{
"order_id": 36552612,
"date": "5/17/2018",
"is_new": True,
"full_name": "Friedrich Straat",
"app_count": 2,
"status": "Pending",
},
{
"order_id": 87362910,
"date": "10/2/2017",
"is_new": False,
"full_name": "Pietro Quirinis",
"app_count": 1,
"status": "Complete",
},
{
"order_id": 29938172,
"date": "1/7/2017",
"is_new": False,
"full_name": "Marina Borsetti",
"app_count": 1,
"status": "Denied",
},
]
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'
"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, requests_client):
self.page = page
@ -48,7 +50,8 @@ class Request(BaseHandler):
@tornado.gen.coroutine
def get(self):
response = yield self.requests_client.get(
'/users/{}/requests'.format(self.get_current_user()))
requests = response.json['requests']
"/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)
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):
screens = [
{ 'title' : 'Details of Use',
'form' : RequestForm,
'subitems' : [
{'title' : 'Application Details',
'id' : 'application-details'},
{'title' : 'Computation',
'id' : 'computation' },
{'title' : 'Storage',
'id' : 'storage' },
{'title' : 'Usage',
'id' : 'usage' },
]},
{
'title' : 'Organizational Info',
'form' : OrganizationInfoForm,
},
{
'title' : 'Funding/Contracting',
'form' : FundingForm,
},
{
'title' : 'Readiness Survey',
'form' : ReadinessForm,
},
{
'title' : 'Review & Submit',
'form' : ReviewForm,
}
]
{
"title": "Details of Use",
"form": RequestForm,
"subitems": [
{"title": "Application Details", "id": "application-details"},
{"title": "Computation", "id": "computation"},
{"title": "Storage", "id": "storage"},
{"title": "Usage", "id": "usage"},
],
},
{"title": "Organizational Info", "form": OrganizationInfoForm},
{"title": "Funding/Contracting", "form": FundingForm},
{"title": "Readiness Survey", "form": ReadinessForm},
{"title": "Review & Submit", "form": ReviewForm},
]
def initialize(self, page, requests_client):
self.page = page
@ -50,12 +36,15 @@ class RequestNew(BaseHandler):
def post(self, screen=1, request_id=None):
self.check_xsrf_cookie()
screen = int(screen)
form = self.screens[ screen - 1 ]['form'](self.request.arguments)
form = self.screens[screen - 1]["form"](self.request.arguments)
if form.validate():
response = yield self.create_or_update_request(form.data, request_id)
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),
request_id or response.json["id"],
)
self.redirect(where)
else:
self.set_status(response.code)
@ -69,39 +58,39 @@ class RequestNew(BaseHandler):
if request_id:
request = yield self.get_request(request_id)
if request.ok:
form_data = request.json['body'] if request else {}
form = self.screens[ int(screen) - 1 ]['form'](data=form_data)
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):
if not form:
form = self.screens[ int(screen) - 1 ]['form'](self.request.arguments)
self.render('requests/screen-%d.html.to' % int(screen),
f=form,
page=self.page,
screens=self.screens,
current=int(screen),
next_screen=int(screen) + 1,
request_id=request_id)
form = self.screens[int(screen) - 1]["form"](self.request.arguments)
self.render(
"requests/screen-%d.html.to" % int(screen),
f=form,
page=self.page,
screens=self.screens,
current=int(screen),
next_screen=int(screen) + 1,
request_id=request_id,
)
@tornado.gen.coroutine
def get_request(self, request_id):
request = yield self.requests_client.get(
'/users/{}/requests/{}'.format(self.get_current_user(), request_id),
raise_error=False)
"/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):
request_data = {
'creator_id': self.get_current_user(),
'request': form_data
}
request_data = {"creator_id": self.get_current_user(), "request": form_data}
if request_id:
response = yield self.requests_client.patch(
'/requests/{}'.format(request_id), json=request_data)
"/requests/{}".format(request_id), json=request_data
)
else:
response = yield self.requests_client.post(
'/requests', json=request_data)
response = yield self.requests_client.post("/requests", json=request_data)
return response

View File

@ -3,17 +3,15 @@ import tornado
mock_workspaces = [
{
'name' : 'Unclassified IaaS and PaaS for Defense Digital Service (DDS)',
'id': '5966187a-eff9-44c3-aa15-4de7a65ac7ff',
'task_order' : {
'number' : 123456,
},
'user_count' : 23,
"name": "Unclassified IaaS and PaaS for Defense Digital Service (DDS)",
"id": "5966187a-eff9-44c3-aa15-4de7a65ac7ff",
"task_order": {"number": 123456},
"user_count": 23,
}
]
class Workspace(BaseHandler):
class Workspace(BaseHandler):
def initialize(self, page, authz_client):
self.page = page
self.authz_client = authz_client
@ -21,4 +19,4 @@ class Workspace(BaseHandler):
@tornado.gen.coroutine
@tornado.web.authenticated
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
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
def app():
TEST_DEPS = {
'authz_client': MockApiClient('authz'),
'requests_client': MockRequestsClient('requests'),
'authnid_client': MockApiClient('authnid'),
"authz_client": MockApiClient("authz"),
"requests_client": MockRequestsClient("requests"),
"authnid_client": MockApiClient("authnid"),
}
config = make_config()

View File

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

View File

@ -1,13 +1,17 @@
import re
import pytest
ERROR_CLASS = 'usa-input-error-message'
ERROR_CLASS = "usa-input-error-message"
@pytest.mark.gen_test
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('atst.handlers.request_new.RequestNew.check_xsrf_cookie', lambda s: True)
monkeypatch.setattr(
"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
response = yield http_client.fetch(
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"},
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())
@pytest.mark.gen_test
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('atst.handlers.request_new.RequestNew.check_xsrf_cookie', lambda s: True)
monkeypatch.setattr('atst.forms.request.RequestForm.validate', lambda s: True)
monkeypatch.setattr(
"atst.handlers.request_new.RequestNew.get_current_user", 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
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"},
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
def get(self, path, **kwargs):
return self._get_response('GET', path)
return self._get_response("GET", path)
@tornado.gen.coroutine
def put(self, path, **kwargs):
return self._get_response('PUT', path)
return self._get_response("PUT", path)
@tornado.gen.coroutine
def patch(self, path, **kwargs):
return self._get_response('PATCH', path)
return self._get_response("PATCH", path)
@tornado.gen.coroutine
def post(self, path, **kwargs):
return self._get_response('POST', path)
return self._get_response("POST", path)
@tornado.gen.coroutine
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):
response = HTTPResponse(
request=HTTPRequest(path, verb),
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:
setattr(response, 'json', json)
setattr(response, "json", json)
return response
@ -45,18 +46,17 @@ 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': {}
"id": "66b8ef71-86d3-48ef-abc2-51bfa1732b6b",
"creator": "49903ae7-da4a-49bf-a6dc-9dff5d004238",
"body": {},
}
return self._get_response('GET', path, 200, json=json)
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': {}
"id": "66b8ef71-86d3-48ef-abc2-51bfa1732b6b",
"creator": "49903ae7-da4a-49bf-a6dc-9dff5d004238",
"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
def test_api_client(http_client, base_url):
client = ApiClient(base_url)
response = yield client.get('')
response = yield client.get("")
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(
base_url + "/home", raise_error=False, follow_redirects=False
)
location = response.headers['Location']
location = response.headers["Location"]
assert response.code == 302
assert response.error
assert re.match('/\??', location)
assert re.match("/\??", location)
@pytest.mark.gen_test
@ -22,16 +22,15 @@ def test_login_with_valid_bearer_token(app, monkeypatch, http_client, base_url):
return True
monkeypatch.setattr(
"atst.handlers.login.Login._validate_login_token",
_validate_login_token
"atst.handlers.login.Login._validate_login_token", _validate_login_token
)
response = yield http_client.fetch(
base_url + "/login?bearer-token=abc-123",
follow_redirects=False,
raise_error=False
raise_error=False,
)
assert response.headers["Set-Cookie"].startswith("atst")
assert response.headers['Location'] == '/home'
assert response.headers["Location"] == "/home"
assert response.code == 302

View File

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