From 2486c17dc9d48266e834fda36590560a2a0d28bd Mon Sep 17 00:00:00 2001 From: Rebecca Law Date: Thu, 21 Jan 2016 16:53:53 +0000 Subject: [PATCH] Add unique constraint for api_key on service_id and name --- app/models.py | 8 ++++-- .../0008_unique_service_to_key_name.py | 26 +++++++++++++++++++ tests/app/dao/test_api_key_dao.py | 13 ++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 migrations/versions/0008_unique_service_to_key_name.py diff --git a/app/models.py b/app/models.py index 4721cdb62..c42e972c8 100644 --- a/app/models.py +++ b/app/models.py @@ -1,6 +1,7 @@ +from sqlalchemy import UniqueConstraint + from . import db import datetime - from sqlalchemy.dialects.postgresql import UUID from app.encryption import ( hashpw, @@ -95,6 +96,10 @@ class ApiKey(db.Model): service = db.relationship('Service', backref=db.backref('api_keys', lazy='dynamic')) expiry_date = db.Column(db.DateTime) + __table_args__ = ( + UniqueConstraint('service_id', 'name', name='uix_service_to_key_name'), + ) + TEMPLATE_TYPES = ['sms', 'email', 'letter'] @@ -123,7 +128,6 @@ class Template(db.Model): class Job(db.Model): - __tablename__ = 'jobs' id = db.Column(UUID(as_uuid=True), primary_key=True) diff --git a/migrations/versions/0008_unique_service_to_key_name.py b/migrations/versions/0008_unique_service_to_key_name.py new file mode 100644 index 000000000..6226b23c0 --- /dev/null +++ b/migrations/versions/0008_unique_service_to_key_name.py @@ -0,0 +1,26 @@ +"""empty message + +Revision ID: 0008_unique_service_to_key_name +Revises: 0007_change_to_api_keys +Create Date: 2016-01-21 16:14:51.773001 + +""" + +# revision identifiers, used by Alembic. +revision = '0008_unique_service_to_key_name' +down_revision = '0007_change_to_api_keys' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.create_unique_constraint('uix_service_to_key_name', 'api_key', ['service_id', 'name']) + ### end Alembic commands ### + + +def downgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint('uix_service_to_key_name', 'api_key', type_='unique') + ### end Alembic commands ### diff --git a/tests/app/dao/test_api_key_dao.py b/tests/app/dao/test_api_key_dao.py index 994b863e7..fbb33e517 100644 --- a/tests/app/dao/test_api_key_dao.py +++ b/tests/app/dao/test_api_key_dao.py @@ -73,3 +73,16 @@ def test_get_unsigned_secret_returns_key(notify_api, unsigned_api_key = get_unsigned_secret(sample_api_key.id) assert sample_api_key.secret != unsigned_api_key assert unsigned_api_key == _get_secret(sample_api_key.secret) + + +def test_should_not_allow_duplicate_key_names_per_service(notify_api, + notify_db, + notify_db_session, + sample_api_key): + api_key = ApiKey( + **{'id': sample_api_key.id + 1, 'service_id': sample_api_key.service_id, 'name': sample_api_key.name}) + try: + save_model_api_key(api_key) + fail("should throw IntegrityError") + except: + pass