mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-06-09 22:14:43 +02:00
Merge branch 'main' into nmb/field-validation
This commit is contained in:
commit
6bda7b7ead
23 changed files with 549 additions and 223 deletions
8
.github/workflows/loaddata.yaml
vendored
8
.github/workflows/loaddata.yaml
vendored
|
@ -6,7 +6,7 @@ name: Reset database
|
||||||
# cf run-task getgov-staging --wait \
|
# cf run-task getgov-staging --wait \
|
||||||
# --command 'python manage.py flush' --name flush
|
# --command 'python manage.py flush' --name flush
|
||||||
# cf run-task getgov-staging --wait \
|
# cf run-task getgov-staging --wait \
|
||||||
# --command 'python manage.py loaddata registrar/fixtures/*' --name loaddata
|
# --command 'python manage.py load' --name loaddata
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
|
@ -24,8 +24,8 @@ jobs:
|
||||||
- name: Delete existing data for staging
|
- name: Delete existing data for staging
|
||||||
uses: 18f/cg-deploy-action@main
|
uses: 18f/cg-deploy-action@main
|
||||||
with:
|
with:
|
||||||
cf_username: ${{ secrets.CF_USERNAME }}
|
cf_username: ${{ secrets.CF_STAGING_USERNAME }}
|
||||||
cf_password: ${{ secrets.CF_PASSWORD }}
|
cf_password: ${{ secrets.CF_STAGING_PASSWORD }}
|
||||||
cf_org: cisa-getgov-prototyping
|
cf_org: cisa-getgov-prototyping
|
||||||
cf_space: staging
|
cf_space: staging
|
||||||
full_command: "cf run-task getgov-staging --wait --command 'python manage.py flush' --name flush"
|
full_command: "cf run-task getgov-staging --wait --command 'python manage.py flush' --name flush"
|
||||||
|
@ -37,4 +37,4 @@ jobs:
|
||||||
cf_password: ${{ secrets.CF_STAGING_PASSWORD }}
|
cf_password: ${{ secrets.CF_STAGING_PASSWORD }}
|
||||||
cf_org: cisa-getgov-prototyping
|
cf_org: cisa-getgov-prototyping
|
||||||
cf_space: staging
|
cf_space: staging
|
||||||
full_command: "cf run-task getgov-staging --wait --command 'python manage.py loaddata registrar/fixtures/*' --name loaddata"
|
full_command: "cf run-task getgov-staging --wait --command 'python manage.py load' --name loaddata"
|
||||||
|
|
|
@ -38,6 +38,12 @@ If you run via `docker-compose up -d`, you can get logs with `docker-compose log
|
||||||
|
|
||||||
You can change the logging verbosity, if needed. Do a web search for "django log level".
|
You can change the logging verbosity, if needed. Do a web search for "django log level".
|
||||||
|
|
||||||
|
## Mock data
|
||||||
|
|
||||||
|
There is a `post_migrate` signal in [signals.py](../../src/registrar/signals.py) that will load the fixtures from [fixtures.py](../../src/registrar/fixtures.py), giving you some test data to play with while developing.
|
||||||
|
|
||||||
|
See the [database-access README](./database-access.md) for information on how to pull data to update these fixtures.
|
||||||
|
|
||||||
## Running tests
|
## Running tests
|
||||||
|
|
||||||
Crash course on Docker's `run` vs `exec`: in order to run the tests inside of a container, a container must be running. If you already have a container running, you can use `exec`. If you do not, you can use `run`, which will attempt to start one.
|
Crash course on Docker's `run` vs `exec`: in order to run the tests inside of a container, a container must be running. If you already have a container running, you can use `exec`. If you do not, you can use `run`, which will attempt to start one.
|
||||||
|
|
|
@ -24,7 +24,7 @@ cf run-task getgov-unstable --command 'python manage.py migrate' --name migrate
|
||||||
Optionally, load data from fixtures as well
|
Optionally, load data from fixtures as well
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
cf run-task getgov-unstable --wait --command 'python manage.py loaddata registrar/fixtures/*' --name loaddata
|
cf run-task getgov-unstable --wait --command 'python manage.py load' --name loaddata
|
||||||
```
|
```
|
||||||
|
|
||||||
For the `staging` environment, developers don't have credentials so we need to
|
For the `staging` environment, developers don't have credentials so we need to
|
||||||
|
|
|
@ -11,6 +11,7 @@ django-allow-cidr = "*"
|
||||||
django-auditlog = "*"
|
django-auditlog = "*"
|
||||||
django-csp = "*"
|
django-csp = "*"
|
||||||
environs = {extras=["django"]}
|
environs = {extras=["django"]}
|
||||||
|
Faker = "*"
|
||||||
gunicorn = "*"
|
gunicorn = "*"
|
||||||
oic = "*"
|
oic = "*"
|
||||||
pyjwkest = "*"
|
pyjwkest = "*"
|
||||||
|
|
137
src/Pipfile.lock
generated
137
src/Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "9e2fe58b6282514da5d054147426e561f451da29f3c743c0cd9dccf4d7dba0cc"
|
"sha256": "c9762342448f1a70dbe93cc496e5fb868c67a73f3e51c4440e726f492f7dc5ee"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {},
|
"requires": {},
|
||||||
|
@ -16,11 +16,11 @@
|
||||||
"default": {
|
"default": {
|
||||||
"asgiref": {
|
"asgiref": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4",
|
"sha256:71e68008da809b957b7ee4b43dbccff33d1b23519fb8344e33f049897077afac",
|
||||||
"sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"
|
"sha256:9567dfe7bd8d3c8c892227827c41cce860b368104c3431da67a0c5a65a949506"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==3.5.2"
|
"version": "==3.6.0"
|
||||||
},
|
},
|
||||||
"cachetools": {
|
"cachetools": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -125,35 +125,32 @@
|
||||||
},
|
},
|
||||||
"cryptography": {
|
"cryptography": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0e70da4bdff7601b0ef48e6348339e490ebfb0cbe638e083c9c41fb49f00c8bd",
|
"sha256:1a6915075c6d3a5e1215eab5d99bcec0da26036ff2102a1038401d6ef5bef25b",
|
||||||
"sha256:10652dd7282de17990b88679cb82f832752c4e8237f0c714be518044269415db",
|
"sha256:1ee1fd0de9851ff32dbbb9362a4d833b579b4a6cc96883e8e6d2ff2a6bc7104f",
|
||||||
"sha256:175c1a818b87c9ac80bb7377f5520b7f31b3ef2a0004e2420319beadedb67290",
|
"sha256:407cec680e811b4fc829de966f88a7c62a596faa250fc1a4b520a0355b9bc190",
|
||||||
"sha256:1d7e632804a248103b60b16fb145e8df0bc60eed790ece0d12efe8cd3f3e7744",
|
"sha256:50386acb40fbabbceeb2986332f0287f50f29ccf1497bae31cf5c3e7b4f4b34f",
|
||||||
"sha256:1f13ddda26a04c06eb57119caf27a524ccae20533729f4b1e4a69b54e07035eb",
|
"sha256:6f97109336df5c178ee7c9c711b264c502b905c2d2a29ace99ed761533a3460f",
|
||||||
"sha256:2ec2a8714dd005949d4019195d72abed84198d877112abb5a27740e217e0ea8d",
|
"sha256:754978da4d0457e7ca176f58c57b1f9de6556591c19b25b8bcce3c77d314f5eb",
|
||||||
"sha256:2fa36a7b2cc0998a3a4d5af26ccb6273f3df133d61da2ba13b3286261e7efb70",
|
"sha256:76c24dd4fd196a80f9f2f5405a778a8ca132f16b10af113474005635fe7e066c",
|
||||||
"sha256:2fb481682873035600b5502f0015b664abc26466153fab5c6bc92c1ea69d478b",
|
"sha256:7dacfdeee048814563eaaec7c4743c8aea529fe3dd53127313a792f0dadc1773",
|
||||||
"sha256:3178d46f363d4549b9a76264f41c6948752183b3f587666aff0555ac50fd7876",
|
"sha256:80ee674c08aaef194bc4627b7f2956e5ba7ef29c3cc3ca488cf15854838a8f72",
|
||||||
"sha256:4367da5705922cf7070462e964f66e4ac24162e22ab0a2e9d31f1b270dd78083",
|
"sha256:844ad4d7c3850081dffba91cdd91950038ee4ac525c575509a42d3fc806b83c8",
|
||||||
"sha256:4eb85075437f0b1fd8cd66c688469a0c4119e0ba855e3fef86691971b887caf6",
|
"sha256:875aea1039d78557c7c6b4db2fe0e9d2413439f4676310a5f269dd342ca7a717",
|
||||||
"sha256:50a1494ed0c3f5b4d07650a68cd6ca62efe8b596ce743a5c94403e6f11bf06c1",
|
"sha256:887cbc1ea60786e534b00ba8b04d1095f4272d380ebd5f7a7eb4cc274710fad9",
|
||||||
"sha256:53049f3379ef05182864d13bb9686657659407148f901f3f1eee57a733fb4b00",
|
"sha256:ad04f413436b0781f20c52a661660f1e23bcd89a0e9bb1d6d20822d048cf2856",
|
||||||
"sha256:6391e59ebe7c62d9902c24a4d8bcbc79a68e7c4ab65863536127c8a9cd94043b",
|
"sha256:bae6c7f4a36a25291b619ad064a30a07110a805d08dc89984f4f441f6c1f3f96",
|
||||||
"sha256:67461b5ebca2e4c2ab991733f8ab637a7265bb582f07c7c88914b5afb88cb95b",
|
"sha256:c52a1a6f81e738d07f43dab57831c29e57d21c81a942f4602fac7ee21b27f288",
|
||||||
"sha256:78e47e28ddc4ace41dd38c42e6feecfdadf9c3be2af389abbfeef1ff06822285",
|
"sha256:e0a05aee6a82d944f9b4edd6a001178787d1546ec7c6223ee9a848a7ade92e39",
|
||||||
"sha256:80ca53981ceeb3241998443c4964a387771588c4e4a5d92735a493af868294f9",
|
"sha256:e324de6972b151f99dc078defe8fb1b0a82c6498e37bff335f5bc6b1e3ab5a1e",
|
||||||
"sha256:8a4b2bdb68a447fadebfd7d24855758fe2d6fecc7fed0b78d190b1af39a8e3b0",
|
"sha256:e5d71c5d5bd5b5c3eebcf7c5c2bb332d62ec68921a8c593bea8c394911a005ce",
|
||||||
"sha256:8e45653fb97eb2f20b8c96f9cd2b3a0654d742b47d638cf2897afbd97f80fa6d",
|
"sha256:f3ed2d864a2fa1666e749fe52fb8e23d8e06b8012e8bd8147c73797c506e86f1",
|
||||||
"sha256:998cd19189d8a747b226d24c0207fdaa1e6658a1d3f2494541cb9dfbf7dcb6d2",
|
"sha256:f671c1bb0d6088e94d61d80c606d65baacc0d374e67bf895148883461cd848de",
|
||||||
"sha256:a10498349d4c8eab7357a8f9aa3463791292845b79597ad1b98a543686fb1ec8",
|
"sha256:f6c0db08d81ead9576c4d94bbb27aed8d7a430fa27890f39084c2d0e2ec6b0df",
|
||||||
"sha256:b4cad0cea995af760f82820ab4ca54e5471fc782f70a007f31531957f43e9dee",
|
"sha256:f964c7dcf7802d133e8dbd1565914fa0194f9d683d82411989889ecd701e8adf",
|
||||||
"sha256:bfe6472507986613dc6cc00b3d492b2f7564b02b3b3682d25ca7f40fa3fd321b",
|
"sha256:fec8b932f51ae245121c4671b4bbc030880f363354b2f0e0bd1366017d891458"
|
||||||
"sha256:c9e0d79ee4c56d841bd4ac6e7697c8ff3c8d6da67379057f29e66acffcd1e9a7",
|
|
||||||
"sha256:ca57eb3ddaccd1112c18fc80abe41db443cc2e9dcb1917078e02dfa010a4f353",
|
|
||||||
"sha256:ce127dd0a6a0811c251a6cddd014d292728484e530d80e872ad9806cfb1c5b3c"
|
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_version >= '3.6'",
|
||||||
"version": "==38.0.4"
|
"version": "==39.0.0"
|
||||||
},
|
},
|
||||||
"defusedxml": {
|
"defusedxml": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -179,11 +176,11 @@
|
||||||
},
|
},
|
||||||
"django": {
|
"django": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0b223bfa55511f950ff741983d408d78d772351284c75e9f77d2b830b6b4d148",
|
"sha256:4b214a05fe4c99476e99e2445c8b978c8369c18d4dea8e22ec412862715ad763",
|
||||||
"sha256:d38a4e108d2386cb9637da66a82dc8d0733caede4c83c4afdbda78af4214211b"
|
"sha256:ff56ebd7ead0fd5dbe06fe157b0024a7aaea2e0593bb3785fb594cf94dad58ef"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==4.1.4"
|
"version": "==4.1.5"
|
||||||
},
|
},
|
||||||
"django-allow-cidr": {
|
"django-allow-cidr": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -262,6 +259,14 @@
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==9.5.0"
|
"version": "==9.5.0"
|
||||||
},
|
},
|
||||||
|
"faker": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2d5443724f640ce07658ca8ca8bbd40d26b58914e63eec6549727869aa67e2cc",
|
||||||
|
"sha256:c2a2ff9dd8dfd991109b517ab98d5cb465e857acb45f6b643a0e284a9eb2cc76"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==15.3.4"
|
||||||
|
},
|
||||||
"furl": {
|
"furl": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:5a6188fe2666c484a12159c18be97a1977a71d632ef5bb867ef15f54af39cc4e",
|
"sha256:5a6188fe2666c484a12159c18be97a1977a71d632ef5bb867ef15f54af39cc4e",
|
||||||
|
@ -379,10 +384,10 @@
|
||||||
},
|
},
|
||||||
"phonenumberslite": {
|
"phonenumberslite": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:87218f3f85f67779007b6cfeeca59b1d370b96f9b3867347f0e6d094b1a3df64",
|
"sha256:2b7452fe69c907b7638ff4cf7f8a773a6dfce26bf32d67ebf4dc74d5e31abb79",
|
||||||
"sha256:8daa2fff393e291531aaa5ed4ddc123749b631d48ae7e504e8d7a4e818b3f799"
|
"sha256:b7f56b77711e6b99c7890f20f1aaa705d9fe2514215446b8426c8515c198775f"
|
||||||
],
|
],
|
||||||
"version": "==8.13.2"
|
"version": "==8.13.3"
|
||||||
},
|
},
|
||||||
"psycopg2-binary": {
|
"psycopg2-binary": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -573,21 +578,21 @@
|
||||||
},
|
},
|
||||||
"whitenoise": {
|
"whitenoise": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:8e9c600a5c18bd17655ef668ad55b5edf6c24ce9bdca5bf607649ca4b1e8e2c2",
|
"sha256:cf8ecf56d86ba1c734fdb5ef6127312e39e92ad5947fef9033dc9e43ba2777d9",
|
||||||
"sha256:8fa943c6d4cd9e27673b70c21a07b0aa120873901e099cd46cab40f7cc96d567"
|
"sha256:fe0af31504ab08faa1ec7fc02845432096e40cc1b27e6a7747263d7b30fb51fa"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==6.2.0"
|
"version": "==6.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"develop": {
|
"develop": {
|
||||||
"asgiref": {
|
"asgiref": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4",
|
"sha256:71e68008da809b957b7ee4b43dbccff33d1b23519fb8344e33f049897077afac",
|
||||||
"sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"
|
"sha256:9567dfe7bd8d3c8c892227827c41cce860b368104c3431da67a0c5a65a949506"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==3.5.2"
|
"version": "==3.6.0"
|
||||||
},
|
},
|
||||||
"bandit": {
|
"bandit": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -602,7 +607,7 @@
|
||||||
"sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30",
|
"sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30",
|
||||||
"sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"
|
"sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_full_version >= '3.6.0'",
|
||||||
"version": "==4.11.1"
|
"version": "==4.11.1"
|
||||||
},
|
},
|
||||||
"black": {
|
"black": {
|
||||||
|
@ -641,11 +646,11 @@
|
||||||
},
|
},
|
||||||
"django": {
|
"django": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0b223bfa55511f950ff741983d408d78d772351284c75e9f77d2b830b6b4d148",
|
"sha256:4b214a05fe4c99476e99e2445c8b978c8369c18d4dea8e22ec412862715ad763",
|
||||||
"sha256:d38a4e108d2386cb9637da66a82dc8d0733caede4c83c4afdbda78af4214211b"
|
"sha256:ff56ebd7ead0fd5dbe06fe157b0024a7aaea2e0593bb3785fb594cf94dad58ef"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==4.1.4"
|
"version": "==4.1.5"
|
||||||
},
|
},
|
||||||
"django-debug-toolbar": {
|
"django-debug-toolbar": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -697,18 +702,18 @@
|
||||||
},
|
},
|
||||||
"gitpython": {
|
"gitpython": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:41eea0deec2deea139b459ac03656f0dd28fc4a3387240ec1d3c259a2c47850f",
|
"sha256:769c2d83e13f5d938b7688479da374c4e3d49f71549aaf462b646db9602ea6f8",
|
||||||
"sha256:cc36bfc4a3f913e66805a28e84703e419d9c264c1077e537b54f0e1af85dbefd"
|
"sha256:cd455b0000615c60e286208ba540271af9fe531fa6a87cc590a7298785ab2882"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==3.1.29"
|
"version": "==3.1.30"
|
||||||
},
|
},
|
||||||
"mccabe": {
|
"mccabe": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
|
"sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
|
||||||
"sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
|
"sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_full_version >= '3.6.0'",
|
||||||
"version": "==0.7.0"
|
"version": "==0.7.0"
|
||||||
},
|
},
|
||||||
"mypy": {
|
"mypy": {
|
||||||
|
@ -780,18 +785,18 @@
|
||||||
},
|
},
|
||||||
"platformdirs": {
|
"platformdirs": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca",
|
"sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490",
|
||||||
"sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e"
|
"sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==2.6.0"
|
"version": "==2.6.2"
|
||||||
},
|
},
|
||||||
"pycodestyle": {
|
"pycodestyle": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053",
|
"sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053",
|
||||||
"sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"
|
"sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_full_version >= '3.6.0'",
|
||||||
"version": "==2.10.0"
|
"version": "==2.10.0"
|
||||||
},
|
},
|
||||||
"pyflakes": {
|
"pyflakes": {
|
||||||
|
@ -799,7 +804,7 @@
|
||||||
"sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf",
|
"sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf",
|
||||||
"sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"
|
"sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_full_version >= '3.6.0'",
|
||||||
"version": "==3.0.1"
|
"version": "==3.0.1"
|
||||||
},
|
},
|
||||||
"pyyaml": {
|
"pyyaml": {
|
||||||
|
@ -845,7 +850,7 @@
|
||||||
"sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
|
"sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
|
||||||
"sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
|
"sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_full_version >= '3.6.0'",
|
||||||
"version": "==6.0"
|
"version": "==6.0"
|
||||||
},
|
},
|
||||||
"six": {
|
"six": {
|
||||||
|
@ -861,7 +866,7 @@
|
||||||
"sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94",
|
"sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94",
|
||||||
"sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"
|
"sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_full_version >= '3.6.0'",
|
||||||
"version": "==5.0.0"
|
"version": "==5.0.0"
|
||||||
},
|
},
|
||||||
"soupsieve": {
|
"soupsieve": {
|
||||||
|
@ -869,7 +874,7 @@
|
||||||
"sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759",
|
"sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759",
|
||||||
"sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"
|
"sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6'",
|
"markers": "python_full_version >= '3.6.0'",
|
||||||
"version": "==2.3.2.post1"
|
"version": "==2.3.2.post1"
|
||||||
},
|
},
|
||||||
"sqlparse": {
|
"sqlparse": {
|
||||||
|
@ -906,10 +911,10 @@
|
||||||
},
|
},
|
||||||
"types-pytz": {
|
"types-pytz": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:bea605ce5d5a5d52a8e1afd7656c9b42476e18a0f888de6be91587355313ddf4",
|
"sha256:1509f182f686ab76e9a8234f22b00b8f50d239974db0cf924b7ae8674bb31a6f",
|
||||||
"sha256:d078196374d1277e9f9984d49373ea043cf2c64d5d5c491fbc86c258557bd46f"
|
"sha256:4f20c2953b3a3a0587e94489ec4c9e02c3d3aedb9ba5cd7e796e12f4cfa7027e"
|
||||||
],
|
],
|
||||||
"version": "==2022.6.0.1"
|
"version": "==2022.7.0.0"
|
||||||
},
|
},
|
||||||
"types-pyyaml": {
|
"types-pyyaml": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -920,11 +925,11 @@
|
||||||
},
|
},
|
||||||
"types-requests": {
|
"types-requests": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:091d4a5a33c1b4f20d8b1b952aa8fa27a6e767c44c3cf65e56580df0b05fd8a9",
|
"sha256:0ae38633734990d019b80f5463dfa164ebd3581998ac8435f526da6fe4d598c3",
|
||||||
"sha256:a7df37cc6fb6187a84097da951f8e21d335448aa2501a6b0a39cbd1d7ca9ee2a"
|
"sha256:b6a2fca8109f4fdba33052f11ed86102bddb2338519e1827387137fefc66a98b"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==2.28.11.5"
|
"version": "==2.28.11.7"
|
||||||
},
|
},
|
||||||
"types-urllib3": {
|
"types-urllib3": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -962,7 +967,7 @@
|
||||||
"sha256:2a001a9efa40d2a7e5d9cd8d1527c75f41814eb6afce2c3d207402547b1e5ead",
|
"sha256:2a001a9efa40d2a7e5d9cd8d1527c75f41814eb6afce2c3d207402547b1e5ead",
|
||||||
"sha256:54bd969725838d9861a9fa27f8d971f79d275d94ae255f5c501f53bb6d9929eb"
|
"sha256:54bd969725838d9861a9fa27f8d971f79d275d94ae255f5c501f53bb6d9929eb"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.6' and python_version < '4'",
|
"markers": "python_full_version >= '3.6.0' and python_version < '4'",
|
||||||
"version": "==3.0.0"
|
"version": "==3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
256
src/registrar/fixtures.py
Normal file
256
src/registrar/fixtures.py
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
import logging
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
from faker import Faker
|
||||||
|
|
||||||
|
from registrar.models import (
|
||||||
|
User,
|
||||||
|
UserProfile,
|
||||||
|
DomainApplication,
|
||||||
|
Domain,
|
||||||
|
Contact,
|
||||||
|
Website,
|
||||||
|
)
|
||||||
|
|
||||||
|
fake = Faker()
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class UserFixture:
|
||||||
|
"""
|
||||||
|
Load users into the database.
|
||||||
|
|
||||||
|
Make sure this class' `load` method is called from `handle`
|
||||||
|
in management/commands/load.py, then use `./manage.py load`
|
||||||
|
to run this code.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ADMINS = [
|
||||||
|
{
|
||||||
|
"username": "c4a0e101-73b4-4d7d-9e5e-7f19a726a0fa",
|
||||||
|
"first_name": "Seamus",
|
||||||
|
"last_name": "Johnston",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "d4c3bd84-dc3a-48bc-a3c3-f53111df2ec6",
|
||||||
|
"first_name": "Igor",
|
||||||
|
"last_name": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "ee80bfe0-49ad-456d-8d82-e2b608a66517",
|
||||||
|
"first_name": "Logan",
|
||||||
|
"last_name": "",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
logger.info("Going to load %s users" % str(len(cls.ADMINS)))
|
||||||
|
for admin in cls.ADMINS:
|
||||||
|
try:
|
||||||
|
user, _ = User.objects.get_or_create(
|
||||||
|
username=admin["username"],
|
||||||
|
)
|
||||||
|
user.is_superuser = True
|
||||||
|
user.first_name = admin["first_name"]
|
||||||
|
user.last_name = admin["last_name"]
|
||||||
|
user.is_staff = True
|
||||||
|
user.is_active = True
|
||||||
|
user.save()
|
||||||
|
logger.debug("User object created for %s" % admin["first_name"])
|
||||||
|
UserProfile.objects.get_or_create(user=user)
|
||||||
|
logger.debug("Profile object created for %s" % admin["first_name"])
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(e)
|
||||||
|
logger.debug("All users loaded.")
|
||||||
|
|
||||||
|
|
||||||
|
class DomainApplicationFixture:
|
||||||
|
"""
|
||||||
|
Load domain applications into the database.
|
||||||
|
|
||||||
|
Make sure this class' `load` method is called from `handle`
|
||||||
|
in management/commands/load.py, then use `./manage.py load`
|
||||||
|
to run this code.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# any fields not specified here will be filled in with fake data or defaults
|
||||||
|
# NOTE BENE: each fixture must have `organization_name` for uniqueness!
|
||||||
|
DA = [
|
||||||
|
{
|
||||||
|
"status": "started",
|
||||||
|
"organization_name": "Example - Finished but not Submitted",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"status": "started",
|
||||||
|
"organization_name": "Example - Just started",
|
||||||
|
"organization_type": "federal",
|
||||||
|
"federal_agency": None,
|
||||||
|
"federal_type": None,
|
||||||
|
"address_line1": None,
|
||||||
|
"address_line2": None,
|
||||||
|
"city": None,
|
||||||
|
"state_territory": None,
|
||||||
|
"zipcode": None,
|
||||||
|
"urbanization": None,
|
||||||
|
"purpose": None,
|
||||||
|
"security_email": None,
|
||||||
|
"anything_else": None,
|
||||||
|
"is_policy_acknowledged": None,
|
||||||
|
"authorizing_official": None,
|
||||||
|
"submitter": None,
|
||||||
|
"other_contacts": [],
|
||||||
|
"current_websites": [],
|
||||||
|
"alternative_domains": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"status": "submitted",
|
||||||
|
"organization_name": "Example - Submitted but pending Investigation",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"status": "investigating",
|
||||||
|
"organization_name": "Example - In Investigation",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fake_contact(cls):
|
||||||
|
return {
|
||||||
|
"first_name": fake.first_name(),
|
||||||
|
"middle_name": None,
|
||||||
|
"last_name": fake.last_name(),
|
||||||
|
"title": fake.job(),
|
||||||
|
"email": fake.ascii_safe_email(),
|
||||||
|
"phone": fake.phone_number(),
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fake_dot_gov(cls):
|
||||||
|
return "".join(random.choices(string.ascii_lowercase, k=16)) + ".gov" # nosec
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _set_non_foreign_key_fields(cls, da: DomainApplication, app: dict):
|
||||||
|
"""Helper method used by `load`."""
|
||||||
|
da.status = app["status"] if "status" in app else "started"
|
||||||
|
da.organization_type = (
|
||||||
|
app["organization_type"] if "organization_type" in app else "federal"
|
||||||
|
)
|
||||||
|
da.federal_agency = app["federal_agency"] if "federal_agency" in app else ""
|
||||||
|
da.federal_type = (
|
||||||
|
app["federal_type"]
|
||||||
|
if "federal_type" in app
|
||||||
|
else random.choice(["executive", "judicial", "legislative"]) # nosec
|
||||||
|
)
|
||||||
|
da.address_line1 = (
|
||||||
|
app["address_line1"] if "address_line1" in app else fake.street_address()
|
||||||
|
)
|
||||||
|
da.address_line2 = app["address_line2"] if "address_line2" in app else None
|
||||||
|
da.city = app["city"] if "city" in app else fake.city()
|
||||||
|
da.state_territory = (
|
||||||
|
app["state_territory"] if "state_territory" in app else fake.state_abbr()
|
||||||
|
)
|
||||||
|
da.zipcode = app["zipcode"] if "zipcode" in app else fake.postalcode()
|
||||||
|
da.urbanization = app["urbanization"] if "urbanization" in app else None
|
||||||
|
da.purpose = app["purpose"] if "purpose" in app else fake.paragraph()
|
||||||
|
da.security_email = app["security_email"] if "security_email" in app else None
|
||||||
|
da.anything_else = app["anything_else"] if "anything_else" in app else None
|
||||||
|
da.is_policy_acknowledged = (
|
||||||
|
app["is_policy_acknowledged"] if "is_policy_acknowledged" in app else True
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _set_foreign_key_fields(cls, da: DomainApplication, app: dict, user: User):
|
||||||
|
"""Helper method used by `load`."""
|
||||||
|
if not da.investigator:
|
||||||
|
da.investigator = (
|
||||||
|
User.objects.get(username=user.username)
|
||||||
|
if "investigator" in app
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
if not da.authorizing_official:
|
||||||
|
if (
|
||||||
|
"authorizing_official" in app
|
||||||
|
and app["authorizing_official"] is not None
|
||||||
|
):
|
||||||
|
da.authorizing_official, _ = Contact.objects.get_or_create(
|
||||||
|
**app["authorizing_official"]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
da.authorizing_official = Contact.objects.create(**cls.fake_contact())
|
||||||
|
|
||||||
|
if not da.submitter:
|
||||||
|
if "submitter" in app and app["submitter"] is not None:
|
||||||
|
da.submitter, _ = Contact.objects.get_or_create(**app["submitter"])
|
||||||
|
else:
|
||||||
|
da.submitter = Contact.objects.create(**cls.fake_contact())
|
||||||
|
|
||||||
|
if not da.requested_domain:
|
||||||
|
if "requested_domain" in app and app["requested_domain"] is not None:
|
||||||
|
da.requested_domain, _ = Domain.objects.get_or_create(
|
||||||
|
name=app["requested_domain"]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
da.requested_domain = Domain.objects.create(name=cls.fake_dot_gov())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _set_many_to_many_relations(cls, da: DomainApplication, app: dict):
|
||||||
|
"""Helper method used by `load`."""
|
||||||
|
if "other_contacts" in app:
|
||||||
|
for contact in app["other_contacts"]:
|
||||||
|
da.other_contacts.add(Contact.objects.get_or_create(**contact)[0])
|
||||||
|
else:
|
||||||
|
other_contacts = [
|
||||||
|
Contact.objects.create(**cls.fake_contact())
|
||||||
|
for _ in range(random.randint(0, 3)) # nosec
|
||||||
|
]
|
||||||
|
da.other_contacts.add(*other_contacts)
|
||||||
|
|
||||||
|
if "current_websites" in app:
|
||||||
|
for website in app["current_websites"]:
|
||||||
|
da.current_websites.add(
|
||||||
|
Website.objects.get_or_create(website=website)[0]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
current_websites = [
|
||||||
|
Website.objects.create(website=fake.uri())
|
||||||
|
for _ in range(random.randint(0, 3)) # nosec
|
||||||
|
]
|
||||||
|
da.current_websites.add(*current_websites)
|
||||||
|
|
||||||
|
if "alternative_domains" in app:
|
||||||
|
for domain in app["alternative_domains"]:
|
||||||
|
da.alternative_domains.add(
|
||||||
|
Website.objects.get_or_create(website=domain)[0]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
alternative_domains = [
|
||||||
|
Website.objects.create(website=cls.fake_dot_gov())
|
||||||
|
for _ in range(random.randint(0, 3)) # nosec
|
||||||
|
]
|
||||||
|
da.alternative_domains.add(*alternative_domains)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
"""Creates domain applications for each user in the database."""
|
||||||
|
logger.info("Going to load %s domain applications" % len(cls.DA))
|
||||||
|
try:
|
||||||
|
users = list(User.objects.all()) # force evaluation to catch db errors
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(e)
|
||||||
|
return
|
||||||
|
|
||||||
|
for user in users:
|
||||||
|
logger.debug("Loading domain applications for %s" % user)
|
||||||
|
for app in cls.DA:
|
||||||
|
try:
|
||||||
|
da, _ = DomainApplication.objects.get_or_create(
|
||||||
|
creator=user,
|
||||||
|
organization_name=app["organization_name"],
|
||||||
|
)
|
||||||
|
cls._set_non_foreign_key_fields(da, app)
|
||||||
|
cls._set_foreign_key_fields(da, app, user)
|
||||||
|
da.save()
|
||||||
|
cls._set_many_to_many_relations(da, app)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(e)
|
|
@ -1,107 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"model": "registrar.user",
|
|
||||||
"pk": 1,
|
|
||||||
"fields": {
|
|
||||||
"password": "",
|
|
||||||
"last_login": "2022-10-04T15:07:34.590Z",
|
|
||||||
"is_superuser": true,
|
|
||||||
"username": "c4a0e101-73b4-4d7d-9e5e-7f19a726a0fa",
|
|
||||||
"first_name": "Seamus",
|
|
||||||
"last_name": "Johnston",
|
|
||||||
"email": "",
|
|
||||||
"is_staff": true,
|
|
||||||
"is_active": true,
|
|
||||||
"date_joined": "2022-09-30T14:14:02.280Z",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"model": "registrar.userprofile",
|
|
||||||
"pk": 1,
|
|
||||||
"fields": {
|
|
||||||
"created_at": "2022-09-30T14:14:02.284Z",
|
|
||||||
"updated_at": "2022-10-04T15:07:34.593Z",
|
|
||||||
"street1": "",
|
|
||||||
"street2": "",
|
|
||||||
"street3": "",
|
|
||||||
"city": "",
|
|
||||||
"sp": "",
|
|
||||||
"pc": "",
|
|
||||||
"cc": "",
|
|
||||||
"user": 1,
|
|
||||||
"display_name": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"model": "registrar.user",
|
|
||||||
"pk": 2,
|
|
||||||
"fields": {
|
|
||||||
"password": "",
|
|
||||||
"last_login": "2022-10-04T16:43:07.738Z",
|
|
||||||
"is_superuser": true,
|
|
||||||
"username": "d4c3bd84-dc3a-48bc-a3c3-f53111df2ec6",
|
|
||||||
"first_name": "Igor",
|
|
||||||
"last_name": "",
|
|
||||||
"email": "",
|
|
||||||
"is_staff": true,
|
|
||||||
"is_active": true,
|
|
||||||
"date_joined": "2022-10-04T16:39:30.529Z",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"model": "registrar.userprofile",
|
|
||||||
"pk": 2,
|
|
||||||
"fields": {
|
|
||||||
"created_at": "2022-10-04T16:39:30.531Z",
|
|
||||||
"updated_at": "2022-10-04T16:43:07.740Z",
|
|
||||||
"street1": "",
|
|
||||||
"street2": "",
|
|
||||||
"street3": "",
|
|
||||||
"city": "",
|
|
||||||
"sp": "",
|
|
||||||
"pc": "",
|
|
||||||
"cc": "",
|
|
||||||
"user": 2,
|
|
||||||
"display_name": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"model": "registrar.user",
|
|
||||||
"pk": 3,
|
|
||||||
"fields": {
|
|
||||||
"password": "",
|
|
||||||
"last_login": "2022-10-13T13:57:52.133Z",
|
|
||||||
"is_superuser": true,
|
|
||||||
"username": "ee80bfe0-49ad-456d-8d82-e2b608a66517",
|
|
||||||
"first_name": "Logan",
|
|
||||||
"last_name": "",
|
|
||||||
"email": "",
|
|
||||||
"is_staff": true,
|
|
||||||
"is_active": true,
|
|
||||||
"date_joined": "2022-10-13T13:57:52.124Z",
|
|
||||||
"groups": [],
|
|
||||||
"user_permissions": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"model": "registrar.userprofile",
|
|
||||||
"pk": 3,
|
|
||||||
"fields": {
|
|
||||||
"created_at": "2022-10-04T16:39:30.531Z",
|
|
||||||
"updated_at": "2022-10-04T16:43:07.740Z",
|
|
||||||
"street1": "",
|
|
||||||
"street2": "",
|
|
||||||
"street3": "",
|
|
||||||
"city": "",
|
|
||||||
"sp": "",
|
|
||||||
"pc": "",
|
|
||||||
"cc": "",
|
|
||||||
"user": 3,
|
|
||||||
"display_name": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -12,6 +12,8 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.urls import resolve
|
from django.urls import resolve
|
||||||
|
|
||||||
from formtools.wizard.views import NamedUrlSessionWizardView # type: ignore
|
from formtools.wizard.views import NamedUrlSessionWizardView # type: ignore
|
||||||
|
from formtools.wizard.storage.session import SessionStorage # type: ignore
|
||||||
|
|
||||||
from phonenumber_field.formfields import PhoneNumberField # type: ignore
|
from phonenumber_field.formfields import PhoneNumberField # type: ignore
|
||||||
|
|
||||||
from registrar.models import Contact, DomainApplication, Domain
|
from registrar.models import Contact, DomainApplication, Domain
|
||||||
|
@ -232,7 +234,7 @@ class DotGovDomainForm(RegistrarForm):
|
||||||
requested = requested[:-4]
|
requested = requested[:-4]
|
||||||
if "." in requested:
|
if "." in requested:
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
"Please enter a top-level domain name without any periods.",
|
"Please enter a domain without any periods.",
|
||||||
code="invalid",
|
code="invalid",
|
||||||
)
|
)
|
||||||
if not Domain.string_could_be_domain(requested + ".gov"):
|
if not Domain.string_could_be_domain(requested + ".gov"):
|
||||||
|
@ -334,7 +336,10 @@ class AnythingElseForm(RegistrarForm):
|
||||||
|
|
||||||
class RequirementsForm(RegistrarForm):
|
class RequirementsForm(RegistrarForm):
|
||||||
is_policy_acknowledged = forms.BooleanField(
|
is_policy_acknowledged = forms.BooleanField(
|
||||||
label="I read and agree to the .gov domain requirements.",
|
label=(
|
||||||
|
"I read and agree to the requirements for registering "
|
||||||
|
"and operating .gov domains."
|
||||||
|
),
|
||||||
required=False, # use field validation to enforce this
|
required=False, # use field validation to enforce this
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -447,6 +452,19 @@ WIZARD_CONDITIONS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TrackingStorage(SessionStorage):
|
||||||
|
|
||||||
|
"""Storage subclass that keeps track of what the current_step has been."""
|
||||||
|
|
||||||
|
def _set_current_step(self, step):
|
||||||
|
super()._set_current_step(step)
|
||||||
|
|
||||||
|
step_history = self.extra_data.setdefault("step_history", [])
|
||||||
|
# can't serialize a set, so keep list entries unique
|
||||||
|
if step not in step_history:
|
||||||
|
step_history.append(step)
|
||||||
|
|
||||||
|
|
||||||
class ApplicationWizard(LoginRequiredMixin, NamedUrlSessionWizardView):
|
class ApplicationWizard(LoginRequiredMixin, NamedUrlSessionWizardView):
|
||||||
|
|
||||||
"""Multi-page form ("wizard") for new domain applications.
|
"""Multi-page form ("wizard") for new domain applications.
|
||||||
|
@ -462,6 +480,7 @@ class ApplicationWizard(LoginRequiredMixin, NamedUrlSessionWizardView):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
form_list = FORMS
|
form_list = FORMS
|
||||||
|
storage_name = "registrar.forms.application_wizard.TrackingStorage"
|
||||||
|
|
||||||
def get_template_names(self):
|
def get_template_names(self):
|
||||||
"""Template for the current step.
|
"""Template for the current step.
|
||||||
|
@ -483,6 +502,14 @@ class ApplicationWizard(LoginRequiredMixin, NamedUrlSessionWizardView):
|
||||||
"""Add title information to the context for all steps."""
|
"""Add title information to the context for all steps."""
|
||||||
context = super().get_context_data(form=form, **kwargs)
|
context = super().get_context_data(form=form, **kwargs)
|
||||||
context["form_titles"] = TITLES
|
context["form_titles"] = TITLES
|
||||||
|
|
||||||
|
# Add information about which steps should be unlocked
|
||||||
|
# TODO: sometimes the first step doesn't get added to the step history
|
||||||
|
# so add it here
|
||||||
|
context["visited"] = self.storage.extra_data.get("step_history", []) + [
|
||||||
|
self.steps.first
|
||||||
|
]
|
||||||
|
|
||||||
if self.steps.current == Step.ORGANIZATION_CONTACT:
|
if self.steps.current == Step.ORGANIZATION_CONTACT:
|
||||||
context["is_federal"] = self._is_federal()
|
context["is_federal"] = self._is_federal()
|
||||||
if self.steps.current == Step.REVIEW:
|
if self.steps.current == Step.REVIEW:
|
||||||
|
|
18
src/registrar/management/commands/load.py
Normal file
18
src/registrar/management/commands/load.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from auditlog.context import disable_auditlog # type: ignore
|
||||||
|
|
||||||
|
from registrar.fixtures import UserFixture, DomainApplicationFixture
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
# django-auditlog has some bugs with fixtures
|
||||||
|
# https://github.com/jazzband/django-auditlog/issues/17
|
||||||
|
with disable_auditlog():
|
||||||
|
UserFixture.load()
|
||||||
|
DomainApplicationFixture.load()
|
||||||
|
logger.info("All fixtures loaded.")
|
|
@ -1,10 +0,0 @@
|
||||||
from django.core.management.commands import loaddata
|
|
||||||
from auditlog.context import disable_auditlog # type: ignore
|
|
||||||
|
|
||||||
|
|
||||||
class Command(loaddata.Command):
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
# django-auditlog has some bugs with fixtures
|
|
||||||
# https://github.com/jazzband/django-auditlog/issues/17
|
|
||||||
with disable_auditlog():
|
|
||||||
super(Command, self).handle(*args, **options)
|
|
|
@ -93,21 +93,28 @@ class DomainApplication(TimeStampedModel):
|
||||||
ARMED_FORCES_AP = "AP", "Armed Forces Pacific (AP)"
|
ARMED_FORCES_AP = "AP", "Armed Forces Pacific (AP)"
|
||||||
|
|
||||||
class OrganizationChoices(models.TextChoices):
|
class OrganizationChoices(models.TextChoices):
|
||||||
FEDERAL = "federal", "Federal: a federal agency"
|
FEDERAL = (
|
||||||
|
"federal",
|
||||||
|
"Federal: an agency of the U.S. government's executive, legislative, "
|
||||||
|
"or judicial branches",
|
||||||
|
)
|
||||||
INTERSTATE = "interstate", "Interstate: an organization of two or more states"
|
INTERSTATE = "interstate", "Interstate: an organization of two or more states"
|
||||||
STATE_OR_TERRITORY = "state_or_territory", (
|
STATE_OR_TERRITORY = "state_or_territory", (
|
||||||
"State or Territory: One of the 50 U.S. states, the District of "
|
"State or territory: one of the 50 U.S. states, the District of "
|
||||||
"Columbia, American Samoa, Guam, Northern Mariana Islands, "
|
"Columbia, American Samoa, Guam, Northern Mariana Islands, "
|
||||||
"Puerto Rico, or the U.S. Virgin Islands"
|
"Puerto Rico, or the U.S. Virgin Islands"
|
||||||
)
|
)
|
||||||
TRIBAL = "tribal", (
|
TRIBAL = "tribal", (
|
||||||
"Tribal: a tribal government recognized by the federal or "
|
"Tribal: a tribal government recognized by the federal or "
|
||||||
"state government"
|
"a state government"
|
||||||
)
|
)
|
||||||
COUNTY = "county", "County: a county, parish, or borough"
|
COUNTY = "county", "County: a county, parish, or borough"
|
||||||
CITY = "city", "City: a city, town, township, village, etc."
|
CITY = "city", "City: a city, town, township, village, etc."
|
||||||
SPECIAL_DISTRICT = "special_district", (
|
SPECIAL_DISTRICT = "special_district", (
|
||||||
"Special District: an independent organization within a single state"
|
"Special district: an independent organization within a single state"
|
||||||
|
)
|
||||||
|
SCHOOL_DISTRICT = "school_district", (
|
||||||
|
"School district: a school district that is not part of a local government"
|
||||||
)
|
)
|
||||||
|
|
||||||
class BranchChoices(models.TextChoices):
|
class BranchChoices(models.TextChoices):
|
||||||
|
@ -288,7 +295,7 @@ class DomainApplication(TimeStampedModel):
|
||||||
federal_agency = models.TextField(
|
federal_agency = models.TextField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Top level federal agency",
|
help_text="Federal agency",
|
||||||
)
|
)
|
||||||
|
|
||||||
federal_type = models.CharField(
|
federal_type = models.CharField(
|
||||||
|
@ -296,7 +303,7 @@ class DomainApplication(TimeStampedModel):
|
||||||
choices=BranchChoices.choices,
|
choices=BranchChoices.choices,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Branch of federal government",
|
help_text="Federal government branch",
|
||||||
)
|
)
|
||||||
|
|
||||||
is_election_board = models.BooleanField(
|
is_election_board = models.BooleanField(
|
||||||
|
@ -314,13 +321,13 @@ class DomainApplication(TimeStampedModel):
|
||||||
address_line1 = models.TextField(
|
address_line1 = models.TextField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Address line 1",
|
help_text="Street address",
|
||||||
)
|
)
|
||||||
address_line2 = models.CharField(
|
address_line2 = models.CharField(
|
||||||
max_length=15,
|
max_length=15,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Address line 2",
|
help_text="Street address line 2",
|
||||||
)
|
)
|
||||||
city = models.TextField(
|
city = models.TextField(
|
||||||
null=True,
|
null=True,
|
||||||
|
@ -331,19 +338,19 @@ class DomainApplication(TimeStampedModel):
|
||||||
max_length=2,
|
max_length=2,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="State/Territory",
|
help_text="State, territory, or military post",
|
||||||
)
|
)
|
||||||
zipcode = models.CharField(
|
zipcode = models.CharField(
|
||||||
max_length=10,
|
max_length=10,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="ZIP code",
|
help_text="Zip code",
|
||||||
db_index=True,
|
db_index=True,
|
||||||
)
|
)
|
||||||
urbanization = models.TextField(
|
urbanization = models.TextField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Urbanization",
|
help_text="Urbanization (Puerto Rico only)",
|
||||||
)
|
)
|
||||||
|
|
||||||
authorizing_official = models.ForeignKey(
|
authorizing_official = models.ForeignKey(
|
||||||
|
@ -388,7 +395,7 @@ class DomainApplication(TimeStampedModel):
|
||||||
purpose = models.TextField(
|
purpose = models.TextField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Purpose of the domain",
|
help_text="Purpose of your domain",
|
||||||
)
|
)
|
||||||
|
|
||||||
other_contacts = models.ManyToManyField(
|
other_contacts = models.ManyToManyField(
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
from django.db.models.signals import post_save
|
import logging
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.management import call_command
|
||||||
|
from django.db.models.signals import post_save, post_migrate
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from .models import User, UserProfile
|
from .models import User, UserProfile
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=User)
|
@receiver(post_save, sender=User)
|
||||||
def handle_profile(sender, instance, **kwargs):
|
def handle_profile(sender, instance, **kwargs):
|
||||||
|
|
||||||
|
@ -21,3 +28,13 @@ def handle_profile(sender, instance, **kwargs):
|
||||||
instance.userprofile.save()
|
instance.userprofile.save()
|
||||||
else:
|
else:
|
||||||
UserProfile.objects.create(user=instance)
|
UserProfile.objects.create(user=instance)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_migrate)
|
||||||
|
def handle_loaddata(**kwargs):
|
||||||
|
"""Attempt to load test fixtures when in DEBUG mode."""
|
||||||
|
if settings.DEBUG:
|
||||||
|
try:
|
||||||
|
call_command("load")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(e)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
{% block form_content %}
|
{% block form_content %}
|
||||||
|
|
||||||
<h2>Who is the authorizing official for your organization</h2>
|
<h2>Who is the authorizing official for your organization?</h2>
|
||||||
|
|
||||||
<div id="instructions">
|
<div id="instructions">
|
||||||
<p>Your authorizing official is the person within your organization who can authorize your domain request. This is generally the highest ranking or highest elected official in your organization. Read more about <a href="#">who can serve as an authorizing official</a>.
|
<p>Your authorizing official is the person within your organization who can authorize your domain request. This is generally the highest ranking or highest elected official in your organization. Read more about <a href="#">who can serve as an authorizing official</a>.
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
<fieldset class="usa-fieldset">
|
<fieldset class="usa-fieldset">
|
||||||
<legend class="usa-sr-only">
|
<legend class="usa-sr-only">
|
||||||
Who is the authorizing official for your organization
|
Who is the authorizing official for your organization?
|
||||||
</legend>
|
</legend>
|
||||||
|
|
||||||
{% input_with_errors wizard.form.first_name %}
|
{% input_with_errors wizard.form.first_name %}
|
||||||
|
|
|
@ -14,7 +14,7 @@ your authorizing official, and any contacts you added.</p>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
<li> We'll review your request. This could take up to two weeks. During
|
<li> We'll review your request. This could take up to two weeks. During
|
||||||
this review we'll verify that you're eligible for a .gov domain, that
|
this review we'll verify that your organization is eligible for a .gov domain, that
|
||||||
your authorizing official approves your request, and that your domain
|
your authorizing official approves your request, and that your domain
|
||||||
meets our naming requirements.
|
meets our naming requirements.
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
|
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
|
||||||
<h2> What .gov domain do you want? </h2>
|
<h2> What .gov domain do you want? </h2>
|
||||||
<p class="domain_instructions"> After you enter your domain, we’ll make sure it’s available and that it meets some of our naming requirements. If your domain passes these initial checks, we’ll verify that it meets all of our requirements once you complete and submit the rest of the domain request form. </p>
|
<p class="domain_instructions"> After you enter your domain, we’ll make sure it’s available and that it meets some of our naming requirements. If your domain passes these initial checks, we’ll verify that it meets all of our requirements once you complete and submit the rest of this form. </p>
|
||||||
|
|
||||||
{{ wizard.management_form }}
|
{{ wizard.management_form }}
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
<h2>What is the name and mailing address of your organization?</h2>
|
<h2>What is the name and mailing address of your organization?</h2>
|
||||||
|
|
||||||
<div id="instructions">
|
<div id="instructions">
|
||||||
<p>Enter the name of the organization your represent. Your organization might be part
|
<p>Enter the name of the organization you represent. Your organization might be part
|
||||||
of a larger entity. If so, enter information about your part of the larger entity.</p>
|
of a larger entity. If so, enter information about your part of the larger entity.</p>
|
||||||
|
|
||||||
<p>Once your domain is approved, the name of your organization will be publicly listed as the domain registrant. </p>
|
<p>If your domain request is approved, the name of your organization will be publicly listed as the domain registrant. </p>
|
||||||
|
|
||||||
<p>All fields are required unless they are marked optional.</p>
|
<p>All fields are required unless they are marked optional.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
<fieldset id="organization_type__fieldset" class="usa-fieldset">
|
<fieldset id="organization_type__fieldset" class="usa-fieldset">
|
||||||
<legend class="usa-legend">
|
<legend class="usa-legend">
|
||||||
<h2> What kind of government organization do you represent?</h2>
|
<h2> What kind of U.S.-based government organization do you represent?</h2>
|
||||||
</legend>
|
</legend>
|
||||||
{{ wizard.form.organization_type.errors }}
|
{{ wizard.form.organization_type.errors }}
|
||||||
{% for choice in choices.values %}
|
{% for choice in choices.values %}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
{% block form_content %}
|
{% block form_content %}
|
||||||
|
|
||||||
<p id="instructions">We strongly encourage you to have at least two points of contact for your domain. Many organizations have an administrative point of contact and a technical point of contact. We recommend that you add at least one more contact.</p>
|
<p id="instructions">We’d like to contact other employees with administrative or technical responsibilities in your organization. For example, they could be involved in managing your organization or its technical infrastructure. This information will help us assess your eligibility and understand the purpose of the .gov domain. These contacts should be in addition to you and your authorizing official. </p>
|
||||||
<p>All fields are required unless they are marked optional.</p>
|
<p>All fields are required unless they are marked optional.</p>
|
||||||
|
|
||||||
<form class="usa-form usa-form--large" id="step__{{wizard.steps.current}}" method="post">
|
<form class="usa-form usa-form--large" id="step__{{wizard.steps.current}}" method="post">
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
{% block form_content %}
|
{% block form_content %}
|
||||||
|
|
||||||
<p id="instructions">Describe your organization’s mission or the reason for your domain request. Explain how you plan to use this domain. Will you use it for a website and/or email? Are you moving your website from another top-level domain (like .com or .org)? Read about <a href="#">activities that are prohibited on .gov domains.</a></p>
|
<p id="instructions">.Gov domain names are intended for use on the internet. They should be registered with an intent to deploy services, not simply to reserve a name. .Gov domains should not be registered for primarily internal use.</p>
|
||||||
|
|
||||||
|
<p id="instructions">Describe the reason for your domain request. Explain how you plan to use this domain. Will you use it for a website and/or email? Are you moving your website from another top-level domain (like .com or .org)? Read about <a href="#">activities that are prohibited on .gov domains.</a></p>
|
||||||
|
|
||||||
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
|
<form id="step__{{wizard.steps.current}}" class="usa-form usa-form--large" method="post">
|
||||||
<div class="usa-form-group">
|
<div class="usa-form-group">
|
||||||
|
|
|
@ -4,9 +4,7 @@
|
||||||
|
|
||||||
{% block form_content %}
|
{% block form_content %}
|
||||||
|
|
||||||
<p>The .gov domain exists to support a broad diversity of government missions and public initiatives. Generally, the .gov registry does not review or audit how government organizations use their domains.</p>
|
<p>The .gov domain exists to support a broad diversity of government missions and public initiatives. Generally, the .gov registry does not review or audit how government organizations use their domains. However, misuse of an individual .gov domain can reflect upon the integrity of the entire .gov space. There are categories of misuse that are statutorily prohibited or abusive in nature.</p>
|
||||||
|
|
||||||
<p>However, misuse of an individual .gov domain can reflect upon the integrity of the entire .gov space. There are categories of misuse that are statutorily prohibited or abusive in nature.</p>
|
|
||||||
|
|
||||||
<h2>Prohibited activities for .gov domains</h2>
|
<h2>Prohibited activities for .gov domains</h2>
|
||||||
|
|
||||||
|
@ -20,12 +18,12 @@
|
||||||
<p>A .gov domain must not be used to distribute or promote material whose distribution violates applicable law.</p>
|
<p>A .gov domain must not be used to distribute or promote material whose distribution violates applicable law.</p>
|
||||||
|
|
||||||
<h3>Malicious cyber activity </h3>
|
<h3>Malicious cyber activity </h3>
|
||||||
<p>.gov is a trusted and safe space. .gov domains must not distribute malware, host open redirects, or otherwise engage in malicious cyber activity.</p>
|
<p>.Gov is a trusted and safe space. .Gov domains must not distribute malware, host open redirects, or otherwise engage in malicious cyber activity.</p>
|
||||||
|
|
||||||
|
|
||||||
<h2>Required activities for .gov domain registrants </h2>
|
<h2>Required activities for .gov domain registrants </h2>
|
||||||
|
|
||||||
<h3>Keep your contact information update</h3>
|
<h3>Keep your contact information updated</h3>
|
||||||
<p>As a .gov domain registrant, maintain current and accurate contact information in the .gov registrar. We strongly recommend that you create and use a security contact.</p>
|
<p>As a .gov domain registrant, maintain current and accurate contact information in the .gov registrar. We strongly recommend that you create and use a security contact.</p>
|
||||||
|
|
||||||
<h3>Be responsive if we contact you</h3>
|
<h3>Be responsive if we contact you</h3>
|
||||||
|
@ -39,12 +37,87 @@
|
||||||
<li>Emails to domain contacts </li>
|
<li>Emails to domain contacts </li>
|
||||||
<li>Phone calls to domain contacts</li>
|
<li>Phone calls to domain contacts</li>
|
||||||
<li>Email or phone call to the authorizing official</li>
|
<li>Email or phone call to the authorizing official</li>
|
||||||
<li>Email or phone call to the government organization, a parent organization, or affiliated entities</li>
|
<li>Emails or phone calls to the government organization, a parent organization, or affiliated entities</li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>We understand the critical importance of the availability of .gov domains. Suspending or terminating a .gov domain is reserved only for prolonged, unresolved serious violations where the registrant is non-responsive. We will make extensive efforts to contact registrants and to identify potential solutions, and will make reasonable accommodations for remediation timelines proportional to the severity of the issue.</p>
|
<p>We understand the critical importance of the availability of .gov domains. Suspending or terminating a .gov domain is reserved only for prolonged, unresolved serious violations where the registrant is non-responsive. We will make extensive efforts to contact registrants and to identify potential solutions, and will make reasonable accommodations for remediation timelines proportional to the severity of the issue.</p>
|
||||||
|
|
||||||
|
<h2>Requirements for authorizing officials</h2>
|
||||||
|
|
||||||
|
<p>Your authorizing official is the person within your organization who can authorize your domain request. This is generally the highest ranking or highest elected official in your organization.</p>
|
||||||
|
|
||||||
|
<h3>Executive branch federal agencies</h3>
|
||||||
|
|
||||||
|
<p>Domain requests from executive branch agencies must be authorized by CIOs or agency heads.</p>
|
||||||
|
|
||||||
|
<p>Domain requests from executive branch agencies are subject to guidance issued by the U.S. Office of Management and Budget.</p>
|
||||||
|
|
||||||
|
<h3>Judicial branch federal agencies</h3>
|
||||||
|
|
||||||
|
<p>Domain requests for judicial branch agencies, except the U.S. Supreme Court, must be authorized by the director or CIO of the Administrative Office (AO) of the United States Courts.</p>
|
||||||
|
|
||||||
|
<p>Domain requests from the U.S. Supreme Court must be authorized by the director of information technology for the U.S. Supreme Court.</p>
|
||||||
|
|
||||||
|
<h3>Legislative branch federal agencies</h3>
|
||||||
|
|
||||||
|
<h4>U.S. Senate</h4>
|
||||||
|
|
||||||
|
<p>Domain requests from the U.S. Senate must come from the Senate Sergeant at Arms.</p>
|
||||||
|
|
||||||
|
<h4>U.S. House of Representatives</h4>
|
||||||
|
|
||||||
|
<p>Domain requests from the U.S. House of Representatives must come from the House Chief Administrative Officer.</p>
|
||||||
|
|
||||||
|
<h4>Other legislative branch agencies</h4>
|
||||||
|
|
||||||
|
<p>Domain requests from legislative branch agencies must come from the agency’s head or CIO.</p>
|
||||||
|
|
||||||
|
<p>Domain requests from legislative commissions must come from the head of the commission, or the head or CIO of the parent agency, if there is one.</p>
|
||||||
|
|
||||||
|
<h3>Interstate</h3>
|
||||||
|
|
||||||
|
<p>Domain requests from interstate organizations must be authorized by the highest-ranking executive (president, director, chair, or equivalent) or one of the state’s governors or CIOs.</p>
|
||||||
|
|
||||||
|
<h3>U.S. states and territories</h3>
|
||||||
|
|
||||||
|
<h4>States and territories: executive branch</h4>
|
||||||
|
|
||||||
|
<p>Domain requests from states and territories must be authorized by the governor or the state CIO.</p>
|
||||||
|
|
||||||
|
<h4>States and territories: judicial and legislative branches</h4>
|
||||||
|
|
||||||
|
<p>Domain requests from state legislatures and courts must be authorized by an agency’s CIO or highest-ranking executive.</p>
|
||||||
|
|
||||||
|
<h3>Tribal governments</h3>
|
||||||
|
|
||||||
|
<p>Domain requests from federally-recognized tribal governments must be authorized by tribal chiefs as noted by the <a href="https://www.bia.gov/service/tribal-leaders-directory">Bureau of Indian Affairs</a>.</p>
|
||||||
|
|
||||||
|
<h3>Counties</h3>
|
||||||
|
|
||||||
|
<p>Domain requests from counties must be authorized by the chair of the county commission or the equivalent highest elected official.</p>
|
||||||
|
|
||||||
|
<h3>Cities</h3>
|
||||||
|
|
||||||
|
<p>Domain requests from cities must be authorized by the mayor or the equivalent highest elected official.</p>
|
||||||
|
|
||||||
|
<h3>Special districts</h3>
|
||||||
|
|
||||||
|
<p>Domain requests from special districts must be authorized by the highest-ranking executive (president, director, chair, or equivalent) or state CIOs for state-based organizations.</p>
|
||||||
|
|
||||||
|
<h3>School districts</h3>
|
||||||
|
|
||||||
|
<p>Domain requests from school district governments must be authorized by the highest-ranking executive (the chair of a school district’s board or a superintendent).</p>
|
||||||
|
|
||||||
|
<h2>Requirements for .gov domain names</h2>
|
||||||
|
<p>.Gov domains must:</p>
|
||||||
|
<ul class="usa-list">
|
||||||
|
<li>Be available</li>
|
||||||
|
<li>Be unique</li>
|
||||||
|
<li>Relate to your organization’s name, location, and/or services</li>
|
||||||
|
<li>Be clear to the general public. Your domain name must not be easily confused with other organizations.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<h2>HSTS preloading</h2>
|
<h2>HSTS preloading</h2>
|
||||||
<p>The .gov program will preload all newly registered .gov domains for HTTP Strict Transport Security (HSTS).</p>
|
<p>The .gov program will preload all newly registered .gov domains for HTTP Strict Transport Security (HSTS).</p>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<nav aria-label="Form steps,">
|
<nav aria-label="Form steps,">
|
||||||
<ul class="usa-sidenav">
|
<ul class="usa-sidenav">
|
||||||
{% for this_step in wizard.steps.all %}
|
{% for this_step in wizard.steps.all %}
|
||||||
{% if forloop.counter <= wizard.steps.step1 %}
|
{% if this_step in visited %}
|
||||||
<li class="usa-sidenav__item">
|
<li class="usa-sidenav__item">
|
||||||
<a href="{% url wizard.url_name step=this_step %}"
|
<a href="{% url wizard.url_name step=this_step %}"
|
||||||
{% if this_step == wizard.steps.current %}class="usa-current"{% endif%}>
|
{% if this_step == wizard.steps.current %}class="usa-current"{% endif%}>
|
||||||
|
|
|
@ -40,7 +40,7 @@ class TestFormValidation(TestCase):
|
||||||
form = DotGovDomainForm(data={"requested_domain": "top-level-agency.com"})
|
form = DotGovDomainForm(data={"requested_domain": "top-level-agency.com"})
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
form.errors["requested_domain"],
|
form.errors["requested_domain"],
|
||||||
["Please enter a top-level domain name without any periods."],
|
["Please enter a domain without any periods."],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_requested_domain_invalid_characters(self):
|
def test_requested_domain_invalid_characters(self):
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.contrib.auth import get_user_model
|
||||||
from django_webtest import WebTest # type: ignore
|
from django_webtest import WebTest # type: ignore
|
||||||
|
|
||||||
from registrar.models import DomainApplication, Domain, Contact, Website
|
from registrar.models import DomainApplication, Domain, Contact, Website
|
||||||
from registrar.forms.application_wizard import TITLES
|
from registrar.forms.application_wizard import TITLES, Step
|
||||||
|
|
||||||
from .common import less_console_noise
|
from .common import less_console_noise
|
||||||
|
|
||||||
|
@ -85,7 +85,8 @@ class LoggedInTests(TestWithUser):
|
||||||
def test_application_form_view(self):
|
def test_application_form_view(self):
|
||||||
response = self.client.get("/register/", follow=True)
|
response = self.client.get("/register/", follow=True)
|
||||||
self.assertContains(
|
self.assertContains(
|
||||||
response, "What kind of government organization do you represent?"
|
response,
|
||||||
|
"What kind of U.S.-based government organization do you represent?",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -111,7 +112,9 @@ class DomainApplicationTests(TestWithUser, WebTest):
|
||||||
page = self.app.get(reverse("application")).follow()
|
page = self.app.get(reverse("application")).follow()
|
||||||
# submitting should get back the same page if the required field is empty
|
# submitting should get back the same page if the required field is empty
|
||||||
result = page.form.submit()
|
result = page.form.submit()
|
||||||
self.assertIn("What kind of government organization do you represent?", result)
|
self.assertIn(
|
||||||
|
"What kind of U.S.-based government organization do you represent?", result
|
||||||
|
)
|
||||||
|
|
||||||
def test_application_form_submission(self):
|
def test_application_form_submission(self):
|
||||||
"""Can fill out the entire form and submit.
|
"""Can fill out the entire form and submit.
|
||||||
|
@ -617,6 +620,34 @@ class DomainApplicationTests(TestWithUser, WebTest):
|
||||||
contact_page = election_result.follow()
|
contact_page = election_result.follow()
|
||||||
self.assertNotContains(contact_page, "Federal agency")
|
self.assertNotContains(contact_page, "Federal agency")
|
||||||
|
|
||||||
|
def test_application_form_section_skipping(self):
|
||||||
|
"""Can skip forward and back in sections"""
|
||||||
|
type_page = self.app.get(reverse("application")).follow()
|
||||||
|
# django-webtest does not handle cookie-based sessions well because it keeps
|
||||||
|
# resetting the session key on each new request, thus destroying the concept
|
||||||
|
# of a "session". We are going to do it manually, saving the session ID here
|
||||||
|
# and then setting the cookie on each request.
|
||||||
|
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
|
||||||
|
|
||||||
|
type_form = type_page.form
|
||||||
|
type_form["organization_type-organization_type"] = "federal"
|
||||||
|
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||||
|
type_result = type_page.form.submit()
|
||||||
|
|
||||||
|
# follow first redirect
|
||||||
|
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||||
|
federal_page = type_result.follow()
|
||||||
|
|
||||||
|
# Now on federal type page, click back to the organization type
|
||||||
|
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||||
|
new_page = federal_page.click(TITLES[Step.ORGANIZATION_TYPE], index=0)
|
||||||
|
|
||||||
|
# Should be a link to the organization_federal page
|
||||||
|
self.assertGreater(
|
||||||
|
len(new_page.html.find_all("a", href="/register/organization_federal/")),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|
||||||
@skip("WIP")
|
@skip("WIP")
|
||||||
def test_application_edit_restore(self):
|
def test_application_edit_restore(self):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue