From e5a1ef96ec521c96f3a4d96c24ee177f2b0e507c Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 08:06:53 -0800 Subject: [PATCH 01/33] update organizaton --- app/models.py | 107 ++++++++++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 47 deletions(-) diff --git a/app/models.py b/app/models.py index 6b008f64b..f0c295f72 100644 --- a/app/models.py +++ b/app/models.py @@ -1,12 +1,25 @@ import itertools import uuid +from typing import List, Optional from flask import current_app, url_for -from sqlalchemy import CheckConstraint, Index, UniqueConstraint +from sqlalchemy import ( + Boolean, + CheckConstraint, + Column, + DateTime, + Float, + ForeignKey, + Index, + String, + Text, + UniqueConstraint, + func, +) from sqlalchemy.dialects.postgresql import JSON, JSONB, UUID from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.declarative import declared_attr -from sqlalchemy.orm import validates +from sqlalchemy.orm import declarative_base, relationship, validates from sqlalchemy.orm.collections import attribute_mapped_collection from app import db, encryption @@ -358,56 +371,56 @@ class Domain(db.Model): ) -class Organization(db.Model): +Base = declarative_base() + + +class Organization(Base): __tablename__ = "organization" - id = db.Column( - UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=False + + id: UUID = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + name: str = Column(String(255), nullable=False, unique=True, index=True) + active: bool = Column(Boolean, nullable=False, default=True) + created_at: DateTime = Column(DateTime, nullable=False, default=func.now()) + updated_at: Optional[DateTime] = Column( + DateTime, nullable=True, onupdate=func.now() ) - name = db.Column(db.String(255), nullable=False, unique=True, index=True) - active = db.Column(db.Boolean, nullable=False, default=True) - created_at = db.Column( - db.DateTime, - nullable=False, - default=utc_now(), + agreement_signed: Optional[bool] = Column(Boolean, nullable=True) + agreement_signed_at: Optional[DateTime] = Column(DateTime, nullable=True) + agreement_signed_by_id: Optional[UUID] = Column( + UUID(as_uuid=True), + ForeignKey("users_id"), + nullable=True, ) - updated_at = db.Column( - db.DateTime, + agreement_signed_by = relationship("User", lazy="select") + agreement_signed_on_behalf_of_name: Optional[str] = Column( + String(255), nullable=True, - onupdate=utc_now(), ) - agreement_signed = db.Column(db.Boolean, nullable=True) - agreement_signed_at = db.Column(db.DateTime, nullable=True) - agreement_signed_by_id = db.Column( - UUID(as_uuid=True), - db.ForeignKey("users.id"), + agreement_signed_on_behalf_of_email_address: Optional[str] = Column( + String(255), nullable=True, ) - agreement_signed_by = db.relationship("User") - agreement_signed_on_behalf_of_name = db.Column(db.String(255), nullable=True) - agreement_signed_on_behalf_of_email_address = db.Column( - db.String(255), nullable=True + agreement_signed_version: Optional[float] = Column(Float, nullable=True) + organization_type: Optional[OrganizationType] = enum_column( + OrganizationType, nullable=True ) - agreement_signed_version = db.Column(db.Float, nullable=True) - organization_type = enum_column(OrganizationType, unique=False, nullable=True) - request_to_go_live_notes = db.Column(db.Text) + request_to_go_live_notes: Optional[str] = Column(Text, nullable=True) - domains = db.relationship("Domain") - - email_branding = db.relationship("EmailBranding") - email_branding_id = db.Column( - UUID(as_uuid=True), - db.ForeignKey("email_branding.id"), - nullable=True, + domains: List["Domain"] = relationship("Domain", lazy="select") + email_branding: Optional["EmailBranding"] = relationship( + "EmailBranding", lazy="select" ) - - notes = db.Column(db.Text, nullable=True) - purchase_order_number = db.Column(db.String(255), nullable=True) - billing_contact_names = db.Column(db.Text, nullable=True) - billing_contact_email_addresses = db.Column(db.Text, nullable=True) - billing_reference = db.Column(db.String(255), nullable=True) + email_branding_id: Optional[UUID] = Column( + UUID(as_uuid=True), ForeignKey("email_branding_id"), nullable=True + ) + notes: Optional[str] = Column(Text, nullable=True) + purchase_order_number = Optional[str] = Column(String(255), nullable=True) + billing_contact_names: Optional[str] = Column(Text, nullable=True) + billing_contact_email_address: Optional[str] = Column(Text, nullable=True) + billing_reference: Optional[str] = Column(String(255), nullable=True) @property - def live_services(self): + def live_services(self) -> List["Service"]: return [ service for service in self.services @@ -415,11 +428,11 @@ def live_services(self): ] @property - def domain_list(self): + def domain_list(self) -> List[str]: return [domain.domain for domain in self.domains] @property - def agreement(self): + def agreement(self) -> Optional["Agreement"]: try: active_agreements = [ agreement @@ -431,20 +444,20 @@ def agreement(self): return None @property - def agreement_active(self): + def agreement_active(self) -> bool: try: return self.agreement.status == AgreementStatus.ACTIVE except AttributeError: return False @property - def has_mou(self): + def has_mou(self) -> bool: try: return self.agreement.type == AgreementType.MOU except AttributeError: return False - def serialize(self): + def serialize(self) -> dict: return { "id": str(self.id), "name": self.name, @@ -453,7 +466,7 @@ def serialize(self): "email_branding_id": self.email_branding_id, "agreement_signed": self.agreement_signed, "agreement_signed_at": self.agreement_signed_at, - "agreement_signed_by_id": self.agreement_signed_by_id, + "agreement_signed_by_id": self.agreemnt_signed_by_id, "agreement_signed_on_behalf_of_name": self.agreement_signed_on_behalf_of_name, "agreement_signed_on_behalf_of_email_address": self.agreement_signed_on_behalf_of_email_address, "agreement_signed_version": self.agreement_signed_version, @@ -467,7 +480,7 @@ def serialize(self): "billing_reference": self.billing_reference, } - def serialize_for_list(self): + def serialize_for_list(self) -> dict: return { "name": self.name, "id": str(self.id), From f8b2a8aef6ebf6e834b6048815406e4f0d2a47bf Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 08:20:03 -0800 Subject: [PATCH 02/33] update organizaton --- app/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index f0c295f72..bde2f3c83 100644 --- a/app/models.py +++ b/app/models.py @@ -414,7 +414,7 @@ class Organization(Base): UUID(as_uuid=True), ForeignKey("email_branding_id"), nullable=True ) notes: Optional[str] = Column(Text, nullable=True) - purchase_order_number = Optional[str] = Column(String(255), nullable=True) + purchase_order_number: Optional[str] = Column(String(255), nullable=True) billing_contact_names: Optional[str] = Column(Text, nullable=True) billing_contact_email_address: Optional[str] = Column(Text, nullable=True) billing_reference: Optional[str] = Column(String(255), nullable=True) From 23a5369fbc74ab31017d95e2da9b563b968bc68b Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 08:37:32 -0800 Subject: [PATCH 03/33] update organizaton --- app/models.py | 61 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/app/models.py b/app/models.py index bde2f3c83..50797adee 100644 --- a/app/models.py +++ b/app/models.py @@ -6,7 +6,6 @@ from sqlalchemy import ( Boolean, CheckConstraint, - Column, DateTime, Float, ForeignKey, @@ -19,7 +18,13 @@ from sqlalchemy.dialects.postgresql import JSON, JSONB, UUID from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.ext.declarative import declared_attr -from sqlalchemy.orm import declarative_base, relationship, validates +from sqlalchemy.orm import ( + Mapped, + declarative_base, + mapped_column, + relationship, + validates, +) from sqlalchemy.orm.collections import attribute_mapped_collection from app import db, encryption @@ -377,47 +382,61 @@ class Domain(db.Model): class Organization(Base): __tablename__ = "organization" - id: UUID = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) - name: str = Column(String(255), nullable=False, unique=True, index=True) - active: bool = Column(Boolean, nullable=False, default=True) - created_at: DateTime = Column(DateTime, nullable=False, default=func.now()) - updated_at: Optional[DateTime] = Column( + id: Mapped[UUID] = mapped_column( + UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 + ) + name: Mapped[str] = mapped_column( + String(255), nullable=False, unique=True, index=True + ) + active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True) + created_at: Mapped[DateTime] = mapped_column( + DateTime, nullable=False, default=func.now() + ) + updated_at: Mapped[Optional[DateTime]] = mapped_column( DateTime, nullable=True, onupdate=func.now() ) - agreement_signed: Optional[bool] = Column(Boolean, nullable=True) - agreement_signed_at: Optional[DateTime] = Column(DateTime, nullable=True) - agreement_signed_by_id: Optional[UUID] = Column( + agreement_signed: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=True) + agreement_signed_at: Mapped[Optional[DateTime]] = mapped_column( + DateTime, nullable=True + ) + agreement_signed_by_id: Mapped[Optional[UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("users_id"), nullable=True, ) agreement_signed_by = relationship("User", lazy="select") - agreement_signed_on_behalf_of_name: Optional[str] = Column( + agreement_signed_on_behalf_of_name: Mapped[Optional[str]] = mapped_column( String(255), nullable=True, ) - agreement_signed_on_behalf_of_email_address: Optional[str] = Column( + agreement_signed_on_behalf_of_email_address: Mapped[Optional[str]] = mapped_column( String(255), nullable=True, ) - agreement_signed_version: Optional[float] = Column(Float, nullable=True) - organization_type: Optional[OrganizationType] = enum_column( + agreement_signed_version: Mapped[Optional[float]] = mapped_column( + Float, nullable=True + ) + organization_type: Mapped[Optional[OrganizationType]] = mapped_column( OrganizationType, nullable=True ) - request_to_go_live_notes: Optional[str] = Column(Text, nullable=True) + request_to_go_live_notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True) domains: List["Domain"] = relationship("Domain", lazy="select") email_branding: Optional["EmailBranding"] = relationship( "EmailBranding", lazy="select" ) - email_branding_id: Optional[UUID] = Column( + email_branding_id: Mapped[Optional[UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("email_branding_id"), nullable=True ) - notes: Optional[str] = Column(Text, nullable=True) - purchase_order_number: Optional[str] = Column(String(255), nullable=True) - billing_contact_names: Optional[str] = Column(Text, nullable=True) - billing_contact_email_address: Optional[str] = Column(Text, nullable=True) - billing_reference: Optional[str] = Column(String(255), nullable=True) + notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True) + purchase_order_number: Mapped[Optional[str]] = mapped_column( + String(255), nullable=True + ) + billing_contact_names: Mapped[Optional[str]] = mapped_column(Text, nullable=True) + billing_contact_email_address: Mapped[Optional[str]] = mapped_column( + Text, nullable=True + ) + billing_reference: Mapped[Optional[str]] = mapped_column(String(255), nullable=True) @property def live_services(self) -> List["Service"]: From 7eb599a692e3db1ac323668e474c30b2128f50b5 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 08:53:16 -0800 Subject: [PATCH 04/33] update organizaton --- app/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index 50797adee..7ed0ffa8e 100644 --- a/app/models.py +++ b/app/models.py @@ -7,6 +7,7 @@ Boolean, CheckConstraint, DateTime, + Enum, Float, ForeignKey, Index, @@ -417,7 +418,7 @@ class Organization(Base): Float, nullable=True ) organization_type: Mapped[Optional[OrganizationType]] = mapped_column( - OrganizationType, nullable=True + Enum(OrganizationType, name="organization_type_enum"), nullable=True ) request_to_go_live_notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True) From e563632dbfc34895301abb8423a59d8d69d720ba Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 09:00:45 -0800 Subject: [PATCH 05/33] update organizaton --- app/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models.py b/app/models.py index 7ed0ffa8e..b16321b23 100644 --- a/app/models.py +++ b/app/models.py @@ -422,8 +422,8 @@ class Organization(Base): ) request_to_go_live_notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True) - domains: List["Domain"] = relationship("Domain", lazy="select") - email_branding: Optional["EmailBranding"] = relationship( + domains: Mapped[List["Domain"]] = relationship("Domain", lazy="select") + email_branding: Mapped[Optional["EmailBranding"]] = relationship( "EmailBranding", lazy="select" ) email_branding_id: Mapped[Optional[UUID]] = mapped_column( From a2569d6b7a8ad9ef825e4c7986b04513d81e24db Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 09:09:43 -0800 Subject: [PATCH 06/33] update organizaton --- app/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index b16321b23..15da3221d 100644 --- a/app/models.py +++ b/app/models.py @@ -179,10 +179,11 @@ class User(db.Model): ) services = db.relationship("Service", secondary="user_to_service", backref="users") - organizations = db.relationship( + organizations: Mapped[List["Organization"]] = relationship( "Organization", secondary="user_to_organization", backref="users", + lazy="select" ) @validates("mobile_number") From f7b8dd752e5f29cc21fd6aa7a0def78d3dd3cbb8 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 09:17:16 -0800 Subject: [PATCH 07/33] update organizaton --- app/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index 15da3221d..190c04eb8 100644 --- a/app/models.py +++ b/app/models.py @@ -125,7 +125,7 @@ def update_from_original(self, original): class User(db.Model): __tablename__ = "users" - id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + id: Mapped[UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) name = db.Column(db.String, nullable=False, index=True, unique=False) email_address = db.Column(db.String(255), nullable=False, index=True, unique=True) login_uuid = db.Column(db.Text, nullable=True, index=True, unique=True) From 192d42ee0aec9029167cfe0a084abdffd8e016d7 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 09:28:31 -0800 Subject: [PATCH 08/33] update organizaton --- app/models.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/models.py b/app/models.py index 190c04eb8..049005ddf 100644 --- a/app/models.py +++ b/app/models.py @@ -125,7 +125,9 @@ def update_from_original(self, original): class User(db.Model): __tablename__ = "users" - id: Mapped[UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + id: Mapped[UUID] = mapped_column( + UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 + ) name = db.Column(db.String, nullable=False, index=True, unique=False) email_address = db.Column(db.String(255), nullable=False, index=True, unique=True) login_uuid = db.Column(db.Text, nullable=True, index=True, unique=True) @@ -180,10 +182,7 @@ class User(db.Model): services = db.relationship("Service", secondary="user_to_service", backref="users") organizations: Mapped[List["Organization"]] = relationship( - "Organization", - secondary="user_to_organization", - backref="users", - lazy="select" + "Organization", secondary="user_to_organization", backref="users", lazy="select" ) @validates("mobile_number") @@ -381,7 +380,11 @@ class Domain(db.Model): Base = declarative_base() -class Organization(Base): +class Organization(db.Model): + + # TODO When everything in this file is upgraded to 2.0 syntax, + # replace all uses of db.Model with Base + # class Organization(Base): __tablename__ = "organization" id: Mapped[UUID] = mapped_column( From ff052f61d15207a72276827b1acb9777a0a51020 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 09:36:45 -0800 Subject: [PATCH 09/33] update organizaton --- app/models.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index 049005ddf..2cd45e72a 100644 --- a/app/models.py +++ b/app/models.py @@ -404,12 +404,18 @@ class Organization(db.Model): agreement_signed_at: Mapped[Optional[DateTime]] = mapped_column( DateTime, nullable=True ) + agreement_signed_by_id: Mapped[Optional[UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("users_id"), nullable=True, ) - agreement_signed_by = relationship("User", lazy="select") + # Specify the relationship with explicity primaryjoin + agreement_signed_by = relationship( + "User", + back_populates="organizations", + primary_join="Organization.agreement_signed_by_id == User.id", + ) agreement_signed_on_behalf_of_name: Mapped[Optional[str]] = mapped_column( String(255), nullable=True, From 8a670b41800d2f18c299d95c91c04715525cfedc Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 09:40:35 -0800 Subject: [PATCH 10/33] update organizaton --- app/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index 2cd45e72a..58f93d0b5 100644 --- a/app/models.py +++ b/app/models.py @@ -414,7 +414,7 @@ class Organization(db.Model): agreement_signed_by = relationship( "User", back_populates="organizations", - primary_join="Organization.agreement_signed_by_id == User.id", + primaryjoin="Organization.agreement_signed_by_id == User.id", ) agreement_signed_on_behalf_of_name: Mapped[Optional[str]] = mapped_column( String(255), From 24de9fb2715c258263a55402bd9c312262b604f6 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 09:43:55 -0800 Subject: [PATCH 11/33] update organizaton --- app/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index 58f93d0b5..5cba5ba64 100644 --- a/app/models.py +++ b/app/models.py @@ -407,7 +407,7 @@ class Organization(db.Model): agreement_signed_by_id: Mapped[Optional[UUID]] = mapped_column( UUID(as_uuid=True), - ForeignKey("users_id"), + ForeignKey("users.id"), nullable=True, ) # Specify the relationship with explicity primaryjoin From cb1ce0f9c66be5d637abbe88e4d6b7d7d13a40d3 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 10:09:33 -0800 Subject: [PATCH 12/33] update organizaton --- app/models.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/models.py b/app/models.py index 5cba5ba64..6f4144b09 100644 --- a/app/models.py +++ b/app/models.py @@ -321,7 +321,7 @@ class ServiceUser(db.Model): class EmailBranding(db.Model): __tablename__ = "email_branding" - id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + id: Mapped[UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) colour = db.Column(db.String(7), nullable=True) logo = db.Column(db.String(255), nullable=True) name = db.Column(db.String(255), unique=True, nullable=False) @@ -434,10 +434,12 @@ class Organization(db.Model): domains: Mapped[List["Domain"]] = relationship("Domain", lazy="select") email_branding: Mapped[Optional["EmailBranding"]] = relationship( - "EmailBranding", lazy="select" + "EmailBranding", + + primaryjoin="Organization.email_branding_id == EmailBranding.id", ) email_branding_id: Mapped[Optional[UUID]] = mapped_column( - UUID(as_uuid=True), ForeignKey("email_branding_id"), nullable=True + UUID(as_uuid=True), ForeignKey("emailbranding.id"), nullable=True ) notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True) purchase_order_number: Mapped[Optional[str]] = mapped_column( From 553c66eaee2a563aeb863050120f43f601703408 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 10:26:04 -0800 Subject: [PATCH 13/33] update organizaton --- app/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index 6f4144b09..a969c1e84 100644 --- a/app/models.py +++ b/app/models.py @@ -436,7 +436,7 @@ class Organization(db.Model): email_branding: Mapped[Optional["EmailBranding"]] = relationship( "EmailBranding", - primaryjoin="Organization.email_branding_id == EmailBranding.id", + primaryjoin="Organization.email_branding_id == Email_Branding.id", ) email_branding_id: Mapped[Optional[UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("emailbranding.id"), nullable=True From 150faad7ad2242761e42aa18f723df77a11a3471 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 11:21:53 -0800 Subject: [PATCH 14/33] update organizaton --- app/commands.py | 6 +++--- app/dao/email_branding_dao.py | 8 ++++---- app/email_branding/rest.py | 4 ++-- app/models.py | 15 ++++++++------- app/service/rest.py | 4 ++-- tests/app/dao/test_email_branding_dao.py | 8 ++++---- tests/app/db.py | 4 ++-- tests/app/delivery/test_send_to_providers.py | 16 ++++++++-------- tests/app/email_branding/test_rest.py | 12 ++++++------ tests/app/service/test_rest.py | 10 +++++----- 10 files changed, 44 insertions(+), 43 deletions(-) diff --git a/app/commands.py b/app/commands.py index 79bd3192d..ac151727c 100644 --- a/app/commands.py +++ b/app/commands.py @@ -49,7 +49,7 @@ from app.models import ( AnnualBilling, Domain, - EmailBranding, + Email_Branding, Notification, Organization, Service, @@ -338,8 +338,8 @@ def boolean_or_none(field): email_branding = None email_branding_column = columns[5].strip() if len(email_branding_column) > 0: - stmt = select(EmailBranding).where( - EmailBranding.name == email_branding_column + stmt = select(Email_Branding).where( + Email_Branding.name == email_branding_column ) email_branding = db.session.execute(stmt).scalars().one() data = { diff --git a/app/dao/email_branding_dao.py b/app/dao/email_branding_dao.py index 1dedd78a8..b872652cd 100644 --- a/app/dao/email_branding_dao.py +++ b/app/dao/email_branding_dao.py @@ -1,18 +1,18 @@ from app import db from app.dao.dao_utils import autocommit -from app.models import EmailBranding +from app.models import Email_Branding def dao_get_email_branding_options(): - return EmailBranding.query.all() + return Email_Branding.query.all() def dao_get_email_branding_by_id(email_branding_id): - return EmailBranding.query.filter_by(id=email_branding_id).one() + return Email_Branding.query.filter_by(id=email_branding_id).one() def dao_get_email_branding_by_name(email_branding_name): - return EmailBranding.query.filter_by(name=email_branding_name).first() + return Email_Branding.query.filter_by(name=email_branding_name).first() @autocommit diff --git a/app/email_branding/rest.py b/app/email_branding/rest.py index 3dc508614..fb71396ba 100644 --- a/app/email_branding/rest.py +++ b/app/email_branding/rest.py @@ -11,7 +11,7 @@ post_update_email_branding_schema, ) from app.errors import register_errors -from app.models import EmailBranding +from app.models import Email_Branding from app.schema_validation import validate email_branding_blueprint = Blueprint("email_branding", __name__) @@ -36,7 +36,7 @@ def create_email_branding(): validate(data, post_create_email_branding_schema) - email_branding = EmailBranding(**data) + email_branding = Email_Branding(**data) if "text" not in data.keys(): email_branding.text = email_branding.name diff --git a/app/models.py b/app/models.py index a969c1e84..950bde4e0 100644 --- a/app/models.py +++ b/app/models.py @@ -319,9 +319,11 @@ class ServiceUser(db.Model): ) -class EmailBranding(db.Model): +class Email_Branding(db.Model): __tablename__ = "email_branding" - id: Mapped[UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + id: Mapped[UUID] = mapped_column( + UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 + ) colour = db.Column(db.String(7), nullable=True) logo = db.Column(db.String(255), nullable=True) name = db.Column(db.String(255), unique=True, nullable=False) @@ -433,13 +435,12 @@ class Organization(db.Model): request_to_go_live_notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True) domains: Mapped[List["Domain"]] = relationship("Domain", lazy="select") - email_branding: Mapped[Optional["EmailBranding"]] = relationship( - "EmailBranding", - + email_branding: Mapped[Optional["Email_Branding"]] = relationship( + "Email_Branding", primaryjoin="Organization.email_branding_id == Email_Branding.id", ) email_branding_id: Mapped[Optional[UUID]] = mapped_column( - UUID(as_uuid=True), ForeignKey("emailbranding.id"), nullable=True + UUID(as_uuid=True), ForeignKey("email_branding.id"), nullable=True ) notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True) purchase_order_number: Mapped[Optional[str]] = mapped_column( @@ -596,7 +597,7 @@ class Service(db.Model, Versioned): billing_reference = db.Column(db.String(255), nullable=True) email_branding = db.relationship( - "EmailBranding", + "Email_Branding", secondary=service_email_branding, uselist=False, backref=db.backref("services", lazy="dynamic"), diff --git a/app/service/rest.py b/app/service/rest.py index 7dd614058..c87d7d9c5 100644 --- a/app/service/rest.py +++ b/app/service/rest.py @@ -79,7 +79,7 @@ from app.dao.users_dao import get_user_by_id from app.enums import KeyType from app.errors import InvalidRequest, register_errors -from app.models import EmailBranding, Permission, Service +from app.models import Email_Branding, Permission, Service from app.notifications.process_notifications import ( persist_notification, send_notification_to_queue, @@ -312,7 +312,7 @@ def update_service(service_id): service.email_branding = ( None if not email_branding_id - else EmailBranding.query.get(email_branding_id) + else Email_Branding.query.get(email_branding_id) ) dao_update_service(service) diff --git a/tests/app/dao/test_email_branding_dao.py b/tests/app/dao/test_email_branding_dao.py index 9e428b345..afbc54353 100644 --- a/tests/app/dao/test_email_branding_dao.py +++ b/tests/app/dao/test_email_branding_dao.py @@ -3,7 +3,7 @@ dao_get_email_branding_by_name, dao_update_email_branding, ) -from app.models import EmailBranding +from app.models import Email_Branding from tests.app.db import create_email_branding @@ -27,14 +27,14 @@ def test_update_email_branding(notify_db_session): updated_name = "new name" create_email_branding() - email_branding = EmailBranding.query.all() + email_branding = Email_Branding.query.all() assert len(email_branding) == 1 assert email_branding[0].name != updated_name dao_update_email_branding(email_branding[0], name=updated_name) - email_branding = EmailBranding.query.all() + email_branding = Email_Branding.query.all() assert len(email_branding) == 1 assert email_branding[0].name == updated_name @@ -42,5 +42,5 @@ def test_update_email_branding(notify_db_session): def test_email_branding_has_no_domain(notify_db_session): create_email_branding() - email_branding = EmailBranding.query.all() + email_branding = Email_Branding.query.all() assert not hasattr(email_branding, "domain") diff --git a/tests/app/db.py b/tests/app/db.py index 07b395295..b4b2b3deb 100644 --- a/tests/app/db.py +++ b/tests/app/db.py @@ -45,7 +45,7 @@ ApiKey, Complaint, Domain, - EmailBranding, + Email_Branding, FactBilling, FactNotificationStatus, FactProcessingTime, @@ -523,7 +523,7 @@ def create_email_branding( } if id: data["id"] = id - email_branding = EmailBranding(**data) + email_branding = Email_Branding(**data) dao_create_email_branding(email_branding) return email_branding diff --git a/tests/app/delivery/test_send_to_providers.py b/tests/app/delivery/test_send_to_providers.py index 20b0f7186..23257bb8d 100644 --- a/tests/app/delivery/test_send_to_providers.py +++ b/tests/app/delivery/test_send_to_providers.py @@ -19,7 +19,7 @@ ) from app.enums import BrandType, KeyType, NotificationStatus, NotificationType from app.exceptions import NotificationTechnicalFailureException -from app.models import EmailBranding, Notification +from app.models import Email_Branding, Notification from app.serialised_models import SerialisedService from app.utils import utc_now from tests.app.db import ( @@ -466,7 +466,7 @@ def test_get_html_email_renderer_should_return_for_normal_service(sample_service def test_get_html_email_renderer_with_branding_details( branding_type, govuk_banner, notify_db_session, sample_service ): - email_branding = EmailBranding( + email_branding = Email_Branding( brand_type=branding_type, colour="#000000", logo="justice-league.png", @@ -504,12 +504,12 @@ def test_get_html_email_renderer_with_branding_details_and_render_govuk_banner_o def test_get_html_email_renderer_prepends_logo_path(notify_api): Service = namedtuple("Service", ["email_branding"]) - EmailBranding = namedtuple( - "EmailBranding", + Email_Branding = namedtuple( + "Email_Branding", ["brand_type", "colour", "name", "logo", "text"], ) - email_branding = EmailBranding( + email_branding = Email_Branding( brand_type=BrandType.ORG, colour="#000000", logo="justice-league.png", @@ -529,12 +529,12 @@ def test_get_html_email_renderer_prepends_logo_path(notify_api): def test_get_html_email_renderer_handles_email_branding_without_logo(notify_api): Service = namedtuple("Service", ["email_branding"]) - EmailBranding = namedtuple( - "EmailBranding", + Email_Branding = namedtuple( + "Email_Branding", ["brand_type", "colour", "name", "logo", "text"], ) - email_branding = EmailBranding( + email_branding = Email_Branding( brand_type=BrandType.ORG_BANNER, colour="#000000", logo=None, diff --git a/tests/app/email_branding/test_rest.py b/tests/app/email_branding/test_rest.py index b406ec8be..38419b8ee 100644 --- a/tests/app/email_branding/test_rest.py +++ b/tests/app/email_branding/test_rest.py @@ -1,15 +1,15 @@ import pytest from app.enums import BrandType -from app.models import EmailBranding +from app.models import Email_Branding from tests.app.db import create_email_branding def test_get_email_branding_options(admin_request, notify_db_session): - email_branding1 = EmailBranding( + email_branding1 = Email_Branding( colour="#FFFFFF", logo="/path/image.png", name="Org1" ) - email_branding2 = EmailBranding( + email_branding2 = Email_Branding( colour="#000000", logo="/path/other.png", name="Org2" ) notify_db_session.add_all([email_branding1, email_branding2]) @@ -27,7 +27,7 @@ def test_get_email_branding_options(admin_request, notify_db_session): def test_get_email_branding_by_id(admin_request, notify_db_session): - email_branding = EmailBranding( + email_branding = Email_Branding( colour="#FFFFFF", logo="/path/image.png", name="Some Org", text="My Org" ) notify_db_session.add(email_branding) @@ -198,7 +198,7 @@ def test_post_update_email_branding_updates_field( email_branding_id=email_branding_id, ) - email_branding = EmailBranding.query.all() + email_branding = Email_Branding.query.all() assert len(email_branding) == 1 assert str(email_branding[0].id) == email_branding_id @@ -231,7 +231,7 @@ def test_post_update_email_branding_updates_field_with_text( email_branding_id=email_branding_id, ) - email_branding = EmailBranding.query.all() + email_branding = Email_Branding.query.all() assert len(email_branding) == 1 assert str(email_branding[0].id) == email_branding_id diff --git a/tests/app/service/test_rest.py b/tests/app/service/test_rest.py index 132de48e9..42520e389 100644 --- a/tests/app/service/test_rest.py +++ b/tests/app/service/test_rest.py @@ -28,7 +28,7 @@ ) from app.models import ( AnnualBilling, - EmailBranding, + Email_Branding, InboundNumber, Notification, Permission, @@ -711,7 +711,7 @@ def test_create_service_should_throw_duplicate_key_constraint_for_existing_email def test_update_service(client, notify_db_session, sample_service): - brand = EmailBranding( + brand = Email_Branding( colour="#000000", logo="justice-league.png", name="Justice League", @@ -765,7 +765,7 @@ def test_cant_update_service_org_type_to_random_value(client, sample_service): def test_update_service_remove_email_branding( admin_request, notify_db_session, sample_service ): - brand = EmailBranding( + brand = Email_Branding( colour="#000000", logo="justice-league.png", name="Justice League", @@ -784,12 +784,12 @@ def test_update_service_remove_email_branding( def test_update_service_change_email_branding( admin_request, notify_db_session, sample_service ): - brand1 = EmailBranding( + brand1 = Email_Branding( colour="#000000", logo="justice-league.png", name="Justice League", ) - brand2 = EmailBranding(colour="#111111", logo="avengers.png", name="Avengers") + brand2 = Email_Branding(colour="#111111", logo="avengers.png", name="Avengers") notify_db_session.add_all([brand1, brand2]) sample_service.email_branding = brand1 notify_db_session.commit() From 1990792a3e5b7709901cba11d635d327afbeaac0 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 11:33:57 -0800 Subject: [PATCH 15/33] update organizaton --- app/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index 950bde4e0..af614b076 100644 --- a/app/models.py +++ b/app/models.py @@ -509,7 +509,7 @@ def serialize(self) -> dict: "notes": self.notes, "purchase_order_number": self.purchase_order_number, "billing_contact_names": self.billing_contact_names, - "billing_contact_email_addresses": self.billing_contact_email_addresses, + "billing_contact_email_address": self.billing_contact_email_address, "billing_reference": self.billing_reference, } From e2ff16e24aff6b3e78e37200ba743c409751190d Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 11:42:43 -0800 Subject: [PATCH 16/33] update organizaton --- app/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models.py b/app/models.py index af614b076..c26aa26b4 100644 --- a/app/models.py +++ b/app/models.py @@ -447,7 +447,7 @@ class Organization(db.Model): String(255), nullable=True ) billing_contact_names: Mapped[Optional[str]] = mapped_column(Text, nullable=True) - billing_contact_email_address: Mapped[Optional[str]] = mapped_column( + billing_contact_email_addresses: Mapped[Optional[str]] = mapped_column( Text, nullable=True ) billing_reference: Mapped[Optional[str]] = mapped_column(String(255), nullable=True) @@ -509,7 +509,7 @@ def serialize(self) -> dict: "notes": self.notes, "purchase_order_number": self.purchase_order_number, "billing_contact_names": self.billing_contact_names, - "billing_contact_email_address": self.billing_contact_email_address, + "billing_contact_email_addresses": self.billing_contact_email_addresses, "billing_reference": self.billing_reference, } From e35e38d60d189383e7bf4dc5ef8a0cb81729d2f6 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 12:06:10 -0800 Subject: [PATCH 17/33] update organizaton --- app/enums.py | 6 +++--- tests/app/dao/test_organization_dao.py | 26 +++++++++++++------------- tests/app/dao/test_services_dao.py | 20 ++++++++++---------- tests/app/db.py | 2 +- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/app/enums.py b/app/enums.py index a0dfbb467..0ff367117 100644 --- a/app/enums.py +++ b/app/enums.py @@ -31,9 +31,9 @@ class CallbackType(StrEnum): class OrganizationType(StrEnum): - FEDERAL = "federal" - STATE = "state" - OTHER = "other" + federal = "federal" + state = "state" + other = "other" class NotificationStatus(StrEnum): diff --git a/tests/app/dao/test_organization_dao.py b/tests/app/dao/test_organization_dao.py index fb2e01d85..2990b17dc 100644 --- a/tests/app/dao/test_organization_dao.py +++ b/tests/app/dao/test_organization_dao.py @@ -65,7 +65,7 @@ def test_update_organization(notify_db_session): data = { "name": "new name", - "organization_type": OrganizationType.STATE, + "organization_type": OrganizationType.state, "agreement_signed": True, "agreement_signed_at": utc_now(), "agreement_signed_by_id": user.id, @@ -144,8 +144,8 @@ def test_update_organization_does_not_update_the_service_if_certain_attributes_n ): email_branding = create_email_branding() - sample_service.organization_type = OrganizationType.STATE - sample_organization.organization_type = OrganizationType.FEDERAL + sample_service.organization_type = OrganizationType.state + sample_organization.organization_type = OrganizationType.federal sample_organization.email_branding = email_branding sample_organization.services.append(sample_service) @@ -157,8 +157,8 @@ def test_update_organization_does_not_update_the_service_if_certain_attributes_n assert sample_organization.name == "updated org name" - assert sample_organization.organization_type == OrganizationType.FEDERAL - assert sample_service.organization_type == OrganizationType.STATE + assert sample_organization.organization_type == OrganizationType.federal + assert sample_service.organization_type == OrganizationType.state assert sample_organization.email_branding == email_branding assert sample_service.email_branding is None @@ -168,24 +168,24 @@ def test_update_organization_updates_the_service_org_type_if_org_type_is_provide sample_service, sample_organization, ): - sample_service.organization_type = OrganizationType.STATE - sample_organization.organization_type = OrganizationType.STATE + sample_service.organization_type = OrganizationType.state + sample_organization.organization_type = OrganizationType.state sample_organization.services.append(sample_service) db.session.commit() dao_update_organization( - sample_organization.id, organization_type=OrganizationType.FEDERAL + sample_organization.id, organization_type=OrganizationType.federal ) - assert sample_organization.organization_type == OrganizationType.FEDERAL - assert sample_service.organization_type == OrganizationType.FEDERAL + assert sample_organization.organization_type == OrganizationType.federal + assert sample_service.organization_type == OrganizationType.federal stmt = select(Service.get_history_model()).filter_by( id=sample_service.id, version=2 ) assert ( db.session.execute(stmt).scalars().one().organization_type - == OrganizationType.FEDERAL + == OrganizationType.federal ) @@ -225,8 +225,8 @@ def test_update_organization_does_not_override_service_branding( def test_add_service_to_organization(sample_service, sample_organization): assert sample_organization.services == [] - sample_service.organization_type = OrganizationType.FEDERAL - sample_organization.organization_type = OrganizationType.STATE + sample_service.organization_type = OrganizationType.federal + sample_organization.organization_type = OrganizationType.state dao_add_service_to_organization(sample_service, sample_organization.id) diff --git a/tests/app/dao/test_services_dao.py b/tests/app/dao/test_services_dao.py index 61fe99419..0eaf5c7f1 100644 --- a/tests/app/dao/test_services_dao.py +++ b/tests/app/dao/test_services_dao.py @@ -121,7 +121,7 @@ def test_create_service(notify_db_session): email_from="email_from", message_limit=1000, restricted=False, - organization_type=OrganizationType.FEDERAL, + organization_type=OrganizationType.federal, created_by=user, ) dao_create_service(service, user) @@ -133,7 +133,7 @@ def test_create_service(notify_db_session): assert service_db.prefix_sms is True assert service.active is True assert user in service_db.users - assert service_db.organization_type == OrganizationType.FEDERAL + assert service_db.organization_type == OrganizationType.federal assert not service.organization_id @@ -141,7 +141,7 @@ def test_create_service_with_organization(notify_db_session): user = create_user(email="local.authority@local-authority.gov.uk") organization = create_organization( name="Some local authority", - organization_type=OrganizationType.STATE, + organization_type=OrganizationType.state, domains=["local-authority.gov.uk"], ) assert _get_service_query_count() == 0 @@ -150,7 +150,7 @@ def test_create_service_with_organization(notify_db_session): email_from="email_from", message_limit=1000, restricted=False, - organization_type=OrganizationType.FEDERAL, + organization_type=OrganizationType.federal, created_by=user, ) dao_create_service(service, user) @@ -163,7 +163,7 @@ def test_create_service_with_organization(notify_db_session): assert service_db.prefix_sms is True assert service.active is True assert user in service_db.users - assert service_db.organization_type == OrganizationType.STATE + assert service_db.organization_type == OrganizationType.state assert service.organization_id == organization.id assert service.organization == organization @@ -172,7 +172,7 @@ def test_fetch_service_by_id_with_api_keys(notify_db_session): user = create_user(email="local.authority@local-authority.gov.uk") organization = create_organization( name="Some local authority", - organization_type=OrganizationType.STATE, + organization_type=OrganizationType.state, domains=["local-authority.gov.uk"], ) assert _get_service_query_count() == 0 @@ -181,7 +181,7 @@ def test_fetch_service_by_id_with_api_keys(notify_db_session): email_from="email_from", message_limit=1000, restricted=False, - organization_type=OrganizationType.FEDERAL, + organization_type=OrganizationType.federal, created_by=user, ) dao_create_service(service, user) @@ -194,7 +194,7 @@ def test_fetch_service_by_id_with_api_keys(notify_db_session): assert service_db.prefix_sms is True assert service.active is True assert user in service_db.users - assert service_db.organization_type == OrganizationType.STATE + assert service_db.organization_type == OrganizationType.state assert service.organization_id == organization.id assert service.organization == organization @@ -530,7 +530,7 @@ def test_get_all_user_services_should_return_empty_list_if_no_services_for_user( @freeze_time("2019-04-23T10:00:00") def test_dao_fetch_live_services_data(sample_user): - org = create_organization(organization_type=OrganizationType.FEDERAL) + org = create_organization(organization_type=OrganizationType.federal) service = create_service(go_live_user=sample_user, go_live_at="2014-04-20T10:00:00") sms_template = create_template(service=service) service_2 = create_service( @@ -569,7 +569,7 @@ def test_dao_fetch_live_services_data(sample_user): "service_id": mock.ANY, "service_name": "Sample service", "organization_name": "test_org_1", - "organization_type": OrganizationType.FEDERAL, + "organization_type": OrganizationType.federal, "consent_to_research": None, "contact_name": "Test User", "contact_email": "notify@digital.fake.gov", diff --git a/tests/app/db.py b/tests/app/db.py index b4b2b3deb..701f3eb45 100644 --- a/tests/app/db.py +++ b/tests/app/db.py @@ -122,7 +122,7 @@ def create_service( prefix_sms=True, message_limit=1000, total_message_limit=250000, - organization_type=OrganizationType.FEDERAL, + organization_type=OrganizationType.federal, check_if_service_exists=False, go_live_user=None, go_live_at=None, From 9bf01d6bac2bbf9f653bb45a0573dc111cadbcea Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 12:12:49 -0800 Subject: [PATCH 18/33] update organizaton --- tests/app/dao/test_annual_billing_dao.py | 20 ++++++++--------- tests/app/organization/test_rest.py | 28 ++++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/app/dao/test_annual_billing_dao.py b/tests/app/dao/test_annual_billing_dao.py index f4c3e3d57..0a0938cc9 100644 --- a/tests/app/dao/test_annual_billing_dao.py +++ b/tests/app/dao/test_annual_billing_dao.py @@ -67,17 +67,17 @@ def test_dao_update_annual_billing_for_future_years(notify_db_session, sample_se @pytest.mark.parametrize( "org_type, year, expected_default", [ - (OrganizationType.FEDERAL, 2021, 150000), - (OrganizationType.STATE, 2021, 150000), + (OrganizationType.federal, 2021, 150000), + (OrganizationType.state, 2021, 150000), (None, 2021, 150000), - (OrganizationType.FEDERAL, 2020, 250000), - (OrganizationType.STATE, 2020, 250000), - (OrganizationType.OTHER, 2020, 250000), + (OrganizationType.federal, 2020, 250000), + (OrganizationType.state, 2020, 250000), + (OrganizationType.other, 2020, 250000), (None, 2020, 250000), - (OrganizationType.FEDERAL, 2019, 250000), - (OrganizationType.FEDERAL, 2022, 40000), - (OrganizationType.STATE, 2022, 40000), - (OrganizationType.FEDERAL, 2023, 40000), + (OrganizationType.federal, 2019, 250000), + (OrganizationType.federal, 2022, 40000), + (OrganizationType.state, 2022, 40000), + (OrganizationType.federal, 2023, 40000), ], ) def test_set_default_free_allowance_for_service( @@ -115,7 +115,7 @@ def test_set_default_free_allowance_for_service_updates_existing_year(sample_ser assert annual_billing[0].service_id == sample_service.id assert annual_billing[0].free_sms_fragment_limit == 150000 - sample_service.organization_type = OrganizationType.FEDERAL + sample_service.organization_type = OrganizationType.federal set_default_free_allowance_for_service(service=sample_service, year_start=None) annual_billing = AnnualBilling.query.all() diff --git a/tests/app/organization/test_rest.py b/tests/app/organization/test_rest.py index 1d521ca9c..80f32039d 100644 --- a/tests/app/organization/test_rest.py +++ b/tests/app/organization/test_rest.py @@ -31,7 +31,7 @@ def test_get_all_organizations(admin_request, notify_db_session): create_organization( - name="inactive org", active=False, organization_type=OrganizationType.FEDERAL + name="inactive org", active=False, organization_type=OrganizationType.federal ) create_organization(name="active org", domains=["example.com"]) @@ -59,7 +59,7 @@ def test_get_all_organizations(admin_request, notify_db_session): assert response[1]["active"] is False assert response[1]["count_of_live_services"] == 0 assert response[1]["domains"] == [] - assert response[1]["organization_type"] == OrganizationType.FEDERAL + assert response[1]["organization_type"] == OrganizationType.federal def test_get_organization_by_id(admin_request, notify_db_session): @@ -170,7 +170,7 @@ def test_post_create_organization(admin_request, notify_db_session): data = { "name": "test organization", "active": True, - "organization_type": OrganizationType.STATE, + "organization_type": OrganizationType.state, } response = admin_request.post( @@ -225,7 +225,7 @@ def test_post_create_organization_existing_name_raises_400( data = { "name": sample_organization.name, "active": True, - "organization_type": OrganizationType.FEDERAL, + "organization_type": OrganizationType.federal, } response = admin_request.post( @@ -245,7 +245,7 @@ def test_post_create_organization_works(admin_request, sample_organization): data = { "name": "org 2", "active": True, - "organization_type": OrganizationType.FEDERAL, + "organization_type": OrganizationType.federal, } admin_request.post( @@ -263,7 +263,7 @@ def test_post_create_organization_works(admin_request, sample_organization): ( { "active": False, - "organization_type": OrganizationType.FEDERAL, + "organization_type": OrganizationType.federal, }, "name is a required property", ), @@ -307,7 +307,7 @@ def test_post_update_organization_updates_fields( data = { "name": "new organization name", "active": False, - "organization_type": OrganizationType.FEDERAL, + "organization_type": OrganizationType.federal, } admin_request.post( @@ -324,7 +324,7 @@ def test_post_update_organization_updates_fields( assert organization[0].name == data["name"] assert organization[0].active == data["active"] assert organization[0].domains == [] - assert organization[0].organization_type == OrganizationType.FEDERAL + assert organization[0].organization_type == OrganizationType.federal @pytest.mark.parametrize( @@ -580,7 +580,7 @@ def test_post_update_organization_set_mou_emails_signed_by( def test_post_link_service_to_organization(admin_request, sample_service): data = {"service_id": str(sample_service.id)} - organization = create_organization(organization_type=OrganizationType.FEDERAL) + organization = create_organization(organization_type=OrganizationType.federal) admin_request.post( "organization.link_service_to_organization", @@ -589,7 +589,7 @@ def test_post_link_service_to_organization(admin_request, sample_service): _expected_status=204, ) assert len(organization.services) == 1 - assert sample_service.organization_type == OrganizationType.FEDERAL + assert sample_service.organization_type == OrganizationType.federal @freeze_time("2021-09-24 13:30") @@ -597,7 +597,7 @@ def test_post_link_service_to_organization_inserts_annual_billing( admin_request, sample_service ): data = {"service_id": str(sample_service.id)} - organization = create_organization(organization_type=OrganizationType.FEDERAL) + organization = create_organization(organization_type=OrganizationType.federal) assert len(organization.services) == 0 assert len(AnnualBilling.query.all()) == 0 admin_request.post( @@ -622,7 +622,7 @@ def test_post_link_service_to_organization_rollback_service_if_annual_billing_up data = {"service_id": str(sample_service.id)} assert not sample_service.organization_type - organization = create_organization(organization_type=OrganizationType.FEDERAL) + organization = create_organization(organization_type=OrganizationType.federal) assert len(organization.services) == 0 assert len(AnnualBilling.query.all()) == 0 with pytest.raises(expected_exception=SQLAlchemyError): @@ -653,7 +653,7 @@ def test_post_link_service_to_another_org( assert len(sample_organization.services) == 1 assert not sample_service.organization_type - new_org = create_organization(organization_type=OrganizationType.FEDERAL) + new_org = create_organization(organization_type=OrganizationType.federal) admin_request.post( "organization.link_service_to_organization", _data=data, @@ -662,7 +662,7 @@ def test_post_link_service_to_another_org( ) assert not sample_organization.services assert len(new_org.services) == 1 - assert sample_service.organization_type == OrganizationType.FEDERAL + assert sample_service.organization_type == OrganizationType.federal annual_billing = AnnualBilling.query.all() assert len(annual_billing) == 1 assert annual_billing[0].free_sms_fragment_limit == 150000 From 3824727e8dbbfa995c0defccd58eb09773368314 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 12:19:27 -0800 Subject: [PATCH 19/33] update organizaton --- tests/app/test_commands.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/app/test_commands.py b/tests/app/test_commands.py index e4a27c0e2..21b24dcfb 100644 --- a/tests/app/test_commands.py +++ b/tests/app/test_commands.py @@ -281,7 +281,7 @@ def test_insert_inbound_numbers_from_file(notify_db_session, notify_api, tmpdir) @pytest.mark.parametrize( "organization_type, expected_allowance", - [(OrganizationType.FEDERAL, 40000), (OrganizationType.STATE, 40000)], + [(OrganizationType.federal, 40000), (OrganizationType.state, 40000)], ) def test_populate_annual_billing_with_defaults( notify_db_session, notify_api, organization_type, expected_allowance @@ -307,7 +307,7 @@ def test_populate_annual_billing_with_defaults( @pytest.mark.parametrize( "organization_type, expected_allowance", - [(OrganizationType.FEDERAL, 40000), (OrganizationType.STATE, 40000)], + [(OrganizationType.federal, 40000), (OrganizationType.state, 40000)], ) def test_populate_annual_billing_with_the_previous_years_allowance( notify_db_session, notify_api, organization_type, expected_allowance @@ -364,7 +364,7 @@ def test_fix_billable_units(notify_db_session, notify_api, sample_template): def test_populate_annual_billing_with_defaults_sets_free_allowance_to_zero_if_previous_year_is_zero( notify_db_session, notify_api ): - service = create_service(organization_type=OrganizationType.FEDERAL) + service = create_service(organization_type=OrganizationType.federal) create_annual_billing( service_id=service.id, free_sms_fragment_limit=0, financial_year_start=2021 ) From 5dfe42a2b7b3c5f89e7f1ed5525607989230057a Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 12:24:56 -0800 Subject: [PATCH 20/33] update organizaton --- app/dao/annual_billing_dao.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/dao/annual_billing_dao.py b/app/dao/annual_billing_dao.py index 306a2dd86..1bac24a4e 100644 --- a/app/dao/annual_billing_dao.py +++ b/app/dao/annual_billing_dao.py @@ -76,17 +76,17 @@ def dao_get_all_free_sms_fragment_limit(service_id): def set_default_free_allowance_for_service(service, year_start=None): default_free_sms_fragment_limits = { - OrganizationType.FEDERAL: { + OrganizationType.federal: { 2020: 250_000, 2021: 150_000, 2022: 40_000, }, - OrganizationType.STATE: { + OrganizationType.state: { 2020: 250_000, 2021: 150_000, 2022: 40_000, }, - OrganizationType.OTHER: { + OrganizationType.other: { 2020: 250_000, 2021: 150_000, 2022: 40_000, @@ -108,7 +108,7 @@ def set_default_free_allowance_for_service(service, year_start=None): f"no organization type for service {service.id}. Using other default of " f"{default_free_sms_fragment_limits['other'][year_start]}" ) - free_allowance = default_free_sms_fragment_limits[OrganizationType.OTHER][ + free_allowance = default_free_sms_fragment_limits[OrganizationType.other][ year_start ] From 4fb236bb28751258ee365d49e49ccc52b8a39530 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 12:35:33 -0800 Subject: [PATCH 21/33] update organizaton --- app/models.py | 2 +- tests/app/service/test_rest.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models.py b/app/models.py index c26aa26b4..06c61a906 100644 --- a/app/models.py +++ b/app/models.py @@ -499,7 +499,7 @@ def serialize(self) -> dict: "email_branding_id": self.email_branding_id, "agreement_signed": self.agreement_signed, "agreement_signed_at": self.agreement_signed_at, - "agreement_signed_by_id": self.agreemnt_signed_by_id, + "agreement_signed_by_id": self.agreement_signed_by_id, "agreement_signed_on_behalf_of_name": self.agreement_signed_on_behalf_of_name, "agreement_signed_on_behalf_of_email_address": self.agreement_signed_on_behalf_of_email_address, "agreement_signed_version": self.agreement_signed_version, diff --git a/tests/app/service/test_rest.py b/tests/app/service/test_rest.py index 42520e389..c6c8647f3 100644 --- a/tests/app/service/test_rest.py +++ b/tests/app/service/test_rest.py @@ -726,7 +726,7 @@ def test_update_service(client, notify_db_session, sample_service): "email_from": "updated.service.name", "created_by": str(sample_service.created_by.id), "email_branding": str(brand.id), - "organization_type": OrganizationType.FEDERAL, + "organization_type": OrganizationType.federal, } auth_header = create_admin_authorization_header() @@ -741,7 +741,7 @@ def test_update_service(client, notify_db_session, sample_service): assert result["data"]["name"] == "updated service name" assert result["data"]["email_from"] == "updated.service.name" assert result["data"]["email_branding"] == str(brand.id) - assert result["data"]["organization_type"] == OrganizationType.FEDERAL + assert result["data"]["organization_type"] == OrganizationType.federal def test_cant_update_service_org_type_to_random_value(client, sample_service): From 719d0ff55c4c91b7cc3c45b431ca62f7cf8ce471 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 14:02:06 -0800 Subject: [PATCH 22/33] update organizaton --- .ds.baseline | 6 ++--- tests/app/user/test_rest.py | 54 ++++++++++++++++++++++--------------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/.ds.baseline b/.ds.baseline index 8aaa131c5..37712951f 100644 --- a/.ds.baseline +++ b/.ds.baseline @@ -341,7 +341,7 @@ "filename": "tests/app/user/test_rest.py", "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", "is_verified": false, - "line_number": 108, + "line_number": 109, "is_secret": false }, { @@ -349,7 +349,7 @@ "filename": "tests/app/user/test_rest.py", "hashed_secret": "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33", "is_verified": false, - "line_number": 826, + "line_number": 836, "is_secret": false } ], @@ -384,5 +384,5 @@ } ] }, - "generated_at": "2024-10-31T21:25:32Z" + "generated_at": "2024-11-20T22:01:58Z" } diff --git a/tests/app/user/test_rest.py b/tests/app/user/test_rest.py index f1ea5041b..350e0d191 100644 --- a/tests/app/user/test_rest.py +++ b/tests/app/user/test_rest.py @@ -87,14 +87,15 @@ def test_get_user_doesnt_return_inactive_services_and_orgs( sample_user = sample_service.users[0] sample_user.organizations = [sample_organization] - json_resp = admin_request.get("user.get_user", user_id=sample_user.id) + with db.session.no_flush: + json_resp = admin_request.get("user.get_user", user_id=sample_user.id) - fetched = json_resp["data"] + fetched = json_resp["data"] - assert fetched["id"] == str(sample_user.id) - assert fetched["services"] == [] - assert fetched["organizations"] == [] - assert fetched["permissions"] == {} + assert fetched["id"] == str(sample_user.id) + assert fetched["services"] == [] + assert fetched["organizations"] == [] + assert fetched["permissions"] == {} def test_post_user(admin_request, notify_db_session): @@ -113,13 +114,16 @@ def test_post_user(admin_request, notify_db_session): "permissions": {}, "auth_type": AuthType.EMAIL, } - json_resp = admin_request.post("user.create_user", _data=data, _expected_status=201) + with db.session.no_flush: + json_resp = admin_request.post( + "user.create_user", _data=data, _expected_status=201 + ) - user = User.query.filter_by(email_address="user@digital.fake.gov").first() - assert user.check_password("password") - assert json_resp["data"]["email_address"] == user.email_address - assert json_resp["data"]["id"] == str(user.id) - assert user.auth_type == AuthType.EMAIL + user = User.query.filter_by(email_address="user@digital.fake.gov").first() + assert user.check_password("password") + assert json_resp["data"]["email_address"] == user.email_address + assert json_resp["data"]["id"] == str(user.id) + assert user.auth_type == AuthType.EMAIL def test_post_user_without_auth_type(admin_request, notify_db_session): @@ -132,11 +136,14 @@ def test_post_user_without_auth_type(admin_request, notify_db_session): "permissions": {}, } - json_resp = admin_request.post("user.create_user", _data=data, _expected_status=201) + with db.session.no_flush: + json_resp = admin_request.post( + "user.create_user", _data=data, _expected_status=201 + ) - user = User.query.filter_by(email_address="user@digital.fake.gov").first() - assert json_resp["data"]["id"] == str(user.id) - assert user.auth_type == AuthType.SMS + user = User.query.filter_by(email_address="user@digital.fake.gov").first() + assert json_resp["data"]["id"] == str(user.id) + assert user.auth_type == AuthType.SMS def test_post_user_missing_attribute_email(admin_request, notify_db_session): @@ -153,12 +160,15 @@ def test_post_user_missing_attribute_email(admin_request, notify_db_session): "failed_login_count": 0, "permissions": {}, } - json_resp = admin_request.post("user.create_user", _data=data, _expected_status=400) - - assert _get_user_count() == 0 - assert {"email_address": ["Missing data for required field."]} == json_resp[ - "message" - ] + with db.session.no_flush: + json_resp = admin_request.post( + "user.create_user", _data=data, _expected_status=400 + ) + + assert _get_user_count() == 0 + assert {"email_address": ["Missing data for required field."]} == json_resp[ + "message" + ] def _get_user_count(): From 5b40d0e876aa56b02b7bcc6ef280759ab5291cc8 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 14:30:44 -0800 Subject: [PATCH 23/33] update organizaton --- tests/app/user/test_rest.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/app/user/test_rest.py b/tests/app/user/test_rest.py index 350e0d191..0557782f4 100644 --- a/tests/app/user/test_rest.py +++ b/tests/app/user/test_rest.py @@ -87,7 +87,7 @@ def test_get_user_doesnt_return_inactive_services_and_orgs( sample_user = sample_service.users[0] sample_user.organizations = [sample_organization] - with db.session.no_flush: + with db.session.no_autoflush: json_resp = admin_request.get("user.get_user", user_id=sample_user.id) fetched = json_resp["data"] @@ -114,7 +114,7 @@ def test_post_user(admin_request, notify_db_session): "permissions": {}, "auth_type": AuthType.EMAIL, } - with db.session.no_flush: + with db.session.no_autoflush: json_resp = admin_request.post( "user.create_user", _data=data, _expected_status=201 ) @@ -136,7 +136,7 @@ def test_post_user_without_auth_type(admin_request, notify_db_session): "permissions": {}, } - with db.session.no_flush: + with db.session.no_autoflush: json_resp = admin_request.post( "user.create_user", _data=data, _expected_status=201 ) @@ -160,7 +160,7 @@ def test_post_user_missing_attribute_email(admin_request, notify_db_session): "failed_login_count": 0, "permissions": {}, } - with db.session.no_flush: + with db.session.no_autoflush: json_resp = admin_request.post( "user.create_user", _data=data, _expected_status=400 ) From 17d8ceab2c7af98ae00e2f02a54995e0b1153fde Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 14:41:45 -0800 Subject: [PATCH 24/33] update organizaton --- .ds.baseline | 6 +- tests/app/user/test_rest.py | 112 ++++++++++++++++++------------------ 2 files changed, 60 insertions(+), 58 deletions(-) diff --git a/.ds.baseline b/.ds.baseline index 37712951f..6e001cebe 100644 --- a/.ds.baseline +++ b/.ds.baseline @@ -341,7 +341,7 @@ "filename": "tests/app/user/test_rest.py", "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", "is_verified": false, - "line_number": 109, + "line_number": 110, "is_secret": false }, { @@ -349,7 +349,7 @@ "filename": "tests/app/user/test_rest.py", "hashed_secret": "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33", "is_verified": false, - "line_number": 836, + "line_number": 837, "is_secret": false } ], @@ -384,5 +384,5 @@ } ] }, - "generated_at": "2024-11-20T22:01:58Z" + "generated_at": "2024-11-20T22:41:41Z" } diff --git a/tests/app/user/test_rest.py b/tests/app/user/test_rest.py index 0557782f4..d1abd36ac 100644 --- a/tests/app/user/test_rest.py +++ b/tests/app/user/test_rest.py @@ -55,24 +55,25 @@ def test_get_user(admin_request, sample_service, sample_organization): """ sample_user = sample_service.users[0] sample_user.organizations = [sample_organization] - json_resp = admin_request.get("user.get_user", user_id=sample_user.id) + with db.session.no_autoflush: + json_resp = admin_request.get("user.get_user", user_id=sample_user.id) - expected_permissions = PermissionType.defaults() - fetched = json_resp["data"] + expected_permissions = PermissionType.defaults() + fetched = json_resp["data"] - assert fetched["id"] == str(sample_user.id) - assert fetched["name"] == sample_user.name - assert fetched["mobile_number"] == sample_user.mobile_number - assert fetched["email_address"] == sample_user.email_address - assert fetched["state"] == sample_user.state - assert fetched["auth_type"] == AuthType.SMS - assert fetched["permissions"].keys() == {str(sample_service.id)} - assert fetched["services"] == [str(sample_service.id)] - assert fetched["organizations"] == [str(sample_organization.id)] - assert fetched["can_use_webauthn"] is False - assert sorted(fetched["permissions"][str(sample_service.id)]) == sorted( - expected_permissions - ) + assert fetched["id"] == str(sample_user.id) + assert fetched["name"] == sample_user.name + assert fetched["mobile_number"] == sample_user.mobile_number + assert fetched["email_address"] == sample_user.email_address + assert fetched["state"] == sample_user.state + assert fetched["auth_type"] == AuthType.SMS + assert fetched["permissions"].keys() == {str(sample_service.id)} + assert fetched["services"] == [str(sample_service.id)] + assert fetched["organizations"] == [str(sample_organization.id)] + assert fetched["can_use_webauthn"] is False + assert sorted(fetched["permissions"][str(sample_service.id)]) == sorted( + expected_permissions + ) def test_get_user_doesnt_return_inactive_services_and_orgs( @@ -855,46 +856,47 @@ def test_get_orgs_and_services_nests_services(admin_request, sample_user): sample_user.organizations = [org1, org2] sample_user.services = [service1, service2, service3] - resp = admin_request.get( - "user.get_organizations_and_services_for_user", user_id=sample_user.id - ) + with db.session.no_autoflush: + resp = admin_request.get( + "user.get_organizations_and_services_for_user", user_id=sample_user.id + ) - assert set(resp.keys()) == { - "organizations", - "services", - } - assert resp["organizations"] == [ - { - "name": org1.name, - "id": str(org1.id), - "count_of_live_services": 2, - }, - { - "name": org2.name, - "id": str(org2.id), - "count_of_live_services": 0, - }, - ] - assert resp["services"] == [ - { - "name": service1.name, - "id": str(service1.id), - "restricted": False, - "organization": str(org1.id), - }, - { - "name": service2.name, - "id": str(service2.id), - "restricted": False, - "organization": str(org1.id), - }, - { - "name": service3.name, - "id": str(service3.id), - "restricted": False, - "organization": None, - }, - ] + assert set(resp.keys()) == { + "organizations", + "services", + } + assert resp["organizations"] == [ + { + "name": org1.name, + "id": str(org1.id), + "count_of_live_services": 2, + }, + { + "name": org2.name, + "id": str(org2.id), + "count_of_live_services": 0, + }, + ] + assert resp["services"] == [ + { + "name": service1.name, + "id": str(service1.id), + "restricted": False, + "organization": str(org1.id), + }, + { + "name": service2.name, + "id": str(service2.id), + "restricted": False, + "organization": str(org1.id), + }, + { + "name": service3.name, + "id": str(service3.id), + "restricted": False, + "organization": None, + }, + ] def test_get_orgs_and_services_only_returns_active(admin_request, sample_user): From c8bc68a7de7638af7f0cdf9fec26ad79a363d990 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Wed, 20 Nov 2024 15:00:08 -0800 Subject: [PATCH 25/33] update organizaton --- tests/app/user/test_rest.py | 114 ++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 56 deletions(-) diff --git a/tests/app/user/test_rest.py b/tests/app/user/test_rest.py index d1abd36ac..93047153e 100644 --- a/tests/app/user/test_rest.py +++ b/tests/app/user/test_rest.py @@ -918,41 +918,42 @@ def test_get_orgs_and_services_only_returns_active(admin_request, sample_user): sample_user.organizations = [org1, org2] sample_user.services = [service1, service2, service3, service4, service5] - resp = admin_request.get( - "user.get_organizations_and_services_for_user", user_id=sample_user.id - ) + with db.session.no_autoflush: + resp = admin_request.get( + "user.get_organizations_and_services_for_user", user_id=sample_user.id + ) - assert set(resp.keys()) == { - "organizations", - "services", - } - assert resp["organizations"] == [ - { - "name": org1.name, - "id": str(org1.id), - "count_of_live_services": 1, + assert set(resp.keys()) == { + "organizations", + "services", } - ] - assert resp["services"] == [ - { - "name": service1.name, - "id": str(service1.id), - "restricted": False, - "organization": str(org1.id), - }, - { - "name": service3.name, - "id": str(service3.id), - "restricted": False, - "organization": str(org2.id), - }, - { - "name": service4.name, - "id": str(service4.id), - "restricted": False, - "organization": None, - }, - ] + assert resp["organizations"] == [ + { + "name": org1.name, + "id": str(org1.id), + "count_of_live_services": 1, + } + ] + assert resp["services"] == [ + { + "name": service1.name, + "id": str(service1.id), + "restricted": False, + "organization": str(org1.id), + }, + { + "name": service3.name, + "id": str(service3.id), + "restricted": False, + "organization": str(org2.id), + }, + { + "name": service4.name, + "id": str(service4.id), + "restricted": False, + "organization": None, + }, + ] def test_get_orgs_and_services_only_shows_users_orgs_and_services( @@ -973,31 +974,32 @@ def test_get_orgs_and_services_only_shows_users_orgs_and_services( other_user.organizations = [org1, org2] other_user.services = [service1, service2] - resp = admin_request.get( - "user.get_organizations_and_services_for_user", user_id=sample_user.id - ) + with db.session.no_autoflush: + resp = admin_request.get( + "user.get_organizations_and_services_for_user", user_id=sample_user.id + ) - assert set(resp.keys()) == { - "organizations", - "services", - } - assert resp["organizations"] == [ - { - "name": org2.name, - "id": str(org2.id), - "count_of_live_services": 0, - } - ] - # 'services' always returns the org_id no matter whether the user - # belongs to that org or not - assert resp["services"] == [ - { - "name": service1.name, - "id": str(service1.id), - "restricted": False, - "organization": str(org1.id), + assert set(resp.keys()) == { + "organizations", + "services", } - ] + assert resp["organizations"] == [ + { + "name": org2.name, + "id": str(org2.id), + "count_of_live_services": 0, + } + ] + # 'services' always returns the org_id no matter whether the user + # belongs to that org or not + assert resp["services"] == [ + { + "name": service1.name, + "id": str(service1.id), + "restricted": False, + "organization": str(org1.id), + } + ] def test_find_users_by_email_finds_user_by_partial_email( From 70837ba75f36d89ccd43ff27944d560b052ef4cc Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 21 Nov 2024 07:47:38 -0800 Subject: [PATCH 26/33] update organizaton --- tests/app/user/test_rest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/app/user/test_rest.py b/tests/app/user/test_rest.py index 93047153e..900d684db 100644 --- a/tests/app/user/test_rest.py +++ b/tests/app/user/test_rest.py @@ -915,10 +915,10 @@ def test_get_orgs_and_services_only_returns_active(admin_request, sample_user): org1.services = [service1, service2] org2.services = [service3] - sample_user.organizations = [org1, org2] - sample_user.services = [service1, service2, service3, service4, service5] - with db.session.no_autoflush: + sample_user.organizations = [org1, org2] + sample_user.services = [service1, service2, service3, service4, service5] + resp = admin_request.get( "user.get_organizations_and_services_for_user", user_id=sample_user.id ) From 42146002a753709637a5bb3c99c370e27292bdd2 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 21 Nov 2024 08:10:27 -0800 Subject: [PATCH 27/33] update organizaton --- tests/app/user/test_rest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/app/user/test_rest.py b/tests/app/user/test_rest.py index 900d684db..391e0ea0b 100644 --- a/tests/app/user/test_rest.py +++ b/tests/app/user/test_rest.py @@ -968,13 +968,13 @@ def test_get_orgs_and_services_only_shows_users_orgs_and_services( org1.services = [service1] - sample_user.organizations = [org2] - sample_user.services = [service1] + with db.session.no_autoflush: + sample_user.organizations = [org2] + sample_user.services = [service1] - other_user.organizations = [org1, org2] - other_user.services = [service1, service2] + other_user.organizations = [org1, org2] + other_user.services = [service1, service2] - with db.session.no_autoflush: resp = admin_request.get( "user.get_organizations_and_services_for_user", user_id=sample_user.id ) From 36dd15edbccf7acd74f094890ed1e5288e60039e Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 21 Nov 2024 08:30:14 -0800 Subject: [PATCH 28/33] update organizaton --- tests/app/user/test_rest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/app/user/test_rest.py b/tests/app/user/test_rest.py index 391e0ea0b..b43eb6eca 100644 --- a/tests/app/user/test_rest.py +++ b/tests/app/user/test_rest.py @@ -850,13 +850,13 @@ def test_get_orgs_and_services_nests_services(admin_request, sample_user): service2 = create_service(service_name="service2") service3 = create_service(service_name="service3") - org1.services = [service1, service2] - org2.services = [] + with db.session.no_autoflush: + org1.services = [service1, service2] + org2.services = [] - sample_user.organizations = [org1, org2] - sample_user.services = [service1, service2, service3] + sample_user.organizations = [org1, org2] + sample_user.services = [service1, service2, service3] - with db.session.no_autoflush: resp = admin_request.get( "user.get_organizations_and_services_for_user", user_id=sample_user.id ) From 0e5f08937ce1738d6535d9386ae4b264bd481d35 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 21 Nov 2024 11:15:56 -0800 Subject: [PATCH 29/33] more --- tests/app/organization/test_rest.py | 69 +++++++++++++++-------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/tests/app/organization/test_rest.py b/tests/app/organization/test_rest.py index 80f32039d..c6c8ae8aa 100644 --- a/tests/app/organization/test_rest.py +++ b/tests/app/organization/test_rest.py @@ -762,16 +762,17 @@ def test_rest_get_organization_services_inactive_services_at_end( def test_add_user_to_organization_returns_added_user( admin_request, sample_organization, sample_user ): - response = admin_request.post( - "organization.add_user_to_organization", - organization_id=str(sample_organization.id), - user_id=str(sample_user.id), - _expected_status=200, - ) + with db.session.no_autoflush: + response = admin_request.post( + "organization.add_user_to_organization", + organization_id=str(sample_organization.id), + user_id=str(sample_user.id), + _expected_status=200, + ) - assert response["data"]["id"] == str(sample_user.id) - assert len(response["data"]["organizations"]) == 1 - assert response["data"]["organizations"][0] == str(sample_organization.id) + assert response["data"]["id"] == str(sample_user.id) + assert len(response["data"]["organizations"]) == 1 + assert response["data"]["organizations"][0] == str(sample_organization.id) def test_add_user_to_organization_returns_404_if_user_does_not_exist( @@ -786,17 +787,18 @@ def test_add_user_to_organization_returns_404_if_user_does_not_exist( def test_remove_user_from_organization(admin_request, sample_organization, sample_user): - dao_add_user_to_organization( - organization_id=sample_organization.id, user_id=sample_user.id - ) + with db.session.no_autoflush: + dao_add_user_to_organization( + organization_id=sample_organization.id, user_id=sample_user.id + ) - admin_request.delete( - "organization.remove_user_from_organization", - organization_id=sample_organization.id, - user_id=sample_user.id, - ) + admin_request.delete( + "organization.remove_user_from_organization", + organization_id=sample_organization.id, + user_id=sample_user.id, + ) - assert sample_organization.users == [] + assert sample_organization.users == [] def test_remove_user_from_organization_when_user_is_not_an_org_member( @@ -815,23 +817,24 @@ def test_remove_user_from_organization_when_user_is_not_an_org_member( def test_get_organization_users_returns_users_for_organization( admin_request, sample_organization ): - first = create_user(email="first@invited.com") - second = create_user(email="another@invited.com") - dao_add_user_to_organization( - organization_id=sample_organization.id, user_id=first.id - ) - dao_add_user_to_organization( - organization_id=sample_organization.id, user_id=second.id - ) + with db.session.no_autoflush: + first = create_user(email="first@invited.com") + second = create_user(email="another@invited.com") + dao_add_user_to_organization( + organization_id=sample_organization.id, user_id=first.id + ) + dao_add_user_to_organization( + organization_id=sample_organization.id, user_id=second.id + ) - response = admin_request.get( - "organization.get_organization_users", - organization_id=sample_organization.id, - _expected_status=200, - ) + response = admin_request.get( + "organization.get_organization_users", + organization_id=sample_organization.id, + _expected_status=200, + ) - assert len(response["data"]) == 2 - assert response["data"][0]["id"] == str(first.id) + assert len(response["data"]) == 2 + assert response["data"][0]["id"] == str(first.id) @freeze_time("2019-12-24 13:30") From 8bee8737835bf5e071f10a865f8b406685508b14 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 21 Nov 2024 11:29:17 -0800 Subject: [PATCH 30/33] try merge instead of add --- app/dao/organization_dao.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/dao/organization_dao.py b/app/dao/organization_dao.py index 668ac6c25..41fe88a32 100644 --- a/app/dao/organization_dao.py +++ b/app/dao/organization_dao.py @@ -133,7 +133,7 @@ def dao_add_user_to_organization(organization_id, user_id): stmt = select(User).filter_by(id=user_id) user = db.session.execute(stmt).scalars().one() user.organizations.append(organization) - db.session.add(organization) + db.session.merge(organization) return user From 779c360f990ebe8c3287600b0f9a1e30fd01be0e Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 21 Nov 2024 11:38:53 -0800 Subject: [PATCH 31/33] try flush instead of merge --- app/dao/organization_dao.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/dao/organization_dao.py b/app/dao/organization_dao.py index 41fe88a32..3099854f1 100644 --- a/app/dao/organization_dao.py +++ b/app/dao/organization_dao.py @@ -133,7 +133,8 @@ def dao_add_user_to_organization(organization_id, user_id): stmt = select(User).filter_by(id=user_id) user = db.session.execute(stmt).scalars().one() user.organizations.append(organization) - db.session.merge(organization) + db.session.add(organization) + db.session.flush() return user From b260be1cd90283cc4f900849f497fb0d6dba30d9 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 21 Nov 2024 11:51:14 -0800 Subject: [PATCH 32/33] try delete before add --- tests/app/organization/test_rest.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/app/organization/test_rest.py b/tests/app/organization/test_rest.py index c6c8ae8aa..c71634e90 100644 --- a/tests/app/organization/test_rest.py +++ b/tests/app/organization/test_rest.py @@ -788,6 +788,12 @@ def test_add_user_to_organization_returns_404_if_user_does_not_exist( def test_remove_user_from_organization(admin_request, sample_organization, sample_user): with db.session.no_autoflush: + admin_request.delete( + "organization.remove_user_from_organization", + organization_id=sample_organization.id, + user_id=sample_user.id, + ) + dao_add_user_to_organization( organization_id=sample_organization.id, user_id=sample_user.id ) From ab6b1d9b49d0972553f22ded576d5e09f1b38ee0 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Thu, 21 Nov 2024 12:14:34 -0800 Subject: [PATCH 33/33] try delete before add --- app/dao/organization_dao.py | 7 ++++--- tests/app/organization/test_rest.py | 5 ----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/dao/organization_dao.py b/app/dao/organization_dao.py index 3099854f1..92f0ec03b 100644 --- a/app/dao/organization_dao.py +++ b/app/dao/organization_dao.py @@ -132,9 +132,10 @@ def dao_add_user_to_organization(organization_id, user_id): organization = dao_get_organization_by_id(organization_id) stmt = select(User).filter_by(id=user_id) user = db.session.execute(stmt).scalars().one() - user.organizations.append(organization) - db.session.add(organization) - db.session.flush() + print(f"ORG TO ADD {organization} USER ORGS {user.organizations}") + if organization not in user.organizations: + user.organizations.append(organization) + db.session.add(organization) return user diff --git a/tests/app/organization/test_rest.py b/tests/app/organization/test_rest.py index c71634e90..39c92cb31 100644 --- a/tests/app/organization/test_rest.py +++ b/tests/app/organization/test_rest.py @@ -788,11 +788,6 @@ def test_add_user_to_organization_returns_404_if_user_does_not_exist( def test_remove_user_from_organization(admin_request, sample_organization, sample_user): with db.session.no_autoflush: - admin_request.delete( - "organization.remove_user_from_organization", - organization_id=sample_organization.id, - user_id=sample_user.id, - ) dao_add_user_to_organization( organization_id=sample_organization.id, user_id=sample_user.id