Format project
This commit is contained in:
@@ -85,7 +85,9 @@ def map_config(config):
|
||||
"SQLALCHEMY_DATABASE_URI": config["default"]["DATABASE_URI"],
|
||||
"SQLALCHEMY_TRACK_MODIFICATIONS": False,
|
||||
"WTF_CSRF_ENABLED": config.getboolean("default", "WTF_CSRF_ENABLED"),
|
||||
"PERMANENT_SESSION_LIFETIME": config.getint("default", "PERMANENT_SESSION_LIFETIME"),
|
||||
"PERMANENT_SESSION_LIFETIME": config.getint(
|
||||
"default", "PERMANENT_SESSION_LIFETIME"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@@ -127,8 +129,10 @@ def make_config():
|
||||
|
||||
return map_config(config)
|
||||
|
||||
|
||||
def make_redis(config):
|
||||
return redis.Redis.from_url(config['REDIS_URI'])
|
||||
return redis.Redis.from_url(config["REDIS_URI"])
|
||||
|
||||
|
||||
def make_crl_validator(app):
|
||||
crl_locations = []
|
||||
@@ -136,5 +140,6 @@ def make_crl_validator(app):
|
||||
crl_locations.append(filename.absolute())
|
||||
app.crl_cache = CRLCache(app.config["CA_CHAIN"], crl_locations, logger=app.logger)
|
||||
|
||||
|
||||
def make_eda_client(app):
|
||||
app.eda_client = MockEDAClient()
|
||||
|
@@ -3,14 +3,10 @@ from flask_assets import Environment, Bundle
|
||||
environment = Environment()
|
||||
|
||||
css = Bundle(
|
||||
"../static/assets/index.css",
|
||||
output="../static/assets/index.%(version)s.css",
|
||||
"../static/assets/index.css", output="../static/assets/index.%(version)s.css"
|
||||
)
|
||||
|
||||
environment.register("css", css)
|
||||
|
||||
js = Bundle(
|
||||
'../static/assets/index.js',
|
||||
output='../static/assets/index.%(version)s.js'
|
||||
)
|
||||
environment.register('js_all', js)
|
||||
js = Bundle("../static/assets/index.js", output="../static/assets/index.%(version)s.js")
|
||||
environment.register("js_all", js)
|
||||
|
@@ -3,7 +3,14 @@ from flask import g, redirect, url_for, session, request
|
||||
from atst.domain.users import Users
|
||||
|
||||
|
||||
UNPROTECTED_ROUTES = ["atst.root", "dev.login_dev", "atst.login_redirect", "atst.unauthorized", "static"]
|
||||
UNPROTECTED_ROUTES = [
|
||||
"atst.root",
|
||||
"dev.login_dev",
|
||||
"atst.login_redirect",
|
||||
"atst.unauthorized",
|
||||
"static",
|
||||
]
|
||||
|
||||
|
||||
def apply_authentication(app):
|
||||
@app.before_request
|
||||
@@ -26,7 +33,7 @@ def get_current_user():
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def _unprotected_route(request):
|
||||
if request.endpoint in UNPROTECTED_ROUTES:
|
||||
return True
|
||||
|
||||
|
@@ -4,8 +4,7 @@ from .utils import parse_sdn, email_from_certificate
|
||||
from .crl import CRLRevocationException
|
||||
|
||||
|
||||
class AuthenticationContext():
|
||||
|
||||
class AuthenticationContext:
|
||||
def __init__(self, crl_cache, auth_status, sdn, cert):
|
||||
if None in locals().values():
|
||||
raise UnauthenticatedError(
|
||||
|
@@ -9,14 +9,16 @@ class CRLRevocationException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class CRLCache():
|
||||
class CRLCache:
|
||||
|
||||
_PEM_RE = re.compile(
|
||||
b"-----BEGIN CERTIFICATE-----\r?.+?\r?-----END CERTIFICATE-----\r?\n?",
|
||||
re.DOTALL,
|
||||
)
|
||||
|
||||
def __init__(self, root_location, crl_locations=[], store_class=crypto.X509Store, logger=None):
|
||||
def __init__(
|
||||
self, root_location, crl_locations=[], store_class=crypto.X509Store, logger=None
|
||||
):
|
||||
self.store_class = store_class
|
||||
self.certificate_authorities = {}
|
||||
self._load_roots(root_location)
|
||||
@@ -57,7 +59,11 @@ class CRLCache():
|
||||
with open(crl_location, "rb") as crl_file:
|
||||
crl = crypto.load_crl(crypto.FILETYPE_ASN1, crl_file.read())
|
||||
store.add_crl(crl)
|
||||
self.log_info("STORE ID: {}. Adding CRL with issuer {}".format(id(store), crl.get_issuer()))
|
||||
self.log_info(
|
||||
"STORE ID: {}. Adding CRL with issuer {}".format(
|
||||
id(store), crl.get_issuer()
|
||||
)
|
||||
)
|
||||
store = self._add_certificate_chain_to_store(store, crl.get_issuer())
|
||||
return store
|
||||
|
||||
@@ -75,7 +81,11 @@ class CRLCache():
|
||||
def _add_certificate_chain_to_store(self, store, issuer):
|
||||
ca = self.certificate_authorities.get(issuer.der())
|
||||
store.add_cert(ca)
|
||||
self.log_info("STORE ID: {}. Adding CA with subject {}".format(id(store), ca.get_subject()))
|
||||
self.log_info(
|
||||
"STORE ID: {}. Adding CA with subject {}".format(
|
||||
id(store), ca.get_subject()
|
||||
)
|
||||
)
|
||||
|
||||
if issuer == ca.get_issuer():
|
||||
# i.e., it is the root CA and we are at the end of the chain
|
||||
|
@@ -25,7 +25,15 @@ def email_from_certificate(cert_file):
|
||||
return email[0]
|
||||
|
||||
else:
|
||||
raise ValueError("No email available for certificate with serial {}".format(cert.serial_number))
|
||||
raise ValueError(
|
||||
"No email available for certificate with serial {}".format(
|
||||
cert.serial_number
|
||||
)
|
||||
)
|
||||
|
||||
except x509.extensions.ExtensionNotFound:
|
||||
raise ValueError("No subjectAltName available for certificate with serial {}".format(cert.serial_number))
|
||||
raise ValueError(
|
||||
"No subjectAltName available for certificate with serial {}".format(
|
||||
cert.serial_number
|
||||
)
|
||||
)
|
||||
|
@@ -6,7 +6,6 @@ from .exceptions import NotFoundError
|
||||
|
||||
|
||||
class PENumbers(object):
|
||||
|
||||
@classmethod
|
||||
def get(cls, number):
|
||||
pe_number = db.session.query(PENumber).get(number)
|
||||
|
@@ -73,9 +73,10 @@ class Requests(object):
|
||||
filters.append(Request.creator == creator)
|
||||
|
||||
requests = (
|
||||
db.session.query(Request).filter(*filters).order_by(
|
||||
Request.time_created.desc()
|
||||
).all()
|
||||
db.session.query(Request)
|
||||
.filter(*filters)
|
||||
.order_by(Request.time_created.desc())
|
||||
.all()
|
||||
)
|
||||
return requests
|
||||
|
||||
@@ -113,9 +114,10 @@ class Requests(object):
|
||||
# Query for request matching id, acquiring a row-level write lock.
|
||||
# https://www.postgresql.org/docs/10/static/sql-select.html#SQL-FOR-UPDATE-SHARE
|
||||
return (
|
||||
db.session.query(Request).filter_by(id=request_id).with_for_update(
|
||||
of=Request
|
||||
).one()
|
||||
db.session.query(Request)
|
||||
.filter_by(id=request_id)
|
||||
.with_for_update(of=Request)
|
||||
.one()
|
||||
)
|
||||
|
||||
except NoResultFound:
|
||||
@@ -153,9 +155,7 @@ class Requests(object):
|
||||
RequestStatus.STARTED: "mission_owner",
|
||||
RequestStatus.PENDING_FINANCIAL_VERIFICATION: "mission_owner",
|
||||
RequestStatus.PENDING_CCPO_APPROVAL: "ccpo",
|
||||
}.get(
|
||||
request.status
|
||||
)
|
||||
}.get(request.status)
|
||||
|
||||
@classmethod
|
||||
def should_auto_approve(cls, request):
|
||||
@@ -167,13 +167,16 @@ class Requests(object):
|
||||
return dollar_value < cls.AUTO_APPROVE_THRESHOLD
|
||||
|
||||
_VALID_SUBMISSION_STATUSES = [
|
||||
RequestStatus.STARTED, RequestStatus.CHANGES_REQUESTED
|
||||
RequestStatus.STARTED,
|
||||
RequestStatus.CHANGES_REQUESTED,
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def should_allow_submission(cls, request):
|
||||
all_request_sections = [
|
||||
"details_of_use", "information_about_you", "primary_poc"
|
||||
"details_of_use",
|
||||
"information_about_you",
|
||||
"primary_poc",
|
||||
]
|
||||
existing_request_sections = request.body.keys()
|
||||
return request.status in Requests._VALID_SUBMISSION_STATUSES and all(
|
||||
|
@@ -6,7 +6,6 @@ from .exceptions import NotFoundError
|
||||
|
||||
|
||||
class Roles(object):
|
||||
|
||||
@classmethod
|
||||
def get(cls, role_name):
|
||||
try:
|
||||
|
@@ -9,7 +9,6 @@ from .exceptions import NotFoundError, AlreadyExistsError
|
||||
|
||||
|
||||
class Users(object):
|
||||
|
||||
@classmethod
|
||||
def get(cls, user_id):
|
||||
try:
|
||||
|
@@ -11,7 +11,6 @@ from .exceptions import NotFoundError
|
||||
|
||||
|
||||
class WorkspaceUsers(object):
|
||||
|
||||
@classmethod
|
||||
def get(cls, workspace_id, user_id):
|
||||
try:
|
||||
|
@@ -64,8 +64,6 @@ class Workspaces(object):
|
||||
@classmethod
|
||||
def _create_workspace_role(cls, user, workspace, role_name):
|
||||
role = Roles.get(role_name)
|
||||
workspace_role = WorkspaceRole(
|
||||
user=user, role=role, workspace=workspace
|
||||
)
|
||||
workspace_role = WorkspaceRole(user=user, role=role, workspace=workspace)
|
||||
db.session.add(workspace_role)
|
||||
return workspace_role
|
||||
|
@@ -1,7 +1,8 @@
|
||||
import re
|
||||
|
||||
|
||||
def iconSvg(name):
|
||||
with open('static/icons/'+name+'.svg') as contents:
|
||||
with open("static/icons/" + name + ".svg") as contents:
|
||||
return contents.read()
|
||||
|
||||
|
||||
@@ -14,8 +15,8 @@ def dollars(value):
|
||||
|
||||
|
||||
def usPhone(number):
|
||||
phone = re.sub(r'\D', '', number)
|
||||
return '+1 ({}) {} - {}'.format(phone[0:3], phone[3:6], phone[6:])
|
||||
phone = re.sub(r"\D", "", number)
|
||||
return "+1 ({}) {} - {}".format(phone[0:3], phone[3:6], phone[6:])
|
||||
|
||||
|
||||
def readableInteger(value):
|
||||
@@ -31,9 +32,8 @@ def getOptionLabel(value, options):
|
||||
|
||||
|
||||
def register_filters(app):
|
||||
app.jinja_env.filters['iconSvg'] = iconSvg
|
||||
app.jinja_env.filters['dollars'] = dollars
|
||||
app.jinja_env.filters['usPhone'] = usPhone
|
||||
app.jinja_env.filters['readableInteger'] = readableInteger
|
||||
app.jinja_env.filters['getOptionLabel'] = getOptionLabel
|
||||
|
||||
app.jinja_env.filters["iconSvg"] = iconSvg
|
||||
app.jinja_env.filters["dollars"] = dollars
|
||||
app.jinja_env.filters["usPhone"] = usPhone
|
||||
app.jinja_env.filters["readableInteger"] = readableInteger
|
||||
app.jinja_env.filters["getOptionLabel"] = getOptionLabel
|
||||
|
@@ -3,7 +3,10 @@ SERVICE_BRANCHES = [
|
||||
("Air Force, Department of the", "Air Force, Department of the"),
|
||||
("Army and Air Force Exchange Service", "Army and Air Force Exchange Service"),
|
||||
("Army, Department of the", "Army, Department of the"),
|
||||
("Defense Advanced Research Projects Agency", "Defense Advanced Research Projects Agency"),
|
||||
(
|
||||
"Defense Advanced Research Projects Agency",
|
||||
"Defense Advanced Research Projects Agency",
|
||||
),
|
||||
("Defense Commissary Agency", "Defense Commissary Agency"),
|
||||
("Defense Contract Audit Agency", "Defense Contract Audit Agency"),
|
||||
("Defense Contract Management Agency", "Defense Contract Management Agency"),
|
||||
@@ -19,31 +22,55 @@ SERVICE_BRANCHES = [
|
||||
("Defense Security Cooperation Agency", "Defense Security Cooperation Agency"),
|
||||
("Defense Security Service", "Defense Security Service"),
|
||||
("Defense Technical Information Center", "Defense Technical Information Center"),
|
||||
("Defense Technology Security Administration", "Defense Technology Security Administration"),
|
||||
(
|
||||
"Defense Technology Security Administration",
|
||||
"Defense Technology Security Administration",
|
||||
),
|
||||
("Defense Threat Reduction Agency", "Defense Threat Reduction Agency"),
|
||||
("DoD Education Activity", "DoD Education Activity"),
|
||||
("DoD Human Recourses Activity", "DoD Human Recourses Activity"),
|
||||
("DoD Inspector General", "DoD Inspector General"),
|
||||
("DoD Test Resource Management Center", "DoD Test Resource Management Center"),
|
||||
("Headquarters Defense Human Resource Activity ", "Headquarters Defense Human Resource Activity "),
|
||||
(
|
||||
"Headquarters Defense Human Resource Activity ",
|
||||
"Headquarters Defense Human Resource Activity ",
|
||||
),
|
||||
("Joint Staff", "Joint Staff"),
|
||||
("Missile Defense Agency", "Missile Defense Agency"),
|
||||
("National Defense University", "National Defense University"),
|
||||
("National Geospatial Intelligence Agency (NGA)", "National Geospatial Intelligence Agency (NGA)"),
|
||||
("National Oceanic and Atmospheric Administration (NOAA)", "National Oceanic and Atmospheric Administration (NOAA)"),
|
||||
(
|
||||
"National Geospatial Intelligence Agency (NGA)",
|
||||
"National Geospatial Intelligence Agency (NGA)",
|
||||
),
|
||||
(
|
||||
"National Oceanic and Atmospheric Administration (NOAA)",
|
||||
"National Oceanic and Atmospheric Administration (NOAA)",
|
||||
),
|
||||
("National Reconnaissance Office", "National Reconnaissance Office"),
|
||||
("National Reconnaissance Office (NRO)", "National Reconnaissance Office (NRO)"),
|
||||
("National Security Agency (NSA)", "National Security Agency (NSA)"),
|
||||
("National Security Agency-Central Security Service", "National Security Agency-Central Security Service"),
|
||||
(
|
||||
"National Security Agency-Central Security Service",
|
||||
"National Security Agency-Central Security Service",
|
||||
),
|
||||
("Navy, Department of the", "Navy, Department of the"),
|
||||
("Office of Economic Adjustment", "Office of Economic Adjustment"),
|
||||
("Office of the Secretary of Defense", "Office of the Secretary of Defense"),
|
||||
("Pentagon Force Protection Agency", "Pentagon Force Protection Agency"),
|
||||
("Uniform Services University of the Health Sciences", "Uniform Services University of the Health Sciences"),
|
||||
(
|
||||
"Uniform Services University of the Health Sciences",
|
||||
"Uniform Services University of the Health Sciences",
|
||||
),
|
||||
("US Cyber Command (USCYBERCOM)", "US Cyber Command (USCYBERCOM)"),
|
||||
("US Special Operations Command (USSOCOM)", "US Special Operations Command (USSOCOM)"),
|
||||
(
|
||||
"US Special Operations Command (USSOCOM)",
|
||||
"US Special Operations Command (USSOCOM)",
|
||||
),
|
||||
("US Strategic Command (USSTRATCOM)", "US Strategic Command (USSTRATCOM)"),
|
||||
("US Transportation Command (USTRANSCOM)", "US Transportation Command (USTRANSCOM)"),
|
||||
(
|
||||
"US Transportation Command (USTRANSCOM)",
|
||||
"US Transportation Command (USTRANSCOM)",
|
||||
),
|
||||
("Washington Headquarters Services", "Washington Headquarters Services"),
|
||||
]
|
||||
|
||||
|
@@ -24,7 +24,7 @@ class NewlineListField(Field):
|
||||
|
||||
def _value(self):
|
||||
if isinstance(self.data, list):
|
||||
return '\n'.join(self.data)
|
||||
return "\n".join(self.data)
|
||||
elif self.data:
|
||||
return self.data
|
||||
else:
|
||||
@@ -46,8 +46,5 @@ class NewlineListField(Field):
|
||||
class SelectField(SelectField_):
|
||||
def __init__(self, *args, **kwargs):
|
||||
render_kw = kwargs.get("render_kw", {})
|
||||
kwargs["render_kw"] = {
|
||||
**render_kw,
|
||||
"required": False
|
||||
}
|
||||
kwargs["render_kw"] = {**render_kw, "required": False}
|
||||
super().__init__(*args, **kwargs)
|
||||
|
@@ -26,6 +26,7 @@ TREASURY_CODE_REGEX = re.compile(r"^0*([1-9]{4}|[1-9]{6})$")
|
||||
|
||||
BA_CODE_REGEX = re.compile(r"^0*[1-9]{2}\w?$")
|
||||
|
||||
|
||||
def suggest_pe_id(pe_id):
|
||||
suggestion = pe_id
|
||||
match = PE_REGEX.match(pe_id)
|
||||
@@ -94,19 +95,26 @@ class BaseFinancialForm(ValidatedForm):
|
||||
task_order_number = StringField(
|
||||
"Task Order Number associated with this request",
|
||||
description="Include the original Task Order number (including the 000X at the end). Do not include any modification numbers. Note that there may be a lag between approving a task order and when it becomes available in our system.",
|
||||
validators=[Required()]
|
||||
validators=[Required()],
|
||||
)
|
||||
|
||||
uii_ids = NewlineListField(
|
||||
"Unique Item Identifier (UII)s related to your application(s) if you already have them",
|
||||
validators=[Required()]
|
||||
validators=[Required()],
|
||||
)
|
||||
|
||||
pe_id = StringField("Program Element (PE) Number related to your request", validators=[Required()])
|
||||
pe_id = StringField(
|
||||
"Program Element (PE) Number related to your request", validators=[Required()]
|
||||
)
|
||||
|
||||
treasury_code = StringField("Program Treasury Code", validators=[Required(), Regexp(TREASURY_CODE_REGEX)])
|
||||
treasury_code = StringField(
|
||||
"Program Treasury Code", validators=[Required(), Regexp(TREASURY_CODE_REGEX)]
|
||||
)
|
||||
|
||||
ba_code = StringField("Program Budget Activity (BA) Code", validators=[Required(), Regexp(BA_CODE_REGEX)])
|
||||
ba_code = StringField(
|
||||
"Program Budget Activity (BA) Code",
|
||||
validators=[Required(), Regexp(BA_CODE_REGEX)],
|
||||
)
|
||||
|
||||
fname_co = StringField("Contracting Officer First Name", validators=[Required()])
|
||||
lname_co = StringField("Contracting Officer Last Name", validators=[Required()])
|
||||
@@ -160,7 +168,7 @@ class ExtendedFinancialForm(BaseFinancialForm):
|
||||
("OTHER", "Other"),
|
||||
],
|
||||
validators=[Required()],
|
||||
render_kw={"required": False}
|
||||
render_kw={"required": False},
|
||||
)
|
||||
|
||||
funding_type_other = StringField("If other, please specify")
|
||||
@@ -169,40 +177,40 @@ class ExtendedFinancialForm(BaseFinancialForm):
|
||||
"<dl><dt>CLIN 0001</dt> - <dd>Unclassified IaaS and PaaS Amount</dd></dl>",
|
||||
validators=[Required()],
|
||||
description="Review your task order document, the amounts for each CLIN must match exactly here",
|
||||
filters=[number_to_int]
|
||||
filters=[number_to_int],
|
||||
)
|
||||
|
||||
clin_0003 = StringField(
|
||||
"<dl><dt>CLIN 0003</dt> - <dd>Unclassified Cloud Support Package</dd></dl>",
|
||||
validators=[Required()],
|
||||
description="Review your task order document, the amounts for each CLIN must match exactly here",
|
||||
filters=[number_to_int]
|
||||
filters=[number_to_int],
|
||||
)
|
||||
|
||||
clin_1001 = StringField(
|
||||
"<dl><dt>CLIN 1001</dt> - <dd>Unclassified IaaS and PaaS Amount <br> OPTION PERIOD 1</dd></dl>",
|
||||
validators=[Required()],
|
||||
description="Review your task order document, the amounts for each CLIN must match exactly here",
|
||||
filters=[number_to_int]
|
||||
filters=[number_to_int],
|
||||
)
|
||||
|
||||
clin_1003 = StringField(
|
||||
"<dl><dt>CLIN 1003</dt> - <dd>Unclassified Cloud Support Package <br> OPTION PERIOD 1</dd></dl>",
|
||||
validators=[Required()],
|
||||
description="Review your task order document, the amounts for each CLIN must match exactly here",
|
||||
filters=[number_to_int]
|
||||
filters=[number_to_int],
|
||||
)
|
||||
|
||||
clin_2001 = StringField(
|
||||
"<dl><dt>CLIN 2001</dt> - <dd>Unclassified IaaS and PaaS Amount <br> OPTION PERIOD 2</dd></dl>",
|
||||
validators=[Required()],
|
||||
description="Review your task order document, the amounts for each CLIN must match exactly here",
|
||||
filters=[number_to_int]
|
||||
filters=[number_to_int],
|
||||
)
|
||||
|
||||
clin_2003 = StringField(
|
||||
"<dl><dt>CLIN 2003</dt> - <dd>Unclassified Cloud Support Package <br> OPTION PERIOD 2</dd></dl>",
|
||||
validators=[Required()],
|
||||
description="Review your task order document, the amounts for each CLIN must match exactly here",
|
||||
filters=[number_to_int]
|
||||
filters=[number_to_int],
|
||||
)
|
||||
|
@@ -16,9 +16,11 @@ class OrgForm(ValidatedForm):
|
||||
|
||||
email_request = EmailField("E-mail Address", validators=[Required(), Email()])
|
||||
|
||||
phone_number = TelField("Phone Number",
|
||||
description='Enter a 10-digit phone number',
|
||||
validators=[Required(), PhoneNumber()])
|
||||
phone_number = TelField(
|
||||
"Phone Number",
|
||||
description="Enter a 10-digit phone number",
|
||||
validators=[Required(), PhoneNumber()],
|
||||
)
|
||||
|
||||
service_branch = SelectField(
|
||||
"Service Branch or Agency",
|
||||
@@ -49,7 +51,7 @@ class OrgForm(ValidatedForm):
|
||||
|
||||
date_latest_training = DateField(
|
||||
"Latest Information Assurance (IA) Training Completion Date",
|
||||
description="To complete the training, you can find it in <a class=\"icon-link\" href=\"https://iatraining.disa.mil/eta/disa_cac2018/launchPage.htm\" target=\"_blank\">Information Assurance Cyber Awareness Challange</a> website.",
|
||||
description='To complete the training, you can find it in <a class="icon-link" href="https://iatraining.disa.mil/eta/disa_cac2018/launchPage.htm" target="_blank">Information Assurance Cyber Awareness Challange</a> website.',
|
||||
validators=[
|
||||
Required(),
|
||||
DateRange(
|
||||
|
@@ -6,7 +6,6 @@ from .validators import IsNumber
|
||||
|
||||
|
||||
class POCForm(ValidatedForm):
|
||||
|
||||
def validate(self, *args, **kwargs):
|
||||
if self.am_poc.data:
|
||||
# Prepend Optional validators so that the validation chain
|
||||
@@ -18,11 +17,10 @@ class POCForm(ValidatedForm):
|
||||
|
||||
return super().validate(*args, **kwargs)
|
||||
|
||||
|
||||
am_poc = BooleanField(
|
||||
"I am the Workspace Owner",
|
||||
default=False,
|
||||
false_values=(False, "false", "False", "no", "")
|
||||
false_values=(False, "false", "False", "no", ""),
|
||||
)
|
||||
|
||||
fname_poc = StringField("First Name", validators=[Required()])
|
||||
|
@@ -4,22 +4,26 @@ from wtforms.validators import Optional, Required
|
||||
|
||||
from .fields import DateField, SelectField
|
||||
from .forms import ValidatedForm
|
||||
from .data import SERVICE_BRANCHES, ASSISTANCE_ORG_TYPES, DATA_TRANSFER_AMOUNTS, COMPLETION_DATE_RANGES
|
||||
from .data import (
|
||||
SERVICE_BRANCHES,
|
||||
ASSISTANCE_ORG_TYPES,
|
||||
DATA_TRANSFER_AMOUNTS,
|
||||
COMPLETION_DATE_RANGES,
|
||||
)
|
||||
from atst.domain.requests import Requests
|
||||
|
||||
|
||||
class RequestForm(ValidatedForm):
|
||||
|
||||
def validate(self, *args, **kwargs):
|
||||
if self.jedi_migration.data == 'no':
|
||||
if self.jedi_migration.data == "no":
|
||||
self.rationalization_software_systems.validators.append(Optional())
|
||||
self.technical_support_team.validators.append(Optional())
|
||||
self.organization_providing_assistance.validators.append(Optional())
|
||||
self.engineering_assessment.validators.append(Optional())
|
||||
self.data_transfers.validators.append(Optional())
|
||||
self.expected_completion_date.validators.append(Optional())
|
||||
elif self.jedi_migration.data == 'yes':
|
||||
if self.technical_support_team.data == 'no':
|
||||
elif self.jedi_migration.data == "yes":
|
||||
if self.technical_support_team.data == "no":
|
||||
self.organization_providing_assistance.validators.append(Optional())
|
||||
self.cloud_native.validators.append(Optional())
|
||||
|
||||
@@ -39,16 +43,15 @@ class RequestForm(ValidatedForm):
|
||||
"DoD Component",
|
||||
description="Identify the DoD component that is requesting access to the JEDI Cloud",
|
||||
choices=SERVICE_BRANCHES,
|
||||
validators=[Required()]
|
||||
validators=[Required()],
|
||||
)
|
||||
|
||||
jedi_usage = TextAreaField(
|
||||
"JEDI Usage",
|
||||
description="Your answer will help us provide tangible examples to DoD leadership how and why commercial cloud resources are accelerating the Department's missions",
|
||||
validators=[Required()]
|
||||
validators=[Required()],
|
||||
)
|
||||
|
||||
|
||||
# Details of Use: Cloud Readiness
|
||||
num_software_systems = IntegerField(
|
||||
"Number of Software Systems",
|
||||
@@ -121,16 +124,15 @@ class RequestForm(ValidatedForm):
|
||||
|
||||
average_daily_traffic = IntegerField(
|
||||
"Average Daily Traffic (Number of Requests)",
|
||||
description="What is the average daily traffic you expect the systems under this cloud contract to use?"
|
||||
description="What is the average daily traffic you expect the systems under this cloud contract to use?",
|
||||
)
|
||||
|
||||
average_daily_traffic_gb = IntegerField(
|
||||
"Average Daily Traffic (GB)",
|
||||
description="What is the average daily traffic you expect the systems under this cloud contract to use?"
|
||||
description="What is the average daily traffic you expect the systems under this cloud contract to use?",
|
||||
)
|
||||
|
||||
start_date = DateField(
|
||||
description="When do you expect to start using the JEDI Cloud (not for billing purposes)?",
|
||||
validators=[
|
||||
Required()]
|
||||
validators=[Required()],
|
||||
)
|
||||
|
@@ -60,5 +60,3 @@ def ListItemRequired(message="Please provide at least one.", empty_values=("", N
|
||||
raise ValidationError(message)
|
||||
|
||||
return _list_item_required
|
||||
|
||||
|
||||
|
@@ -2,6 +2,12 @@ from sqlalchemy import Column, func, TIMESTAMP
|
||||
|
||||
|
||||
class TimestampsMixin(object):
|
||||
time_created = Column(TIMESTAMP(timezone=True), nullable=False, server_default=func.now())
|
||||
time_updated = Column(TIMESTAMP(timezone=True), nullable=False, server_default=func.now(), onupdate=func.current_timestamp())
|
||||
|
||||
time_created = Column(
|
||||
TIMESTAMP(timezone=True), nullable=False, server_default=func.now()
|
||||
)
|
||||
time_updated = Column(
|
||||
TIMESTAMP(timezone=True),
|
||||
nullable=False,
|
||||
server_default=func.now(),
|
||||
onupdate=func.current_timestamp(),
|
||||
)
|
||||
|
@@ -4,6 +4,7 @@ from sqlalchemy import Column, Integer, String, Enum as SQLAEnum
|
||||
|
||||
from atst.models import Base
|
||||
|
||||
|
||||
class Source(Enum):
|
||||
MANUAL = "Manual"
|
||||
EDA = "eda"
|
||||
|
@@ -25,21 +25,21 @@ def styleguide():
|
||||
return render_template("styleguide.html")
|
||||
|
||||
|
||||
@bp.route('/<path:path>')
|
||||
@bp.route("/<path:path>")
|
||||
def catch_all(path):
|
||||
return render_template("{}.html".format(path))
|
||||
|
||||
|
||||
def _make_authentication_context():
|
||||
return AuthenticationContext(
|
||||
crl_cache=app.crl_cache,
|
||||
auth_status=request.environ.get("HTTP_X_SSL_CLIENT_VERIFY"),
|
||||
sdn=request.environ.get("HTTP_X_SSL_CLIENT_S_DN"),
|
||||
cert=request.environ.get("HTTP_X_SSL_CLIENT_CERT")
|
||||
crl_cache=app.crl_cache,
|
||||
auth_status=request.environ.get("HTTP_X_SSL_CLIENT_VERIFY"),
|
||||
sdn=request.environ.get("HTTP_X_SSL_CLIENT_S_DN"),
|
||||
cert=request.environ.get("HTTP_X_SSL_CLIENT_CERT"),
|
||||
)
|
||||
|
||||
|
||||
@bp.route('/login-redirect')
|
||||
@bp.route("/login-redirect")
|
||||
def login_redirect():
|
||||
auth_context = _make_authentication_context()
|
||||
auth_context.authenticate()
|
||||
@@ -53,7 +53,7 @@ def login_redirect():
|
||||
|
||||
|
||||
def _is_valid_certificate(request):
|
||||
cert = request.environ.get('HTTP_X_SSL_CLIENT_CERT')
|
||||
cert = request.environ.get("HTTP_X_SSL_CLIENT_CERT")
|
||||
if cert:
|
||||
result = app.crl_validator.validate(cert.encode())
|
||||
return result
|
||||
|
@@ -10,45 +10,46 @@ _DEV_USERS = {
|
||||
"first_name": "Sam",
|
||||
"last_name": "Seeceepio",
|
||||
"atat_role_name": "ccpo",
|
||||
"email": "sam@test.com"
|
||||
"email": "sam@test.com",
|
||||
},
|
||||
"amanda": {
|
||||
"dod_id": "2345678901",
|
||||
"first_name": "Amanda",
|
||||
"last_name": "Adamson",
|
||||
"atat_role_name": "default",
|
||||
"email": "amanda@test.com"
|
||||
"email": "amanda@test.com",
|
||||
},
|
||||
"brandon": {
|
||||
"dod_id": "3456789012",
|
||||
"first_name": "Brandon",
|
||||
"last_name": "Buchannan",
|
||||
"atat_role_name": "default",
|
||||
"email": "brandon@test.com"
|
||||
"email": "brandon@test.com",
|
||||
},
|
||||
"christina": {
|
||||
"dod_id": "4567890123",
|
||||
"first_name": "Christina",
|
||||
"last_name": "Collins",
|
||||
"atat_role_name": "default",
|
||||
"email": "christina@test.com"
|
||||
"email": "christina@test.com",
|
||||
},
|
||||
"dominick": {
|
||||
"dod_id": "5678901234",
|
||||
"first_name": "Dominick",
|
||||
"last_name": "Domingo",
|
||||
"atat_role_name": "default",
|
||||
"email": "dominick@test.com"
|
||||
"email": "dominick@test.com",
|
||||
},
|
||||
"erica": {
|
||||
"dod_id": "6789012345",
|
||||
"first_name": "Erica",
|
||||
"last_name": "Eichner",
|
||||
"atat_role_name": "default",
|
||||
"email": "erica@test.com"
|
||||
"email": "erica@test.com",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@bp.route("/login-dev")
|
||||
def login_dev():
|
||||
role = request.args.get("username", "amanda")
|
||||
@@ -58,7 +59,7 @@ def login_dev():
|
||||
atat_role_name=user_data["atat_role_name"],
|
||||
first_name=user_data["first_name"],
|
||||
last_name=user_data["last_name"],
|
||||
email=user_data["email"]
|
||||
email=user_data["email"],
|
||||
)
|
||||
session["user_id"] = user.id
|
||||
|
||||
|
@@ -11,11 +11,10 @@ def make_error_pages(app):
|
||||
app.logger.error(e.message)
|
||||
return render_template("not_found.html"), 404
|
||||
|
||||
|
||||
@app.errorhandler(exceptions.UnauthenticatedError)
|
||||
# pylint: disable=unused-variable
|
||||
def unauthorized(e):
|
||||
app.logger.error(e.message)
|
||||
return render_template('unauthenticated.html'), 401
|
||||
return render_template("unauthenticated.html"), 401
|
||||
|
||||
return app
|
||||
|
@@ -8,6 +8,7 @@ from . import index
|
||||
from . import requests_form
|
||||
from . import financial_verification
|
||||
|
||||
|
||||
@requests_bp.context_processor
|
||||
def annual_spend_threshold():
|
||||
return { "annual_spend_threshold": Requests.ANNUAL_SPEND_THRESHOLD }
|
||||
return {"annual_spend_threshold": Requests.ANNUAL_SPEND_THRESHOLD}
|
||||
|
@@ -43,7 +43,13 @@ def update_financial_verification(request_id):
|
||||
if valid:
|
||||
Requests.submit_financial_verification(request_id)
|
||||
new_workspace = Requests.approve_and_create_workspace(updated_request)
|
||||
return redirect(url_for("workspaces.workspace_projects", workspace_id=new_workspace.id, newWorkspace=True))
|
||||
return redirect(
|
||||
url_for(
|
||||
"workspaces.workspace_projects",
|
||||
workspace_id=new_workspace.id,
|
||||
newWorkspace=True,
|
||||
)
|
||||
)
|
||||
|
||||
else:
|
||||
form.reset()
|
||||
|
@@ -24,15 +24,18 @@ def map_request(request):
|
||||
"date": time_created.format("M/DD/YYYY"),
|
||||
"full_name": request.creator.full_name,
|
||||
"annual_usage": annual_usage,
|
||||
"edit_link": verify_url if Requests.is_pending_financial_verification(
|
||||
request
|
||||
) else update_url,
|
||||
"edit_link": verify_url
|
||||
if Requests.is_pending_financial_verification(request)
|
||||
else update_url,
|
||||
}
|
||||
|
||||
|
||||
@requests_bp.route("/requests", methods=["GET"])
|
||||
def requests_index():
|
||||
if Permissions.REVIEW_AND_APPROVE_JEDI_WORKSPACE_REQUEST in g.current_user.atat_permissions:
|
||||
if (
|
||||
Permissions.REVIEW_AND_APPROVE_JEDI_WORKSPACE_REQUEST
|
||||
in g.current_user.atat_permissions
|
||||
):
|
||||
return _ccpo_view()
|
||||
|
||||
else:
|
||||
|
@@ -129,7 +129,9 @@ class JEDIRequestFlow(object):
|
||||
if section == "primary_poc":
|
||||
if data.get("am_poc", False):
|
||||
try:
|
||||
request_user_info = self.existing_request.body.get("information_about_you", {})
|
||||
request_user_info = self.existing_request.body.get(
|
||||
"information_about_you", {}
|
||||
)
|
||||
except AttributeError:
|
||||
request_user_info = {}
|
||||
|
||||
|
@@ -6,7 +6,12 @@ from atst.routes.requests.jedi_request_flow import JEDIRequestFlow
|
||||
from atst.models.permissions import Permissions
|
||||
from atst.models.request_status_event import RequestStatus
|
||||
from atst.domain.exceptions import UnauthorizedError
|
||||
from atst.forms.data import SERVICE_BRANCHES, ASSISTANCE_ORG_TYPES, DATA_TRANSFER_AMOUNTS, COMPLETION_DATE_RANGES
|
||||
from atst.forms.data import (
|
||||
SERVICE_BRANCHES,
|
||||
ASSISTANCE_ORG_TYPES,
|
||||
DATA_TRANSFER_AMOUNTS,
|
||||
COMPLETION_DATE_RANGES,
|
||||
)
|
||||
|
||||
|
||||
@requests_bp.route("/requests/new/<int:screen>", methods=["GET"])
|
||||
@@ -27,6 +32,7 @@ def requests_form_new(screen):
|
||||
completion_date_ranges=COMPLETION_DATE_RANGES,
|
||||
)
|
||||
|
||||
|
||||
@requests_bp.route(
|
||||
"/requests/new/<int:screen>", methods=["GET"], defaults={"request_id": None}
|
||||
)
|
||||
@@ -36,7 +42,9 @@ def requests_form_update(screen=1, request_id=None):
|
||||
_check_can_view_request(request_id)
|
||||
|
||||
request = Requests.get(request_id) if request_id is not None else None
|
||||
jedi_flow = JEDIRequestFlow(screen, request=request, request_id=request_id, current_user=g.current_user)
|
||||
jedi_flow = JEDIRequestFlow(
|
||||
screen, request=request, request_id=request_id, current_user=g.current_user
|
||||
)
|
||||
|
||||
return render_template(
|
||||
"requests/screen-%d.html" % int(screen),
|
||||
@@ -114,10 +122,12 @@ def requests_submit(request_id=None):
|
||||
# TODO: generalize this, along with other authorizations, into a policy-pattern
|
||||
# for authorization in the application
|
||||
def _check_can_view_request(request_id):
|
||||
if Permissions.REVIEW_AND_APPROVE_JEDI_WORKSPACE_REQUEST in g.current_user.atat_permissions:
|
||||
if (
|
||||
Permissions.REVIEW_AND_APPROVE_JEDI_WORKSPACE_REQUEST
|
||||
in g.current_user.atat_permissions
|
||||
):
|
||||
pass
|
||||
elif Requests.exists(request_id, g.current_user):
|
||||
pass
|
||||
else:
|
||||
raise UnauthorizedError(g.current_user, "view request {}".format(request_id))
|
||||
|
||||
|
Reference in New Issue
Block a user