From d8d663519b8e8cbdb278bf316b5ca1f78617548e Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Wed, 6 Apr 2016 16:05:54 -0500 Subject: [PATCH 01/26] fixes #364 --- stock/templates/registered/operationmanagement.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/stock/templates/registered/operationmanagement.html b/stock/templates/registered/operationmanagement.html index a878d4b8..dfd90499 100644 --- a/stock/templates/registered/operationmanagement.html +++ b/stock/templates/registered/operationmanagement.html @@ -81,13 +81,10 @@ - {% endblock content %} From cfe0e23430f5b648b3564df9e6ec5f5b331e4858 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Wed, 6 Apr 2016 20:32:02 -0500 Subject: [PATCH 02/26] SMF Forum Integration * Added SMF Forum Support * removed comment * Fixed bugs. * removed unused SQL statement * Fixed Grammer in debug code * Fixed Null Bug * Update operationmanagement.html * fixed bug * fixed error * Users now show up on the posts correctly --- alliance_auth/settings.py.example | 16 +- alliance_auth/urls.py | 7 + authentication/managers.py | 11 + authentication/models.py | 2 + celerytask/signals.py | 3 + celerytask/tasks.py | 20 ++ services/managers/smf_manager.py | 260 ++++++++++++++++++ services/views.py | 82 ++++++ .../registered/operationmanagement.html | 10 +- stock/templates/registered/services.html | 56 ++++ util/context_processors.py | 3 + 11 files changed, 464 insertions(+), 6 deletions(-) create mode 100644 services/managers/smf_manager.py diff --git a/alliance_auth/settings.py.example b/alliance_auth/settings.py.example index 4c6de4c6..d89ca0ba 100755 --- a/alliance_auth/settings.py.example +++ b/alliance_auth/settings.py.example @@ -106,6 +106,14 @@ DATABASES = { 'PASSWORD': os.environ.get('AA_DB_IPS4_PASSWORD', 'password'), 'HOST': os.environ.get('AA_DB_IPS4_HOST', '127.0.0.1'), 'PORT': os.environ.get('AA_DB_IPS4_PORT', '3306'), + }, + 'smf': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'alliance_smf', + 'USER': os.environ.get('AA_DB_SMF_USER', 'allianceserver'), + 'PASSWORD': os.environ.get('AA_DB_SMF_PASSWORD', 'password'), + 'HOST': os.environ.get('AA_DB_SMF_HOST', '127.0.0.1'), + 'PORT': os.environ.get('AA_DB_SMF_PORT', '3306'), } } @@ -206,10 +214,12 @@ EMAIL_USE_TLS = 'True' == os.environ.get('AA_EMAIL_USE_TLS', 'True') # KILLBOARD_URL - URL for your killboard. Blank to hide link # MEDIA_URL - URL for your media page (youtube etc). Blank to hide link # FORUM_URL - URL for your forums. Blank to hide link +# SMF_URL - URL for your SMF forums. #################### KILLBOARD_URL = os.environ.get('AA_KILLBOARD_URL', '') EXTERNAL_MEDIA_URL = os.environ.get('AA_EXTERNAL_MEDIA_URL', '') FORUM_URL = os.environ.get('AA_FORUM_URL', '') +SMF_URL = os.environ.get('AA_SMF_URL', '') ######################### # Default Group Settings @@ -235,6 +245,7 @@ BLUE_ALLIANCE_GROUPS = 'True' == os.environ.get('AA_BLUE_ALLIANCE_GROUPS', 'Fals # ENABLE_AUTH_IPBOARD - Enable IPBoard forum support in the auth for auth'd members # ENABLE_AUTH_DISCORD - Enable Discord support in the auth for auth'd members # ENABLE_AUTH_IPS4 - Enable IPS4 support in the auth for auth'd members +# ENABLE_AUTH_SMF - Enable SMF forum support in the auth for auth'd members ######################### ENABLE_AUTH_FORUM = 'True' == os.environ.get('AA_ENABLE_AUTH_FORUM', 'False') ENABLE_AUTH_JABBER = 'True' == os.environ.get('AA_ENABLE_AUTH_JABBER', 'False') @@ -243,6 +254,7 @@ ENABLE_AUTH_IPBOARD = 'True' == os.environ.get('AA_ENABLE_AUTH_IPBOARD', 'False' ENABLE_AUTH_TEAMSPEAK3 = 'True' == os.environ.get('AA_ENABLE_AUTH_TEAMSPEAK3', 'False') ENABLE_AUTH_DISCORD = 'True' == os.environ.get('AA_ENABLE_AUTH_DISCORD', 'False') ENABLE_AUTH_IPS4 = 'True' == os.environ.get('AA_ENABLE_AUTH_IPS4', 'False') +ENABLE_AUTH_SMF = 'True' == os.environ.get('AA_ENABLE_AUTH_SMF', 'False') ##################### # Blue service Setup @@ -253,7 +265,8 @@ ENABLE_AUTH_IPS4 = 'True' == os.environ.get('AA_ENABLE_AUTH_IPS4', 'False') # ENABLE_BLUE_MUMBLE - Enable mumble support in the auth for blues # ENABLE_BLUE_IPBOARD - Enable IPBoard forum support in the auth for blues # ENABLE_BLUE_DISCORD - Enable Discord support in the auth for blues -# ENABLE_BLUE_IPS4 - Enable IPS4 support in the auth for blues +# ENABLE_BLUE_IPS4 - Enable IPS4 forum support in the auth for blues +# ENABLE_BLUE_SMF - Enable SMF forum support in the auth for blues ##################### BLUE_STANDING = float(os.environ.get('AA_BLUE_STANDING', '5.0')) ENABLE_BLUE_FORUM = 'True' == os.environ.get('AA_ENABLE_BLUE_FORUM', 'False') @@ -263,6 +276,7 @@ ENABLE_BLUE_IPBOARD = 'True' == os.environ.get('AA_ENABLE_BLUE_IPBOARD', 'False' ENABLE_BLUE_TEAMSPEAK3 = 'True' == os.environ.get('AA_ENABLE_BLUE_TEAMSPEAK3', 'False') ENABLE_BLUE_DISCORD = 'True' == os.environ.get('AA_ENABLE_BLUE_DISCORD', 'False') ENABLE_BLUE_IPS4 = 'True' == os.environ.get('AA_ENABLE_BLUE_IPS4', 'False') +ENABLE_BLUE_SMF = 'True' == os.environ.get('AA_ENABLE_BLUE_SMF', 'False') ######################### # Corp Configuration diff --git a/alliance_auth/urls.py b/alliance_auth/urls.py index 52b2c157..ad22c0e0 100755 --- a/alliance_auth/urls.py +++ b/alliance_auth/urls.py @@ -146,6 +146,13 @@ urlpatterns = patterns('', name='auth_reset_ips4_password'), url(r'^set_ips4_password/$', 'services.views.set_ips4_password', name='auth_set_ips4_password'), + # SMF Service Control + url(r'^activate_smf/$', 'services.views.activate_smf', name='auth_activate_smf'), + url(r'^deactivate_smf/$', 'services.views.deactivate_smf', name='auth_deactivate_smf'), + url(r'^reset_smf_password/$', 'services.views.reset_smf_password', + name='auth_reset_smf_password'), + url(r'^set_smf_password/$', 'services.views.set_smf_password', name='auth_set_smf_password'), + # Tools url(r'^tool/fleet_formatter_tool/$', 'services.views.fleet_formatter_view', name='auth_fleet_format_tool_view'), diff --git a/authentication/managers.py b/authentication/managers.py index 74f0a825..91332899 100755 --- a/authentication/managers.py +++ b/authentication/managers.py @@ -135,3 +135,14 @@ class AuthServicesInfoManager: else: logger.error("Failed to update user %s IPS4 info: user does not exist." % user) + @staticmethod + def update_user_smf_info(username, password, user): + if User.objects.filter(username=user.username).exists(): + logger.debug("Updating user %s forum info: username %s" % (user, username)) + authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo.smf_username = username + authserviceinfo.smf_password = password + authserviceinfo.save(update_fields=['smf_username', 'smf_password']) + logger.info("Updated user %s smf info in authservicesinfo model." % user) + else: + logger.error("Failed to update user %s smf info: user does not exist." % user) diff --git a/authentication/models.py b/authentication/models.py index 70269410..ce6c0172 100755 --- a/authentication/models.py +++ b/authentication/models.py @@ -17,6 +17,8 @@ class AuthServicesInfo(models.Model): ips4_username = models.CharField(max_length=254, blank=True, default="") ips4_password = models.CharField(max_length=254, blank=True, default="") ips4_id = models.CharField(max_length=254, blank=True, default="") + smf_username = models.CharField(max_length=254, blank=True, default="") + smf_password = models.CharField(max_length=254, blank=True, default="") main_char_id = models.CharField(max_length=64, blank=True, default="") is_blue = models.BooleanField(default=False) user = models.ForeignKey(User) diff --git a/celerytask/signals.py b/celerytask/signals.py index d4ea2103..9ca9954a 100644 --- a/celerytask/signals.py +++ b/celerytask/signals.py @@ -10,6 +10,7 @@ from .tasks import update_forum_groups from .tasks import update_ipboard_groups from .tasks import update_discord_groups from .tasks import update_teamspeak3_groups +from .tasks import update_smf_groups from authentication.models import AuthServicesInfo from services.models import AuthTS @@ -27,6 +28,8 @@ def m2m_changed_user_groups(sender, instance, action, *args, **kwargs): update_teamspeak3_groups.delay(instance.pk) if auth.forum_username: update_forum_groups.delay(instance.pk) + if auth.smf_username: + update_smf_groups.delay(instance.pk) if auth.ipboard_username: update_ipboard_groups.delay(instance.pk) if auth.discord_uid: diff --git a/celerytask/tasks.py b/celerytask/tasks.py index a369da55..8bff12b0 100755 --- a/celerytask/tasks.py +++ b/celerytask/tasks.py @@ -11,6 +11,7 @@ from services.managers.phpbb3_manager import Phpbb3Manager from services.managers.ipboard_manager import IPBoardManager from services.managers.teamspeak3_manager import Teamspeak3Manager from services.managers.discord_manager import DiscordManager, DiscordAPIManager +from services.managers.smf_manager import smfManager from services.models import AuthTS from services.models import TSgroup from authentication.models import AuthServicesInfo @@ -107,6 +108,25 @@ def update_forum_groups(pk): raise self.retry(countdown = 60 * 10) logger.debug("Updated user %s forum groups." % user) +@task +def update_smf_groups(pk): + user = User.objects.get(pk=pk) + logger.debug("Updating smf groups for user %s" % user) + authserviceinfo = AuthServicesInfo.objects.get(user=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 smf groups to %s" % (user, groups)) + try: + smfManager.update_groups(authserviceinfo.smf_username, groups) + except: + logger.exception("smf group sync failed for %s, retrying in 10 mins" % user) + raise self.retry(countdown = 60 * 10) + logger.debug("Updated user %s smf groups." % user) + + @task def update_ipboard_groups(pk): user = User.objects.get(pk=pk) diff --git a/services/managers/smf_manager.py b/services/managers/smf_manager.py new file mode 100644 index 00000000..7ef93add --- /dev/null +++ b/services/managers/smf_manager.py @@ -0,0 +1,260 @@ +import os +import calendar +from datetime import datetime +import hashlib +import logging + +from django.db import connections +from django.conf import settings + +logger = logging.getLogger(__name__) + +class smfManager: + SQL_ADD_USER = r"INSERT INTO smf_members (member_name, passwd, email_address, date_registered, real_name," \ + r" buddy_list, message_labels, openid_uri, signature, ignore_boards) " \ + r"VALUES (%s, %s, %s, %s, %s, 0, 0, 0, 0, 0)" + + SQL_DEL_USER = r"DELETE FROM smf_members where member_name = %s" + + SQL_DIS_USER = r"UPDATE smf_members SET email_address = %s, passwd = %s WHERE member_name = %s" + + SQL_USER_ID_FROM_USERNAME = r"SELECT id_member from smf_members WHERE member_name = %s" + + SQL_ADD_USER_GROUP = r"UPDATE smf_members SET additional_groups = %s WHERE id_member = %s" + + SQL_GET_GROUP_ID = r"SELECT id_group from smf_membergroups WHERE group_name = %s" + + SQL_ADD_GROUP = r"INSERT INTO smf_membergroups (group_name,description) VALUES (%s,%s)" + + SQL_UPDATE_USER_PASSWORD = r"UPDATE smf_members SET passwd = %s WHERE member_name = %s" + + SQL_REMOVE_USER_GROUP = r"UPDATE smf_members SET additional_groups = %s WHERE id_member = %s" + + SQL_GET_ALL_GROUPS = r"SELECT id_group, group_name FROM smf_membergroups" + + SQL_GET_USER_GROUPS = r"SELECT additional_groups FROM smf_members WHERE id_member = %s" + + SQL_ADD_USER_AVATAR = r"UPDATE smf_members SET avatar = %s WHERE id_member = %s" + + + + @staticmethod + def generate_random_pass(): + return os.urandom(8).encode('hex') + + @staticmethod + def gen_hash(username_clean, passwd): + return hashlib.sha1((username_clean) + passwd).hexdigest() + + @staticmethod + def santatize_username(username): + sanatized = username.replace(" ", "_") + sanatized = sanatized.replace("'", "") + return sanatized.lower() + + @staticmethod + def get_current_utc_date(): + d = datetime.utcnow() + unixtime = calendar.timegm(d.utctimetuple()) + return unixtime + + @staticmethod + def create_group(groupname): + logger.debug("Creating smf group %s" % groupname) + cursor = connections['smf'].cursor() + cursor.execute(smfManager.SQL_ADD_GROUP, [groupname, groupname]) + logger.info("Created smf group %s" % groupname) + return smfManager.get_group_id(groupname) + + + @staticmethod + def get_group_id(groupname): + logger.debug("Getting smf group id for groupname %s" % groupname) + cursor = connections['smf'].cursor() + cursor.execute(smfManager.SQL_GET_GROUP_ID, [groupname]) + row = cursor.fetchone() + logger.debug("Got smf group id %s for groupname %s" % (row[0], groupname)) + return row[0] + + @staticmethod + def check_user(username): + logger.debug("Checking smf username %s" % username) + cursor = connections['smf'].cursor() + cursor.execute(smfManager.SQL_USER_ID_FROM_USERNAME, [smfManager.santatize_username(username)]) + row = cursor.fetchone() + if row: + logger.debug("Found user %s on smf" % username) + return True + logger.debug("User %s not found on smf" % username) + return False + + + @staticmethod + def add_avatar(member_name, characterid): + logger.debug("Adding EVE character id %s portrait as smf avatar for user %s" % (characterid, member_name)) + avatar_url = "https://image.eveonline.com/Character/" + characterid + "_64.jpg" + cursor = connections['smf'].cursor() + id_member = smfManager.get_user_id(member_name) + cursor.execute(smfManager.SQL_ADD_USER_AVATAR, [avatar_url, id_member]) + + @staticmethod + def get_user_id(username): + logger.debug("Getting smf user id for username %s" % username) + cursor = connections['smf'].cursor() + cursor.execute(smfManager.SQL_USER_ID_FROM_USERNAME, [username]) + row = cursor.fetchone() + if row is not None: + logger.debug("Got smf user id %s for username %s" % (row[0], username)) + return row[0] + else: + logger.error("username %s not found on smf. Unable to determine user id ." % username) + return None + + @staticmethod + def get_all_groups(): + logger.debug("Getting all smf groups.") + cursor = connections['smf'].cursor() + cursor.execute(smfManager.SQL_GET_ALL_GROUPS) + rows = cursor.fetchall() + out = {} + for row in rows: + out[row[1]] = row[0] + logger.debug("Got smf groups %s" % out) + return out + + @staticmethod + def get_user_groups(userid): + logger.debug("Getting smf user id %s groups" % userid) + cursor = connections['smf'].cursor() + cursor.execute(smfManager.SQL_GET_USER_GROUPS, [userid]) + out = [row[0] for row in cursor.fetchall()] + logger.debug("Got user %s smf groups %s" % (userid, out)) + return out + + @staticmethod + def add_user(username, email_address, groups, characterid): + logger.debug("Adding smf user with member_name %s, email_address %s, characterid %s" % (username, email_address, characterid)) + cursor = connections['smf'].cursor() + username_clean = smfManager.santatize_username(username) + passwd = smfManager.generate_random_pass() + pwhash = smfManager.gen_hash(username_clean, passwd) + logger.debug("Proceeding to add smf user %s and pwhash starting with %s" % (username, pwhash[0:5])) + register_date = smfManager.get_current_utc_date() + # check if the username was simply revoked + if smfManager.check_user(username)is True : + logger.warn("Unable to add smf user with username %s - already exists. Updating user instead." % username) + smfManager.__update_user_info(username_clean, email_address, pwhash) + else: + try: + cursor.execute(smfManager.SQL_ADD_USER, [username_clean, passwd, email_address, register_date, username_clean]) + smfManager.add_avatar(username_clean, characterid) + logger.info("Added smf member_name %s" % username_clean) + smfManager.update_groups(username_clean, groups) + except: + logger.warn("Unable to add smf user %s" % username_clean) + pass + return username_clean, passwd + + @staticmethod + def __update_user_info(username, email_address, passwd): + logger.debug("Updating smf user %s info: username %s password of length %s" % (username, email_address, len(passwd))) + cursor = connections['smf'].cursor() + try: + cursor.execute(smfManager.SQL_DIS_USER, [email_address, passwd, username]) + logger.info("Updated smf user %s info" % username) + except: + logger.exception("Unable to update smf user %s info." % username) + pass + + @staticmethod + def delete_user(username): + logger.debug("Deleting smf user %s" % username) + cursor = connections['smf'].cursor() + + if smfManager.check_user(username): + cursor.execute(smfManager.SQL_DEL_USER, [username]) + logger.info("Deleted smf user %s" % username) + return True + logger.error("Unable to delete smf user %s - user not found on smf." % username) + return False + + @staticmethod + def update_groups(username, groups): + userid = smfManager.get_user_id(username) + logger.debug("Updating smf user %s with id %s groups %s" % (username, userid, groups)) + if userid is not None: + forum_groups = smfManager.get_all_groups() + user_groups = set(smfManager.get_user_groups(userid)) + act_groups = set([g.replace(' ', '-') for g in groups]) + addgroups = act_groups - user_groups + remgroups = user_groups - act_groups + logger.info("Updating smf user %s groups - adding %s, removing %s" % (username, addgroups, remgroups)) + act_group_id = set() + for g in addgroups: + if not g in forum_groups: + forum_groups[g] = smfManager.create_group(g) + act_group_id.add(str(smfManager.get_group_id(g))) + string_groups = ','.join(act_group_id) + smfManager.add_user_to_group(userid, string_groups) + + + @staticmethod + def add_user_to_group(userid, groupid): + logger.debug("Adding smf user id %s to group id %s" % (userid, groupid)) + try: + cursor = connections['smf'].cursor() + cursor.execute(smfManager.SQL_ADD_USER_GROUP, [groupid, userid]) + logger.info("Added smf user id %s to group id %s" % (userid, groupid)) + except: + logger.exception("Unable to add smf user id %s to group id %s" % (userid, groupid)) + pass + + @staticmethod + def remove_user_from_group(userid, groupid): + logger.debug("Removing smf user id %s from group id %s" % (userid, groupid)) + try: + cursor = connections['smf'].cursor() + cursor.execute(smfManager.SQL_REMOVE_USER_GROUP, [groupid, userid]) + logger.info("Removed smf user id %s from group id %s" % (userid, groupid)) + except: + logger.exception("Unable to remove smf user id %s from group id %s" % (userid, groupid)) + pass + + @staticmethod + def disable_user(username): + logger.debug("Disabling smf user %s" % username) + cursor = connections['smf'].cursor() + + password = smfManager.generate_random_pass() + revoke_email = "revoked@" + settings.DOMAIN + try: + pwhash = smfManager.gen_hash(username, password) + cursor.execute(smfManager.SQL_DIS_USER, [revoke_email, pwhash, username]) + userid = smfManager.get_user_id(username) + smfManager.update_groups(username, []) + logger.info("Disabled smf user %s" % username) + return True + except TypeError as e: + logger.exception("TypeError occured while disabling user %s - failed to disable." % username) + return False + + @staticmethod + def update_user_password(username, characterid, password=None): + logger.debug("Updating smf user %s password" % username) + cursor = connections['smf'].cursor() + if not password: + password = smfManager.generate_random_pass() + if smfManager.check_user(username): + username_clean = smfManager.santatize_username(username) + pwhash = smfManager.gen_hash(username_clean, password) + logger.debug("Proceeding to update smf user %s password with pwhash starting with %s" % (username, pwhash[0:5])) + cursor.execute(smfManager.SQL_UPDATE_USER_PASSWORD, [pwhash, username]) + smfManager.add_avatar(username, characterid) + logger.info("Updated smf user %s password." % username) + return password + logger.error("Unable to update smf user %s password - user not found on smf." % username) + return "" + + + + diff --git a/services/views.py b/services/views.py index 124efc2f..e5ba42f0 100755 --- a/services/views.py +++ b/services/views.py @@ -15,12 +15,14 @@ from managers.ipboard_manager import IPBoardManager from managers.teamspeak3_manager import Teamspeak3Manager from managers.discord_manager import DiscordManager from managers.ips4_manager import Ips4Manager +from managers.smf_manager import smfManager from authentication.managers import AuthServicesInfoManager from eveonline.managers import EveManager from celerytask.tasks import update_jabber_groups from celerytask.tasks import update_mumble_groups from celerytask.tasks import update_forum_groups from celerytask.tasks import update_ipboard_groups +from celerytask.tasks import update_smf_groups from celerytask.tasks import update_teamspeak3_groups from celerytask.tasks import update_discord_groups from forms import JabberBroadcastForm @@ -683,3 +685,83 @@ def deactivate_ips4(request): return HttpResponseRedirect("/services/") logger.error("Unsuccesful attempt to deactivate IPS4 for user %s" % request.user) return HttpResponseRedirect("/dashboard") + +@login_required +@user_passes_test(service_blue_alliance_test) +def activate_smf(request): + logger.debug("activate_smf called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + # Valid now we get the main characters + character = EveManager.get_character_by_id(authinfo.main_char_id) + logger.debug("Adding smf user for user %s with main character %s" % (request.user, character)) + result = smfManager.add_user(character.character_name, request.user.email, ['Member'], authinfo.main_char_id) + # if empty we failed + if result[0] != "": + AuthServicesInfoManager.update_user_smf_info(result[0], result[1], request.user) + logger.debug("Updated authserviceinfo for user %s with smf credentials. Updating groups." % request.user) + update_smf_groups.delay(request.user.pk) + logger.info("Succesfully activated smf for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccesful attempt to activate smf for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + + +@login_required +@user_passes_test(service_blue_alliance_test) +def deactivate_smf(request): + logger.debug("deactivate_smf called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = smfManager.disable_user(authinfo.smf_username) + # false we failed + if result: + AuthServicesInfoManager.update_user_smf_info("", "", request.user) + logger.info("Succesfully deactivated smf for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccesful attempt to activate smf for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + + +@login_required +@user_passes_test(service_blue_alliance_test) +def reset_smf_password(request): + logger.debug("reset_smf_password called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = smfManager.update_user_password(authinfo.smf_username, authinfo.main_char_id) + # false we failed + if result != "": + AuthServicesInfoManager.update_user_smf_info(authinfo.smf_username, result, request.user) + logger.info("Succesfully reset smf password for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccessful attempt to reset smf password for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + +@login_required +@user_passes_test(service_blue_alliance_test) +def set_smf_password(request): + logger.debug("set_smf_password called by user %s" % request.user) + error = None + 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(): + password = form.cleaned_data['password'] + logger.debug("Form contains password of length %s" % len(password)) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = smfManager.update_user_password(authinfo.smf_username, authinfo.main_char_id, password=password) + if result != "": + AuthServicesInfoManager.update_user_smf_info(authinfo.smf_username, result, request.user) + logger.info("Succesfully reset smf password for user %s" % request.user) + return HttpResponseRedirect("/services/") + else: + logger.error("Failed to install custom smf password for user %s" % request.user) + error = "Failed to install custom password." + else: + error = "Invalid 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': 'Forum'} + return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) diff --git a/stock/templates/registered/operationmanagement.html b/stock/templates/registered/operationmanagement.html index dfd90499..6902fd31 100644 --- a/stock/templates/registered/operationmanagement.html +++ b/stock/templates/registered/operationmanagement.html @@ -40,7 +40,7 @@ Action {% endif %} - + {% for ops in optimer %} {{ ops.operation_name }} @@ -54,7 +54,7 @@ {{ ops.duration }} {{ ops.fc }} {{ ops.details }} - {{ ops.post_time}} + {{ ops.post_time}} {% if perms.auth.optimer_management %} {{ ops.eve_character }} @@ -67,15 +67,15 @@ class="glyphicon glyphicon-pencil"> - - + + {% endif %} {% endfor %} - + diff --git a/stock/templates/registered/services.html b/stock/templates/registered/services.html index 18fa422a..1e5bb23c 100755 --- a/stock/templates/registered/services.html +++ b/stock/templates/registered/services.html @@ -45,6 +45,33 @@ {% endifequal %} {% endif %} + {% if ENABLE_BLUE_SMF %} + SMF Forums + {{ authinfo.smf_username }} + {{ authinfo.smf_password }} + {{ SMF_URL }} + + {% ifequal authinfo.smf_username "" %} + + + + {% else %} + + + + + + + + + + {% endifequal %} + + {% endif %} {% if ENABLE_BLUE_IPBOARD %} IPBoard Forums {{ authinfo.ipboard_username }} @@ -260,6 +287,35 @@ {% endif %} + {% if ENABLE_AUTH_SMF %} + + SMF Forums + {{ authinfo.smf_username }} + {{ authinfo.smf_password }} + {{ SMF_URL }} + + {% ifequal authinfo.smf_username "" %} + + + + {% else %} + + + + + + + + + + {% endifequal %} + + + {% endif %} {% if ENABLE_AUTH_IPBOARD %} IPBoard Forums {{ authinfo.ipboard_username }} diff --git a/util/context_processors.py b/util/context_processors.py index 315c6424..02572ddc 100755 --- a/util/context_processors.py +++ b/util/context_processors.py @@ -38,6 +38,7 @@ def domain_url(request): 'ENABLE_AUTH_TEAMSPEAK3': settings.ENABLE_AUTH_TEAMSPEAK3, 'ENABLE_AUTH_DISCORD': settings.ENABLE_AUTH_DISCORD, 'ENABLE_AUTH_IPS4': settings.ENABLE_AUTH_IPS4, + 'ENABLE_AUTH_SMF': settings.ENABLE_AUTH_SMF, 'ENABLE_BLUE_JABBER': settings.ENABLE_BLUE_JABBER, 'ENABLE_BLUE_FORUM': settings.ENABLE_BLUE_FORUM, 'ENABLE_BLUE_MUMBLE': settings.ENABLE_BLUE_MUMBLE, @@ -45,10 +46,12 @@ def domain_url(request): 'ENABLE_BLUE_TEAMSPEAK3': settings.ENABLE_BLUE_TEAMSPEAK3, 'ENABLE_BLUE_DISCORD': settings.ENABLE_BLUE_DISCORD, 'ENABLE_BLUE_IPS4': settings.ENABLE_BLUE_IPS4, + 'ENABLE_BLUE_SMF': settings.ENABLE_BLUE_SMF, 'TEAMSPEAK3_PUBLIC_URL': settings.TEAMSPEAK3_PUBLIC_URL, 'JACK_KNIFE_URL': settings.JACK_KNIFE_URL, 'DISCORD_SERVER_ID': settings.DISCORD_SERVER_ID, 'KILLBOARD_URL': settings.KILLBOARD_URL, 'IPS4_URL': settings.IPS4_URL, + 'SMF_URL': settings.SMF_URL, 'EXTERNAL_MEDIA_URL': settings.EXTERNAL_MEDIA_URL, 'CURRENT_UTC_TIME': timezone.now()} From 6f8e478bafd066da33b228fe2473ab6b4c42da49 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Thu, 7 Apr 2016 20:46:14 -0500 Subject: [PATCH 03/26] Evernus Alliance Market Integration (#369) * Added SMF Forum Support * removed comment * Fixed bugs. * removed unused SQL statement * Fixed Grammer in debug code * Fixed Null Bug * Update operationmanagement.html * fixed bug * fixed error * Users now show up on the posts correctly * Evernus Alliance Market Integration * removed duplicate function * empty string handling --- alliance_auth/settings.py.example | 19 +++ alliance_auth/urls.py | 7 ++ authentication/managers.py | 12 ++ authentication/models.py | 2 + services/managers/market_manager.py | 145 +++++++++++++++++++++++ services/views.py | 82 ++++++++++++- stock/templates/registered/services.html | 54 +++++++++ util/context_processors.py | 3 + 8 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 services/managers/market_manager.py diff --git a/alliance_auth/settings.py.example b/alliance_auth/settings.py.example index d89ca0ba..977cd9c0 100755 --- a/alliance_auth/settings.py.example +++ b/alliance_auth/settings.py.example @@ -107,6 +107,7 @@ DATABASES = { 'HOST': os.environ.get('AA_DB_IPS4_HOST', '127.0.0.1'), 'PORT': os.environ.get('AA_DB_IPS4_PORT', '3306'), }, + 'smf': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'alliance_smf', @@ -114,6 +115,15 @@ DATABASES = { 'PASSWORD': os.environ.get('AA_DB_SMF_PASSWORD', 'password'), 'HOST': os.environ.get('AA_DB_SMF_HOST', '127.0.0.1'), 'PORT': os.environ.get('AA_DB_SMF_PORT', '3306'), + }, + + 'market': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'alliance_market', + 'USER': os.environ.get('AA_DB_MARKET_USER', 'allianceserver'), + 'PASSWORD': os.environ.get('AA_DB_MARKET_PASSWORD', 'password'), + 'HOST': os.environ.get('AA_DB_MARKET_HOST', '127.0.0.1'), + 'PORT': os.environ.get('AA_DB_MARKET_PORT', '3306'), } } @@ -246,6 +256,7 @@ BLUE_ALLIANCE_GROUPS = 'True' == os.environ.get('AA_BLUE_ALLIANCE_GROUPS', 'Fals # ENABLE_AUTH_DISCORD - Enable Discord support in the auth for auth'd members # ENABLE_AUTH_IPS4 - Enable IPS4 support in the auth for auth'd members # ENABLE_AUTH_SMF - Enable SMF forum support in the auth for auth'd members +# ENABLE_AUTH_MARKET = Enable Alliance Market support in auth for auth'd members ######################### ENABLE_AUTH_FORUM = 'True' == os.environ.get('AA_ENABLE_AUTH_FORUM', 'False') ENABLE_AUTH_JABBER = 'True' == os.environ.get('AA_ENABLE_AUTH_JABBER', 'False') @@ -255,6 +266,7 @@ ENABLE_AUTH_TEAMSPEAK3 = 'True' == os.environ.get('AA_ENABLE_AUTH_TEAMSPEAK3', ' ENABLE_AUTH_DISCORD = 'True' == os.environ.get('AA_ENABLE_AUTH_DISCORD', 'False') ENABLE_AUTH_IPS4 = 'True' == os.environ.get('AA_ENABLE_AUTH_IPS4', 'False') ENABLE_AUTH_SMF = 'True' == os.environ.get('AA_ENABLE_AUTH_SMF', 'False') +ENABLE_AUTH_MARKET = 'True' == os.environ.get('AA_ENABLE_AUTH_MARKET', 'False') ##################### # Blue service Setup @@ -267,6 +279,7 @@ ENABLE_AUTH_SMF = 'True' == os.environ.get('AA_ENABLE_AUTH_SMF', 'False') # ENABLE_BLUE_DISCORD - Enable Discord support in the auth for blues # ENABLE_BLUE_IPS4 - Enable IPS4 forum support in the auth for blues # ENABLE_BLUE_SMF - Enable SMF forum support in the auth for blues +# ENABLE_BLUE_MARKET - Enable Alliance Market in the auth for blues ##################### BLUE_STANDING = float(os.environ.get('AA_BLUE_STANDING', '5.0')) ENABLE_BLUE_FORUM = 'True' == os.environ.get('AA_ENABLE_BLUE_FORUM', 'False') @@ -277,6 +290,7 @@ ENABLE_BLUE_TEAMSPEAK3 = 'True' == os.environ.get('AA_ENABLE_BLUE_TEAMSPEAK3', ' ENABLE_BLUE_DISCORD = 'True' == os.environ.get('AA_ENABLE_BLUE_DISCORD', 'False') ENABLE_BLUE_IPS4 = 'True' == os.environ.get('AA_ENABLE_BLUE_IPS4', 'False') ENABLE_BLUE_SMF = 'True' == os.environ.get('AA_ENABLE_BLUE_SMF', 'False') +ENABLE_BLUE_MARKET = 'True' == os.environ.get('AA_ENABLE_BLUE_MARKET', 'False') ######################### # Corp Configuration @@ -314,6 +328,11 @@ MEMBER_API_ACCOUNT = 'True' == os.environ.get('AA_MEMBER_API_ACCOUNT', 'True') BLUE_API_MASK = os.environ.get('AA_BLUE_API_MASK', 8388608) BLUE_API_ACCOUNT = 'True' == os.environ.get('AA_BLUE_API_ACCOUNT', 'False') +##################### +# Alliance Market +##################### +MARKET_URL = os.environ.get('AA_MARKET_URL', 'http://yourdomain.com/market') + ##################### # HR Configuration ##################### diff --git a/alliance_auth/urls.py b/alliance_auth/urls.py index ad22c0e0..6016057c 100755 --- a/alliance_auth/urls.py +++ b/alliance_auth/urls.py @@ -153,6 +153,13 @@ urlpatterns = patterns('', name='auth_reset_smf_password'), url(r'^set_smf_password/$', 'services.views.set_smf_password', name='auth_set_smf_password'), + # Alliance Market Control + url(r'^activate_market/$', 'services.views.activate_market', name='auth_activate_market'), + url(r'^deactivate_market/$', 'services.views.deactivate_market', name='auth_deactivate_market'), + url(r'^reset_market_password/$', 'services.views.reset_market_password', + name='auth_reset_market_password'), + url(r'^set_market_password/$', 'services.views.set_market_password', name='auth_set_market_password'), + # Tools url(r'^tool/fleet_formatter_tool/$', 'services.views.fleet_formatter_view', name='auth_fleet_format_tool_view'), diff --git a/authentication/managers.py b/authentication/managers.py index 91332899..5ce01acf 100755 --- a/authentication/managers.py +++ b/authentication/managers.py @@ -146,3 +146,15 @@ class AuthServicesInfoManager: logger.info("Updated user %s smf info in authservicesinfo model." % user) else: logger.error("Failed to update user %s smf info: user does not exist." % user) + + @staticmethod + def update_user_market_info(username, password, user): + if User.objects.filter(username=user.username).exists(): + logger.debug("Updating user %s market info: username %s" % (user, username)) + authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo.market_username = username + authserviceinfo.market_password = password + authserviceinfo.save(update_fields=['market_username', 'market_password']) + logger.info("Updated user %s market info in authservicesinfo model." % user) + else: + logger.error("Failed to update user %s market info: user does not exist." % user) diff --git a/authentication/models.py b/authentication/models.py index ce6c0172..5a7df68b 100755 --- a/authentication/models.py +++ b/authentication/models.py @@ -19,6 +19,8 @@ class AuthServicesInfo(models.Model): ips4_id = models.CharField(max_length=254, blank=True, default="") smf_username = models.CharField(max_length=254, blank=True, default="") smf_password = models.CharField(max_length=254, blank=True, default="") + market_username = models.CharField(max_length=254, blank=True, default="") + market_password = models.CharField(max_length=254, blank=True, default="") main_char_id = models.CharField(max_length=64, blank=True, default="") is_blue = models.BooleanField(default=False) user = models.ForeignKey(User) diff --git a/services/managers/market_manager.py b/services/managers/market_manager.py new file mode 100644 index 00000000..e2d64338 --- /dev/null +++ b/services/managers/market_manager.py @@ -0,0 +1,145 @@ +import logging +from django.conf import settings +import requests +import os + +from django.db import connections +from passlib.hash import bcrypt +## requires yum install libffi-devel and pip install bcrypt + +logger = logging.getLogger(__name__) + +class marketManager: + + SQL_ADD_USER = r"INSERT INTO fos_user (username, username_canonical, email, email_canonical, enabled, salt, password," \ + r"locked, expired, roles, credentials_expired, characterid, characterName)" \ + r"VALUES (%s, %s, %s, %s, 1,%s, %s, 0, 0, 'a:0:{}', 0, %s, %s) " + SQL_GET_USER_ID = r"SELECT id FROM fos_user WHERE username = %s" + SQL_DISABLE_USER = r"UPDATE fos_user SET enabled = '0' WHERE username = %s" + SQL_ENABLE_USER = r"UPDATE fos_user SET enabled = '1' WHERE username = %s" + SQL_UPDATE_PASSWORD = r"UPDATE fos_user SET password = %s, salt = %s WHERE username = %s" + SQL_CHECK_EMAIL = r"SELECT email FROM fos_user WHERE email = %s" + SQL_CHECK_USERNAME = r"SELECT username FROM fos_user WHERE username = %s" + SQL_UPDATE_USER = r"UPDATE fos_user SET password = %s, salt = %s, enabled = '1' WHERE username = %s" + + + @staticmethod + def __santatize_username(username): + sanatized = username.replace(" ", "_") + sanatized = sanatized.replace("'", "") + return sanatized.lower() + + @staticmethod + def __generate_random_pass(): + return os.urandom(8).encode('hex') + + @staticmethod + def check_username(username): + logger.debug("Checking alliance market username %s" % username) + cursor = connections['market'].cursor() + cursor.execute(marketManager.SQL_CHECK_USERNAME, [marketManager.__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 + + @staticmethod + def check_user_email(username, email): + logger.debug("Checking if alliance market email exists for user %s" % username) + cursor = connections['market'].cursor() + cursor.execute(marketManager.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 + + + @staticmethod + def add_user(username, email, characterid, charactername): + logger.debug("Adding new market user %s" % username) + plain_password = marketManager.__generate_random_pass() + hash = bcrypt.encrypt(plain_password, rounds=13) + hash_result = hash + rounds_striped = hash_result.strip('$2a$13$') + salt = rounds_striped[:22] + username_clean = marketManager.__santatize_username(username) + if marketManager.check_username(username)== False: + if marketManager.check_user_email(username, email) == False: + try: + logger.debug("Adding user %s to alliance market" % username) + cursor = connections['market'].cursor() + cursor.execute(marketManager.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 = marketManager.update_user_info(username) + return username_clean, password + else: + logger.debug("Alliance market username %s already exists Updating instead" % username) + username_clean, password = marketManager.update_user_info(username) + return username_clean, password + + @staticmethod + def disable_user(username): + logger.debug("Disabling alliance market user %s " % username) + cursor = connections['market'].cursor() + cursor.execute(marketManager.SQL_DISABLE_USER, [username]) + return True + + @staticmethod + def update_custom_password(username, plain_password): + logger.debug("Updating alliance market user %s password" % username) + if marketManager.check_username(username): + username_clean = marketManager.__santatize_username(username) + hash = bcrypt.encrypt(plain_password, rounds=13) + hash_result = hash + rounds_striped = hash_result.strip('$2a$13$') + salt = rounds_striped[:22] + cursor = connections['market'].cursor() + cursor.execute(marketManager.SQL_UPDATE_PASSWORD, [hash, salt, username_clean]) + return plain_password + else: + logger.error("Unable to update alliance market user %s password" % username) + return "" + + @staticmethod + def update_user_password(username): + logger.debug("Updating alliance market user %s password" % username) + if marketManager.check_username(username): + username_clean = marketManager.__santatize_username(username) + plain_password = marketManager.__generate_random_pass() + hash = bcrypt.encrypt(plain_password, rounds=13) + hash_result = hash + rounds_striped = hash_result.strip('$2a$13$') + salt = rounds_striped[:22] + cursor = connections['market'].cursor() + cursor.execute(marketManager.SQL_UPDATE_PASSWORD, [hash, salt, username_clean]) + return plain_password + else: + logger.error("Unable to update alliance market user %s password" % username) + return "" + + @staticmethod + def update_user_info(username): + logger.debug("Updating alliance market user %s" % username) + try: + username_clean = marketManager.__santatize_username(username) + plain_password = marketManager.__generate_random_pass() + hash = bcrypt.encrypt(plain_password, rounds=13) + hash_result = hash + rounds_striped = hash_result.strip('$2a$13$') + salt = rounds_striped[:22] + cursor = connections['market'].cursor() + cursor.execute(marketManager.SQL_UPDATE_USER, [hash, salt, username_clean]) + return username_clean, plain_password + except: + logger.debug("Alliance market update user failed for %s" % username) + return "", "" diff --git a/services/views.py b/services/views.py index e5ba42f0..15f3697a 100755 --- a/services/views.py +++ b/services/views.py @@ -16,6 +16,7 @@ from managers.teamspeak3_manager import Teamspeak3Manager from managers.discord_manager import DiscordManager from managers.ips4_manager import Ips4Manager from managers.smf_manager import smfManager +from managers.market_manager import marketManager from authentication.managers import AuthServicesInfoManager from eveonline.managers import EveManager from celerytask.tasks import update_jabber_groups @@ -763,5 +764,84 @@ def set_smf_password(request): form = ServicePasswordForm() logger.debug("Rendering form for user %s" % request.user) - context = {'form': form, 'service': 'Forum'} + context = {'form': form, 'service': 'SMF'} return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) + +@login_required +@user_passes_test(service_blue_alliance_test) +def activate_market(request): + logger.debug("activate_market called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + # Valid now we get the main characters + character = EveManager.get_character_by_id(authinfo.main_char_id) + 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, authinfo.main_char_id, character.character_name) + # if empty we failed + if result[0] != "": + AuthServicesInfoManager.update_user_market_info(result[0], result[1], request.user) + logger.debug("Updated authserviceinfo for user %s with market credentials." % request.user) + logger.info("Succesfully activated market for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccesful attempt to activate market for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + + +@login_required +@user_passes_test(service_blue_alliance_test) +def deactivate_market(request): + logger.debug("deactivate_market called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = marketManager.disable_user(authinfo.market_username) + # false we failed + if result: + AuthServicesInfoManager.update_user_market_info("", "", request.user) + logger.info("Succesfully deactivated market for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccesful attempt to activate market for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + + +@login_required +@user_passes_test(service_blue_alliance_test) +def reset_market_password(request): + logger.debug("reset_market_password called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = marketManager.update_user_password(authinfo.market_username) + # false we failed + if result != "": + AuthServicesInfoManager.update_user_market_info(authinfo.market_username, result, request.user) + logger.info("Succesfully reset market password for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccessful attempt to reset market password for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + +@login_required +@user_passes_test(service_blue_alliance_test) +def set_market_password(request): + logger.debug("set_market_password called by user %s" % request.user) + error = None + 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(): + password = form.cleaned_data['password'] + logger.debug("Form contains password of length %s" % len(password)) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = marketManager.update_custom_password(authinfo.market_username, password) + if result != "": + AuthServicesInfoManager.update_user_market_info(authinfo.market_username, result, request.user) + logger.info("Succesfully reset market password for user %s" % request.user) + return HttpResponseRedirect("/services/") + else: + logger.error("Failed to install custom market password for user %s" % request.user) + error = "Failed to install custom password." + else: + error = "Invalid 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': 'Market'} + return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) \ No newline at end of file diff --git a/stock/templates/registered/services.html b/stock/templates/registered/services.html index 1e5bb23c..1ff6b002 100755 --- a/stock/templates/registered/services.html +++ b/stock/templates/registered/services.html @@ -99,6 +99,33 @@ {% endifequal %} {% endif %} + {% if ENABLE_BLUE_MARKET %} + Alliance Market + {{ authinfo.market_username }} + {{ authinfo.market_password }} + {{ MARKET_URL }} + + {% ifequal authinfo.market_username "" %} + + + + {% else %} + + + + + + + + + + {% endifequal %} + + {% endif %} {% if ENABLE_BLUE_JABBER %} Jabber @@ -343,6 +370,33 @@ {% endifequal %} {% endif %} + {% if ENABLE_AUTH_MARKET %} + Alliance Market + {{ authinfo.market_username }} + {{ authinfo.market_password }} + {{ MARKET_URL }} + + {% ifequal authinfo.market_username "" %} + + + + {% else %} + + + + + + + + + + {% endifequal %} + + {% endif %} {% if ENABLE_AUTH_JABBER %} Jabber diff --git a/util/context_processors.py b/util/context_processors.py index 02572ddc..c9a74e19 100755 --- a/util/context_processors.py +++ b/util/context_processors.py @@ -39,6 +39,7 @@ def domain_url(request): 'ENABLE_AUTH_DISCORD': settings.ENABLE_AUTH_DISCORD, 'ENABLE_AUTH_IPS4': settings.ENABLE_AUTH_IPS4, 'ENABLE_AUTH_SMF': settings.ENABLE_AUTH_SMF, + 'ENABLE_AUTH_MARKET': settings.ENABLE_AUTH_MARKET, 'ENABLE_BLUE_JABBER': settings.ENABLE_BLUE_JABBER, 'ENABLE_BLUE_FORUM': settings.ENABLE_BLUE_FORUM, 'ENABLE_BLUE_MUMBLE': settings.ENABLE_BLUE_MUMBLE, @@ -47,11 +48,13 @@ def domain_url(request): 'ENABLE_BLUE_DISCORD': settings.ENABLE_BLUE_DISCORD, 'ENABLE_BLUE_IPS4': settings.ENABLE_BLUE_IPS4, 'ENABLE_BLUE_SMF': settings.ENABLE_BLUE_SMF, + 'ENABLE_BLUE_MARKET': settings.ENABLE_BLUE_MARKET, 'TEAMSPEAK3_PUBLIC_URL': settings.TEAMSPEAK3_PUBLIC_URL, 'JACK_KNIFE_URL': settings.JACK_KNIFE_URL, 'DISCORD_SERVER_ID': settings.DISCORD_SERVER_ID, 'KILLBOARD_URL': settings.KILLBOARD_URL, 'IPS4_URL': settings.IPS4_URL, 'SMF_URL': settings.SMF_URL, + 'MARKET_URL': settings.MARKET_URL, 'EXTERNAL_MEDIA_URL': settings.EXTERNAL_MEDIA_URL, 'CURRENT_UTC_TIME': timezone.now()} From 83e369965cf1978bd18502f2f978e3ed76240ad8 Mon Sep 17 00:00:00 2001 From: Adarnof Date: Fri, 8 Apr 2016 18:48:37 -0400 Subject: [PATCH 04/26] correctly trigger ts group updates --- celerytask/signals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/celerytask/signals.py b/celerytask/signals.py index 9ca9954a..48830303 100644 --- a/celerytask/signals.py +++ b/celerytask/signals.py @@ -39,7 +39,7 @@ def m2m_changed_user_groups(sender, instance, action, *args, **kwargs): def trigger_all_ts_update(): for auth in AuthServicesInfo.objects.filter(teamspeak3_uid__isnull=False): - update_teamspeak3_groups.delay(auth.user) + update_teamspeak3_groups.delay(auth.user.pk) @receiver(m2m_changed, sender=AuthTS.ts_group.through) def m2m_changed_authts_group(sender, instance, action, *args, **kwargs): From 38acd7df16de585610eb106843d2583593c21a4d Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Sat, 9 Apr 2016 02:54:41 -0500 Subject: [PATCH 05/26] Removed unused cache settings --- alliance_auth/settings.py.example | 5 ----- 1 file changed, 5 deletions(-) diff --git a/alliance_auth/settings.py.example b/alliance_auth/settings.py.example index 977cd9c0..e01d1176 100755 --- a/alliance_auth/settings.py.example +++ b/alliance_auth/settings.py.example @@ -179,11 +179,6 @@ USE_TZ = True STATIC_URL = '/static/' STATIC_ROOT = '/home/allianceserver/allianceauth/static/' -# Cache directory for EveWho, no ending / -# by default this becomes ~//alliance_auth/cache -# This directory needs to be writable by the webserver -EVEWHO_CACHE_DIR = '{}/cache'.format(BASE_DIR) - ##################################################### ## From fa9992f1d6e05f5e922f31d046aaa51052795cb1 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Mon, 11 Apr 2016 02:53:35 -0500 Subject: [PATCH 06/26] Fixed Grammer --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 213c7e0d..b600ad1a 100755 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ Special Permissions In Admin: hrapplications | application | accept_application ( Can accept applications ) hrapplications | application | reject_application ( Can reject applications ) hrapplications | application | view_apis ( Can see applicant's API keys ) - hrapplicstions | applicationcomment | add_applicationcomment ( Can comment on applications ) + hrapplications | applicationcomment | add_applicationcomment ( Can comment on applications ) Active Developers From 321ea9cca3936de6c3477990b24599419d7ad465 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Thu, 14 Apr 2016 08:03:37 -0500 Subject: [PATCH 07/26] Closes #379 --- services/managers/phpbb3_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/phpbb3_manager.py b/services/managers/phpbb3_manager.py index 1521c580..92384328 100755 --- a/services/managers/phpbb3_manager.py +++ b/services/managers/phpbb3_manager.py @@ -67,7 +67,7 @@ class Phpbb3Manager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "") + sanatized = sanatized.replace("'", "_") return sanatized.lower() @staticmethod From a4a23e3dde9472a77c91248d05e33e0684c357d4 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Thu, 14 Apr 2016 08:04:33 -0500 Subject: [PATCH 08/26] Addresses #379 --- services/managers/ipboard_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/ipboard_manager.py b/services/managers/ipboard_manager.py index 677062a2..8fa92353 100755 --- a/services/managers/ipboard_manager.py +++ b/services/managers/ipboard_manager.py @@ -15,7 +15,7 @@ class IPBoardManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "") + sanatized = sanatized.replace("'", "_") return sanatized.lower() @staticmethod From 3a508421be5ad02cdc3aa58fefe5ebd90304f10a Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Thu, 14 Apr 2016 08:05:13 -0500 Subject: [PATCH 09/26] Addresses #379 --- services/managers/market_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/market_manager.py b/services/managers/market_manager.py index e2d64338..49c13889 100644 --- a/services/managers/market_manager.py +++ b/services/managers/market_manager.py @@ -26,7 +26,7 @@ class marketManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "") + sanatized = sanatized.replace("'", "_") return sanatized.lower() @staticmethod From adde2bb7a87783e857159e5f7c7438d41248d2c8 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Thu, 14 Apr 2016 08:05:36 -0500 Subject: [PATCH 10/26] Addresses #379 --- services/managers/mumble_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/mumble_manager.py b/services/managers/mumble_manager.py index e70f56ac..233c56ef 100755 --- a/services/managers/mumble_manager.py +++ b/services/managers/mumble_manager.py @@ -17,7 +17,7 @@ class MumbleManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "") + sanatized = sanatized.replace("'", "_") return sanatized @staticmethod From affbc946a73fc9e725c033307bb4ea87c1aa816c Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Thu, 14 Apr 2016 08:06:00 -0500 Subject: [PATCH 11/26] Addresses #379 --- services/managers/openfire_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/openfire_manager.py b/services/managers/openfire_manager.py index 4c2a2c63..6db9a474 100755 --- a/services/managers/openfire_manager.py +++ b/services/managers/openfire_manager.py @@ -32,7 +32,7 @@ class OpenfireManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "") + sanatized = sanatized.replace("'", "_") return sanatized.lower() @staticmethod From 877c6511f30fe1cba52285e1ee1c1c016d7264d9 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Thu, 14 Apr 2016 08:06:28 -0500 Subject: [PATCH 12/26] Addresses #379 --- services/managers/smf_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/smf_manager.py b/services/managers/smf_manager.py index 7ef93add..701f63c5 100644 --- a/services/managers/smf_manager.py +++ b/services/managers/smf_manager.py @@ -49,7 +49,7 @@ class smfManager: @staticmethod def santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "") + sanatized = sanatized.replace("'", "_") return sanatized.lower() @staticmethod From 93d3481527f6380107707f0b76b60aba192c392d Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Thu, 14 Apr 2016 08:06:50 -0500 Subject: [PATCH 13/26] Addresses #379 --- services/managers/teamspeak3_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/teamspeak3_manager.py b/services/managers/teamspeak3_manager.py index 75e51e36..b3a8e8ef 100755 --- a/services/managers/teamspeak3_manager.py +++ b/services/managers/teamspeak3_manager.py @@ -21,7 +21,7 @@ class Teamspeak3Manager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "") + sanatized = sanatized.replace("'", "_") return sanatized @staticmethod From ab9423ec1f156520afeed155ccdf3579203c3254 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Thu, 14 Apr 2016 10:12:00 -0500 Subject: [PATCH 14/26] Fixed Security Issue (#380) * fixed security issue * fixed security issue * fixed security issue * fixed security issue * fixed security issue * fixed security issue --- services/managers/market_manager.py | 2 +- services/managers/mumble_manager.py | 2 +- services/managers/openfire_manager.py | 2 +- services/managers/phpbb3_manager.py | 2 +- services/managers/smf_manager.py | 2 +- services/managers/teamspeak3_manager.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/services/managers/market_manager.py b/services/managers/market_manager.py index 49c13889..1b27b049 100644 --- a/services/managers/market_manager.py +++ b/services/managers/market_manager.py @@ -26,7 +26,7 @@ class marketManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "_") + sanatized = sanatized.replace("'", "-") return sanatized.lower() @staticmethod diff --git a/services/managers/mumble_manager.py b/services/managers/mumble_manager.py index 233c56ef..93d000eb 100755 --- a/services/managers/mumble_manager.py +++ b/services/managers/mumble_manager.py @@ -17,7 +17,7 @@ class MumbleManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "_") + sanatized = sanatized.replace("'", "-") return sanatized @staticmethod diff --git a/services/managers/openfire_manager.py b/services/managers/openfire_manager.py index 6db9a474..ff4d1e14 100755 --- a/services/managers/openfire_manager.py +++ b/services/managers/openfire_manager.py @@ -32,7 +32,7 @@ class OpenfireManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "_") + sanatized = sanatized.replace("'", "-") return sanatized.lower() @staticmethod diff --git a/services/managers/phpbb3_manager.py b/services/managers/phpbb3_manager.py index 92384328..b086e1fc 100755 --- a/services/managers/phpbb3_manager.py +++ b/services/managers/phpbb3_manager.py @@ -67,7 +67,7 @@ class Phpbb3Manager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "_") + sanatized = sanatized.replace("'", "-") return sanatized.lower() @staticmethod diff --git a/services/managers/smf_manager.py b/services/managers/smf_manager.py index 701f63c5..2a499656 100644 --- a/services/managers/smf_manager.py +++ b/services/managers/smf_manager.py @@ -49,7 +49,7 @@ class smfManager: @staticmethod def santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "_") + sanatized = sanatized.replace("'", "-") return sanatized.lower() @staticmethod diff --git a/services/managers/teamspeak3_manager.py b/services/managers/teamspeak3_manager.py index b3a8e8ef..681e735f 100755 --- a/services/managers/teamspeak3_manager.py +++ b/services/managers/teamspeak3_manager.py @@ -21,7 +21,7 @@ class Teamspeak3Manager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "_") + sanatized = sanatized.replace("'", "-") return sanatized @staticmethod From 3b8a62adafe9dadca5f5aef45c85e9dda7154a16 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Fri, 15 Apr 2016 03:55:55 -0500 Subject: [PATCH 15/26] Escaped mysql character to prevent errors --- services/managers/ipboard_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/ipboard_manager.py b/services/managers/ipboard_manager.py index 8fa92353..ec1625dd 100755 --- a/services/managers/ipboard_manager.py +++ b/services/managers/ipboard_manager.py @@ -15,7 +15,7 @@ class IPBoardManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "_") + sanatized = username.replace("'", "\\'") return sanatized.lower() @staticmethod From e69744b7eb847cd371019b5bfcbe2b196af042dc Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Fri, 15 Apr 2016 03:56:22 -0500 Subject: [PATCH 16/26] Escaped mysql character to prevent errors --- services/managers/market_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/market_manager.py b/services/managers/market_manager.py index 1b27b049..e56d9df2 100644 --- a/services/managers/market_manager.py +++ b/services/managers/market_manager.py @@ -26,7 +26,7 @@ class marketManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "-") + sanatized = username.replace("'", "\\'") return sanatized.lower() @staticmethod From 4ca9a96f8d56216ba88f7ebdfddb8be8a66d2ba6 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Fri, 15 Apr 2016 03:56:40 -0500 Subject: [PATCH 17/26] Escaped mysql character to prevent errors --- services/managers/mumble_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/mumble_manager.py b/services/managers/mumble_manager.py index 93d000eb..ed96b0bb 100755 --- a/services/managers/mumble_manager.py +++ b/services/managers/mumble_manager.py @@ -17,7 +17,7 @@ class MumbleManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "-") + sanatized = username.replace("'", "\\'") return sanatized @staticmethod From 445c1e82e55bece7167828d72ad6f0718ca0a012 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Fri, 15 Apr 2016 03:57:13 -0500 Subject: [PATCH 18/26] Escaped mysql character to prevent errors --- services/managers/openfire_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/openfire_manager.py b/services/managers/openfire_manager.py index ff4d1e14..54e5ecfb 100755 --- a/services/managers/openfire_manager.py +++ b/services/managers/openfire_manager.py @@ -32,7 +32,7 @@ class OpenfireManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "-") + sanatized = username.replace("'", "\\'") return sanatized.lower() @staticmethod From 35e69847eab83105c5a705cfccc07e5b8d85c730 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Fri, 15 Apr 2016 03:57:32 -0500 Subject: [PATCH 19/26] Escaped mysql character to prevent errors --- services/managers/phpbb3_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/phpbb3_manager.py b/services/managers/phpbb3_manager.py index b086e1fc..e690dbe5 100755 --- a/services/managers/phpbb3_manager.py +++ b/services/managers/phpbb3_manager.py @@ -67,7 +67,7 @@ class Phpbb3Manager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "-") + sanatized = username.replace("'", "\\'") return sanatized.lower() @staticmethod From 4edcfafc8a2bc8b72c8616c67d8f631771c8020e Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Fri, 15 Apr 2016 03:57:52 -0500 Subject: [PATCH 20/26] Escaped mysql character to prevent errors --- services/managers/smf_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/managers/smf_manager.py b/services/managers/smf_manager.py index 2a499656..54c525e3 100644 --- a/services/managers/smf_manager.py +++ b/services/managers/smf_manager.py @@ -49,7 +49,7 @@ class smfManager: @staticmethod def santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = sanatized.replace("'", "-") + sanatized = username.replace("'", "\\'") return sanatized.lower() @staticmethod From 490d1944de63c6c1dd3ff70eab530857527a08fb Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Fri, 15 Apr 2016 11:35:18 -0500 Subject: [PATCH 21/26] removed redundant code (#386) * Update ipboard_manager.py * Update market_manager.py * Update mumble_manager.py * Update openfire_manager.py * Update phpbb3_manager.py * Update smf_manager.py --- services/managers/ipboard_manager.py | 1 - services/managers/market_manager.py | 1 - services/managers/mumble_manager.py | 1 - services/managers/openfire_manager.py | 1 - services/managers/phpbb3_manager.py | 1 - services/managers/smf_manager.py | 1 - 6 files changed, 6 deletions(-) diff --git a/services/managers/ipboard_manager.py b/services/managers/ipboard_manager.py index ec1625dd..f966d0f5 100755 --- a/services/managers/ipboard_manager.py +++ b/services/managers/ipboard_manager.py @@ -15,7 +15,6 @@ class IPBoardManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = username.replace("'", "\\'") return sanatized.lower() @staticmethod diff --git a/services/managers/market_manager.py b/services/managers/market_manager.py index e56d9df2..c397c336 100644 --- a/services/managers/market_manager.py +++ b/services/managers/market_manager.py @@ -26,7 +26,6 @@ class marketManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = username.replace("'", "\\'") return sanatized.lower() @staticmethod diff --git a/services/managers/mumble_manager.py b/services/managers/mumble_manager.py index ed96b0bb..a1ef9b5f 100755 --- a/services/managers/mumble_manager.py +++ b/services/managers/mumble_manager.py @@ -17,7 +17,6 @@ class MumbleManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = username.replace("'", "\\'") return sanatized @staticmethod diff --git a/services/managers/openfire_manager.py b/services/managers/openfire_manager.py index 54e5ecfb..5d8c88db 100755 --- a/services/managers/openfire_manager.py +++ b/services/managers/openfire_manager.py @@ -32,7 +32,6 @@ class OpenfireManager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = username.replace("'", "\\'") return sanatized.lower() @staticmethod diff --git a/services/managers/phpbb3_manager.py b/services/managers/phpbb3_manager.py index e690dbe5..aef61a18 100755 --- a/services/managers/phpbb3_manager.py +++ b/services/managers/phpbb3_manager.py @@ -67,7 +67,6 @@ class Phpbb3Manager: @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = username.replace("'", "\\'") return sanatized.lower() @staticmethod diff --git a/services/managers/smf_manager.py b/services/managers/smf_manager.py index 54c525e3..c869eeb9 100644 --- a/services/managers/smf_manager.py +++ b/services/managers/smf_manager.py @@ -49,7 +49,6 @@ class smfManager: @staticmethod def santatize_username(username): sanatized = username.replace(" ", "_") - sanatized = username.replace("'", "\\'") return sanatized.lower() @staticmethod From 0b20f8f72b8968ab67164e8fd3913a51612ecb44 Mon Sep 17 00:00:00 2001 From: Adarnof Date: Fri, 15 Apr 2016 21:47:16 -0400 Subject: [PATCH 22/26] Update requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 71b65d17..1f4ddbac 100755 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,7 @@ evelink dnspython passlib requests>=2.9.1 +bcrypt zeroc-ice # Django Stuff # From e29c1d3295b44650a3661c85e90c5b05aded7684 Mon Sep 17 00:00:00 2001 From: Adarnof Date: Sun, 17 Apr 2016 15:17:32 -0400 Subject: [PATCH 23/26] Discourse (#377) * Initial work on Discourse integration * Views for discourse * Discourse group updates Correct password display * Removed password functions Changed delete to suspend user forever Added unsuspend check to add_user --- alliance_auth/settings.py.example | 16 ++ alliance_auth/urls.py | 4 + authentication/managers.py | 12 + authentication/models.py | 2 + celerytask/signals.py | 4 + celerytask/tasks.py | 21 ++ services/managers/discourse_manager.py | 338 +++++++++++++++++++++++ services/models.py | 9 + services/views.py | 36 ++- stock/templates/registered/services.html | 38 +++ util/context_processors.py | 3 + 11 files changed, 481 insertions(+), 2 deletions(-) create mode 100644 services/managers/discourse_manager.py diff --git a/alliance_auth/settings.py.example b/alliance_auth/settings.py.example index e01d1176..bfa42806 100755 --- a/alliance_auth/settings.py.example +++ b/alliance_auth/settings.py.example @@ -249,6 +249,7 @@ BLUE_ALLIANCE_GROUPS = 'True' == os.environ.get('AA_BLUE_ALLIANCE_GROUPS', 'Fals # ENABLE_AUTH_MUMBLE - Enable mumble support in the auth for auth'd members # ENABLE_AUTH_IPBOARD - Enable IPBoard forum support in the auth for auth'd members # ENABLE_AUTH_DISCORD - Enable Discord support in the auth for auth'd members +# ENABLE_AUTH_DISCOURSE - Enable Discourse support in the auth for auth'd members # ENABLE_AUTH_IPS4 - Enable IPS4 support in the auth for auth'd members # ENABLE_AUTH_SMF - Enable SMF forum support in the auth for auth'd members # ENABLE_AUTH_MARKET = Enable Alliance Market support in auth for auth'd members @@ -259,10 +260,12 @@ ENABLE_AUTH_MUMBLE = 'True' == os.environ.get('AA_ENABLE_AUTH_MUMBLE', 'False') ENABLE_AUTH_IPBOARD = 'True' == os.environ.get('AA_ENABLE_AUTH_IPBOARD', 'False') ENABLE_AUTH_TEAMSPEAK3 = 'True' == os.environ.get('AA_ENABLE_AUTH_TEAMSPEAK3', 'False') ENABLE_AUTH_DISCORD = 'True' == os.environ.get('AA_ENABLE_AUTH_DISCORD', 'False') +ENABLE_AUTH_DISCOURSE = 'True' == os.environ.get('AA_ENABLE_AUTH_DISCOURSE', 'False') ENABLE_AUTH_IPS4 = 'True' == os.environ.get('AA_ENABLE_AUTH_IPS4', 'False') ENABLE_AUTH_SMF = 'True' == os.environ.get('AA_ENABLE_AUTH_SMF', 'False') ENABLE_AUTH_MARKET = 'True' == os.environ.get('AA_ENABLE_AUTH_MARKET', 'False') + ##################### # Blue service Setup ##################### @@ -272,6 +275,7 @@ ENABLE_AUTH_MARKET = 'True' == os.environ.get('AA_ENABLE_AUTH_MARKET', 'False') # ENABLE_BLUE_MUMBLE - Enable mumble support in the auth for blues # ENABLE_BLUE_IPBOARD - Enable IPBoard forum support in the auth for blues # ENABLE_BLUE_DISCORD - Enable Discord support in the auth for blues +# ENABLE_BLUE_DISCOURSE - Enable Discord support in the auth for blues # ENABLE_BLUE_IPS4 - Enable IPS4 forum support in the auth for blues # ENABLE_BLUE_SMF - Enable SMF forum support in the auth for blues # ENABLE_BLUE_MARKET - Enable Alliance Market in the auth for blues @@ -283,6 +287,7 @@ ENABLE_BLUE_MUMBLE = 'True' == os.environ.get('AA_ENABLE_BLUE_MUMBLE', 'False') ENABLE_BLUE_IPBOARD = 'True' == os.environ.get('AA_ENABLE_BLUE_IPBOARD', 'False') ENABLE_BLUE_TEAMSPEAK3 = 'True' == os.environ.get('AA_ENABLE_BLUE_TEAMSPEAK3', 'False') ENABLE_BLUE_DISCORD = 'True' == os.environ.get('AA_ENABLE_BLUE_DISCORD', 'False') +ENABLE_BLUE_DISCOURSE = 'True' == os.environ.get('AA_ENABLE_BLUE_DISCOURSE', 'False') ENABLE_BLUE_IPS4 = 'True' == os.environ.get('AA_ENABLE_BLUE_IPS4', 'False') ENABLE_BLUE_SMF = 'True' == os.environ.get('AA_ENABLE_BLUE_SMF', 'False') ENABLE_BLUE_MARKET = 'True' == os.environ.get('AA_ENABLE_BLUE_MARKET', 'False') @@ -406,6 +411,17 @@ DISCORD_SERVER_ID = os.environ.get('AA_DISCORD_SERVER_ID', '') DISCORD_USER_EMAIL = os.environ.get('AA_DISCORD_USER_EMAIL', '') DISCORD_USER_PASSWORD = os.environ.get('AA_DISCORD_USER_PASSWORD', '') +###################################### +# Discourse Configuration +###################################### +# DISCOURSE_URL - Web address of the forums (no trailing slash) +# DISCOURSE_API_USERNAME - API account username +# DISCOURSE_API_KEY - API Key +###################################### +DISCOURSE_URL = os.environ.get('AA_DISCOURSE_URL', '') +DISCOURSE_API_USERNAME = os.environ.get('AA_DISCOURSE_API_USERNAME', '') +DISCOURSE_API_KEY = os.environ.get('AA_DISCOURSE_API_KEY', '') + ##################################### # IPS4 Configuration ##################################### diff --git a/alliance_auth/urls.py b/alliance_auth/urls.py index 6016057c..ca15a232 100755 --- a/alliance_auth/urls.py +++ b/alliance_auth/urls.py @@ -137,6 +137,10 @@ urlpatterns = patterns('', url(r'^deactivate_discord/$', 'services.views.deactivate_discord', name='auth_deactivate_discord'), url(r'^reset_discord/$', 'services.views.reset_discord', name='auth_reset_discord'), + # Discourse Service Control + url(r'^activate_discourse/$', 'services.views.activate_discourse', name='auth_activate_discourse'), + url(r'^deactivate_discourse/$', 'services.views.deactivate_discourse', name='auth_deactivate_discourse'), + # IPS4 Service Control url(r'^activate_ips4/$', 'services.views.activate_ips4', name='auth_activate_ips4'), diff --git a/authentication/managers.py b/authentication/managers.py index 5ce01acf..926b6ca1 100755 --- a/authentication/managers.py +++ b/authentication/managers.py @@ -122,6 +122,18 @@ class AuthServicesInfoManager: else: logger.error("Failed to update user %s discord info: user does not exist." % user) + @staticmethod + def update_user_discourse_info(username, password, user): + if User.objects.filter(username=user.username).exists(): + logger.debug("Updating user %s discourse info: username %s" % (user, username)) + authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo.discourse_username = username + authserviceinfo.discourse_password = password + authserviceinfo.save(update_fields=['discourse_username', 'discourse_password']) + logger.info("Updated user %s discourse info in authservicesinfo model." % user) + else: + logger.error("Failed to update user %s discourse info: user does not exist." % user) + @staticmethod def update_user_ips4_info(username, password, id, user): if User.objects.filter(username=user.username).exists(): diff --git a/authentication/models.py b/authentication/models.py index 5a7df68b..713f658f 100755 --- a/authentication/models.py +++ b/authentication/models.py @@ -14,6 +14,8 @@ class AuthServicesInfo(models.Model): teamspeak3_uid = models.CharField(max_length=254, blank=True, default="") teamspeak3_perm_key = models.CharField(max_length=254, blank=True, default="") discord_uid = models.CharField(max_length=254, blank=True, default="") + discourse_username = models.CharField(max_length=254, blank=True, default="") + discourse_password = models.CharField(max_length=254, blank=True, default="") ips4_username = models.CharField(max_length=254, blank=True, default="") ips4_password = models.CharField(max_length=254, blank=True, default="") ips4_id = models.CharField(max_length=254, blank=True, default="") diff --git a/celerytask/signals.py b/celerytask/signals.py index 48830303..f2fcd60e 100644 --- a/celerytask/signals.py +++ b/celerytask/signals.py @@ -10,6 +10,7 @@ from .tasks import update_forum_groups from .tasks import update_ipboard_groups from .tasks import update_discord_groups from .tasks import update_teamspeak3_groups +from .tasks import update_discourse_groups from .tasks import update_smf_groups from authentication.models import AuthServicesInfo from services.models import AuthTS @@ -36,6 +37,8 @@ def m2m_changed_user_groups(sender, instance, action, *args, **kwargs): update_discord_groups.delay(instance.pk) if auth.mumble_username: update_mumble_groups.delay(instance.pk) + if auth.discourse_username: + update_discourse_groups.delay(instance.pk) def trigger_all_ts_update(): for auth in AuthServicesInfo.objects.filter(teamspeak3_uid__isnull=False): @@ -56,3 +59,4 @@ def post_save_authts(sender, instance, *args, **kwargs): def post_delete_authts(sender, instance, *args, **kwargs): logger.debug("Received post_delete signal from %s" % instance) trigger_all_ts_update() + diff --git a/celerytask/tasks.py b/celerytask/tasks.py index 8bff12b0..866bd8cf 100755 --- a/celerytask/tasks.py +++ b/celerytask/tasks.py @@ -11,6 +11,7 @@ from services.managers.phpbb3_manager import Phpbb3Manager from services.managers.ipboard_manager import IPBoardManager from services.managers.teamspeak3_manager import Teamspeak3Manager from services.managers.discord_manager import DiscordManager, DiscordAPIManager +from services.managers.discourse_manager import DiscourseManager from services.managers.smf_manager import smfManager from services.models import AuthTS from services.models import TSgroup @@ -181,6 +182,26 @@ def update_discord_groups(pk): raise self.retry(countdown = 60 * 10) logger.debug("Updated user %s discord groups." % user) +@task +def update_discourse_groups(pk): + user = User.objects.get(pk=pk) + logger.debug("Updating discourse groups for user %s" % user) + authserviceinfo = AuthServicesInfo.objects.get(user=user) + groups = [] + for group in user.groups.all(): + groups.append(str(group.name)) + if len(groups) == 0: + logger.debug("No syncgroups found for user. Adding empty group.") + groups.append('empty') + logger.debug("Updating user %s discord groups to %s" % (user, groups)) + try: + DiscourseManager.update_groups(authserviceinfo.discourse_username, groups) + except: + logger.warn("Discourse group sync failed for %s, retrying in 10 mins" % user, exc_info=True) + raise self.retry(countdown = 60 * 10) + logger.debug("Updated user %s discord groups." % user) + + def assign_corp_group(auth): corp_group = None if auth.main_char_id: diff --git a/services/managers/discourse_manager.py b/services/managers/discourse_manager.py new file mode 100644 index 00000000..047963fa --- /dev/null +++ b/services/managers/discourse_manager.py @@ -0,0 +1,338 @@ +import logging +import requests +import os +import datetime +import json +from django.conf import settings +from django.utils import timezone +from services.models import GroupCache + +logger = logging.getLogger(__name__) + +# not exhaustive, only the ones we need +ENDPOINTS = { + 'groups': { + 'list': { + 'path': "/admin/groups.json", + 'method': requests.get, + 'args': { + 'required': [], + 'optional': [], + }, + }, + 'create': { + 'path': "/admin/groups", + 'method': requests.post, + 'args': { + 'required': ['name'], + 'optional': ['visible'], + } + }, + 'add_user': { + 'path': "/admin/groups/%s/members.json", + 'method': requests.put, + 'args': { + 'required': ['usernames'], + 'optional': [], + }, + }, + 'remove_user': { + 'path': "/admin/groups/%s/members.json", + 'method': requests.delete, + 'args': { + 'required': ['username'], + 'optional': [], + }, + }, + 'delete': { + 'path': "/admin/groups/%s.json", + 'method': requests.delete, + 'args': { + 'required': [], + 'optional': [], + }, + }, + }, + 'users': { + 'create': { + 'path': "/users", + 'method': requests.post, + 'args': { + 'required': ['name', 'email', 'password', 'username'], + 'optional': ['active'], + }, + }, + 'update': { + 'path': "/users/%s.json", + 'method': requests.put, + 'args': { + 'required': ['params'], + 'optional': [], + } + }, + 'get': { + 'path': "/users/%s.json", + 'method': requests.get, + 'args': { + 'required': [], + 'optional': [], + }, + }, + 'activate': { + 'path': "/admin/users/%s/activate", + 'method': requests.put, + 'args': { + 'required': [], + 'optional': [], + }, + }, + 'set_email': { + 'path': "/users/%s/preferences/email", + 'method': requests.put, + 'args': { + 'required': ['email'], + 'optional': [], + }, + }, + 'suspend': { + 'path': "/admin/users/%s/suspend", + 'method': requests.put, + 'args': { + 'required': ['duration', 'reason'], + 'optional': [], + }, + }, + 'unsuspend': { + 'path': "/admin/users/%s/unsuspend", + 'method': requests.put, + 'args': { + 'required': [], + 'optional': [], + }, + }, + }, +} + +class DiscourseManager: + GROUP_CACHE_MAX_AGE = datetime.timedelta(minutes=30) + REVOKED_EMAIL = 'revoked@' + settings.DOMAIN + SUSPEND_DAYS = 99999 + SUSPEND_REASON = "Disabled by auth." + + @staticmethod + def __exc(endpoint, *args, **kwargs): + params = { + 'api_key': settings.DISCOURSE_API_KEY, + 'api_username': settings.DISCOURSE_API_USERNAME, + } + if args: + path = endpoint['path'] % args + else: + path = endpoint['path'] + data = {} + for arg in endpoint['args']['required']: + data[arg] = kwargs[arg] + for arg in endpoint['args']['optional']: + if arg in kwargs: + data[arg] = kwargs[arg] + for arg in kwargs: + if not arg in endpoint['args']['required'] and not arg in endpoint['args']['optional']: + logger.warn("Received unrecognized kwarg %s for endpoint %s" % (arg, endpoint)) + r = endpoint['method'](settings.DISCOURSE_URL + path, params=params, json=data) + out = r.text + try: + if 'errors' in r.json(): + logger.error("Discourse execution failed.\nEndpoint: %s\nErrors: %s" % (endpoint, r.json()['errors'])) + r.raise_for_status() + if 'success' in r.json(): + if not r.json()['success']: + raise Exception("Execution failed") + out = r.json() + except ValueError: + logger.warn("No json data received for endpoint %s" % endpoint) + r.raise_for_status() + return out + + @staticmethod + def __generate_random_pass(): + return os.urandom(8).encode('hex') + + @staticmethod + def __get_groups(): + endpoint = ENDPOINTS['groups']['list'] + data = DiscourseManager.__exc(endpoint) + return [g for g in data if not g['automatic']] + + @staticmethod + def __update_group_cache(): + GroupCache.objects.filter(service="discourse").delete() + cache = GroupCache.objects.create(service="discourse") + cache.groups = json.dumps(DiscourseManager.__get_groups()) + cache.save() + return cache + + @staticmethod + def __get_group_cache(): + if not GroupCache.objects.filter(service="discourse").exists(): + DiscourseManager.__update_group_cache() + cache = GroupCache.objects.get(service="discourse") + age = timezone.now() - cache.created + if age > DiscourseManager.GROUP_CACHE_MAX_AGE: + logger.debug("Group cache has expired. Triggering update.") + cache = DiscourseManager.__update_group_cache() + return json.loads(cache.groups) + + @staticmethod + def __create_group(name): + endpoint = ENDPOINTS['groups']['create'] + DiscourseManager.__exc(endpoint, name=name[:20], visible=True) + DiscourseManager.__update_group_cache() + + @staticmethod + def __group_name_to_id(name): + cache = DiscourseManager.__get_group_cache() + for g in cache: + if g['name'] == name[0:20]: + return g['id'] + logger.debug("Group %s not found on Discourse. Creating" % name) + DiscourseManager.__create_group(name) + return DiscourseManager.__group_name_to_id(name) + + @staticmethod + def __group_id_to_name(id): + cache = DiscourseManager.__get_group_cache() + for g in cache: + if g['id'] == id: + return g['name'] + raise KeyError("Group ID %s not found on Discourse" % id) + + @staticmethod + def __add_user_to_group(id, username): + endpoint = ENDPOINTS['groups']['add_user'] + DiscourseManager.__exc(endpoint, id, usernames=[username]) + + @staticmethod + def __remove_user_from_group(id, username): + endpoint = ENDPOINTS['groups']['remove_user'] + DiscourseManager.__exc(endpoint, id, username=username) + + @staticmethod + def __generate_group_dict(names): + dict = {} + for name in names: + dict[name] = DiscourseManager.__group_name_to_id(name) + return dict + + @staticmethod + def __get_user_groups(username): + data = DiscourseManager.__get_user(username) + return [g['id'] for g in data['user']['groups'] if not g['automatic']] + + @staticmethod + def __user_name_to_id(name): + data = DiscourseManager.__get_user(name) + return data['user']['id'] + + @staticmethod + def __user_id_to_name(id): + raise NotImplementedError + + @staticmethod + def __get_user(username): + endpoint = ENDPOINTS['users']['get'] + return DiscourseManager.__exc(endpoint, username) + + @staticmethod + def __activate_user(username): + endpoint = ENDPOINTS['users']['activate'] + id = DiscourseManager.__user_name_to_id(username) + DiscourseManager.__exc(endpoint, id) + + @staticmethod + def __update_user(username, **kwargs): + endpoint = ENDPOINTS['users']['update'] + id = DiscourseManager.__user_name_to_id(username) + DiscourseManager.__exc(endpoint, id, params=kwargs) + + @staticmethod + def __create_user(username, email, password): + endpoint = ENDPOINTS['users']['create'] + DiscourseManager.__exc(endpoint, name=username, username=username, email=email, password=password, active=True) + + @staticmethod + def __check_if_user_exists(username): + try: + DiscourseManager.__user_name_to_id(username) + return True + except: + return False + + @staticmethod + def __suspend_user(username): + id = DiscourseManager.__user_name_to_id(username) + endpoint = ENDPOINTS['users']['suspend'] + return DiscourseManager.__exc(endpoint, id, duration=DiscourseManager.SUSPEND_DAYS, reason=DiscourseManager.SUSPEND_REASON) + + @staticmethod + def __unsuspend(username): + id = DiscourseManager.__user_name_to_id(username) + endpoint = ENDPOINTS['users']['unsuspend'] + return DiscourseManager.__exc(endpoint, id) + + @staticmethod + def __set_email(username, email): + endpoint = ENDPOINTS['users']['set_email'] + return DiscourseManager.__exc(endpoint, username, email=email) + + @staticmethod + def _sanatize_username(username): + sanatized = username.replace(" ", "_") + sanatized = sanatized.replace("'", "") + return sanatized + + @staticmethod + def add_user(username, email): + logger.debug("Adding new discourse user %s" % username) + password = DiscourseManager.__generate_random_pass() + safe_username = DiscourseManager._sanatize_username(username) + try: + if DiscourseManager.__check_if_user_exists(safe_username): + logger.debug("Discourse user %s already exists. Reactivating" % safe_username) + DiscourseManager.__unsuspend(safe_username) + else: + logger.debug("Creating new user account for %s" % username) + DiscourseManager.__create_user(safe_username, email, password) + logger.info("Added new discourse user %s" % username) + return safe_username, password + except: + logger.exception("Failed to add new discourse user %s" % username) + return "","" + + @staticmethod + def delete_user(username): + logger.debug("Deleting discourse user %s" % username) + try: + DiscourseManager.__suspend_user(username) + logger.info("Deleted discourse user %s" % username) + return True + except: + logger.exception("Failed to delete discourse user %s" % username) + return False + + @staticmethod + def update_groups(username, raw_groups): + groups = [] + for g in raw_groups: + groups.append(g[:20]) + logger.debug("Updating discourse user %s groups to %s" % (username, groups)) + group_dict = DiscourseManager.__generate_group_dict(groups) + inv_group_dict = {v:k for k,v in group_dict.items()} + user_groups = DiscourseManager.__get_user_groups(username) + add_groups = [group_dict[x] for x in group_dict if not group_dict[x] in user_groups] + rem_groups = [x for x in user_groups if not inv_group_dict[x] in groups] + if add_groups or rem_groups: + logger.info("Updating discourse user %s groups: adding %s, removing %s" % (username, add_groups, rem_groups)) + for g in add_groups: + DiscourseManager.__add_user_to_group(g, username) + for g in rem_groups: + DiscourseManager.__remove_user_from_group(g, username) diff --git a/services/models.py b/services/models.py index 7a69db70..47b3cdd8 100644 --- a/services/models.py +++ b/services/models.py @@ -46,3 +46,12 @@ class MumbleUser(models.Model): def __str__(self): return self.username + +class GroupCache(models.Model): + SERVICE_CHOICES = ( + ("discourse", "discourse"), + ) + + created = models.DateTimeField(auto_now_add=True) + groups = models.TextField(blank=True, null=True) + service = models.CharField(max_length=254, choices=SERVICE_CHOICES, unique=True) diff --git a/services/views.py b/services/views.py index 15f3697a..fd8534a6 100755 --- a/services/views.py +++ b/services/views.py @@ -14,6 +14,7 @@ from managers.mumble_manager import MumbleManager from managers.ipboard_manager import IPBoardManager from managers.teamspeak3_manager import Teamspeak3Manager from managers.discord_manager import DiscordManager +from managers.discourse_manager import DiscourseManager from managers.ips4_manager import Ips4Manager from managers.smf_manager import smfManager from managers.market_manager import marketManager @@ -26,6 +27,7 @@ from celerytask.tasks import update_ipboard_groups from celerytask.tasks import update_smf_groups from celerytask.tasks import update_teamspeak3_groups from celerytask.tasks import update_discord_groups +from celerytask.tasks import update_discourse_groups from forms import JabberBroadcastForm from forms import FleetFormatterForm from forms import DiscordForm @@ -608,6 +610,37 @@ def set_ipboard_password(request): context = {'form': form, 'service': 'IPBoard', 'error': error} return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) +@login_required +@user_passes_test(service_blue_alliance_test) +def activate_discourse(request): + logger.debug("activate_discourse called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + character = EveManager.get_character_by_id(authinfo.main_char_id) + logger.debug("Adding discourse user for user %s with main character %s" % (request.user, character)) + result = DiscourseManager.add_user(character.character_name, request.user.email) + if result[0] != "": + AuthServicesInfoManager.update_user_discourse_info(result[0], result[1], request.user) + logger.debug("Updated authserviceinfo for user %s with discourse credentials. Updating groups." % request.user) + update_discourse_groups.delay(request.user.pk) + logger.info("Successfully activated discourse for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccessful attempt to activate forum for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + + +@login_required +@user_passes_test(service_blue_alliance_test) +def deactivate_discourse(request): + logger.debug("deactivate_discourse called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = DiscourseManager.delete_user(authinfo.discourse_username) + if result: + AuthServicesInfoManager.update_user_discourse_info("", "", request.user) + logger.info("Successfully deactivated discourse for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccessful attempt to activate discourse for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + @login_required @user_passes_test(service_blue_alliance_test) def activate_ips4(request): @@ -721,7 +754,6 @@ def deactivate_smf(request): logger.error("Unsuccesful attempt to activate smf for user %s" % request.user) return HttpResponseRedirect("/dashboard") - @login_required @user_passes_test(service_blue_alliance_test) def reset_smf_password(request): @@ -844,4 +876,4 @@ def set_market_password(request): logger.debug("Rendering form for user %s" % request.user) context = {'form': form, 'service': 'Market'} - return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) \ No newline at end of file + return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) diff --git a/stock/templates/registered/services.html b/stock/templates/registered/services.html index 1ff6b002..1e7cac52 100755 --- a/stock/templates/registered/services.html +++ b/stock/templates/registered/services.html @@ -236,6 +236,25 @@ {% endif %} + {% if ENABLE_BLUE_DISCOURSE %} + Discourse + {{ authinfo.discourse_username }} + {{ authinfo.discourse_password }} + {{ DISCOURSE_URL }} + + {% ifequal authinfo.discourse_username "" %} + + + + {% else %} + + + + {% endifequal %} + + {% endif %} {% if ENABLE_BLUE_TEAMSPEAK3 %} Service @@ -507,6 +526,25 @@ {% endif %} + {% if ENABLE_AUTH_DISCOURSE %} + Discourse + {{ authinfo.discourse_username }} + {{ authinfo.discourse_password }} + {{ DISCOURSE_URL }} + + {% ifequal authinfo.discourse_username "" %} + + + + {% else %} + + + + {% endifequal %} + + {% endif %} {% if ENABLE_AUTH_TEAMSPEAK3 %} Service diff --git a/util/context_processors.py b/util/context_processors.py index c9a74e19..524217ad 100755 --- a/util/context_processors.py +++ b/util/context_processors.py @@ -37,6 +37,7 @@ def domain_url(request): 'ENABLE_AUTH_IPBOARD': settings.ENABLE_AUTH_IPBOARD, 'ENABLE_AUTH_TEAMSPEAK3': settings.ENABLE_AUTH_TEAMSPEAK3, 'ENABLE_AUTH_DISCORD': settings.ENABLE_AUTH_DISCORD, + 'ENABLE_AUTH_DISCOURSE': settings.ENABLE_AUTH_DISCOURSE, 'ENABLE_AUTH_IPS4': settings.ENABLE_AUTH_IPS4, 'ENABLE_AUTH_SMF': settings.ENABLE_AUTH_SMF, 'ENABLE_AUTH_MARKET': settings.ENABLE_AUTH_MARKET, @@ -46,6 +47,7 @@ def domain_url(request): 'ENABLE_BLUE_IPBOARD': settings.ENABLE_BLUE_IPBOARD, 'ENABLE_BLUE_TEAMSPEAK3': settings.ENABLE_BLUE_TEAMSPEAK3, 'ENABLE_BLUE_DISCORD': settings.ENABLE_BLUE_DISCORD, + 'ENABLE_BLUE_DISCOURSE': settings.ENABLE_BLUE_DISCOURSE, 'ENABLE_BLUE_IPS4': settings.ENABLE_BLUE_IPS4, 'ENABLE_BLUE_SMF': settings.ENABLE_BLUE_SMF, 'ENABLE_BLUE_MARKET': settings.ENABLE_BLUE_MARKET, @@ -53,6 +55,7 @@ def domain_url(request): 'JACK_KNIFE_URL': settings.JACK_KNIFE_URL, 'DISCORD_SERVER_ID': settings.DISCORD_SERVER_ID, 'KILLBOARD_URL': settings.KILLBOARD_URL, + 'DISCOURSE_URL': settings.DISCOURSE_URL, 'IPS4_URL': settings.IPS4_URL, 'SMF_URL': settings.SMF_URL, 'MARKET_URL': settings.MARKET_URL, From 5025ab8ffec9aaddfdd2c2bd1bf3d3b35bc2a185 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Sun, 17 Apr 2016 15:02:50 -0500 Subject: [PATCH 24/26] Pathfinder Integration (#394) tested and working --- alliance_auth/settings.py.example | 20 ++- alliance_auth/urls.py | 9 +- authentication/managers.py | 14 +- authentication/models.py | 2 + cache/.gitignore | 4 - cache/README.md | 1 - services/managers/pathfinder_manager.py | 196 +++++++++++++++++++++++ services/views.py | 87 +++++++++- stock/templates/registered/services.html | 54 +++++++ util/context_processors.py | 3 + 10 files changed, 379 insertions(+), 11 deletions(-) delete mode 100644 cache/.gitignore delete mode 100644 cache/README.md create mode 100644 services/managers/pathfinder_manager.py diff --git a/alliance_auth/settings.py.example b/alliance_auth/settings.py.example index bfa42806..d2bde0f5 100755 --- a/alliance_auth/settings.py.example +++ b/alliance_auth/settings.py.example @@ -124,6 +124,15 @@ DATABASES = { 'PASSWORD': os.environ.get('AA_DB_MARKET_PASSWORD', 'password'), 'HOST': os.environ.get('AA_DB_MARKET_HOST', '127.0.0.1'), 'PORT': os.environ.get('AA_DB_MARKET_PORT', '3306'), + }, + + 'pathfinder': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'alliance_pathfinder', + 'USER': os.environ.get('AA_DB_PATHFINDER_USER', 'allianceserver'), + 'PASSWORD': os.environ.get('AA_DB_PATHFINDER_PASSWORD', 'password'), + 'HOST': os.environ.get('AA_DB_PATHFINDER_HOST', '127.0.0.1'), + 'PORT': os.environ.get('AA_DB_PATHFINDER_PORT', '3306'), } } @@ -253,6 +262,7 @@ BLUE_ALLIANCE_GROUPS = 'True' == os.environ.get('AA_BLUE_ALLIANCE_GROUPS', 'Fals # ENABLE_AUTH_IPS4 - Enable IPS4 support in the auth for auth'd members # ENABLE_AUTH_SMF - Enable SMF forum support in the auth for auth'd members # ENABLE_AUTH_MARKET = Enable Alliance Market support in auth for auth'd members +# ENABLE_AUTH_PATHFINDER = Enable Alliance Pathfinder suppor in auth for auth'd members ######################### ENABLE_AUTH_FORUM = 'True' == os.environ.get('AA_ENABLE_AUTH_FORUM', 'False') ENABLE_AUTH_JABBER = 'True' == os.environ.get('AA_ENABLE_AUTH_JABBER', 'False') @@ -264,7 +274,7 @@ ENABLE_AUTH_DISCOURSE = 'True' == os.environ.get('AA_ENABLE_AUTH_DISCOURSE', 'Fa ENABLE_AUTH_IPS4 = 'True' == os.environ.get('AA_ENABLE_AUTH_IPS4', 'False') ENABLE_AUTH_SMF = 'True' == os.environ.get('AA_ENABLE_AUTH_SMF', 'False') ENABLE_AUTH_MARKET = 'True' == os.environ.get('AA_ENABLE_AUTH_MARKET', 'False') - +ENABLE_AUTH_PATHFINDER = 'True' == os.environ.get('AA_ENABLE_AUTH_PATHFINDER', 'False') ##################### # Blue service Setup @@ -279,6 +289,7 @@ ENABLE_AUTH_MARKET = 'True' == os.environ.get('AA_ENABLE_AUTH_MARKET', 'False') # ENABLE_BLUE_IPS4 - Enable IPS4 forum support in the auth for blues # ENABLE_BLUE_SMF - Enable SMF forum support in the auth for blues # ENABLE_BLUE_MARKET - Enable Alliance Market in the auth for blues +# ENABLE_BLUE_PATHFINDER = Enable Pathfinder support in the auth for blues ##################### BLUE_STANDING = float(os.environ.get('AA_BLUE_STANDING', '5.0')) ENABLE_BLUE_FORUM = 'True' == os.environ.get('AA_ENABLE_BLUE_FORUM', 'False') @@ -291,6 +302,7 @@ ENABLE_BLUE_DISCOURSE = 'True' == os.environ.get('AA_ENABLE_BLUE_DISCOURSE', 'Fa ENABLE_BLUE_IPS4 = 'True' == os.environ.get('AA_ENABLE_BLUE_IPS4', 'False') ENABLE_BLUE_SMF = 'True' == os.environ.get('AA_ENABLE_BLUE_SMF', 'False') ENABLE_BLUE_MARKET = 'True' == os.environ.get('AA_ENABLE_BLUE_MARKET', 'False') +ENABLE_BLUE_PATHFINDER = 'True' == os.environ.get('AA_ENABLE_BLUE_PATHFINDER', 'False') ######################### # Corp Configuration @@ -328,6 +340,11 @@ MEMBER_API_ACCOUNT = 'True' == os.environ.get('AA_MEMBER_API_ACCOUNT', 'True') BLUE_API_MASK = os.environ.get('AA_BLUE_API_MASK', 8388608) BLUE_API_ACCOUNT = 'True' == os.environ.get('AA_BLUE_API_ACCOUNT', 'False') +########################## +# Pathfinder Configuration +########################## +PATHFINDER_URL = os.environ.get('AA_PATHFINDER_URL', 'http://pathfinder.yourdomain.com') + ##################### # Alliance Market ##################### @@ -422,6 +439,7 @@ DISCOURSE_URL = os.environ.get('AA_DISCOURSE_URL', '') DISCOURSE_API_USERNAME = os.environ.get('AA_DISCOURSE_API_USERNAME', '') DISCOURSE_API_KEY = os.environ.get('AA_DISCOURSE_API_KEY', '') + ##################################### # IPS4 Configuration ##################################### diff --git a/alliance_auth/urls.py b/alliance_auth/urls.py index ca15a232..7bb36e8d 100755 --- a/alliance_auth/urls.py +++ b/alliance_auth/urls.py @@ -136,7 +136,7 @@ urlpatterns = patterns('', url(r'^activate_discord/$', 'services.views.activate_discord', name='auth_activate_discord'), url(r'^deactivate_discord/$', 'services.views.deactivate_discord', name='auth_deactivate_discord'), url(r'^reset_discord/$', 'services.views.reset_discord', name='auth_reset_discord'), - + # Discourse Service Control url(r'^activate_discourse/$', 'services.views.activate_discourse', name='auth_activate_discourse'), url(r'^deactivate_discourse/$', 'services.views.deactivate_discourse', name='auth_deactivate_discourse'), @@ -164,6 +164,13 @@ urlpatterns = patterns('', name='auth_reset_market_password'), url(r'^set_market_password/$', 'services.views.set_market_password', name='auth_set_market_password'), + # Pathfinder Control + url(r'^activate_pathfinder/$', 'services.views.activate_pathfinder', name='auth_activate_pathfinder'), + url(r'^deactivate_pathfinder/$', 'services.views.deactivate_pathfinder', name='auth_deactivate_pathfinder'), + url(r'^reset_pathfinder_password/$', 'services.views.reset_pathfinder_password', + name='auth_reset_pathfinder_password'), + url(r'^set_pathfinder_password/$', 'services.views.set_pathfinder_password', name='auth_set_pathfinder_password'), + # Tools url(r'^tool/fleet_formatter_tool/$', 'services.views.fleet_formatter_view', name='auth_fleet_format_tool_view'), diff --git a/authentication/managers.py b/authentication/managers.py index 926b6ca1..84f867bf 100755 --- a/authentication/managers.py +++ b/authentication/managers.py @@ -121,7 +121,7 @@ class AuthServicesInfoManager: logger.info("Updated user %s discord info in authservicesinfo model." % user) else: logger.error("Failed to update user %s discord info: user does not exist." % user) - + @staticmethod def update_user_discourse_info(username, password, user): if User.objects.filter(username=user.username).exists(): @@ -170,3 +170,15 @@ class AuthServicesInfoManager: logger.info("Updated user %s market info in authservicesinfo model." % user) else: logger.error("Failed to update user %s market info: user does not exist." % user) + + @staticmethod + def update_user_pathfinder_info(username, password, user): + if User.objects.filter(username=user.username).exists(): + logger.debug("Updating user %s market info: username %s" % (user, username)) + authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo.pathfinder_username = username + authserviceinfo.pathfinder_password = password + authserviceinfo.save(update_fields=['pathfinder_username', 'pathfinder_password']) + logger.info("Updated user %s pathfinder info in authservicesinfo model." % user) + else: + logger.error("Failed to update user %s pathfinder info: user does not exist." % user) diff --git a/authentication/models.py b/authentication/models.py index 713f658f..11b51097 100755 --- a/authentication/models.py +++ b/authentication/models.py @@ -23,6 +23,8 @@ class AuthServicesInfo(models.Model): smf_password = models.CharField(max_length=254, blank=True, default="") market_username = models.CharField(max_length=254, blank=True, default="") market_password = models.CharField(max_length=254, blank=True, default="") + pathfinder_username = models.CharField(max_length=254, blank=True, default="") + pathfinder_password = models.CharField(max_length=254, blank=True, default="") main_char_id = models.CharField(max_length=64, blank=True, default="") is_blue = models.BooleanField(default=False) user = models.ForeignKey(User) diff --git a/cache/.gitignore b/cache/.gitignore deleted file mode 100644 index bbd659de..00000000 --- a/cache/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -* - -!README.md -!.gitignore diff --git a/cache/README.md b/cache/README.md deleted file mode 100644 index dd8a0213..00000000 --- a/cache/README.md +++ /dev/null @@ -1 +0,0 @@ -Make sure to make this folder writeable to the web server diff --git a/services/managers/pathfinder_manager.py b/services/managers/pathfinder_manager.py new file mode 100644 index 00000000..dedc7b4a --- /dev/null +++ b/services/managers/pathfinder_manager.py @@ -0,0 +1,196 @@ +import logging +from django.conf import settings +import requests +import os +from django.db import connections +from passlib.hash import bcrypt +from eveonline.managers import EveManager +from authentication.managers import AuthServicesInfo +from eveonline.models import EveCharacter +from eveonline.models import EveApiKeyPair + +logger = logging.getLogger(__name__) + +class pathfinderManager: + + SQL_ADD_USER = r"INSERT INTO user (name, email, password, active) VALUES (%s, %s, %s, %s)" + SQL_ADD_API = r"INSERT INTO user_api (userid, keyid, vCode, active) VALUES (%s, %s, %s, %s)" + SQL_ADD_CHARACTER = r"INSERT INTO user_character (userid, apiId, characterId, isMain) VALUES (%s, %s, %s, %s)" + SQL_GET_APIID = r"SELECT id, keyId FROM user_api WHERE userId = %s" + SQL_GET_USERID = r"SELECT id FROM user WHERE name = %s" + SQL_DISABLE_USER = r"UPDATE user SET active = '0' WHERE name = %s" + SQL_UPDATE_USER = r"UPDATE user SET active = '1', password = %s WHERE name = %s" + SQL_CHECK_USER = r"SELECT name FROM user WHERE name = %s" + SQL_CHECK_EMAIL = r"SELECT email from user WHERE email = %s" + SQL_SET_MAIN = r"UPDATE user_character SET isMain = 1 WHERE characterId = %s" + + + @staticmethod + def __santatize_username(username): + sanatized = username.replace(" ", "_") + return sanatized.lower() + + @staticmethod + def __generate_random_pass(): + return os.urandom(8).encode('hex') + + @staticmethod + def check_username(username): + logger.debug("Checking for pathfinder username %s" % username) + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_CHECK_USER, [pathfinderManager.__santatize_username(username)]) + row = cursor.fetchone() + if row: + logger.debug("Found user %s on pathfinder" % username) + return True + logger.debug("User %s not found on pathfinder" % username) + return False + + @staticmethod + def update_user_info(username): + logger.debug("Updating pathfinder user %s" % username) + try: + username_clean = pathfinderManager.__santatize_username(username) + plain_password = pathfinderManager.__generate_random_pass() + passwd = bcrypt.encrypt(plain_password, rounds=10) + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_UPDATE_USER, [passwd, username_clean]) + return username_clean, plain_password + except: + logger.debug("Pathfinder update user failed for %s" % username) + return "", "" + + @staticmethod + def update_custom_password(username, plain_password): + logger.debug("Updating pathfinder user id %s password" % username) + if pathfinderManager.check_username(username): + username_clean = pathfinderManager.__santatize_username(username) + passwd = bcrypt.encrypt(plain_password, rounds=10) + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_UPDATE_USER, [passwd, username_clean]) + return plain_password + else: + logger.error("Unable to update ips4 user %s password" % username) + return "" + + @staticmethod + def disable_user(username): + logger.debug("Disabling user %s" % username) + if pathfinderManager.check_username(username) == True: + try: + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_DISABLE_USER, [pathfinderManager.__santatize_username(username)]) + return True + except: + logger.debug("User %s not found cannot disable" % username) + + + + @staticmethod + def add_user(username, email, charactername): + logger.debug("Adding new pathfinder user %s" % username) + plain_password = pathfinderManager.__generate_random_pass() + passwd = bcrypt.encrypt(plain_password, rounds=10) + username_clean = pathfinderManager.__santatize_username(username) + auth_id = pathfinderManager.get_authid_by_username(charactername) + + if pathfinderManager.check_username(username)== False: + if pathfinderManager.check_email(username, email) == False: + try: + logger.debug("Adding user %s to pathfinder" % username) + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_ADD_USER, [username_clean,email, passwd, '1']) + path_id = pathfinderManager.get_pathfinder_user_id(username_clean) + api_keys = pathfinderManager.get_api_key_pairs(auth_id) + main_character = AuthServicesInfo.objects.get(user=auth_id).main_char_id + + for keyId, key in api_keys.items(): + cursor.execute(pathfinderManager.SQL_ADD_API, [path_id, keyId, key, '1']) + + char_apis = pathfinderManager.get_char_id(auth_id) + + for c,a in char_apis.items(): + cursor.execute(pathfinderManager.SQL_ADD_CHARACTER, [path_id, (pathfinderManager.get_pathfinder_api_id(username, path_id)), c, '0']) + + pathfinderManager.set_main_char(username, main_character) + return username_clean, plain_password + + except: + logger.debug("Unsuccessful attempt at adding user %s to pathfinder on add_user" % username) + return "","" + else: + logger.debug("pathfinder username %s already exists Updating instead" % username) + username_clean, password = pathfinderManager.update_user_info(username) + return username_clean, password + else: + logger.debug("pathfinder username %s already exists Updating instead" % username) + username_clean, password = pathfinderManager.update_user_info(username) + return username_clean, password + + @staticmethod + def set_main_char (username, main_character): + try: + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_SET_MAIN, [main_character]) + except: + logger.debug("Failed setting main character for user %s"% username) + return "" + + @staticmethod + def get_api_key_pairs(user_id): + char = EveCharacter.objects.all().filter(user_id=user_id) + api_list = dict() + for c in char: + api_pair = EveApiKeyPair.objects.get(api_id=c.api_id) + api_list[api_pair.api_id] = api_pair.api_key + return api_list + + @staticmethod + def get_char_id(auth_id): + char = EveCharacter.objects.all().filter(user_id=auth_id) + char_list = dict() + for c in char: + char_list[c.character_id] = c.api_id + logger.debug("printing char list %s" % char_list) + return char_list + + @staticmethod + def get_authid_by_username(username): + authid = EveCharacter.objects.get(character_name=username).user_id + return authid + + @staticmethod + def get_pathfinder_user_id(username): + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_GET_USERID, [username]) + row = cursor.fetchone() + if row: + logger.debug("Pathfinder ID for user %s is %s" % (username, row[0])) + return int(row[0]) + else: + logger.debug("failed to get pathfinder ID for user %s" % username) + return "" + + @staticmethod + def get_pathfinder_api_id(username, path_id): + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_GET_APIID, [path_id]) + row = cursor.fetchone() + if row: + logger.debug("Pathfinder API ID for user %s is %s" % (username, row[0])) + return int(row[0]) + else: + logger.debug("failed to get pathfinder API ID for user %s" % username) + return "" + + @staticmethod + def check_email(username, email): + logger.debug("Checking if email %s exists for username %s" % (email,username)) + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_CHECK_EMAIL, [email]) + row = cursor.fetchone() + if row: + logger.debug("Found user %s email on pathfinder" % username) + return True + logger.debug("User %s email not found on pathfinder" % username) + return False \ No newline at end of file diff --git a/services/views.py b/services/views.py index fd8534a6..7edc6129 100755 --- a/services/views.py +++ b/services/views.py @@ -18,6 +18,7 @@ from managers.discourse_manager import DiscourseManager from managers.ips4_manager import Ips4Manager from managers.smf_manager import smfManager from managers.market_manager import marketManager +from managers.pathfinder_manager import pathfinderManager from authentication.managers import AuthServicesInfoManager from eveonline.managers import EveManager from celerytask.tasks import update_jabber_groups @@ -609,7 +610,7 @@ def set_ipboard_password(request): logger.debug("Rendering form for user %s" % request.user) context = {'form': form, 'service': 'IPBoard', 'error': error} return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) - + @login_required @user_passes_test(service_blue_alliance_test) def activate_discourse(request): @@ -640,9 +641,9 @@ def deactivate_discourse(request): return HttpResponseRedirect("/services/") logger.error("Unsuccessful attempt to activate discourse for user %s" % request.user) return HttpResponseRedirect("/dashboard") - + @login_required -@user_passes_test(service_blue_alliance_test) +user_passes_test(service_blue_alliance_test) def activate_ips4(request): logger.debug("activate_ips4 called by user %s" % request.user) authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) @@ -754,6 +755,7 @@ def deactivate_smf(request): logger.error("Unsuccesful attempt to activate smf for user %s" % request.user) return HttpResponseRedirect("/dashboard") + @login_required @user_passes_test(service_blue_alliance_test) def reset_smf_password(request): @@ -877,3 +879,82 @@ def set_market_password(request): logger.debug("Rendering form for user %s" % request.user) context = {'form': form, 'service': 'Market'} return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) + +@login_required +@user_passes_test(service_blue_alliance_test) +def activate_pathfinder(request): + logger.debug("activate_pathfinder called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + # Valid now we get the main characters + character = EveManager.get_character_by_id(authinfo.main_char_id) + logger.debug("Adding pathfinder for user %s with main character %s" % (request.user, character)) + result = pathfinderManager.add_user(character.character_name, request.user.email, character.character_name) + # if empty we failed + if result[0] != "": + AuthServicesInfoManager.update_user_pathfinder_info(result[0], result[1], request.user) + logger.debug("Updated authserviceinfo for user %s with pathfinder credentials." % request.user) + logger.info("Succesfully activated pathfinder for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccesful attempt to activate pathfinder for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + + +@login_required +@user_passes_test(service_blue_alliance_test) +def deactivate_pathfinder(request): + logger.debug("deactivate_pathfinder called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = pathfinderManager.disable_user(authinfo.pathfinder_username) + # false we failed + if result: + AuthServicesInfoManager.update_user_pathfinder_info("", "", request.user) + logger.info("Succesfully deactivated pathfinder for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccesful attempt to activate pathfinder for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + + +@login_required +@user_passes_test(service_blue_alliance_test) +def reset_pathfinder_password(request): + logger.debug("reset_pathfinder_password called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = pathfinderManager.update_user_info(authinfo.pathfinder_username) + # false we failed + if result != "": + AuthServicesInfoManager.update_user_pathfinder_info(authinfo.pathfinder_username, result[1], request.user) + logger.info("Succesfully reset pathfinder password for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccessful attempt to reset pathfinder password for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + +@login_required +@user_passes_test(service_blue_alliance_test) +def set_pathfinder_password(request): + logger.debug("set_pathfinder_password called by user %s" % request.user) + error = None + 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(): + password = form.cleaned_data['password'] + logger.debug("Form contains password of length %s" % len(password)) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = pathfinderManager.update_custom_password(authinfo.pathfinder_username, password) + if result != "": + AuthServicesInfoManager.update_user_pathfinder_info(authinfo.pathfinder_username, result, request.user) + logger.info("Succesfully reset pathfinder password for user %s" % request.user) + return HttpResponseRedirect("/services/") + else: + logger.error("Failed to install custom pathfinder password for user %s" % request.user) + error = "Failed to install custom password." + else: + error = "Invalid 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': 'Pathfinder'} + return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) diff --git a/stock/templates/registered/services.html b/stock/templates/registered/services.html index 1e7cac52..34a07fea 100755 --- a/stock/templates/registered/services.html +++ b/stock/templates/registered/services.html @@ -126,6 +126,33 @@ {% endifequal %} {% endif %} + {% if ENABLE_BLUE_PATHFINDER %} + Pathfinder + {{ authinfo.pathfinder_username }} + {{ authinfo.pathfinder_password }} + {{ PATHFINDER_URL }} + + {% ifequal authinfo.pathfinder_username "" %} + + + + {% else %} + + + + + + + + + + {% endifequal %} + + {% endif %} {% if ENABLE_BLUE_JABBER %} Jabber @@ -416,6 +443,33 @@ {% endifequal %} {% endif %} + {% if ENABLE_AUTH_PATHFINDER %} + Pathfinder + {{ authinfo.pathfinder_username }} + {{ authinfo.pathfinder_password }} + {{ PATHFINDER_URL }} + + {% ifequal authinfo.pathfinder_username "" %} + + + + {% else %} + + + + + + + + + + {% endifequal %} + + {% endif %} {% if ENABLE_AUTH_JABBER %} Jabber diff --git a/util/context_processors.py b/util/context_processors.py index 524217ad..83b52eb4 100755 --- a/util/context_processors.py +++ b/util/context_processors.py @@ -41,6 +41,7 @@ def domain_url(request): 'ENABLE_AUTH_IPS4': settings.ENABLE_AUTH_IPS4, 'ENABLE_AUTH_SMF': settings.ENABLE_AUTH_SMF, 'ENABLE_AUTH_MARKET': settings.ENABLE_AUTH_MARKET, + 'ENABLE_AUTH_PATHFINDER': settings.ENABLE_AUTH_PATHFINDER, 'ENABLE_BLUE_JABBER': settings.ENABLE_BLUE_JABBER, 'ENABLE_BLUE_FORUM': settings.ENABLE_BLUE_FORUM, 'ENABLE_BLUE_MUMBLE': settings.ENABLE_BLUE_MUMBLE, @@ -51,6 +52,7 @@ def domain_url(request): 'ENABLE_BLUE_IPS4': settings.ENABLE_BLUE_IPS4, 'ENABLE_BLUE_SMF': settings.ENABLE_BLUE_SMF, 'ENABLE_BLUE_MARKET': settings.ENABLE_BLUE_MARKET, + 'ENABLE_BLUE_PATHFINDER': settings.ENABLE_BLUE_PATHFINDER, 'TEAMSPEAK3_PUBLIC_URL': settings.TEAMSPEAK3_PUBLIC_URL, 'JACK_KNIFE_URL': settings.JACK_KNIFE_URL, 'DISCORD_SERVER_ID': settings.DISCORD_SERVER_ID, @@ -59,5 +61,6 @@ def domain_url(request): 'IPS4_URL': settings.IPS4_URL, 'SMF_URL': settings.SMF_URL, 'MARKET_URL': settings.MARKET_URL, + 'PATHFINDER_URL': settings.PATHFINDER_URL, 'EXTERNAL_MEDIA_URL': settings.EXTERNAL_MEDIA_URL, 'CURRENT_UTC_TIME': timezone.now()} From 10090bce796ac63d61d59aca9d5ff5041ac149ea Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Sun, 17 Apr 2016 15:59:26 -0500 Subject: [PATCH 25/26] fixed error in syntax --- services/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/views.py b/services/views.py index 7edc6129..e136a102 100755 --- a/services/views.py +++ b/services/views.py @@ -643,7 +643,7 @@ def deactivate_discourse(request): return HttpResponseRedirect("/dashboard") @login_required -user_passes_test(service_blue_alliance_test) +@user_passes_test(service_blue_alliance_test) def activate_ips4(request): logger.debug("activate_ips4 called by user %s" % request.user) authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) From ed539067269e5f0bcec3e0fe3d2a1fcf1e136fc7 Mon Sep 17 00:00:00 2001 From: Mr McClain Date: Mon, 18 Apr 2016 19:48:13 -0500 Subject: [PATCH 26/26] Addresses #398 --- stock/templates/registered/services.html | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/stock/templates/registered/services.html b/stock/templates/registered/services.html index 34a07fea..a98bedd8 100755 --- a/stock/templates/registered/services.html +++ b/stock/templates/registered/services.html @@ -19,6 +19,7 @@ Action {% if ENABLE_BLUE_FORUM %} + Forums {{ authinfo.forum_username }} {{ authinfo.forum_password }} @@ -44,8 +45,10 @@ {% endifequal %} + {% endif %} {% if ENABLE_BLUE_SMF %} + SMF Forums {{ authinfo.smf_username }} {{ authinfo.smf_password }} @@ -71,8 +74,10 @@ {% endifequal %} + {% endif %} {% if ENABLE_BLUE_IPBOARD %} + IPBoard Forums {{ authinfo.ipboard_username }} {{ authinfo.ipboard_password }} @@ -98,8 +103,10 @@ {% endifequal %} + {% endif %} {% if ENABLE_BLUE_MARKET %} + Alliance Market {{ authinfo.market_username }} {{ authinfo.market_password }} @@ -125,8 +132,10 @@ {% endifequal %} + {% endif %} {% if ENABLE_BLUE_PATHFINDER %} + Pathfinder {{ authinfo.pathfinder_username }} {{ authinfo.pathfinder_password }} @@ -152,6 +161,7 @@ {% endifequal %} + {% endif %} {% if ENABLE_BLUE_JABBER %} @@ -264,6 +274,7 @@ {% endif %} {% if ENABLE_BLUE_DISCOURSE %} + Discourse {{ authinfo.discourse_username }} {{ authinfo.discourse_password }} @@ -281,6 +292,7 @@ {% endifequal %} + {% endif %} {% if ENABLE_BLUE_TEAMSPEAK3 %} @@ -390,6 +402,7 @@ {% endif %} {% if ENABLE_AUTH_IPBOARD %} + IPBoard Forums {{ authinfo.ipboard_username }} {{ authinfo.ipboard_password }} @@ -415,8 +428,10 @@ {% endifequal %} + {% endif %} {% if ENABLE_AUTH_MARKET %} + Alliance Market {{ authinfo.market_username }} {{ authinfo.market_password }} @@ -442,8 +457,10 @@ {% endifequal %} + {% endif %} {% if ENABLE_AUTH_PATHFINDER %} + Pathfinder {{ authinfo.pathfinder_username }} {{ authinfo.pathfinder_password }} @@ -469,6 +486,7 @@ {% endifequal %} + {% endif %} {% if ENABLE_AUTH_JABBER %}