Skip to content

Commit

Permalink
PP-35 Migrate license goal integrations ⛰️ (#1189)
Browse files Browse the repository at this point in the history
* Add to all license goal type integrations the IntegrationConfiguration paradigm

* Migration script for license configurations

Used previous code and made it slightly more modular
so it can be re-used for further integration migrations

* Collection relationships to the integration configurations

CollectionsSettings controller uses the integration settings for the Admin API

* The admin /collections POST API with integration configurations

External integrations are still maintained so that integrationlinks can continue to work
All external_account_id properties have been set as optional

* Deleted all the previous ConfigurationSettings definitions for collections

* No part of collection settings uses the in built PROVIDER APIs anymore

Added a BaseCirculationAPIProtocol for mypy reasons

* Introduced a child settings interface
  • Loading branch information
RishiDiwanTT authored Jun 21, 2023
1 parent 299003e commit aaf2d70
Show file tree
Hide file tree
Showing 98 changed files with 3,851 additions and 2,818 deletions.
1 change: 1 addition & 0 deletions alembic/versions/20230525_0a1c9c3f5dd2_revert_pr_980.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def downgrade() -> None:
postgresql.ENUM("RED", "GREEN", name="status"),
autoincrement=False,
nullable=False,
server_default=sa.text("'GREEN'::status"),
),
)
op.create_table(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"""Migrate license integrations to configuration settings
Revision ID: 0af587ff8595
Revises: b883671b7bc5
Create Date: 2023-05-31 12:34:42.550703+00:00
"""

from typing import Type

from alembic import op
from api.integration.registry.license_providers import LicenseProvidersRegistry
from core.integration.base import HasLibraryIntegrationConfiguration
from core.integration.settings import BaseSettings
from core.migration.migrate_external_integration import (
_migrate_external_integration,
_migrate_library_settings,
get_configuration_settings,
get_integrations,
get_library_for_integration,
)

# revision identifiers, used by Alembic.
revision = "0af587ff8595"
down_revision = "b883671b7bc5"
branch_labels = None
depends_on = None


LICENSE_GOAL = "LICENSE_GOAL"


def upgrade() -> None:
registry = LicenseProvidersRegistry()

connection = op.get_bind()

# Fetch all license type integrations
# The old enum had 'licenses', the new enum has 'LICENSE_GOAL'
integrations = get_integrations(connection, "licenses")
for integration in integrations:
_id, protocol, name = integration

# Get the right API class for it
api_class = registry.get(protocol, None)
if not api_class:
raise RuntimeError(f"Could not find API class for '{protocol}'")

# Create the settings and library settings dicts from the configurationsettings
settings_dict, library_settings, self_test_result = get_configuration_settings(
connection, integration
)

# License type integrations take their external_account_id data from the collection.
# The configurationsetting for it seems to be unused, so we take the value from the collection
collection = connection.execute(
"select id, external_account_id, name from collections where external_integration_id = %s",
integration.id,
).fetchone()
if not collection:
raise RuntimeError(
f"Could not fetch collection for integration {integration}"
)
settings_class: Type[BaseSettings] = api_class.settings_class()
if "external_account_id" in settings_class.__fields__:
settings_dict["external_account_id"] = collection.external_account_id

# Write the configurationsettings into the integration_configurations table
integration_id = _migrate_external_integration(
connection,
integration,
api_class,
LICENSE_GOAL,
settings_dict,
self_test_result,
name=collection.name,
)

# Connect the collection to the settings
connection.execute(
"UPDATE collections SET integration_configuration_id=%s where id=%s",
(integration_id, collection.id),
)

# If we have library settings too, then write each one into it's own row
if issubclass(api_class, HasLibraryIntegrationConfiguration):
integration_libraries = get_library_for_integration(connection, _id)
for library in integration_libraries:
_migrate_library_settings(
connection,
integration_id,
library.library_id,
library_settings[library.library_id],
api_class,
)


def downgrade() -> None:
connection = op.get_bind()
connection.execute(
"DELETE from integration_configurations where goal = %s", LICENSE_GOAL
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Add the license type goal
Revision ID: b883671b7bc5
Revises: 0a1c9c3f5dd2
Create Date: 2023-05-31 10:50:32.045821+00:00
"""
import sqlalchemy as sa

from alembic import op

# revision identifiers, used by Alembic.
revision = "b883671b7bc5"
down_revision = "0a1c9c3f5dd2"
branch_labels = None
depends_on = None


def upgrade() -> None:
# We need to use an autocommit blcok since the next migration is going to use
# the new enum value immediately, so we must ensure the value is commited
# before the next migration runs
with op.get_context().autocommit_block():
op.execute(f"ALTER TYPE goals ADD VALUE IF NOT EXISTS 'LICENSE_GOAL'")
op.add_column(
"collections",
sa.Column("integration_configuration_id", sa.Integer(), nullable=True),
)
op.create_index(
op.f("ix_collections_integration_configuration_id"),
"collections",
["integration_configuration_id"],
unique=True,
)
op.create_foreign_key(
None,
"collections",
"integration_configurations",
["integration_configuration_id"],
["id"],
ondelete="SET NULL",
)


def downgrade() -> None:
"""There is no way to drop single values from an Enum from postgres"""
op.drop_constraint(
"collections_integration_configuration_id_fkey",
"collections",
type_="foreignkey",
)
op.drop_index(
op.f("ix_collections_integration_configuration_id"), table_name="collections"
)
op.drop_column("collections", "integration_configuration_id")
Loading

0 comments on commit aaf2d70

Please sign in to comment.