diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 80c4e5899..5d8efaba8 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,3 +1,10 @@ +## February 08, 2024 +- **Task**Consolidate and re-write old migration files [DESENG-452](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-452) + - Change some foreign key field to nullbale false in model files + - Change `rejected_reason_other` to nullable true in `submission` model + - Generated new migration file based on the pending model changes which confirmed to be valid + - Updated Unit test of email verfication to send type to the api + ## February 06, 2024 - **Task**Convert keycloak groups to composite roles for permission levels [DESENG-447](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-447) - Commented out unit test related to Keycloak groups diff --git a/met-api/migrations/versions/37176ea4708d_.py b/met-api/migrations/versions/37176ea4708d_.py new file mode 100644 index 000000000..3ae7a8545 --- /dev/null +++ b/met-api/migrations/versions/37176ea4708d_.py @@ -0,0 +1,91 @@ +"""empty message + +Revision ID: 37176ea4708d +Revises: ec0128056a33 +Create Date: 2024-02-08 12:40:09.456210 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '37176ea4708d' +down_revision = 'ec0128056a33' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('email_verification', 'type', + existing_type=postgresql.ENUM('Survey', 'RejectedComment', 'Subscribe', name='emailverificationtype'), + nullable=False) + op.create_index(op.f('ix_engagement_metadata_engagement_id'), 'engagement_metadata', ['engagement_id'], unique=False) + op.create_index(op.f('ix_engagement_metadata_taxon_id'), 'engagement_metadata', ['taxon_id'], unique=False) + op.create_index(op.f('ix_engagement_metadata_value'), 'engagement_metadata', ['value'], unique=False) + op.create_index(op.f('ix_engagement_metadata_taxa_tenant_id'), 'engagement_metadata_taxa', ['tenant_id'], unique=False) + op.create_unique_constraint(None, 'engagement_metadata_taxa', ['id']) + op.execute('UPDATE membership_status_codes SET created_date = CURRENT_TIMESTAMP WHERE created_date IS NULL;') + op.alter_column('membership_status_codes', 'created_date', + existing_type=postgresql.TIMESTAMP(), + nullable=False) + op.drop_index('ix_participant_email_address', table_name='participant') + op.alter_column('timeline_event', 'widget_id', + existing_type=sa.INTEGER(), + nullable=False) + op.alter_column('timeline_event', 'status', + existing_type=postgresql.ENUM('Pending', 'InProgress', 'Completed', name='timelineeventstatus'), + nullable=False) + op.alter_column('timeline_event', 'position', + existing_type=sa.INTEGER(), + nullable=False) + op.alter_column('widget_documents', 'is_uploaded', + existing_type=sa.BOOLEAN(), + nullable=True, + existing_server_default=sa.text('false')) + op.alter_column('widget_timeline', 'widget_id', + existing_type=sa.INTEGER(), + nullable=False) + op.execute('UPDATE widget_type SET created_date = CURRENT_TIMESTAMP WHERE created_date IS NULL;') + op.alter_column('widget_type', 'created_date', + existing_type=postgresql.TIMESTAMP(), + nullable=False) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('widget_type', 'created_date', + existing_type=postgresql.TIMESTAMP(), + nullable=True) + op.alter_column('widget_timeline', 'widget_id', + existing_type=sa.INTEGER(), + nullable=True) + op.alter_column('widget_documents', 'is_uploaded', + existing_type=sa.BOOLEAN(), + nullable=False, + existing_server_default=sa.text('false')) + op.alter_column('timeline_event', 'position', + existing_type=sa.INTEGER(), + nullable=True) + op.alter_column('timeline_event', 'status', + existing_type=postgresql.ENUM('Pending', 'InProgress', 'Completed', name='timelineeventstatus'), + nullable=True) + op.alter_column('timeline_event', 'widget_id', + existing_type=sa.INTEGER(), + nullable=True) + op.create_index('ix_participant_email_address', 'participant', ['email_address'], unique=False) + + op.alter_column('membership_status_codes', 'created_date', + existing_type=postgresql.TIMESTAMP(), + nullable=True) + op.drop_constraint(None, 'engagement_metadata_taxa', type_='unique') + op.drop_index(op.f('ix_engagement_metadata_taxa_tenant_id'), table_name='engagement_metadata_taxa') + op.drop_index(op.f('ix_engagement_metadata_value'), table_name='engagement_metadata') + op.drop_index(op.f('ix_engagement_metadata_taxon_id'), table_name='engagement_metadata') + op.drop_index(op.f('ix_engagement_metadata_engagement_id'), table_name='engagement_metadata') + op.alter_column('email_verification', 'type', + existing_type=postgresql.ENUM('Survey', 'RejectedComment', 'Subscribe', name='emailverificationtype'), + nullable=True) + # ### end Alembic commands ### diff --git a/met-api/src/met_api/models/submission.py b/met-api/src/met_api/models/submission.py index 40a0cb559..0698b9ff3 100644 --- a/met-api/src/met_api/models/submission.py +++ b/met-api/src/met_api/models/submission.py @@ -35,7 +35,7 @@ class Submission(BaseModel): # pylint: disable=too-few-public-methods comment_status_id = db.Column(db.Integer, ForeignKey('comment_status.id', ondelete='SET NULL')) has_personal_info = db.Column(db.Boolean, nullable=True) has_profanity = db.Column(db.Boolean, nullable=True) - rejected_reason_other = db.Column(db.String(500), nullable=False) + rejected_reason_other = db.Column(db.String(500), nullable=True) has_threat = db.Column(db.Boolean, nullable=True) notify_email = db.Column(db.Boolean(), default=True) comments = db.relationship('Comment', backref='submission', cascade='all, delete') diff --git a/met-api/src/met_api/models/timeline_event.py b/met-api/src/met_api/models/timeline_event.py index 7a80a12dc..cdd6e9b8f 100644 --- a/met-api/src/met_api/models/timeline_event.py +++ b/met-api/src/met_api/models/timeline_event.py @@ -16,9 +16,9 @@ class TimelineEvent(BaseModel): __tablename__ = 'timeline_event' id = db.Column(db.Integer, primary_key=True, autoincrement=True) - engagement_id = db.Column(db.Integer, ForeignKey('engagement.id', ondelete='CASCADE'), nullable=True) - widget_id = db.Column(db.Integer, ForeignKey('widget.id', ondelete='CASCADE'), nullable=True) - timeline_id = db.Column(db.Integer, ForeignKey('widget_timeline.id', ondelete='CASCADE'), nullable=True) + engagement_id = db.Column(db.Integer, ForeignKey('engagement.id', ondelete='CASCADE'), nullable=False) + widget_id = db.Column(db.Integer, ForeignKey('widget.id', ondelete='CASCADE'), nullable=False) + timeline_id = db.Column(db.Integer, ForeignKey('widget_timeline.id', ondelete='CASCADE'), nullable=False) status = db.Column(db.Enum(TimelineEventStatus), nullable=False) position = db.Column(db.Integer, nullable=False) description = db.Column(db.Text(), nullable=True) diff --git a/met-api/src/met_api/models/widget_timeline.py b/met-api/src/met_api/models/widget_timeline.py index 18cb732be..7de9743ef 100755 --- a/met-api/src/met_api/models/widget_timeline.py +++ b/met-api/src/met_api/models/widget_timeline.py @@ -14,8 +14,8 @@ class WidgetTimeline(BaseModel): # pylint: disable=too-few-public-methods, too- __tablename__ = 'widget_timeline' id = db.Column(db.Integer, primary_key=True, autoincrement=True) - engagement_id = db.Column(db.Integer, ForeignKey('engagement.id', ondelete='CASCADE'), nullable=True) - widget_id = db.Column(db.Integer, ForeignKey('widget.id', ondelete='CASCADE'), nullable=True) + engagement_id = db.Column(db.Integer, ForeignKey('engagement.id', ondelete='CASCADE'), nullable=False) + widget_id = db.Column(db.Integer, ForeignKey('widget.id', ondelete='CASCADE'), nullable=False) title = db.Column(db.String(255), nullable=True) description = db.Column(db.Text(), nullable=True) diff --git a/met-api/tests/unit/api/test_email_verification_service.py b/met-api/tests/unit/api/test_email_verification_service.py index 87bef2173..325425485 100644 --- a/met-api/tests/unit/api/test_email_verification_service.py +++ b/met-api/tests/unit/api/test_email_verification_service.py @@ -41,7 +41,8 @@ def test_email_verification(client, jwt, session, notify_mock, ): # pylint:disa survey, eng = factory_survey_and_eng_model() to_dict = { 'email_address': fake.email(), - 'survey_id': survey.id + 'survey_id': survey.id, + 'type': EmailVerificationType.Survey, } headers = factory_auth_header(jwt=jwt, claims=claims) rv = client.post('/api/email_verification/', data=json.dumps(to_dict), @@ -87,7 +88,7 @@ def test_patch_email_verification_by_token(client, jwt, session): # pylint:disa claims = TestJwtClaims.public_user_role set_global_tenant() survey, eng = factory_survey_and_eng_model() - email_verification = factory_email_verification(survey.id) + email_verification = factory_email_verification(survey.id, EmailVerificationType.Subscribe) headers = factory_auth_header(jwt=jwt, claims=claims) rv = client.put(f'/api/email_verification/{email_verification.verification_token}', diff --git a/met-api/tests/unit/services/test_email_verification_service.py b/met-api/tests/unit/services/test_email_verification_service.py index 2f96cdd14..813cd1b27 100644 --- a/met-api/tests/unit/services/test_email_verification_service.py +++ b/met-api/tests/unit/services/test_email_verification_service.py @@ -23,6 +23,7 @@ from met_api.exceptions.business_exception import BusinessException from met_api.services.email_verification_service import EmailVerificationService +from met_api.constants.email_verification import EmailVerificationType from met_api.utils import notification from tests.utilities.factory_scenarios import TestEngagementSlugInfo from tests.utilities.factory_utils import factory_engagement_slug_model, factory_survey_and_eng_model, set_global_tenant @@ -43,7 +44,8 @@ def test_create_email_verification(client, jwt, session, ): # pylint:disable=un email = fake.email() to_dict = { 'email_address': email, - 'survey_id': survey.id + 'survey_id': survey.id, + 'type': EmailVerificationType.Survey } with patch.object(notification, 'send_email', return_value=False) as mock_mail: EmailVerificationService().create(to_dict) @@ -66,7 +68,8 @@ def test_create_email_verification_exception(client, jwt, session, ): # pylint: email = fake.email() to_dict = { 'email_address': email, - 'survey_id': survey.id + 'survey_id': survey.id, + 'type': EmailVerificationType.Survey } with pytest.raises(BusinessException) as exception: with patch.object(notification, 'send_email', side_effect=Exception('mocked error')): diff --git a/met-api/tests/utilities/factory_utils.py b/met-api/tests/utilities/factory_utils.py index 7d2b8809c..a04528468 100644 --- a/met-api/tests/utilities/factory_utils.py +++ b/met-api/tests/utilities/factory_utils.py @@ -50,6 +50,7 @@ from met_api.models.widget_video import WidgetVideo as WidgetVideoModel from met_api.utils.constants import TENANT_ID_HEADER from met_api.utils.enums import MembershipStatus +from met_api.constants.email_verification import EmailVerificationType from tests.utilities.factory_scenarios import ( TestCommentInfo, TestEngagementInfo, TestEngagementMetadataInfo, TestEngagementMetadataTaxonInfo, TestEngagementSlugInfo, TestFeedbackInfo, TestJwtClaims, TestParticipantInfo, TestPollAnswerInfo, @@ -121,12 +122,17 @@ def factory_subscription_model(): return subscription -def factory_email_verification(survey_id): +def factory_email_verification(survey_id, type=None): """Produce a EmailVerification model.""" email_verification = EmailVerificationModel( verification_token=fake.uuid4(), - is_active=True + is_active=True, ) + if type: + email_verification.type = type + else: + email_verification.type = EmailVerificationType.Survey + if survey_id: email_verification.survey_id = survey_id