mirror of
https://github.com/GSA/notifications-api.git
synced 2026-02-03 18:01:08 -05:00
Merge pull request #97 from GSA/stvnrlly-create-user-command
Add command to create user in non-prod environments
This commit is contained in:
@@ -30,7 +30,7 @@ Our other repositories are:
|
||||
### Common dev work
|
||||
|
||||
- [Local setup](#local-setup)
|
||||
- [Testing](./docs/testing.md)
|
||||
- [Testing](./docs/testing.md), both automated and manual
|
||||
- [Deploying](./docs/deploying.md)
|
||||
- [Running one-off tasks](./docs/one-off-tasks.md)
|
||||
|
||||
|
||||
@@ -340,33 +340,6 @@ def update_jobs_archived_flag(start_date, end_date):
|
||||
current_app.logger.info('Total archived jobs = {}'.format(total_updated))
|
||||
|
||||
|
||||
@notify_command(name='update-emails-to-remove-gsi')
|
||||
@click.option('-s', '--service_id', required=True, help="service id. Update all user.email_address to remove .gsi")
|
||||
@statsd(namespace="tasks")
|
||||
def update_emails_to_remove_gsi(service_id):
|
||||
users_to_update = """SELECT u.id user_id, u.name, email_address, s.id, s.name
|
||||
FROM users u
|
||||
JOIN user_to_service us on (u.id = us.user_id)
|
||||
JOIN services s on (s.id = us.service_id)
|
||||
WHERE s.id = :service_id
|
||||
AND u.email_address ilike ('%.gsi.gov.uk%')
|
||||
"""
|
||||
results = db.session.execute(users_to_update, {'service_id': service_id})
|
||||
print("Updating {} users.".format(results.rowcount))
|
||||
|
||||
for user in results:
|
||||
print('User with id {} updated'.format(user.user_id))
|
||||
|
||||
update_stmt = """
|
||||
UPDATE users
|
||||
SET email_address = replace(replace(email_address, '.gsi.gov.uk', '.gov.uk'), '.GSI.GOV.UK', '.GOV.UK'),
|
||||
updated_at = now()
|
||||
WHERE id = :user_id
|
||||
"""
|
||||
db.session.execute(update_stmt, {'user_id': str(user.user_id)})
|
||||
db.session.commit()
|
||||
|
||||
|
||||
@notify_command(name='replay-daily-sorted-count-files')
|
||||
@click.option('-f', '--file_extension', required=False, help="File extension to search for, defaults to rs.txt")
|
||||
@statsd(namespace="tasks")
|
||||
@@ -733,3 +706,43 @@ def populate_annual_billing_with_defaults(year, missing_services_only):
|
||||
else:
|
||||
print(f'update service {service.id} with default')
|
||||
set_default_free_allowance_for_service(service, year)
|
||||
|
||||
|
||||
def validate_mobile(ctx, param, value):
|
||||
if (len(''.join(i for i in value if i.isdigit())) != 10):
|
||||
raise click.BadParameter("mobile number must have 10 digits")
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
@notify_command(name='create-test-user')
|
||||
@click.option('-n', '--name', required=True, prompt=True)
|
||||
@click.option('-e', '--email', required=True, prompt=True) # TODO: require valid email
|
||||
@click.option('-m', '--mobile_number',
|
||||
required=True, prompt=True, callback=validate_mobile)
|
||||
@click.option('-p', '--password',
|
||||
required=True, prompt=True, hide_input=True, confirmation_prompt=True)
|
||||
@click.option('-a', '--auth_type', default="sms_auth")
|
||||
@click.option('-s', '--state', default="active")
|
||||
@click.option('-d', '--admin', default=False, type=bool)
|
||||
def create_test_user(name, email, mobile_number, password, auth_type, state, admin):
|
||||
if os.getenv('NOTIFY_ENVIRONMENT', '') not in ['development', 'test']:
|
||||
current_app.logger.error('Can only be run in development')
|
||||
return
|
||||
|
||||
data = {
|
||||
'name': name,
|
||||
'email_address': email,
|
||||
'mobile_number': mobile_number,
|
||||
'password': password,
|
||||
'auth_type': auth_type,
|
||||
'state': state, # skip the email verification for our test user
|
||||
'platform_admin': admin,
|
||||
}
|
||||
user = User(**data)
|
||||
try:
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
except IntegrityError:
|
||||
print("duplicate user", user.name)
|
||||
db.session.rollback()
|
||||
|
||||
@@ -2,14 +2,18 @@
|
||||
|
||||
For these, we're using Flask commands, which live in [`/app/commands.py`](../app/commands.py).
|
||||
|
||||
This includes things that might be one-time operations! Using a command allows the operation to be tested,
|
||||
both with `pytest` and with trial runs.
|
||||
This includes things that might be one-time operations! If we're running it on production, it should be a Flask
|
||||
command Using a command allows the operation to be tested, both with `pytest` and with trial runs in staging.
|
||||
|
||||
To see information about available commands, you can get a list with:
|
||||
|
||||
`pipenv run flask command`
|
||||
|
||||
Appending `--help` to any command will give you more information about parameters.
|
||||
|
||||
To run a command on cloud.gov, use this format:
|
||||
|
||||
```
|
||||
cf run-task CLOUD-GOV-APP --commmand "YOUR COMMAND HERE" --name YOUR-COMMAND
|
||||
```
|
||||
`cf run-task CLOUD-GOV-APP --commmand "YOUR COMMAND HERE" --name YOUR-COMMAND`
|
||||
|
||||
[Here's more documentation](https://docs.cloudfoundry.org/devguide/using-tasks.html) about Cloud Foundry tasks.
|
||||
|
||||
|
||||
@@ -23,6 +23,14 @@ We're using GitHub Actions. See [/.github](../.github/) for the configuration.
|
||||
|
||||
In addition to commit-triggered scans, the `daily_checks.yml` workflow runs the relevant dependency audits, static scan, and/or dynamic scans at 10am UTC each day. Developers will be notified of failures in daily scans by GitHub notifications.
|
||||
|
||||
## Manual testing
|
||||
|
||||
If you're checking out the system locally, you may want to create a user quickly.
|
||||
|
||||
`pipenv run flask command create-test-user`
|
||||
|
||||
This will run an interactive prompt to create a user, and then mark that user as active. *Use a real mobile number* if you want to log in, as the SMS auth code will be sent here.
|
||||
|
||||
## To run a local OWASP scan
|
||||
|
||||
1. Run `make run-flask` from within the dev container.
|
||||
|
||||
@@ -1,14 +1,45 @@
|
||||
import pytest
|
||||
|
||||
from app.commands import (
|
||||
create_test_user,
|
||||
insert_inbound_numbers_from_file,
|
||||
populate_annual_billing_with_defaults,
|
||||
)
|
||||
from app.dao.inbound_numbers_dao import dao_get_available_inbound_numbers
|
||||
from app.models import AnnualBilling
|
||||
from app.models import AnnualBilling, User
|
||||
from tests.app.db import create_annual_billing, create_service
|
||||
|
||||
|
||||
def test_create_test_user_command(notify_db_session, notify_api):
|
||||
|
||||
# number of users before adding ours
|
||||
user_count = User.query.count()
|
||||
|
||||
# run the command
|
||||
notify_api.test_cli_runner().invoke(
|
||||
create_test_user, [
|
||||
'--email', 'somebody@fake.gov',
|
||||
'--mobile_number', '555-555-5555',
|
||||
'--password', 'correct horse battery staple',
|
||||
'--name', 'Fake Personson',
|
||||
# '--auth_type', 'sms_auth', # this is the default
|
||||
# '--state', 'active', # this is the default
|
||||
# '--admin', 'False', # this is the default
|
||||
]
|
||||
)
|
||||
|
||||
# there should be one more user
|
||||
assert User.query.count() == user_count + 1
|
||||
|
||||
# that user should be the one we added
|
||||
user = User.query.filter_by(
|
||||
name='Fake Personson'
|
||||
).first()
|
||||
assert user.email_address == 'somebody@fake.gov'
|
||||
assert user.auth_type == 'sms_auth'
|
||||
assert user.state == 'active'
|
||||
|
||||
|
||||
def test_insert_inbound_numbers_from_file(notify_db_session, notify_api, tmpdir):
|
||||
numbers_file = tmpdir.join("numbers.txt")
|
||||
numbers_file.write("07700900373\n07700900473\n07700900375\n\n\n\n")
|
||||
|
||||
Reference in New Issue
Block a user