From 87723493098060bb8aa1318eaccf1dc4f9f9d184 Mon Sep 17 00:00:00 2001 From: Peter Pfeufer Date: Wed, 7 Sep 2022 21:04:23 +0200 Subject: [PATCH 1/3] [ADDED] Main character name as displayed name on SMF service activation --- allianceauth/services/modules/smf/manager.py | 66 ++++++++++++++------ allianceauth/services/modules/smf/views.py | 47 ++++++++++---- 2 files changed, 84 insertions(+), 29 deletions(-) diff --git a/allianceauth/services/modules/smf/manager.py b/allianceauth/services/modules/smf/manager.py index 3293c8d3..1d406a79 100644 --- a/allianceauth/services/modules/smf/manager.py +++ b/allianceauth/services/modules/smf/manager.py @@ -5,6 +5,7 @@ from datetime import datetime import hashlib import logging import re +from typing import Tuple from packaging import version @@ -37,6 +38,8 @@ class SmfManager: SQL_DEL_USER = r"DELETE FROM %smembers where member_name = %%s" % TABLE_PREFIX + SQL_UPD_USER = r"UPDATE %smembers SET email_address = %%s, passwd = %%s, real_name = %%s WHERE member_name = %%s" % TABLE_PREFIX + SQL_DIS_USER = r"UPDATE %smembers SET email_address = %%s, passwd = %%s WHERE member_name = %%s" % TABLE_PREFIX SQL_USER_ID_FROM_USERNAME = r"SELECT id_member from %smembers WHERE member_name = %%s" % TABLE_PREFIX @@ -174,50 +177,75 @@ class SmfManager: return out @classmethod - def add_user(cls, username, email_address, groups, characterid): + def add_user(cls, username, email_address, groups, main_character: EveCharacter) -> Tuple: + """ + Add a user to SMF + :param username: + :param email_address: + :param groups: + :param main_character: + :return: + """ + + main_character_id = main_character.character_id + main_character_name = main_character.character_name + logger.debug( - f"Adding smf user with member_name {username}, " - f"email_address {email_address}, " - f"characterid {characterid}" + f"Adding smf user with member_name: {username}, " + f"email_address: {email_address}, " + f"characterid: {main_character_id}, " + f"main character: {main_character_name}" ) + cursor = connections['smf'].cursor() username_clean = cls.santatize_username(username) passwd = cls.generate_random_pass() pwhash = cls.gen_hash(username_clean, passwd) - logger.debug(f"Proceeding to add smf user {username} and pwhash starting with {pwhash[0:5]}") register_date = cls.get_current_utc_date() + + logger.debug(f"Proceeding to add smf user {username} and pwhash starting with {pwhash[0:5]}") + # check if the username was simply revoked if cls.check_user(username) is True: - logger.warning(f"Unable to add smf user with username {username} - already exists. Updating user instead.") - cls.__update_user_info(username_clean, email_address, pwhash) + logger.warning( + f"Unable to add smf user with username {username} - " + f"already exists. Updating user instead." + ) + + cls.__update_user_info( + username_clean, email_address, pwhash, main_character_name + ) else: try: smf_version = cls._get_current_smf_version() + sql_add_user_arguments = [ + username_clean, + pwhash, + email_address, + register_date, + main_character_name, + ] if version.parse(smf_version) < version.parse("2.1"): logger.debug("SMF compatibility: < 2.1") - cursor.execute( - cls.SQL_ADD_USER_SMF_20, - [username_clean, pwhash, email_address, register_date, username_clean] - ) + cursor.execute(cls.SQL_ADD_USER_SMF_20, sql_add_user_arguments) else: logger.debug("SMF compatibility: >= 2.1") - cursor.execute( - cls.SQL_ADD_USER_SMF_21, - [username_clean, pwhash, email_address, register_date, username_clean] - ) - cls.add_avatar(username_clean, characterid) + cursor.execute(cls.SQL_ADD_USER_SMF_21, sql_add_user_arguments) + + cls.add_avatar(username_clean, main_character_id) logger.info(f"Added smf member_name {username_clean}") cls.update_groups(username_clean, groups) except Exception as e: logger.warning(f"Unable to add smf user {username_clean}: {e}") pass + return username_clean, passwd @classmethod - def __update_user_info(cls, username, email_address, passwd): + def __update_user_info(cls, username, email_address, passwd, main_character_name): logger.debug( f"Updating smf user {username} info: " f"username {email_address} " @@ -225,7 +253,9 @@ class SmfManager: ) cursor = connections['smf'].cursor() try: - cursor.execute(cls.SQL_DIS_USER, [email_address, passwd, username]) + cursor.execute( + cls.SQL_UPD_USER, [email_address, passwd, main_character_name, username] + ) logger.info(f"Updated smf user {username} info") except Exception as e: logger.exception(f"Unable to update smf user {username} info. ({e})") diff --git a/allianceauth/services/modules/smf/views.py b/allianceauth/services/modules/smf/views.py index b7d26635..33bd2148 100644 --- a/allianceauth/services/modules/smf/views.py +++ b/allianceauth/services/modules/smf/views.py @@ -19,26 +19,51 @@ ACCESS_PERM = 'smf.access_smf' @login_required @permission_required(ACCESS_PERM) def activate_smf(request): - logger.debug("activate_smf called by user %s" % request.user) + logger.debug(f"activate_smf called by user {request.user}") # Valid now we get the main characters - character = request.user.profile.main_character - logger.debug(f"Adding smf user for user {request.user} with main character {character}") - result = SmfManager.add_user(SmfTasks.get_username(request.user), request.user.email, ['Member'], character.character_id) + main_character = request.user.profile.main_character + + logger.debug( + f"Adding smf user for user {request.user} with main character {main_character}" + ) + + result = SmfManager.add_user( + SmfTasks.get_username(request.user), + request.user.email, + ['Member'], + main_character, + ) + # if empty we failed if result[0] != "": - SmfUser.objects.update_or_create(user=request.user, defaults={'username': result[0]}) - logger.debug("Updated authserviceinfo for user %s with smf credentials. Updating groups." % request.user) + SmfUser.objects.update_or_create( + user=request.user, defaults={'username': result[0]} + ) + + logger.debug( + f"Updated authserviceinfo for user {request.user} " + f"with smf credentials. Updating groups." + ) + SmfTasks.update_groups.delay(request.user.pk) - logger.info("Successfully activated smf for user %s" % request.user) + + logger.info(f"Successfully activated smf for user {request.user}") + messages.success(request, _('Activated SMF account.')) credentials = { 'username': result[0], 'password': result[1], } - return render(request, 'services/service_credentials.html', context={'credentials': credentials, 'service': 'SMF'}) - else: - logger.error("Unsuccessful attempt to activate smf for user %s" % request.user) - messages.error(request, _('An error occurred while processing your SMF account.')) + + return render( + request, + 'services/service_credentials.html', + context={'credentials': credentials, 'service': 'SMF'}, + ) + + logger.error(f"Unsuccessful attempt to activate smf for user {request.user}") + messages.error(request, _('An error occurred while processing your SMF account.')) + return redirect("services:services") From cd189927fe8731195848126cc7bd899f2aace846 Mon Sep 17 00:00:00 2001 From: Peter Pfeufer Date: Wed, 7 Sep 2022 23:01:07 +0200 Subject: [PATCH 2/3] [ADDED] Update displayed name when main is changed --- .../services/modules/smf/auth_hooks.py | 6 ++++ allianceauth/services/modules/smf/manager.py | 25 ++++++++++++++ allianceauth/services/modules/smf/tasks.py | 34 +++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/allianceauth/services/modules/smf/auth_hooks.py b/allianceauth/services/modules/smf/auth_hooks.py index d2c9618d..8065e935 100644 --- a/allianceauth/services/modules/smf/auth_hooks.py +++ b/allianceauth/services/modules/smf/auth_hooks.py @@ -38,6 +38,12 @@ class SmfService(ServicesHook): if SmfTasks.has_account(user): SmfTasks.update_groups.delay(user.pk) + def sync_nickname(self, user): + logger.debug(f"Updating {self.name} displayed name for {user}") + + if SmfTasks.has_account(user): + SmfTasks.update_display_name.apply_async(args=[user.pk], countdown=5) # cooldown on this task to ensure DB clean when syncing + def update_all_groups(self): logger.debug('Update all %s groups called' % self.name) SmfTasks.update_all_groups.delay() diff --git a/allianceauth/services/modules/smf/manager.py b/allianceauth/services/modules/smf/manager.py index 1d406a79..9a3d7049 100644 --- a/allianceauth/services/modules/smf/manager.py +++ b/allianceauth/services/modules/smf/manager.py @@ -11,6 +11,8 @@ from packaging import version from django.db import connections from django.conf import settings +from django.contrib.auth.models import User + from allianceauth.eveonline.models import EveCharacter logger = logging.getLogger(__name__) @@ -40,6 +42,8 @@ class SmfManager: SQL_UPD_USER = r"UPDATE %smembers SET email_address = %%s, passwd = %%s, real_name = %%s WHERE member_name = %%s" % TABLE_PREFIX + SQL_UPD_DISPLAY_NAME = r"UPDATE %smembers SET real_name = %%s WHERE member_name = %%s" % TABLE_PREFIX + SQL_DIS_USER = r"UPDATE %smembers SET email_address = %%s, passwd = %%s WHERE member_name = %%s" % TABLE_PREFIX SQL_USER_ID_FROM_USERNAME = r"SELECT id_member from %smembers WHERE member_name = %%s" % TABLE_PREFIX @@ -273,6 +277,27 @@ class SmfManager: logger.error(f"Unable to delete smf user {username} - user not found on smf.") return False + @classmethod + def update_display_name(cls, user: User): + logger.debug(f"Updating SMF displayed name for user {user}") + cursor = connections['smf'].cursor() + smf_username = user.smf.username + + try: + display_name = user.profile.main_character.character_name + except Exception as exc: + logger.exception( + f"Unable to find a main character name for {user}, skipping... ({exc})" + ) + display_name = smf_username + + if cls.check_user(smf_username): + cursor.execute(cls.SQL_UPD_DISPLAY_NAME, [display_name, smf_username]) + logger.info(f"Updated displayed name for smf user {smf_username}") + return True + logger.error(f"Unable to update smf user {smf_username} - user not found on smf.") + return False + @classmethod def update_groups(cls, username, groups): userid = cls.get_user_id(username) diff --git a/allianceauth/services/modules/smf/tasks.py b/allianceauth/services/modules/smf/tasks.py index 580c8e86..3f6392e0 100644 --- a/allianceauth/services/modules/smf/tasks.py +++ b/allianceauth/services/modules/smf/tasks.py @@ -57,6 +57,40 @@ class SmfTasks: else: logger.debug("User does not have an smf account") + @staticmethod + @shared_task(bind=True, name="smf.update_display_name", base=QueueOnce) + def update_display_name(self, pk): + user = User.objects.get(pk=pk) + logger.debug(f"Updating SMF displayed name user {user}") + + if SmfTasks.has_account(user): + try: + if not SmfManager.update_display_name(user): + raise Exception("SMF Displayed Name Sync failed") + logger.debug(f"Updated user {user} SMF displayed name.") + return True + except SmfUser.DoesNotExist: + logger.info( + f"SMF displayed name sync failed for {user}, " + "user does not have a SMF account" + ) + except: + logger.exception( + f"SMF displayed name sync failed for {user}, retrying in 10 mins" + ) + raise self.retry(countdown=60 * 10) + else: + logger.debug(f"User {user} does not have a SMF account, skipping") + + return False + + @staticmethod + @shared_task(name="smf.update_all_display_names") + def update_all_display_names(): + logger.debug("Updating ALL SMF display names") + for smf_user in SmfUser.objects.exclude(username__exact=''): + SmfTasks.update_display_name.delay(smf_user) + @staticmethod @shared_task(name="smf.update_all_groups") def update_all_groups(): From 7a943591ec5fe191bc055730adb1cc5de29895a5 Mon Sep 17 00:00:00 2001 From: Peter Pfeufer Date: Wed, 7 Sep 2022 23:01:38 +0200 Subject: [PATCH 3/3] [ADDED] Migration to update existing user's displayed names --- .../0003_set_smf_displayed_names.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 allianceauth/services/modules/smf/migrations/0003_set_smf_displayed_names.py diff --git a/allianceauth/services/modules/smf/migrations/0003_set_smf_displayed_names.py b/allianceauth/services/modules/smf/migrations/0003_set_smf_displayed_names.py new file mode 100644 index 00000000..ea4f82a9 --- /dev/null +++ b/allianceauth/services/modules/smf/migrations/0003_set_smf_displayed_names.py @@ -0,0 +1,29 @@ +from django.db import migrations +from ..manager import SmfManager + +def on_migrate(apps, schema_editor): + SmfUser = apps.get_model("smf", "SmfUser") + db_alias = schema_editor.connection.alias + all_smf_users = SmfUser.objects.using(db_alias).all() + + for smf_user in all_smf_users: + try: + auth_user = smf_user.user + except: + pass + else: + SmfManager.update_display_name(auth_user) + +def on_migrate_zero(apps, schema_editor): + pass + + +class Migration(migrations.Migration): + + dependencies = [ + ('smf', '0002_service_permissions'), + ] + + operations = [ + migrations.RunPython(on_migrate, on_migrate_zero), + ]