mirror of
https://github.com/GSA/notifications-api.git
synced 2026-09-11 10:28:55 -04:00
Merge pull request #621 from GSA/API-331_Create_Properties_On_Org_Model
Api 331 create properties on org model
This commit is contained in:
+50
-2
@@ -1,6 +1,7 @@
|
||||
import datetime
|
||||
import itertools
|
||||
import uuid
|
||||
from enum import Enum
|
||||
|
||||
from flask import current_app, url_for
|
||||
from notifications_utils.clients.encryption.encryption_client import EncryptionError
|
||||
@@ -433,6 +434,32 @@ class Organization(db.Model):
|
||||
def domain_list(self):
|
||||
return [domain.domain for domain in self.domains]
|
||||
|
||||
@property
|
||||
def agreement(self):
|
||||
try:
|
||||
active_agreements = [
|
||||
agreement
|
||||
for agreement in self.agreements
|
||||
if agreement.status == AgreementStatus.ACTIVE
|
||||
]
|
||||
return active_agreements[0]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
@property
|
||||
def agreement_active(self):
|
||||
try:
|
||||
return self.agreement.status == AgreementStatus.ACTIVE
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_mou(self):
|
||||
try:
|
||||
return self.agreement.type == AgreementType.MOU
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
def serialize(self):
|
||||
return {
|
||||
"id": str(self.id),
|
||||
@@ -2353,14 +2380,34 @@ class WebauthnCredential(db.Model):
|
||||
}
|
||||
|
||||
|
||||
class AgreementType(Enum):
|
||||
MOU = "MOU"
|
||||
IAA = "IAA"
|
||||
|
||||
|
||||
class AgreementStatus(Enum):
|
||||
ACTIVE = "active"
|
||||
EXPIRED = "expired"
|
||||
|
||||
|
||||
class Agreement(db.Model):
|
||||
__tablename__ = "agreements"
|
||||
id = db.Column(
|
||||
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=False
|
||||
)
|
||||
type = db.Column(db.String(3), nullable=False, unique=True, index=True)
|
||||
type = db.Column(
|
||||
db.Enum(AgreementType, name="agreement_types"),
|
||||
index=False,
|
||||
unique=False,
|
||||
nullable=False,
|
||||
)
|
||||
partner_name = db.Column(db.String(255), nullable=False, unique=True, index=True)
|
||||
status = db.Column(db.String(255), nullable=False, unique=True, index=True)
|
||||
status = db.Column(
|
||||
db.Enum(AgreementStatus, name="agreement_statuses"),
|
||||
index=False,
|
||||
unique=False,
|
||||
nullable=False,
|
||||
)
|
||||
start_time = db.Column(db.DateTime, nullable=True)
|
||||
end_time = db.Column(db.DateTime, nullable=True)
|
||||
url = db.Column(db.String(255), nullable=False, unique=True, index=True)
|
||||
@@ -2370,6 +2417,7 @@ class Agreement(db.Model):
|
||||
db.ForeignKey("organization.id"),
|
||||
nullable=True,
|
||||
)
|
||||
organization = db.relationship("Organization", backref="agreements")
|
||||
|
||||
def serialize(self):
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
|
||||
Revision ID: eb7747053d5d
|
||||
Revises: 0404_expire_invites
|
||||
Create Date: 2023-11-17 15:39:45.470089
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
revision = "0406_adjust_agreement_model"
|
||||
down_revision = "0405_add_preferred_timezone"
|
||||
|
||||
agreement_type_name = "agreement_types"
|
||||
agreement_type_options = ("MOU", "IAA")
|
||||
agreement_types = sa.Enum(*agreement_type_options, name=agreement_type_name)
|
||||
|
||||
agreement_status_name = "agreement_statuses"
|
||||
agreement_status_options = ("active", "expired")
|
||||
agreement_statuses = sa.Enum(*agreement_status_options, name=agreement_status_name)
|
||||
|
||||
|
||||
def upgrade():
|
||||
agreement_types.create(op.get_bind())
|
||||
op.execute(
|
||||
f"ALTER TABLE agreements ALTER COLUMN type TYPE {agreement_type_name} using type::text::{agreement_type_name}"
|
||||
)
|
||||
|
||||
agreement_statuses.create(op.get_bind())
|
||||
op.execute(
|
||||
f"ALTER TABLE agreements ALTER COLUMN status TYPE {agreement_status_name} using status::text::{agreement_status_name}"
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.alter_column(
|
||||
"agreements",
|
||||
"status",
|
||||
existing_type=agreement_statuses,
|
||||
type_=sa.VARCHAR(length=255),
|
||||
existing_nullable=False,
|
||||
)
|
||||
op.execute(f"DROP TYPE {agreement_status_name}")
|
||||
|
||||
op.alter_column(
|
||||
"agreements",
|
||||
"type",
|
||||
existing_type=agreement_types,
|
||||
type_=sa.VARCHAR(length=3),
|
||||
existing_nullable=False,
|
||||
)
|
||||
op.execute(f"DROP TYPE {agreement_type_name}")
|
||||
@@ -133,16 +133,18 @@ def test_should_delete_all_invitations_more_than_one_day_old(
|
||||
def test_should_not_delete_invitations_less_than_two_days_old(
|
||||
sample_user, sample_service
|
||||
):
|
||||
two_days = timedelta(days=2)
|
||||
one_second = timedelta(seconds=1)
|
||||
make_invitation(
|
||||
sample_user,
|
||||
sample_service,
|
||||
age=timedelta(hours=47, minutes=59, seconds=59),
|
||||
age=two_days - one_second, # Not quite two days
|
||||
email_address="valid@2.com",
|
||||
)
|
||||
make_invitation(
|
||||
sample_user,
|
||||
sample_service,
|
||||
age=timedelta(hours=48),
|
||||
age=two_days,
|
||||
email_address="expired@1.com",
|
||||
)
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ from app.models import (
|
||||
NOTIFICATION_TECHNICAL_FAILURE,
|
||||
SMS_TYPE,
|
||||
Agreement,
|
||||
AgreementStatus,
|
||||
AgreementType,
|
||||
AnnualBilling,
|
||||
Notification,
|
||||
NotificationHistory,
|
||||
@@ -28,6 +30,7 @@ from app.models import (
|
||||
from tests.app.db import (
|
||||
create_inbound_number,
|
||||
create_notification,
|
||||
create_organization,
|
||||
create_rate,
|
||||
create_reply_to_email,
|
||||
create_service,
|
||||
@@ -412,6 +415,46 @@ def test_rate_str():
|
||||
assert rate.__str__() == "1.5 sms 2023-01-01 00:00:00"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["agreement_type", "expected"],
|
||||
(
|
||||
(AgreementType.IAA, False),
|
||||
(AgreementType.MOU, True),
|
||||
),
|
||||
)
|
||||
def test_organization_agreement_mou(notify_db_session, agreement_type, expected):
|
||||
now = datetime.utcnow()
|
||||
agree = Agreement()
|
||||
agree.id = "whatever"
|
||||
agree.start_time = now
|
||||
agree.end_time = now
|
||||
agree.status = AgreementStatus.ACTIVE
|
||||
agree.type = agreement_type
|
||||
organization = create_organization(name="Something")
|
||||
organization.agreements.append(agree)
|
||||
assert organization.has_mou == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["agreement_status", "expected"],
|
||||
(
|
||||
(AgreementStatus.EXPIRED, False),
|
||||
(AgreementStatus.ACTIVE, True),
|
||||
),
|
||||
)
|
||||
def test_organization_agreement_active(notify_db_session, agreement_status, expected):
|
||||
now = datetime.utcnow()
|
||||
agree = Agreement()
|
||||
agree.id = "whatever"
|
||||
agree.start_time = now
|
||||
agree.end_time = now
|
||||
agree.status = agreement_status
|
||||
agree.type = AgreementType.IAA
|
||||
organization = create_organization(name="Something")
|
||||
organization.agreements.append(agree)
|
||||
assert organization.agreement_active == expected
|
||||
|
||||
|
||||
def test_agreement_serialize():
|
||||
agree = Agreement()
|
||||
agree.id = "abc"
|
||||
|
||||
Reference in New Issue
Block a user