mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-09 12:30:15 +02:00
Mumble Display Names
This commit is contained in:
parent
32e0621b0a
commit
cc1f94cf61
@ -36,7 +36,7 @@ class DiscordService(ServicesHook):
|
|||||||
|
|
||||||
def sync_nickname(self, user):
|
def sync_nickname(self, user):
|
||||||
logger.debug('Syncing %s nickname for user %s' % (self.name, user))
|
logger.debug('Syncing %s nickname for user %s' % (self.name, user))
|
||||||
DiscordTasks.update_nickname.delay(user.pk)
|
DiscordTasks.update_nickname.apply_async(args=[user.pk], countdown=5)
|
||||||
|
|
||||||
def update_all_groups(self):
|
def update_all_groups(self):
|
||||||
logger.debug('Update all %s groups called' % self.name)
|
logger.debug('Update all %s groups called' % self.name)
|
||||||
|
@ -40,6 +40,11 @@ class MumbleService(ServicesHook):
|
|||||||
if MumbleTasks.has_account(user):
|
if MumbleTasks.has_account(user):
|
||||||
MumbleTasks.update_groups.delay(user.pk)
|
MumbleTasks.update_groups.delay(user.pk)
|
||||||
|
|
||||||
|
def sync_nickname(self, user):
|
||||||
|
logger.debug("Updating %s nickname for %s" % (self.name, user))
|
||||||
|
if MumbleTasks.has_account(user):
|
||||||
|
MumbleTasks.update_display_name.apply_async(args=[user.pk], countdown=5) # cooldown on this task to ensure DB clean when syncing
|
||||||
|
|
||||||
def validate_user(self, user):
|
def validate_user(self, user):
|
||||||
if MumbleTasks.has_account(user) and not self.service_active_for_user(user):
|
if MumbleTasks.has_account(user) and not self.service_active_for_user(user):
|
||||||
self.delete_user(user, notify_user=True)
|
self.delete_user(user, notify_user=True)
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 2.2.9 on 2020-03-16 07:49
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mumble', '0007_not_null_user'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='mumbleuser',
|
||||||
|
name='display_name',
|
||||||
|
field=models.CharField(max_length=254, null=True),
|
||||||
|
)
|
||||||
|
]
|
@ -0,0 +1,37 @@
|
|||||||
|
from django.db import migrations, models
|
||||||
|
from ..auth_hooks import MumbleService
|
||||||
|
from allianceauth.services.hooks import NameFormatter
|
||||||
|
|
||||||
|
def fwd_func(apps, schema_editor):
|
||||||
|
MumbleUser = apps.get_model("mumble", "MumbleUser")
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
all_users = MumbleUser.objects.using(db_alias).all()
|
||||||
|
for user in all_users:
|
||||||
|
display_name = NameFormatter(MumbleService(), user.user).format_name()
|
||||||
|
user.display_name = display_name
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
def rev_func(apps, schema_editor):
|
||||||
|
MumbleUser = apps.get_model("mumble", "MumbleUser")
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
all_users = MumbleUser.objects.using(db_alias).all()
|
||||||
|
for user in all_users:
|
||||||
|
user.display_name = None
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mumble', '0008_mumbleuser_display_name'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(fwd_func, rev_func),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='mumbleuser',
|
||||||
|
name='display_name',
|
||||||
|
field=models.CharField(max_length=254, unique=True),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
@ -15,10 +15,14 @@ class MumbleManager(models.Manager):
|
|||||||
HASH_FN = 'bcrypt-sha256'
|
HASH_FN = 'bcrypt-sha256'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_username(user):
|
def get_display_name(user):
|
||||||
from .auth_hooks import MumbleService
|
from .auth_hooks import MumbleService
|
||||||
return NameFormatter(MumbleService(), user).format_name()
|
return NameFormatter(MumbleService(), user).format_name()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_username(user):
|
||||||
|
return user.profile.main_character.character_name # main character as the user.username may be incorect
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def sanitise_username(username):
|
def sanitise_username(username):
|
||||||
return username.replace(" ", "_")
|
return username.replace(" ", "_")
|
||||||
@ -32,9 +36,11 @@ class MumbleManager(models.Manager):
|
|||||||
return bcrypt_sha256.encrypt(password.encode('utf-8'))
|
return bcrypt_sha256.encrypt(password.encode('utf-8'))
|
||||||
|
|
||||||
def create(self, user):
|
def create(self, user):
|
||||||
|
try:
|
||||||
username = self.get_username(user)
|
username = self.get_username(user)
|
||||||
logger.debug("Creating mumble user with username {}".format(username))
|
logger.debug("Creating mumble user with username {}".format(username))
|
||||||
username_clean = self.sanitise_username(username)
|
username_clean = self.sanitise_username(username)
|
||||||
|
display_name = self.get_display_name(user)
|
||||||
password = self.generate_random_pass()
|
password = self.generate_random_pass()
|
||||||
pwhash = self.gen_pwhash(password)
|
pwhash = self.gen_pwhash(password)
|
||||||
logger.debug("Proceeding with mumble user creation: clean username {}, pwhash starts with {}".format(
|
logger.debug("Proceeding with mumble user creation: clean username {}, pwhash starts with {}".format(
|
||||||
@ -42,10 +48,14 @@ class MumbleManager(models.Manager):
|
|||||||
logger.info("Creating mumble user {}".format(username_clean))
|
logger.info("Creating mumble user {}".format(username_clean))
|
||||||
|
|
||||||
result = super(MumbleManager, self).create(user=user, username=username_clean,
|
result = super(MumbleManager, self).create(user=user, username=username_clean,
|
||||||
pwhash=pwhash, hashfn=self.HASH_FN)
|
pwhash=pwhash, hashfn=self.HASH_FN,
|
||||||
|
display_name=display_name)
|
||||||
result.update_groups()
|
result.update_groups()
|
||||||
result.credentials.update({'username': result.username, 'password': password})
|
result.credentials.update({'username': result.username, 'password': password})
|
||||||
return result
|
return result
|
||||||
|
except AttributeError: # No Main or similar errors
|
||||||
|
return False
|
||||||
|
return False
|
||||||
|
|
||||||
def user_exists(self, username):
|
def user_exists(self, username):
|
||||||
return self.filter(username=username).exists()
|
return self.filter(username=username).exists()
|
||||||
@ -59,6 +69,8 @@ class MumbleUser(AbstractServiceModel):
|
|||||||
|
|
||||||
objects = MumbleManager()
|
objects = MumbleManager()
|
||||||
|
|
||||||
|
display_name = models.CharField(max_length=254, unique=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.username
|
return self.username
|
||||||
|
|
||||||
@ -91,6 +103,12 @@ class MumbleUser(AbstractServiceModel):
|
|||||||
self.save()
|
self.save()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def update_display_name(self):
|
||||||
|
logger.info("Updating mumble user {} display name".format(self.user))
|
||||||
|
self.display_name = MumbleManager.get_display_name(self.user)
|
||||||
|
self.save()
|
||||||
|
return True
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
permissions = (
|
permissions = (
|
||||||
("access_mumble", u"Can access the Mumble service"),
|
("access_mumble", u"Can access the Mumble service"),
|
||||||
|
@ -45,9 +45,37 @@ class MumbleTasks:
|
|||||||
logger.debug("User %s does not have a mumble account, skipping" % user)
|
logger.debug("User %s does not have a mumble account, skipping" % user)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@shared_task(bind=True, name="mumble.update_display_name", base=QueueOnce)
|
||||||
|
def update_display_name(self, pk):
|
||||||
|
user = User.objects.get(pk=pk)
|
||||||
|
logger.debug("Updating mumble groups for user %s" % user)
|
||||||
|
if MumbleTasks.has_account(user):
|
||||||
|
try:
|
||||||
|
if not user.mumble.update_display_name():
|
||||||
|
raise Exception("Display Name Sync failed")
|
||||||
|
logger.debug("Updated user %s mumble display name." % user)
|
||||||
|
return True
|
||||||
|
except MumbleUser.DoesNotExist:
|
||||||
|
logger.info("Mumble display name sync failed for {}, user does not have a mumble account".format(user))
|
||||||
|
except:
|
||||||
|
logger.exception("Mumble display name sync failed for %s, retrying in 10 mins" % user)
|
||||||
|
raise self.retry(countdown=60 * 10)
|
||||||
|
else:
|
||||||
|
logger.debug("User %s does not have a mumble account, skipping" % user)
|
||||||
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@shared_task(name="mumble.update_all_groups")
|
@shared_task(name="mumble.update_all_groups")
|
||||||
def update_all_groups():
|
def update_all_groups():
|
||||||
logger.debug("Updating ALL mumble groups")
|
logger.debug("Updating ALL mumble groups")
|
||||||
for mumble_user in MumbleUser.objects.exclude(username__exact=''):
|
for mumble_user in MumbleUser.objects.exclude(username__exact=''):
|
||||||
MumbleTasks.update_groups.delay(mumble_user.user.pk)
|
MumbleTasks.update_groups.delay(mumble_user.user.pk)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@shared_task(name="mumble.update_all_display_names")
|
||||||
|
def update_all_display_names():
|
||||||
|
logger.debug("Updating ALL mumble display names")
|
||||||
|
for mumble_user in MumbleUser.objects.exclude(username__exact=''):
|
||||||
|
MumbleTasks.update_display_name.delay(mumble_user.user.pk)
|
||||||
|
|
||||||
|
@ -25,6 +25,9 @@ class MumbleHooksTestCase(TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.member = 'member_user'
|
self.member = 'member_user'
|
||||||
member = AuthUtils.create_member(self.member)
|
member = AuthUtils.create_member(self.member)
|
||||||
|
AuthUtils.add_main_character(member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation',
|
||||||
|
corp_ticker='TESTR')
|
||||||
|
member = User.objects.get(pk=member.pk)
|
||||||
MumbleUser.objects.create(user=member)
|
MumbleUser.objects.create(user=member)
|
||||||
self.none_user = 'none_user'
|
self.none_user = 'none_user'
|
||||||
none_user = AuthUtils.create_user(self.none_user)
|
none_user = AuthUtils.create_user(self.none_user)
|
||||||
@ -122,23 +125,45 @@ class MumbleViewsTestCase(TestCase):
|
|||||||
self.member.save()
|
self.member.save()
|
||||||
AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation',
|
AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation',
|
||||||
corp_ticker='TESTR')
|
corp_ticker='TESTR')
|
||||||
|
self.member = User.objects.get(pk=self.member.pk)
|
||||||
add_permissions()
|
add_permissions()
|
||||||
|
|
||||||
def login(self):
|
def login(self):
|
||||||
self.client.force_login(self.member)
|
self.client.force_login(self.member)
|
||||||
|
|
||||||
def test_activate(self):
|
def test_activate_update(self):
|
||||||
self.login()
|
self.login()
|
||||||
expected_username = '[TESTR]auth_member'
|
expected_username = 'auth_member'
|
||||||
|
expected_displayname = '[TESTR]auth_member'
|
||||||
response = self.client.get(urls.reverse('mumble:activate'), follow=False)
|
response = self.client.get(urls.reverse('mumble:activate'), follow=False)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertContains(response, expected_username)
|
self.assertContains(response, expected_username)
|
||||||
|
# create
|
||||||
mumble_user = MumbleUser.objects.get(user=self.member)
|
mumble_user = MumbleUser.objects.get(user=self.member)
|
||||||
self.assertEqual(mumble_user.username, expected_username)
|
self.assertEqual(mumble_user.username, expected_username)
|
||||||
|
self.assertTrue(MumbleUser.objects.user_exists(expected_username))
|
||||||
|
self.assertEqual(str(mumble_user), expected_username)
|
||||||
|
self.assertEqual(mumble_user.display_name, expected_displayname)
|
||||||
self.assertTrue(mumble_user.pwhash)
|
self.assertTrue(mumble_user.pwhash)
|
||||||
self.assertIn('Guest', mumble_user.groups)
|
self.assertIn('Guest', mumble_user.groups)
|
||||||
self.assertIn('Member', mumble_user.groups)
|
self.assertIn('Member', mumble_user.groups)
|
||||||
self.assertIn(',', mumble_user.groups)
|
self.assertIn(',', mumble_user.groups)
|
||||||
|
# test update
|
||||||
|
self.member.profile.main_character.character_name = "auth_member_updated"
|
||||||
|
self.member.profile.main_character.corporation_ticker = "TESTU"
|
||||||
|
self.member.profile.main_character.save()
|
||||||
|
mumble_user.update_display_name()
|
||||||
|
mumble_user = MumbleUser.objects.get(user=self.member)
|
||||||
|
expected_displayname = '[TESTU]auth_member_updated'
|
||||||
|
self.assertEqual(mumble_user.username, expected_username)
|
||||||
|
self.assertTrue(MumbleUser.objects.user_exists(expected_username))
|
||||||
|
self.assertEqual(str(mumble_user), expected_username)
|
||||||
|
self.assertEqual(mumble_user.display_name, expected_displayname)
|
||||||
|
self.assertTrue(mumble_user.pwhash)
|
||||||
|
self.assertIn('Guest', mumble_user.groups)
|
||||||
|
self.assertIn('Member', mumble_user.groups)
|
||||||
|
self.assertIn(',', mumble_user.groups)
|
||||||
|
|
||||||
|
|
||||||
def test_deactivate_post(self):
|
def test_deactivate_post(self):
|
||||||
self.login()
|
self.login()
|
||||||
@ -171,7 +196,6 @@ class MumbleViewsTestCase(TestCase):
|
|||||||
self.assertTemplateUsed(response, 'services/service_credentials.html')
|
self.assertTemplateUsed(response, 'services/service_credentials.html')
|
||||||
self.assertContains(response, 'auth_member')
|
self.assertContains(response, 'auth_member')
|
||||||
|
|
||||||
|
|
||||||
class MumbleManagerTestCase(TestCase):
|
class MumbleManagerTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
from .models import MumbleManager
|
from .models import MumbleManager
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.contrib.auth.models import User, Group, Permission
|
from django.contrib.auth.models import User, Group, Permission
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models.signals import m2m_changed
|
from django.db.models.signals import m2m_changed
|
||||||
from django.db.models.signals import pre_delete
|
from django.db.models.signals import pre_delete
|
||||||
@ -11,6 +12,7 @@ from .tasks import disable_user
|
|||||||
|
|
||||||
from allianceauth.authentication.models import State, UserProfile
|
from allianceauth.authentication.models import State, UserProfile
|
||||||
from allianceauth.authentication.signals import state_changed
|
from allianceauth.authentication.signals import state_changed
|
||||||
|
from allianceauth.eveonline.models import EveCharacter
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -157,14 +159,45 @@ def disable_services_on_inactive(sender, instance, *args, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
@receiver(pre_save, sender=UserProfile)
|
@receiver(pre_save, sender=UserProfile)
|
||||||
def disable_services_on_no_main(sender, instance, *args, **kwargs):
|
def process_main_character_change(sender, instance, *args, **kwargs):
|
||||||
if not instance.pk:
|
|
||||||
|
if not instance.pk: # ignore
|
||||||
# new model being created
|
# new model being created
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
old_instance = UserProfile.objects.get(pk=instance.pk)
|
old_instance = UserProfile.objects.get(pk=instance.pk)
|
||||||
if old_instance.main_character and not instance.main_character:
|
if old_instance.main_character and not instance.main_character: # lost main char disable services
|
||||||
logger.info("Disabling services due to loss of main character for user {0}".format(instance.user))
|
logger.info("Disabling services due to loss of main character for user {0}".format(instance.user))
|
||||||
disable_user(instance.user)
|
disable_user(instance.user)
|
||||||
|
elif old_instance.main_character is not instance.main_character: # swapping/changing main character
|
||||||
|
logger.info("Updating Names due to change of main character for user {0}".format(instance.user))
|
||||||
|
for svc in ServicesHook.get_services():
|
||||||
|
try:
|
||||||
|
svc.validate_user(instance.user)
|
||||||
|
svc.sync_nickname(instance.user)
|
||||||
|
except:
|
||||||
|
logger.exception('Exception running sync_nickname for services module %s on user %s' % (svc, instance))
|
||||||
|
|
||||||
except UserProfile.DoesNotExist:
|
except UserProfile.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(pre_save, sender=EveCharacter)
|
||||||
|
def process_main_character_update(sender, instance, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
if instance.userprofile:
|
||||||
|
old_instance = EveCharacter.objects.get(pk=instance.pk)
|
||||||
|
if not instance.character_name == old_instance.character_name or \
|
||||||
|
not instance.corporation_name == old_instance.corporation_name or \
|
||||||
|
not instance.alliance_name == old_instance.alliance_name:
|
||||||
|
logger.info("syncing service nickname for user {0}".format(instance.userprofile.user))
|
||||||
|
|
||||||
|
for svc in ServicesHook.get_services():
|
||||||
|
try:
|
||||||
|
svc.validate_user(instance.userprofile.user)
|
||||||
|
svc.sync_nickname(instance.userprofile.user)
|
||||||
|
except:
|
||||||
|
logger.exception('Exception running sync_nickname for services module %s on user %s' % (svc, instance))
|
||||||
|
|
||||||
|
except ObjectDoesNotExist: # not a main char ignore
|
||||||
|
pass
|
||||||
|
1
tox.ini
1
tox.ini
@ -19,4 +19,5 @@ install_command = pip install -e ".[testing]" -U {opts} {packages}
|
|||||||
commands =
|
commands =
|
||||||
all: coverage run runtests.py -v 2
|
all: coverage run runtests.py -v 2
|
||||||
all: coverage report -m
|
all: coverage report -m
|
||||||
|
all: coverage xml
|
||||||
core: coverage run runtests.py allianceauth.authentication.tests.test_app_settings -v 2
|
core: coverage run runtests.py allianceauth.authentication.tests.test_app_settings -v 2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user