From 5074a27cb6fd868540dc1a7e3abdb22bd0b36e65 Mon Sep 17 00:00:00 2001
From: Pierre Ducroquet <pducroquet@entrouvert.com>
Date: Tue, 7 Jun 2022 11:02:23 +0200
Subject: [PATCH] hobo agent: index the common::Role.uuid column and use uuid
 type (#66011)

---
 .../common/migrations/0004_alter_role_uuid.py | 18 +++++
 hobo/agent/common/models.py                   |  2 +-
 hobo/provisionning/utils.py                   |  4 +-
 tests_multitenant/test_hobo_notify.py         | 81 ++++++++++---------
 4 files changed, 67 insertions(+), 38 deletions(-)
 create mode 100644 hobo/agent/common/migrations/0004_alter_role_uuid.py

diff --git a/hobo/agent/common/migrations/0004_alter_role_uuid.py b/hobo/agent/common/migrations/0004_alter_role_uuid.py
new file mode 100644
index 0000000..6ffb474
--- /dev/null
+++ b/hobo/agent/common/migrations/0004_alter_role_uuid.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.2.13 on 2022-06-07 09:01
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('common', '0003_auto_20200707_1656'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='role',
+            name='uuid',
+            field=models.UUIDField(db_index=True),
+        ),
+    ]
diff --git a/hobo/agent/common/models.py b/hobo/agent/common/models.py
index 61312f9..3372e6d 100644
--- a/hobo/agent/common/models.py
+++ b/hobo/agent/common/models.py
@@ -4,7 +4,7 @@ from django.db import models
 
 
 class Role(Group):
-    uuid = models.CharField(max_length=32)
+    uuid = models.UUIDField(db_index=True)
     description = models.TextField(default=u'')
     details = models.TextField(default=u'')
     emails = ArrayField(models.CharField(max_length=128), default=list)
diff --git a/hobo/provisionning/utils.py b/hobo/provisionning/utils.py
index dc59e6c..c90f975 100644
--- a/hobo/provisionning/utils.py
+++ b/hobo/provisionning/utils.py
@@ -16,6 +16,7 @@
 
 import hashlib
 import logging
+from uuid import UUID
 
 from django.contrib.auth.models import Group
 from django.db import IntegrityError
@@ -172,12 +173,13 @@ class NotificationProcessing:
             target_uuids = set()
             for o in data:
                 assert 'uuid' in o
-                target_uuids.add(o['uuid'])
+                target_uuids.add(UUID(o['uuid']))
             for role in Role.objects.filter(uuid__in=target_uuids):
                 roles_by_uuid[role.uuid] = role
 
         for o in data:
             assert 'uuid' in o
+            o['uuid'] = UUID(o['uuid'])
             uuids.add(o['uuid'])
             if action == 'provision':
                 created = False
diff --git a/tests_multitenant/test_hobo_notify.py b/tests_multitenant/test_hobo_notify.py
index 90d1b42..bca4ce7 100644
--- a/tests_multitenant/test_hobo_notify.py
+++ b/tests_multitenant/test_hobo_notify.py
@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 
 import logging
+from uuid import UUID
 
 import pytest
 from django.db import connection
@@ -26,7 +27,7 @@ def test_hobo_notify_roles(caplog, tenants):
                     u'@type': 'role',
                     u'data': [
                         {
-                            u'uuid': u'12345',
+                            u'uuid': u'7b347080-0d38-4ffa-8407-63734610fc45',
                             u'name': u'Service petite enfance',
                             u'slug': u'service-petite-enfance',
                             u'description': u'Role du service petite enfance %s' % tenant.domain_url,
@@ -48,7 +49,7 @@ def test_hobo_notify_roles(caplog, tenants):
                     u'@type': 'role',
                     u'data': [
                         {
-                            u'uuid': u'12345',
+                            u'uuid': u'7b347080-0d38-4ffa-8407-63734610fc45',
                             u'name': u'Service petite enfance',
                             u'slug': u'service-petite-enfance',
                             u'description': u'Role du service petite enfance %s' % tenant.domain_url,
@@ -63,7 +64,7 @@ def test_hobo_notify_roles(caplog, tenants):
             assert Group.objects.count() == 1
             assert Role.objects.count() == 1
             role = Role.objects.get()
-            assert role.uuid == u'12345'
+            assert role.uuid == UUID('7b347080-0d38-4ffa-8407-63734610fc45')
             assert role.name == u'Service petite enfance'
             assert role.description == u'Role du service petite enfance %s' % tenant.domain_url
             assert role.details == u'Some details'
@@ -81,7 +82,7 @@ def test_hobo_notify_roles(caplog, tenants):
                     u'@type': 'role',
                     u'data': [
                         {
-                            u'uuid': u'xyz',
+                            u'uuid': u'10d8ecbd-116a-464f-96c5-f8507daa5c2c',
                             u'name': u'Service état civil',
                             u'slug': u'service-etat-civil',
                             u'description': u'Role du service état civil %s' % tenant.domain_url,
@@ -93,7 +94,7 @@ def test_hobo_notify_roles(caplog, tenants):
             assert Group.objects.count() == 1
             assert Role.objects.count() == 1
             role = Role.objects.get()
-            assert role.uuid == u'xyz'
+            assert role.uuid == UUID('10d8ecbd-116a-464f-96c5-f8507daa5c2c')
             assert role.name == u'Service état civil'
             assert role.description == u'Role du service état civil %s' % tenant.domain_url
 
@@ -107,7 +108,7 @@ def test_hobo_notify_roles(caplog, tenants):
                     u'@type': 'role',
                     u'data': [
                         {
-                            u'uuid': u'xyz',
+                            u'uuid': u'10d8ecbd-116a-464f-96c5-f8507daa5c2c',
                             u'name': u'Service état civil',
                             u'slug': u'service-etat-civil',
                             u'description': u'Role du service état civil %s' % tenant.domain_url,
@@ -129,7 +130,7 @@ def test_hobo_notify_roles(caplog, tenants):
                     u'@type': 'role',
                     u'data': [
                         {
-                            u'uuid': u'12345',
+                            u'uuid': u'7b347080-0d38-4ffa-8407-63734610fc45',
                             u'name': u'Service petite enfance',
                             u'slug': u'service-petite-enfance',
                             u'description': u'Role du service petite enfance %s' % tenant.domain_url,
@@ -148,7 +149,7 @@ def test_hobo_notify_roles(caplog, tenants):
                     u'@type': 'role',
                     u'data': [
                         {
-                            u'uuid': u'12345',
+                            u'uuid': u'7b347080-0d38-4ffa-8407-63734610fc45',
                             u'name': u'Service petite enfance2',
                             u'slug': u'service-petite-enfance2',
                             u'description': u'Role du service petite enfance %s' % tenant.domain_url,
@@ -168,7 +169,7 @@ def test_hobo_notify_roles(caplog, tenants):
                     u'@type': 'role',
                     u'data': [
                         {
-                            u'uuid': u'xyz',
+                            u'uuid': u'7b347080-0d38-4ffa-8407-63734610fc45',
                             u'name': u'Service petite enfance2',
                             u'slug': u'service-petite-enfance2',
                             u'description': u'Role du service petite enfance %s' % tenant.domain_url,
@@ -181,7 +182,7 @@ def test_hobo_notify_roles(caplog, tenants):
             assert Role.objects.count() == 1
             assert Role.objects.get().uuid == notification['objects']['data'][0]['uuid']
             # test error on collision
-            Role.objects.create(uuid='12345', name='Foo', description='foo')
+            Role.objects.create(uuid='1f5beb43-5297-468e-ae79-e32ead8495b4', name='Foo', description='foo')
             assert Role.objects.count() == 2
             notification = {
                 u'@type': u'provision',
@@ -190,7 +191,7 @@ def test_hobo_notify_roles(caplog, tenants):
                     u'@type': 'role',
                     u'data': [
                         {
-                            u'uuid': u'12345',
+                            u'uuid': u'1f5beb43-5297-468e-ae79-e32ead8495b4',
                             u'name': u'Service petite enfance2',
                             u'slug': u'service-petite-enfance2',
                             u'description': u'Role du service petite enfance %s' % tenant.domain_url,
@@ -201,10 +202,18 @@ def test_hobo_notify_roles(caplog, tenants):
             Command.process_notification(tenant, notification)
             assert Group.objects.count() == 2
             assert Role.objects.count() == 2
-            assert Role.objects.filter(uuid='12345', name=u'Service petite enfance').count() == 0
+            assert (
+                Role.objects.filter(
+                    uuid='7b347080-0d38-4ffa-8407-63734610fc45', name=u'Service petite enfance'
+                ).count()
+                == 0
+            )
             assert caplog.records[-1].levelno == logging.ERROR
             assert caplog.records[-1].msg.startswith('cannot provision')
-            assert caplog.records[-1].args == (u'Service petite enfance2', u'12345')
+            assert caplog.records[-1].args == (
+                u'Service petite enfance2',
+                UUID('1f5beb43-5297-468e-ae79-e32ead8495b4'),
+            )
 
 
 def test_hobo_notify_roles_db_queries(caplog, tenants):
@@ -224,7 +233,7 @@ def test_hobo_notify_roles_db_queries(caplog, tenants):
                     '@type': 'role',
                     'data': [
                         {
-                            'uuid': '12345',
+                            'uuid': '2e3c6110-34ec-4466-b8da-15ad84e3a141',
                             'name': 'Service petite enfance',
                             'slug': 'service-petite-enfance',
                             'description': 'Role du service petite enfance %s' % tenant.domain_url,
@@ -233,7 +242,7 @@ def test_hobo_notify_roles_db_queries(caplog, tenants):
                             'emails_to_members': False,
                         },
                         {
-                            'uuid': '6789',
+                            'uuid': '60ba0310-12e9-461d-bb7c-ffabf6654a40',
                             'name': 'Autre service',
                             'slug': 'autre service',
                             'description': "Role d'un autre service petite enfance %s" % tenant.domain_url,
@@ -258,7 +267,7 @@ def test_hobo_notify_roles_db_queries(caplog, tenants):
                     '@type': 'role',
                     'data': [
                         {
-                            'uuid': '12sed45',
+                            'uuid': 'dbb108f3-7349-4345-9b59-3d372c035cc9',
                             'name': 'Le dernier service',
                             'slug': 'le-dernier-service',
                             'description': '',
@@ -282,7 +291,7 @@ def test_hobo_notify_roles_db_queries(caplog, tenants):
                     '@type': 'role',
                     'data': [
                         {
-                            'uuid': '12345',
+                            'uuid': '2e3c6110-34ec-4466-b8da-15ad84e3a141',
                             'name': 'Service petite enfance',
                             'slug': 'service-petite-enfance',
                             'description': 'Role du service petite enfance %s' % tenant.domain_url,
@@ -291,7 +300,7 @@ def test_hobo_notify_roles_db_queries(caplog, tenants):
                             'emails_to_members': False,
                         },
                         {
-                            'uuid': '6789',
+                            'uuid': '60ba0310-12e9-461d-bb7c-ffabf6654a40',
                             'name': 'Autre service',
                             'slug': 'autre service',
                             'description': "Role d'un autre service petite enfance %s" % tenant.domain_url,
@@ -313,13 +322,13 @@ def test_hobo_notify_roles_db_queries(caplog, tenants):
                     '@type': 'role',
                     'data': [
                         {
-                            'uuid': '12sed45',
+                            'uuid': 'dbb108f3-7349-4345-9b59-3d372c035cc9',
                             'name': 'Le dernier service',
                             'slug': 'le-dernier-service',
                             'description': '',
                         },
                         {
-                            'uuid': '12345',
+                            'uuid': '2e3c6110-34ec-4466-b8da-15ad84e3a141',
                             'name': 'Service petite enfance',
                             'slug': 'service-petite-enfance',
                             'description': 'Role du service petite enfance %s' % tenant.domain_url,
@@ -328,7 +337,7 @@ def test_hobo_notify_roles_db_queries(caplog, tenants):
                             'emails_to_members': False,
                         },
                         {
-                            'uuid': '6789',
+                            'uuid': '60ba0310-12e9-461d-bb7c-ffabf6654a40',
                             'name': 'Autre service',
                             'slug': 'autre service',
                             'description': "Role d'un autre service petite enfance %s" % tenant.domain_url,
@@ -364,7 +373,7 @@ def test_provision_users(tenants):
                     u'@type': 'role',
                     u'data': [
                         {
-                            u'uuid': u'12345',
+                            u'uuid': u'beb23af6-d7c9-4ce1-b232-d859b0565296',
                             u'name': u'Service petite enfance',
                             u'slug': u'service-petite-enfance',
                             u'description': u'Role du service petite enfance %s' % tenant.domain_url,
@@ -376,7 +385,7 @@ def test_provision_users(tenants):
             assert Group.objects.count() == 1
             assert Role.objects.count() == 1
             role = Role.objects.get()
-            assert role.uuid == u'12345'
+            assert role.uuid == UUID('beb23af6-d7c9-4ce1-b232-d859b0565296')
             assert role.name == u'Service petite enfance'
             assert role.description == u'Role du service petite enfance %s' % tenant.domain_url
 
@@ -391,19 +400,19 @@ def test_provision_users(tenants):
                     u'@type': 'user',
                     u'data': [
                         {
-                            u'uuid': u'a' * 32,
+                            u'uuid': 'beb23af6-d7c9-4ce1-b232-d859b0565296',
                             u'first_name': u'John',
                             u'last_name': u'Doe',
                             u'email': u'john.doe@example.net',
                             u'is_superuser': False,
                             u'roles': [
                                 {
-                                    u'uuid': u'12345',
+                                    u'uuid': u'beb23af6-d7c9-4ce1-b232-d859b0565296',
                                     u'name': u'Service petite enfance',
                                     u'description': u'etc.',
                                 },
                                 {
-                                    u'uuid': u'xyz',
+                                    u'uuid': u'c0647609-c68d-42ac-88fc-efc371163320',
                                     u'name': u'Service état civil',
                                     u'description': u'etc.',
                                 },
@@ -417,7 +426,7 @@ def test_provision_users(tenants):
             assert Role.objects.count() == 1
             assert Group.objects.count() == 1
             user = User.objects.get()
-            assert user.username == 'a' * 32
+            assert user.username == 'beb23af6-d7c9-4ce1-b232-d859b0565296'
             assert user.first_name == 'John'
             assert user.last_name == 'Doe'
             assert user.email == 'john.doe@example.net'
@@ -426,12 +435,12 @@ def test_provision_users(tenants):
             assert user.saml_identifiers.count() == 1
             usi = user.saml_identifiers.get()
             assert usi.issuer.entity_id == 'http://idp.example.net/idp/saml/metadata'
-            assert usi.name_id == 'a' * 32
+            assert usi.name_id == 'beb23af6-d7c9-4ce1-b232-d859b0565296'
             assert user.groups.count() == 1
             group = user.groups.get()
             assert group.name == 'Service petite enfance'
             role = Role.objects.get(group_ptr=group.pk)
-            assert role.uuid == '12345'
+            assert role.uuid == UUID('beb23af6-d7c9-4ce1-b232-d859b0565296')
 
     # test nothing change if run a second time
     for tenant in tenants:
@@ -444,19 +453,19 @@ def test_provision_users(tenants):
                     u'@type': 'user',
                     u'data': [
                         {
-                            u'uuid': u'a' * 32,
+                            u'uuid': 'beb23af6-d7c9-4ce1-b232-d859b0565296',
                             u'first_name': u'John',
                             u'last_name': u'Doe',
                             u'email': u'john.doe@example.net',
                             u'is_superuser': True,
                             u'roles': [
                                 {
-                                    u'uuid': u'12345',
+                                    u'uuid': u'beb23af6-d7c9-4ce1-b232-d859b0565296',
                                     u'name': u'Service petite enfance',
                                     u'description': u'etc.',
                                 },
                                 {
-                                    u'uuid': u'xyz',
+                                    u'uuid': u'c0647609-c68d-42ac-88fc-efc371163320',
                                     u'name': u'Service état civil',
                                     u'description': u'etc.',
                                 },
@@ -470,7 +479,7 @@ def test_provision_users(tenants):
             assert Role.objects.count() == 1
             assert Group.objects.count() == 1
             user = User.objects.get()
-            assert user.username == 'a' * 32
+            assert user.username == 'beb23af6-d7c9-4ce1-b232-d859b0565296'
             assert user.first_name == 'John'
             assert user.last_name == 'Doe'
             assert user.email == 'john.doe@example.net'
@@ -479,12 +488,12 @@ def test_provision_users(tenants):
             assert user.saml_identifiers.count() == 1
             usi = user.saml_identifiers.get()
             assert usi.issuer.entity_id == 'http://idp.example.net/idp/saml/metadata'
-            assert usi.name_id == 'a' * 32
+            assert usi.name_id == 'beb23af6-d7c9-4ce1-b232-d859b0565296'
             assert user.groups.count() == 1
             group = user.groups.get()
             assert group.name == 'Service petite enfance'
             role = Role.objects.get(group_ptr=group.pk)
-            assert role.uuid == '12345'
+            assert role.uuid == UUID('beb23af6-d7c9-4ce1-b232-d859b0565296')
 
     # test deprovision works
     for tenant in tenants:
@@ -497,7 +506,7 @@ def test_provision_users(tenants):
                     u'@type': 'user',
                     u'data': [
                         {
-                            u'uuid': u'a' * 32,
+                            u'uuid': 'beb23af6-d7c9-4ce1-b232-d859b0565296',
                         }
                     ],
                 },
-- 
2.35.1

