Merge branch 'master' into ui/tooltips
This commit is contained in:
commit
b4b7d0cbcb
@ -1,10 +1,13 @@
|
|||||||
import requests
|
import requests
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
import pendulum
|
||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
|
|
||||||
_DISA_CRLS = "https://iasecontent.disa.mil/pki-pke/data/crls/dod_crldps.htm"
|
_DISA_CRLS = "https://iasecontent.disa.mil/pki-pke/data/crls/dod_crldps.htm"
|
||||||
|
|
||||||
|
MODIFIED_TIME_BUFFER = 15 * 60
|
||||||
|
|
||||||
|
|
||||||
def fetch_disa():
|
def fetch_disa():
|
||||||
response = requests.get(_DISA_CRLS)
|
response = requests.get(_DISA_CRLS)
|
||||||
@ -29,29 +32,67 @@ def crl_list_from_disa_html(html):
|
|||||||
return parser.crl_list
|
return parser.crl_list
|
||||||
|
|
||||||
|
|
||||||
def write_crl(out_dir, crl_location):
|
def crl_local_path(out_dir, crl_location):
|
||||||
name = re.split("/", crl_location)[-1]
|
name = re.split("/", crl_location)[-1]
|
||||||
crl = os.path.join(out_dir, name)
|
crl = os.path.join(out_dir, name)
|
||||||
with requests.get(crl_location, stream=True) as r:
|
return crl
|
||||||
|
|
||||||
|
|
||||||
|
def existing_crl_modification_time(crl):
|
||||||
|
if os.path.exists(crl):
|
||||||
|
prev_time = os.path.getmtime(crl)
|
||||||
|
buffered = prev_time + MODIFIED_TIME_BUFFER
|
||||||
|
mod_time = prev_time if pendulum.now().timestamp() < buffered else buffered
|
||||||
|
dt = pendulum.from_timestamp(mod_time, tz="GMT")
|
||||||
|
return dt.format("ddd, DD MMM YYYY HH:mm:ss zz")
|
||||||
|
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def write_crl(out_dir, target_dir, crl_location):
|
||||||
|
crl = crl_local_path(out_dir, crl_location)
|
||||||
|
existing = crl_local_path(target_dir, crl_location)
|
||||||
|
options = {"stream": True}
|
||||||
|
mod_time = existing_crl_modification_time(existing)
|
||||||
|
if mod_time:
|
||||||
|
options["headers"] = {"If-Modified-Since": mod_time}
|
||||||
|
|
||||||
|
with requests.get(crl_location, **options) as response:
|
||||||
|
if response.status_code == 304:
|
||||||
|
return False
|
||||||
|
|
||||||
with open(crl, "wb") as crl_file:
|
with open(crl, "wb") as crl_file:
|
||||||
for chunk in r.iter_content(chunk_size=1024):
|
for chunk in response.iter_content(chunk_size=1024):
|
||||||
if chunk:
|
if chunk:
|
||||||
crl_file.write(chunk)
|
crl_file.write(chunk)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def refresh_crls(out_dir, logger=None):
|
|
||||||
|
def remove_bad_crl(out_dir, crl_location):
|
||||||
|
crl = crl_local_path(out_dir, crl_location)
|
||||||
|
os.remove(crl)
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_crls(out_dir, target_dir, logger):
|
||||||
disa_html = fetch_disa()
|
disa_html = fetch_disa()
|
||||||
crl_list = crl_list_from_disa_html(disa_html)
|
crl_list = crl_list_from_disa_html(disa_html)
|
||||||
for crl_location in crl_list:
|
for crl_location in crl_list:
|
||||||
if logger:
|
|
||||||
logger.info("updating CRL from {}".format(crl_location))
|
logger.info("updating CRL from {}".format(crl_location))
|
||||||
try:
|
try:
|
||||||
write_crl(out_dir, crl_location)
|
if write_crl(out_dir, target_dir, crl_location):
|
||||||
|
logger.info("successfully synced CRL from {}".format(crl_location))
|
||||||
|
else:
|
||||||
|
logger.info("no updates for CRL from {}".format(crl_location))
|
||||||
except requests.exceptions.ChunkedEncodingError:
|
except requests.exceptions.ChunkedEncodingError:
|
||||||
if logger:
|
if logger:
|
||||||
logger.error(
|
logger.error(
|
||||||
"Error downloading {}, continuing anyway".format(crl_location)
|
"Error downloading {}, removing file and continuing anyway".format(
|
||||||
|
crl_location
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
remove_bad_crl(out_dir, crl_location)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@ -64,7 +105,7 @@ if __name__ == "__main__":
|
|||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
logger.info("Updating CRLs")
|
logger.info("Updating CRLs")
|
||||||
try:
|
try:
|
||||||
refresh_crls(sys.argv[1], logger=logger)
|
refresh_crls(sys.argv[1], sys.argv[2], logger)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.exception("Fatal error encountered, stopping")
|
logger.exception("Fatal error encountered, stopping")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
@ -1,11 +1,38 @@
|
|||||||
from wtforms.fields.html5 import IntegerField
|
from wtforms.fields.html5 import IntegerField
|
||||||
from wtforms.fields import RadioField, TextAreaField, SelectField
|
from wtforms.fields import RadioField, TextAreaField, SelectField
|
||||||
|
from wtforms.validators import Optional, Required
|
||||||
|
|
||||||
from .fields import DateField
|
from .fields import DateField
|
||||||
from .forms import ValidatedForm
|
from .forms import ValidatedForm
|
||||||
|
from atst.domain.requests import Requests
|
||||||
|
|
||||||
|
|
||||||
class RequestForm(ValidatedForm):
|
class RequestForm(ValidatedForm):
|
||||||
|
|
||||||
|
def validate(self, *args, **kwargs):
|
||||||
|
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':
|
||||||
|
self.organization_providing_assistance.validators.append(Optional())
|
||||||
|
self.cloud_native.validators.append(Optional())
|
||||||
|
|
||||||
|
try:
|
||||||
|
annual_spend = int(self.estimated_monthly_spend.data or 0) * 12
|
||||||
|
except ValueError:
|
||||||
|
annual_spend = 0
|
||||||
|
|
||||||
|
if annual_spend > Requests.AUTO_APPROVE_THRESHOLD:
|
||||||
|
self.number_user_sessions.validators.append(Required())
|
||||||
|
self.average_daily_traffic.validators.append(Required())
|
||||||
|
|
||||||
|
return super(RequestForm, self).validate(*args, **kwargs)
|
||||||
|
|
||||||
# Details of Use: General
|
# Details of Use: General
|
||||||
dod_component = SelectField(
|
dod_component = SelectField(
|
||||||
"DoD Component",
|
"DoD Component",
|
||||||
@ -36,16 +63,19 @@ class RequestForm(ValidatedForm):
|
|||||||
"JEDI Migration",
|
"JEDI Migration",
|
||||||
description="Are you using the JEDI Cloud to migrate existing systems?",
|
description="Are you using the JEDI Cloud to migrate existing systems?",
|
||||||
choices=[("yes", "Yes"), ("no", "No")],
|
choices=[("yes", "Yes"), ("no", "No")],
|
||||||
|
default="",
|
||||||
)
|
)
|
||||||
|
|
||||||
rationalization_software_systems = RadioField(
|
rationalization_software_systems = RadioField(
|
||||||
description="Have you completed a “rationalization” of your software systems to move to the cloud?",
|
description="Have you completed a “rationalization” of your software systems to move to the cloud?",
|
||||||
choices=[("yes", "Yes"), ("no", "No"), ("in_progress", "In Progress")],
|
choices=[("yes", "Yes"), ("no", "No"), ("in_progress", "In Progress")],
|
||||||
|
default="",
|
||||||
)
|
)
|
||||||
|
|
||||||
technical_support_team = RadioField(
|
technical_support_team = RadioField(
|
||||||
description="Are you working with a technical support team experienced in cloud migrations?",
|
description="Are you working with a technical support team experienced in cloud migrations?",
|
||||||
choices=[("yes", "Yes"), ("no", "No")],
|
choices=[("yes", "Yes"), ("no", "No")],
|
||||||
|
default="",
|
||||||
)
|
)
|
||||||
|
|
||||||
organization_providing_assistance = RadioField( # this needs to be updated to use checkboxes instead of radio
|
organization_providing_assistance = RadioField( # this needs to be updated to use checkboxes instead of radio
|
||||||
@ -56,11 +86,13 @@ class RequestForm(ValidatedForm):
|
|||||||
("other_dod_organization", "Other DoD organization"),
|
("other_dod_organization", "Other DoD organization"),
|
||||||
("none", "None"),
|
("none", "None"),
|
||||||
],
|
],
|
||||||
|
default="",
|
||||||
)
|
)
|
||||||
|
|
||||||
engineering_assessment = RadioField(
|
engineering_assessment = RadioField(
|
||||||
description="Have you completed an engineering assessment of your systems for cloud readiness?",
|
description="Have you completed an engineering assessment of your systems for cloud readiness?",
|
||||||
choices=[("yes", "Yes"), ("no", "No"), ("in_progress", "In Progress")],
|
choices=[("yes", "Yes"), ("no", "No"), ("in_progress", "In Progress")],
|
||||||
|
default="",
|
||||||
)
|
)
|
||||||
|
|
||||||
data_transfers = SelectField(
|
data_transfers = SelectField(
|
||||||
@ -94,6 +126,7 @@ class RequestForm(ValidatedForm):
|
|||||||
cloud_native = RadioField(
|
cloud_native = RadioField(
|
||||||
description="Are your software systems being developed cloud native?",
|
description="Are your software systems being developed cloud native?",
|
||||||
choices=[("yes", "Yes"), ("no", "No")],
|
choices=[("yes", "Yes"), ("no", "No")],
|
||||||
|
default="",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Details of Use: Financial Usage
|
# Details of Use: Financial Usage
|
||||||
|
71
js/components/forms/details_of_use.js
Normal file
71
js/components/forms/details_of_use.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import createNumberMask from 'text-mask-addons/dist/createNumberMask'
|
||||||
|
import { conformToMask } from 'vue-text-mask'
|
||||||
|
|
||||||
|
import textinput from '../text_input'
|
||||||
|
import optionsinput from '../options_input'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'details-of-use',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
textinput,
|
||||||
|
optionsinput,
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
initialData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data: function () {
|
||||||
|
const {
|
||||||
|
estimated_monthly_spend = 0,
|
||||||
|
jedi_migration = '',
|
||||||
|
technical_support_team = ''
|
||||||
|
} = this.initialData
|
||||||
|
|
||||||
|
return {
|
||||||
|
estimated_monthly_spend,
|
||||||
|
jedi_migration,
|
||||||
|
technical_support_team
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted: function () {
|
||||||
|
this.$root.$on('field-change', this.handleFieldChange)
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
annualSpend: function () {
|
||||||
|
const monthlySpend = this.estimated_monthly_spend || 0
|
||||||
|
return monthlySpend * 12
|
||||||
|
},
|
||||||
|
annualSpendStr: function () {
|
||||||
|
return this.formatDollars(this.annualSpend)
|
||||||
|
},
|
||||||
|
jediMigrationOptionSelected: function () {
|
||||||
|
return this.jedi_migration !== ''
|
||||||
|
},
|
||||||
|
isJediMigration: function () {
|
||||||
|
return this.jedi_migration === 'yes'
|
||||||
|
},
|
||||||
|
hasTechnicalSupportTeam: function () {
|
||||||
|
return this.technical_support_team === 'yes'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
formatDollars: function (intValue) {
|
||||||
|
const mask = createNumberMask({ prefix: '$', allowDecimal: true })
|
||||||
|
return conformToMask(intValue.toString(), mask).conformedValue
|
||||||
|
},
|
||||||
|
handleFieldChange: function (event) {
|
||||||
|
const { value, name } = event
|
||||||
|
if (typeof this[name] !== undefined) {
|
||||||
|
this[name] = value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
16
js/components/options_input.js
Normal file
16
js/components/options_input.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export default {
|
||||||
|
name: 'optionsinput',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
name: String
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onInput: function (e) {
|
||||||
|
this.$root.$emit('field-change', {
|
||||||
|
value: e.target.value,
|
||||||
|
name: this.name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -89,8 +89,8 @@ export default {
|
|||||||
this.showValid = valid
|
this.showValid = valid
|
||||||
|
|
||||||
// Emit a change event
|
// Emit a change event
|
||||||
this.$emit('fieldChange', {
|
this.$root.$emit('field-change', {
|
||||||
value,
|
value: this._rawValue(value),
|
||||||
valid,
|
valid,
|
||||||
name: this.name
|
name: this.name
|
||||||
})
|
})
|
||||||
|
@ -2,7 +2,9 @@ import classes from '../styles/atat.scss'
|
|||||||
import Vue from 'vue/dist/vue'
|
import Vue from 'vue/dist/vue'
|
||||||
import VTooltip from 'v-tooltip'
|
import VTooltip from 'v-tooltip'
|
||||||
|
|
||||||
|
import optionsinput from './components/options_input'
|
||||||
import textinput from './components/text_input'
|
import textinput from './components/text_input'
|
||||||
|
import DetailsOfUse from './components/forms/details_of_use'
|
||||||
|
|
||||||
Vue.use(VTooltip)
|
Vue.use(VTooltip)
|
||||||
|
|
||||||
@ -10,7 +12,9 @@ Vue.use(VTooltip)
|
|||||||
const app = new Vue({
|
const app = new Vue({
|
||||||
el: '#app-root',
|
el: '#app-root',
|
||||||
components: {
|
components: {
|
||||||
textinput
|
optionsinput,
|
||||||
|
textinput,
|
||||||
|
DetailsOfUse,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
closeModal: function(name) {
|
closeModal: function(name) {
|
||||||
@ -35,5 +39,6 @@ const app = new Vue({
|
|||||||
const modal = modalOpen.getAttribute("data-modal");
|
const modal = modalOpen.getAttribute("data-modal");
|
||||||
this.modals[modal] = true;
|
this.modals[modal] = true;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
delimiters: ['!{', '}']
|
||||||
})
|
})
|
||||||
|
@ -5,9 +5,9 @@ set -e
|
|||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
mkdir -p crl-tmp
|
mkdir -p crl-tmp
|
||||||
pipenv run python ./atst/domain/authnid/crl/util.py crl-tmp
|
pipenv run python ./atst/domain/authnid/crl/util.py crl-tmp crl
|
||||||
mkdir -p crl
|
mkdir -p crl
|
||||||
rsync -rq crl-tmp/. crl/.
|
rsync -rq --min-size 400 crl-tmp/. crl/.
|
||||||
rm -rf crl-tmp
|
rm -rf crl-tmp
|
||||||
|
|
||||||
if [[ $FLASK_ENV != "prod" ]]; then
|
if [[ $FLASK_ENV != "prod" ]]; then
|
||||||
|
@ -2,20 +2,22 @@
|
|||||||
{% from "components/tooltip.html" import Tooltip %}
|
{% from "components/tooltip.html" import Tooltip %}
|
||||||
|
|
||||||
{% macro OptionsInput(field, tooltip, inline=False) -%}
|
{% macro OptionsInput(field, tooltip, inline=False) -%}
|
||||||
|
<optionsinput name='{{ field.name }}' inline-template key='{{ field.name }}'>
|
||||||
<div class='usa-input {% if field.errors %}usa-input--error{% endif %}'>
|
<div class='usa-input {% if field.errors %}usa-input--error{% endif %}'>
|
||||||
|
|
||||||
<fieldset class="usa-input__choices {% if inline %}usa-input__choices--inline{% endif %}">
|
<fieldset v-on:change="onInput" class="usa-input__choices {% if inline %}usa-input__choices--inline{% endif %}">
|
||||||
<legend>
|
<legend>
|
||||||
<div class="usa-input__title">
|
<div class="usa-input__title">
|
||||||
{{ field.label | striptags}}
|
{{ field.label | striptags}}
|
||||||
{% if tooltip %}{{ Tooltip(tooltip) }}{% endif %}
|
{% if tooltip %}{{ Tooltip(tooltip) }}{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if field.description %}
|
{% if field.description %}
|
||||||
<span class='usa-input__help'>{{ field.description | safe }}</span>
|
<span class='usa-input__help'>{{ field.description | safe }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if field.errors %}
|
{% if field.errors %}
|
||||||
{{ Icon('alert',classes="icon-validation") }}
|
{{ Icon('alert',classes="icon-validation")) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</legend>
|
</legend>
|
||||||
|
|
||||||
@ -30,6 +32,6 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</optionsinput>
|
||||||
|
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
validation='{{ validation }}'
|
validation='{{ validation }}'
|
||||||
{% if field.data %}initial-value='{{ field.data }}'{% endif %}
|
{% if field.data %}initial-value='{{ field.data }}'{% endif %}
|
||||||
{% if field.errors %}v-bind:initial-errors='{{ field.errors }}'{% endif %}
|
{% if field.errors %}v-bind:initial-errors='{{ field.errors }}'{% endif %}
|
||||||
|
key='{{ field.name }}'
|
||||||
inline-template>
|
inline-template>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -17,31 +17,48 @@
|
|||||||
) }}
|
) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<details-of-use inline-template v-bind:initial-data='{{ f.data|tojson }}'>
|
||||||
|
<div>
|
||||||
|
|
||||||
<p>We’d like to know a little about how you plan to use JEDI Cloud services to process your request. Please answer the following questions to the best of your ability. Note that the CCPO does not directly help with migrating systems to JEDI Cloud. These questions are for learning about your cloud readiness and financial usage of the JEDI Cloud; your estimates will not be used for any department level reporting.</p>
|
<p>We’d like to know a little about how you plan to use JEDI Cloud services to process your request. Please answer the following questions to the best of your ability. Note that the CCPO does not directly help with migrating systems to JEDI Cloud. These questions are for learning about your cloud readiness and financial usage of the JEDI Cloud; your estimates will not be used for any department level reporting.</p>
|
||||||
<p><em>All fields are required, unless specified optional.</em></p>
|
<p><em>All fields are required, unless specified optional.</em></p>
|
||||||
|
|
||||||
<h2>General</h2>
|
<h2>General</h2>
|
||||||
{{ OptionsInput(f.dod_component) }}
|
{{ OptionsInput(f.dod_component) }}
|
||||||
{{ TextInput(f.jedi_usage,placeholder="Briefly describe how you are expecting to use the JEDI Cloud. \n e.g. We are migrating XYZ application to the cloud so that...",tooltip="Your answer will help us provide tangible examples to DoD leadership how and why commercial cloud resources are accelerating the Department\\'s missions.") }}
|
{{ TextInput(f.jedi_usage, paragraph=True, placeholder="Briefly describe how you are expecting to use the JEDI Cloud. \n e.g. We are migrating XYZ application to the cloud so that...",tooltip="Your answer will help us provide tangible examples to DoD leadership how and why commercial cloud resources are accelerating the Department\\'s missions.") }}
|
||||||
|
|
||||||
<h2>Cloud Readiness</h2>
|
<h2>Cloud Readiness</h2>
|
||||||
{{ TextInput(f.num_software_systems,validation="integer",tooltip="A software system can be any code that you plan to host on cloud infrastructure. For example, it could be a custom-developed web application, or a large ERP system.") }}
|
{{ TextInput(f.num_software_systems,validation="integer",tooltip="A software system can be any code that you plan to host on cloud infrastructure. For example, it could be a custom-developed web application, or a large ERP system.") }}
|
||||||
{{ OptionsInput(f.jedi_migration, tooltip="Cloud migration is the process of moving data, applications or other business elements from an organization\\'s onsite computers/data centers to the cloud, or moving them from one cloud environment to another.") }}
|
{{ OptionsInput(f.jedi_migration, tooltip="Cloud migration is the process of moving data, applications or other business elements from an organization\\'s onsite computers/data centers to the cloud, or moving them from one cloud environment to another.") }}
|
||||||
|
<template v-if="jediMigrationOptionSelected">
|
||||||
|
<template v-if='isJediMigration' v-cloak>
|
||||||
{{ OptionsInput(f.rationalization_software_systems, tooltip="Rationalization is the DoD process to determine whether the application should move to the cloud.") }}
|
{{ OptionsInput(f.rationalization_software_systems, tooltip="Rationalization is the DoD process to determine whether the application should move to the cloud.") }}
|
||||||
{{ OptionsInput(f.technical_support_team) }}
|
{{ OptionsInput(f.technical_support_team) }}
|
||||||
|
<template v-if="hasTechnicalSupportTeam">
|
||||||
{{ OptionsInput(f.organization_providing_assistance) }}
|
{{ OptionsInput(f.organization_providing_assistance) }}
|
||||||
|
</template>
|
||||||
{{ OptionsInput(f.engineering_assessment, tooltip="An engineering assessment is an evaluation to convert your application architecture from on-premises to using the commercial cloud") }}
|
{{ OptionsInput(f.engineering_assessment, tooltip="An engineering assessment is an evaluation to convert your application architecture from on-premises to using the commercial cloud") }}
|
||||||
{{ OptionsInput(f.data_transfers) }}
|
{{ OptionsInput(f.data_transfers) }}
|
||||||
{{ OptionsInput(f.expected_completion_date) }}
|
{{ OptionsInput(f.expected_completion_date) }}
|
||||||
|
</template>
|
||||||
|
<template v-else-if='!isJediMigration' v-cloak>
|
||||||
{{ OptionsInput(f.cloud_native, tooltip="Cloud native is architecting and designing your application to use all the benefits of the commercial cloud. Specifically, designing applications so that they are decoupled from a physical resource.") }}
|
{{ OptionsInput(f.cloud_native, tooltip="Cloud native is architecting and designing your application to use all the benefits of the commercial cloud. Specifically, designing applications so that they are decoupled from a physical resource.") }}
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
<h2>Financial Usage</h2>
|
<h2>Financial Usage</h2>
|
||||||
{{ TextInput(f.estimated_monthly_spend, tooltip="Refer to financial verification step help docs", validation="dollars") }}
|
{{ TextInput(f.estimated_monthly_spend, tooltip="Refer to financial verification step help docs", validation="dollars") }}
|
||||||
<span>So this means you are spending approximately <b class="label">$1,000,023</b> annually.</span>
|
<p>So this means you are spending approximately <span class="label">!{ annualSpendStr }</span> annually</p>
|
||||||
{{ TextInput(f.dollar_value,validation="dollars") }}
|
|
||||||
{{ TextInput(f.number_user_sessions,validation="integer") }}
|
{{ TextInput(f.dollar_value, validation='dollars') }}
|
||||||
|
<template v-if="annualSpend > 1000000">
|
||||||
|
{{ TextInput(f.number_user_sessions, validation='integer') }}
|
||||||
{{ TextInput(f.average_daily_traffic, tooltip="Requests are the client-to-server network traffic that is being transferred to your systems",validation="integer") }}
|
{{ TextInput(f.average_daily_traffic, tooltip="Requests are the client-to-server network traffic that is being transferred to your systems",validation="integer") }}
|
||||||
{{ TextInput(f.average_daily_traffic_gb, tooltip="GB uploaded is the gigabyte amount of data traffic that is being transferred to your systems",validation="gigabytes") }}
|
{{ TextInput(f.average_daily_traffic_gb, tooltip="GB uploaded is the gigabyte amount of data traffic that is being transferred to your systems",validation="gigabytes") }}
|
||||||
{{ TextInput(f.start_date, validation="date", placeholder="MM / DD / YYYY") }}
|
</template>
|
||||||
|
{{ TextInput(f.start_date, validation='date', placeholder='MM / DD / YYYY') }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</details-of-use>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -66,8 +66,9 @@ def test_parse_disa_pki_list():
|
|||||||
assert len(crl_list) == len(href_matches)
|
assert len(crl_list) == len(href_matches)
|
||||||
|
|
||||||
class MockStreamingResponse():
|
class MockStreamingResponse():
|
||||||
def __init__(self, content_chunks):
|
def __init__(self, content_chunks, code=200):
|
||||||
self.content_chunks = content_chunks
|
self.content_chunks = content_chunks
|
||||||
|
self.status_code = code
|
||||||
|
|
||||||
def iter_content(self, chunk_size=0):
|
def iter_content(self, chunk_size=0):
|
||||||
return self.content_chunks
|
return self.content_chunks
|
||||||
@ -81,6 +82,10 @@ class MockStreamingResponse():
|
|||||||
def test_write_crl(tmpdir, monkeypatch):
|
def test_write_crl(tmpdir, monkeypatch):
|
||||||
monkeypatch.setattr('requests.get', lambda u, **kwargs: MockStreamingResponse([b'it worked']))
|
monkeypatch.setattr('requests.get', lambda u, **kwargs: MockStreamingResponse([b'it worked']))
|
||||||
crl = 'crl_1'
|
crl = 'crl_1'
|
||||||
util.write_crl(tmpdir, crl)
|
assert util.write_crl(tmpdir, "random_target_dir", crl)
|
||||||
assert [p.basename for p in tmpdir.listdir()] == [crl]
|
assert [p.basename for p in tmpdir.listdir()] == [crl]
|
||||||
assert [p.read() for p in tmpdir.listdir()] == ['it worked']
|
assert [p.read() for p in tmpdir.listdir()] == ['it worked']
|
||||||
|
|
||||||
|
def test_skips_crl_if_it_has_not_been_modified(tmpdir, monkeypatch):
|
||||||
|
monkeypatch.setattr('requests.get', lambda u, **kwargs: MockStreamingResponse([b'it worked'], 304))
|
||||||
|
assert not util.write_crl(tmpdir, "random_target_dir", 'crl_file_name')
|
||||||
|
85
tests/forms/test_request.py
Normal file
85
tests/forms/test_request.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from atst.forms.request import RequestForm
|
||||||
|
|
||||||
|
|
||||||
|
class TestRequestForm:
|
||||||
|
|
||||||
|
form_data = {
|
||||||
|
'dod_component': 'us_air_force',
|
||||||
|
'jedi_usage': 'cloud-ify all the things',
|
||||||
|
'num_software_systems': '12',
|
||||||
|
'estimated_monthly_spend': '1000000',
|
||||||
|
'dollar_value': '42',
|
||||||
|
'number_user_sessions': '6',
|
||||||
|
'average_daily_traffic': '0',
|
||||||
|
'start_date': '12/12/2012',
|
||||||
|
}
|
||||||
|
migration_data = {
|
||||||
|
'jedi_migration': 'yes',
|
||||||
|
'rationalization_software_systems': 'yes',
|
||||||
|
'technical_support_team': 'yes',
|
||||||
|
'organization_providing_assistance': 'in_house_staff',
|
||||||
|
'engineering_assessment': 'yes',
|
||||||
|
'data_transfers': 'less_than_100gb',
|
||||||
|
'expected_completion_date': 'less_than_1_month'
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_require_cloud_native_when_not_migrating(self):
|
||||||
|
extra_data = { 'jedi_migration': 'no' }
|
||||||
|
request_form = RequestForm(data={ **self.form_data, **extra_data })
|
||||||
|
assert not request_form.validate()
|
||||||
|
assert request_form.errors == { 'cloud_native': ['Not a valid choice'] }
|
||||||
|
|
||||||
|
def test_require_migration_questions_when_migrating(self):
|
||||||
|
extra_data = { 'jedi_migration': 'yes' }
|
||||||
|
request_form = RequestForm(data={ **self.form_data, **extra_data })
|
||||||
|
assert not request_form.validate()
|
||||||
|
assert request_form.errors == {
|
||||||
|
'rationalization_software_systems': ['Not a valid choice'],
|
||||||
|
'technical_support_team': ['Not a valid choice'],
|
||||||
|
'organization_providing_assistance': ['Not a valid choice'],
|
||||||
|
'engineering_assessment': ['Not a valid choice'],
|
||||||
|
'data_transfers': ['Not a valid choice'],
|
||||||
|
'expected_completion_date': ['Not a valid choice']
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_require_organization_when_technical_support_team(self):
|
||||||
|
data = { **self.form_data, **self.migration_data }
|
||||||
|
del data['organization_providing_assistance']
|
||||||
|
|
||||||
|
request_form = RequestForm(data=data)
|
||||||
|
assert not request_form.validate()
|
||||||
|
assert request_form.errors == {
|
||||||
|
'organization_providing_assistance': ['Not a valid choice'],
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_valid_form_data(self):
|
||||||
|
data = { **self.form_data, **self.migration_data }
|
||||||
|
data['technical_support_team'] = 'no'
|
||||||
|
del data['organization_providing_assistance']
|
||||||
|
|
||||||
|
request_form = RequestForm(data=data)
|
||||||
|
assert request_form.validate()
|
||||||
|
|
||||||
|
def test_sessions_required_for_large_projects(self):
|
||||||
|
data = { **self.form_data, **self.migration_data }
|
||||||
|
data['estimated_monthly_spend'] = '9999999'
|
||||||
|
del data['number_user_sessions']
|
||||||
|
del data['average_daily_traffic']
|
||||||
|
|
||||||
|
request_form = RequestForm(data=data)
|
||||||
|
assert not request_form.validate()
|
||||||
|
assert request_form.errors == {
|
||||||
|
'number_user_sessions': ['This field is required.'],
|
||||||
|
'average_daily_traffic': ['This field is required.'],
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_sessions_not_required_invalid_monthly_spend(self):
|
||||||
|
data = { **self.form_data, **self.migration_data }
|
||||||
|
data['estimated_monthly_spend'] = 'foo'
|
||||||
|
del data['number_user_sessions']
|
||||||
|
del data['average_daily_traffic']
|
||||||
|
|
||||||
|
request_form = RequestForm(data=data)
|
||||||
|
assert request_form.validate()
|
Loading…
x
Reference in New Issue
Block a user