mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-09 20:40:17 +02:00
Merge branch 'services-deprecation' into 'master'
Deprecate Market and Seat service See merge request allianceauth/allianceauth!1168
This commit is contained in:
commit
148916d35e
@ -1443,56 +1443,6 @@ msgstr "Ping Enviado"
|
|||||||
msgid "Broadcast"
|
msgid "Broadcast"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/services/modules/seat/views.py:40
|
|
||||||
#, python-format
|
|
||||||
msgid "Successfully activated your %(service)s account."
|
|
||||||
msgstr "Se activo con exito el %(service)s en tu cuenta."
|
|
||||||
|
|
||||||
#: allianceauth/services/modules/seat/views.py:49
|
|
||||||
#, python-format
|
|
||||||
msgid ""
|
|
||||||
"Failed to activate your %(service)s account, please contact your "
|
|
||||||
"administrator."
|
|
||||||
msgstr "Fallo al activar el %(service)s en tu cuenta, por favor contacta a tu administrador."
|
|
||||||
|
|
||||||
#: allianceauth/services/modules/seat/views.py:62
|
|
||||||
#, python-format
|
|
||||||
msgid "Successfully deactivated your %(service)s account."
|
|
||||||
msgstr "Se desactivo el servicio %(service)s con exito."
|
|
||||||
|
|
||||||
#: allianceauth/services/modules/seat/views.py:68
|
|
||||||
#, python-format
|
|
||||||
msgid ""
|
|
||||||
"Failed to deactivate your %(service)s account, please contact your "
|
|
||||||
"administrator."
|
|
||||||
msgstr "Fallo al desactivar el servicio %(service)s, por favor contacta a tu administrador."
|
|
||||||
|
|
||||||
#: allianceauth/services/modules/seat/views.py:87
|
|
||||||
#, python-format
|
|
||||||
msgid "Successfully reset your %(service)s password."
|
|
||||||
msgstr "Se restablecio con exito tu contraseña del servicio %(service)s."
|
|
||||||
|
|
||||||
#: allianceauth/services/modules/seat/views.py:93
|
|
||||||
#, python-format
|
|
||||||
msgid ""
|
|
||||||
"Failed to reset your %(service)s password, please contact your administrator."
|
|
||||||
msgstr "Fallo al restablecer tu contraseña en el servicio %(service)s, por favor contacta a tu adminsitrador."
|
|
||||||
|
|
||||||
#: allianceauth/services/modules/seat/views.py:114
|
|
||||||
#, python-format
|
|
||||||
msgid "Successfully set your %(service)s password."
|
|
||||||
msgstr "Se cambio con exito tu contraseña en el servicio %(service)s"
|
|
||||||
|
|
||||||
#: allianceauth/services/modules/seat/views.py:119
|
|
||||||
#, python-format
|
|
||||||
msgid ""
|
|
||||||
"Failed to set your %(service)s password, please contact your administrator."
|
|
||||||
msgstr "Fallo al cambiar tu contraseña en %(service)s, por favor contacta a tu administrador."
|
|
||||||
|
|
||||||
#: allianceauth/services/modules/seat/views.py:123
|
|
||||||
msgid "Invalid password."
|
|
||||||
msgstr "Contraseña invalida."
|
|
||||||
|
|
||||||
#: allianceauth/services/modules/teamspeak3/forms.py:14
|
#: allianceauth/services/modules/teamspeak3/forms.py:14
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Unable to locate user %s on server"
|
msgid "Unable to locate user %s on server"
|
||||||
|
@ -1 +0,0 @@
|
|||||||
default_app_config = 'allianceauth.services.modules.market.apps.MarketServiceConfig'
|
|
@ -1,9 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
from .models import MarketUser
|
|
||||||
|
|
||||||
|
|
||||||
class MarketUserAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('user', 'username')
|
|
||||||
search_fields = ('user__username', 'username')
|
|
||||||
|
|
||||||
admin.site.register(MarketUser, MarketUserAdmin)
|
|
@ -1,6 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class MarketServiceConfig(AppConfig):
|
|
||||||
name = 'allianceauth.services.modules.market'
|
|
||||||
label = 'market'
|
|
@ -1,54 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.template.loader import render_to_string
|
|
||||||
|
|
||||||
from allianceauth import hooks
|
|
||||||
from allianceauth.services.hooks import ServicesHook
|
|
||||||
from .tasks import MarketTasks
|
|
||||||
from .urls import urlpatterns
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class MarketService(ServicesHook):
|
|
||||||
def __init__(self):
|
|
||||||
ServicesHook.__init__(self)
|
|
||||||
self.name = 'market'
|
|
||||||
self.urlpatterns = urlpatterns
|
|
||||||
self.service_url = settings.MARKET_URL
|
|
||||||
self.access_perm = 'market.access_market'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def title(self):
|
|
||||||
return "Alliance Market"
|
|
||||||
|
|
||||||
def delete_user(self, user, notify_user=False):
|
|
||||||
logger.debug('Deleting user %s %s account' % (user, self.name))
|
|
||||||
return MarketTasks.delete_user(user, notify_user=notify_user)
|
|
||||||
|
|
||||||
def validate_user(self, user):
|
|
||||||
logger.debug('Validating user %s %s account' % (user, self.name))
|
|
||||||
if MarketTasks.has_account(user) and not self.service_active_for_user(user):
|
|
||||||
self.delete_user(user)
|
|
||||||
|
|
||||||
def service_active_for_user(self, user):
|
|
||||||
return user.has_perm(self.access_perm)
|
|
||||||
|
|
||||||
def render_services_ctrl(self, request):
|
|
||||||
urls = self.Urls()
|
|
||||||
urls.auth_activate = 'evernusmarket:activate'
|
|
||||||
urls.auth_deactivate = 'evernusmarket:deactivate'
|
|
||||||
urls.auth_reset_password = 'evernusmarket:reset_password'
|
|
||||||
urls.auth_set_password = 'evernusmarket:set_password'
|
|
||||||
return render_to_string(self.service_ctrl_template, {
|
|
||||||
'service_name': self.title,
|
|
||||||
'urls': urls,
|
|
||||||
'service_url': self.service_url,
|
|
||||||
'username': request.user.market.username if MarketTasks.has_account(request.user) else ''
|
|
||||||
}, request=request)
|
|
||||||
|
|
||||||
|
|
||||||
@hooks.register('services_hook')
|
|
||||||
def register_service():
|
|
||||||
return MarketService()
|
|
@ -1,152 +0,0 @@
|
|||||||
import logging
|
|
||||||
import random
|
|
||||||
import string
|
|
||||||
import re
|
|
||||||
|
|
||||||
from django.db import connections
|
|
||||||
from passlib.hash import bcrypt
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
# requires yum install libffi-devel and pip install bcrypt
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
TABLE_PREFIX = getattr(settings, 'MARKET_TABLE_PREFIX', 'fos_')
|
|
||||||
|
|
||||||
|
|
||||||
class MarketManager:
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
SQL_ADD_USER = r"INSERT INTO %suser (username, username_canonical, email, email_canonical, enabled, salt," \
|
|
||||||
r"password, locked, expired, roles, credentials_expired, characterid, characterName)" \
|
|
||||||
r"VALUES (%%s, %%s, %%s, %%s, 1,%%s, %%s, 0, 0, 'a:0:{}', 0, %%s, %%s) " % TABLE_PREFIX
|
|
||||||
SQL_GET_USER_ID = r"SELECT id FROM %suser WHERE username = %%s" % TABLE_PREFIX
|
|
||||||
SQL_DISABLE_USER = r"UPDATE %suser SET enabled = '0' WHERE username = %%s" % TABLE_PREFIX
|
|
||||||
SQL_ENABLE_USER = r"UPDATE %suser SET enabled = '1' WHERE username = %%s" % TABLE_PREFIX
|
|
||||||
SQL_UPDATE_PASSWORD = r"UPDATE %suser SET password = %%s, salt = %%s WHERE username = %%s" % TABLE_PREFIX
|
|
||||||
SQL_CHECK_EMAIL = r"SELECT email FROM %suser WHERE email = %%s" % TABLE_PREFIX
|
|
||||||
SQL_CHECK_USERNAME = r"SELECT username FROM %suser WHERE username = %%s" % TABLE_PREFIX
|
|
||||||
SQL_UPDATE_USER = r"UPDATE %suser SET password = %%s, salt = %%s, enabled = '1' WHERE username = %%s" % TABLE_PREFIX
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __santatize_username(username):
|
|
||||||
sanatized = username.replace(" ", "_")
|
|
||||||
return sanatized.lower()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __generate_random_pass():
|
|
||||||
return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(16)])
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _gen_pwhash(password):
|
|
||||||
return bcrypt.using(ident='2y').encrypt(password.encode('utf-8'), rounds=13)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_salt(pw_hash):
|
|
||||||
search = re.compile(r"^\$2[a-z]?\$([0-9]+)\$(.{22})(.{31})$")
|
|
||||||
match = re.match(search, pw_hash)
|
|
||||||
return match.group(2)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def check_username(cls, username):
|
|
||||||
logger.debug("Checking alliance market username %s" % username)
|
|
||||||
cursor = connections['market'].cursor()
|
|
||||||
cursor.execute(cls.SQL_CHECK_USERNAME, [cls.__santatize_username(username)])
|
|
||||||
row = cursor.fetchone()
|
|
||||||
if row:
|
|
||||||
logger.debug("Found user %s on alliance market" % username)
|
|
||||||
return True
|
|
||||||
logger.debug("User %s not found on alliance market" % username)
|
|
||||||
return False
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def check_user_email(cls, username, email):
|
|
||||||
logger.debug("Checking if alliance market email exists for user %s" % username)
|
|
||||||
cursor = connections['market'].cursor()
|
|
||||||
cursor.execute(cls.SQL_CHECK_EMAIL, [email])
|
|
||||||
row = cursor.fetchone()
|
|
||||||
if row:
|
|
||||||
logger.debug("Found user %s email address on alliance market" % username)
|
|
||||||
return True
|
|
||||||
logger.debug("User %s email address not found on alliance market" % username)
|
|
||||||
return False
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def add_user(cls, username, email, characterid, charactername):
|
|
||||||
logger.debug("Adding new market user %s" % username)
|
|
||||||
plain_password = cls.__generate_random_pass()
|
|
||||||
hash = cls._gen_pwhash(plain_password)
|
|
||||||
salt = cls._get_salt(hash)
|
|
||||||
username_clean = cls.__santatize_username(username)
|
|
||||||
if not cls.check_username(username):
|
|
||||||
if not cls.check_user_email(username, email):
|
|
||||||
try:
|
|
||||||
logger.debug("Adding user %s to alliance market" % username)
|
|
||||||
cursor = connections['market'].cursor()
|
|
||||||
cursor.execute(cls.SQL_ADD_USER, [username_clean, username_clean, email, email, salt,
|
|
||||||
hash, characterid, charactername])
|
|
||||||
return username_clean, plain_password
|
|
||||||
except:
|
|
||||||
logger.debug("Unsuccessful attempt to add market user %s" % username)
|
|
||||||
return "", ""
|
|
||||||
else:
|
|
||||||
logger.debug("Alliance market email %s already exists Updating instead" % email)
|
|
||||||
username_clean, password = cls.update_user_info(username)
|
|
||||||
return username_clean, password
|
|
||||||
else:
|
|
||||||
logger.debug("Alliance market username %s already exists Updating instead" % username)
|
|
||||||
username_clean, password = cls.update_user_info(username)
|
|
||||||
return username_clean, password
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def disable_user(cls, username):
|
|
||||||
logger.debug("Disabling alliance market user %s " % username)
|
|
||||||
cursor = connections['market'].cursor()
|
|
||||||
cursor.execute(cls.SQL_DISABLE_USER, [username])
|
|
||||||
return True
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def update_custom_password(cls, username, plain_password):
|
|
||||||
logger.debug("Updating alliance market user %s password" % username)
|
|
||||||
if cls.check_username(username):
|
|
||||||
username_clean = cls.__santatize_username(username)
|
|
||||||
hash = cls._gen_pwhash(plain_password)
|
|
||||||
salt = cls._get_salt(hash)
|
|
||||||
cursor = connections['market'].cursor()
|
|
||||||
cursor.execute(cls.SQL_UPDATE_PASSWORD, [hash, salt, username_clean])
|
|
||||||
return plain_password
|
|
||||||
else:
|
|
||||||
logger.error("Unable to update alliance market user %s password" % username)
|
|
||||||
return ""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def update_user_password(cls, username):
|
|
||||||
logger.debug("Updating alliance market user %s password" % username)
|
|
||||||
if cls.check_username(username):
|
|
||||||
username_clean = cls.__santatize_username(username)
|
|
||||||
plain_password = cls.__generate_random_pass()
|
|
||||||
hash = cls._gen_pwhash(plain_password)
|
|
||||||
salt = cls._get_salt(hash)
|
|
||||||
cursor = connections['market'].cursor()
|
|
||||||
cursor.execute(cls.SQL_UPDATE_PASSWORD, [hash, salt, username_clean])
|
|
||||||
return plain_password
|
|
||||||
else:
|
|
||||||
logger.error("Unable to update alliance market user %s password" % username)
|
|
||||||
return ""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def update_user_info(cls, username):
|
|
||||||
logger.debug("Updating alliance market user %s" % username)
|
|
||||||
try:
|
|
||||||
username_clean = cls.__santatize_username(username)
|
|
||||||
plain_password = cls.__generate_random_pass()
|
|
||||||
hash = cls._gen_pwhash(plain_password)
|
|
||||||
salt = cls._get_salt(hash)
|
|
||||||
cursor = connections['market'].cursor()
|
|
||||||
cursor.execute(cls.SQL_UPDATE_USER, [hash, salt, username_clean])
|
|
||||||
return username_clean, plain_password
|
|
||||||
except:
|
|
||||||
logger.debug("Alliance market update user failed for %s" % username)
|
|
||||||
return "", ""
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.2 on 2016-12-12 03:27
|
|
||||||
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'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='MarketUser',
|
|
||||||
fields=[
|
|
||||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='market', serialize=False, to=settings.AUTH_USER_MODEL)),
|
|
||||||
('username', models.CharField(max_length=254)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,61 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.5 on 2017-02-02 05:59
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
from django.conf import settings
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
from django.contrib.auth.management import create_permissions
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def migrate_service_enabled(apps, schema_editor):
|
|
||||||
for app_config in apps.get_app_configs():
|
|
||||||
app_config.models_module = True
|
|
||||||
create_permissions(app_config, apps=apps, verbosity=0)
|
|
||||||
app_config.models_module = None
|
|
||||||
|
|
||||||
Group = apps.get_model("auth", "Group")
|
|
||||||
Permission = apps.get_model("auth", "Permission")
|
|
||||||
MarketUser = apps.get_model("market", "MarketUser")
|
|
||||||
|
|
||||||
perm = Permission.objects.get(codename='access_market')
|
|
||||||
|
|
||||||
member_group_name = getattr(settings, str('DEFAULT_AUTH_GROUP'), 'Member')
|
|
||||||
blue_group_name = getattr(settings, str('DEFAULT_BLUE_GROUP'), 'Blue')
|
|
||||||
|
|
||||||
# Migrate members
|
|
||||||
if MarketUser.objects.filter(user__groups__name=member_group_name).exists() or \
|
|
||||||
getattr(settings, str('ENABLE_AUTH_MARKET'), False):
|
|
||||||
try:
|
|
||||||
group = Group.objects.get(name=member_group_name)
|
|
||||||
group.permissions.add(perm)
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
logger.warning('Failed to migrate ENABLE_AUTH_MARKET setting')
|
|
||||||
|
|
||||||
# Migrate blues
|
|
||||||
if MarketUser.objects.filter(user__groups__name=blue_group_name).exists() or \
|
|
||||||
getattr(settings, str('ENABLE_BLUE_MARKET'), False):
|
|
||||||
try:
|
|
||||||
group = Group.objects.get(name=blue_group_name)
|
|
||||||
group.permissions.add(perm)
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
logger.warning('Failed to migrate ENABLE_BLUE_MARKET setting')
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('market', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='marketuser',
|
|
||||||
options={'permissions': (('access_market', 'Can access the Evernus Market service'),)},
|
|
||||||
),
|
|
||||||
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
|
||||||
]
|
|
@ -1,18 +0,0 @@
|
|||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
|
|
||||||
class MarketUser(models.Model):
|
|
||||||
user = models.OneToOneField(User,
|
|
||||||
primary_key=True,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='market')
|
|
||||||
username = models.CharField(max_length=254)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.username
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
permissions = (
|
|
||||||
("access_market", u"Can access the Evernus Market service"),
|
|
||||||
)
|
|
@ -1,36 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
|
|
||||||
from allianceauth.notifications import notify
|
|
||||||
from .manager import MarketManager
|
|
||||||
from .models import MarketUser
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class MarketTasks:
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def delete_user(cls, user, notify_user=False):
|
|
||||||
if cls.has_account(user):
|
|
||||||
logger.debug("User %s has a Market account %s. Deleting." % (user, user.market.username))
|
|
||||||
if MarketManager.disable_user(user.market.username):
|
|
||||||
user.market.delete()
|
|
||||||
if notify_user:
|
|
||||||
notify(user, 'Alliance Market Account Disabled', level='danger')
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def has_account(user):
|
|
||||||
try:
|
|
||||||
return user.market.username != ''
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def disable():
|
|
||||||
MarketUser.objects.all().delete()
|
|
@ -1,183 +0,0 @@
|
|||||||
from unittest import mock
|
|
||||||
|
|
||||||
from django.test import TestCase, RequestFactory
|
|
||||||
from django import urls
|
|
||||||
from django.contrib.auth.models import User, Group, Permission
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
|
|
||||||
from allianceauth.tests.auth_utils import AuthUtils
|
|
||||||
|
|
||||||
from .auth_hooks import MarketService
|
|
||||||
from .models import MarketUser
|
|
||||||
from .tasks import MarketTasks
|
|
||||||
|
|
||||||
MODULE_PATH = 'allianceauth.services.modules.market'
|
|
||||||
DEFAULT_AUTH_GROUP = 'Member'
|
|
||||||
|
|
||||||
|
|
||||||
def add_permissions():
|
|
||||||
permission = Permission.objects.get(codename='access_market')
|
|
||||||
members = Group.objects.get_or_create(name=DEFAULT_AUTH_GROUP)[0]
|
|
||||||
AuthUtils.add_permissions_to_groups([permission], [members])
|
|
||||||
|
|
||||||
|
|
||||||
class MarketHooksTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.member = 'member_user'
|
|
||||||
member = AuthUtils.create_member(self.member)
|
|
||||||
MarketUser.objects.create(user=member, username=self.member)
|
|
||||||
self.none_user = 'none_user'
|
|
||||||
none_user = AuthUtils.create_user(self.none_user)
|
|
||||||
self.service = MarketService
|
|
||||||
add_permissions()
|
|
||||||
|
|
||||||
def test_has_account(self):
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
none_user = User.objects.get(username=self.none_user)
|
|
||||||
self.assertTrue(MarketTasks.has_account(member))
|
|
||||||
self.assertFalse(MarketTasks.has_account(none_user))
|
|
||||||
|
|
||||||
def test_service_enabled(self):
|
|
||||||
service = self.service()
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
none_user = User.objects.get(username=self.none_user)
|
|
||||||
|
|
||||||
self.assertTrue(service.service_active_for_user(member))
|
|
||||||
self.assertFalse(service.service_active_for_user(none_user))
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.tasks.MarketManager')
|
|
||||||
def test_delete_user(self, manager):
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
|
|
||||||
service = self.service()
|
|
||||||
result = service.delete_user(member)
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
self.assertTrue(manager.disable_user.called)
|
|
||||||
with self.assertRaises(ObjectDoesNotExist):
|
|
||||||
market_user = User.objects.get(username=self.member).market
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.tasks.MarketManager')
|
|
||||||
def test_validate_user(self, manager):
|
|
||||||
service = self.service()
|
|
||||||
# Test member is not deleted
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
service.validate_user(member)
|
|
||||||
self.assertTrue(User.objects.get(username=self.member).market)
|
|
||||||
|
|
||||||
# Test none user is deleted
|
|
||||||
none_user = User.objects.get(username=self.none_user)
|
|
||||||
MarketUser.objects.create(user=none_user, username='abc123')
|
|
||||||
service.validate_user(none_user)
|
|
||||||
self.assertTrue(manager.disable_user.called)
|
|
||||||
with self.assertRaises(ObjectDoesNotExist):
|
|
||||||
none_svc = User.objects.get(username=self.none_user).market
|
|
||||||
|
|
||||||
def test_render_services_ctrl(self):
|
|
||||||
service = self.service()
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
request = RequestFactory().get('/services/')
|
|
||||||
request.user = member
|
|
||||||
|
|
||||||
response = service.render_services_ctrl(request)
|
|
||||||
self.assertTemplateUsed(service.service_ctrl_template)
|
|
||||||
self.assertIn(urls.reverse('evernusmarket:set_password'), response)
|
|
||||||
self.assertIn(urls.reverse('evernusmarket:reset_password'), response)
|
|
||||||
self.assertIn(urls.reverse('evernusmarket:deactivate'), response)
|
|
||||||
|
|
||||||
# Test register becomes available
|
|
||||||
member.market.delete()
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
request.user = member
|
|
||||||
response = service.render_services_ctrl(request)
|
|
||||||
self.assertIn(urls.reverse('evernusmarket:activate'), response)
|
|
||||||
|
|
||||||
|
|
||||||
class MarketViewsTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.member = AuthUtils.create_member('auth_member')
|
|
||||||
self.member.email = 'auth_member@example.com'
|
|
||||||
self.member.save()
|
|
||||||
AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation')
|
|
||||||
add_permissions()
|
|
||||||
|
|
||||||
def login(self):
|
|
||||||
self.client.force_login(self.member)
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.views.MarketManager')
|
|
||||||
def test_activate(self, manager):
|
|
||||||
self.login()
|
|
||||||
expected_username = 'auth_member'
|
|
||||||
expected_password = 'password'
|
|
||||||
expected_id = '1234'
|
|
||||||
|
|
||||||
manager.add_user.return_value = (expected_username, expected_password, expected_id)
|
|
||||||
|
|
||||||
response = self.client.get(urls.reverse('evernusmarket:activate'), follow=False)
|
|
||||||
|
|
||||||
self.assertTrue(manager.add_user.called)
|
|
||||||
args, kwargs = manager.add_user.call_args
|
|
||||||
self.assertEqual(args[0], expected_username)
|
|
||||||
self.assertEqual(args[1], self.member.email)
|
|
||||||
|
|
||||||
self.assertTemplateUsed(response, 'services/service_credentials.html')
|
|
||||||
self.assertContains(response, expected_username)
|
|
||||||
self.assertContains(response, expected_password)
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.tasks.MarketManager')
|
|
||||||
def test_deactivate(self, manager):
|
|
||||||
self.login()
|
|
||||||
MarketUser.objects.create(user=self.member, username='12345')
|
|
||||||
manager.disable_user.return_value = True
|
|
||||||
|
|
||||||
response = self.client.get(urls.reverse('evernusmarket:deactivate'))
|
|
||||||
|
|
||||||
self.assertTrue(manager.disable_user.called)
|
|
||||||
self.assertRedirects(response, expected_url=urls.reverse('services:services'), target_status_code=200)
|
|
||||||
with self.assertRaises(ObjectDoesNotExist):
|
|
||||||
market_user = User.objects.get(pk=self.member.pk).market
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.views.MarketManager')
|
|
||||||
def test_set_password(self, manager):
|
|
||||||
self.login()
|
|
||||||
MarketUser.objects.create(user=self.member, username='12345')
|
|
||||||
expected_password = 'password'
|
|
||||||
manager.update_user_password.return_value = expected_password
|
|
||||||
|
|
||||||
response = self.client.post(urls.reverse('evernusmarket:set_password'), data={'password': expected_password})
|
|
||||||
|
|
||||||
self.assertTrue(manager.update_custom_password.called)
|
|
||||||
args, kwargs = manager.update_custom_password.call_args
|
|
||||||
self.assertEqual(args[1], expected_password)
|
|
||||||
self.assertRedirects(response, expected_url=urls.reverse('services:services'), target_status_code=200)
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.views.MarketManager')
|
|
||||||
def test_reset_password(self, manager):
|
|
||||||
self.login()
|
|
||||||
MarketUser.objects.create(user=self.member, username='12345')
|
|
||||||
|
|
||||||
response = self.client.get(urls.reverse('evernusmarket:reset_password'))
|
|
||||||
|
|
||||||
self.assertTrue(manager.update_user_password.called)
|
|
||||||
self.assertTemplateUsed(response, 'services/service_credentials.html')
|
|
||||||
|
|
||||||
|
|
||||||
class MarketManagerTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
from .manager import MarketManager
|
|
||||||
self.manager = MarketManager
|
|
||||||
|
|
||||||
def test_generate_random_password(self):
|
|
||||||
password = self.manager._MarketManager__generate_random_pass()
|
|
||||||
|
|
||||||
self.assertEqual(len(password), 16)
|
|
||||||
self.assertIsInstance(password, type(''))
|
|
||||||
|
|
||||||
def test_gen_pwhash(self):
|
|
||||||
pwhash = self.manager._gen_pwhash('test')
|
|
||||||
salt = self.manager._get_salt(pwhash)
|
|
||||||
|
|
||||||
self.assertIsInstance(pwhash, str)
|
|
||||||
self.assertGreaterEqual(len(pwhash), 59)
|
|
||||||
self.assertIsInstance(salt, str)
|
|
||||||
self.assertEqual(len(salt), 22)
|
|
@ -1,17 +0,0 @@
|
|||||||
from django.conf.urls import url, include
|
|
||||||
|
|
||||||
from . import views
|
|
||||||
|
|
||||||
app_name = 'evernusmarket'
|
|
||||||
|
|
||||||
module_urls = [
|
|
||||||
# Alliance Market Control
|
|
||||||
url(r'^activate/$', views.activate_market, name='activate'),
|
|
||||||
url(r'^deactivate/$', views.deactivate_market, name='deactivate'),
|
|
||||||
url(r'^reset_password/$', views.reset_market_password, name='reset_password'),
|
|
||||||
url(r'^set_password/$', views.set_market_password, name='set_password'),
|
|
||||||
]
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^evernus-market/', include((module_urls, app_name), namespace=app_name))
|
|
||||||
]
|
|
@ -1,104 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
|
||||||
from django.shortcuts import render, redirect
|
|
||||||
|
|
||||||
from allianceauth.services.forms import ServicePasswordForm
|
|
||||||
from .manager import MarketManager
|
|
||||||
from .models import MarketUser
|
|
||||||
from .tasks import MarketTasks
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
ACCESS_PERM = 'market.access_market'
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@permission_required(ACCESS_PERM)
|
|
||||||
def activate_market(request):
|
|
||||||
logger.debug("activate_market called by user %s" % request.user)
|
|
||||||
character = request.user.profile.main_character
|
|
||||||
if character is not None:
|
|
||||||
logger.debug("Adding market user for user %s with main character %s" % (request.user, character))
|
|
||||||
result = MarketManager.add_user(character.character_name, request.user.email, character.character_id,
|
|
||||||
character.character_name)
|
|
||||||
# if empty we failed
|
|
||||||
if result[0] != "":
|
|
||||||
MarketUser.objects.create(user=request.user, username=result[0])
|
|
||||||
logger.debug("Updated authserviceinfo for user %s with market credentials." % request.user)
|
|
||||||
logger.info("Successfully activated market for user %s" % request.user)
|
|
||||||
messages.success(request, 'Activated Alliance Market account.')
|
|
||||||
credentials = {
|
|
||||||
'username': result[0],
|
|
||||||
'password': result[1],
|
|
||||||
}
|
|
||||||
return render(request, 'services/service_credentials.html',
|
|
||||||
context={'credentials': credentials, 'service': 'Alliance Market'})
|
|
||||||
logger.error("Unsuccessful attempt to activate market for user %s" % request.user)
|
|
||||||
messages.error(request, 'An error occurred while processing your Alliance Market account.')
|
|
||||||
return redirect("services:services")
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@permission_required(ACCESS_PERM)
|
|
||||||
def deactivate_market(request):
|
|
||||||
logger.debug("deactivate_market called by user %s" % request.user)
|
|
||||||
# false we failed
|
|
||||||
if MarketTasks.delete_user(request.user):
|
|
||||||
logger.info("Successfully deactivated market for user %s" % request.user)
|
|
||||||
messages.success(request, 'Deactivated Alliance Market account.')
|
|
||||||
else:
|
|
||||||
logger.error("Unsuccessful attempt to activate market for user %s" % request.user)
|
|
||||||
messages.error(request, 'An error occurred while processing your Alliance Market account.')
|
|
||||||
return redirect("services:services")
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@permission_required(ACCESS_PERM)
|
|
||||||
def reset_market_password(request):
|
|
||||||
logger.debug("reset_market_password called by user %s" % request.user)
|
|
||||||
if MarketTasks.has_account(request.user):
|
|
||||||
result = MarketManager.update_user_password(request.user.market.username)
|
|
||||||
# false we failed
|
|
||||||
if result != "":
|
|
||||||
logger.info("Successfully reset market password for user %s" % request.user)
|
|
||||||
messages.success(request, 'Reset Alliance Market password.')
|
|
||||||
credentials = {
|
|
||||||
'username': request.user.market.username,
|
|
||||||
'password': result,
|
|
||||||
}
|
|
||||||
return render(request, 'services/service_credentials.html',
|
|
||||||
context={'credentials': credentials, 'service': 'Alliance Market'})
|
|
||||||
|
|
||||||
logger.error("Unsuccessful attempt to reset market password for user %s" % request.user)
|
|
||||||
messages.error(request, 'An error occurred while processing your Alliance Market account.')
|
|
||||||
return redirect("services:services")
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@permission_required(ACCESS_PERM)
|
|
||||||
def set_market_password(request):
|
|
||||||
logger.debug("set_market_password called by user %s" % request.user)
|
|
||||||
if request.method == 'POST':
|
|
||||||
logger.debug("Received POST request with form.")
|
|
||||||
form = ServicePasswordForm(request.POST)
|
|
||||||
logger.debug("Form is valid: %s" % form.is_valid())
|
|
||||||
if form.is_valid() and MarketTasks.has_account(request.user):
|
|
||||||
password = form.cleaned_data['password']
|
|
||||||
logger.debug("Form contains password of length %s" % len(password))
|
|
||||||
result = MarketManager.update_custom_password(request.user.market.username, password)
|
|
||||||
if result != "":
|
|
||||||
logger.info("Successfully reset market password for user %s" % request.user)
|
|
||||||
messages.success(request, 'Set Alliance Market password.')
|
|
||||||
else:
|
|
||||||
logger.error("Failed to install custom market password for user %s" % request.user)
|
|
||||||
messages.error(request, 'An error occurred while processing your Alliance Market account.')
|
|
||||||
return redirect("services:services")
|
|
||||||
else:
|
|
||||||
logger.debug("Request is not type POST - providing empty form.")
|
|
||||||
form = ServicePasswordForm()
|
|
||||||
|
|
||||||
logger.debug("Rendering form for user %s" % request.user)
|
|
||||||
context = {'form': form, 'service': 'Market'}
|
|
||||||
return render(request, 'services/service_password.html', context=context)
|
|
@ -1 +0,0 @@
|
|||||||
default_app_config = 'allianceauth.services.modules.seat.apps.SeatServiceConfig'
|
|
@ -1,9 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
from .models import SeatUser
|
|
||||||
|
|
||||||
|
|
||||||
class SeatUserAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('user', 'username')
|
|
||||||
search_fields = ('user__username', 'username')
|
|
||||||
|
|
||||||
admin.site.register(SeatUser, SeatUserAdmin)
|
|
@ -1,6 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class SeatServiceConfig(AppConfig):
|
|
||||||
name = 'allianceauth.services.modules.seat'
|
|
||||||
label = 'seat'
|
|
@ -1,64 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.template.loader import render_to_string
|
|
||||||
|
|
||||||
from allianceauth import hooks
|
|
||||||
from allianceauth.services.hooks import ServicesHook
|
|
||||||
from .tasks import SeatTasks
|
|
||||||
from .urls import urlpatterns
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class SeatService(ServicesHook):
|
|
||||||
def __init__(self):
|
|
||||||
ServicesHook.__init__(self)
|
|
||||||
self.urlpatterns = urlpatterns
|
|
||||||
self.name = 'seat'
|
|
||||||
self.service_url = settings.SEAT_URL
|
|
||||||
self.access_perm = 'seat.access_seat'
|
|
||||||
self.name_format = '{character_name}'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def title(self):
|
|
||||||
return "SeAT"
|
|
||||||
|
|
||||||
def delete_user(self, user, notify_user=False):
|
|
||||||
logger.debug('Deleting user %s %s account' % (user, self.name))
|
|
||||||
return SeatTasks.delete_user(user, notify_user=notify_user)
|
|
||||||
|
|
||||||
def validate_user(self, user):
|
|
||||||
logger.debug('Validating user %s %s account' % (user, self.name))
|
|
||||||
if SeatTasks.has_account(user) and not self.service_active_for_user(user):
|
|
||||||
self.delete_user(user)
|
|
||||||
|
|
||||||
def update_groups(self, user):
|
|
||||||
logger.debug("Updating %s groups for %s" % (self.name, user))
|
|
||||||
if SeatTasks.has_account(user):
|
|
||||||
SeatTasks.update_roles.delay(user.pk)
|
|
||||||
|
|
||||||
def update_all_groups(self):
|
|
||||||
logger.debug('Update all %s groups called' % self.name)
|
|
||||||
SeatTasks.update_all_roles.delay()
|
|
||||||
|
|
||||||
def service_active_for_user(self, user):
|
|
||||||
return user.has_perm(self.access_perm)
|
|
||||||
|
|
||||||
def render_services_ctrl(self, request):
|
|
||||||
urls = self.Urls()
|
|
||||||
urls.auth_activate = 'seat:activate'
|
|
||||||
urls.auth_deactivate = 'seat:deactivate'
|
|
||||||
urls.auth_reset_password = 'seat:reset_password'
|
|
||||||
urls.auth_set_password = 'seat:set_password'
|
|
||||||
return render_to_string(self.service_ctrl_template, {
|
|
||||||
'service_name': self.title,
|
|
||||||
'urls': urls,
|
|
||||||
'service_url': self.service_url,
|
|
||||||
'username': request.user.seat.username if SeatTasks.has_account(request.user) else ''
|
|
||||||
}, request=request)
|
|
||||||
|
|
||||||
|
|
||||||
@hooks.register('services_hook')
|
|
||||||
def register_service():
|
|
||||||
return SeatService()
|
|
@ -1,204 +0,0 @@
|
|||||||
import hashlib
|
|
||||||
import logging
|
|
||||||
import random
|
|
||||||
import string
|
|
||||||
|
|
||||||
import requests
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class SeatManager:
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
RESPONSE_OK = 'ok'
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __sanitize_username(username):
|
|
||||||
sanatized = username.replace(" ", "_")
|
|
||||||
return sanatized.lower()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __generate_random_pass():
|
|
||||||
return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(16)])
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _response_ok(cls, response):
|
|
||||||
return cls.RESPONSE_OK in response
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def exec_request(endpoint, func, raise_for_status=False, **kwargs):
|
|
||||||
""" Send an https api request """
|
|
||||||
try:
|
|
||||||
endpoint = '{0}/api/v1/{1}'.format(settings.SEAT_URL, endpoint)
|
|
||||||
headers = {'X-Token': settings.SEAT_XTOKEN, 'Accept': 'application/json'}
|
|
||||||
logger.debug(headers)
|
|
||||||
logger.debug(endpoint)
|
|
||||||
ret = getattr(requests, func)(endpoint, headers=headers, data=kwargs)
|
|
||||||
ret.raise_for_status()
|
|
||||||
return ret.json()
|
|
||||||
except requests.HTTPError as e:
|
|
||||||
if raise_for_status:
|
|
||||||
raise e
|
|
||||||
logger.exception("Error encountered while performing API request to SeAT with url {}".format(endpoint))
|
|
||||||
return {}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def add_user(cls, username, email):
|
|
||||||
""" Add user to service """
|
|
||||||
sanitized = str(cls.__sanitize_username(username))
|
|
||||||
logger.debug("Adding user to SeAT with username %s" % sanitized)
|
|
||||||
password = cls.__generate_random_pass()
|
|
||||||
ret = cls.exec_request('user', 'post', username=sanitized, email=str(email), password=password)
|
|
||||||
logger.debug(ret)
|
|
||||||
if cls._response_ok(ret):
|
|
||||||
logger.info("Added SeAT user with username %s" % sanitized)
|
|
||||||
return sanitized, password
|
|
||||||
logger.info("Failed to add SeAT user with username %s" % sanitized)
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def delete_user(cls, username):
|
|
||||||
""" Delete user """
|
|
||||||
ret = cls.exec_request('user/{}'.format(username), 'delete')
|
|
||||||
logger.debug(ret)
|
|
||||||
if cls._response_ok(ret):
|
|
||||||
logger.info("Deleted SeAT user with username %s" % username)
|
|
||||||
return username
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def enable_user(cls, username):
|
|
||||||
""" Enable user """
|
|
||||||
ret = cls.exec_request('user/{}'.format(username), 'put', account_status=1)
|
|
||||||
logger.debug(ret)
|
|
||||||
if cls._response_ok(ret):
|
|
||||||
logger.info("Enabled SeAT user with username %s" % username)
|
|
||||||
return username
|
|
||||||
logger.info("Failed to enabled SeAT user with username %s" % username)
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def disable_user(cls, username):
|
|
||||||
""" Disable user """
|
|
||||||
cls.update_roles(username, [])
|
|
||||||
ret = cls.exec_request('user/{}'.format(username), 'put', account_status=0)
|
|
||||||
logger.debug(ret)
|
|
||||||
if cls._response_ok(ret):
|
|
||||||
logger.info("Disabled SeAT user with username %s" % username)
|
|
||||||
return username
|
|
||||||
logger.info("Failed to disable SeAT user with username %s" % username)
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _check_email_changed(cls, username, email):
|
|
||||||
"""Compares email to one set on SeAT"""
|
|
||||||
ret = cls.exec_request('user/{}'.format(username), 'get', raise_for_status=True)
|
|
||||||
return ret['email'] != email
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def update_user(cls, username, email, password):
|
|
||||||
""" Edit user info """
|
|
||||||
if cls._check_email_changed(username, email):
|
|
||||||
# if we try to set the email to whatever it is already on SeAT, we get a HTTP422 error
|
|
||||||
logger.debug("Updating SeAT username %s with email %s and password" % (username, email))
|
|
||||||
ret = cls.exec_request('user/{}'.format(username), 'put', email=email)
|
|
||||||
logger.debug(ret)
|
|
||||||
if not cls._response_ok(ret):
|
|
||||||
logger.warn("Failed to update email for username {}".format(username))
|
|
||||||
ret = cls.exec_request('user/{}'.format(username), 'put', password=password)
|
|
||||||
logger.debug(ret)
|
|
||||||
if not cls._response_ok(ret):
|
|
||||||
logger.warn("Failed to update password for username {}".format(username))
|
|
||||||
return None
|
|
||||||
logger.info("Updated SeAT user with username %s" % username)
|
|
||||||
return username
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def update_user_password(cls, username, email, plain_password=None):
|
|
||||||
logger.debug("Settings new SeAT password for user %s" % username)
|
|
||||||
if not plain_password:
|
|
||||||
plain_password = cls.__generate_random_pass()
|
|
||||||
if cls.update_user(username, email, plain_password):
|
|
||||||
return plain_password
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def check_user_status(cls, username):
|
|
||||||
sanitized = str(cls.__sanitize_username(username))
|
|
||||||
logger.debug("Checking SeAT status for user %s" % sanitized)
|
|
||||||
ret = cls.exec_request('user/{}'.format(sanitized), 'get')
|
|
||||||
logger.debug(ret)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_all_seat_eveapis(cls):
|
|
||||||
seat_all_keys = cls.exec_request('key', 'get')
|
|
||||||
seat_keys = {}
|
|
||||||
for key in seat_all_keys:
|
|
||||||
try:
|
|
||||||
seat_keys[key["key_id"]] = key["user_id"]
|
|
||||||
except KeyError:
|
|
||||||
seat_keys[key["key_id"]] = None
|
|
||||||
return seat_keys
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_all_roles(cls):
|
|
||||||
groups = {}
|
|
||||||
ret = cls.exec_request('role', 'get')
|
|
||||||
logger.debug(ret)
|
|
||||||
for group in ret:
|
|
||||||
groups[group["title"]] = group["id"]
|
|
||||||
logger.debug("Retrieved role list from SeAT: %s" % str(groups))
|
|
||||||
return groups
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def add_role(cls, role):
|
|
||||||
ret = cls.exec_request('role/new', 'post', name=role)
|
|
||||||
logger.debug(ret)
|
|
||||||
logger.info("Added Seat group %s" % role)
|
|
||||||
role_info = cls.exec_request('role/detail/{}'.format(role), 'get')
|
|
||||||
logger.debug(role_info)
|
|
||||||
return role_info["id"]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def add_role_to_user(cls, user_id, role_id):
|
|
||||||
ret = cls.exec_request('role/grant-user-role/{}/{}'.format(user_id, role_id), 'get')
|
|
||||||
logger.info("Added role %s to user %s" % (role_id, user_id))
|
|
||||||
return ret
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def revoke_role_from_user(cls, user_id, role_id):
|
|
||||||
ret = cls.exec_request('role/revoke-user-role/{}/{}'.format(user_id, role_id), 'get')
|
|
||||||
logger.info("Revoked role %s from user %s" % (role_id, user_id))
|
|
||||||
return ret
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def update_roles(cls, seat_user, roles):
|
|
||||||
logger.debug("Updating SeAT user %s with roles %s" % (seat_user, roles))
|
|
||||||
user_info = cls.check_user_status(seat_user)
|
|
||||||
user_roles = {}
|
|
||||||
if type(user_info["roles"]) is list:
|
|
||||||
for role in user_info["roles"]:
|
|
||||||
user_roles[role["title"]] = role["id"]
|
|
||||||
logger.debug("Got user %s SeAT roles %s" % (seat_user, user_roles))
|
|
||||||
seat_roles = cls.get_all_roles()
|
|
||||||
addroles = set(roles) - set(user_roles.keys())
|
|
||||||
remroles = set(user_roles.keys()) - set(roles)
|
|
||||||
|
|
||||||
logger.info("Updating SeAT roles for user %s - adding %s, removing %s" % (seat_user, addroles, remroles))
|
|
||||||
for r in addroles:
|
|
||||||
if r not in seat_roles:
|
|
||||||
seat_roles[r] = cls.add_role(r)
|
|
||||||
logger.debug("Adding role %s to SeAT user %s" % (r, seat_user))
|
|
||||||
cls.add_role_to_user(user_info["id"], seat_roles[r])
|
|
||||||
for r in remroles:
|
|
||||||
logger.debug("Removing role %s from user %s" % (r, seat_user))
|
|
||||||
cls.revoke_role_from_user(user_info["id"], seat_roles[r])
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def username_hash(username):
|
|
||||||
m = hashlib.sha1()
|
|
||||||
m.update(username.encode('utf-8'))
|
|
||||||
return m.hexdigest()
|
|
@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.4 on 2017-01-15 07:06
|
|
||||||
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'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='SeatUser',
|
|
||||||
fields=[
|
|
||||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='seat', serialize=False, to=settings.AUTH_USER_MODEL)),
|
|
||||||
('username', models.CharField(max_length=254)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,19 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.5 on 2017-02-02 10:49
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('seat', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='seatuser',
|
|
||||||
options={'permissions': (('access_seat', 'Can access the SeAT service'),)},
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,18 +0,0 @@
|
|||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
|
|
||||||
class SeatUser(models.Model):
|
|
||||||
user = models.OneToOneField(User,
|
|
||||||
primary_key=True,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='seat')
|
|
||||||
username = models.CharField(max_length=254)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.username
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
permissions = (
|
|
||||||
("access_seat", u"Can access the SeAT service"),
|
|
||||||
)
|
|
@ -1,69 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
from celery import shared_task
|
|
||||||
from allianceauth.services.tasks import QueueOnce
|
|
||||||
from allianceauth.notifications import notify
|
|
||||||
from allianceauth.services.hooks import NameFormatter
|
|
||||||
from .manager import SeatManager
|
|
||||||
from .models import SeatUser
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class SeatTasks:
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def has_account(user):
|
|
||||||
try:
|
|
||||||
return user.seat.username != ''
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
return False
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def delete_user(cls, user, notify_user=False):
|
|
||||||
if cls.has_account(user) and SeatManager.disable_user(user.seat.username):
|
|
||||||
user.seat.delete()
|
|
||||||
logger.info("Successfully deactivated SeAT for user %s" % user)
|
|
||||||
if notify_user:
|
|
||||||
notify(user, 'SeAT Account Disabled', level='danger')
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@shared_task(bind=True, name='seat.update_roles', base=QueueOnce)
|
|
||||||
def update_roles(self, pk):
|
|
||||||
user = User.objects.get(pk=pk)
|
|
||||||
logger.debug("Updating SeAT roles for user %s" % user)
|
|
||||||
if SeatTasks.has_account(user):
|
|
||||||
groups = [user.profile.state.name]
|
|
||||||
for group in user.groups.all():
|
|
||||||
groups.append(str(group.name))
|
|
||||||
logger.debug("Updating user %s SeAT roles to %s" % (user, groups))
|
|
||||||
try:
|
|
||||||
SeatManager.update_roles(user.seat.username, groups)
|
|
||||||
except:
|
|
||||||
logger.warn("SeAT group sync failed for %s, retrying in 10 mins" % user, exc_info=True)
|
|
||||||
raise self.retry(countdown=60 * 10)
|
|
||||||
logger.debug("Updated user %s SeAT roles." % user)
|
|
||||||
else:
|
|
||||||
logger.debug("User %s does not have a SeAT account")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@shared_task
|
|
||||||
def update_all_roles():
|
|
||||||
logger.debug("Updating ALL SeAT roles")
|
|
||||||
for user in SeatUser.objects.all():
|
|
||||||
SeatTasks.update_roles.delay(user.user_id)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def deactivate():
|
|
||||||
SeatUser.objects.all().delete()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_username(user):
|
|
||||||
from .auth_hooks import SeatService
|
|
||||||
return NameFormatter(SeatService(), user).format_name()
|
|
@ -1,204 +0,0 @@
|
|||||||
from unittest import mock
|
|
||||||
|
|
||||||
from django.test import TestCase, RequestFactory
|
|
||||||
from django import urls
|
|
||||||
from django.contrib.auth.models import User, Group, Permission
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
|
|
||||||
from allianceauth.tests.auth_utils import AuthUtils
|
|
||||||
|
|
||||||
from .auth_hooks import SeatService
|
|
||||||
from .models import SeatUser
|
|
||||||
from .tasks import SeatTasks
|
|
||||||
|
|
||||||
MODULE_PATH = 'allianceauth.services.modules.seat'
|
|
||||||
DEFAULT_AUTH_GROUP = 'Member'
|
|
||||||
|
|
||||||
|
|
||||||
def add_permissions():
|
|
||||||
permission = Permission.objects.get(codename='access_seat')
|
|
||||||
members = Group.objects.get_or_create(name=DEFAULT_AUTH_GROUP)[0]
|
|
||||||
AuthUtils.add_permissions_to_groups([permission], [members])
|
|
||||||
|
|
||||||
|
|
||||||
class SeatHooksTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.member = 'member_user'
|
|
||||||
member = AuthUtils.create_member(self.member)
|
|
||||||
SeatUser.objects.create(user=member, username=self.member)
|
|
||||||
self.none_user = 'none_user'
|
|
||||||
none_user = AuthUtils.create_user(self.none_user, disconnect_signals=True)
|
|
||||||
self.service = SeatService
|
|
||||||
add_permissions()
|
|
||||||
|
|
||||||
def test_has_account(self):
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
none_user = User.objects.get(username=self.none_user)
|
|
||||||
self.assertTrue(SeatTasks.has_account(member))
|
|
||||||
self.assertFalse(SeatTasks.has_account(none_user))
|
|
||||||
|
|
||||||
def test_service_enabled(self):
|
|
||||||
service = self.service()
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
none_user = User.objects.get(username=self.none_user)
|
|
||||||
|
|
||||||
self.assertTrue(service.service_active_for_user(member))
|
|
||||||
self.assertFalse(service.service_active_for_user(none_user))
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.tasks.SeatManager')
|
|
||||||
def test_update_all_groups(self, manager):
|
|
||||||
service = self.service()
|
|
||||||
service.update_all_groups()
|
|
||||||
# Check member and blue user have groups updated
|
|
||||||
self.assertTrue(manager.update_roles.called)
|
|
||||||
self.assertEqual(manager.update_roles.call_count, 1)
|
|
||||||
|
|
||||||
def test_update_groups(self):
|
|
||||||
# Check member has Member group updated
|
|
||||||
with mock.patch(MODULE_PATH + '.tasks.SeatManager') as manager:
|
|
||||||
service = self.service()
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
service.update_groups(member)
|
|
||||||
self.assertTrue(manager.update_roles.called)
|
|
||||||
args, kwargs = manager.update_roles.call_args
|
|
||||||
user_id, groups = args
|
|
||||||
self.assertIn(DEFAULT_AUTH_GROUP, groups)
|
|
||||||
self.assertEqual(user_id, member.seat.username)
|
|
||||||
|
|
||||||
# Check none user does not have groups updated
|
|
||||||
with mock.patch(MODULE_PATH + '.tasks.SeatManager') as manager:
|
|
||||||
service = self.service()
|
|
||||||
none_user = User.objects.get(username=self.none_user)
|
|
||||||
service.update_groups(none_user)
|
|
||||||
self.assertFalse(manager.update_roles.called)
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.tasks.SeatManager')
|
|
||||||
def test_validate_user(self, manager):
|
|
||||||
service = self.service()
|
|
||||||
# Test member is not deleted
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
# Pre assertion
|
|
||||||
self.assertTrue(member.has_perm('seat.access_seat'))
|
|
||||||
|
|
||||||
service.validate_user(member)
|
|
||||||
self.assertTrue(User.objects.get(username=self.member).seat)
|
|
||||||
|
|
||||||
# Test none user is deleted
|
|
||||||
none_user = User.objects.get(username=self.none_user)
|
|
||||||
manager.disable_user.return_value = 'abc123'
|
|
||||||
SeatUser.objects.create(user=none_user, username='abc123')
|
|
||||||
service.validate_user(none_user)
|
|
||||||
self.assertTrue(manager.disable_user.called)
|
|
||||||
with self.assertRaises(ObjectDoesNotExist):
|
|
||||||
none_seat = User.objects.get(username=self.none_user).seat
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.tasks.SeatManager')
|
|
||||||
def test_delete_user(self, manager):
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
|
|
||||||
service = self.service()
|
|
||||||
result = service.delete_user(member)
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
self.assertTrue(manager.disable_user.called)
|
|
||||||
with self.assertRaises(ObjectDoesNotExist):
|
|
||||||
seat_user = User.objects.get(username=self.member).seat
|
|
||||||
|
|
||||||
def test_render_services_ctrl(self):
|
|
||||||
service = self.service()
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
request = RequestFactory().get('/services/')
|
|
||||||
request.user = member
|
|
||||||
|
|
||||||
response = service.render_services_ctrl(request)
|
|
||||||
self.assertTemplateUsed(service.service_ctrl_template)
|
|
||||||
self.assertIn(urls.reverse('seat:deactivate'), response)
|
|
||||||
self.assertIn(urls.reverse('seat:reset_password'), response)
|
|
||||||
self.assertIn(urls.reverse('seat:set_password'), response)
|
|
||||||
|
|
||||||
# Test register becomes available
|
|
||||||
member.seat.delete()
|
|
||||||
member = User.objects.get(username=self.member)
|
|
||||||
request.user = member
|
|
||||||
response = service.render_services_ctrl(request)
|
|
||||||
self.assertIn(urls.reverse('seat:activate'), response)
|
|
||||||
|
|
||||||
|
|
||||||
class SeatViewsTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.member = AuthUtils.create_member('auth_member')
|
|
||||||
self.member.email = 'auth_member@example.com'
|
|
||||||
self.member.save()
|
|
||||||
AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation')
|
|
||||||
add_permissions()
|
|
||||||
|
|
||||||
def login(self):
|
|
||||||
self.client.force_login(self.member)
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.tasks.SeatManager')
|
|
||||||
@mock.patch(MODULE_PATH + '.views.SeatManager')
|
|
||||||
def test_activate(self, manager, tasks_manager):
|
|
||||||
self.login()
|
|
||||||
expected_username = 'auth_member'
|
|
||||||
manager.check_user_status.return_value = {}
|
|
||||||
manager.add_user.return_value = (expected_username, 'abc123')
|
|
||||||
|
|
||||||
response = self.client.get(urls.reverse('seat:activate'))
|
|
||||||
|
|
||||||
self.assertTrue(manager.add_user.called)
|
|
||||||
self.assertTrue(tasks_manager.update_roles.called)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertTemplateUsed('services/service_credentials.html')
|
|
||||||
self.assertContains(response, expected_username)
|
|
||||||
seat_user = SeatUser.objects.get(user=self.member)
|
|
||||||
self.assertEqual(seat_user.username, expected_username)
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.tasks.SeatManager')
|
|
||||||
def test_deactivate(self, manager):
|
|
||||||
self.login()
|
|
||||||
SeatUser.objects.create(user=self.member, username='some member')
|
|
||||||
|
|
||||||
response = self.client.get(urls.reverse('seat:deactivate'))
|
|
||||||
|
|
||||||
self.assertTrue(manager.disable_user.called)
|
|
||||||
self.assertRedirects(response, expected_url=urls.reverse('services:services'), target_status_code=200)
|
|
||||||
|
|
||||||
with self.assertRaises(ObjectDoesNotExist):
|
|
||||||
seat_user = User.objects.get(pk=self.member.pk).seat
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.views.SeatManager')
|
|
||||||
def test_set_password(self, manager):
|
|
||||||
self.login()
|
|
||||||
SeatUser.objects.create(user=self.member, username='some member')
|
|
||||||
|
|
||||||
response = self.client.post(urls.reverse('seat:set_password'), data={'password': '1234asdf'})
|
|
||||||
|
|
||||||
self.assertTrue(manager.update_user_password.called)
|
|
||||||
args, kwargs = manager.update_user_password.call_args
|
|
||||||
self.assertEqual(kwargs['plain_password'], '1234asdf')
|
|
||||||
self.assertRedirects(response, expected_url=urls.reverse('services:services'), target_status_code=200)
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.views.SeatManager')
|
|
||||||
def test_reset_password(self, manager):
|
|
||||||
self.login()
|
|
||||||
SeatUser.objects.create(user=self.member, username='some member')
|
|
||||||
|
|
||||||
manager.update_user_password.return_value = 'hunter2'
|
|
||||||
|
|
||||||
response = self.client.get(urls.reverse('seat:reset_password'))
|
|
||||||
|
|
||||||
self.assertTemplateUsed(response, 'services/service_credentials.html')
|
|
||||||
self.assertContains(response, 'some member')
|
|
||||||
self.assertContains(response, 'hunter2')
|
|
||||||
|
|
||||||
|
|
||||||
class SeatManagerTestCase(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
from .manager import SeatManager
|
|
||||||
self.manager = SeatManager
|
|
||||||
|
|
||||||
def test_generate_random_password(self):
|
|
||||||
password = self.manager._SeatManager__generate_random_pass()
|
|
||||||
|
|
||||||
self.assertEqual(len(password), 16)
|
|
||||||
self.assertIsInstance(password, type(''))
|
|
@ -1,17 +0,0 @@
|
|||||||
from django.conf.urls import url, include
|
|
||||||
|
|
||||||
from . import views
|
|
||||||
|
|
||||||
app_name='seat'
|
|
||||||
|
|
||||||
module_urls = [
|
|
||||||
# SeAT Service Control
|
|
||||||
url(r'^activate/$', views.activate_seat, name='activate'),
|
|
||||||
url(r'^deactivate/$', views.deactivate_seat, name='deactivate'),
|
|
||||||
url(r'^reset_password/$', views.reset_seat_password, name='reset_password'),
|
|
||||||
url(r'^set_password/$', views.set_seat_password, name='set_password'),
|
|
||||||
]
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^seat/', include((module_urls, app_name), namespace=app_name)),
|
|
||||||
]
|
|
@ -1,130 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
|
||||||
from django.shortcuts import render, redirect
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from allianceauth.services.forms import ServicePasswordForm
|
|
||||||
from .manager import SeatManager
|
|
||||||
from .models import SeatUser
|
|
||||||
from .tasks import SeatTasks
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
ACCESS_PERM = 'seat.access_seat'
|
|
||||||
SERVICE_NAME = {'service': 'SeAT'}
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@permission_required(ACCESS_PERM)
|
|
||||||
def activate_seat(request):
|
|
||||||
logger.debug("activate_seat called by user %s" % request.user)
|
|
||||||
character = request.user.profile.main_character
|
|
||||||
logger.debug("Checking SeAT for inactive users with the same username")
|
|
||||||
stat = SeatManager.check_user_status(character.character_name)
|
|
||||||
if stat == {}:
|
|
||||||
logger.debug("User not found, adding SeAT user for user %s with main character %s" % (request.user, character))
|
|
||||||
result = SeatManager.add_user(SeatTasks.get_username(request.user), request.user.email)
|
|
||||||
else:
|
|
||||||
logger.debug("User found, resetting password")
|
|
||||||
username = SeatManager.enable_user(stat["name"])
|
|
||||||
password = SeatManager.update_user_password(username, request.user.email)
|
|
||||||
result = [username, password]
|
|
||||||
# if empty we failed
|
|
||||||
if result[0] and result[1]:
|
|
||||||
SeatUser.objects.update_or_create(user=request.user, defaults={'username': result[0]})
|
|
||||||
logger.debug("Updated SeatUser for user %s with SeAT credentials. Adding eve-apis..." % request.user)
|
|
||||||
SeatTasks.update_roles.delay(request.user.pk)
|
|
||||||
logger.info("Successfully activated SeAT for user %s" % request.user)
|
|
||||||
messages.add_message(request, messages.SUCCESS, _('Successfully activated your %(service)s account.') %
|
|
||||||
SERVICE_NAME)
|
|
||||||
credentials = {
|
|
||||||
'username': request.user.seat.username,
|
|
||||||
'password': result[1],
|
|
||||||
}
|
|
||||||
return render(request, 'services/service_credentials.html',
|
|
||||||
context={'credentials': credentials, 'service': 'SeAT'})
|
|
||||||
messages.add_message(request, messages.ERROR,
|
|
||||||
_('Failed to activate your %(service)s account, please contact your administrator.') %
|
|
||||||
SERVICE_NAME)
|
|
||||||
logger.error("Unsuccessful attempt to activate seat for user %s" % request.user)
|
|
||||||
return redirect("services:services")
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@permission_required(ACCESS_PERM)
|
|
||||||
def deactivate_seat(request):
|
|
||||||
logger.debug("deactivate_seat called by user %s" % request.user)
|
|
||||||
# false we failed
|
|
||||||
if SeatTasks.delete_user(request.user):
|
|
||||||
messages.add_message(request, messages.SUCCESS,
|
|
||||||
_('Successfully deactivated your %(service)s account.') % SERVICE_NAME)
|
|
||||||
logger.info("Successfully deactivated SeAT for user %s" % request.user)
|
|
||||||
return redirect("services:services")
|
|
||||||
else:
|
|
||||||
logging.error("User does not have a SeAT account")
|
|
||||||
messages.add_message(request, messages.ERROR,
|
|
||||||
_('Failed to deactivate your %(service)s account, please contact your administrator.') %
|
|
||||||
SERVICE_NAME)
|
|
||||||
logger.error("Unsuccessful attempt to activate SeAT for user %s" % request.user)
|
|
||||||
return redirect("services:services")
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@permission_required(ACCESS_PERM)
|
|
||||||
def reset_seat_password(request):
|
|
||||||
logger.debug("reset_seat_password called by user %s" % request.user)
|
|
||||||
if SeatTasks.has_account(request.user):
|
|
||||||
result = SeatManager.update_user_password(request.user.seat.username, request.user.email)
|
|
||||||
# false we failed
|
|
||||||
if result:
|
|
||||||
credentials = {
|
|
||||||
'username': request.user.seat.username,
|
|
||||||
'password': result,
|
|
||||||
}
|
|
||||||
messages.add_message(request, messages.SUCCESS,
|
|
||||||
_('Successfully reset your %(service)s password.') % {'service': 'SeAT'})
|
|
||||||
logger.info("Succesfully reset SeAT password for user %s" % request.user)
|
|
||||||
return render(request, 'services/service_credentials.html',
|
|
||||||
context={'credentials': credentials, 'service': 'SeAT'})
|
|
||||||
logger.error("Unsuccessful attempt to reset SeAT password for user %s" % request.user)
|
|
||||||
messages.add_message(request, messages.ERROR,
|
|
||||||
_('Failed to reset your %(service)s password, please contact your administrator.') %
|
|
||||||
{'service': 'SeAT'})
|
|
||||||
return redirect("services:services")
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@permission_required(ACCESS_PERM)
|
|
||||||
def set_seat_password(request):
|
|
||||||
logger.debug("set_seat_password called by user %s" % request.user)
|
|
||||||
if request.method == 'POST':
|
|
||||||
logger.debug("Received POST request with form.")
|
|
||||||
form = ServicePasswordForm(request.POST)
|
|
||||||
logger.debug("Form is valid: %s" % form.is_valid())
|
|
||||||
if form.is_valid() and SeatTasks.has_account(request.user):
|
|
||||||
password = form.cleaned_data['password']
|
|
||||||
logger.debug("Form contains password of length %s" % len(password))
|
|
||||||
result = SeatManager.update_user_password(request.user.seat.username,
|
|
||||||
request.user.email,
|
|
||||||
plain_password=password)
|
|
||||||
if result:
|
|
||||||
messages.add_message(request, messages.SUCCESS,
|
|
||||||
_('Successfully set your %(service)s password.') % SERVICE_NAME)
|
|
||||||
logger.info("Succesfully reset SeAT password for user %s" % request.user)
|
|
||||||
return redirect("services:services")
|
|
||||||
else:
|
|
||||||
messages.add_message(request, messages.ERROR,
|
|
||||||
_('Failed to set your %(service)s password, please contact your administrator.') %
|
|
||||||
SERVICE_NAME)
|
|
||||||
logger.error("Failed to install custom SeAT password for user %s" % request.user)
|
|
||||||
else:
|
|
||||||
messages.add_message(request, messages.ERROR, _('Invalid password.'))
|
|
||||||
logger.error("Invalid SeAT password provided")
|
|
||||||
else:
|
|
||||||
logger.debug("Request is not type POST - providing empty form.")
|
|
||||||
form = ServicePasswordForm()
|
|
||||||
logger.debug("Rendering form for user %s" % request.user)
|
|
||||||
context = {'form': form, 'service': 'SeAT'}
|
|
||||||
return render(request, 'services/service_password.html', context)
|
|
@ -25,8 +25,6 @@ Currently the following services support custom name formats:
|
|||||||
+-------------+-----------+-------------------------------------+
|
+-------------+-----------+-------------------------------------+
|
||||||
| phpBB3 | Username | ``{character_name}`` |
|
| phpBB3 | Username | ``{character_name}`` |
|
||||||
+-------------+-----------+-------------------------------------+
|
+-------------+-----------+-------------------------------------+
|
||||||
| SeAT | Username | ``{character_name}`` |
|
|
||||||
+-------------+-----------+-------------------------------------+
|
|
||||||
| SMF | Username | ``{character_name}`` |
|
| SMF | Username | ``{character_name}`` |
|
||||||
+-------------+-----------+-------------------------------------+
|
+-------------+-----------+-------------------------------------+
|
||||||
| Teamspeak 3 | Nickname | ``[{corp_ticker}]{character_name}`` |
|
| Teamspeak 3 | Nickname | ``[{corp_ticker}]{character_name}`` |
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
|
|
||||||
permissions
|
permissions
|
||||||
market
|
|
||||||
discord
|
discord
|
||||||
discourse
|
discourse
|
||||||
mumble
|
mumble
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
# Alliance Market
|
|
||||||
|
|
||||||
## Deprecation
|
|
||||||
|
|
||||||
Alliance Market relies on the now non-functional XML API.
|
|
||||||
|
|
||||||
Please remove this service data with `python manage.py migrate appname zero` and then remove from your `INSTALLED_APPS` list.
|
|
@ -62,7 +62,7 @@ SMF needs a database. Create one:
|
|||||||
Enter the database information into the `DATABASES['smf']` section of your auth project's settings file.
|
Enter the database information into the `DATABASES['smf']` section of your auth project's settings file.
|
||||||
|
|
||||||
### Web Server Configuration
|
### Web Server Configuration
|
||||||
Your web server needs to be configured to serve Alliance Market.
|
Your web server needs to be configured to serve SMF.
|
||||||
|
|
||||||
A minimal Apache config might look like:
|
A minimal Apache config might look like:
|
||||||
|
|
||||||
|
@ -29,9 +29,7 @@ INSTALLED_APPS += [
|
|||||||
'allianceauth.services.modules.discord',
|
'allianceauth.services.modules.discord',
|
||||||
'allianceauth.services.modules.discourse',
|
'allianceauth.services.modules.discourse',
|
||||||
'allianceauth.services.modules.ips4',
|
'allianceauth.services.modules.ips4',
|
||||||
'allianceauth.services.modules.market',
|
|
||||||
'allianceauth.services.modules.openfire',
|
'allianceauth.services.modules.openfire',
|
||||||
'allianceauth.services.modules.seat',
|
|
||||||
'allianceauth.services.modules.smf',
|
'allianceauth.services.modules.smf',
|
||||||
'allianceauth.services.modules.phpbb3',
|
'allianceauth.services.modules.phpbb3',
|
||||||
'allianceauth.services.modules.xenforo',
|
'allianceauth.services.modules.xenforo',
|
||||||
@ -43,11 +41,6 @@ ROOT_URLCONF = 'tests.urls'
|
|||||||
|
|
||||||
CACHES['default'] = {'BACKEND': 'django.core.cache.backends.db.DatabaseCache'}
|
CACHES['default'] = {'BACKEND': 'django.core.cache.backends.db.DatabaseCache'}
|
||||||
|
|
||||||
#####################
|
|
||||||
# Alliance Market
|
|
||||||
#####################
|
|
||||||
MARKET_URL = 'http://yourdomain.com/market'
|
|
||||||
|
|
||||||
#####################
|
#####################
|
||||||
# HR Configuration
|
# HR Configuration
|
||||||
#####################
|
#####################
|
||||||
@ -159,15 +152,6 @@ DISCOURSE_SSO_SECRET = 'd836444a9e4084d5b224a60c208dce14'
|
|||||||
IPS4_URL = 'http://example.com/ips4'
|
IPS4_URL = 'http://example.com/ips4'
|
||||||
IPS4_API_KEY = ''
|
IPS4_API_KEY = ''
|
||||||
|
|
||||||
#####################################
|
|
||||||
# SEAT Configuration
|
|
||||||
#####################################
|
|
||||||
# SEAT_URL - base url of the seat install (no trailing slash)
|
|
||||||
# SEAT_XTOKEN - API key X-Token provided by SeAT
|
|
||||||
#####################################
|
|
||||||
SEAT_URL = 'http://example.com/seat'
|
|
||||||
SEAT_XTOKEN = 'tokentokentoken'
|
|
||||||
|
|
||||||
######################################
|
######################################
|
||||||
# SMF Configuration
|
# SMF Configuration
|
||||||
######################################
|
######################################
|
||||||
|
Loading…
x
Reference in New Issue
Block a user