Skip to content
Snippets Groups Projects
migrate_users.py 2.96 KiB
Newer Older
Dan Braghis's avatar
Dan Braghis committed
import argparse
import json

Dan Braghis's avatar
Dan Braghis committed
from django.conf import settings
Dan Braghis's avatar
Dan Braghis committed
from django.contrib.auth import get_user_model
Dan Braghis's avatar
Dan Braghis committed
from django.contrib.auth.models import Group
Dan Braghis's avatar
Dan Braghis committed
from django.core.management.base import BaseCommand
from django.db import transaction
Dan Braghis's avatar
Dan Braghis committed
from opentech.apply.users.groups import STAFF_GROUP_NAME

Dan Braghis's avatar
Dan Braghis committed

class Command(BaseCommand):
    help = "User migration script. Requires a source JSON file."
Dan Braghis's avatar
Dan Braghis committed
    groups = Group.objects.all()
Dan Braghis's avatar
Dan Braghis committed

    def add_arguments(self, parser):
Dan Braghis's avatar
Dan Braghis committed
        parser.add_argument('source', type=argparse.FileType('r'), help='Migration source JSON file')
    @transaction.atomic
Dan Braghis's avatar
Dan Braghis committed
    def handle(self, *args, **options):
        with options['source'] as json_data:
            User = get_user_model()
            users = json.load(json_data)

            for uid in users:
                user = users[uid]

Dan Braghis's avatar
Dan Braghis committed
                full_name = self.get_full_name(user)
                user_object, created = User.objects.get_or_create(
Dan Braghis's avatar
Dan Braghis committed
                    email=user.get('mail'),
Dan Braghis's avatar
Dan Braghis committed
                    defaults={
                        'full_name': full_name,
                        'drupal_id': uid,
                    }
Dan Braghis's avatar
Dan Braghis committed
                operation = "Imported" if created else "Processed"
Dan Braghis's avatar
Dan Braghis committed

Dan Braghis's avatar
Dan Braghis committed
                groups = self.get_user_groups(user)
                user_object.groups.set(groups)
Dan Braghis's avatar
Dan Braghis committed

                # Ensure uid is set
                user_object.drupal_id = uid
Dan Braghis's avatar
Dan Braghis committed
                user_object.save()

Dan Braghis's avatar
Dan Braghis committed
                self.stdout.write(f"{operation} user {uid} ({full_name})")
Dan Braghis's avatar
Dan Braghis committed
    def get_full_name(self, user):
        full_name = user.get('field_otf_real_name', None)
        try:
Dan Braghis's avatar
Dan Braghis committed
            """
            Drupal is i18n-ready out of the box. As such, the data
            structure includes a language reference, defaulting to 'und' (undefined)
            In addition to that, most fields are arrays indexed by language, and
            the value delta. Different field types will have a different value.
            Native entity fields are loaded directly (as string or int). They are
            things like entity id, owner, created/updated timestamp.
            And name/mail on users.
            """
Dan Braghis's avatar
Dan Braghis committed
            full_name = full_name['und'][0]['safe_value']
        except (KeyError, TypeError):
            full_name = user.get('name')

        return full_name

    def get_user_groups(self, user):
        groups = []
        role_map = {
            'proposer': 'Applicant',
            'council': 'Advisor',
            'administrator': 'Administrator',
            'dev': 'Administrator',
        }

        _, email_domain = user.get('mail').split('@')
        if email_domain in settings.STAFF_EMAIL_DOMAINS:
            groups.append(self.groups.filter(name=STAFF_GROUP_NAME).first())

        roles = [role for role in user.get('roles').values() if role != "authenticated user"]

        for role in roles:
            group_name = role_map.get(role)
            if group_name:
                groups.append(self.groups.filter(name=group_name).first())

        return groups