File indexing completed on 2026-04-28 07:24:56
0001 """Sync user accounts from swf-monitor via the SSH tunnel.
0002
0003 Calls swf-monitor's /api/users/ endpoint and creates matching local
0004 Django accounts. Sync is one-way (upstream → devcloud) and password
0005 sync only happens at initial provisioning: existing local users are
0006 never password-overwritten by sync, since devcloud account management
0007 is autonomous after creation.
0008
0009 Usage:
0010 python manage.py sync_users
0011 python manage.py sync_users --set-password changeme # fallback if no hash
0012 """
0013
0014 import logging
0015
0016 from django.contrib.auth import get_user_model
0017 from django.core.management.base import BaseCommand
0018
0019 from remote_app import monitor_client
0020
0021 logger = logging.getLogger(__name__)
0022
0023
0024 class Command(BaseCommand):
0025 help = 'Sync user accounts from swf-monitor'
0026
0027 def add_arguments(self, parser):
0028 parser.add_argument(
0029 '--set-password',
0030 help='Fallback password for new accounts when no hash available from upstream',
0031 )
0032
0033 def handle(self, *args, **options):
0034
0035
0036
0037 data = monitor_client._get('/api/users/', as_user='swf-remote-proxy')
0038 if 'error' in data:
0039 self.stderr.write(self.style.ERROR(f"Failed to fetch users: {data['error']}"))
0040 return
0041
0042 users = data.get('users', [])
0043 if not users:
0044 self.stdout.write('No users returned from swf-monitor.')
0045 return
0046
0047 User = get_user_model()
0048 created_count = 0
0049 unchanged_count = 0
0050
0051 for u in users:
0052 username = u.get('username', '').strip()
0053 if not username:
0054 continue
0055 pw_hash = u.get('password', '')
0056 user, created = User.objects.get_or_create(
0057 username=username,
0058 defaults={
0059 'is_active': u.get('is_active', True),
0060 'email': u.get('email', '') or '',
0061 'first_name': u.get('first_name', '') or '',
0062 'last_name': u.get('last_name', '') or '',
0063 },
0064 )
0065 if created:
0066 if pw_hash:
0067
0068 user.password = pw_hash
0069 user.save(update_fields=['password'])
0070 elif options['set_password']:
0071 user.set_password(options['set_password'])
0072 user.save(update_fields=['password'])
0073 created_count += 1
0074 self.stdout.write(self.style.SUCCESS(f' Created: {username}'))
0075 else:
0076
0077
0078 unchanged_count += 1
0079
0080 self.stdout.write(
0081 f'Done. {created_count} created, '
0082 f'{unchanged_count} unchanged (of {len(users)} from swf-monitor).'
0083 )