269 lines
10 KiB
Python
269 lines
10 KiB
Python
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)
|