-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(PC-33659)[API] chore: script to disable old integration provider
- Loading branch information
1 parent
b925839
commit 0a7bead
Showing
2 changed files
with
159 additions
and
0 deletions.
There are no files selected for viewing
101 changes: 101 additions & 0 deletions
101
api/src/pcapi/scripts/provider_clean_old_integration_data/main.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import logging | ||
|
||
from sqlalchemy import text | ||
|
||
from pcapi import settings | ||
from pcapi.core.providers import models as providers_models | ||
from pcapi.flask_app import app | ||
from pcapi.models import db | ||
from pcapi.repository import transaction | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
_LEGACY_API_PROVIDERS_IDS = [ | ||
15, # TiteLive Stocks (Epagine / Place des libraires.com) | ||
59, # Praxiel/Inférence | ||
58, # FNAC | ||
23, # www.leslibraires.fr | ||
66, # Decitre | ||
63, # Librisoft | ||
68, # TMIC-Ellipses | ||
65, # Mollat | ||
67, # CDI-Bookshop | ||
] | ||
|
||
_BATCH_SIZE = 1000 | ||
|
||
|
||
def _clean_id_at_providers(provider_ids: list[int], batch_size: int = _BATCH_SIZE) -> None: | ||
# Disabling statement_timeout as we can't know in advance how long it would take | ||
db.session.execute(text("SET statement_timeout = '300s';")) | ||
|
||
# create procedure | ||
db.session.execute( | ||
text( | ||
""" | ||
CREATE OR REPLACE PROCEDURE update_deprecated_provider_offer_batch(provider_id_list INT[], batch_size INT) | ||
LANGUAGE plpgsql | ||
AS $$ | ||
BEGIN | ||
LOOP | ||
-- Begin a new transaction | ||
BEGIN | ||
WITH batch AS ( | ||
SELECT "id" | ||
FROM offer | ||
WHERE "lastProviderId" = ANY (provider_id_list) | ||
AND "idAtProvider" IS NOT NULL | ||
LIMIT batch_size | ||
) | ||
UPDATE offer SET "idAtProvider" = NULL WHERE "id" IN (SELECT "id" FROM batch); | ||
-- Exit the loop if no rows were updated | ||
EXIT WHEN NOT FOUND; | ||
EXCEPTION | ||
-- Rollback the transaction in case of any error | ||
WHEN OTHERS THEN | ||
ROLLBACK; | ||
-- Optionally, you can raise an exception to stop the procedure | ||
RAISE; | ||
END; | ||
END LOOP; | ||
END $$; | ||
""" | ||
) | ||
) | ||
|
||
db.session.execute( | ||
text("""CALL update_deprecated_provider_offer_batch(:provider_id_list, :batch_size);"""), | ||
params={"provider_id_list": provider_ids, "batch_size": batch_size}, | ||
) | ||
|
||
# delete procedure | ||
db.session.execute(text("""DROP PROCEDURE IF EXISTS update_deprecated_provider_offer_batch;""")) | ||
|
||
# According to PostgreSQL, setting such values this way is affecting only the current session | ||
# but let's be defensive by setting back to the original values | ||
db.session.execute(text(f"SET statement_timeout = {settings.DATABASE_STATEMENT_TIMEOUT}")) | ||
|
||
|
||
def clean_old_provider_data(provider_ids: list[int]) -> None: | ||
# Update providers | ||
for provider_id in provider_ids: | ||
with transaction(): | ||
provider = providers_models.Provider.query.get(provider_id) | ||
|
||
logger.info("Cleaning data for provider %s (id: %s)", provider.name, provider.id) | ||
|
||
if "[DÉPRÉCIÉ]" not in provider.name: | ||
provider.name = f"[DÉPRÉCIÉ] {provider.name}" | ||
provider.enabledForPro = False | ||
provider.isActive = False | ||
|
||
# Update providers offers | ||
_clean_id_at_providers(provider_ids) | ||
|
||
|
||
if __name__ == "__main__": | ||
app.app_context().push() | ||
clean_old_provider_data(_LEGACY_API_PROVIDERS_IDS) |
58 changes: 58 additions & 0 deletions
58
api/tests/scripts/provider_clean_old_integraiton_data/main_test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import pytest | ||
|
||
from pcapi.core.offers import factories as offers_factories | ||
from pcapi.core.providers import factories as providers_factories | ||
from pcapi.models import db | ||
from pcapi.scripts.provider_clean_old_integration_data.main import _clean_id_at_providers | ||
from pcapi.scripts.provider_clean_old_integration_data.main import clean_old_provider_data | ||
|
||
|
||
@pytest.mark.usefixtures("db_session") | ||
def test_clean_old_provider_data(): | ||
provider_1 = providers_factories.ProviderFactory(name="Old Provider that should be deprecated") | ||
provider_already_deprecated = providers_factories.ProviderFactory(name="[DÉPRÉCIÉ] Old Provider") | ||
provider_3 = providers_factories.ProviderFactory() | ||
offer_provider_1 = offers_factories.ThingOfferFactory(lastProvider=provider_1, idAtProvider="12345") | ||
offer_provider_2 = offers_factories.EventOfferFactory(lastProvider=provider_already_deprecated, idAtProvider=None) | ||
offer_provider_3 = offers_factories.ThingOfferFactory(lastProvider=provider_3, idAtProvider="offerId3") | ||
|
||
clean_old_provider_data([provider_1.id, provider_already_deprecated.id]) | ||
|
||
db.session.refresh(offer_provider_1) | ||
db.session.refresh(offer_provider_2) | ||
db.session.refresh(offer_provider_3) | ||
|
||
# should be deprecated | ||
assert provider_1.name == "[DÉPRÉCIÉ] Old Provider that should be deprecated" | ||
assert not provider_1.enabledForPro | ||
assert not provider_1.isActive | ||
assert not offer_provider_1.idAtProvider | ||
assert provider_already_deprecated.name == "[DÉPRÉCIÉ] Old Provider" | ||
assert not provider_already_deprecated.enabledForPro | ||
assert not provider_already_deprecated.isActive | ||
assert not offer_provider_2.idAtProvider | ||
|
||
# should stay the same | ||
assert offer_provider_3.idAtProvider | ||
assert provider_3.enabledForPro | ||
assert provider_3.isActive | ||
|
||
|
||
@pytest.mark.usefixtures("db_session") | ||
def test_clean_id_at_providers(): | ||
provider_1 = providers_factories.ProviderFactory(name="Old Provider that should be deprecated") | ||
provider_3 = providers_factories.ProviderFactory() | ||
offer_provider_1 = offers_factories.ThingOfferFactory(lastProvider=provider_1, idAtProvider="12345") | ||
offer_provider_2 = offers_factories.ThingOfferFactory(lastProvider=provider_1, idAtProvider="12346") | ||
offer_provider_3 = offers_factories.ThingOfferFactory(lastProvider=provider_1, idAtProvider="12347") | ||
offer_provider_4 = offers_factories.ThingOfferFactory(lastProvider=provider_3, idAtProvider="offerId3") | ||
|
||
_clean_id_at_providers([provider_1.id], batch_size=2) | ||
|
||
# should be deprecated | ||
assert not offer_provider_1.idAtProvider | ||
assert not offer_provider_2.idAtProvider | ||
assert not offer_provider_3.idAtProvider | ||
|
||
# should stay the same | ||
assert offer_provider_4.idAtProvider |