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 diff --git a/alliance_auth/urls.py b/alliance_auth/urls.py index 1e62b602..e64b9761 100755 --- a/alliance_auth/urls.py +++ b/alliance_auth/urls.py @@ -136,6 +136,10 @@ 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'), # IPS4 Service Control url(r'^activate_ips4/$', 'services.views.activate_ips4', @@ -146,6 +150,27 @@ 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'), + + # 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'), + + # 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 74f0a825..84f867bf 100755 --- a/authentication/managers.py +++ b/authentication/managers.py @@ -121,6 +121,18 @@ 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(): + 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): @@ -135,3 +147,38 @@ 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) + + @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) + + @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 70269410..11b51097 100755 --- a/authentication/models.py +++ b/authentication/models.py @@ -14,9 +14,17 @@ 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="") + 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="") + 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 100755 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 100755 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/celerytask/signals.py b/celerytask/signals.py index d4ea2103..f2fcd60e 100644 --- a/celerytask/signals.py +++ b/celerytask/signals.py @@ -10,6 +10,8 @@ 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 @@ -27,16 +29,20 @@ 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: 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): - 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): @@ -53,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 a369da55..866bd8cf 100755 --- a/celerytask/tasks.py +++ b/celerytask/tasks.py @@ -11,6 +11,8 @@ 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 from authentication.models import AuthServicesInfo @@ -107,6 +109,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) @@ -161,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/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 # 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/managers/ipboard_manager.py b/services/managers/ipboard_manager.py index 677062a2..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 = sanatized.replace("'", "") return sanatized.lower() @staticmethod diff --git a/services/managers/market_manager.py b/services/managers/market_manager.py new file mode 100644 index 00000000..c397c336 --- /dev/null +++ b/services/managers/market_manager.py @@ -0,0 +1,144 @@ +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(" ", "_") + 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/managers/mumble_manager.py b/services/managers/mumble_manager.py index e70f56ac..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 = sanatized.replace("'", "") return sanatized @staticmethod diff --git a/services/managers/openfire_manager.py b/services/managers/openfire_manager.py index 4c2a2c63..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 = sanatized.replace("'", "") return sanatized.lower() @staticmethod 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/managers/phpbb3_manager.py b/services/managers/phpbb3_manager.py index 1521c580..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 = sanatized.replace("'", "") return sanatized.lower() @staticmethod diff --git a/services/managers/smf_manager.py b/services/managers/smf_manager.py new file mode 100644 index 00000000..c869eeb9 --- /dev/null +++ b/services/managers/smf_manager.py @@ -0,0 +1,259 @@ +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(" ", "_") + 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/managers/teamspeak3_manager.py b/services/managers/teamspeak3_manager.py index 75e51e36..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 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 124efc2f..e136a102 100755 --- a/services/views.py +++ b/services/views.py @@ -14,15 +14,21 @@ 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 +from managers.pathfinder_manager import pathfinderManager 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 celerytask.tasks import update_discourse_groups from forms import JabberBroadcastForm from forms import FleetFormatterForm from forms import DiscordForm @@ -604,7 +610,38 @@ 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): + 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): @@ -683,3 +720,241 @@ 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': '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)) + +@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/operationmanagement.html b/stock/templates/registered/operationmanagement.html index a878d4b8..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,27 +67,24 @@ class="glyphicon glyphicon-pencil"> - - + + {% endif %} {% endfor %} - + - {% endblock content %} diff --git a/stock/templates/registered/services.html b/stock/templates/registered/services.html index 18fa422a..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,39 @@ {% 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 }} {{ authinfo.ipboard_password }} @@ -71,6 +103,65 @@ {% 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_PATHFINDER %} + + Pathfinder + {{ authinfo.pathfinder_username }} + {{ authinfo.pathfinder_password }} + {{ PATHFINDER_URL }} + + {% ifequal authinfo.pathfinder_username "" %} + + + + {% else %} + + + + + + + + + + {% endifequal %} + + {% endif %} {% if ENABLE_BLUE_JABBER %} @@ -182,6 +273,27 @@ {% 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 @@ -260,7 +372,37 @@ {% 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 }} {{ authinfo.ipboard_password }} @@ -286,6 +428,65 @@ {% 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_PATHFINDER %} + + Pathfinder + {{ authinfo.pathfinder_username }} + {{ authinfo.pathfinder_password }} + {{ PATHFINDER_URL }} + + {% ifequal authinfo.pathfinder_username "" %} + + + + {% else %} + + + + + + + + + + {% endifequal %} + + {% endif %} {% if ENABLE_AUTH_JABBER %} @@ -397,6 +598,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 315c6424..83b52eb4 100755 --- a/util/context_processors.py +++ b/util/context_processors.py @@ -37,18 +37,30 @@ 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, + '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, '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, + '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, '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, + 'PATHFINDER_URL': settings.PATHFINDER_URL, 'EXTERNAL_MEDIA_URL': settings.EXTERNAL_MEDIA_URL, 'CURRENT_UTC_TIME': timezone.now()}