mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-13 06:20:16 +02:00
Name generator/formatter (#897)
* Squash services migrations * Add name to example service to allow it to be used in tests * Add name formatter to services * Add documentation
This commit is contained in:
parent
b95bb9aa6a
commit
ef37cb3ea5
@ -1 +0,0 @@
|
|||||||
# Create your tests here.
|
|
20
allianceauth/services/admin.py
Normal file
20
allianceauth/services/admin.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from django import forms
|
||||||
|
from allianceauth import hooks
|
||||||
|
from .models import NameFormatConfig
|
||||||
|
|
||||||
|
|
||||||
|
class NameFormatConfigForm(forms.ModelForm):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(NameFormatConfigForm, self).__init__(*args, **kwargs)
|
||||||
|
SERVICE_CHOICES = [(s.name, s.name) for h in hooks.get_hooks('services_hook') for s in [h()]]
|
||||||
|
if self.instance.id:
|
||||||
|
SERVICE_CHOICES.append((self.instance.field, self.instance.field))
|
||||||
|
self.fields['service_name'] = forms.ChoiceField(choices=SERVICE_CHOICES)
|
||||||
|
|
||||||
|
|
||||||
|
class NameFormatConfigAdmin(admin.ModelAdmin):
|
||||||
|
form = NameFormatConfigForm
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(NameFormatConfig, NameFormatConfigAdmin)
|
@ -1,8 +1,14 @@
|
|||||||
from django.conf.urls import include, url
|
from django.conf.urls import include, url
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
from django.utils.functional import cached_property
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.conf import settings
|
||||||
|
from string import Formatter
|
||||||
|
|
||||||
from allianceauth.hooks import get_hooks
|
from allianceauth.hooks import get_hooks
|
||||||
|
|
||||||
|
from .models import NameFormatConfig
|
||||||
|
|
||||||
|
|
||||||
class ServicesHook:
|
class ServicesHook:
|
||||||
"""
|
"""
|
||||||
@ -122,3 +128,77 @@ class MenuItemHook:
|
|||||||
class UrlHook:
|
class UrlHook:
|
||||||
def __init__(self, urls, namespace, base_url):
|
def __init__(self, urls, namespace, base_url):
|
||||||
self.include_pattern = url(base_url, include(urls, namespace=namespace))
|
self.include_pattern = url(base_url, include(urls, namespace=namespace))
|
||||||
|
|
||||||
|
|
||||||
|
class NameFormatter:
|
||||||
|
DEFAULT_FORMAT = getattr(settings, "DEFAULT_SERVICE_NAME_FORMAT", '[{corp_ticker}] {character_name}')
|
||||||
|
|
||||||
|
def __init__(self, service, user):
|
||||||
|
"""
|
||||||
|
:param service: ServicesHook of the service to generate the name for.
|
||||||
|
:param user: django.contrib.auth.models.User to format name for
|
||||||
|
"""
|
||||||
|
self.service = service
|
||||||
|
self.user = user
|
||||||
|
|
||||||
|
def format_name(self):
|
||||||
|
"""
|
||||||
|
:return: str Generated name
|
||||||
|
"""
|
||||||
|
format_data = self.get_format_data()
|
||||||
|
return Formatter().vformat(self.string_formatter, args=[], kwargs=format_data)
|
||||||
|
|
||||||
|
def get_format_data(self):
|
||||||
|
main_char = getattr(self.user.profile, 'main_character', None)
|
||||||
|
|
||||||
|
format_data = {
|
||||||
|
'character_name': getattr(main_char, 'character_name',
|
||||||
|
self.user.username if self._default_to_username else None),
|
||||||
|
'character_id': getattr(main_char, 'character_id', None),
|
||||||
|
'corp_ticker': getattr(main_char, 'corporation_ticker', None),
|
||||||
|
'corp_name': getattr(main_char, 'corporation_name', None),
|
||||||
|
'corp_id': getattr(main_char, 'corporation_id', None),
|
||||||
|
'alliance_name': getattr(main_char, 'alliance_name', None),
|
||||||
|
'alliance_id': getattr(main_char, 'alliance_id', None),
|
||||||
|
'username': self.user.username,
|
||||||
|
}
|
||||||
|
|
||||||
|
if main_char is not None and 'alliance_ticker' in self.string_formatter:
|
||||||
|
# Reduces db lookups
|
||||||
|
try:
|
||||||
|
format_data['alliance_ticker'] = getattr(getattr(main_char, 'alliance', None), 'alliance_ticker', None)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
format_data['alliance_ticker'] = None
|
||||||
|
return format_data
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def formatter_config(self):
|
||||||
|
format_config = NameFormatConfig.objects.filter(service_name=self.service.name,
|
||||||
|
states__pk=self.user.profile.state.pk)
|
||||||
|
|
||||||
|
if format_config.exists():
|
||||||
|
return format_config[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def string_formatter(self):
|
||||||
|
"""
|
||||||
|
Try to get the config format first
|
||||||
|
Then the service default
|
||||||
|
Before finally defaulting to global default
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
return getattr(self.formatter_config, 'format', self.default_formatter)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def default_formatter(self):
|
||||||
|
return getattr(self.service, 'name_format', self.DEFAULT_FORMAT)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def _default_to_username(self):
|
||||||
|
"""
|
||||||
|
Default to a users username if they have no main character.
|
||||||
|
Default is True
|
||||||
|
:return: bool
|
||||||
|
"""
|
||||||
|
return getattr(self.formatter_config, 'default_to_username', True)
|
||||||
|
38
allianceauth/services/migrations/0001_initial.py
Normal file
38
allianceauth/services/migrations/0001_initial.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.1 on 2016-09-05 21:40
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('auth', '0008_alter_user_username_max_length'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='DiscordAuthToken',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('email', models.CharField(max_length=254, unique=True)),
|
||||||
|
('token', models.CharField(max_length=254)),
|
||||||
|
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='GroupCache',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('groups', models.TextField(default={})),
|
||||||
|
('service', models.CharField(choices=[(b'discourse', b'discourse'), (b'discord', b'discord')], max_length=254, unique=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,21 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.5 on 2017-10-07 03:55
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
replaces = [('services', '0001_initial'), ('services', '0002_auto_20161016_0135'), ('services', '0003_delete_groupcache')]
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('auth', '0008_alter_user_username_max_length'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
]
|
22
allianceauth/services/migrations/0002_auto_20161016_0135.py
Normal file
22
allianceauth/services/migrations/0002_auto_20161016_0135.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.1 on 2016-10-16 01:35
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('services', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='discordauthtoken',
|
||||||
|
name='user',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='DiscordAuthToken',
|
||||||
|
),
|
||||||
|
]
|
27
allianceauth/services/migrations/0002_nameformatter.py
Normal file
27
allianceauth/services/migrations/0002_nameformatter.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.5 on 2017-10-07 06:43
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('services', '0001_squashed_0003_delete_groupcache'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='NameFormatConfig',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('service_name', models.CharField(max_length=100)),
|
||||||
|
('default_to_username', models.BooleanField(default=True, help_text='If a user has no main_character, default to using their Auth username instead.')),
|
||||||
|
('format', models.CharField(help_text='For information on constructing name formats, please see the <a href="https://allianceauth.readthedocs.io/en/latest/features/nameformats">name format documentation</a>', max_length=100)),
|
||||||
|
('states', models.ManyToManyField(help_text='States to apply this format to. You should only have one formatter for each state for each service.', to='authentication.State')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
18
allianceauth/services/migrations/0003_delete_groupcache.py
Normal file
18
allianceauth/services/migrations/0003_delete_groupcache.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.5 on 2017-09-02 06:07
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('services', '0002_auto_20161016_0135'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='GroupCache',
|
||||||
|
),
|
||||||
|
]
|
0
allianceauth/services/migrations/__init__.py
Normal file
0
allianceauth/services/migrations/__init__.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
from allianceauth.authentication.models import State
|
||||||
|
|
||||||
|
|
||||||
|
class NameFormatConfig(models.Model):
|
||||||
|
service_name = models.CharField(max_length=100, blank=False, null=False)
|
||||||
|
default_to_username = models.BooleanField(default=True, help_text="If a user has no main_character, "
|
||||||
|
"default to using their Auth username instead.")
|
||||||
|
format = models.CharField(max_length=100, blank=False, null=False,
|
||||||
|
help_text='For information on constructing name formats, please see the '
|
||||||
|
'<a href="https://allianceauth.readthedocs.io/en/latest/features/nameformats">'
|
||||||
|
'name format documentation</a>')
|
||||||
|
states = models.ManyToManyField(State, help_text="States to apply this format to. You should only have one "
|
||||||
|
"formatter for each state for each service.")
|
||||||
|
|
||||||
|
|
@ -18,6 +18,7 @@ class DiscordService(ServicesHook):
|
|||||||
self.name = 'discord'
|
self.name = 'discord'
|
||||||
self.service_ctrl_template = 'services/discord/discord_service_ctrl.html'
|
self.service_ctrl_template = 'services/discord/discord_service_ctrl.html'
|
||||||
self.access_perm = 'discord.access_discord'
|
self.access_perm = 'discord.access_discord'
|
||||||
|
self.name_format = '{character_name}'
|
||||||
|
|
||||||
def delete_user(self, user, notify_user=False):
|
def delete_user(self, user, notify_user=False):
|
||||||
logger.debug('Deleting user %s %s account' % (user, self.name))
|
logger.debug('Deleting user %s %s account' % (user, self.name))
|
||||||
|
@ -6,6 +6,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
|||||||
from allianceauth.notifications import notify
|
from allianceauth.notifications import notify
|
||||||
|
|
||||||
from allianceauth.celery import app
|
from allianceauth.celery import app
|
||||||
|
from allianceauth.services.hooks import NameFormatter
|
||||||
from .manager import DiscordOAuthManager, DiscordApiBackoff
|
from .manager import DiscordOAuthManager, DiscordApiBackoff
|
||||||
from .models import DiscordUser
|
from .models import DiscordUser
|
||||||
|
|
||||||
@ -102,7 +103,7 @@ class DiscordTasks:
|
|||||||
character = user.profile.main_character
|
character = user.profile.main_character
|
||||||
logger.debug("Updating user %s discord nickname to %s" % (user, character.character_name))
|
logger.debug("Updating user %s discord nickname to %s" % (user, character.character_name))
|
||||||
try:
|
try:
|
||||||
DiscordOAuthManager.update_nickname(user.discord.uid, character.character_name)
|
DiscordOAuthManager.update_nickname(user.discord.uid, DiscordTasks.get_nickname(user))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if self:
|
if self:
|
||||||
logger.exception("Discord nickname sync failed for %s, retrying in 10 mins" % user)
|
logger.exception("Discord nickname sync failed for %s, retrying in 10 mins" % user)
|
||||||
@ -126,3 +127,8 @@ class DiscordTasks:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def disable(cls):
|
def disable(cls):
|
||||||
DiscordUser.objects.all().delete()
|
DiscordUser.objects.all().delete()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_nickname(user):
|
||||||
|
from .auth_hooks import DiscordService
|
||||||
|
return NameFormatter(DiscordService(), user).format_name()
|
||||||
|
@ -18,6 +18,7 @@ class DiscourseService(ServicesHook):
|
|||||||
self.name = 'discourse'
|
self.name = 'discourse'
|
||||||
self.service_ctrl_template = 'services/discourse/discourse_service_ctrl.html'
|
self.service_ctrl_template = 'services/discourse/discourse_service_ctrl.html'
|
||||||
self.access_perm = 'discourse.access_discourse'
|
self.access_perm = 'discourse.access_discourse'
|
||||||
|
self.name_format = '{character_name}'
|
||||||
|
|
||||||
def delete_user(self, user, notify_user=False):
|
def delete_user(self, user, notify_user=False):
|
||||||
logger.debug('Deleting user %s %s account' % (user, self.name))
|
logger.debug('Deleting user %s %s account' % (user, self.name))
|
||||||
|
@ -5,6 +5,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
|||||||
|
|
||||||
from allianceauth.celery import app
|
from allianceauth.celery import app
|
||||||
from allianceauth.notifications import notify
|
from allianceauth.notifications import notify
|
||||||
|
from allianceauth.services.hooks import NameFormatter
|
||||||
from .manager import DiscourseManager
|
from .manager import DiscourseManager
|
||||||
from .models import DiscourseUser
|
from .models import DiscourseUser
|
||||||
|
|
||||||
@ -56,3 +57,8 @@ class DiscourseTasks:
|
|||||||
logger.debug("Updating ALL discourse groups")
|
logger.debug("Updating ALL discourse groups")
|
||||||
for discourse_user in DiscourseUser.objects.filter(enabled=True):
|
for discourse_user in DiscourseUser.objects.filter(enabled=True):
|
||||||
DiscourseTasks.update_groups.delay(discourse_user.user.pk)
|
DiscourseTasks.update_groups.delay(discourse_user.user.pk)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_username(user):
|
||||||
|
from .auth_hooks import DiscourseService
|
||||||
|
return NameFormatter(DiscourseService(), user).format_name()
|
||||||
|
@ -71,7 +71,7 @@ def discourse_sso(request):
|
|||||||
|
|
||||||
## Build the return payload
|
## Build the return payload
|
||||||
|
|
||||||
username = DiscourseManager._sanitize_username(main_char.character_name)
|
username = DiscourseManager._sanitize_username(DiscourseTasks.get_username(request.user))
|
||||||
|
|
||||||
qs = parse_qs(decoded)
|
qs = parse_qs(decoded)
|
||||||
params = {
|
params = {
|
||||||
|
@ -10,6 +10,7 @@ class ExampleService(ServicesHook):
|
|||||||
ServicesHook.__init__(self)
|
ServicesHook.__init__(self)
|
||||||
self.urlpatterns = urlpatterns
|
self.urlpatterns = urlpatterns
|
||||||
self.service_url = 'http://exampleservice.example.com'
|
self.service_url = 'http://exampleservice.example.com'
|
||||||
|
self.name = 'example'
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Overload base methods here to implement functionality
|
Overload base methods here to implement functionality
|
||||||
|
@ -14,6 +14,7 @@ class Ips4Service(ServicesHook):
|
|||||||
self.urlpatterns = urlpatterns
|
self.urlpatterns = urlpatterns
|
||||||
self.service_url = settings.IPS4_URL
|
self.service_url = settings.IPS4_URL
|
||||||
self.access_perm = 'ips4.access_ips4'
|
self.access_perm = 'ips4.access_ips4'
|
||||||
|
self.name_format = '{character_name}'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
|
from allianceauth.services.hooks import NameFormatter
|
||||||
from .manager import Ips4Manager
|
from .manager import Ips4Manager
|
||||||
from .models import Ips4User
|
from .models import Ips4User
|
||||||
|
|
||||||
@ -33,3 +34,8 @@ class Ips4Tasks:
|
|||||||
def disable():
|
def disable():
|
||||||
logging.debug("Deleting all IPS4 users")
|
logging.debug("Deleting all IPS4 users")
|
||||||
Ips4User.objects.all().delete()
|
Ips4User.objects.all().delete()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_username(user):
|
||||||
|
from .auth_hooks import Ips4Service
|
||||||
|
return NameFormatter(Ips4Service(), user).format_name()
|
||||||
|
@ -20,7 +20,7 @@ def activate_ips4(request):
|
|||||||
logger.debug("activate_ips4 called by user %s" % request.user)
|
logger.debug("activate_ips4 called by user %s" % request.user)
|
||||||
character = request.user.profile.main_character
|
character = request.user.profile.main_character
|
||||||
logger.debug("Adding IPS4 user for user %s with main character %s" % (request.user, character))
|
logger.debug("Adding IPS4 user for user %s with main character %s" % (request.user, character))
|
||||||
result = Ips4Manager.add_user(character.character_name, request.user.email)
|
result = Ips4Manager.add_user(Ips4Tasks.get_username(request.user), request.user.email)
|
||||||
# if empty we failed
|
# if empty we failed
|
||||||
if result[0] != "" and not Ips4Tasks.has_account(request.user):
|
if result[0] != "" and not Ips4Tasks.has_account(request.user):
|
||||||
ips_user = Ips4User.objects.create(user=request.user, id=result[2], username=result[0])
|
ips_user = Ips4User.objects.create(user=request.user, id=result[2], username=result[0])
|
||||||
|
@ -21,6 +21,7 @@ class MumbleService(ServicesHook):
|
|||||||
self.service_url = settings.MUMBLE_URL
|
self.service_url = settings.MUMBLE_URL
|
||||||
self.access_perm = 'mumble.access_mumble'
|
self.access_perm = 'mumble.access_mumble'
|
||||||
self.service_ctrl_template = 'services/mumble/mumble_service_ctrl.html'
|
self.service_ctrl_template = 'services/mumble/mumble_service_ctrl.html'
|
||||||
|
self.name_format = '[{corp_ticker}]{character_name}'
|
||||||
|
|
||||||
def delete_user(self, user, notify_user=False):
|
def delete_user(self, user, notify_user=False):
|
||||||
logging.debug("Deleting user %s %s account" % (user, self.name))
|
logging.debug("Deleting user %s %s account" % (user, self.name))
|
||||||
|
@ -26,25 +26,14 @@ class MumbleManager:
|
|||||||
def __generate_random_pass():
|
def __generate_random_pass():
|
||||||
return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(16)])
|
return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(16)])
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __generate_username(username, corp_ticker):
|
|
||||||
return "[" + corp_ticker + "]" + username
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __generate_username_blue(username, corp_ticker):
|
|
||||||
return "[BLUE][" + corp_ticker + "]" + username
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _gen_pwhash(cls, password):
|
def _gen_pwhash(cls, password):
|
||||||
return bcrypt_sha256.encrypt(password.encode('utf-8'))
|
return bcrypt_sha256.encrypt(password.encode('utf-8'))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_user(cls, user, corp_ticker, username, blue=False):
|
def create_user(cls, user, username):
|
||||||
logger.debug("Creating%s mumble user with username %s and ticker %s" % (' blue' if blue else '',
|
logger.debug("Creating mumble user with username %s" % (username))
|
||||||
username, corp_ticker))
|
username_clean = cls.__santatize_username(username)
|
||||||
username_clean = cls.__santatize_username(
|
|
||||||
cls.__generate_username_blue(username, corp_ticker) if blue else
|
|
||||||
cls.__generate_username(username, corp_ticker))
|
|
||||||
password = cls.__generate_random_pass()
|
password = cls.__generate_random_pass()
|
||||||
pwhash = cls._gen_pwhash(password)
|
pwhash = cls._gen_pwhash(password)
|
||||||
logger.debug("Proceeding with mumble user creation: clean username %s, pwhash starts with %s" % (
|
logger.debug("Proceeding with mumble user creation: clean username %s, pwhash starts with %s" % (
|
||||||
|
@ -2,6 +2,7 @@ import logging
|
|||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from allianceauth.services.hooks import NameFormatter
|
||||||
|
|
||||||
from allianceauth.celery import app
|
from allianceauth.celery import app
|
||||||
from .manager import MumbleManager
|
from .manager import MumbleManager
|
||||||
@ -26,6 +27,11 @@ class MumbleTasks:
|
|||||||
logger.info("Deleting all MumbleUser models")
|
logger.info("Deleting all MumbleUser models")
|
||||||
MumbleUser.objects.all().delete()
|
MumbleUser.objects.all().delete()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_username(user):
|
||||||
|
from .auth_hooks import MumbleService
|
||||||
|
return NameFormatter(MumbleService(), user).format_name()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@app.task(bind=True, name="mumble.update_groups")
|
@app.task(bind=True, name="mumble.update_groups")
|
||||||
def update_groups(self, pk):
|
def update_groups(self, pk):
|
||||||
|
@ -18,10 +18,9 @@ ACCESS_PERM = 'mumble.access_mumble'
|
|||||||
def activate_mumble(request):
|
def activate_mumble(request):
|
||||||
logger.debug("activate_mumble called by user %s" % request.user)
|
logger.debug("activate_mumble called by user %s" % request.user)
|
||||||
character = request.user.profile.main_character
|
character = request.user.profile.main_character
|
||||||
ticker = character.corporation_ticker
|
|
||||||
|
|
||||||
logger.debug("Adding mumble user for %s with main character %s" % (request.user, character))
|
logger.debug("Adding mumble user for %s with main character %s" % (request.user, character))
|
||||||
result = MumbleManager.create_user(request.user, ticker, character.character_name)
|
result = MumbleManager.create_user(request.user, MumbleTasks.get_username(request.user))
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
logger.debug("Updated authserviceinfo for user %s with mumble credentials. Updating groups." % request.user)
|
logger.debug("Updated authserviceinfo for user %s with mumble credentials. Updating groups." % request.user)
|
||||||
|
@ -18,6 +18,7 @@ class OpenfireService(ServicesHook):
|
|||||||
self.urlpatterns = urlpatterns
|
self.urlpatterns = urlpatterns
|
||||||
self.service_url = settings.JABBER_URL
|
self.service_url = settings.JABBER_URL
|
||||||
self.access_perm = 'openfire.access_openfire'
|
self.access_perm = 'openfire.access_openfire'
|
||||||
|
self.name_format = '{character_name}'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
|
@ -6,6 +6,7 @@ from allianceauth.notifications import notify
|
|||||||
|
|
||||||
from allianceauth.celery import app
|
from allianceauth.celery import app
|
||||||
from allianceauth.services.modules.openfire.manager import OpenfireManager
|
from allianceauth.services.modules.openfire.manager import OpenfireManager
|
||||||
|
from allianceauth.services.hooks import NameFormatter
|
||||||
from .models import OpenfireUser
|
from .models import OpenfireUser
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -65,3 +66,8 @@ class OpenfireTasks:
|
|||||||
logger.debug("Updating ALL jabber groups")
|
logger.debug("Updating ALL jabber groups")
|
||||||
for openfire_user in OpenfireUser.objects.exclude(username__exact=''):
|
for openfire_user in OpenfireUser.objects.exclude(username__exact=''):
|
||||||
OpenfireTasks.update_groups.delay(openfire_user.user.pk)
|
OpenfireTasks.update_groups.delay(openfire_user.user.pk)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_username(user):
|
||||||
|
from .auth_hooks import OpenfireService
|
||||||
|
return NameFormatter(OpenfireService(), user).format_name()
|
||||||
|
@ -23,7 +23,7 @@ def activate_jabber(request):
|
|||||||
logger.debug("activate_jabber called by user %s" % request.user)
|
logger.debug("activate_jabber called by user %s" % request.user)
|
||||||
character = request.user.profile.main_character
|
character = request.user.profile.main_character
|
||||||
logger.debug("Adding jabber user for user %s with main character %s" % (request.user, character))
|
logger.debug("Adding jabber user for user %s with main character %s" % (request.user, character))
|
||||||
info = OpenfireManager.add_user(character.character_name)
|
info = OpenfireManager.add_user(OpenfireTasks.get_username(request.user))
|
||||||
# If our username is blank means we already had a user
|
# If our username is blank means we already had a user
|
||||||
if info[0] is not "":
|
if info[0] is not "":
|
||||||
OpenfireUser.objects.update_or_create(user=request.user, defaults={'username': info[0]})
|
OpenfireUser.objects.update_or_create(user=request.user, defaults={'username': info[0]})
|
||||||
|
@ -18,6 +18,7 @@ class Phpbb3Service(ServicesHook):
|
|||||||
self.urlpatterns = urlpatterns
|
self.urlpatterns = urlpatterns
|
||||||
self.service_url = settings.PHPBB3_URL
|
self.service_url = settings.PHPBB3_URL
|
||||||
self.access_perm = 'phpbb3.access_phpbb3'
|
self.access_perm = 'phpbb3.access_phpbb3'
|
||||||
|
self.name_format = '{character_name}'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
|
@ -5,6 +5,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
|||||||
|
|
||||||
from allianceauth.celery import app
|
from allianceauth.celery import app
|
||||||
from allianceauth.notifications import notify
|
from allianceauth.notifications import notify
|
||||||
|
from allianceauth.services.hooks import NameFormatter
|
||||||
from .manager import Phpbb3Manager
|
from .manager import Phpbb3Manager
|
||||||
from .models import Phpbb3User
|
from .models import Phpbb3User
|
||||||
|
|
||||||
@ -64,3 +65,8 @@ class Phpbb3Tasks:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def disable():
|
def disable():
|
||||||
Phpbb3User.objects.all().delete()
|
Phpbb3User.objects.all().delete()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_username(user):
|
||||||
|
from .auth_hooks import Phpbb3Service
|
||||||
|
return NameFormatter(Phpbb3Service(), user).format_name()
|
||||||
|
@ -21,7 +21,7 @@ def activate_forum(request):
|
|||||||
# Valid now we get the main characters
|
# Valid now we get the main characters
|
||||||
character = request.user.profile.main_character
|
character = request.user.profile.main_character
|
||||||
logger.debug("Adding phpbb user for user %s with main character %s" % (request.user, character))
|
logger.debug("Adding phpbb user for user %s with main character %s" % (request.user, character))
|
||||||
result = Phpbb3Manager.add_user(character.character_name, request.user.email, ['REGISTERED'],
|
result = Phpbb3Manager.add_user(Phpbb3Tasks.get_username(request.user), request.user.email, ['REGISTERED'],
|
||||||
character.character_id)
|
character.character_id)
|
||||||
# if empty we failed
|
# if empty we failed
|
||||||
if result[0] != "":
|
if result[0] != "":
|
||||||
|
@ -18,6 +18,7 @@ class SeatService(ServicesHook):
|
|||||||
self.name = 'seat'
|
self.name = 'seat'
|
||||||
self.service_url = settings.SEAT_URL
|
self.service_url = settings.SEAT_URL
|
||||||
self.access_perm = 'seat.access_seat'
|
self.access_perm = 'seat.access_seat'
|
||||||
|
self.name_format = '{character_name}'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
|
@ -5,6 +5,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
|||||||
|
|
||||||
from allianceauth.celery import app
|
from allianceauth.celery import app
|
||||||
from allianceauth.notifications import notify
|
from allianceauth.notifications import notify
|
||||||
|
from allianceauth.services.hooks import NameFormatter
|
||||||
from .manager import SeatManager
|
from .manager import SeatManager
|
||||||
from .models import SeatUser
|
from .models import SeatUser
|
||||||
|
|
||||||
@ -64,3 +65,8 @@ class SeatTasks:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def deactivate():
|
def deactivate():
|
||||||
SeatUser.objects.all().delete()
|
SeatUser.objects.all().delete()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_username(user):
|
||||||
|
from .auth_hooks import SeatService
|
||||||
|
return NameFormatter(SeatService(), user).format_name()
|
||||||
|
@ -25,7 +25,7 @@ def activate_seat(request):
|
|||||||
stat = SeatManager.check_user_status(character.character_name)
|
stat = SeatManager.check_user_status(character.character_name)
|
||||||
if stat == {}:
|
if stat == {}:
|
||||||
logger.debug("User not found, adding SeAT user for user %s with main character %s" % (request.user, character))
|
logger.debug("User not found, adding SeAT user for user %s with main character %s" % (request.user, character))
|
||||||
result = SeatManager.add_user(character.character_name, request.user.email)
|
result = SeatManager.add_user(SeatTasks.get_username(request.user), request.user.email)
|
||||||
else:
|
else:
|
||||||
logger.debug("User found, resetting password")
|
logger.debug("User found, resetting password")
|
||||||
username = SeatManager.enable_user(stat["name"])
|
username = SeatManager.enable_user(stat["name"])
|
||||||
|
@ -18,6 +18,7 @@ class SmfService(ServicesHook):
|
|||||||
self.urlpatterns = urlpatterns
|
self.urlpatterns = urlpatterns
|
||||||
self.service_url = settings.SMF_URL
|
self.service_url = settings.SMF_URL
|
||||||
self.access_perm = 'smf.access_smf'
|
self.access_perm = 'smf.access_smf'
|
||||||
|
self.name_format = '{character_name}'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
|
@ -5,6 +5,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
|||||||
|
|
||||||
from allianceauth.celery import app
|
from allianceauth.celery import app
|
||||||
from allianceauth.notifications import notify
|
from allianceauth.notifications import notify
|
||||||
|
from allianceauth.services.hooks import NameFormatter
|
||||||
from .manager import SmfManager
|
from .manager import SmfManager
|
||||||
from .models import SmfUser
|
from .models import SmfUser
|
||||||
|
|
||||||
@ -64,3 +65,8 @@ class SmfTasks:
|
|||||||
logger.debug("Updating ALL smf groups")
|
logger.debug("Updating ALL smf groups")
|
||||||
for user in SmfUser.objects.exclude(username__exact=''):
|
for user in SmfUser.objects.exclude(username__exact=''):
|
||||||
SmfTasks.update_groups.delay(user.user_id)
|
SmfTasks.update_groups.delay(user.user_id)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_username(user):
|
||||||
|
from .auth_hooks import SmfService
|
||||||
|
return NameFormatter(SmfService(), user).format_name()
|
||||||
|
@ -21,7 +21,8 @@ def activate_smf(request):
|
|||||||
# Valid now we get the main characters
|
# Valid now we get the main characters
|
||||||
character = request.user.profile.main_character
|
character = request.user.profile.main_character
|
||||||
logger.debug("Adding smf user for user %s with main character %s" % (request.user, character))
|
logger.debug("Adding smf user for user %s with main character %s" % (request.user, character))
|
||||||
result = SmfManager.add_user(character.character_name, request.user.email, ['Member'], character.character_id)
|
result = SmfManager.add_user(SmfTasks.get_username(request.user), request.user.email, ['Member'],
|
||||||
|
character.character_id)
|
||||||
# if empty we failed
|
# if empty we failed
|
||||||
if result[0] != "":
|
if result[0] != "":
|
||||||
SmfUser.objects.update_or_create(user=request.user, defaults={'username': result[0]})
|
SmfUser.objects.update_or_create(user=request.user, defaults={'username': result[0]})
|
||||||
|
@ -18,6 +18,7 @@ class Teamspeak3Service(ServicesHook):
|
|||||||
self.urlpatterns = urlpatterns
|
self.urlpatterns = urlpatterns
|
||||||
self.service_ctrl_template = 'services/teamspeak3/teamspeak3_service_ctrl.html'
|
self.service_ctrl_template = 'services/teamspeak3/teamspeak3_service_ctrl.html'
|
||||||
self.access_perm = 'teamspeak3.access_teamspeak3'
|
self.access_perm = 'teamspeak3.access_teamspeak3'
|
||||||
|
self.name_format = '[{corp_ticker}]{character_name}'
|
||||||
|
|
||||||
def delete_user(self, user, notify_user=False):
|
def delete_user(self, user, notify_user=False):
|
||||||
logger.debug('Deleting user %s %s account' % (user, self.name))
|
logger.debug('Deleting user %s %s account' % (user, self.name))
|
||||||
|
@ -50,11 +50,6 @@ class Teamspeak3Manager:
|
|||||||
sanatized = sanatized.replace("'", "-")
|
sanatized = sanatized.replace("'", "-")
|
||||||
return sanatized
|
return sanatized
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __generate_username(username, corp_ticker):
|
|
||||||
sanatized = "[" + corp_ticker + "]" + username
|
|
||||||
return sanatized[:30]
|
|
||||||
|
|
||||||
def _get_userid(self, uid):
|
def _get_userid(self, uid):
|
||||||
logger.debug("Looking for uid %s on TS3 server." % uid)
|
logger.debug("Looking for uid %s on TS3 server." % uid)
|
||||||
try:
|
try:
|
||||||
@ -184,8 +179,8 @@ class Teamspeak3Manager:
|
|||||||
except:
|
except:
|
||||||
logger.exception("An unhandled exception has occured while syncing TS groups.")
|
logger.exception("An unhandled exception has occured while syncing TS groups.")
|
||||||
|
|
||||||
def add_user(self, username, corp_ticker):
|
def add_user(self, username):
|
||||||
username_clean = self.__santatize_username(self.__generate_username(username, corp_ticker))
|
username_clean = self.__santatize_username(username[:30])
|
||||||
logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean)
|
logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean)
|
||||||
server_groups = self._group_list()
|
server_groups = self._group_list()
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
|||||||
|
|
||||||
from allianceauth.celery import app
|
from allianceauth.celery import app
|
||||||
from allianceauth.notifications import notify
|
from allianceauth.notifications import notify
|
||||||
|
from allianceauth.services.hooks import NameFormatter
|
||||||
from .manager import Teamspeak3Manager
|
from .manager import Teamspeak3Manager
|
||||||
from .models import AuthTS, TSgroup, UserTSgroup, Teamspeak3User
|
from .models import AuthTS, TSgroup, UserTSgroup, Teamspeak3User
|
||||||
from .util.ts3 import TeamspeakError
|
from .util.ts3 import TeamspeakError
|
||||||
@ -85,3 +86,8 @@ class Teamspeak3Tasks:
|
|||||||
logger.debug("Updating ALL teamspeak3 groups")
|
logger.debug("Updating ALL teamspeak3 groups")
|
||||||
for user in Teamspeak3User.objects.exclude(uid__exact=''):
|
for user in Teamspeak3User.objects.exclude(uid__exact=''):
|
||||||
Teamspeak3Tasks.update_groups.delay(user.user_id)
|
Teamspeak3Tasks.update_groups.delay(user.user_id)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_username(user):
|
||||||
|
from .auth_hooks import Teamspeak3Service
|
||||||
|
return NameFormatter(Teamspeak3Service(), user).format_name()
|
||||||
|
@ -23,7 +23,7 @@ def activate_teamspeak3(request):
|
|||||||
ticker = character.corporation_ticker
|
ticker = character.corporation_ticker
|
||||||
with Teamspeak3Manager() as ts3man:
|
with Teamspeak3Manager() as ts3man:
|
||||||
logger.debug("Adding TS3 user for user %s with main character %s" % (request.user, character))
|
logger.debug("Adding TS3 user for user %s with main character %s" % (request.user, character))
|
||||||
result = ts3man.add_user(character.character_name, ticker)
|
result = ts3man.add_user(Teamspeak3Tasks.get_username(request.user))
|
||||||
|
|
||||||
# if its empty we failed
|
# if its empty we failed
|
||||||
if result[0] is not "":
|
if result[0] is not "":
|
||||||
|
@ -16,6 +16,7 @@ class XenforoService(ServicesHook):
|
|||||||
self.name = 'xenforo'
|
self.name = 'xenforo'
|
||||||
self.urlpatterns = urlpatterns
|
self.urlpatterns = urlpatterns
|
||||||
self.access_perm = 'xenforo.access_xenforo'
|
self.access_perm = 'xenforo.access_xenforo'
|
||||||
|
self.name_format = '{character_name}'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
|
@ -3,6 +3,7 @@ import logging
|
|||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
from allianceauth.notifications import notify
|
from allianceauth.notifications import notify
|
||||||
|
from allianceauth.services.hooks import NameFormatter
|
||||||
from .manager import XenForoManager
|
from .manager import XenForoManager
|
||||||
from .models import XenforoUser
|
from .models import XenforoUser
|
||||||
|
|
||||||
@ -35,3 +36,8 @@ class XenforoTasks:
|
|||||||
def disable(cls):
|
def disable(cls):
|
||||||
logger.debug("Deleting ALL XenForo users")
|
logger.debug("Deleting ALL XenForo users")
|
||||||
XenforoUser.objects.all().delete()
|
XenforoUser.objects.all().delete()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_username(user):
|
||||||
|
from .auth_hooks import XenforoService
|
||||||
|
return NameFormatter(XenforoService(), user).format_name()
|
||||||
|
@ -20,7 +20,7 @@ def activate_xenforo_forum(request):
|
|||||||
logger.debug("activate_xenforo_forum called by user %s" % request.user)
|
logger.debug("activate_xenforo_forum called by user %s" % request.user)
|
||||||
character = request.user.profile.main_character
|
character = request.user.profile.main_character
|
||||||
logger.debug("Adding XenForo user for user %s with main character %s" % (request.user, character))
|
logger.debug("Adding XenForo user for user %s with main character %s" % (request.user, character))
|
||||||
result = XenForoManager.add_user(character.character_name, request.user.email)
|
result = XenForoManager.add_user(XenforoTasks.get_username(request.user), request.user.email)
|
||||||
# Based on XenAPI's response codes
|
# Based on XenAPI's response codes
|
||||||
if result['response']['status_code'] == 200:
|
if result['response']['status_code'] == 200:
|
||||||
XenforoUser.objects.update_or_create(user=request.user, defaults={'username': result['username']})
|
XenforoUser.objects.update_or_create(user=request.user, defaults={'username': result['username']})
|
||||||
|
103
allianceauth/services/tests/test_nameformatter.py
Normal file
103
allianceauth/services/tests/test_nameformatter.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
from allianceauth.eveonline.models import EveAllianceInfo, EveCorporationInfo, EveCharacter
|
||||||
|
from ..models import NameFormatConfig
|
||||||
|
from ..hooks import NameFormatter
|
||||||
|
from ..modules.example.auth_hooks import ExampleService
|
||||||
|
|
||||||
|
|
||||||
|
class NameFormatterTestCase(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.member = AuthUtils.create_user('auth_member', disconnect_signals=True)
|
||||||
|
|
||||||
|
self.alliance = EveAllianceInfo.objects.create(
|
||||||
|
alliance_id='3456',
|
||||||
|
alliance_name='alliance name',
|
||||||
|
alliance_ticker='TIKR',
|
||||||
|
executor_corp_id='2345',
|
||||||
|
)
|
||||||
|
|
||||||
|
self.corp = EveCorporationInfo.objects.create(
|
||||||
|
corporation_id='2345',
|
||||||
|
corporation_name='corp name',
|
||||||
|
corporation_ticker='TIKK',
|
||||||
|
member_count=10,
|
||||||
|
alliance=self.alliance,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.char = EveCharacter.objects.create(
|
||||||
|
character_id='1234',
|
||||||
|
character_name='test character',
|
||||||
|
corporation_id='2345',
|
||||||
|
corporation_name='test corp',
|
||||||
|
corporation_ticker='TIKK',
|
||||||
|
alliance_id='3456',
|
||||||
|
alliance_name='alliance name',
|
||||||
|
)
|
||||||
|
self.member.profile.main_character = self.char
|
||||||
|
self.member.profile.save()
|
||||||
|
|
||||||
|
def test_formatter_prop(self):
|
||||||
|
config = NameFormatConfig.objects.create(
|
||||||
|
service_name='example',
|
||||||
|
default_to_username=False,
|
||||||
|
format='{character_name}',
|
||||||
|
)
|
||||||
|
|
||||||
|
config.states.add(self.member.profile.state)
|
||||||
|
|
||||||
|
formatter = NameFormatter(ExampleService(), self.member)
|
||||||
|
|
||||||
|
self.assertEqual(config, formatter.formatter_config)
|
||||||
|
|
||||||
|
def test_default_formatter(self):
|
||||||
|
|
||||||
|
formatter = NameFormatter(ExampleService(), self.member)
|
||||||
|
|
||||||
|
self.assertEqual(NameFormatter.DEFAULT_FORMAT, formatter.default_formatter)
|
||||||
|
# Test the default is returned when the service has no default
|
||||||
|
self.assertEqual(NameFormatter.DEFAULT_FORMAT, formatter.string_formatter)
|
||||||
|
|
||||||
|
def test_get_format_data(self):
|
||||||
|
config = NameFormatConfig.objects.create(
|
||||||
|
service_name='example',
|
||||||
|
default_to_username=False,
|
||||||
|
format='{alliance_ticker}', # Ensures that alliance_ticker is filled
|
||||||
|
)
|
||||||
|
config.states.add(self.member.profile.state)
|
||||||
|
|
||||||
|
formatter = NameFormatter(ExampleService(), self.member)
|
||||||
|
|
||||||
|
result = formatter.get_format_data()
|
||||||
|
|
||||||
|
self.assertIn('character_name', result)
|
||||||
|
self.assertEqual(result['character_name'], self.char.character_name)
|
||||||
|
self.assertIn('character_id', result)
|
||||||
|
self.assertEqual(result['character_id'], self.char.character_id)
|
||||||
|
self.assertIn('corp_name', result)
|
||||||
|
self.assertEqual(result['corp_name'], self.char.corporation_name)
|
||||||
|
self.assertIn('corp_id', result)
|
||||||
|
self.assertEqual(result['corp_id'], self.char.corporation_id)
|
||||||
|
self.assertIn('corp_ticker', result)
|
||||||
|
self.assertEqual(result['corp_ticker'], self.char.corporation_ticker)
|
||||||
|
self.assertIn('alliance_name', result)
|
||||||
|
self.assertEqual(result['alliance_name'], self.char.alliance_name)
|
||||||
|
self.assertIn('alliance_ticker', result)
|
||||||
|
self.assertEqual(result['alliance_ticker'], self.char.alliance.alliance_ticker)
|
||||||
|
self.assertIn('alliance_id', result)
|
||||||
|
self.assertEqual(result['alliance_id'], self.char.alliance_id)
|
||||||
|
self.assertIn('username', result)
|
||||||
|
self.assertEqual(result['username'], self.member.username)
|
||||||
|
|
||||||
|
def test_format_name(self):
|
||||||
|
config = NameFormatConfig.objects.create(
|
||||||
|
service_name='example',
|
||||||
|
default_to_username=False,
|
||||||
|
format='{character_id} test {username}',
|
||||||
|
)
|
||||||
|
config.states.add(self.member.profile.state)
|
||||||
|
formatter = NameFormatter(ExampleService(), self.member)
|
||||||
|
|
||||||
|
result = formatter.format_name()
|
||||||
|
|
||||||
|
self.assertEqual('1234 test auth_member', result)
|
@ -9,4 +9,5 @@
|
|||||||
corpstats
|
corpstats
|
||||||
groups
|
groups
|
||||||
permissions_tool
|
permissions_tool
|
||||||
|
nameformats
|
||||||
```
|
```
|
||||||
|
84
docs/features/nameformats.md
Normal file
84
docs/features/nameformats.md
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# Services Name Formats
|
||||||
|
|
||||||
|
```eval_rst
|
||||||
|
.. note::
|
||||||
|
New in 2.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Each service's username or nickname, depending on which the service supports, can be customised through the use of the Name Formatter Config provided the service supports custom formats. This config can be found in the admin panel under **Services -> Name format config**
|
||||||
|
|
||||||
|
Currently the following services support custom name formats:
|
||||||
|
|
||||||
|
```eval_rst
|
||||||
|
+-------------+-----------+-------------------------------------+
|
||||||
|
| Service | Used with | Default Formatter |
|
||||||
|
+=============+===========+=====================================+
|
||||||
|
| Discord | Nickname | ``{character_name}`` |
|
||||||
|
+-------------+-----------+-------------------------------------+
|
||||||
|
| Discourse | Username | ``{character_name}`` |
|
||||||
|
+-------------+-----------+-------------------------------------+
|
||||||
|
| IPS4 | Username | ``{character_name}`` |
|
||||||
|
+-------------+-----------+-------------------------------------+
|
||||||
|
| Mumble | Username | ``[{corp_ticker}]{character_name}`` |
|
||||||
|
+-------------+-----------+-------------------------------------+
|
||||||
|
| Openfire | Username | ``{character_name}`` |
|
||||||
|
+-------------+-----------+-------------------------------------+
|
||||||
|
| phpBB3 | Username | ``{character_name}`` |
|
||||||
|
+-------------+-----------+-------------------------------------+
|
||||||
|
| SeAT | Username | ``{character_name}`` |
|
||||||
|
+-------------+-----------+-------------------------------------+
|
||||||
|
| SMF | Username | ``{character_name}`` |
|
||||||
|
+-------------+-----------+-------------------------------------+
|
||||||
|
| Teamspeak 3 | Nickname | ``[{corp_ticker}]{character_name}`` |
|
||||||
|
+-------------+-----------+-------------------------------------+
|
||||||
|
| Xenforo | Username | ``{character_name}`` |
|
||||||
|
+-------------+-----------+-------------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
```eval_rst
|
||||||
|
.. note::
|
||||||
|
It's important to note here, before we get into what you can do with a name formatter, that before the generated name is passed off to the service to create an account it will be sanitised to remove characters (the letters and numbers etc) that the service cannot support. This means that, despite what you configured, the service may display something different. It is up to you to test your formatter and understand how your format may be disrupted by a certain services sanitisation function.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Available format data
|
||||||
|
|
||||||
|
The following fields are available from a users account and main character:
|
||||||
|
|
||||||
|
- `username` - Alliance Auth username
|
||||||
|
- `character_id`
|
||||||
|
- `character_name`
|
||||||
|
- `corp_id`
|
||||||
|
- `corp_name`
|
||||||
|
- `corp_ticker`
|
||||||
|
- `alliance_id`
|
||||||
|
- `alliance_name`
|
||||||
|
- `alliance_ticker`
|
||||||
|
|
||||||
|
## Building a formatter string
|
||||||
|
|
||||||
|
The name formatter uses the advanced string formatting specified by [PEP-3101](https://www.python.org/dev/peps/pep-3101/). Anything supported by this specification is supported in a name formatter.
|
||||||
|
|
||||||
|
A more digestable documentation of string formatting in Python is available on the [PyFormat](https://pyformat.info/) website.
|
||||||
|
|
||||||
|
Some examples of strings you could use:
|
||||||
|
```eval_rst
|
||||||
|
+------------------------------------------+---------------------------+
|
||||||
|
| Formatter | Result |
|
||||||
|
+==========================================+===========================+
|
||||||
|
| ``{alliance_ticker} - {character_name}`` | ``MYALLI - My Character`` |
|
||||||
|
+------------------------------------------+---------------------------+
|
||||||
|
| ``[{corp_ticker}] {character_name}`` | ``[CORP] My Character`` |
|
||||||
|
+------------------------------------------+---------------------------+
|
||||||
|
| ``{{{corp_name}}}{character_name}`` | ``{My Corp}My Character`` |
|
||||||
|
+------------------------------------------+---------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
```eval_rst
|
||||||
|
.. important::
|
||||||
|
For most services, name formats only take effect when a user creates an account. This means if you create or update a name formatter it wont retroactively alter the format of users names. There are some exceptions to this where the service updates nicknames on a periodic basis. Check the service's documentation to see which of these apply.
|
||||||
|
```
|
||||||
|
|
||||||
|
```eval_rst
|
||||||
|
.. important::
|
||||||
|
You must only create one formatter per service per state. E.g. don't create two formatters for Mumble for the Member state. In this case one of the formatters will be used and it may not be the formatter you are expecting.
|
||||||
|
```
|
Loading…
x
Reference in New Issue
Block a user