script de correction du journal GLC

This commit is contained in:
Benjamin Dauvergne 2022-09-28 11:46:35 +02:00
parent 7d519ff647
commit 76d04af320
2 changed files with 280 additions and 0 deletions

View File

@ -0,0 +1,12 @@
TENANT=moncompte-rec.grandlyon.com
HOST=grandlyon-cut-test-sso-1
SCRIPT=fix_journal.py
all:
scp $(SCRIPT) $(HOST):/tmp
ssh $(HOST) sudo authentic2-multitenant-manage tenant_command runscript -d $(TENANT) /tmp/$(SCRIPT)
shell:
ssh $(HOST)

View File

@ -0,0 +1,268 @@
import collections
import datetime
import sys
sys.stdout.reconfigure(line_buffering=True)
from authentic2.apps.journal.models import Event, EventType
from authentic2.custom_user.models import User
from authentic2.models import Attribute, AttributeValue
from authentic2_auth_fc.models import FcAccount
from django.db import connection, transaction
from django.utils.timezone import localtime, make_aware
registration_type = EventType.objects.get(name="user.registration")
validated_attribute = Attribute.objects.get(name="validated")
qs = User.objects.filter(
ou__slug="usagers",
date_joined__gt=make_aware(datetime.datetime(2019, 4, 1)),
fc_accounts__isnull=False,
)
user_ids = set(qs.values_list("id", flat=True))
atvs = AttributeValue.objects.filter(attribute=validated_attribute, content="1", object_id__in=user_ids)
validated_user_ids = set(atvs.values_list("object_id", flat=True))
events = (
Event.objects.filter(user_id__in=user_ids, type__name__in=["user.registration", "user.login"])
.select_related("type")
.order_by(
"type__name",
"user_id",
"timestamp",
)
.distinct("type__name", "user_id")
)
registration = {}
first_login = {}
for event in events.iterator():
if event.type.name == "user.registration":
registration[event.user_id] = event
if (
event.type.name == "user.login"
and event.user_id not in first_login
and event.data["how"] == "france-connect"
):
first_login[event.user_id] = event
counter = collections.Counter()
date_joined = dict(User.objects.filter(id__in=user_ids).values_list("id", "date_joined"))
fc_accounts = dict(FcAccount.objects.values_list("user_id", "id"))
fc_accounts_created = dict(FcAccount.objects.values_list("user_id", "created"))
print(f"{len(user_ids)} accounts to fix.")
print()
delay = 240
count = 0
for user_id in sorted(user_ids):
if (
user_id in registration
and registration[user_id].data["how"] == "france-connect"
and user_id in validated_user_ids
):
user_ids.remove(user_id)
count += 1
print(f"Removed {count} valid user ids.")
print(f"{len(user_ids)} remaining accounts to fix.\n")
count = 0
for user_id in sorted(user_ids):
if (
user_id in registration
and registration[user_id].data["how"] != "france-connect"
and user_id in validated_user_ids
and abs((fc_accounts_created[user_id] - date_joined[user_id]).total_seconds()) > 10
):
user_ids.remove(user_id)
count += 1
print(f"Removed {count} valid user ids linked after registration.")
print(f"{len(user_ids)} remaining accounts to fix.\n")
count = 0
for user_id in sorted(user_ids):
if (
(user_id not in registration or registration[user_id].data['how'] != 'france-connect')
and (
user_id not in first_login
or abs((first_login[user_id].timestamp - date_joined[user_id]).total_seconds()) > delay
or date_joined[user_id] < make_aware(datetime.datetime(2022, 4, 1))
)
and user_id in validated_user_ids
and (
abs((fc_accounts_created[user_id] - date_joined[user_id]).total_seconds()) > delay
or date_joined[user_id] < make_aware(datetime.datetime(2022, 4, 1))
)
):
user_ids.remove(user_id)
count += 1
print(f"Removed {count} old accounts linked to FC later.")
print(f"{len(user_ids)} remaining accounts to fix.\n")
# for accounts with a first login through FC and no registration event and no validation
user_ids_to_validate = set()
for user_id in sorted(user_ids):
if (
user_id in first_login
and first_login[user_id].data["how"] == "france-connect"
and abs((first_login[user_id].timestamp - date_joined[user_id]).total_seconds()) < delay
and user_id not in registration
and user_id not in validated_user_ids
):
user_ids.remove(user_id)
user_ids_to_validate.add(user_id)
if user_ids_to_validate:
print(
f"{len(user_ids_to_validate)} registered through FC but not validated and needing a registration event."
)
for i, user in enumerate(User.objects.filter(id__in=user_ids_to_validate)):
print(f"\r[{i+1:06d}/{len(user_ids_to_validate):06d}] validating... ", end="")
with transaction.atomic():
data = {
"how": "france-connect",
}
if "service_name" in first_login[user.id].data:
data["service_name"] = first_login[user.id].data["service_name"]
reg = Event.objects.create(
type=registration_type,
timestamp=user.date_joined,
user_id=user.id,
session_id=first_login[user.id].session_id,
references=first_login[user.id].references,
data=data,
api=False,
)
user.attributes.validated = True
user.attributes.validation_context = "FC"
user.attributes.validation_date = localtime(fc_accounts_created[user.id]).date()
if "service_name" in first_login[user.id].data:
user.attributes.validation_partner = data["service_name"]
print("DONE")
print(f"{len(user_ids)} remaining accounts to fix.\n")
else:
print("No account registered through FC not validated and missing registration event..\n")
user_ids_to_validate = set()
# for accounts with more than 24h between join and FC creation just validate
user_ids_to_validate = set()
for user_id in sorted(user_ids):
if (
user_id not in validated_user_ids
and (abs((fc_accounts_created[user_id] - date_joined[user_id]).total_seconds()) > delay)
or (user_id in registration and registration[user_id].data["how"] == "france-connect")
):
user_ids.remove(user_id)
user_ids_to_validate.add(user_id)
if user_ids_to_validate:
print(
f"{len(user_ids_to_validate)} registered by mail or FC but validated with FC and just needing validation"
)
for i, user in enumerate(User.objects.filter(id__in=user_ids_to_validate).order_by("id")):
print(
f"\r[{i+1:06d}/{len(user_ids_to_validate):06d}] validating {user.id}... ",
end="",
)
with transaction.atomic():
user.attributes.validated = True
user.attributes.validation_context = "FC"
user.attributes.validation_date = localtime(fc_accounts_created[user.id]).date()
if user.id in registration and "service_name" in registration[user.id].data:
user.attributes.validation_partner = registration[user.id].data["service_name"]
print("DONE")
print(f"{len(user_ids)} remaining accounts to fix.\n")
else:
print("No account just missing validation.\n")
user_ids_to_validate = set()
# for accounts with more than 24h between join and FC creation just validate
user_ids_to_modify_reg_and_validate = set()
for user_id in sorted(user_ids):
if (
abs((fc_accounts_created[user_id] - date_joined[user_id]).total_seconds()) <= delay
and user_id in registration
and registration[user_id].data["how"] != "france-connect"
and user_id not in validated_user_ids
):
user_ids.remove(user_id)
user_ids_to_modify_reg_and_validate.add(user_id)
if user_ids_to_modify_reg_and_validate:
print(
f"{len(user_ids_to_modify_reg_and_validate)} linked to FC near the registration but registration event is wrong."
)
for i, user in enumerate(User.objects.filter(id__in=user_ids_to_modify_reg_and_validate)):
print(
f"\r[{i+1:06d}/{len(user_ids_to_modify_reg_and_validate):06d}] fixing registration and validating... ",
end="",
)
continue
with transaction.atomic():
registration[user.id].data["how"] = "france-connect"
registration[user.id].save()
user.attributes.validated = True
user.attributes.validation_context = "FC"
user.attributes.validation_date = localtime(fc_accounts_created[user.id]).date()
transaction.set_rollback(True)
print("DONE\n")
print(f"{len(user_ids)} remaining accounts to fix.\n")
else:
print("No account with wrong registration event.\n")
user_ids_to_modify_reg_and_validate = set()
# for accounts with more than 24h between join and FC creation just validate
create_reg_and_validate = set()
for user_id in sorted(user_ids):
if (
abs((fc_accounts_created[user_id] - date_joined[user_id]).total_seconds()) <= delay
and user_id not in registration
and user_id in first_login
and abs((first_login[user_id].timestamp - fc_accounts_created[user_id]).total_seconds()) < delay
and first_login[user_id].data["how"] == "france-connect"
):
user_ids.remove(user_id)
create_reg_and_validate.add(user_id)
if create_reg_and_validate:
print(f"{len(create_reg_and_validate)} registered by FC but without registration event and to validate.")
for i, user in enumerate(User.objects.filter(id__in=create_reg_and_validate).order_by("id")):
print(
f"\r[{i+1:06d}/{len(create_reg_and_validate):06d}] creating registration and validating {user.id}... ",
end="",
)
continue
with transaction.atomic():
data = {
"how": "france-connect",
}
if "service_name" in first_login[user.id].data:
data["service_name"] = first_login[user.id].data["service_name"]
reg = Event.objects.create(
type=registration_type,
timestamp=user.date_joined,
user_id=user.id,
session_id=first_login[user.id].session_id,
references=first_login[user.id].references,
data=data,
api=False,
)
user.attributes.validated = True
user.attributes.validation_context = "FC"
user.attributes.validation_date = localtime(fc_accounts_created[user.id]).date()
transaction.set_rollback(True)
print("DONE\n")
print(f"{len(user_ids)} remaining accounts to fix.\n")
else:
print("No account with needing registration creation.\n")
create_reg_and_validate = set()
if user_ids:
print(f'Some remaining accounts: {", ".join(list(map(str, sorted(user_ids, reverse=True)))[:10])}')
raise SystemExit(0)