diff --git a/legal-api/manage.py b/legal-api/manage.py index 703a97702a..7ab202b25e 100644 --- a/legal-api/manage.py +++ b/legal-api/manage.py @@ -16,7 +16,6 @@ """ import logging -from flask import url_for from flask_migrate import Migrate, MigrateCommand from flask_script import Manager # class for handling a set of commands @@ -32,25 +31,6 @@ MANAGER.add_command("db", MigrateCommand) - -@MANAGER.command -def list_routes(): - output = [] - for rule in APP.url_map.iter_rules(): - - options = {} - for arg in rule.arguments: - options[arg] = f"[{arg}]" - - methods = ",".join(rule.methods) - url = url_for(rule.endpoint, **options) - line = (f"{rule.endpoint:50s} {methods:20s} {url}") - output.append(line) - - for line in sorted(output): - print(line) # noqa: T201 - - if __name__ == "__main__": logging.log(logging.INFO, "Running the Manager") MANAGER.run() diff --git a/legal-api/migrations/versions/edbd0f6ef10e_ar_reminder_opt_out.py b/legal-api/migrations/versions/edbd0f6ef10e_ar_reminder_opt_out.py new file mode 100644 index 0000000000..0f5df139c0 --- /dev/null +++ b/legal-api/migrations/versions/edbd0f6ef10e_ar_reminder_opt_out.py @@ -0,0 +1,98 @@ +"""ar_reminder_opt_out + +Revision ID: edbd0f6ef10e +Revises: 7efd0c42babd +Create Date: 2026-02-13 23:48:54.926017 + +""" +from datetime import datetime, timezone +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'edbd0f6ef10e' +down_revision = '7efd0c42babd' +branch_labels = None +depends_on = None + + +def upgrade(): + now = datetime.now(timezone.utc) + + permissions = sa.table( + 'permissions', + sa.column('id', sa.Integer), + sa.column('permission_name', sa.String), + sa.column('description', sa.String), + sa.column('created_date', sa.TIMESTAMP(timezone=True)), + sa.column('last_modified', sa.TIMESTAMP(timezone=True)), + sa.column('created_by_id', sa.Integer), + sa.column('modified_by_id', sa.Integer) + ) + + op.bulk_insert( + permissions, + [{ + 'permission_name': 'AR_REMINDER_OPT_OUT', + 'description': 'Authorized to access Opt out ar reminder option.', + 'created_date': now, + 'last_modified': now, + 'created_by_id': None, + 'modified_by_id': None + }] + ) + + bind = op.get_bind() + + roles = bind.execute(sa.text("SELECT id, role_name FROM authorized_roles where role_name in ('sbc_staff', 'staff', 'public_user')")).mappings().all() + role_map = {r['role_name']: r['id'] for r in roles} + + permission = bind.execute( + sa.text("SELECT id FROM permissions WHERE permission_name = 'AR_REMINDER_OPT_OUT'") + ).mappings().first() + permission_id = permission['id'] + + authorized_role_permissions = sa.table( + 'authorized_role_permissions', + sa.column('role_id', sa.Integer), + sa.column('permission_id', sa.Integer), + sa.column('created_date', sa.TIMESTAMP(timezone=True)), + sa.column('last_modified', sa.TIMESTAMP(timezone=True)), + sa.column('created_by_id', sa.Integer), + sa.column('modified_by_id', sa.Integer) + ) + + role_permission_list = [ + { + 'role_id': role_id, + 'permission_id': permission_id, + 'created_date': now, + 'last_modified': now, + 'created_by_id': None, + 'modified_by_id': None + } + for role_id in role_map.values() + ] + + op.bulk_insert(authorized_role_permissions, role_permission_list) + + + +def downgrade(): + bind = op.get_bind() + + permission = bind.execute( + sa.text("SELECT id FROM permissions WHERE permission_name = 'AR_REMINDER_OPT_OUT'") + ).mappings().first() + if permission: + permission_id = permission['id'] + + op.execute( + sa.text("DELETE FROM authorized_role_permissions WHERE permission_id = :pid").bindparams(pid=permission_id) + ) + + op.execute( + sa.text("DELETE FROM permissions WHERE id = :pid").bindparams(pid=permission_id) + ) + diff --git a/legal-api/pre-hook-update-db.sh b/legal-api/pre-hook-update-db.sh index fe6814c43b..04f190e701 100755 --- a/legal-api/pre-hook-update-db.sh +++ b/legal-api/pre-hook-update-db.sh @@ -1,14 +1,4 @@ #! /bin/sh -#export LIBRARY_PATH=/opt/rh/httpd24/root/usr/lib64 -#export X_SCLS=rh-python35 httpd24 -#export LD_LIBRARY_PATH=/opt/rh/rh-python35/root/usr/lib64:/opt/rh/httpd24/root/usr/lib64 -#export PATH=/opt/app-root/bin:/opt/rh/rh-python35/root/usr/bin:/opt/rh/httpd24/root/usr/bin:/opt/rh/httpd24/root/usr/sbin:/opt/app-root/src/.local/bin/:/opt/app-root/src/bin:/opt/app-root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - -# psql -U postgres -tc "SELECT 1 FROM pg_database WHERE datname = 'my_db'" | grep -q 1 || psql -U postgres -c "CREATE DATABASE my_db" - -cd /opt/app-root -echo 'ensure database is created' -python pre_hook_create_database.py - echo 'starting upgrade' -python manage.py db upgrade +poetry run python manage.py db upgrade +echo 'upgrade completed' diff --git a/legal-api/pre_hook_create_database.py b/legal-api/pre_hook_create_database.py deleted file mode 100644 index bd9b289dad..0000000000 --- a/legal-api/pre_hook_create_database.py +++ /dev/null @@ -1,24 +0,0 @@ -import contextlib -import os -import sys - -import sqlalchemy -import sqlalchemy.exc - -from legal_api.config import ProdConfig - -DB_ADMIN_PASSWORD = os.getenv("DB_ADMIN_PASSWORD", None) -DB_ADMIN_USERNAME = os.getenv("DB_ADMIN_USERNAME", "postgres") - -if not hasattr(ProdConfig, "DB_NAME") or not DB_ADMIN_PASSWORD: - print("Unable to create database.", sys.stdout) # noqa: T201 - sys.exit(-1) - -DATABASE_URI = f"postgresql://{DB_ADMIN_USERNAME}:{DB_ADMIN_PASSWORD}@{ProdConfig.DB_HOST}:{int(ProdConfig.DB_PORT)}/{DB_ADMIN_USERNAME}" - -with contextlib.suppress(sqlalchemy.exc.ProgrammingError), sqlalchemy.create_engine( - DATABASE_URI, - isolation_level="AUTOCOMMIT" -).connect() as connection: - database = ProdConfig.DB_NAME - connection.execute(f"CREATE DATABASE {database}") diff --git a/legal-api/src/legal_api/services/authz.py b/legal-api/src/legal_api/services/authz.py index a03f06789b..95bdba33f8 100644 --- a/legal-api/src/legal_api/services/authz.py +++ b/legal-api/src/legal_api/services/authz.py @@ -761,6 +761,9 @@ def get_allowable_actions(jwt: JwtManager, business: Business): "digitalBusinessCardPreconditions": get_digital_credentials_preconditions(business), "viewAll": is_competent_authority(jwt) } + if business.legal_type in Business.CORPS: + result["arReminder"] = (business.state == Business.State.ACTIVE) + return result diff --git a/legal-api/tests/unit/services/test_authorization.py b/legal-api/tests/unit/services/test_authorization.py index 5fab81f461..573b37af1e 100644 --- a/legal-api/tests/unit/services/test_authorization.py +++ b/legal-api/tests/unit/services/test_authorization.py @@ -1262,6 +1262,14 @@ def mock_auth(one, two): # pylint: disable=unused-argument; mocks of library me assert result['filing']['filingSubmissionLink'] assert result['filing']['filingTypes'] == expected assert result['viewAll'] == is_comp_auth + if legal_type in Business.CORPS: + if state == Business.State.ACTIVE: + assert result["arReminder"] == True + else: + assert result["arReminder"] == False + else: + assert "arReminder" not in result + @pytest.mark.parametrize( diff --git a/python/common/business-registry-model/pyproject.toml b/python/common/business-registry-model/pyproject.toml index 70d6b4c990..625ac88a8a 100644 --- a/python/common/business-registry-model/pyproject.toml +++ b/python/common/business-registry-model/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "business-model" -version = "3.3.20" +version = "3.3.21" description = "" authors = [ {name = "thor",email = "1042854+thorwolpert@users.noreply.github.com"} diff --git a/python/common/business-registry-model/src/business_model_migrations/versions/20260217_222138_edbd0f6ef10e_ar_reminder_opt_out_.py b/python/common/business-registry-model/src/business_model_migrations/versions/20260217_222138_edbd0f6ef10e_ar_reminder_opt_out_.py new file mode 100644 index 0000000000..1db253687b --- /dev/null +++ b/python/common/business-registry-model/src/business_model_migrations/versions/20260217_222138_edbd0f6ef10e_ar_reminder_opt_out_.py @@ -0,0 +1,96 @@ +"""ar_reminder_opt_out + +Revision ID: edbd0f6ef10e +Revises: 7efd0c42babd +Create Date: 2026-02-17 22:21:38.643521 + +""" +from datetime import UTC, datetime, timezone + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = 'edbd0f6ef10e' +down_revision = '7efd0c42babd' +branch_labels = None +depends_on = None + + +def upgrade(): + now = datetime.now(UTC) + + permissions = sa.table( + 'permissions', + sa.column('id', sa.Integer), + sa.column('permission_name', sa.String), + sa.column('description', sa.String), + sa.column('created_date', sa.TIMESTAMP(timezone=True)), + sa.column('last_modified', sa.TIMESTAMP(timezone=True)), + sa.column('created_by_id', sa.Integer), + sa.column('modified_by_id', sa.Integer) + ) + + op.bulk_insert( + permissions, + [{ + 'permission_name': 'AR_REMINDER_OPT_OUT', + 'description': 'Authorized to access Opt out ar reminder option.', + 'created_date': now, + 'last_modified': now, + 'created_by_id': None, + 'modified_by_id': None + }] + ) + + bind = op.get_bind() + + roles = bind.execute(sa.text("SELECT id, role_name FROM authorized_roles where role_name in ('sbc_staff', 'staff', 'public_user')")).mappings().all() + role_map = {r['role_name']: r['id'] for r in roles} + + permission = bind.execute( + sa.text("SELECT id FROM permissions WHERE permission_name = 'AR_REMINDER_OPT_OUT'") + ).mappings().first() + permission_id = permission['id'] + + authorized_role_permissions = sa.table( + 'authorized_role_permissions', + sa.column('role_id', sa.Integer), + sa.column('permission_id', sa.Integer), + sa.column('created_date', sa.TIMESTAMP(timezone=True)), + sa.column('last_modified', sa.TIMESTAMP(timezone=True)), + sa.column('created_by_id', sa.Integer), + sa.column('modified_by_id', sa.Integer) + ) + + role_permission_list = [ + { + 'role_id': role_id, + 'permission_id': permission_id, + 'created_date': now, + 'last_modified': now, + 'created_by_id': None, + 'modified_by_id': None + } + for role_id in role_map.values() + ] + + op.bulk_insert(authorized_role_permissions, role_permission_list) + + +def downgrade(): + bind = op.get_bind() + + permission = bind.execute( + sa.text("SELECT id FROM permissions WHERE permission_name = 'AR_REMINDER_OPT_OUT'") + ).mappings().first() + if permission: + permission_id = permission['id'] + + op.execute( + sa.text("DELETE FROM authorized_role_permissions WHERE permission_id = :pid").bindparams(pid=permission_id) + ) + + op.execute( + sa.text("DELETE FROM permissions WHERE id = :pid").bindparams(pid=permission_id) + )