mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-06 07:06:19 +01:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a096023553 | ||
|
|
5eecee49f5 | ||
|
|
d8f4d56dd8 | ||
|
|
d58ac8a718 | ||
|
|
d503243e12 | ||
|
|
5962f0f29f | ||
|
|
a2f4226381 | ||
|
|
1ce041b90a | ||
|
|
91ec924acc | ||
|
|
0f1535161c | ||
|
|
1caa4b6baa | ||
|
|
0474fa6d17 | ||
|
|
e1907d9d17 | ||
|
|
2e214e442c |
@@ -4,5 +4,5 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
# Django starts so that shared_task will use this app.
|
# Django starts so that shared_task will use this app.
|
||||||
from .celeryapp import app as celery_app # noqa
|
from .celeryapp import app as celery_app # noqa
|
||||||
|
|
||||||
__version__ = '1.15.6'
|
__version__ = '1.15.7'
|
||||||
NAME = 'Alliance Auth v%s' % __version__
|
NAME = 'Alliance Auth v%s' % __version__
|
||||||
|
|||||||
@@ -482,7 +482,6 @@ TEAMSPEAK3_PUBLIC_URL = os.environ.get('AA_TEAMSPEAK3_PUBLIC_URL', 'example.com'
|
|||||||
######################################
|
######################################
|
||||||
# DISCORD_GUILD_ID - ID of the guild to manage
|
# DISCORD_GUILD_ID - ID of the guild to manage
|
||||||
# DISCORD_BOT_TOKEN - oauth token of the app bot user
|
# DISCORD_BOT_TOKEN - oauth token of the app bot user
|
||||||
# DISCORD_INVITE_CODE - invite code to the server
|
|
||||||
# DISCORD_APP_ID - oauth app client ID
|
# DISCORD_APP_ID - oauth app client ID
|
||||||
# DISCORD_APP_SECRET - oauth app secret
|
# DISCORD_APP_SECRET - oauth app secret
|
||||||
# DISCORD_CALLBACK_URL - oauth callback url
|
# DISCORD_CALLBACK_URL - oauth callback url
|
||||||
@@ -490,7 +489,6 @@ TEAMSPEAK3_PUBLIC_URL = os.environ.get('AA_TEAMSPEAK3_PUBLIC_URL', 'example.com'
|
|||||||
######################################
|
######################################
|
||||||
DISCORD_GUILD_ID = os.environ.get('AA_DISCORD_GUILD_ID', '')
|
DISCORD_GUILD_ID = os.environ.get('AA_DISCORD_GUILD_ID', '')
|
||||||
DISCORD_BOT_TOKEN = os.environ.get('AA_DISCORD_BOT_TOKEN', '')
|
DISCORD_BOT_TOKEN = os.environ.get('AA_DISCORD_BOT_TOKEN', '')
|
||||||
DISCORD_INVITE_CODE = os.environ.get('AA_DISCORD_INVITE_CODE', '')
|
|
||||||
DISCORD_APP_ID = os.environ.get('AA_DISCORD_APP_ID', '')
|
DISCORD_APP_ID = os.environ.get('AA_DISCORD_APP_ID', '')
|
||||||
DISCORD_APP_SECRET = os.environ.get('AA_DISCORD_APP_SECRET', '')
|
DISCORD_APP_SECRET = os.environ.get('AA_DISCORD_APP_SECRET', '')
|
||||||
DISCORD_CALLBACK_URL = os.environ.get('AA_DISCORD_CALLBACK_URL', 'http://example.com/discord/callback')
|
DISCORD_CALLBACK_URL = os.environ.get('AA_DISCORD_CALLBACK_URL', 'http://example.com/discord/callback')
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ Enter the folder by issuing `cd allianceauth`
|
|||||||
|
|
||||||
Ensure you're on the latest version with the following:
|
Ensure you're on the latest version with the following:
|
||||||
|
|
||||||
git tag | sort -n | tail -1 | xargs git checkout
|
git checkout v1.15.7
|
||||||
|
|
||||||
Python package dependencies can be installed from the requirements file:
|
Python package dependencies can be installed from the requirements file:
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ Enter the folder by issuing `cd allianceauth`
|
|||||||
|
|
||||||
Ensure you're on the latest version with the following:
|
Ensure you're on the latest version with the following:
|
||||||
|
|
||||||
git tag | sort -n | tail -1 | xargs git checkout
|
git checkout v1.15.7
|
||||||
|
|
||||||
Python package dependencies can be installed from the requirements file:
|
Python package dependencies can be installed from the requirements file:
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,6 @@ with a server ID of `120631096835571712`
|
|||||||
|
|
||||||
Update settings.py, inputting the server ID as `DISCORD_GUILD_ID`
|
Update settings.py, inputting the server ID as `DISCORD_GUILD_ID`
|
||||||
|
|
||||||
### Generating an Invite
|
|
||||||
Still on the Discord site, in your new server, an invite needs to be generated for users to join. If you with for users to initially join a different channel than `#general`, create it and follow the steps below, substituting this channel for `#general`.
|
|
||||||
|
|
||||||
On the left bar under the Text Channels heading, hover over `#general` on the right site. There are two icons, a box with an arrow and a gear. Press the box, then on the bottom left select Advanced Settings. Set the expiration to never, and no limit on uses. Press generate.
|
|
||||||
|
|
||||||
This returns a code that looks like `https://discord.gg/0fmA8MyXV6qt7XAZ`. The part after the last slash, `0fmA8MyXV6qt7XAZ`, is the invite code. Update settings.py, inputting this invite code as `DISCORD_INVITE_CODE`
|
|
||||||
|
|
||||||
### Registering an Application
|
### Registering an Application
|
||||||
|
|
||||||
Navigate to the [Discord Developers site.](https://discordapp.com/developers/applications/me) Press the plus sign to create a new application.
|
Navigate to the [Discord Developers site.](https://discordapp.com/developers/applications/me) Press the plus sign to create a new application.
|
||||||
|
|||||||
@@ -39,13 +39,14 @@ def hr_application_management_view(request):
|
|||||||
except EveCharacter.DoesNotExist:
|
except EveCharacter.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
if request.user.is_superuser:
|
if request.user.is_superuser:
|
||||||
corp_applications = Application.objects.filter(approved=None)
|
corp_applications = Application.objects.filter(approved=None).order_by('-created')
|
||||||
finished_corp_applications = Application.objects.exclude(approved=None)
|
finished_corp_applications = Application.objects.exclude(approved=None).order_by('-created')
|
||||||
elif request.user.has_perm('auth.human_resources') and main_char:
|
elif request.user.has_perm('auth.human_resources') and main_char:
|
||||||
if ApplicationForm.objects.filter(corp__corporation_id=main_char.corporation_id).exists():
|
if ApplicationForm.objects.filter(corp__corporation_id=main_char.corporation_id).exists():
|
||||||
app_form = ApplicationForm.objects.get(corp__corporation_id=main_char.corporation_id)
|
app_form = ApplicationForm.objects.get(corp__corporation_id=main_char.corporation_id)
|
||||||
corp_applications = Application.objects.filter(form=app_form).filter(approved=None)
|
corp_applications = Application.objects.filter(form=app_form).filter(approved=None).sorted_by('-created')
|
||||||
finished_corp_applications = Application.objects.filter(form=app_form).filter(approved__in=[True, False])
|
finished_corp_applications = Application.objects.filter(form=app_form).filter(
|
||||||
|
approved__in=[True, False]).order_by('-created')
|
||||||
logger.debug("Retrieved %s personal, %s corp applications for %s" % (
|
logger.debug("Retrieved %s personal, %s corp applications for %s" % (
|
||||||
len(request.user.applications.all()), len(corp_applications), request.user))
|
len(request.user.applications.all()), len(corp_applications), request.user))
|
||||||
context = {
|
context = {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import requests
|
|
||||||
import json
|
|
||||||
import re
|
import re
|
||||||
|
import requests
|
||||||
import math
|
import math
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from requests_oauthlib import OAuth2Session
|
from requests_oauthlib import OAuth2Session
|
||||||
@@ -25,8 +24,8 @@ Previously all we asked for was permission to kick members, manage roles, and ma
|
|||||||
Users have reported weird unauthorized errors we don't understand. So now we ask for full server admin.
|
Users have reported weird unauthorized errors we don't understand. So now we ask for full server admin.
|
||||||
It's almost fixed the problem.
|
It's almost fixed the problem.
|
||||||
"""
|
"""
|
||||||
# kick members, manage roles, manage nicknames
|
# kick members, manage roles, manage nicknames, create instant invite
|
||||||
# BOT_PERMISSIONS = 0x00000002 + 0x10000000 + 0x08000000
|
# BOT_PERMISSIONS = 0x00000002 + 0x10000000 + 0x08000000 + 0x00000001
|
||||||
BOT_PERMISSIONS = 0x00000008
|
BOT_PERMISSIONS = 0x00000008
|
||||||
|
|
||||||
# get user ID, accept invite
|
# get user ID, accept invite
|
||||||
@@ -118,8 +117,7 @@ def api_backoff(func):
|
|||||||
global_ratelimit=bool(existing_global_backoff)
|
global_ratelimit=bool(existing_global_backoff)
|
||||||
)
|
)
|
||||||
logger.debug("Calling API calling function")
|
logger.debug("Calling API calling function")
|
||||||
func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
break
|
|
||||||
except requests.HTTPError as e:
|
except requests.HTTPError as e:
|
||||||
if e.response.status_code == 429:
|
if e.response.status_code == 429:
|
||||||
try:
|
try:
|
||||||
@@ -164,12 +162,11 @@ class DiscordOAuthManager:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _sanitize_name(name):
|
def _sanitize_name(name):
|
||||||
return re.sub('[^\w.-]', '', name)[:32]
|
return name[:32]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _sanitize_groupname(name):
|
def _sanitize_group_name(name):
|
||||||
name = name.strip(' _')
|
return name[:100]
|
||||||
return DiscordOAuthManager._sanitize_name(name)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_bot_add_url():
|
def generate_bot_add_url():
|
||||||
@@ -188,23 +185,33 @@ class DiscordOAuthManager:
|
|||||||
return token
|
return token
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_user(code):
|
def add_user(code, groups, nickname=None):
|
||||||
try:
|
try:
|
||||||
token = DiscordOAuthManager._process_callback_code(code)['access_token']
|
token = DiscordOAuthManager._process_callback_code(code)['access_token']
|
||||||
logger.debug("Received token from OAuth")
|
logger.debug("Received token from OAuth")
|
||||||
|
|
||||||
custom_headers = {'accept': 'application/json', 'authorization': 'Bearer ' + token}
|
custom_headers = {'accept': 'application/json', 'authorization': 'Bearer ' + token}
|
||||||
path = DISCORD_URL + "/invites/" + str(settings.DISCORD_INVITE_CODE)
|
|
||||||
r = requests.post(path, headers=custom_headers)
|
|
||||||
logger.debug("Got status code %s after accepting Discord invite" % r.status_code)
|
|
||||||
r.raise_for_status()
|
|
||||||
|
|
||||||
path = DISCORD_URL + "/users/@me"
|
path = DISCORD_URL + "/users/@me"
|
||||||
r = requests.get(path, headers=custom_headers)
|
r = requests.get(path, headers=custom_headers)
|
||||||
logger.debug("Got status code %s after retrieving Discord profile" % r.status_code)
|
logger.debug("Got status code %s after retrieving Discord profile" % r.status_code)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
|
||||||
user_id = r.json()['id']
|
user_id = r.json()['id']
|
||||||
|
|
||||||
|
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
||||||
|
group_ids = [DiscordOAuthManager._group_name_to_id(DiscordOAuthManager._sanitize_group_name(g)) for g in
|
||||||
|
groups]
|
||||||
|
data = {
|
||||||
|
'roles': group_ids,
|
||||||
|
'access_token': token,
|
||||||
|
}
|
||||||
|
if nickname:
|
||||||
|
data['nick'] = nickname
|
||||||
|
custom_headers['authorization'] = 'Bot ' + settings.DISCORD_BOT_TOKEN
|
||||||
|
r = requests.put(path, headers=custom_headers, json=data)
|
||||||
|
logger.debug("Got status code %s after joining Discord server" % r.status_code)
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
logger.info("Added Discord user ID %s to server." % user_id)
|
logger.info("Added Discord user ID %s to server." % user_id)
|
||||||
return user_id
|
return user_id
|
||||||
except:
|
except:
|
||||||
@@ -212,6 +219,7 @@ class DiscordOAuthManager:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@api_backoff
|
||||||
def update_nickname(user_id, nickname):
|
def update_nickname(user_id, nickname):
|
||||||
try:
|
try:
|
||||||
nickname = DiscordOAuthManager._sanitize_name(nickname)
|
nickname = DiscordOAuthManager._sanitize_name(nickname)
|
||||||
@@ -261,7 +269,7 @@ class DiscordOAuthManager:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _group_name_to_id(name):
|
def _group_name_to_id(name):
|
||||||
name = DiscordOAuthManager._sanitize_groupname(name)
|
name = DiscordOAuthManager._sanitize_group_name(name)
|
||||||
|
|
||||||
def get_or_make_role():
|
def get_or_make_role():
|
||||||
groups = DiscordOAuthManager._get_groups()
|
groups = DiscordOAuthManager._get_groups()
|
||||||
@@ -272,42 +280,36 @@ class DiscordOAuthManager:
|
|||||||
return cache.get_or_set(DiscordOAuthManager._generate_cache_role_key(name), get_or_make_role, GROUP_CACHE_MAX_AGE)
|
return cache.get_or_set(DiscordOAuthManager._generate_cache_role_key(name), get_or_make_role, GROUP_CACHE_MAX_AGE)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __generate_role():
|
def __generate_role(name, **kwargs):
|
||||||
custom_headers = {'accept': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
custom_headers = {'accept': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/roles"
|
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/roles"
|
||||||
r = requests.post(path, headers=custom_headers)
|
data = {'name': name}
|
||||||
|
data.update(kwargs)
|
||||||
|
r = requests.post(path, headers=custom_headers, json=data)
|
||||||
logger.debug("Received status code %s after generating new role." % r.status_code)
|
logger.debug("Received status code %s after generating new role." % r.status_code)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __edit_role(role_id, name, color=0, hoist=True, permissions=36785152):
|
def __edit_role(role_id, **kwargs):
|
||||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||||
data = {
|
|
||||||
'color': color,
|
|
||||||
'hoist': hoist,
|
|
||||||
'name': name,
|
|
||||||
'permissions': permissions,
|
|
||||||
}
|
|
||||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/roles/" + str(role_id)
|
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/roles/" + str(role_id)
|
||||||
r = requests.patch(path, headers=custom_headers, data=json.dumps(data))
|
r = requests.patch(path, headers=custom_headers, json=kwargs)
|
||||||
logger.debug("Received status code %s after editing role id %s" % (r.status_code, role_id))
|
logger.debug("Received status code %s after editing role id %s" % (r.status_code, role_id))
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_group(name):
|
def _create_group(name):
|
||||||
role = DiscordOAuthManager.__generate_role()
|
return DiscordOAuthManager.__generate_role(name)
|
||||||
return DiscordOAuthManager.__edit_role(role['id'], name)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@api_backoff
|
@api_backoff
|
||||||
def update_groups(user_id, groups):
|
def update_groups(user_id, groups):
|
||||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||||
group_ids = [DiscordOAuthManager._group_name_to_id(DiscordOAuthManager._sanitize_groupname(g)) for g in groups]
|
group_ids = [DiscordOAuthManager._group_name_to_id(DiscordOAuthManager._sanitize_group_name(g)) for g in groups]
|
||||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
||||||
data = {'roles': group_ids}
|
data = {'roles': group_ids}
|
||||||
r = requests.patch(path, headers=custom_headers, json=data)
|
r = requests.patch(path, headers=custom_headers, json=data)
|
||||||
logger.debug("Received status code %s after setting user roles" % r.status_code)
|
logger.debug("Received status code %s after setting user roles" % r.status_code)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from alliance_auth.celeryapp import app
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from requests.exceptions import HTTPError
|
||||||
from eveonline.managers import EveManager
|
from eveonline.managers import EveManager
|
||||||
from notifications import notify
|
from notifications import notify
|
||||||
from services.modules.discord.manager import DiscordOAuthManager, DiscordApiBackoff
|
from services.modules.discord.manager import DiscordOAuthManager, DiscordApiBackoff
|
||||||
@@ -21,15 +21,16 @@ class DiscordTasks:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_user(cls, user, code):
|
def add_user(cls, user, code):
|
||||||
user_id = DiscordOAuthManager.add_user(code)
|
groups = DiscordTasks.get_groups(user)
|
||||||
|
nickname = None
|
||||||
|
if settings.DISCORD_SYNC_NAMES:
|
||||||
|
nickname = DiscordTasks.get_nickname(user)
|
||||||
|
user_id = DiscordOAuthManager.add_user(code, groups, nickname=nickname)
|
||||||
if user_id:
|
if user_id:
|
||||||
discord_user = DiscordUser()
|
discord_user = DiscordUser()
|
||||||
discord_user.user = user
|
discord_user.user = user
|
||||||
discord_user.uid = user_id
|
discord_user.uid = user_id
|
||||||
discord_user.save()
|
discord_user.save()
|
||||||
if settings.DISCORD_SYNC_NAMES:
|
|
||||||
cls.update_nickname.delay(user.pk)
|
|
||||||
cls.update_groups.delay(user.pk)
|
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -64,12 +65,7 @@ class DiscordTasks:
|
|||||||
user = User.objects.get(pk=pk)
|
user = User.objects.get(pk=pk)
|
||||||
logger.debug("Updating discord groups for user %s" % user)
|
logger.debug("Updating discord groups for user %s" % user)
|
||||||
if DiscordTasks.has_account(user):
|
if DiscordTasks.has_account(user):
|
||||||
groups = []
|
groups = DiscordTasks.get_groups(user)
|
||||||
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))
|
logger.debug("Updating user %s discord groups to %s" % (user, groups))
|
||||||
try:
|
try:
|
||||||
DiscordOAuthManager.update_groups(user.discord.uid, groups)
|
DiscordOAuthManager.update_groups(user.discord.uid, groups)
|
||||||
@@ -77,6 +73,15 @@ class DiscordTasks:
|
|||||||
logger.info("Discord group sync API back off for %s, "
|
logger.info("Discord group sync API back off for %s, "
|
||||||
"retrying in %s seconds" % (user, bo.retry_after_seconds))
|
"retrying in %s seconds" % (user, bo.retry_after_seconds))
|
||||||
raise task_self.retry(countdown=bo.retry_after_seconds)
|
raise task_self.retry(countdown=bo.retry_after_seconds)
|
||||||
|
except HTTPError as e:
|
||||||
|
if e.response.status_code == 404:
|
||||||
|
try:
|
||||||
|
if e.response.json()['code'] == 10007:
|
||||||
|
# user has left the server
|
||||||
|
DiscordTasks.delete_user(user)
|
||||||
|
return
|
||||||
|
finally:
|
||||||
|
raise e
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if task_self:
|
if task_self:
|
||||||
logger.exception("Discord group sync failed for %s, retrying in 10 mins" % user)
|
logger.exception("Discord group sync failed for %s, retrying in 10 mins" % user)
|
||||||
@@ -97,18 +102,22 @@ class DiscordTasks:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@app.task(bind=True, name='discord.update_nickname')
|
@app.task(bind=True, name='discord.update_nickname')
|
||||||
def update_nickname(self, pk):
|
def update_nickname(task_self, pk):
|
||||||
user = User.objects.get(pk=pk)
|
user = User.objects.get(pk=pk)
|
||||||
logger.debug("Updating discord nickname for user %s" % user)
|
logger.debug("Updating discord nickname for user %s" % user)
|
||||||
if DiscordTasks.has_account(user):
|
if DiscordTasks.has_account(user):
|
||||||
character = EveManager.get_main_character(user)
|
name = DiscordTasks.get_nickname(user)
|
||||||
logger.debug("Updating user %s discord nickname to %s" % (user, character.character_name))
|
logger.debug("Updating user %s discord nickname to %s" % (user, name))
|
||||||
try:
|
try:
|
||||||
DiscordOAuthManager.update_nickname(user.discord.uid, character.character_name)
|
DiscordOAuthManager.update_nickname(user.discord.uid, name)
|
||||||
|
except DiscordApiBackoff as bo:
|
||||||
|
logger.info("Discord nickname update API back off for %s, "
|
||||||
|
"retrying in %s seconds" % (user, bo.retry_after_seconds))
|
||||||
|
raise task_self.retry(countdown=bo.retry_after_seconds)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if self:
|
if task_self:
|
||||||
logger.exception("Discord nickname sync failed for %s, retrying in 10 mins" % user)
|
logger.exception("Discord nickname sync failed for %s, retrying in 10 mins" % user)
|
||||||
raise self.retry(countdown=60 * 10)
|
raise task_self.retry(countdown=60 * 10)
|
||||||
else:
|
else:
|
||||||
# Rethrow
|
# Rethrow
|
||||||
raise e
|
raise e
|
||||||
@@ -126,3 +135,11 @@ class DiscordTasks:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def disable(cls):
|
def disable(cls):
|
||||||
DiscordUser.objects.all().delete()
|
DiscordUser.objects.all().delete()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_nickname(user):
|
||||||
|
return EveManager.get_main_character(user).character_name
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_groups(user):
|
||||||
|
return [g.name for g in user.groups.all()]
|
||||||
|
|||||||
@@ -208,11 +208,11 @@ class DiscordManagerTestCase(TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test__sanitize_groupname(self):
|
def test__sanitize_group_name(self):
|
||||||
test_group_name = ' Group Name_Test_'
|
test_group_name = str(10**103)
|
||||||
group_name = DiscordOAuthManager._sanitize_groupname(test_group_name)
|
group_name = DiscordOAuthManager._sanitize_group_name(test_group_name)
|
||||||
|
|
||||||
self.assertEqual(group_name, 'GroupName_Test')
|
self.assertEqual(group_name, test_group_name[:100])
|
||||||
|
|
||||||
def test_generate_Bot_add_url(self):
|
def test_generate_Bot_add_url(self):
|
||||||
from . import manager
|
from . import manager
|
||||||
@@ -267,18 +267,20 @@ class DiscordManagerTestCase(TestCase):
|
|||||||
|
|
||||||
headers = {'accept': 'application/json', 'authorization': 'Bearer accesstoken'}
|
headers = {'accept': 'application/json', 'authorization': 'Bearer accesstoken'}
|
||||||
|
|
||||||
m.register_uri('POST',
|
|
||||||
manager.DISCORD_URL + '/invites/'+str(settings.DISCORD_INVITE_CODE),
|
|
||||||
request_headers=headers,
|
|
||||||
text='{}')
|
|
||||||
|
|
||||||
m.register_uri('GET',
|
m.register_uri('GET',
|
||||||
manager.DISCORD_URL + "/users/@me",
|
manager.DISCORD_URL + "/users/@me",
|
||||||
request_headers=headers,
|
request_headers=headers,
|
||||||
text=json.dumps({'id': "123456"}))
|
text=json.dumps({'id': "123456"}))
|
||||||
|
|
||||||
|
headers = {'accept': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||||
|
|
||||||
|
m.register_uri('PUT',
|
||||||
|
manager.DISCORD_URL + '/guilds/' + str(settings.DISCORD_GUILD_ID) + '/members/123456',
|
||||||
|
request_headers=headers,
|
||||||
|
text='{}')
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
return_value = DiscordOAuthManager.add_user('abcdef')
|
return_value = DiscordOAuthManager.add_user('abcdef', [])
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(return_value, '123456')
|
self.assertEqual(return_value, '123456')
|
||||||
@@ -358,7 +360,7 @@ class DiscordManagerTestCase(TestCase):
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
# Arrange
|
# Arrange
|
||||||
groups = ['Member', 'Blue', 'Special Group']
|
groups = ['Member', 'Blue', 'SpecialGroup']
|
||||||
|
|
||||||
group_cache.return_value = [{'id': 111, 'name': 'Member'},
|
group_cache.return_value = [{'id': 111, 'name': 'Member'},
|
||||||
{'id': 222, 'name': 'Blue'},
|
{'id': 222, 'name': 'Blue'},
|
||||||
|
|||||||
@@ -118,9 +118,7 @@
|
|||||||
<h4 class="panel-title">
|
<h4 class="panel-title">
|
||||||
<a class="collapsed" data-toggle="collapse" data-parent="#accordion"
|
<a class="collapsed" data-toggle="collapse" data-parent="#accordion"
|
||||||
href="#collapseThree" aria-expanded="false"
|
href="#collapseThree" aria-expanded="false"
|
||||||
aria-controls="collapseThree">
|
aria-controls="collapseThree">{% trans "Comments" %} - {{ comments|length }}</a>
|
||||||
{% blocktrans %}Comments - {{ comments|length }}{% endblocktrans %}
|
|
||||||
</a>
|
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div id="collapseThree" class="panel-collapse collapse" role="tabpanel"
|
<div id="collapseThree" class="panel-collapse collapse" role="tabpanel"
|
||||||
|
|||||||
@@ -120,7 +120,6 @@
|
|||||||
Engineering Complex [XL]
|
Engineering Complex [XL]
|
||||||
</div>
|
</div>
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
|
|
||||||
{% ifequal timer.structure "Station" %}
|
{% ifequal timer.structure "Station" %}
|
||||||
<div class="label label-danger">
|
<div class="label label-danger">
|
||||||
Station
|
Station
|
||||||
@@ -131,6 +130,21 @@
|
|||||||
TCU
|
TCU
|
||||||
</div>
|
</div>
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
|
{% ifequal timer.structure "Refinery[M]" %}
|
||||||
|
<div class="label label-warning">
|
||||||
|
Refinery [M]
|
||||||
|
</div>
|
||||||
|
{% endifequal %}
|
||||||
|
{% ifequal timer.structure "Refinery[L]" %}
|
||||||
|
<div class="label label-warning">
|
||||||
|
Refinery [L]
|
||||||
|
</div>
|
||||||
|
{% endifequal %}
|
||||||
|
{% ifequal timer.structure "Moon Mining Cycle" %}
|
||||||
|
<div class="label label-success">
|
||||||
|
Moon Mining Cycle
|
||||||
|
</div>
|
||||||
|
{% endifequal %}
|
||||||
{% ifequal timer.structure "Other" %}
|
{% ifequal timer.structure "Other" %}
|
||||||
<div class="label label-default">
|
<div class="label label-default">
|
||||||
Other
|
Other
|
||||||
@@ -265,6 +279,21 @@
|
|||||||
TCU
|
TCU
|
||||||
</div>
|
</div>
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
|
{% ifequal timer.structure "Refinery[M]" %}
|
||||||
|
<div class="label label-warning">
|
||||||
|
Refinery [M]
|
||||||
|
</div>
|
||||||
|
{% endifequal %}
|
||||||
|
{% ifequal timer.structure "Refinery[L]" %}
|
||||||
|
<div class="label label-warning">
|
||||||
|
Refinery [L]
|
||||||
|
</div>
|
||||||
|
{% endifequal %}
|
||||||
|
{% ifequal timer.structure "Moon Mining Cycle" %}
|
||||||
|
<div class="label label-success">
|
||||||
|
Moon Mining Cycle
|
||||||
|
</div>
|
||||||
|
{% endifequal %}
|
||||||
{% ifequal timer.structure "Other" %}
|
{% ifequal timer.structure "Other" %}
|
||||||
<div class="label label-default">
|
<div class="label label-default">
|
||||||
Other
|
Other
|
||||||
@@ -400,6 +429,21 @@
|
|||||||
TCU
|
TCU
|
||||||
</div>
|
</div>
|
||||||
{% endifequal %}
|
{% endifequal %}
|
||||||
|
{% ifequal timer.structure "Refinery[M]" %}
|
||||||
|
<div class="label label-warning">
|
||||||
|
Refinery [M]
|
||||||
|
</div>
|
||||||
|
{% endifequal %}
|
||||||
|
{% ifequal timer.structure "Refinery[L]" %}
|
||||||
|
<div class="label label-warning">
|
||||||
|
Refinery [L]
|
||||||
|
</div>
|
||||||
|
{% endifequal %}
|
||||||
|
{% ifequal timer.structure "Moon Mining Cycle" %}
|
||||||
|
<div class="label label-success">
|
||||||
|
Moon Mining Cycle
|
||||||
|
</div>
|
||||||
|
{% endifequal %}
|
||||||
{% ifequal timer.structure "Other" %}
|
{% ifequal timer.structure "Other" %}
|
||||||
<div class="label label-default">
|
<div class="label label-default">
|
||||||
Other
|
Other
|
||||||
|
|||||||
@@ -5,14 +5,26 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
|
|
||||||
|
|
||||||
class TimerForm(forms.Form):
|
class TimerForm(forms.Form):
|
||||||
structure_choices = [('POCO', 'POCO'), ('I-HUB', 'I-HUB'), ('POS[S]', 'POS[S]'),
|
structure_choices = [('POCO', 'POCO'),
|
||||||
('POS[M]', 'POS[M]'), ('POS[L]', 'POS[L]'), ('Citadel[M]', 'Citadel[M]'),
|
('I-HUB', 'I-HUB'),
|
||||||
('Citadel[L]', 'Citadel[L]'), ('Citadel[XL]', 'Citadel[XL]'),
|
('POS[S]', 'POS[S]'),
|
||||||
|
('POS[M]', 'POS[M]'),
|
||||||
|
('POS[L]', 'POS[L]'),
|
||||||
|
('Citadel[M]', 'Citadel[M]'),
|
||||||
|
('Citadel[L]', 'Citadel[L]'),
|
||||||
|
('Citadel[XL]', 'Citadel[XL]'),
|
||||||
('Engineering Complex[M]', 'Engineering Complex[M]'),
|
('Engineering Complex[M]', 'Engineering Complex[M]'),
|
||||||
('Engineering Complex[L]', 'Engineering Complex[L]'),
|
('Engineering Complex[L]', 'Engineering Complex[L]'),
|
||||||
('Engineering Complex[XL]', 'Engineering Complex[XL]'),
|
('Engineering Complex[XL]', 'Engineering Complex[XL]'),
|
||||||
('Station', 'Station'), ('TCU', 'TCU'), (_('Other'), _('Other'))]
|
('Refinery[M]', 'Refinery[M]'),
|
||||||
objective_choices = [('Friendly', _('Friendly')), ('Hostile', _('Hostile')), ('Neutral', _('Neutral'))]
|
('Refinery[L]', 'Refinery[L]'),
|
||||||
|
('Station', 'Station'),
|
||||||
|
('TCU', 'TCU'),
|
||||||
|
('Moon Mining Cycle', 'Moon Mining Cycle'),
|
||||||
|
(_('Other'), _('Other'))]
|
||||||
|
objective_choices = [('Friendly', _('Friendly')),
|
||||||
|
('Hostile', _('Hostile')),
|
||||||
|
('Neutral', _('Neutral'))]
|
||||||
|
|
||||||
details = forms.CharField(max_length=254, required=True, label=_('Details'))
|
details = forms.CharField(max_length=254, required=True, label=_('Details'))
|
||||||
system = forms.CharField(max_length=254, required=True, label=_("System"))
|
system = forms.CharField(max_length=254, required=True, label=_("System"))
|
||||||
|
|||||||
Reference in New Issue
Block a user