diff --git a/app/schemas.py b/app/schemas.py index 192428f4e..1cebafbbc 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -74,7 +74,11 @@ class UUIDsAsStringsMixin: ] -class BaseSchema(ma.ModelSchema): +class BaseSchema(ma.SQLAlchemyAutoSchema): + + class Meta: + load_instance = True + include_relationships = True def __init__(self, load_json=False, *args, **kwargs): self.load_json = load_json @@ -108,7 +112,7 @@ class UserSchema(BaseSchema): retval[service_id].append(x.permission) return retval - class Meta: + class Meta(BaseSchema.Meta): model = models.User exclude = ( "updated_at", @@ -145,7 +149,7 @@ class UserSchema(BaseSchema): class UserUpdateAttributeSchema(BaseSchema): auth_type = field_for(models.User, 'auth_type') - class Meta: + class Meta(BaseSchema.Meta): model = models.User exclude = ( 'id', 'updated_at', 'created_at', 'user_to_service', @@ -182,7 +186,7 @@ class UserUpdateAttributeSchema(BaseSchema): class UserUpdatePasswordSchema(BaseSchema): - class Meta: + class Meta(BaseSchema.Meta): model = models.User only = ('password') strict = True @@ -197,7 +201,7 @@ class UserUpdatePasswordSchema(BaseSchema): class ProviderDetailsSchema(BaseSchema): created_by = fields.Nested(UserSchema, only=['id', 'name', 'email_address'], dump_only=True) - class Meta: + class Meta(BaseSchema.Meta): model = models.ProviderDetails exclude = ("provider_rates", "provider_stats") strict = True @@ -206,7 +210,7 @@ class ProviderDetailsSchema(BaseSchema): class ProviderDetailsHistorySchema(BaseSchema): created_by = fields.Nested(UserSchema, only=['id', 'name', 'email_address'], dump_only=True) - class Meta: + class Meta(BaseSchema.Meta): model = models.ProviderDetailsHistory exclude = ("provider_rates", "provider_stats") strict = True @@ -236,7 +240,7 @@ class ServiceSchema(BaseSchema, UUIDsAsStringsMixin): def get_letter_contact(self, service): return service.get_default_letter_contact() - class Meta: + class Meta(BaseSchema.Meta): model = models.Service exclude = ( 'updated_at', @@ -296,7 +300,7 @@ class DetailedServiceSchema(BaseSchema): statistics = fields.Dict() organisation_type = field_for(models.Service, 'organisation_type') - class Meta: + class Meta(BaseSchema.Meta): model = models.Service exclude = ( 'api_keys', @@ -337,7 +341,7 @@ class DetailedServiceSchema(BaseSchema): class NotificationModelSchema(BaseSchema): - class Meta: + class Meta(BaseSchema.Meta): model = models.Notification strict = True exclude = ('_personalisation', 'job', 'service', 'template', 'api_key',) @@ -355,7 +359,7 @@ class BaseTemplateSchema(BaseSchema): def get_reply_to_text(self, template): return template.get_reply_to_text() - class Meta: + class Meta(BaseSchema.Meta): model = models.Template exclude = ("service_id", "jobs", "service_letter_contact_id", "broadcast_messages") strict = True @@ -421,7 +425,7 @@ class TemplateHistorySchema(BaseSchema): def get_reply_to_text(self, template): return template.get_reply_to_text() - class Meta: + class Meta(BaseSchema.Meta): model = models.TemplateHistory @@ -430,7 +434,7 @@ class ApiKeySchema(BaseSchema): created_by = field_for(models.ApiKey, 'created_by', required=True) key_type = field_for(models.ApiKey, 'key_type', required=True) - class Meta: + class Meta(BaseSchema.Meta): model = models.ApiKey exclude = ("service", "_secret") strict = True @@ -462,7 +466,7 @@ class JobSchema(BaseSchema): _validate_datetime_not_in_past(value) _validate_datetime_not_more_than_96_hours_in_future(value) - class Meta: + class Meta(BaseSchema.Meta): model = models.Job exclude = ( 'notifications', @@ -515,7 +519,7 @@ class SmsTemplateNotificationSchema(SmsNotificationSchema): class NotificationWithTemplateSchema(BaseSchema): - class Meta: + class Meta(BaseSchema.Meta): model = models.Notification strict = True exclude = ('_personalisation', 'scheduled_notification') @@ -594,7 +598,7 @@ class NotificationWithPersonalisationSchema(NotificationWithTemplateSchema): class InvitedUserSchema(BaseSchema): auth_type = field_for(models.InvitedUser, 'auth_type') - class Meta: + class Meta(BaseSchema.Meta): model = models.InvitedUser strict = True @@ -697,7 +701,7 @@ class ApiKeyHistorySchema(ma.Schema): class EventSchema(BaseSchema): - class Meta: + class Meta(BaseSchema.Meta): model = models.Event strict = True diff --git a/requirements-app.txt b/requirements-app.txt index 38a4f9cbf..a71754683 100644 --- a/requirements-app.txt +++ b/requirements-app.txt @@ -1,30 +1,30 @@ # Run `make freeze-requirements` to update requirements.txt # with package version changes made in requirements-app.txt -cffi==1.14.3 +cffi==1.14.4 celery[sqs]==3.1.26.post2 # pyup: <4 docopt==0.6.2 Flask-Bcrypt==0.7.1 -flask-marshmallow==0.11.0 +flask-marshmallow==0.14.0 Flask-Migrate==2.5.3 git+https://github.com/mitsuhiko/flask-sqlalchemy.git@500e732dd1b975a56ab06a46bd1a20a21e682262#egg=Flask-SQLAlchemy==2.3.2.dev20190108 Flask==1.1.2 click-datetime==0.2 -eventlet==0.29.1 +eventlet==0.30.0 gunicorn==20.0.4 iso8601==0.1.13 itsdangerous==1.1.0 jsonschema==3.2.0 -marshmallow-sqlalchemy==0.23.1 +marshmallow-sqlalchemy==0.23.1 # pyup: <0.24.1 # marshmallow v3 throws errors marshmallow==2.21.0 # pyup: <3 # v3 throws errors psycopg2-binary==2.8.6 -PyJWT==1.7.1 -SQLAlchemy==1.3.20 +PyJWT==2.0.0 +SQLAlchemy==1.3.22 strict-rfc3339==0.7 rfc3987==1.3.8 -cachetools==4.1.1 +cachetools==4.2.0 -notifications-python-client==5.7.0 +notifications-python-client==5.7.1 # PaaS awscli-cwlogs==1.4.6 @@ -32,5 +32,5 @@ awscli-cwlogs==1.4.6 git+https://github.com/alphagov/notifications-utils.git@43.5.9#egg=notifications-utils==43.5.9 # gds-metrics requires prometheseus 0.2.0, override that requirement as 0.7.1 brings significant performance gains -prometheus-client==0.8.0 +prometheus-client==0.9.0 gds-metrics==0.2.4 diff --git a/requirements.txt b/requirements.txt index 794dc2d75..3e1cefe8c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,30 +3,30 @@ # Run `make freeze-requirements` to update requirements.txt # with package version changes made in requirements-app.txt -cffi==1.14.3 +cffi==1.14.4 celery[sqs]==3.1.26.post2 # pyup: <4 docopt==0.6.2 Flask-Bcrypt==0.7.1 -flask-marshmallow==0.11.0 +flask-marshmallow==0.14.0 Flask-Migrate==2.5.3 git+https://github.com/mitsuhiko/flask-sqlalchemy.git@500e732dd1b975a56ab06a46bd1a20a21e682262#egg=Flask-SQLAlchemy==2.3.2.dev20190108 Flask==1.1.2 click-datetime==0.2 -eventlet==0.29.1 +eventlet==0.30.0 gunicorn==20.0.4 iso8601==0.1.13 itsdangerous==1.1.0 jsonschema==3.2.0 -marshmallow-sqlalchemy==0.23.1 +marshmallow-sqlalchemy==0.23.1 # pyup: <0.24.1 # marshmallow v3 throws errors marshmallow==2.21.0 # pyup: <3 # v3 throws errors psycopg2-binary==2.8.6 -PyJWT==1.7.1 -SQLAlchemy==1.3.20 +PyJWT==2.0.0 +SQLAlchemy==1.3.22 strict-rfc3339==0.7 rfc3987==1.3.8 -cachetools==4.1.1 +cachetools==4.2.0 -notifications-python-client==5.7.0 +notifications-python-client==5.7.1 # PaaS awscli-cwlogs==1.4.6 @@ -34,7 +34,7 @@ awscli-cwlogs==1.4.6 git+https://github.com/alphagov/notifications-utils.git@43.5.9#egg=notifications-utils==43.5.9 # gds-metrics requires prometheseus 0.2.0, override that requirement as 0.7.1 brings significant performance gains -prometheus-client==0.8.0 +prometheus-client==0.9.0 gds-metrics==0.2.4 ## The following requirements were added by pip freeze: @@ -42,14 +42,14 @@ alembic==1.4.3 amqp==1.4.9 anyjson==0.3.3 attrs==20.3.0 -awscli==1.18.199 +awscli==1.18.206 bcrypt==3.2.0 billiard==3.3.0.23 bleach==3.2.1 blinker==1.4 boto==2.49.0 -boto3==1.16.39 -botocore==1.19.39 +boto3==1.16.46 +botocore==1.19.46 certifi==2020.12.5 chardet==4.0.0 click==7.1.2 @@ -81,7 +81,7 @@ pyrsistent==0.17.3 python-dateutil==2.8.1 python-editor==1.0.4 python-json-logger==2.0.1 -pytz==2020.4 +pytz==2020.5 PyYAML==5.3.1 redis==3.5.3 requests==2.25.1 diff --git a/tests/app/authentication/test_authentication.py b/tests/app/authentication/test_authentication.py index e799bb619..b40f8b616 100644 --- a/tests/app/authentication/test_authentication.py +++ b/tests/app/authentication/test_authentication.py @@ -63,7 +63,7 @@ def test_should_not_allow_request_with_no_iss(client, auth_fn): 'iat': int(time.time()) } - token = jwt.encode(payload=claims, key=str(uuid.uuid4()), headers=headers).decode() + token = jwt.encode(payload=claims, key=str(uuid.uuid4()), headers=headers) request.headers = {'Authorization': 'Bearer {}'.format(token)} with pytest.raises(AuthError) as exc: @@ -84,7 +84,7 @@ def test_auth_should_not_allow_request_with_no_iat(client, sample_api_key): # 'iat': not provided } - token = jwt.encode(payload=claims, key=str(uuid.uuid4()), headers=headers).decode() + token = jwt.encode(payload=claims, key=str(uuid.uuid4()), headers=headers) request.headers = {'Authorization': 'Bearer {}'.format(token)} with pytest.raises(AuthError) as exc: @@ -105,7 +105,7 @@ def test_auth_should_not_allow_request_with_non_hs256_algorithm(client, sample_a 'iat': int(time.time()) } - token = jwt.encode(payload=claims, key=str(uuid.uuid4()), headers=headers).decode() + token = jwt.encode(payload=claims, key=str(uuid.uuid4()), headers=headers) request.headers = {'Authorization': 'Bearer {}'.format(token)} with pytest.raises(AuthError) as exc: @@ -128,7 +128,7 @@ def test_admin_auth_should_not_allow_request_with_no_iat(client): # 'iat': not provided } - token = jwt.encode(payload=claims, key=secret, headers=headers).decode() + token = jwt.encode(payload=claims, key=secret, headers=headers) request.headers = {'Authorization': 'Bearer {}'.format(token)} with pytest.raises(AuthError) as exc: @@ -151,7 +151,7 @@ def test_admin_auth_should_not_allow_request_with_old_iat(client): 'iat': int(time.time()) - 60 } - token = jwt.encode(payload=claims, key=secret, headers=headers).decode() + token = jwt.encode(payload=claims, key=secret, headers=headers) request.headers = {'Authorization': 'Bearer {}'.format(token)} with pytest.raises(AuthError) as exc: @@ -174,7 +174,7 @@ def test_auth_should_not_allow_request_with_extra_claims(client, sample_api_key) 'aud': 'notifications.service.gov.uk' # extra claim that we don't support } - token = jwt.encode(payload=claims, key=key, headers=headers).decode() + token = jwt.encode(payload=claims, key=key, headers=headers) request.headers = {'Authorization': 'Bearer {}'.format(token)} with pytest.raises(AuthError) as exc: