mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-29 02:33:43 -04:00
Merge pull request #723 from alphagov/active-service
deactivate a service
This commit is contained in:
@@ -53,10 +53,19 @@ def requires_auth():
|
|||||||
return handle_admin_key(auth_token, current_app.config.get('ADMIN_CLIENT_SECRET'))
|
return handle_admin_key(auth_token, current_app.config.get('ADMIN_CLIENT_SECRET'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
api_keys = get_model_api_keys(client)
|
service = dao_fetch_service_by_id(client)
|
||||||
except DataError:
|
except DataError:
|
||||||
raise AuthError("Invalid token: service id is not the right data type", 403)
|
raise AuthError("Invalid token: service id is not the right data type", 403)
|
||||||
for api_key in api_keys:
|
except NoResultFound:
|
||||||
|
raise AuthError("Invalid token: service not found", 403)
|
||||||
|
|
||||||
|
if not service.api_keys:
|
||||||
|
raise AuthError("Invalid token: service has no API keys", 403)
|
||||||
|
|
||||||
|
if not service.active:
|
||||||
|
raise AuthError("Invalid token: service is archived", 403)
|
||||||
|
|
||||||
|
for api_key in service.api_keys:
|
||||||
try:
|
try:
|
||||||
get_decode_errors(auth_token, api_key.unsigned_secret)
|
get_decode_errors(auth_token, api_key.unsigned_secret)
|
||||||
except TokenDecodeError:
|
except TokenDecodeError:
|
||||||
@@ -67,15 +76,8 @@ def requires_auth():
|
|||||||
|
|
||||||
_request_ctx_stack.top.api_user = api_key
|
_request_ctx_stack.top.api_user = api_key
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
|
||||||
dao_fetch_service_by_id(client)
|
|
||||||
except NoResultFound:
|
|
||||||
raise AuthError("Invalid token: service not found", 403)
|
|
||||||
|
|
||||||
if not api_keys:
|
|
||||||
raise AuthError("Invalid token: service has no API keys", 403)
|
|
||||||
else:
|
else:
|
||||||
|
# service has API keys, but none matching the one the user provided
|
||||||
raise AuthError("Invalid token: signature, api token is not valid", 403)
|
raise AuthError("Invalid token: signature, api token is not valid", 403)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ def transactional(func):
|
|||||||
@wraps(func)
|
@wraps(func)
|
||||||
def commit_or_rollback(*args, **kwargs):
|
def commit_or_rollback(*args, **kwargs):
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from app import db
|
|
||||||
try:
|
try:
|
||||||
res = func(*args, **kwargs)
|
res = func(*args, **kwargs)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@@ -27,7 +26,6 @@ def version_class(model_class, history_cls=None):
|
|||||||
def versioned(func):
|
def versioned(func):
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def record_version(*args, **kwargs):
|
def record_version(*args, **kwargs):
|
||||||
from app import db
|
|
||||||
func(*args, **kwargs)
|
func(*args, **kwargs)
|
||||||
history_objects = [create_hist(obj) for obj in
|
history_objects = [create_hist(obj) for obj in
|
||||||
itertools.chain(db.session.new, db.session.dirty)
|
itertools.chain(db.session.new, db.session.dirty)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import uuid
|
import uuid
|
||||||
from datetime import date
|
from datetime import date, datetime
|
||||||
|
|
||||||
from sqlalchemy import asc, func
|
from sqlalchemy import asc, func
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
@@ -28,30 +28,68 @@ from app.models import (
|
|||||||
from app.statsd_decorators import statsd
|
from app.statsd_decorators import statsd
|
||||||
|
|
||||||
|
|
||||||
def dao_fetch_all_services():
|
def dao_fetch_all_services(only_active=False):
|
||||||
return Service.query.order_by(
|
query = Service.query.order_by(
|
||||||
asc(Service.created_at)
|
asc(Service.created_at)
|
||||||
).options(
|
).options(
|
||||||
joinedload('users')
|
joinedload('users')
|
||||||
).all()
|
)
|
||||||
|
|
||||||
|
if only_active:
|
||||||
|
query = query.filter(Service.active)
|
||||||
|
|
||||||
|
return query.all()
|
||||||
|
|
||||||
|
|
||||||
def dao_fetch_service_by_id(service_id):
|
def dao_fetch_service_by_id(service_id, only_active=False):
|
||||||
return Service.query.filter_by(
|
query = Service.query.filter_by(
|
||||||
id=service_id
|
id=service_id
|
||||||
).options(
|
).options(
|
||||||
joinedload('users')
|
joinedload('users')
|
||||||
).one()
|
)
|
||||||
|
|
||||||
|
if only_active:
|
||||||
|
query = query.filter(Service.active)
|
||||||
|
|
||||||
|
return query.one()
|
||||||
|
|
||||||
|
|
||||||
def dao_fetch_all_services_by_user(user_id):
|
def dao_fetch_all_services_by_user(user_id, only_active=False):
|
||||||
return Service.query.filter(
|
query = Service.query.filter(
|
||||||
Service.users.any(id=user_id)
|
Service.users.any(id=user_id)
|
||||||
).order_by(
|
).order_by(
|
||||||
asc(Service.created_at)
|
asc(Service.created_at)
|
||||||
).options(
|
).options(
|
||||||
joinedload('users')
|
joinedload('users')
|
||||||
).all()
|
)
|
||||||
|
|
||||||
|
if only_active:
|
||||||
|
query = query.filter(Service.active)
|
||||||
|
|
||||||
|
return query.all()
|
||||||
|
|
||||||
|
|
||||||
|
@transactional
|
||||||
|
@version_class(Service)
|
||||||
|
@version_class(Template, TemplateHistory)
|
||||||
|
@version_class(ApiKey)
|
||||||
|
def dao_deactive_service(service_id):
|
||||||
|
# have to eager load templates and api keys so that we don't flush when we loop through them
|
||||||
|
# to ensure that db.session still contains the models when it comes to creating history objects
|
||||||
|
service = Service.query.options(
|
||||||
|
joinedload('templates'),
|
||||||
|
joinedload('api_keys'),
|
||||||
|
).filter(Service.id == service_id).one()
|
||||||
|
|
||||||
|
service.active = False
|
||||||
|
service.name = '_archived_' + service.name
|
||||||
|
service.email_from = '_archived_' + service.email_from
|
||||||
|
|
||||||
|
for template in service.templates:
|
||||||
|
template.archived = True
|
||||||
|
|
||||||
|
for api_key in service.api_keys:
|
||||||
|
api_key.expiry_date = datetime.utcnow()
|
||||||
|
|
||||||
|
|
||||||
def dao_fetch_service_by_id_and_user(service_id, user_id):
|
def dao_fetch_service_by_id_and_user(service_id, user_id):
|
||||||
@@ -70,6 +108,7 @@ def dao_create_service(service, user):
|
|||||||
service.users.append(user)
|
service.users.append(user)
|
||||||
permission_dao.add_default_service_permissions_for_user(user, service)
|
permission_dao.add_default_service_permissions_for_user(user, service)
|
||||||
service.id = uuid.uuid4() # must be set now so version history model can use same id
|
service.id = uuid.uuid4() # must be set now so version history model can use same id
|
||||||
|
service.active = True
|
||||||
service.research_mode = False
|
service.research_mode = False
|
||||||
db.session.add(service)
|
db.session.add(service)
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ class Service(db.Model, Versioned):
|
|||||||
unique=False,
|
unique=False,
|
||||||
nullable=True,
|
nullable=True,
|
||||||
onupdate=datetime.datetime.utcnow)
|
onupdate=datetime.datetime.utcnow)
|
||||||
active = db.Column(db.Boolean, index=False, unique=False, nullable=False)
|
active = db.Column(db.Boolean, index=False, unique=False, nullable=False, default=True)
|
||||||
message_limit = db.Column(db.BigInteger, index=False, unique=False, nullable=False)
|
message_limit = db.Column(db.BigInteger, index=False, unique=False, nullable=False)
|
||||||
users = db.relationship(
|
users = db.relationship(
|
||||||
'User',
|
'User',
|
||||||
@@ -188,7 +188,7 @@ class ApiKey(db.Model, Versioned):
|
|||||||
name = db.Column(db.String(255), nullable=False)
|
name = db.Column(db.String(255), nullable=False)
|
||||||
secret = db.Column(db.String(255), unique=True, nullable=False)
|
secret = db.Column(db.String(255), unique=True, nullable=False)
|
||||||
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, nullable=False)
|
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, nullable=False)
|
||||||
service = db.relationship('Service', backref=db.backref('api_keys', lazy='dynamic'))
|
service = db.relationship('Service', backref='api_keys')
|
||||||
key_type = db.Column(db.String(255), db.ForeignKey('key_types.name'), index=True, nullable=False)
|
key_type = db.Column(db.String(255), db.ForeignKey('key_types.name'), index=True, nullable=False)
|
||||||
expiry_date = db.Column(db.DateTime)
|
expiry_date = db.Column(db.DateTime)
|
||||||
created_at = db.Column(
|
created_at = db.Column(
|
||||||
@@ -275,7 +275,7 @@ class Template(db.Model):
|
|||||||
content = db.Column(db.Text, index=False, unique=False, nullable=False)
|
content = db.Column(db.Text, index=False, unique=False, nullable=False)
|
||||||
archived = db.Column(db.Boolean, index=False, nullable=False, default=False)
|
archived = db.Column(db.Boolean, index=False, nullable=False, default=False)
|
||||||
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, unique=False, nullable=False)
|
service_id = db.Column(UUID(as_uuid=True), db.ForeignKey('services.id'), index=True, unique=False, nullable=False)
|
||||||
service = db.relationship('Service', backref=db.backref('templates', lazy='dynamic'))
|
service = db.relationship('Service', backref='templates')
|
||||||
subject = db.Column(db.Text, index=False, unique=False, nullable=True)
|
subject = db.Column(db.Text, index=False, unique=False, nullable=True)
|
||||||
created_by_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), index=True, nullable=False)
|
created_by_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), index=True, nullable=False)
|
||||||
created_by = db.relationship('User')
|
created_by = db.relationship('User')
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ from app.dao.services_dao import (
|
|||||||
dao_fetch_stats_for_service,
|
dao_fetch_stats_for_service,
|
||||||
dao_fetch_todays_stats_for_service,
|
dao_fetch_todays_stats_for_service,
|
||||||
dao_fetch_weekly_historical_stats_for_service,
|
dao_fetch_weekly_historical_stats_for_service,
|
||||||
dao_fetch_todays_stats_for_all_services
|
dao_fetch_todays_stats_for_all_services,
|
||||||
|
dao_deactive_service
|
||||||
)
|
)
|
||||||
from app.dao.service_whitelist_dao import (
|
from app.dao.service_whitelist_dao import (
|
||||||
dao_fetch_service_whitelist,
|
dao_fetch_service_whitelist,
|
||||||
@@ -58,13 +59,16 @@ register_errors(service_blueprint)
|
|||||||
|
|
||||||
@service_blueprint.route('', methods=['GET'])
|
@service_blueprint.route('', methods=['GET'])
|
||||||
def get_services():
|
def get_services():
|
||||||
|
only_active = request.args.get('only_active') == 'True'
|
||||||
|
detailed = request.args.get('detailed') == 'True'
|
||||||
user_id = request.args.get('user_id', None)
|
user_id = request.args.get('user_id', None)
|
||||||
|
|
||||||
if user_id:
|
if user_id:
|
||||||
services = dao_fetch_all_services_by_user(user_id)
|
services = dao_fetch_all_services_by_user(user_id, only_active)
|
||||||
elif request.args.get('detailed') == 'True':
|
elif detailed:
|
||||||
return jsonify(data=get_detailed_services())
|
return jsonify(data=get_detailed_services(only_active))
|
||||||
else:
|
else:
|
||||||
services = dao_fetch_all_services()
|
services = dao_fetch_all_services(only_active)
|
||||||
data = service_schema.dump(services, many=True).data
|
data = service_schema.dump(services, many=True).data
|
||||||
return jsonify(data=data)
|
return jsonify(data=data)
|
||||||
|
|
||||||
@@ -264,8 +268,8 @@ def get_detailed_service(service_id, today_only=False):
|
|||||||
return detailed_service_schema.dump(service).data
|
return detailed_service_schema.dump(service).data
|
||||||
|
|
||||||
|
|
||||||
def get_detailed_services():
|
def get_detailed_services(only_active=False):
|
||||||
services = {service.id: service for service in dao_fetch_all_services()}
|
services = {service.id: service for service in dao_fetch_all_services(only_active)}
|
||||||
stats = dao_fetch_todays_stats_for_all_services()
|
stats = dao_fetch_todays_stats_for_all_services()
|
||||||
|
|
||||||
for service_id, rows in itertools.groupby(stats, lambda x: x.service_id):
|
for service_id, rows in itertools.groupby(stats, lambda x: x.service_id):
|
||||||
@@ -312,6 +316,19 @@ def update_whitelist(service_id):
|
|||||||
return '', 204
|
return '', 204
|
||||||
|
|
||||||
|
|
||||||
|
@service_blueprint.route('/<uuid:service_id>/deactivate', methods=['POST'])
|
||||||
|
def deactivate_service(service_id):
|
||||||
|
service = dao_fetch_service_by_id(service_id)
|
||||||
|
|
||||||
|
if not service.active:
|
||||||
|
# assume already inactive, don't change service name
|
||||||
|
return '', 204
|
||||||
|
|
||||||
|
dao_deactive_service(service.id)
|
||||||
|
|
||||||
|
return '', 204
|
||||||
|
|
||||||
|
|
||||||
@service_blueprint.route('/<uuid:service_id>/billable-units')
|
@service_blueprint.route('/<uuid:service_id>/billable-units')
|
||||||
def get_billable_unit_count(service_id):
|
def get_billable_unit_count(service_id):
|
||||||
try:
|
try:
|
||||||
|
|||||||
23
migrations/versions/0059_set_services_to_active.py
Normal file
23
migrations/versions/0059_set_services_to_active.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
"""
|
||||||
|
we weren't previously using the services.active column , and by default it was set to false. lets set all services to
|
||||||
|
active, so that in the future we can turn it off to signify deactivating a service
|
||||||
|
|
||||||
|
Revision ID: 0059_set_services_to_active
|
||||||
|
Revises: 0058_add_letters_flag
|
||||||
|
Create Date: 2016-10-31 15:17:16.716450
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '0059_set_services_to_active'
|
||||||
|
down_revision = '0058_add_letters_flag'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.execute('UPDATE services SET active = TRUE')
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.execute('UPDATE services SET active = FALSE')
|
||||||
@@ -30,3 +30,12 @@ def create_authorization_header(service_id=None, key_type=KEY_TYPE_NORMAL):
|
|||||||
|
|
||||||
token = create_jwt_token(secret=secret, client_id=client_id)
|
token = create_jwt_token(secret=secret, client_id=client_id)
|
||||||
return 'Authorization', 'Bearer {}'.format(token)
|
return 'Authorization', 'Bearer {}'.format(token)
|
||||||
|
|
||||||
|
|
||||||
|
def unwrap_function(fn):
|
||||||
|
"""
|
||||||
|
Given a function, returns its undecorated original.
|
||||||
|
"""
|
||||||
|
while hasattr(fn, '__wrapped__'):
|
||||||
|
fn = fn.__wrapped__
|
||||||
|
return fn
|
||||||
|
|||||||
@@ -266,6 +266,17 @@ def test_authentication_returns_error_when_service_doesnt_exit(
|
|||||||
assert error_message['message'] == {'token': ['Invalid token: service not found']}
|
assert error_message['message'] == {'token': ['Invalid token: service not found']}
|
||||||
|
|
||||||
|
|
||||||
|
def test_authentication_returns_error_when_service_inactive(client, sample_api_key):
|
||||||
|
sample_api_key.service.active = False
|
||||||
|
token = create_jwt_token(secret=str(sample_api_key.id), client_id=str(sample_api_key.service_id))
|
||||||
|
|
||||||
|
response = client.get('/service', headers={'Authorization': 'Bearer {}'.format(token)})
|
||||||
|
|
||||||
|
assert response.status_code == 403
|
||||||
|
error_message = json.loads(response.get_data())
|
||||||
|
assert error_message['message'] == {'token': ['Invalid token: service is archived']}
|
||||||
|
|
||||||
|
|
||||||
def test_authentication_returns_error_when_service_has_no_secrets(notify_api,
|
def test_authentication_returns_error_when_service_has_no_secrets(notify_api,
|
||||||
sample_service,
|
sample_service,
|
||||||
fake_uuid):
|
fake_uuid):
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ def sample_service(notify_db,
|
|||||||
notify_db_session,
|
notify_db_session,
|
||||||
service_name="Sample service",
|
service_name="Sample service",
|
||||||
user=None,
|
user=None,
|
||||||
|
active=True,
|
||||||
restricted=False,
|
restricted=False,
|
||||||
limit=1000,
|
limit=1000,
|
||||||
email_from=None):
|
email_from=None):
|
||||||
@@ -139,7 +140,7 @@ def sample_service(notify_db,
|
|||||||
data = {
|
data = {
|
||||||
'name': service_name,
|
'name': service_name,
|
||||||
'message_limit': limit,
|
'message_limit': limit,
|
||||||
'active': False,
|
'active': active,
|
||||||
'restricted': restricted,
|
'restricted': restricted,
|
||||||
'email_from': email_from,
|
'email_from': email_from,
|
||||||
'created_by': user
|
'created_by': user
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ def test_create_service(sample_user):
|
|||||||
service = Service(name="service_name",
|
service = Service(name="service_name",
|
||||||
email_from="email_from",
|
email_from="email_from",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
dao_create_service(service, sample_user)
|
dao_create_service(service, sample_user)
|
||||||
@@ -68,7 +67,8 @@ def test_create_service(sample_user):
|
|||||||
assert service_db.name == "service_name"
|
assert service_db.name == "service_name"
|
||||||
assert service_db.id == service.id
|
assert service_db.id == service.id
|
||||||
assert service_db.branding == BRANDING_GOVUK
|
assert service_db.branding == BRANDING_GOVUK
|
||||||
assert not service_db.research_mode
|
assert service_db.research_mode is False
|
||||||
|
assert service.active is True
|
||||||
assert sample_user in service_db.users
|
assert sample_user in service_db.users
|
||||||
|
|
||||||
|
|
||||||
@@ -77,14 +77,12 @@ def test_cannot_create_two_services_with_same_name(sample_user):
|
|||||||
service1 = Service(name="service_name",
|
service1 = Service(name="service_name",
|
||||||
email_from="email_from1",
|
email_from="email_from1",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
|
|
||||||
service2 = Service(name="service_name",
|
service2 = Service(name="service_name",
|
||||||
email_from="email_from2",
|
email_from="email_from2",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
with pytest.raises(IntegrityError) as excinfo:
|
with pytest.raises(IntegrityError) as excinfo:
|
||||||
@@ -98,13 +96,11 @@ def test_cannot_create_two_services_with_same_email_from(sample_user):
|
|||||||
service1 = Service(name="service_name1",
|
service1 = Service(name="service_name1",
|
||||||
email_from="email_from",
|
email_from="email_from",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
service2 = Service(name="service_name2",
|
service2 = Service(name="service_name2",
|
||||||
email_from="email_from",
|
email_from="email_from",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
with pytest.raises(IntegrityError) as excinfo:
|
with pytest.raises(IntegrityError) as excinfo:
|
||||||
@@ -118,7 +114,6 @@ def test_cannot_create_service_with_no_user(notify_db_session, sample_user):
|
|||||||
service = Service(name="service_name",
|
service = Service(name="service_name",
|
||||||
email_from="email_from",
|
email_from="email_from",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
with pytest.raises(FlushError) as excinfo:
|
with pytest.raises(FlushError) as excinfo:
|
||||||
@@ -130,7 +125,6 @@ def test_should_add_user_to_service(sample_user):
|
|||||||
service = Service(name="service_name",
|
service = Service(name="service_name",
|
||||||
email_from="email_from",
|
email_from="email_from",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
dao_create_service(service, sample_user)
|
dao_create_service(service, sample_user)
|
||||||
@@ -150,7 +144,6 @@ def test_should_remove_user_from_service(sample_user):
|
|||||||
service = Service(name="service_name",
|
service = Service(name="service_name",
|
||||||
email_from="email_from",
|
email_from="email_from",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
dao_create_service(service, sample_user)
|
dao_create_service(service, sample_user)
|
||||||
@@ -244,7 +237,6 @@ def test_create_service_creates_a_history_record_with_current_data(sample_user):
|
|||||||
service = Service(name="service_name",
|
service = Service(name="service_name",
|
||||||
email_from="email_from",
|
email_from="email_from",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
dao_create_service(service, sample_user)
|
dao_create_service(service, sample_user)
|
||||||
@@ -270,7 +262,6 @@ def test_update_service_creates_a_history_record_with_current_data(sample_user):
|
|||||||
service = Service(name="service_name",
|
service = Service(name="service_name",
|
||||||
email_from="email_from",
|
email_from="email_from",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
dao_create_service(service, sample_user)
|
dao_create_service(service, sample_user)
|
||||||
@@ -299,7 +290,6 @@ def test_create_service_and_history_is_transactional(sample_user):
|
|||||||
service = Service(name=None,
|
service = Service(name=None,
|
||||||
email_from="email_from",
|
email_from="email_from",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
|
|
||||||
@@ -348,7 +338,6 @@ def test_add_existing_user_to_another_service_doesnot_change_old_permissions(sam
|
|||||||
service_one = Service(name="service_one",
|
service_one = Service(name="service_one",
|
||||||
email_from="service_one",
|
email_from="service_one",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=sample_user)
|
created_by=sample_user)
|
||||||
|
|
||||||
@@ -367,7 +356,6 @@ def test_add_existing_user_to_another_service_doesnot_change_old_permissions(sam
|
|||||||
service_two = Service(name="service_two",
|
service_two = Service(name="service_two",
|
||||||
email_from="service_two",
|
email_from="service_two",
|
||||||
message_limit=1000,
|
message_limit=1000,
|
||||||
active=True,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
created_by=other_user)
|
created_by=other_user)
|
||||||
dao_create_service(service_two, other_user)
|
dao_create_service(service_two, other_user)
|
||||||
@@ -397,7 +385,6 @@ def test_fetch_stats_filters_on_service(sample_notification):
|
|||||||
service_two = Service(name="service_two",
|
service_two = Service(name="service_two",
|
||||||
created_by=sample_notification.service.created_by,
|
created_by=sample_notification.service.created_by,
|
||||||
email_from="hello",
|
email_from="hello",
|
||||||
active=False,
|
|
||||||
restricted=False,
|
restricted=False,
|
||||||
message_limit=1000)
|
message_limit=1000)
|
||||||
dao_create_service(service_two, sample_notification.service.created_by)
|
dao_create_service(service_two, sample_notification.service.created_by)
|
||||||
|
|||||||
89
tests/app/service/test_deactivate.py
Normal file
89
tests/app/service/test_deactivate.py
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import uuid
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from app import db
|
||||||
|
from app.models import Service, TemplateHistory, ApiKey
|
||||||
|
from app.dao.services_dao import dao_deactive_service
|
||||||
|
|
||||||
|
from tests import create_authorization_header, unwrap_function
|
||||||
|
from tests.app.conftest import (
|
||||||
|
sample_template as create_template,
|
||||||
|
sample_api_key as create_api_key
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_deactivate_only_allows_post(client):
|
||||||
|
auth_header = create_authorization_header()
|
||||||
|
response = client.get('/service/{}/deactivate'.format(uuid.uuid4()), headers=[auth_header])
|
||||||
|
assert response.status_code == 405
|
||||||
|
|
||||||
|
|
||||||
|
def test_deactivate_service_errors_with_bad_service_id(client):
|
||||||
|
auth_header = create_authorization_header()
|
||||||
|
response = client.post('/service/{}/deactivate'.format(uuid.uuid4()), headers=[auth_header])
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
def test_deactivating_inactive_service_does_nothing(client, sample_service):
|
||||||
|
auth_header = create_authorization_header()
|
||||||
|
sample_service.active = False
|
||||||
|
response = client.post('/service/{}/deactivate'.format(sample_service.id), headers=[auth_header])
|
||||||
|
assert response.status_code == 204
|
||||||
|
assert sample_service.name == 'Sample service'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def deactivated_service(client, notify_db, notify_db_session, sample_service):
|
||||||
|
create_template(notify_db, notify_db_session, template_name='a')
|
||||||
|
create_template(notify_db, notify_db_session, template_name='b')
|
||||||
|
create_api_key(notify_db, notify_db_session)
|
||||||
|
create_api_key(notify_db, notify_db_session)
|
||||||
|
|
||||||
|
auth_header = create_authorization_header()
|
||||||
|
response = client.post('/service/{}/deactivate'.format(sample_service.id), headers=[auth_header])
|
||||||
|
assert response.status_code == 204
|
||||||
|
assert response.data == b''
|
||||||
|
return sample_service
|
||||||
|
|
||||||
|
|
||||||
|
def test_deactivating_service_changes_name_and_email(deactivated_service):
|
||||||
|
assert deactivated_service.name == '_archived_Sample service'
|
||||||
|
assert deactivated_service.email_from == '_archived_sample.service'
|
||||||
|
|
||||||
|
|
||||||
|
def test_deactivating_service_revokes_api_keys(deactivated_service):
|
||||||
|
assert len(deactivated_service.api_keys) == 2
|
||||||
|
for key in deactivated_service.api_keys:
|
||||||
|
assert key.expiry_date is not None
|
||||||
|
assert key.version == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_deactivating_service_archives_templates(deactivated_service):
|
||||||
|
assert len(deactivated_service.templates) == 2
|
||||||
|
for template in deactivated_service.templates:
|
||||||
|
assert template.archived is True
|
||||||
|
assert template.version == 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_deactivating_service_creates_history(deactivated_service):
|
||||||
|
ServiceHistory = Service.get_history_model()
|
||||||
|
history = ServiceHistory.query.filter_by(
|
||||||
|
id=deactivated_service.id
|
||||||
|
).order_by(
|
||||||
|
ServiceHistory.version.desc()
|
||||||
|
).first()
|
||||||
|
|
||||||
|
assert history.version == 2
|
||||||
|
assert history.active is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_deactivating_service_rolls_back_everything_on_error(sample_service, sample_api_key, sample_template):
|
||||||
|
unwrapped_deactive_service = unwrap_function(dao_deactive_service)
|
||||||
|
|
||||||
|
unwrapped_deactive_service(sample_service.id)
|
||||||
|
|
||||||
|
assert sample_service in db.session.dirty
|
||||||
|
assert sample_api_key in db.session.dirty
|
||||||
|
assert sample_template in db.session.dirty
|
||||||
@@ -11,8 +11,8 @@ from app.dao.services_dao import dao_remove_user_from_service
|
|||||||
from app.models import User, Organisation
|
from app.models import User, Organisation
|
||||||
from tests import create_authorization_header
|
from tests import create_authorization_header
|
||||||
from tests.app.conftest import (
|
from tests.app.conftest import (
|
||||||
sample_service as create_sample_service,
|
sample_service as create_service,
|
||||||
sample_service_permission as create_sample_service_permission,
|
sample_service_permission as create_service_permission,
|
||||||
sample_user as create_sample_user,
|
sample_user as create_sample_user,
|
||||||
sample_notification as create_sample_notification,
|
sample_notification as create_sample_notification,
|
||||||
sample_notification_with_job)
|
sample_notification_with_job)
|
||||||
@@ -22,9 +22,9 @@ from app.models import KEY_TYPE_TEST
|
|||||||
def test_get_service_list(notify_api, service_factory):
|
def test_get_service_list(notify_api, service_factory):
|
||||||
with notify_api.test_request_context():
|
with notify_api.test_request_context():
|
||||||
with notify_api.test_client() as client:
|
with notify_api.test_client() as client:
|
||||||
service_factory.get('one', email_from='one')
|
service_factory.get('one')
|
||||||
service_factory.get('two', email_from='two')
|
service_factory.get('two')
|
||||||
service_factory.get('three', email_from='three')
|
service_factory.get('three')
|
||||||
auth_header = create_authorization_header()
|
auth_header = create_authorization_header()
|
||||||
response = client.get(
|
response = client.get(
|
||||||
'/service',
|
'/service',
|
||||||
@@ -38,50 +38,84 @@ def test_get_service_list(notify_api, service_factory):
|
|||||||
assert json_resp['data'][2]['name'] == 'three'
|
assert json_resp['data'][2]['name'] == 'three'
|
||||||
|
|
||||||
|
|
||||||
def test_get_service_list_by_user(notify_api, sample_user, service_factory):
|
def test_get_service_list_with_only_active_flag(client, service_factory):
|
||||||
|
inactive = service_factory.get('one')
|
||||||
|
active = service_factory.get('two')
|
||||||
|
|
||||||
with notify_api.test_request_context():
|
inactive.active = False
|
||||||
with notify_api.test_client() as client:
|
|
||||||
service_factory.get('one', sample_user, email_from='one')
|
|
||||||
service_factory.get('two', sample_user, email_from='two')
|
|
||||||
service_factory.get('three', sample_user, email_from='three')
|
|
||||||
|
|
||||||
auth_header = create_authorization_header()
|
auth_header = create_authorization_header()
|
||||||
response = client.get(
|
response = client.get(
|
||||||
'/service?user_id='.format(sample_user.id),
|
'/service?only_active=True',
|
||||||
headers=[auth_header]
|
headers=[auth_header]
|
||||||
)
|
)
|
||||||
json_resp = json.loads(response.get_data(as_text=True))
|
assert response.status_code == 200
|
||||||
assert response.status_code == 200
|
json_resp = json.loads(response.get_data(as_text=True))
|
||||||
assert len(json_resp['data']) == 3
|
assert len(json_resp['data']) == 1
|
||||||
assert json_resp['data'][0]['name'] == 'one'
|
assert json_resp['data'][0]['id'] == str(active.id)
|
||||||
assert json_resp['data'][1]['name'] == 'two'
|
|
||||||
assert json_resp['data'][2]['name'] == 'three'
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_service_list_by_user_should_return_empty_list_if_no_services(notify_api, service_factory, sample_user):
|
def test_get_service_list_with_user_id_and_only_active_flag(
|
||||||
with notify_api.test_request_context():
|
notify_db,
|
||||||
with notify_api.test_client() as client:
|
notify_db_session,
|
||||||
new_user = User(
|
client,
|
||||||
name='Test User',
|
sample_user,
|
||||||
email_address='new_user@digital.cabinet-office.gov.uk',
|
service_factory
|
||||||
password='password',
|
):
|
||||||
mobile_number='+447700900986'
|
other_user = create_sample_user(notify_db, notify_db_session, email='foo@bar.gov.uk')
|
||||||
)
|
|
||||||
save_model_user(new_user)
|
|
||||||
|
|
||||||
service_factory.get('one', sample_user, email_from='one')
|
inactive = service_factory.get('one', user=sample_user)
|
||||||
service_factory.get('two', sample_user, email_from='two')
|
active = service_factory.get('two', user=sample_user)
|
||||||
service_factory.get('three', sample_user, email_from='three')
|
from_other_user = service_factory.get('three', user=other_user)
|
||||||
|
|
||||||
auth_header = create_authorization_header()
|
inactive.active = False
|
||||||
response = client.get(
|
|
||||||
'/service?user_id={}'.format(new_user.id),
|
auth_header = create_authorization_header()
|
||||||
headers=[auth_header]
|
response = client.get(
|
||||||
)
|
'/service?user_id={}&only_active=True'.format(sample_user.id),
|
||||||
json_resp = json.loads(response.get_data(as_text=True))
|
headers=[auth_header]
|
||||||
assert response.status_code == 200
|
)
|
||||||
assert len(json_resp['data']) == 0
|
assert response.status_code == 200
|
||||||
|
json_resp = json.loads(response.get_data(as_text=True))
|
||||||
|
assert len(json_resp['data']) == 1
|
||||||
|
assert json_resp['data'][0]['id'] == str(active.id)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_service_list_by_user(notify_db, notify_db_session, client, sample_user, service_factory):
|
||||||
|
other_user = create_sample_user(notify_db, notify_db_session, email='foo@bar.gov.uk')
|
||||||
|
service_factory.get('one', sample_user)
|
||||||
|
service_factory.get('two', sample_user)
|
||||||
|
service_factory.get('three', other_user)
|
||||||
|
|
||||||
|
auth_header = create_authorization_header()
|
||||||
|
response = client.get(
|
||||||
|
'/service?user_id={}'.format(sample_user.id),
|
||||||
|
headers=[auth_header]
|
||||||
|
)
|
||||||
|
json_resp = json.loads(response.get_data(as_text=True))
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert len(json_resp['data']) == 2
|
||||||
|
assert json_resp['data'][0]['name'] == 'one'
|
||||||
|
assert json_resp['data'][1]['name'] == 'two'
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_service_list_by_user_should_return_empty_list_if_no_services(
|
||||||
|
notify_db,
|
||||||
|
notify_db_session,
|
||||||
|
client,
|
||||||
|
sample_service
|
||||||
|
):
|
||||||
|
# service is already created by sample user
|
||||||
|
new_user = create_sample_user(notify_db, notify_db_session, email='foo@bar.gov.uk')
|
||||||
|
|
||||||
|
auth_header = create_authorization_header()
|
||||||
|
response = client.get(
|
||||||
|
'/service?user_id={}'.format(new_user.id),
|
||||||
|
headers=[auth_header]
|
||||||
|
)
|
||||||
|
json_resp = json.loads(response.get_data(as_text=True))
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert len(json_resp['data']) == 0
|
||||||
|
|
||||||
|
|
||||||
def test_get_service_list_should_return_empty_list_if_no_services(notify_api, notify_db, notify_db_session):
|
def test_get_service_list_should_return_empty_list_if_no_services(notify_api, notify_db, notify_db_session):
|
||||||
@@ -132,7 +166,7 @@ def test_get_service_by_id_should_404_if_no_service(notify_api, notify_db):
|
|||||||
def test_get_service_by_id_and_user(notify_api, service_factory, sample_user):
|
def test_get_service_by_id_and_user(notify_api, service_factory, sample_user):
|
||||||
with notify_api.test_request_context():
|
with notify_api.test_request_context():
|
||||||
with notify_api.test_client() as client:
|
with notify_api.test_client() as client:
|
||||||
service = service_factory.get('new service', sample_user, email_from='new.service')
|
service = service_factory.get('new.service', sample_user)
|
||||||
auth_header = create_authorization_header()
|
auth_header = create_authorization_header()
|
||||||
resp = client.get(
|
resp = client.get(
|
||||||
'/service/{}?user_id={}'.format(service.id, sample_user.id),
|
'/service/{}?user_id={}'.format(service.id, sample_user.id),
|
||||||
@@ -285,7 +319,6 @@ def test_should_not_create_service_if_missing_data(notify_api, sample_user):
|
|||||||
assert resp.status_code == 400
|
assert resp.status_code == 400
|
||||||
assert json_resp['result'] == 'error'
|
assert json_resp['result'] == 'error'
|
||||||
assert 'Missing data for required field.' in json_resp['message']['name']
|
assert 'Missing data for required field.' in json_resp['message']['name']
|
||||||
assert 'Missing data for required field.' in json_resp['message']['active']
|
|
||||||
assert 'Missing data for required field.' in json_resp['message']['message_limit']
|
assert 'Missing data for required field.' in json_resp['message']['message_limit']
|
||||||
assert 'Missing data for required field.' in json_resp['message']['restricted']
|
assert 'Missing data for required field.' in json_resp['message']['restricted']
|
||||||
|
|
||||||
@@ -446,7 +479,7 @@ def test_should_not_update_service_with_duplicate_name(notify_api,
|
|||||||
with notify_api.test_request_context():
|
with notify_api.test_request_context():
|
||||||
with notify_api.test_client() as client:
|
with notify_api.test_client() as client:
|
||||||
service_name = "another name"
|
service_name = "another name"
|
||||||
service = create_sample_service(
|
service = create_service(
|
||||||
notify_db,
|
notify_db,
|
||||||
notify_db_session,
|
notify_db_session,
|
||||||
service_name=service_name,
|
service_name=service_name,
|
||||||
@@ -479,7 +512,7 @@ def test_should_not_update_service_with_duplicate_email_from(notify_api,
|
|||||||
with notify_api.test_client() as client:
|
with notify_api.test_client() as client:
|
||||||
email_from = "duplicate.name"
|
email_from = "duplicate.name"
|
||||||
service_name = "duplicate name"
|
service_name = "duplicate name"
|
||||||
service = create_sample_service(
|
service = create_service(
|
||||||
notify_db,
|
notify_db,
|
||||||
notify_db_session,
|
notify_db_session,
|
||||||
service_name=service_name,
|
service_name=service_name,
|
||||||
@@ -915,7 +948,7 @@ def test_remove_user_from_service(notify_api, notify_db, notify_db_session, samp
|
|||||||
notify_db_session,
|
notify_db_session,
|
||||||
email="new@digital.cabinet-office.gov.uk")
|
email="new@digital.cabinet-office.gov.uk")
|
||||||
# Simulates successfully adding a user to the service
|
# Simulates successfully adding a user to the service
|
||||||
second_permission = create_sample_service_permission(
|
second_permission = create_service_permission(
|
||||||
notify_db,
|
notify_db,
|
||||||
notify_db_session,
|
notify_db_session,
|
||||||
user=second_user)
|
user=second_user)
|
||||||
@@ -1019,8 +1052,8 @@ def test_set_reply_to_email_for_service(notify_api, sample_service):
|
|||||||
|
|
||||||
def test_get_all_notifications_for_service_in_order(notify_api, notify_db, notify_db_session):
|
def test_get_all_notifications_for_service_in_order(notify_api, notify_db, notify_db_session):
|
||||||
with notify_api.test_request_context(), notify_api.test_client() as client:
|
with notify_api.test_request_context(), notify_api.test_client() as client:
|
||||||
service_1 = create_sample_service(notify_db, notify_db_session, service_name="1", email_from='1')
|
service_1 = create_service(notify_db, notify_db_session, service_name="1", email_from='1')
|
||||||
service_2 = create_sample_service(notify_db, notify_db_session, service_name="2", email_from='2')
|
service_2 = create_service(notify_db, notify_db_session, service_name="2", email_from='2')
|
||||||
|
|
||||||
create_sample_notification(notify_db, notify_db_session, service=service_2)
|
create_sample_notification(notify_db, notify_db_session, service=service_2)
|
||||||
|
|
||||||
@@ -1240,8 +1273,8 @@ def test_get_services_with_detailed_flag(notify_api, notify_db, notify_db_sessio
|
|||||||
def test_get_detailed_services_groups_by_service(notify_db, notify_db_session):
|
def test_get_detailed_services_groups_by_service(notify_db, notify_db_session):
|
||||||
from app.service.rest import get_detailed_services
|
from app.service.rest import get_detailed_services
|
||||||
|
|
||||||
service_1 = create_sample_service(notify_db, notify_db_session, service_name="1", email_from='1')
|
service_1 = create_service(notify_db, notify_db_session, service_name="1", email_from='1')
|
||||||
service_2 = create_sample_service(notify_db, notify_db_session, service_name="2", email_from='2')
|
service_2 = create_service(notify_db, notify_db_session, service_name="2", email_from='2')
|
||||||
|
|
||||||
create_sample_notification(notify_db, notify_db_session, service=service_1, status='created')
|
create_sample_notification(notify_db, notify_db_session, service=service_1, status='created')
|
||||||
create_sample_notification(notify_db, notify_db_session, service=service_2, status='created')
|
create_sample_notification(notify_db, notify_db_session, service=service_2, status='created')
|
||||||
@@ -1267,8 +1300,8 @@ def test_get_detailed_services_groups_by_service(notify_db, notify_db_session):
|
|||||||
def test_get_detailed_services_includes_services_with_no_notifications(notify_db, notify_db_session):
|
def test_get_detailed_services_includes_services_with_no_notifications(notify_db, notify_db_session):
|
||||||
from app.service.rest import get_detailed_services
|
from app.service.rest import get_detailed_services
|
||||||
|
|
||||||
service_1 = create_sample_service(notify_db, notify_db_session, service_name="1", email_from='1')
|
service_1 = create_service(notify_db, notify_db_session, service_name="1", email_from='1')
|
||||||
service_2 = create_sample_service(notify_db, notify_db_session, service_name="2", email_from='2')
|
service_2 = create_service(notify_db, notify_db_session, service_name="2", email_from='2')
|
||||||
|
|
||||||
create_sample_notification(notify_db, notify_db_session, service=service_1)
|
create_sample_notification(notify_db, notify_db_session, service=service_1)
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ def client(notify_api):
|
|||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def notify_db(notify_api):
|
def notify_db(notify_api):
|
||||||
|
assert db.engine.url.database != 'notification_api', 'dont run tests against main db'
|
||||||
Migrate(notify_api, db)
|
Migrate(notify_api, db)
|
||||||
Manager(db, MigrateCommand)
|
Manager(db, MigrateCommand)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
|||||||
Reference in New Issue
Block a user