mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-07 15:46:20 +01:00
Restructure Alliance Auth package (#867)
* Refactor allianceauth into its own package * Add setup * Add missing default_app_config declarations * Fix timerboard namespacing * Remove obsolete future imports * Remove py2 mock support * Remove six * Add experimental 3.7 support and multiple Dj versions * Remove python_2_unicode_compatible * Add navhelper as local package * Update requirements
This commit is contained in:
1
allianceauth/services/modules/phpbb3/__init__.py
Normal file
1
allianceauth/services/modules/phpbb3/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
default_app_config = 'allianceauth.services.modules.phpbb3.apps.Phpbb3ServiceConfig'
|
||||
9
allianceauth/services/modules/phpbb3/admin.py
Normal file
9
allianceauth/services/modules/phpbb3/admin.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.contrib import admin
|
||||
from .models import Phpbb3User
|
||||
|
||||
|
||||
class Phpbb3UserAdmin(admin.ModelAdmin):
|
||||
list_display = ('user', 'username')
|
||||
search_fields = ('user__username', 'username')
|
||||
|
||||
admin.site.register(Phpbb3User, Phpbb3UserAdmin)
|
||||
6
allianceauth/services/modules/phpbb3/apps.py
Normal file
6
allianceauth/services/modules/phpbb3/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class Phpbb3ServiceConfig(AppConfig):
|
||||
name = 'allianceauth.services.modules.phpbb3'
|
||||
label = 'phpbb3'
|
||||
63
allianceauth/services/modules/phpbb3/auth_hooks.py
Normal file
63
allianceauth/services/modules/phpbb3/auth_hooks.py
Normal file
@@ -0,0 +1,63 @@
|
||||
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 Phpbb3Tasks
|
||||
from .urls import urlpatterns
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Phpbb3Service(ServicesHook):
|
||||
def __init__(self):
|
||||
ServicesHook.__init__(self)
|
||||
self.name = 'phpbb3'
|
||||
self.urlpatterns = urlpatterns
|
||||
self.service_url = settings.PHPBB3_URL
|
||||
self.access_perm = 'phpbb3.access_phpbb3'
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return 'phpBB3 Forum'
|
||||
|
||||
def delete_user(self, user, notify_user=False):
|
||||
logger.debug('Deleting user %s %s account' % (user, self.name))
|
||||
return Phpbb3Tasks.delete_user(user, notify_user=notify_user)
|
||||
|
||||
def validate_user(self, user):
|
||||
logger.debug('Validating user %s %s account' % (user, self.name))
|
||||
if Phpbb3Tasks.has_account(user) and not self.service_active_for_user(user):
|
||||
self.delete_user(user, notify_user=True)
|
||||
|
||||
def update_groups(self, user):
|
||||
logger.debug('Updating %s groups for %s' % (self.name, user))
|
||||
if Phpbb3Tasks.has_account(user):
|
||||
Phpbb3Tasks.update_groups.delay(user.pk)
|
||||
|
||||
def update_all_groups(self):
|
||||
logger.debug('Update all %s groups called' % self.name)
|
||||
Phpbb3Tasks.update_all_groups.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 = 'auth_activate_phpbb3'
|
||||
urls.auth_deactivate = 'auth_deactivate_phpbb3'
|
||||
urls.auth_reset_password = 'auth_reset_phpbb3_password'
|
||||
urls.auth_set_password = 'auth_set_phpbb3_password'
|
||||
return render_to_string(self.service_ctrl_template, {
|
||||
'service_name': self.title,
|
||||
'urls': urls,
|
||||
'service_url': self.service_url,
|
||||
'username': request.user.phpbb3.username if Phpbb3Tasks.has_account(request.user) else ''
|
||||
}, request=request)
|
||||
|
||||
|
||||
@hooks.register('services_hook')
|
||||
def register_service():
|
||||
return Phpbb3Service()
|
||||
301
allianceauth/services/modules/phpbb3/manager.py
Executable file
301
allianceauth/services/modules/phpbb3/manager.py
Executable file
@@ -0,0 +1,301 @@
|
||||
import random
|
||||
import string
|
||||
import calendar
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
from passlib.apps import phpbb3_context
|
||||
from django.db import connections
|
||||
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Phpbb3Manager:
|
||||
SQL_ADD_USER = r"INSERT INTO phpbb_users (username, username_clean, " \
|
||||
r"user_password, user_email, group_id, user_regdate, user_permissions, " \
|
||||
r"user_sig, user_lang) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, 'en')"
|
||||
|
||||
SQL_DEL_USER = r"DELETE FROM phpbb_users where username = %s"
|
||||
|
||||
SQL_DIS_USER = r"UPDATE phpbb_users SET user_email= %s, user_password=%s WHERE username = %s"
|
||||
|
||||
SQL_USER_ID_FROM_USERNAME = r"SELECT user_id from phpbb_users WHERE username = %s"
|
||||
|
||||
SQL_ADD_USER_GROUP = r"INSERT INTO phpbb_user_group (group_id, user_id, user_pending) VALUES (%s, %s, %s)"
|
||||
|
||||
SQL_GET_GROUP_ID = r"SELECT group_id from phpbb_groups WHERE group_name = %s"
|
||||
|
||||
SQL_ADD_GROUP = r"INSERT INTO phpbb_groups (group_name,group_desc,group_legend) VALUES (%s,%s,0)"
|
||||
|
||||
SQL_UPDATE_USER_PASSWORD = r"UPDATE phpbb_users SET user_password = %s WHERE username = %s"
|
||||
|
||||
SQL_REMOVE_USER_GROUP = r"DELETE FROM phpbb_user_group WHERE user_id=%s AND group_id=%s "
|
||||
|
||||
SQL_GET_ALL_GROUPS = r"SELECT group_id, group_name FROM phpbb_groups"
|
||||
|
||||
SQL_GET_USER_GROUPS = r"SELECT phpbb_groups.group_name FROM phpbb_groups , phpbb_user_group WHERE " \
|
||||
r"phpbb_user_group.group_id = phpbb_groups.group_id AND user_id=%s"
|
||||
|
||||
SQL_ADD_USER_AVATAR = r"UPDATE phpbb_users SET user_avatar_type=2, user_avatar_width=64, user_avatar_height=64, " \
|
||||
"user_avatar=%s WHERE user_id = %s"
|
||||
|
||||
SQL_CLEAR_USER_PERMISSIONS = r"UPDATE phpbb_users SET user_permissions = '' WHERE user_Id = %s"
|
||||
|
||||
SQL_DEL_SESSION = r"DELETE FROM phpbb_sessions where session_user_id = %s"
|
||||
|
||||
SQL_DEL_AUTOLOGIN = r"DELETE FROM phpbb_sessions_keys where user_id = %s"
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def __add_avatar(username, characterid):
|
||||
logger.debug("Adding EVE character id %s portrait as phpbb avater for user %s" % (characterid, username))
|
||||
avatar_url = "https://image.eveonline.com/Character/" + characterid + "_64.jpg"
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
userid = Phpbb3Manager.__get_user_id(username)
|
||||
cursor.execute(Phpbb3Manager.SQL_ADD_USER_AVATAR, [avatar_url, userid])
|
||||
|
||||
@staticmethod
|
||||
def __generate_random_pass():
|
||||
return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(16)])
|
||||
|
||||
@staticmethod
|
||||
def __gen_hash(password):
|
||||
return phpbb3_context.encrypt(password)
|
||||
|
||||
@staticmethod
|
||||
def __santatize_username(username):
|
||||
sanatized = username.replace(" ", "_")
|
||||
sanatized = sanatized.replace("'", "_")
|
||||
return sanatized.lower()
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_groupname(name):
|
||||
name = name.strip(' _')
|
||||
return re.sub('[^\w.-]', '', name)
|
||||
|
||||
@staticmethod
|
||||
def __get_group_id(groupname):
|
||||
logger.debug("Getting phpbb3 group id for groupname %s" % groupname)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_GET_GROUP_ID, [groupname])
|
||||
row = cursor.fetchone()
|
||||
logger.debug("Got phpbb group id %s for groupname %s" % (row[0], groupname))
|
||||
return row[0]
|
||||
|
||||
@staticmethod
|
||||
def __get_user_id(username):
|
||||
logger.debug("Getting phpbb3 user id for username %s" % username)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_USER_ID_FROM_USERNAME, [username])
|
||||
row = cursor.fetchone()
|
||||
if row is not None:
|
||||
logger.debug("Got phpbb user id %s for username %s" % (row[0], username))
|
||||
return row[0]
|
||||
else:
|
||||
logger.error("Username %s not found on phpbb. Unable to determine user id." % username)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def __get_all_groups():
|
||||
logger.debug("Getting all phpbb3 groups.")
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_GET_ALL_GROUPS)
|
||||
rows = cursor.fetchall()
|
||||
out = {}
|
||||
for row in rows:
|
||||
out[row[1]] = row[0]
|
||||
logger.debug("Got phpbb groups %s" % out)
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def __get_user_groups(userid):
|
||||
logger.debug("Getting phpbb3 user id %s groups" % userid)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_GET_USER_GROUPS, [userid])
|
||||
out = [row[0] for row in cursor.fetchall()]
|
||||
logger.debug("Got user %s phpbb groups %s" % (userid, out))
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def __get_current_utc_date():
|
||||
d = datetime.utcnow()
|
||||
unixtime = calendar.timegm(d.utctimetuple())
|
||||
return unixtime
|
||||
|
||||
@staticmethod
|
||||
def __create_group(groupname):
|
||||
logger.debug("Creating phpbb3 group %s" % groupname)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_ADD_GROUP, [groupname, groupname])
|
||||
logger.info("Created phpbb group %s" % groupname)
|
||||
return Phpbb3Manager.__get_group_id(groupname)
|
||||
|
||||
@staticmethod
|
||||
def __add_user_to_group(userid, groupid):
|
||||
logger.debug("Adding phpbb3 user id %s to group id %s" % (userid, groupid))
|
||||
try:
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_ADD_USER_GROUP, [groupid, userid, 0])
|
||||
cursor.execute(Phpbb3Manager.SQL_CLEAR_USER_PERMISSIONS, [userid])
|
||||
logger.info("Added phpbb user id %s to group id %s" % (userid, groupid))
|
||||
except:
|
||||
logger.exception("Unable to add phpbb user id %s to group id %s" % (userid, groupid))
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def __remove_user_from_group(userid, groupid):
|
||||
logger.debug("Removing phpbb3 user id %s from group id %s" % (userid, groupid))
|
||||
try:
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_REMOVE_USER_GROUP, [userid, groupid])
|
||||
cursor.execute(Phpbb3Manager.SQL_CLEAR_USER_PERMISSIONS, [userid])
|
||||
logger.info("Removed phpbb user id %s from group id %s" % (userid, groupid))
|
||||
except:
|
||||
logger.exception("Unable to remove phpbb user id %s from group id %s" % (userid, groupid))
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def add_user(username, email, groups, characterid):
|
||||
logger.debug("Adding phpbb user with username %s, email %s, groups %s, characterid %s" % (
|
||||
username, email, groups, characterid))
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
|
||||
username_clean = Phpbb3Manager.__santatize_username(username)
|
||||
password = Phpbb3Manager.__generate_random_pass()
|
||||
pwhash = Phpbb3Manager.__gen_hash(password)
|
||||
logger.debug("Proceeding to add phpbb user %s and pwhash starting with %s" % (username_clean, pwhash[0:5]))
|
||||
# check if the username was simply revoked
|
||||
if Phpbb3Manager.check_user(username_clean):
|
||||
logger.warn("Unable to add phpbb user with username %s - already exists. Updating user instead." % username)
|
||||
Phpbb3Manager.__update_user_info(username_clean, email, pwhash)
|
||||
else:
|
||||
try:
|
||||
|
||||
cursor.execute(Phpbb3Manager.SQL_ADD_USER, [username_clean, username_clean, pwhash,
|
||||
email, 2, Phpbb3Manager.__get_current_utc_date(),
|
||||
"", ""])
|
||||
Phpbb3Manager.update_groups(username_clean, groups)
|
||||
Phpbb3Manager.__add_avatar(username_clean, characterid)
|
||||
logger.info("Added phpbb user %s" % username_clean)
|
||||
except:
|
||||
logger.exception("Unable to add phpbb user %s" % username_clean)
|
||||
pass
|
||||
|
||||
return username_clean, password
|
||||
|
||||
@staticmethod
|
||||
def disable_user(username):
|
||||
logger.debug("Disabling phpbb user %s" % username)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
|
||||
password = Phpbb3Manager.__gen_hash(Phpbb3Manager.__generate_random_pass())
|
||||
revoke_email = "revoked@" + settings.DOMAIN
|
||||
try:
|
||||
pwhash = Phpbb3Manager.__gen_hash(password)
|
||||
cursor.execute(Phpbb3Manager.SQL_DIS_USER, [revoke_email, pwhash, username])
|
||||
userid = Phpbb3Manager.__get_user_id(username)
|
||||
cursor.execute(Phpbb3Manager.SQL_DEL_AUTOLOGIN, [userid])
|
||||
cursor.execute(Phpbb3Manager.SQL_DEL_SESSION, [userid])
|
||||
Phpbb3Manager.update_groups(username, [])
|
||||
logger.info("Disabled phpbb user %s" % username)
|
||||
return True
|
||||
except TypeError:
|
||||
logger.exception("TypeError occured while disabling user %s - failed to disable." % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def delete_user(username):
|
||||
logger.debug("Deleting phpbb user %s" % username)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
|
||||
if Phpbb3Manager.check_user(username):
|
||||
cursor.execute(Phpbb3Manager.SQL_DEL_USER, [username])
|
||||
logger.info("Deleted phpbb user %s" % username)
|
||||
return True
|
||||
logger.error("Unable to delete phpbb user %s - user not found on phpbb." % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def update_groups(username, groups):
|
||||
userid = Phpbb3Manager.__get_user_id(username)
|
||||
logger.debug("Updating phpbb user %s with id %s groups %s" % (username, userid, groups))
|
||||
if userid is not None:
|
||||
forum_groups = Phpbb3Manager.__get_all_groups()
|
||||
user_groups = set(Phpbb3Manager.__get_user_groups(userid))
|
||||
act_groups = set([Phpbb3Manager._sanitize_groupname(g) for g in groups])
|
||||
addgroups = act_groups - user_groups
|
||||
remgroups = user_groups - act_groups
|
||||
logger.info("Updating phpbb user %s groups - adding %s, removing %s" % (username, addgroups, remgroups))
|
||||
for g in addgroups:
|
||||
if not g in forum_groups:
|
||||
forum_groups[g] = Phpbb3Manager.__create_group(g)
|
||||
Phpbb3Manager.__add_user_to_group(userid, forum_groups[g])
|
||||
|
||||
for g in remgroups:
|
||||
Phpbb3Manager.__remove_user_from_group(userid, forum_groups[g])
|
||||
|
||||
@staticmethod
|
||||
def remove_group(username, group):
|
||||
logger.debug("Removing phpbb user %s from group %s" % (username, group))
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
userid = Phpbb3Manager.__get_user_id(username)
|
||||
if userid is not None:
|
||||
groupid = Phpbb3Manager.__get_group_id(group)
|
||||
|
||||
if userid:
|
||||
if groupid:
|
||||
try:
|
||||
cursor.execute(Phpbb3Manager.SQL_REMOVE_USER_GROUP, [userid, groupid])
|
||||
logger.info("Removed phpbb user %s from group %s" % (username, group))
|
||||
except:
|
||||
logger.exception(
|
||||
"Exception prevented removal of phpbb user %s with id %s from group %s with id %s" % (
|
||||
username, userid, group, groupid))
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def check_user(username):
|
||||
logger.debug("Checking phpbb username %s" % username)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
cursor.execute(Phpbb3Manager.SQL_USER_ID_FROM_USERNAME, [Phpbb3Manager.__santatize_username(username)])
|
||||
row = cursor.fetchone()
|
||||
if row:
|
||||
logger.debug("Found user %s on phpbb" % username)
|
||||
return True
|
||||
logger.debug("User %s not found on phpbb" % username)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def update_user_password(username, characterid, password=None):
|
||||
logger.debug("Updating phpbb user %s password" % username)
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
if not password:
|
||||
password = Phpbb3Manager.__generate_random_pass()
|
||||
if Phpbb3Manager.check_user(username):
|
||||
pwhash = Phpbb3Manager.__gen_hash(password)
|
||||
logger.debug(
|
||||
"Proceeding to update phpbb user %s password with pwhash starting with %s" % (username, pwhash[0:5]))
|
||||
cursor.execute(Phpbb3Manager.SQL_UPDATE_USER_PASSWORD, [pwhash, username])
|
||||
Phpbb3Manager.__add_avatar(username, characterid)
|
||||
logger.info("Updated phpbb user %s password." % username)
|
||||
return password
|
||||
logger.error("Unable to update phpbb user %s password - user not found on phpbb." % username)
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def __update_user_info(username, email, password):
|
||||
logger.debug(
|
||||
"Updating phpbb user %s info: username %s password of length %s" % (username, email, len(password)))
|
||||
cursor = connections['phpbb3'].cursor()
|
||||
try:
|
||||
cursor.execute(Phpbb3Manager.SQL_DIS_USER, [email, password, username])
|
||||
logger.info("Updated phpbb user %s info" % username)
|
||||
except:
|
||||
logger.exception("Unable to update phpbb user %s info." % username)
|
||||
pass
|
||||
@@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.2 on 2016-12-12 03:28
|
||||
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='Phpbb3User',
|
||||
fields=[
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='phpbb3', serialize=False, to=settings.AUTH_USER_MODEL)),
|
||||
('username', models.CharField(max_length=254)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,61 @@
|
||||
# -*- 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")
|
||||
Phpbb3User = apps.get_model("phpbb3", "Phpbb3User")
|
||||
|
||||
perm = Permission.objects.get(codename='access_phpbb3')
|
||||
|
||||
member_group_name = getattr(settings, str('DEFAULT_AUTH_GROUP'), 'Member')
|
||||
blue_group_name = getattr(settings, str('DEFAULT_BLUE_GROUP'), 'Blue')
|
||||
|
||||
# Migrate members
|
||||
if Phpbb3User.objects.filter(user__groups__name=member_group_name).exists() or \
|
||||
getattr(settings, str('ENABLE_AUTH_FORUM'), False):
|
||||
try:
|
||||
group = Group.objects.get(name=member_group_name)
|
||||
group.permissions.add(perm)
|
||||
except ObjectDoesNotExist:
|
||||
logger.warning('Failed to migrate ENABLE_AUTH_FORUM setting')
|
||||
|
||||
# Migrate blues
|
||||
if Phpbb3User.objects.filter(user__groups__name=blue_group_name).exists() or \
|
||||
getattr(settings, str('ENABLE_BLUE_FORUM'), False):
|
||||
try:
|
||||
group = Group.objects.get(name=blue_group_name)
|
||||
group.permissions.add(perm)
|
||||
except ObjectDoesNotExist:
|
||||
logger.warning('Failed to migrate ENABLE_BLUE_FORUM setting')
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('phpbb3', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='phpbb3user',
|
||||
options={'permissions': (('access_phpbb3', 'Can access the phpBB3 service'),)},
|
||||
),
|
||||
migrations.RunPython(migrate_service_enabled),
|
||||
]
|
||||
17
allianceauth/services/modules/phpbb3/models.py
Normal file
17
allianceauth/services/modules/phpbb3/models.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Phpbb3User(models.Model):
|
||||
user = models.OneToOneField('auth.User',
|
||||
primary_key=True,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='phpbb3')
|
||||
username = models.CharField(max_length=254)
|
||||
|
||||
def __str__(self):
|
||||
return self.username
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("access_phpbb3", u"Can access the phpBB3 service"),
|
||||
)
|
||||
66
allianceauth/services/modules/phpbb3/tasks.py
Normal file
66
allianceauth/services/modules/phpbb3/tasks.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import logging
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
from allianceauth.celeryapp import app
|
||||
from allianceauth.notifications import notify
|
||||
from .manager import Phpbb3Manager
|
||||
from .models import Phpbb3User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Phpbb3Tasks:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def delete_user(cls, user, notify_user=False):
|
||||
if cls.has_account(user):
|
||||
logger.debug("User %s has forum account %s. Deleting." % (user, user.phpbb3.username))
|
||||
if Phpbb3Manager.disable_user(user.phpbb3.username):
|
||||
user.phpbb3.delete()
|
||||
if notify_user:
|
||||
notify(user, 'Forum Account Disabled', level='danger')
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def has_account(user):
|
||||
try:
|
||||
return user.phpbb3.username != ''
|
||||
except ObjectDoesNotExist:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
@app.task(bind=True, name="phpbb3.update_groups")
|
||||
def update_groups(self, pk):
|
||||
user = User.objects.get(pk=pk)
|
||||
logger.debug("Updating phpbb3 groups for user %s" % user)
|
||||
if Phpbb3Tasks.has_account(user):
|
||||
groups = []
|
||||
for group in user.groups.all():
|
||||
groups.append(str(group.name))
|
||||
if len(groups) == 0:
|
||||
groups.append('empty')
|
||||
logger.debug("Updating user %s phpbb3 groups to %s" % (user, groups))
|
||||
try:
|
||||
Phpbb3Manager.update_groups(user.phpbb3.username, groups)
|
||||
except:
|
||||
logger.exception("Phpbb group sync failed for %s, retrying in 10 mins" % user)
|
||||
raise self.retry(countdown=60 * 10)
|
||||
logger.debug("Updated user %s phpbb3 groups." % user)
|
||||
else:
|
||||
logger.debug("User does not have a Phpbb3 account")
|
||||
|
||||
@staticmethod
|
||||
@app.task(name="phpbb3.update_all_groups")
|
||||
def update_all_groups():
|
||||
logger.debug("Updating ALL phpbb3 groups")
|
||||
for user in Phpbb3User.objects.exclude(username__exact=''):
|
||||
Phpbb3Tasks.update_groups.delay(user.user_id)
|
||||
|
||||
@staticmethod
|
||||
def disable():
|
||||
Phpbb3User.objects.all().delete()
|
||||
204
allianceauth/services/modules/phpbb3/tests.py
Normal file
204
allianceauth/services/modules/phpbb3/tests.py
Normal file
@@ -0,0 +1,204 @@
|
||||
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 Phpbb3Service
|
||||
from .models import Phpbb3User
|
||||
from .tasks import Phpbb3Tasks
|
||||
|
||||
MODULE_PATH = 'allianceauth.services.modules.phpbb3'
|
||||
DEFAULT_AUTH_GROUP = 'Member'
|
||||
|
||||
|
||||
def add_permissions():
|
||||
permission = Permission.objects.get(codename='access_phpbb3')
|
||||
members = Group.objects.get_or_create(name=DEFAULT_AUTH_GROUP)[0]
|
||||
AuthUtils.add_permissions_to_groups([permission], [members])
|
||||
|
||||
|
||||
class Phpbb3HooksTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.member = 'member_user'
|
||||
member = AuthUtils.create_member(self.member)
|
||||
Phpbb3User.objects.create(user=member, username=self.member)
|
||||
self.none_user = 'none_user'
|
||||
none_user = AuthUtils.create_user(self.none_user)
|
||||
self.service = Phpbb3Service
|
||||
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(Phpbb3Tasks.has_account(member))
|
||||
self.assertFalse(Phpbb3Tasks.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.Phpbb3Manager')
|
||||
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_groups.called)
|
||||
self.assertEqual(manager.update_groups.call_count, 1)
|
||||
|
||||
def test_update_groups(self):
|
||||
# Check member has Member group updated
|
||||
with mock.patch(MODULE_PATH + '.tasks.Phpbb3Manager') as manager:
|
||||
service = self.service()
|
||||
member = User.objects.get(username=self.member)
|
||||
service.update_groups(member)
|
||||
self.assertTrue(manager.update_groups.called)
|
||||
args, kwargs = manager.update_groups.call_args
|
||||
user_id, groups = args
|
||||
self.assertIn(DEFAULT_AUTH_GROUP, groups)
|
||||
self.assertEqual(user_id, member.phpbb3.username)
|
||||
|
||||
# Check none user does not have groups updated
|
||||
with mock.patch(MODULE_PATH + '.tasks.Phpbb3Manager') as manager:
|
||||
service = self.service()
|
||||
none_user = User.objects.get(username=self.none_user)
|
||||
service.update_groups(none_user)
|
||||
self.assertFalse(manager.update_groups.called)
|
||||
|
||||
@mock.patch(MODULE_PATH + '.tasks.Phpbb3Manager')
|
||||
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(member.phpbb3)
|
||||
|
||||
# Test none user is deleted
|
||||
none_user = User.objects.get(username=self.none_user)
|
||||
Phpbb3User.objects.create(user=none_user, username='abc123')
|
||||
service.validate_user(none_user)
|
||||
self.assertTrue(manager.disable_user.called)
|
||||
with self.assertRaises(ObjectDoesNotExist):
|
||||
none_phpbb3 = User.objects.get(username=self.none_user).phpbb3
|
||||
|
||||
@mock.patch(MODULE_PATH + '.tasks.Phpbb3Manager')
|
||||
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):
|
||||
phpbb3_user = User.objects.get(username=self.member).phpbb3
|
||||
|
||||
def test_render_services_ctrl(self):
|
||||
service = self.service()
|
||||
member = User.objects.get(username=self.member)
|
||||
request = RequestFactory().get('/en/services/')
|
||||
request.user = member
|
||||
|
||||
response = service.render_services_ctrl(request)
|
||||
self.assertTemplateUsed(service.service_ctrl_template)
|
||||
self.assertIn(urls.reverse('auth_deactivate_phpbb3'), response)
|
||||
self.assertIn(urls.reverse('auth_reset_phpbb3_password'), response)
|
||||
self.assertIn(urls.reverse('auth_set_phpbb3_password'), response)
|
||||
|
||||
# Test register becomes available
|
||||
member.phpbb3.delete()
|
||||
member = User.objects.get(username=self.member)
|
||||
request.user = member
|
||||
response = service.render_services_ctrl(request)
|
||||
self.assertIn(urls.reverse('auth_activate_phpbb3'), response)
|
||||
|
||||
|
||||
class Phpbb3ViewsTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.member = AuthUtils.create_member('auth_member')
|
||||
self.member.set_password('password')
|
||||
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.login(username=self.member.username, password='password')
|
||||
|
||||
@mock.patch(MODULE_PATH + '.tasks.Phpbb3Manager')
|
||||
@mock.patch(MODULE_PATH + '.views.Phpbb3Manager')
|
||||
def test_activate(self, manager, tasks_manager):
|
||||
self.login()
|
||||
expected_username = 'auth_member'
|
||||
manager.add_user.return_value = (expected_username, 'abc123')
|
||||
|
||||
response = self.client.get(urls.reverse('auth_activate_phpbb3'))
|
||||
|
||||
self.assertTrue(manager.add_user.called)
|
||||
self.assertTrue(tasks_manager.update_groups.called)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed('registered/service_credentials.html')
|
||||
self.assertContains(response, expected_username)
|
||||
phpbb3_user = Phpbb3User.objects.get(user=self.member)
|
||||
self.assertEqual(phpbb3_user.username, expected_username)
|
||||
|
||||
@mock.patch(MODULE_PATH + '.tasks.Phpbb3Manager')
|
||||
def test_deactivate(self, manager):
|
||||
self.login()
|
||||
Phpbb3User.objects.create(user=self.member, username='some member')
|
||||
|
||||
response = self.client.get(urls.reverse('auth_deactivate_phpbb3'))
|
||||
|
||||
self.assertTrue(manager.disable_user.called)
|
||||
self.assertRedirects(response, expected_url=urls.reverse('auth_services'), target_status_code=200)
|
||||
with self.assertRaises(ObjectDoesNotExist):
|
||||
phpbb3_user = User.objects.get(pk=self.member.pk).phpbb3
|
||||
|
||||
@mock.patch(MODULE_PATH + '.views.Phpbb3Manager')
|
||||
def test_set_password(self, manager):
|
||||
self.login()
|
||||
Phpbb3User.objects.create(user=self.member, username='some member')
|
||||
|
||||
response = self.client.post(urls.reverse('auth_set_phpbb3_password'), data={'password': '1234asdf'})
|
||||
|
||||
self.assertTrue(manager.update_user_password.called)
|
||||
args, kwargs = manager.update_user_password.call_args
|
||||
self.assertEqual(kwargs['password'], '1234asdf')
|
||||
self.assertRedirects(response, expected_url=urls.reverse('auth_services'), target_status_code=200)
|
||||
|
||||
@mock.patch(MODULE_PATH + '.views.Phpbb3Manager')
|
||||
def test_reset_password(self, manager):
|
||||
self.login()
|
||||
Phpbb3User.objects.create(user=self.member, username='some member')
|
||||
|
||||
manager.update_user_password.return_value = 'hunter2'
|
||||
|
||||
response = self.client.get(urls.reverse('auth_reset_phpbb3_password'))
|
||||
|
||||
self.assertTemplateUsed(response, 'registered/service_credentials.html')
|
||||
self.assertContains(response, 'some member')
|
||||
self.assertContains(response, 'hunter2')
|
||||
|
||||
|
||||
class Phpbb3ManagerTestCase(TestCase):
|
||||
def setUp(self):
|
||||
from .manager import Phpbb3Manager
|
||||
self.manager = Phpbb3Manager
|
||||
|
||||
def test_generate_random_password(self):
|
||||
password = self.manager._Phpbb3Manager__generate_random_pass()
|
||||
|
||||
self.assertEqual(len(password), 16)
|
||||
self.assertIsInstance(password, type(''))
|
||||
|
||||
def test_gen_pwhash(self):
|
||||
pwhash = self.manager._Phpbb3Manager__gen_hash('test')
|
||||
|
||||
self.assertIsInstance(pwhash, str)
|
||||
15
allianceauth/services/modules/phpbb3/urls.py
Normal file
15
allianceauth/services/modules/phpbb3/urls.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from django.conf.urls import url, include
|
||||
|
||||
from . import views
|
||||
|
||||
module_urls = [
|
||||
# Forum Service Control
|
||||
url(r'^activate/$', views.activate_forum, name='auth_activate_phpbb3'),
|
||||
url(r'^deactivate/$', views.deactivate_forum, name='auth_deactivate_phpbb3'),
|
||||
url(r'^reset_password/$', views.reset_forum_password, name='auth_reset_phpbb3_password'),
|
||||
url(r'^set_password/$', views.set_forum_password, name='auth_set_phpbb3_password'),
|
||||
]
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^phpbb3/', include(module_urls))
|
||||
]
|
||||
109
allianceauth/services/modules/phpbb3/views.py
Normal file
109
allianceauth/services/modules/phpbb3/views.py
Normal file
@@ -0,0 +1,109 @@
|
||||
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 Phpbb3Manager
|
||||
from .models import Phpbb3User
|
||||
from .tasks import Phpbb3Tasks
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ACCESS_PERM = 'phpbb3.access_phpbb3'
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required(ACCESS_PERM)
|
||||
def activate_forum(request):
|
||||
logger.debug("activate_forum called by user %s" % request.user)
|
||||
# Valid now we get the main characters
|
||||
character = request.user.profile.main_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'],
|
||||
character.character_id)
|
||||
# if empty we failed
|
||||
if result[0] != "":
|
||||
Phpbb3User.objects.update_or_create(user=request.user, defaults={'username': result[0]})
|
||||
logger.debug("Updated authserviceinfo for user %s with forum credentials. Updating groups." % request.user)
|
||||
Phpbb3Tasks.update_groups.delay(request.user.pk)
|
||||
logger.info("Successfully activated forum for user %s" % request.user)
|
||||
messages.success(request, 'Activated forum account.')
|
||||
credentials = {
|
||||
'username': result[0],
|
||||
'password': result[1],
|
||||
}
|
||||
return render(request, 'registered/service_credentials.html',
|
||||
context={'credentials': credentials, 'service': 'Forum'})
|
||||
else:
|
||||
logger.error("Unsuccessful attempt to activate forum for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your forum account.')
|
||||
return redirect("auth_services")
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required(ACCESS_PERM)
|
||||
def deactivate_forum(request):
|
||||
logger.debug("deactivate_forum called by user %s" % request.user)
|
||||
# false we failed
|
||||
if Phpbb3Tasks.delete_user(request.user):
|
||||
logger.info("Successfully deactivated forum for user %s" % request.user)
|
||||
messages.success(request, 'Deactivated forum account.')
|
||||
else:
|
||||
logger.error("Unsuccessful attempt to activate forum for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your forum account.')
|
||||
return redirect("auth_services")
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required(ACCESS_PERM)
|
||||
def reset_forum_password(request):
|
||||
logger.debug("reset_forum_password called by user %s" % request.user)
|
||||
if Phpbb3Tasks.has_account(request.user):
|
||||
character = request.user.profile.main_character
|
||||
result = Phpbb3Manager.update_user_password(request.user.phpbb3.username, character.character_id)
|
||||
# false we failed
|
||||
if result != "":
|
||||
logger.info("Successfully reset forum password for user %s" % request.user)
|
||||
messages.success(request, 'Reset forum password.')
|
||||
credentials = {
|
||||
'username': request.user.phpbb3.username,
|
||||
'password': result,
|
||||
}
|
||||
return render(request, 'registered/service_credentials.html',
|
||||
context={'credentials': credentials, 'service': 'Forum'})
|
||||
|
||||
logger.error("Unsuccessful attempt to reset forum password for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your forum account.')
|
||||
return redirect("auth_services")
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required(ACCESS_PERM)
|
||||
def set_forum_password(request):
|
||||
logger.debug("set_forum_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 Phpbb3Tasks.has_account(request.user):
|
||||
password = form.cleaned_data['password']
|
||||
logger.debug("Form contains password of length %s" % len(password))
|
||||
character = request.user.profile.main_character
|
||||
result = Phpbb3Manager.update_user_password(request.user.phpbb3.username, character.character_id,
|
||||
password=password)
|
||||
if result != "":
|
||||
logger.info("Successfully set forum password for user %s" % request.user)
|
||||
messages.success(request, 'Set forum password.')
|
||||
else:
|
||||
logger.error("Failed to install custom forum password for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your forum account.')
|
||||
return redirect("auth_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': 'Forum'}
|
||||
return render(request, 'registered/service_password.html', context=context)
|
||||
Reference in New Issue
Block a user