Projet

Général

Profil

0003-migrations-set-existing-user-phone-fields-to-E.164-v.patch

Paul Marillonnet, 22 septembre 2022 11:36

Télécharger (6,75 ko)

Voir les différences:

Subject: [PATCH 3/3] migrations: set existing user phone fields to E.164 value
 format (#69365)

 src/authentic2/managers.py                    |  7 ++-
 .../0043_attribute_alter_model_managers.py    | 27 +++++++++
 .../migrations/0044_migrate_phone_field.py    | 55 +++++++++++++++++++
 tests/test_migrations.py                      | 47 ++++++++++++++++
 4 files changed, 134 insertions(+), 2 deletions(-)
 create mode 100644 src/authentic2/migrations/0043_attribute_alter_model_managers.py
 create mode 100644 src/authentic2/migrations/0044_migrate_phone_field.py
src/authentic2/managers.py
109 109

  
110 110

  
111 111
class AttributeManager(managers.QueryManager.from_queryset(GetByNameQuerySet)):
112
    pass
112
    use_in_migrations = True
113

  
114

  
115
class AttributeValueManager(managers.QueryManager.from_queryset(AttributeValueQuerySet)):
116
    use_in_migrations = True
113 117

  
114 118

  
115 119
ServiceManager = BaseServiceManager.from_queryset(ServiceQuerySet)
116
AttributeValueManager = managers.QueryManager.from_queryset(AttributeValueQuerySet)
src/authentic2/migrations/0043_attribute_alter_model_managers.py
1
from django.db import migrations
2

  
3
import authentic2.managers
4

  
5

  
6
class Migration(migrations.Migration):
7

  
8
    dependencies = [
9
        ('authentic2', '0042_api_client'),
10
    ]
11

  
12
    operations = [
13
        migrations.AlterModelManagers(
14
            name='attribute',
15
            managers=[
16
                ('all_objects', authentic2.managers.AttributeManager()),
17
                ('objects', authentic2.managers.AttributeManager(disabled=False)),
18
            ],
19
        ),
20
        migrations.AlterModelManagers(
21
            name='attributevalue',
22
            managers=[
23
                ('all_objects', authentic2.managers.AttributeValueManager()),
24
                ('objects', authentic2.managers.AttributeValueManager(attribute__disabled=False)),
25
            ],
26
        ),
27
    ]
src/authentic2/migrations/0044_migrate_phone_field.py
1
import phonenumbers
2
from django.conf import settings
3
from django.db import migrations
4

  
5

  
6
def migrate_phone_field(apps, schema_editor):
7
    Attribute = apps.get_model('authentic2', 'Attribute')
8
    AttributeValue = apps.get_model('authentic2', 'AttributeValue')
9
    User = apps.get_model(*settings.AUTH_USER_MODEL.split('.', maxsplit=1))
10
    ContentType = apps.get_model('contenttypes', 'ContentType')
11

  
12
    user_ct = ContentType.objects.get_for_model(User)
13
    try:
14
        phone_attr = Attribute.objects.get(name='phone')
15
    except Attribute.DoesNotExist:
16
        return
17

  
18
    for atv in AttributeValue.objects.filter(attribute=phone_attr):
19
        pn = None
20
        try:
21
            pn = phonenumbers.parse(atv.content)
22
        except phonenumbers.NumberParseException:
23
            try:
24
                pn = phonenumbers.parse(
25
                    atv.content,
26
                    settings.PHONE_COUNTRY_CODES[settings.DEFAULT_COUNTRY_CODE],
27
                )
28
            except phonenumbers.NumberParseException:
29
                pass
30
        number_e164 = phonenumbers.format_number(pn, phonenumbers.PhoneNumberFormat.E164) if pn else ''
31
        atv.content = number_e164
32
        atv.save()
33

  
34
        if not atv.content_type == user_ct:
35
            continue
36
        try:
37
            user = User.objects.get(id=atv.object_id)
38
        except User.DoesNotExist:
39
            continue
40
        if hasattr(user, 'phone'):
41
            user.phone = number_e164
42
            user.save()
43

  
44

  
45
class Migration(migrations.Migration):
46

  
47
    dependencies = [
48
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
49
        ('custom_user', '0032_auto_20220919_1230'),
50
        ('authentic2', '0043_attribute_alter_model_managers'),
51
    ]
52

  
53
    operations = [
54
        migrations.RunPython(migrate_phone_field, reverse_code=migrations.RunPython.noop),
55
    ]
tests/test_migrations.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from django.conf import settings
17 18
from django.contrib.auth.models import AbstractUser
18 19
from django.utils.timezone import now
19 20

  
......
58 59
    User = new_apps.get_model('custom_user', 'User')
59 60
    user = User.objects.get()
60 61
    assert user.email_verified_date == user.date_joined
62

  
63

  
64
def test_migration_authentic2_0044_migrate_phone_field(transactional_db, migration):
65
    old_apps = migration.before([('authentic2', '0043_attribute_alter_model_managers')])
66

  
67
    Attribute = old_apps.get_model('authentic2', 'Attribute')
68
    AttributeValue = old_apps.get_model('authentic2', 'AttributeValue')
69
    User = old_apps.get_model(*settings.AUTH_USER_MODEL.split('.', maxsplit=1))
70
    ContentType = old_apps.get_model('contenttypes', 'ContentType')
71

  
72
    at = Attribute.objects.create(
73
        name='phone',
74
        label='Phone number',
75
        kind='phone_number',
76
    )
77

  
78
    user = User.objects.create(
79
        email='john.doe@example.com',
80
        username='john.doe',
81
        phone='12345',
82
    )
83

  
84
    AttributeValue.objects.create(
85
        attribute=at,
86
        content_type=ContentType.objects.get_for_model(User),
87
        object_id=user.id,
88
        content='12345',
89
    )
90

  
91
    new_apps = migration.apply([('authentic2', '0044_migrate_phone_field')])
92
    User = new_apps.get_model('custom_user', 'User')
93

  
94
    user = User.objects.get()
95
    assert user.phone == '+3312345'
96

  
97
    Attribute = new_apps.get_model('authentic2', 'Attribute')
98
    AttributeValue = new_apps.get_model('authentic2', 'AttributeValue')
99
    ContentType = new_apps.get_model('contenttypes', 'ContentType')
100

  
101
    at = Attribute.objects.get(name='phone')
102
    atv = AttributeValue.objects.get(
103
        attribute=at,
104
        content_type=ContentType.objects.get_for_model(User),
105
        object_id=user.id,
106
    )
107
    assert atv.content == '+3312345'
61
-