mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-10 00:56:19 +01:00
remove trailing whitespaces
This commit is contained in:
@@ -3,9 +3,9 @@ from django.contrib import admin
|
||||
|
||||
from allianceauth import hooks
|
||||
from allianceauth.authentication.admin import (
|
||||
user_profile_pic,
|
||||
user_username,
|
||||
user_main_organization,
|
||||
user_profile_pic,
|
||||
user_username,
|
||||
user_main_organization,
|
||||
MainCorporationsFilter,
|
||||
MainAllianceFilter
|
||||
)
|
||||
@@ -22,17 +22,17 @@ class ServicesUserAdmin(admin.ModelAdmin):
|
||||
|
||||
search_fields = ('user__username',)
|
||||
ordering = ('user__username',)
|
||||
list_select_related = True
|
||||
list_select_related = True
|
||||
list_display = (
|
||||
user_profile_pic,
|
||||
user_username,
|
||||
'_state',
|
||||
user_main_organization,
|
||||
user_main_organization,
|
||||
'_date_joined'
|
||||
)
|
||||
list_filter = (
|
||||
list_filter = (
|
||||
'user__profile__state',
|
||||
MainCorporationsFilter,
|
||||
MainCorporationsFilter,
|
||||
MainAllianceFilter,
|
||||
'user__date_joined',
|
||||
)
|
||||
@@ -45,7 +45,7 @@ class ServicesUserAdmin(admin.ModelAdmin):
|
||||
|
||||
def _date_joined(self, obj):
|
||||
return obj.user.date_joined
|
||||
|
||||
|
||||
_date_joined.short_description = 'date joined'
|
||||
_date_joined.admin_order_field = 'user__date_joined'
|
||||
|
||||
|
||||
@@ -139,11 +139,11 @@ class MenuItemHook:
|
||||
self.url_name = url_name
|
||||
self.template = 'public/menuitem.html'
|
||||
self.order = order if order is not None else 9999
|
||||
|
||||
|
||||
# count is an integer shown next to the menu item as badge when count != None
|
||||
# apps need to set the count in their child class, e.g. in render() method
|
||||
self.count = None
|
||||
|
||||
|
||||
navactive = navactive or []
|
||||
navactive.append(url_name)
|
||||
self.navactive = navactive
|
||||
|
||||
@@ -6,7 +6,7 @@ from allianceauth.authentication.models import State
|
||||
class NameFormatConfig(models.Model):
|
||||
service_name = models.CharField(max_length=100, blank=False)
|
||||
default_to_username = models.BooleanField(
|
||||
default=True,
|
||||
default=True,
|
||||
help_text=
|
||||
'If a user has no main_character, '
|
||||
'default to using their Auth username instead.'
|
||||
@@ -20,10 +20,10 @@ class NameFormatConfig(models.Model):
|
||||
'topic "Services Name Formats".'
|
||||
)
|
||||
states = models.ManyToManyField(
|
||||
State,
|
||||
State,
|
||||
help_text=
|
||||
"States to apply this format to. You should only have one "
|
||||
"formatter for each state for each service."
|
||||
"formatter for each state for each service."
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
|
||||
@@ -12,15 +12,15 @@ logger = LoggerAddTag(logging.getLogger(__name__), __title__)
|
||||
|
||||
|
||||
@admin.register(DiscordUser)
|
||||
class DiscordUserAdmin(ServicesUserAdmin):
|
||||
class DiscordUserAdmin(ServicesUserAdmin):
|
||||
search_fields = ServicesUserAdmin.search_fields + ('uid', 'username')
|
||||
list_display = ServicesUserAdmin.list_display + ('activated', '_username', '_uid')
|
||||
list_filter = ServicesUserAdmin.list_filter + ('activated',)
|
||||
ordering = ('-activated',)
|
||||
|
||||
|
||||
def _uid(self, obj):
|
||||
return obj.uid
|
||||
|
||||
|
||||
_uid.short_description = 'Discord ID (UID)'
|
||||
_uid.admin_order_field = 'uid'
|
||||
|
||||
@@ -29,6 +29,6 @@ class DiscordUserAdmin(ServicesUserAdmin):
|
||||
return f'{obj.username}#{obj.discriminator}'
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
_username.short_description = 'Discord Username'
|
||||
_username.admin_order_field = 'username'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import logging
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.models import User
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from allianceauth import hooks
|
||||
@@ -33,11 +33,11 @@ class DiscordService(ServicesHook):
|
||||
if self.user_has_account(user):
|
||||
logger.debug('Deleting user %s %s account', user, self.name)
|
||||
tasks.delete_user.apply_async(
|
||||
kwargs={'user_pk': user.pk, 'notify_user': notify_user},
|
||||
kwargs={'user_pk': user.pk, 'notify_user': notify_user},
|
||||
priority=SINGLE_TASK_PRIORITY
|
||||
)
|
||||
|
||||
def render_services_ctrl(self, request):
|
||||
)
|
||||
|
||||
def render_services_ctrl(self, request):
|
||||
if self.user_has_account(request.user):
|
||||
user_has_account = True
|
||||
username = request.user.discord.username
|
||||
@@ -51,12 +51,12 @@ class DiscordService(ServicesHook):
|
||||
user_has_account = False
|
||||
|
||||
return render_to_string(
|
||||
self.service_ctrl_template,
|
||||
self.service_ctrl_template,
|
||||
{
|
||||
'server_name': DiscordUser.objects.server_name(),
|
||||
'user_has_account': user_has_account,
|
||||
'discord_username': discord_username
|
||||
},
|
||||
},
|
||||
request=request
|
||||
)
|
||||
|
||||
@@ -71,15 +71,15 @@ class DiscordService(ServicesHook):
|
||||
tasks.update_nickname.apply_async(
|
||||
kwargs={
|
||||
'user_pk': user.pk,
|
||||
# since the new nickname is not yet in the DB we need to
|
||||
# since the new nickname is not yet in the DB we need to
|
||||
# provide it manually to the task
|
||||
'nickname': DiscordUser.objects.user_formatted_nick(user)
|
||||
},
|
||||
},
|
||||
priority=SINGLE_TASK_PRIORITY
|
||||
)
|
||||
|
||||
def sync_nicknames_bulk(self, users: list):
|
||||
"""Sync nickname for a list of users in bulk.
|
||||
"""Sync nickname for a list of users in bulk.
|
||||
Preferred over sync_nickname(), because it will not break the rate limit
|
||||
"""
|
||||
logger.debug(
|
||||
@@ -92,21 +92,21 @@ class DiscordService(ServicesHook):
|
||||
logger.debug('Update all %s groups called', self.name)
|
||||
tasks.update_all_groups.delay()
|
||||
|
||||
def update_groups(self, user):
|
||||
logger.debug('Processing %s groups for %s', self.name, user)
|
||||
def update_groups(self, user):
|
||||
logger.debug('Processing %s groups for %s', self.name, user)
|
||||
if self.user_has_account(user):
|
||||
tasks.update_groups.apply_async(
|
||||
kwargs={
|
||||
'user_pk': user.pk,
|
||||
# since state changes may not yet be in the DB we need to
|
||||
# since state changes may not yet be in the DB we need to
|
||||
# provide the new state name manually to the task
|
||||
'state_name': user.profile.state.name
|
||||
},
|
||||
},
|
||||
priority=SINGLE_TASK_PRIORITY
|
||||
)
|
||||
|
||||
def update_groups_bulk(self, users: list):
|
||||
"""Updates groups for a list of users in bulk.
|
||||
"""Updates groups for a list of users in bulk.
|
||||
Preferred over update_groups(), because it will not break the rate limit
|
||||
"""
|
||||
logger.debug(
|
||||
@@ -114,7 +114,7 @@ class DiscordService(ServicesHook):
|
||||
)
|
||||
user_pks = [user.pk for user in users]
|
||||
tasks.update_groups_bulk.delay(user_pks)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def user_has_account(user: User) -> bool:
|
||||
result = DiscordUser.objects.user_has_account(user)
|
||||
|
||||
@@ -26,7 +26,7 @@ DISCORD_OAUTH_TOKEN_URL = clean_setting(
|
||||
'DISCORD_OAUTH_TOKEN_URL', 'https://discord.com/api/oauth2/token'
|
||||
)
|
||||
|
||||
# How long the Discord guild names retrieved from the server are
|
||||
# How long the Discord guild names retrieved from the server are
|
||||
# caches locally in seconds.
|
||||
DISCORD_GUILD_NAME_CACHE_MAX_AGE = clean_setting(
|
||||
'DISCORD_GUILD_NAME_CACHE_MAX_AGE', 3600 * 24
|
||||
@@ -38,7 +38,7 @@ DISCORD_ROLES_CACHE_MAX_AGE = clean_setting(
|
||||
)
|
||||
|
||||
# Turns off creation of new roles. In case the rate limit for creating roles is
|
||||
# exhausted, this setting allows the Discord service to continue to function
|
||||
# exhausted, this setting allows the Discord service to continue to function
|
||||
# and wait out the reset. Rate limit is about 250 per 48 hrs.
|
||||
DISCORD_DISABLE_ROLE_CREATION = clean_setting(
|
||||
'DISCORD_DISABLE_ROLE_CREATION', False
|
||||
|
||||
@@ -19,9 +19,9 @@ from .app_settings import (
|
||||
DISCORD_API_TIMEOUT_READ,
|
||||
DISCORD_DISABLE_ROLE_CREATION,
|
||||
DISCORD_GUILD_NAME_CACHE_MAX_AGE,
|
||||
DISCORD_OAUTH_BASE_URL,
|
||||
DISCORD_OAUTH_TOKEN_URL,
|
||||
DISCORD_ROLES_CACHE_MAX_AGE,
|
||||
DISCORD_OAUTH_BASE_URL,
|
||||
DISCORD_OAUTH_TOKEN_URL,
|
||||
DISCORD_ROLES_CACHE_MAX_AGE,
|
||||
)
|
||||
from .exceptions import DiscordRateLimitExhausted, DiscordTooManyRequestsError
|
||||
from .helpers import DiscordRoles
|
||||
@@ -31,7 +31,7 @@ from ..utils import LoggerAddTag
|
||||
logger = LoggerAddTag(logging.getLogger(__name__), __title__)
|
||||
|
||||
# max requests that can be executed until reset
|
||||
RATE_LIMIT_MAX_REQUESTS = 5
|
||||
RATE_LIMIT_MAX_REQUESTS = 5
|
||||
|
||||
# Time until remaining requests are reset
|
||||
RATE_LIMIT_RESETS_AFTER = 5000
|
||||
@@ -39,7 +39,7 @@ RATE_LIMIT_RESETS_AFTER = 5000
|
||||
# Delay used for API backoff in case no info returned from API on 429s
|
||||
DEFAULT_BACKOFF_DELAY = 5000
|
||||
|
||||
# additional duration to compensate for potential clock discrepancies
|
||||
# additional duration to compensate for potential clock discrepancies
|
||||
# with the Discord server
|
||||
DURATION_CONTINGENCY = 500
|
||||
|
||||
@@ -51,23 +51,23 @@ WAIT_THRESHOLD = 250
|
||||
MINIMUM_BLOCKING_WAIT = 50
|
||||
|
||||
# If the rate limit resets soon we will wait it out and then retry to
|
||||
# either get a remaining request from our cached counter
|
||||
# either get a remaining request from our cached counter
|
||||
# or again wait out a short reset time and retry again.
|
||||
# This could happen several times within a high concurrency situation,
|
||||
# This could happen several times within a high concurrency situation,
|
||||
# but must fail after x tries to avoid an infinite loop
|
||||
RATE_LIMIT_RETRIES = 1000
|
||||
|
||||
|
||||
class DiscordClient:
|
||||
"""This class provides a web client for interacting with the Discord API
|
||||
|
||||
|
||||
The client has rate limiting that supports concurrency.
|
||||
This means it is able to ensure the API rate limit is not violated,
|
||||
This means it is able to ensure the API rate limit is not violated,
|
||||
even when used concurrently, e.g. with multiple parallel celery tasks.
|
||||
|
||||
In addition the client support proper API backoff.
|
||||
|
||||
Synchronization of rate limit infos accross multiple processes
|
||||
Synchronization of rate limit infos accross multiple processes
|
||||
is implemented with Redis and thus requires Redis as Django cache backend.
|
||||
|
||||
All durations are in milliseconds.
|
||||
@@ -79,25 +79,25 @@ class DiscordClient:
|
||||
_KEY_GLOBAL_RATE_LIMIT_REMAINING = 'DISCORD_GLOBAL_RATE_LIMIT_REMAINING'
|
||||
_KEYPREFIX_GUILD_NAME = 'DISCORD_GUILD_NAME'
|
||||
_KEYPREFIX_GUILD_ROLES = 'DISCORD_GUILD_ROLES'
|
||||
_KEYPREFIX_ROLE_NAME = 'DISCORD_ROLE_NAME'
|
||||
_KEYPREFIX_ROLE_NAME = 'DISCORD_ROLE_NAME'
|
||||
_NICK_MAX_CHARS = 32
|
||||
|
||||
|
||||
_HTTP_STATUS_CODE_NOT_FOUND = 404
|
||||
_HTTP_STATUS_CODE_RATE_LIMITED = 429
|
||||
_DISCORD_STATUS_CODE_UNKNOWN_MEMBER = 10007
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
access_token: str,
|
||||
redis: Redis = None,
|
||||
self,
|
||||
access_token: str,
|
||||
redis: Redis = None,
|
||||
is_rate_limited: bool = True
|
||||
) -> None:
|
||||
"""
|
||||
"""
|
||||
Params:
|
||||
- access_token: Discord access token used to authenticate all calls to the API
|
||||
- redis: Redis instance to be used.
|
||||
- redis: Redis instance to be used.
|
||||
- is_rate_limited: Set to False to run of rate limiting (use with care)
|
||||
If not specified will try to use the Redis instance
|
||||
If not specified will try to use the Redis instance
|
||||
from the default Django cache backend.
|
||||
"""
|
||||
self._access_token = str(access_token)
|
||||
@@ -116,7 +116,7 @@ class DiscordClient:
|
||||
lua_1 = """
|
||||
if redis.call("exists", KEYS[1]) == 0 then
|
||||
redis.call("set", KEYS[1], ARGV[1], 'px', ARGV[2])
|
||||
end
|
||||
end
|
||||
return redis.call("decr", KEYS[1])
|
||||
"""
|
||||
self.__redis_script_decr_or_set = self._redis.register_script(lua_1)
|
||||
@@ -138,24 +138,24 @@ class DiscordClient:
|
||||
@property
|
||||
def is_rate_limited(self):
|
||||
return self._is_rate_limited
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return f'{type(self).__name__}(access_token=...{self.access_token[-5:]})'
|
||||
|
||||
def _redis_decr_or_set(self, name: str, value: str, px: int) -> bool:
|
||||
"""decreases the key value if it exists and returns the result
|
||||
else sets the key
|
||||
|
||||
|
||||
Implemented as Lua script to ensure atomicity.
|
||||
"""
|
||||
return self.__redis_script_decr_or_set(
|
||||
keys=[str(name)], args=[str(value), int(px)]
|
||||
)
|
||||
|
||||
|
||||
def _redis_set_if_longer(self, name: str, value: str, px: int) -> bool:
|
||||
"""like set, but only goes through if either key doesn't exist
|
||||
or px would be extended.
|
||||
|
||||
"""like set, but only goes through if either key doesn't exist
|
||||
or px would be extended.
|
||||
|
||||
Implemented as Lua script to ensure atomicity.
|
||||
"""
|
||||
return self.__redis_script_set_longer(
|
||||
@@ -163,7 +163,7 @@ class DiscordClient:
|
||||
)
|
||||
|
||||
# users
|
||||
|
||||
|
||||
def current_user(self) -> dict:
|
||||
"""returns the user belonging to the current access_token"""
|
||||
authorization = f'Bearer {self.access_token}'
|
||||
@@ -171,7 +171,7 @@ class DiscordClient:
|
||||
method='get', route='users/@me', authorization=authorization
|
||||
)
|
||||
return r.json()
|
||||
|
||||
|
||||
# guild
|
||||
|
||||
def guild_infos(self, guild_id: int) -> dict:
|
||||
@@ -181,7 +181,7 @@ class DiscordClient:
|
||||
return r.json()
|
||||
|
||||
def guild_name(self, guild_id: int, use_cache: bool = True) -> str:
|
||||
"""returns the name of this guild (cached)
|
||||
"""returns the name of this guild (cached)
|
||||
or an empty string if something went wrong
|
||||
|
||||
Params:
|
||||
@@ -198,8 +198,8 @@ class DiscordClient:
|
||||
if 'name' in guild_infos:
|
||||
guild_name = guild_infos['name']
|
||||
self._redis.set(
|
||||
name=key_name,
|
||||
value=guild_name,
|
||||
name=key_name,
|
||||
value=guild_name,
|
||||
ex=DISCORD_GUILD_NAME_CACHE_MAX_AGE
|
||||
)
|
||||
else:
|
||||
@@ -208,7 +208,7 @@ class DiscordClient:
|
||||
return guild_name
|
||||
|
||||
@classmethod
|
||||
def _guild_name_cache_key(cls, guild_id: int) -> str:
|
||||
def _guild_name_cache_key(cls, guild_id: int) -> str:
|
||||
"""Returns key for accessing role given by name in the role cache"""
|
||||
gen_key = DiscordClient._generate_hash(f'{guild_id}')
|
||||
return f'{cls._KEYPREFIX_GUILD_NAME}__{gen_key}'
|
||||
@@ -217,38 +217,38 @@ class DiscordClient:
|
||||
|
||||
def guild_roles(self, guild_id: int, use_cache: bool = True) -> list:
|
||||
"""Returns the list of all roles for this guild
|
||||
|
||||
|
||||
If use_cache is set to False it will always hit the API to retrieve
|
||||
fresh data and update the cache
|
||||
"""
|
||||
cache_key = self._guild_roles_cache_key(guild_id)
|
||||
if use_cache:
|
||||
if use_cache:
|
||||
roles_raw = self._redis.get(name=cache_key)
|
||||
if roles_raw:
|
||||
logger.debug('Returning roles for guild %s from cache', guild_id)
|
||||
return json.loads(self._redis_decode(roles_raw))
|
||||
else:
|
||||
logger.debug('No roles for guild %s in cache', guild_id)
|
||||
|
||||
|
||||
route = f"guilds/{guild_id}/roles"
|
||||
r = self._api_request(method='get', route=route)
|
||||
r = self._api_request(method='get', route=route)
|
||||
roles = r.json()
|
||||
if roles and isinstance(roles, list):
|
||||
self._redis.set(
|
||||
name=cache_key,
|
||||
value=json.dumps(roles),
|
||||
name=cache_key,
|
||||
value=json.dumps(roles),
|
||||
ex=DISCORD_ROLES_CACHE_MAX_AGE
|
||||
)
|
||||
return roles
|
||||
|
||||
def create_guild_role(self, guild_id: int, role_name: str, **kwargs) -> dict:
|
||||
"""Create a new guild role with the given name.
|
||||
"""Create a new guild role with the given name.
|
||||
See official documentation for additional optional parameters.
|
||||
|
||||
Note that Discord allows the creation of multiple roles with the same name,
|
||||
so to avoid duplicates it's important to check existing roles
|
||||
so to avoid duplicates it's important to check existing roles
|
||||
before creating new one
|
||||
|
||||
|
||||
returns a new role dict on success
|
||||
"""
|
||||
route = f"guilds/{guild_id}/roles"
|
||||
@@ -269,9 +269,9 @@ class DiscordClient:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def _invalidate_guild_roles_cache(self, guild_id: int) -> None:
|
||||
cache_key = self._guild_roles_cache_key(guild_id)
|
||||
|
||||
def _invalidate_guild_roles_cache(self, guild_id: int) -> None:
|
||||
cache_key = self._guild_roles_cache_key(guild_id)
|
||||
self._redis.delete(cache_key)
|
||||
logger.debug('Guild roles cache invalidated')
|
||||
|
||||
@@ -280,7 +280,7 @@ class DiscordClient:
|
||||
"""Returns key for accessing cached roles for a guild"""
|
||||
gen_key = cls._generate_hash(f'{guild_id}')
|
||||
return f'{cls._KEYPREFIX_GUILD_ROLES}__{gen_key}'
|
||||
|
||||
|
||||
def match_role_from_name(self, guild_id: int, role_name: str) -> dict:
|
||||
"""returns Discord role matching the given name or an empty dict"""
|
||||
guild_roles = DiscordRoles(self.guild_roles(guild_id))
|
||||
@@ -288,12 +288,12 @@ class DiscordClient:
|
||||
|
||||
def match_or_create_roles_from_names(self, guild_id: int, role_names: list) -> list:
|
||||
"""returns Discord roles matching the given names
|
||||
|
||||
|
||||
Returns as list of tuple of role and created flag
|
||||
|
||||
Will try to match with existing roles names
|
||||
Non-existing roles will be created, then created flag will be True
|
||||
|
||||
|
||||
Params:
|
||||
- guild_id: ID of guild
|
||||
- role_names: list of name strings each defining a role
|
||||
@@ -305,7 +305,7 @@ class DiscordClient:
|
||||
}
|
||||
for role_name in role_names_cleaned:
|
||||
role, created = self.match_or_create_role_from_name(
|
||||
guild_id=guild_id,
|
||||
guild_id=guild_id,
|
||||
role_name=DiscordRoles.sanitize_role_name(role_name),
|
||||
guild_roles=guild_roles
|
||||
)
|
||||
@@ -321,46 +321,46 @@ class DiscordClient:
|
||||
"""returns Discord role matching the given name
|
||||
|
||||
Returns as tuple of role and created flag
|
||||
|
||||
|
||||
Will try to match with existing roles names
|
||||
Non-existing roles will be created, then created flag will be True
|
||||
|
||||
|
||||
Params:
|
||||
- guild_id: ID of guild
|
||||
- role_name: strings defining name of a role
|
||||
- guild_roles: All known guild roles as DiscordRoles object.
|
||||
Helps to void redundant lookups of guild roles
|
||||
- guild_roles: All known guild roles as DiscordRoles object.
|
||||
Helps to void redundant lookups of guild roles
|
||||
when this method is used multiple times.
|
||||
"""
|
||||
if not isinstance(role_name, str):
|
||||
raise TypeError('role_name must be of type string')
|
||||
|
||||
created = False
|
||||
created = False
|
||||
if guild_roles is None:
|
||||
guild_roles = DiscordRoles(self.guild_roles(guild_id))
|
||||
role = guild_roles.role_by_name(role_name)
|
||||
if not role:
|
||||
if not DISCORD_DISABLE_ROLE_CREATION:
|
||||
logger.debug('Need to create missing role: %s', role_name)
|
||||
role = self.create_guild_role(guild_id, role_name)
|
||||
role = self.create_guild_role(guild_id, role_name)
|
||||
created = True
|
||||
else:
|
||||
role = None
|
||||
|
||||
|
||||
return role, created
|
||||
|
||||
# guild members
|
||||
|
||||
def add_guild_member(
|
||||
self,
|
||||
guild_id: int,
|
||||
user_id: int,
|
||||
access_token: str,
|
||||
role_ids: list = None,
|
||||
self,
|
||||
guild_id: int,
|
||||
user_id: int,
|
||||
access_token: str,
|
||||
role_ids: list = None,
|
||||
nick: str = None
|
||||
) -> bool:
|
||||
) -> bool:
|
||||
"""Adds a user to the guilds.
|
||||
|
||||
|
||||
Returns:
|
||||
- True when a new user was added
|
||||
- None if the user already existed
|
||||
@@ -370,13 +370,13 @@ class DiscordClient:
|
||||
data = {
|
||||
'access_token': str(access_token)
|
||||
}
|
||||
if role_ids:
|
||||
if role_ids:
|
||||
data['roles'] = self._sanitize_role_ids(role_ids)
|
||||
|
||||
if nick:
|
||||
data['nick'] = str(nick)[:self._NICK_MAX_CHARS]
|
||||
|
||||
r = self._api_request(method='put', route=route, data=data)
|
||||
r = self._api_request(method='put', route=route, data=data)
|
||||
r.raise_for_status()
|
||||
if r.status_code == 201:
|
||||
return True
|
||||
@@ -384,10 +384,10 @@ class DiscordClient:
|
||||
return None
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def guild_member(self, guild_id: int, user_id: int) -> dict:
|
||||
"""returns the user info for a guild member
|
||||
|
||||
|
||||
or None if the user is not a member of the guild
|
||||
"""
|
||||
route = f'guilds/{guild_id}/members/{user_id}'
|
||||
@@ -411,14 +411,14 @@ class DiscordClient:
|
||||
"""
|
||||
if not role_ids and not nick:
|
||||
raise ValueError('Must specify role_ids or nick')
|
||||
|
||||
|
||||
if role_ids and not isinstance(role_ids, list):
|
||||
raise TypeError('role_ids must be a list type')
|
||||
|
||||
data = dict()
|
||||
if role_ids:
|
||||
if role_ids:
|
||||
data['roles'] = self._sanitize_role_ids(role_ids)
|
||||
|
||||
|
||||
if nick:
|
||||
data['nick'] = self._sanitize_nick(nick)
|
||||
|
||||
@@ -431,7 +431,7 @@ class DiscordClient:
|
||||
return None
|
||||
else:
|
||||
r.raise_for_status()
|
||||
|
||||
|
||||
if r.status_code == 204:
|
||||
return True
|
||||
else:
|
||||
@@ -439,7 +439,7 @@ class DiscordClient:
|
||||
|
||||
def remove_guild_member(self, guild_id: int, user_id: int) -> bool:
|
||||
"""Remove a member from a guild
|
||||
|
||||
|
||||
Returns:
|
||||
- True when successful
|
||||
- None if member does not exist
|
||||
@@ -448,7 +448,7 @@ class DiscordClient:
|
||||
route = f"guilds/{guild_id}/members/{user_id}"
|
||||
r = self._api_request(
|
||||
method='delete', route=route, raise_for_status=False
|
||||
)
|
||||
)
|
||||
if self._is_member_unknown_error(r):
|
||||
logger.warning('User ID %s is not a member of this guild', user_id)
|
||||
return None
|
||||
@@ -461,12 +461,12 @@ class DiscordClient:
|
||||
return False
|
||||
|
||||
# Guild member roles
|
||||
|
||||
|
||||
def add_guild_member_role(
|
||||
self, guild_id: int, user_id: int, role_id: int
|
||||
) -> bool:
|
||||
) -> bool:
|
||||
"""Adds a role to a guild member
|
||||
|
||||
|
||||
Returns:
|
||||
- True when successful
|
||||
- None if member does not exist
|
||||
@@ -479,7 +479,7 @@ class DiscordClient:
|
||||
return None
|
||||
else:
|
||||
r.raise_for_status()
|
||||
|
||||
|
||||
if r.status_code == 204:
|
||||
return True
|
||||
else:
|
||||
@@ -489,7 +489,7 @@ class DiscordClient:
|
||||
self, guild_id: int, user_id: int, role_id: int
|
||||
) -> bool:
|
||||
"""Removes a role to a guild member
|
||||
|
||||
|
||||
Returns:
|
||||
- True when successful
|
||||
- None if member does not exist
|
||||
@@ -517,31 +517,31 @@ class DiscordClient:
|
||||
)
|
||||
except (ValueError, KeyError):
|
||||
result = False
|
||||
|
||||
|
||||
return result
|
||||
|
||||
# Internal methods
|
||||
|
||||
def _api_request(
|
||||
self,
|
||||
method: str,
|
||||
route: str,
|
||||
data: dict = None,
|
||||
self,
|
||||
method: str,
|
||||
route: str,
|
||||
data: dict = None,
|
||||
authorization: str = None,
|
||||
raise_for_status: bool = True
|
||||
) -> requests.Response:
|
||||
"""Core method for performing all API calls"""
|
||||
uid = uuid1().hex
|
||||
|
||||
|
||||
if not hasattr(requests, method):
|
||||
raise ValueError('Invalid method: %s' % method)
|
||||
|
||||
if not authorization:
|
||||
authorization = f'Bot {self.access_token}'
|
||||
|
||||
self._handle_ongoing_api_backoff(uid)
|
||||
|
||||
self._handle_ongoing_api_backoff(uid)
|
||||
if self.is_rate_limited:
|
||||
self._ensure_rate_limed_not_exhausted(uid)
|
||||
self._ensure_rate_limed_not_exhausted(uid)
|
||||
headers = {
|
||||
'User-Agent': f'{AUTH_TITLE} ({__url__}, {__version__})',
|
||||
'accept': 'application/json',
|
||||
@@ -559,21 +559,21 @@ class DiscordClient:
|
||||
}
|
||||
if data:
|
||||
args['json'] = data
|
||||
|
||||
|
||||
logger.info('%s: sending %s request to url \'%s\'', uid, method.upper(), url)
|
||||
logger.debug('%s: request headers: %s', uid, headers)
|
||||
r = getattr(requests, method)(**args)
|
||||
logger.debug(
|
||||
'%s: returned status code %d with headers: %s',
|
||||
uid,
|
||||
r.status_code,
|
||||
'%s: returned status code %d with headers: %s',
|
||||
uid,
|
||||
r.status_code,
|
||||
r.headers
|
||||
)
|
||||
logger.debug('%s: response:\n%s', uid, r.text)
|
||||
if not r.ok:
|
||||
logger.warning(
|
||||
'%s: Discord API returned error code %d and this response: %s',
|
||||
uid,
|
||||
uid,
|
||||
r.status_code,
|
||||
r.text
|
||||
)
|
||||
@@ -582,15 +582,15 @@ class DiscordClient:
|
||||
self._handle_new_api_backoff(r, uid)
|
||||
|
||||
self._report_rate_limit_from_api(r, uid)
|
||||
|
||||
|
||||
if raise_for_status:
|
||||
r.raise_for_status()
|
||||
|
||||
|
||||
return r
|
||||
|
||||
def _handle_ongoing_api_backoff(self, uid: str) -> None:
|
||||
def _handle_ongoing_api_backoff(self, uid: str) -> None:
|
||||
"""checks if api is currently on backoff
|
||||
if on backoff: will do a blocking wait if it expires soon,
|
||||
if on backoff: will do a blocking wait if it expires soon,
|
||||
else raises exception
|
||||
"""
|
||||
global_backoff_duration = self._redis.pttl(self._KEY_GLOBAL_BACKOFF_UNTIL)
|
||||
@@ -611,52 +611,52 @@ class DiscordClient:
|
||||
raise DiscordTooManyRequestsError(retry_after=global_backoff_duration)
|
||||
|
||||
def _ensure_rate_limed_not_exhausted(self, uid: str) -> int:
|
||||
"""ensures that the rate limit is not exhausted
|
||||
if exhausted: will do a blocking wait if rate limit resets soon,
|
||||
"""ensures that the rate limit is not exhausted
|
||||
if exhausted: will do a blocking wait if rate limit resets soon,
|
||||
else raises exception
|
||||
|
||||
returns requests remaining on success
|
||||
"""
|
||||
for _ in range(RATE_LIMIT_RETRIES):
|
||||
requests_remaining = self._redis_decr_or_set(
|
||||
name=self._KEY_GLOBAL_RATE_LIMIT_REMAINING,
|
||||
value=RATE_LIMIT_MAX_REQUESTS,
|
||||
name=self._KEY_GLOBAL_RATE_LIMIT_REMAINING,
|
||||
value=RATE_LIMIT_MAX_REQUESTS,
|
||||
px=RATE_LIMIT_RESETS_AFTER + DURATION_CONTINGENCY
|
||||
)
|
||||
)
|
||||
resets_in = max(
|
||||
MINIMUM_BLOCKING_WAIT,
|
||||
MINIMUM_BLOCKING_WAIT,
|
||||
self._redis.pttl(self._KEY_GLOBAL_RATE_LIMIT_REMAINING)
|
||||
)
|
||||
if requests_remaining >= 0:
|
||||
logger.debug(
|
||||
'%s: Got one of %d remaining requests until reset in %s ms',
|
||||
uid,
|
||||
uid,
|
||||
requests_remaining + 1,
|
||||
resets_in
|
||||
)
|
||||
return requests_remaining
|
||||
|
||||
elif resets_in < WAIT_THRESHOLD:
|
||||
elif resets_in < WAIT_THRESHOLD:
|
||||
sleep(resets_in / 1000)
|
||||
logger.debug(
|
||||
'%s: No requests remaining until reset in %d ms. '
|
||||
'Waiting for reset.',
|
||||
uid,
|
||||
uid,
|
||||
resets_in
|
||||
)
|
||||
continue
|
||||
|
||||
else:
|
||||
else:
|
||||
logger.debug(
|
||||
'%s: No requests remaining until reset in %d ms. '
|
||||
'Raising exception.',
|
||||
uid,
|
||||
uid,
|
||||
resets_in
|
||||
)
|
||||
raise DiscordRateLimitExhausted(resets_in)
|
||||
|
||||
raise RuntimeError('Failed to handle rate limit after after too tries.')
|
||||
|
||||
|
||||
def _handle_new_api_backoff(self, r: requests.Response, uid: str) -> None:
|
||||
"""raises exception for new API backoff error"""
|
||||
response = r.json()
|
||||
@@ -669,7 +669,7 @@ class DiscordClient:
|
||||
else:
|
||||
retry_after = DEFAULT_BACKOFF_DELAY
|
||||
self._redis_set_if_longer(
|
||||
name=self._KEY_GLOBAL_BACKOFF_UNTIL,
|
||||
name=self._KEY_GLOBAL_BACKOFF_UNTIL,
|
||||
value='GLOBAL_API_BACKOFF',
|
||||
px=retry_after
|
||||
)
|
||||
@@ -684,8 +684,8 @@ class DiscordClient:
|
||||
"""Tries to log the current rate limit reported from API"""
|
||||
if (
|
||||
logger.getEffectiveLevel() <= logging.DEBUG
|
||||
and 'x-ratelimit-limit' in r.headers
|
||||
and 'x-ratelimit-remaining' in r.headers
|
||||
and 'x-ratelimit-limit' in r.headers
|
||||
and 'x-ratelimit-remaining' in r.headers
|
||||
and 'x-ratelimit-reset-after' in r.headers
|
||||
):
|
||||
try:
|
||||
@@ -701,7 +701,7 @@ class DiscordClient:
|
||||
)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _redis_decode(value: str) -> str:
|
||||
"""Decodes a string from Redis and passes through None and Booleans"""
|
||||
|
||||
@@ -3,18 +3,18 @@ import math
|
||||
|
||||
class DiscordClientException(Exception):
|
||||
"""Base Exception for the Discord client"""
|
||||
|
||||
|
||||
|
||||
class DiscordApiBackoff(DiscordClientException):
|
||||
"""Exception signaling we need to backoff from sending requests to the API for now
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, retry_after: int):
|
||||
"""
|
||||
:param retry_after: int time to retry after in milliseconds
|
||||
"""
|
||||
super().__init__()
|
||||
self.retry_after = int(retry_after)
|
||||
self.retry_after = int(retry_after)
|
||||
|
||||
@property
|
||||
def retry_after_seconds(self):
|
||||
@@ -22,12 +22,12 @@ class DiscordApiBackoff(DiscordClientException):
|
||||
|
||||
|
||||
class DiscordRateLimitExhausted(DiscordApiBackoff):
|
||||
"""Exception signaling that the total number of requests allowed under the
|
||||
"""Exception signaling that the total number of requests allowed under the
|
||||
current rate limit have been exhausted and weed to wait until next reset.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
class DiscordTooManyRequestsError(DiscordApiBackoff):
|
||||
"""API has responded with a 429 Too Many Requests Error.
|
||||
"""API has responded with a 429 Too Many Requests Error.
|
||||
Need to backoff for now.
|
||||
"""
|
||||
"""
|
||||
|
||||
@@ -3,10 +3,10 @@ from copy import copy
|
||||
|
||||
class DiscordRoles:
|
||||
"""Container class that helps dealing with Discord roles.
|
||||
|
||||
|
||||
Objects of this class are immutable and work in many ways like sets.
|
||||
|
||||
Ideally objects are initialized from raw API responses,
|
||||
|
||||
Ideally objects are initialized from raw API responses,
|
||||
e.g. from DiscordClient.guild.roles()
|
||||
"""
|
||||
_ROLE_NAME_MAX_CHARS = 100
|
||||
@@ -21,7 +21,7 @@ class DiscordRoles:
|
||||
self._assert_valid_role(role)
|
||||
self._roles[int(role['id'])] = role
|
||||
self._roles_by_name[self.sanitize_role_name(role['name'])] = role
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, type(self)):
|
||||
return self.ids() == other.ids()
|
||||
@@ -29,31 +29,31 @@ class DiscordRoles:
|
||||
|
||||
def __hash__(self):
|
||||
return hash(tuple(sorted(self._roles.keys())))
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
for role in self._roles.values():
|
||||
yield role
|
||||
|
||||
def __contains__(self, item) -> bool:
|
||||
def __contains__(self, item) -> bool:
|
||||
return int(item) in self._roles
|
||||
|
||||
def __len__(self):
|
||||
def __len__(self):
|
||||
return len(self._roles.keys())
|
||||
|
||||
|
||||
def has_roles(self, role_ids: set) -> bool:
|
||||
"""returns true if this objects contains all roles defined by given role_ids
|
||||
incl. managed roles
|
||||
"""
|
||||
role_ids = {int(id) for id in role_ids}
|
||||
all_role_ids = self._roles.keys()
|
||||
all_role_ids = self._roles.keys()
|
||||
return role_ids.issubset(all_role_ids)
|
||||
|
||||
|
||||
def ids(self) -> set:
|
||||
"""return a set of all role IDs"""
|
||||
return set(self._roles.keys())
|
||||
|
||||
def subset(self, role_ids: set = None, managed_only: bool = False) -> object:
|
||||
"""returns a new object containing the subset of roles as defined
|
||||
"""returns a new object containing the subset of roles as defined
|
||||
by given role IDs and/or including managed roles only
|
||||
"""
|
||||
if role_ids is not None:
|
||||
@@ -68,23 +68,23 @@ class DiscordRoles:
|
||||
return type(self)([
|
||||
role for _, role in self._roles.items() if role['managed']
|
||||
])
|
||||
|
||||
|
||||
elif role_ids is not None and managed_only:
|
||||
return type(self)([
|
||||
role for role_id, role in self._roles.items()
|
||||
role for role_id, role in self._roles.items()
|
||||
if role_id in role_ids and role['managed']
|
||||
])
|
||||
|
||||
|
||||
else:
|
||||
return copy(self)
|
||||
|
||||
def union(self, other: object) -> object:
|
||||
"""returns a new roles object that is the union of this roles object
|
||||
"""returns a new roles object that is the union of this roles object
|
||||
with other"""
|
||||
return type(self)(list(self) + list(other))
|
||||
|
||||
def difference(self, other: object) -> object:
|
||||
"""returns a new roles object that only contains the roles
|
||||
"""returns a new roles object that only contains the roles
|
||||
that exist in the current objects, but not in other
|
||||
"""
|
||||
new_ids = self.ids().difference(other.ids())
|
||||
@@ -97,11 +97,11 @@ class DiscordRoles:
|
||||
return self._roles_by_name[role_name]
|
||||
else:
|
||||
return dict()
|
||||
|
||||
|
||||
@classmethod
|
||||
def create_from_matched_roles(cls, matched_roles: list) -> None:
|
||||
"""returns a new object created from the given list of matches roles
|
||||
|
||||
|
||||
matches_roles must be a list of tuples in the form: (role, created)
|
||||
"""
|
||||
raw_roles = [x[0] for x in matched_roles]
|
||||
@@ -111,10 +111,10 @@ class DiscordRoles:
|
||||
def _assert_valid_role(role: dict):
|
||||
if not isinstance(role, dict):
|
||||
raise TypeError('Roles must be of type dict: %s' % role)
|
||||
|
||||
|
||||
if 'id' not in role or 'name' not in role or 'managed' not in role:
|
||||
raise ValueError('This role is not valid: %s' % role)
|
||||
|
||||
|
||||
@classmethod
|
||||
def sanitize_role_name(cls, role_name: str) -> str:
|
||||
"""shortens too long strings if necessary"""
|
||||
|
||||
@@ -27,8 +27,8 @@ ALL_ROLES = [ROLE_ALPHA, ROLE_BRAVO, ROLE_CHARLIE, ROLE_MIKE]
|
||||
|
||||
|
||||
def create_user_info(
|
||||
id: int = TEST_USER_ID,
|
||||
username: str = TEST_USER_NAME,
|
||||
id: int = TEST_USER_ID,
|
||||
username: str = TEST_USER_NAME,
|
||||
discriminator: str = TEST_USER_DISCRIMINATOR
|
||||
):
|
||||
return {
|
||||
|
||||
@@ -5,11 +5,11 @@ The results can be analysed in a special log file.
|
||||
|
||||
This script is design to be run manually as unit test, e.g. by running the following:
|
||||
|
||||
python manage.py test
|
||||
python manage.py test
|
||||
allianceauth.services.modules.discord.discord_client.tests.piloting_concurrency
|
||||
|
||||
To make it work please set the below mentioned environment variables for your server.
|
||||
Since this may cause lots of 429s we'd recommend NOT to use your
|
||||
Since this may cause lots of 429s we'd recommend NOT to use your
|
||||
alliance Discord server for this.
|
||||
"""
|
||||
|
||||
@@ -49,7 +49,7 @@ def worker(num: int):
|
||||
client = DiscordClient(DISCORD_BOT_TOKEN)
|
||||
try:
|
||||
runs = 0
|
||||
while runs < NUMBER_OF_RUNS:
|
||||
while runs < NUMBER_OF_RUNS:
|
||||
run_info = '%s: run %d' % (worker_info, runs + 1)
|
||||
my_jitter_secs = random() * MAX_JITTER_PER_RUN_SECS
|
||||
logger.info('%s - waiting %s secs', run_info, f'{my_jitter_secs:.3f}')
|
||||
@@ -67,18 +67,18 @@ def worker(num: int):
|
||||
logger.info(message)
|
||||
print()
|
||||
print(message)
|
||||
sleep(bo.retry_after / 1000)
|
||||
|
||||
sleep(bo.retry_after / 1000)
|
||||
|
||||
except Exception as ex:
|
||||
logger.exception('%s: Processing aborted: %s', worker_info, ex)
|
||||
|
||||
|
||||
logger.info('%s: finished', worker_info)
|
||||
return
|
||||
|
||||
|
||||
class TestMulti(TestCase):
|
||||
|
||||
def test_multi(self):
|
||||
|
||||
def test_multi(self):
|
||||
logger.info('Starting multi test')
|
||||
for num in range(NUMBER_OF_WORKERS):
|
||||
x = threading.Thread(target=worker, args=(num + 1,))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""This script is for functional testing of the Discord client with a Discord server
|
||||
|
||||
It will run single requests of the various functions to validate
|
||||
that they actually work - excluding those that require Oauth, or does not work
|
||||
It will run single requests of the various functions to validate
|
||||
that they actually work - excluding those that require Oauth, or does not work
|
||||
with a bot token. The results can be also seen in a special log file.
|
||||
|
||||
This script is design to be run manually as unit test, e.g. by running the following:
|
||||
@@ -10,7 +10,7 @@ python manage.py test
|
||||
allianceauth.services.modules.discord.discord_self.client.tests.piloting_functionality
|
||||
|
||||
To make it work please set the below mentioned environment variables for your server.
|
||||
Since this may cause lots of 429s we'd recommend NOT to use your
|
||||
Since this may cause lots of 429s we'd recommend NOT to use your
|
||||
alliance Discord server for this.
|
||||
"""
|
||||
|
||||
@@ -46,7 +46,7 @@ class TestDiscordApiLive(TestCase):
|
||||
"""runs features that have not been run in any of the other tests"""
|
||||
self.client.guild_infos(DISCORD_GUILD_ID)
|
||||
sleep(RATE_LIMIT_DELAY_SECS)
|
||||
|
||||
|
||||
self.client.guild_name(DISCORD_GUILD_ID)
|
||||
sleep(RATE_LIMIT_DELAY_SECS)
|
||||
|
||||
@@ -57,9 +57,9 @@ class TestDiscordApiLive(TestCase):
|
||||
DISCORD_GUILD_ID, ['Testrole A', 'Testrole B']
|
||||
)
|
||||
sleep(RATE_LIMIT_DELAY_SECS)
|
||||
|
||||
def test_create_and_remove_roles(self):
|
||||
# get base
|
||||
|
||||
def test_create_and_remove_roles(self):
|
||||
# get base
|
||||
logger.info('guild_roles')
|
||||
expected = {role['id'] for role in self.client.guild_roles(DISCORD_GUILD_ID)}
|
||||
|
||||
@@ -70,8 +70,8 @@ class TestDiscordApiLive(TestCase):
|
||||
guild_id=DISCORD_GUILD_ID, role_name=role_name
|
||||
)
|
||||
sleep(RATE_LIMIT_DELAY_SECS)
|
||||
self.assertEqual(new_role['name'], role_name)
|
||||
|
||||
self.assertEqual(new_role['name'], role_name)
|
||||
|
||||
# remove role again
|
||||
logger.info('delete_guild_role')
|
||||
self.client.delete_guild_role(
|
||||
@@ -102,7 +102,7 @@ class TestDiscordApiLive(TestCase):
|
||||
sleep(RATE_LIMIT_DELAY_SECS)
|
||||
self.assertEqual(user['nick'], new_nick)
|
||||
|
||||
def test_member_add_remove_roles(self):
|
||||
def test_member_add_remove_roles(self):
|
||||
# create new guild role
|
||||
logger.info('create_guild_role')
|
||||
new_role = self.client.create_guild_role(
|
||||
@@ -110,7 +110,7 @@ class TestDiscordApiLive(TestCase):
|
||||
)
|
||||
sleep(RATE_LIMIT_DELAY_SECS)
|
||||
new_role_id = new_role['id']
|
||||
|
||||
|
||||
# add to member
|
||||
logger.info('add_guild_member_role')
|
||||
self.assertTrue(
|
||||
@@ -119,7 +119,7 @@ class TestDiscordApiLive(TestCase):
|
||||
)
|
||||
)
|
||||
sleep(RATE_LIMIT_DELAY_SECS)
|
||||
|
||||
|
||||
# remove again
|
||||
logger.info('remove_guild_member_role')
|
||||
self.assertTrue(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from ..exceptions import (
|
||||
DiscordApiBackoff,
|
||||
DiscordClientException,
|
||||
DiscordApiBackoff,
|
||||
DiscordClientException,
|
||||
DiscordRateLimitExhausted,
|
||||
DiscordTooManyRequestsError
|
||||
)
|
||||
|
||||
@@ -25,7 +25,7 @@ class TestDiscordRoles(TestCase):
|
||||
def test_raises_exception_if_roles_raw_of_wrong_type(self):
|
||||
with self.assertRaises(TypeError):
|
||||
DiscordRoles({'id': 1})
|
||||
|
||||
|
||||
def test_raises_exception_if_list_contains_non_dict(self):
|
||||
roles_raw = [ROLE_ALPHA, 'not_valid']
|
||||
with self.assertRaises(TypeError):
|
||||
@@ -45,7 +45,7 @@ class TestDiscordRoles(TestCase):
|
||||
roles_raw = [{'id': 1, 'name': 'alpha'}]
|
||||
with self.assertRaises(ValueError):
|
||||
DiscordRoles(roles_raw)
|
||||
|
||||
|
||||
def test_roles_are_equal(self):
|
||||
roles_a = DiscordRoles([ROLE_ALPHA, ROLE_BRAVO])
|
||||
roles_b = DiscordRoles([ROLE_ALPHA, ROLE_BRAVO])
|
||||
@@ -57,19 +57,19 @@ class TestDiscordRoles(TestCase):
|
||||
self.assertNotEqual(roles_a, roles_b)
|
||||
|
||||
def test_different_objects_are_not_equal(self):
|
||||
roles_a = DiscordRoles([ROLE_ALPHA, ROLE_BRAVO])
|
||||
roles_a = DiscordRoles([ROLE_ALPHA, ROLE_BRAVO])
|
||||
self.assertFalse(roles_a == "invalid")
|
||||
|
||||
def test_len(self):
|
||||
def test_len(self):
|
||||
self.assertEqual(len(self.all_roles), 4)
|
||||
|
||||
def test_contains(self):
|
||||
self.assertTrue(1 in self.all_roles)
|
||||
self.assertFalse(99 in self.all_roles)
|
||||
|
||||
def test_sanitize_role_name(self):
|
||||
def test_sanitize_role_name(self):
|
||||
role_name_input = 'x' * 110
|
||||
role_name_expected = 'x' * 100
|
||||
role_name_expected = 'x' * 100
|
||||
result = DiscordRoles.sanitize_role_name(role_name_input)
|
||||
self.assertEqual(result, role_name_expected)
|
||||
|
||||
@@ -94,8 +94,8 @@ class TestIds(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.all_roles = DiscordRoles(ALL_ROLES)
|
||||
|
||||
def test_return_role_ids_default(self):
|
||||
|
||||
def test_return_role_ids_default(self):
|
||||
result = self.all_roles.ids()
|
||||
expected = {1, 2, 3, 13}
|
||||
self.assertSetEqual(result, expected)
|
||||
@@ -154,7 +154,7 @@ class TestHasRoles(TestCase):
|
||||
|
||||
def test_true_if_all_roles_exit_str(self):
|
||||
self.assertTrue(self.all_roles.has_roles(['1', '2']))
|
||||
|
||||
|
||||
def test_false_if_role_does_not_exit(self):
|
||||
self.assertFalse(self.all_roles.has_roles([99]))
|
||||
|
||||
@@ -163,7 +163,7 @@ class TestHasRoles(TestCase):
|
||||
|
||||
def test_true_for_empty_roles(self):
|
||||
self.assertTrue(self.all_roles.has_roles([]))
|
||||
|
||||
|
||||
|
||||
class TestGetMatchingRolesByName(TestCase):
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ from .app_settings import (
|
||||
DISCORD_APP_SECRET,
|
||||
DISCORD_BOT_TOKEN,
|
||||
DISCORD_CALLBACK_URL,
|
||||
DISCORD_GUILD_ID,
|
||||
DISCORD_GUILD_ID,
|
||||
DISCORD_SYNC_NAMES
|
||||
)
|
||||
from .discord_client import DiscordClient
|
||||
@@ -41,9 +41,9 @@ class DiscordUserManager(models.Manager):
|
||||
]
|
||||
|
||||
def add_user(
|
||||
self,
|
||||
user: User,
|
||||
authorization_code: str,
|
||||
self,
|
||||
user: User,
|
||||
authorization_code: str,
|
||||
is_rate_limited: bool = True
|
||||
) -> bool:
|
||||
"""adds a new Discord user
|
||||
@@ -52,10 +52,10 @@ class DiscordUserManager(models.Manager):
|
||||
- user: Auth user to join
|
||||
- authorization_code: authorization code returns from oauth
|
||||
- is_rate_limited: When False will disable default rate limiting (use with care)
|
||||
|
||||
|
||||
Returns: True on success, else False or raises exception
|
||||
"""
|
||||
try:
|
||||
try:
|
||||
nickname = self.user_formatted_nick(user) if DISCORD_SYNC_NAMES else None
|
||||
group_names = self.user_group_names(user)
|
||||
access_token = self._exchange_auth_code_for_token(authorization_code)
|
||||
@@ -63,18 +63,18 @@ class DiscordUserManager(models.Manager):
|
||||
discord_user = user_client.current_user()
|
||||
user_id = discord_user['id']
|
||||
bot_client = self._bot_client(is_rate_limited=is_rate_limited)
|
||||
|
||||
if group_names:
|
||||
|
||||
if group_names:
|
||||
role_ids = match_or_create_roles_from_names(
|
||||
client=bot_client,
|
||||
guild_id=DISCORD_GUILD_ID,
|
||||
client=bot_client,
|
||||
guild_id=DISCORD_GUILD_ID,
|
||||
role_names=group_names
|
||||
).ids()
|
||||
else:
|
||||
role_ids = None
|
||||
|
||||
|
||||
created = bot_client.add_guild_member(
|
||||
guild_id=DISCORD_GUILD_ID,
|
||||
guild_id=DISCORD_GUILD_ID,
|
||||
user_id=user_id,
|
||||
access_token=access_token,
|
||||
role_ids=role_ids,
|
||||
@@ -88,10 +88,10 @@ class DiscordUserManager(models.Manager):
|
||||
user_id,
|
||||
)
|
||||
self.update_or_create(
|
||||
user=user,
|
||||
user=user,
|
||||
defaults={
|
||||
'uid': user_id,
|
||||
'username': discord_user['username'][:32],
|
||||
'uid': user_id,
|
||||
'username': discord_user['username'][:32],
|
||||
'discriminator': discord_user['discriminator'][:4],
|
||||
'activated': now()
|
||||
}
|
||||
@@ -121,7 +121,7 @@ class DiscordUserManager(models.Manager):
|
||||
or None if user has no main
|
||||
"""
|
||||
from .auth_hooks import DiscordService
|
||||
|
||||
|
||||
if user.profile.main_character:
|
||||
return NameFormatter(DiscordService(), user).format_name()
|
||||
else:
|
||||
@@ -139,10 +139,10 @@ class DiscordUserManager(models.Manager):
|
||||
"Group names for roles updates of user %s are: %s", user, group_names
|
||||
)
|
||||
return group_names
|
||||
|
||||
|
||||
def user_has_account(self, user: User) -> bool:
|
||||
"""Returns True if the user has an Discord account, else False
|
||||
|
||||
|
||||
only checks locally, does not hit the API
|
||||
"""
|
||||
if not isinstance(user, User):
|
||||
@@ -157,7 +157,7 @@ class DiscordUserManager(models.Manager):
|
||||
'permissions': str(cls.BOT_PERMISSIONS)
|
||||
|
||||
})
|
||||
return f'{DiscordClient.OAUTH_BASE_URL}?{params}'
|
||||
return f'{DiscordClient.OAUTH_BASE_URL}?{params}'
|
||||
|
||||
@classmethod
|
||||
def generate_oauth_redirect_url(cls) -> str:
|
||||
@@ -171,16 +171,16 @@ class DiscordUserManager(models.Manager):
|
||||
def _exchange_auth_code_for_token(authorization_code: str) -> str:
|
||||
oauth = OAuth2Session(DISCORD_APP_ID, redirect_uri=DISCORD_CALLBACK_URL)
|
||||
token = oauth.fetch_token(
|
||||
DiscordClient.OAUTH_TOKEN_URL,
|
||||
client_secret=DISCORD_APP_SECRET,
|
||||
DiscordClient.OAUTH_TOKEN_URL,
|
||||
client_secret=DISCORD_APP_SECRET,
|
||||
code=authorization_code
|
||||
)
|
||||
logger.debug("Received token from OAuth")
|
||||
return token['access_token']
|
||||
|
||||
|
||||
@classmethod
|
||||
def server_name(cls, use_cache: bool = True) -> str:
|
||||
"""returns the name of the current Discord server
|
||||
"""returns the name of the current Discord server
|
||||
or an empty string if the name could not be retrieved
|
||||
|
||||
Params:
|
||||
@@ -194,7 +194,7 @@ class DiscordUserManager(models.Manager):
|
||||
server_name = ""
|
||||
except Exception:
|
||||
logger.warning(
|
||||
"Unexpected error when trying to retrieve the server name from Discord",
|
||||
"Unexpected error when trying to retrieve the server name from Discord",
|
||||
exc_info=True
|
||||
)
|
||||
server_name = ""
|
||||
|
||||
@@ -22,11 +22,11 @@ logger = LoggerAddTag(logging.getLogger(__name__), __title__)
|
||||
class DiscordUser(models.Model):
|
||||
|
||||
USER_RELATED_NAME = 'discord'
|
||||
|
||||
|
||||
user = models.OneToOneField(
|
||||
User,
|
||||
primary_key=True,
|
||||
on_delete=models.CASCADE,
|
||||
User,
|
||||
primary_key=True,
|
||||
on_delete=models.CASCADE,
|
||||
related_name=USER_RELATED_NAME,
|
||||
help_text='Auth user owning this Discord account'
|
||||
)
|
||||
@@ -35,21 +35,21 @@ class DiscordUser(models.Model):
|
||||
help_text='user\'s ID on Discord'
|
||||
)
|
||||
username = models.CharField(
|
||||
max_length=32,
|
||||
default='',
|
||||
max_length=32,
|
||||
default='',
|
||||
blank=True,
|
||||
db_index=True,
|
||||
help_text='user\'s username on Discord'
|
||||
)
|
||||
discriminator = models.CharField(
|
||||
max_length=4,
|
||||
default='',
|
||||
blank=True,
|
||||
max_length=4,
|
||||
default='',
|
||||
blank=True,
|
||||
help_text='user\'s discriminator on Discord'
|
||||
)
|
||||
activated = models.DateTimeField(
|
||||
default=None,
|
||||
null=True,
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text='Date & time this service account was activated'
|
||||
)
|
||||
@@ -77,11 +77,11 @@ class DiscordUser(models.Model):
|
||||
- True on success
|
||||
- None if user is no longer a member of the Discord server
|
||||
- False on error or raises exception
|
||||
"""
|
||||
"""
|
||||
if not nickname:
|
||||
nickname = DiscordUser.objects.user_formatted_nick(self.user)
|
||||
if nickname:
|
||||
client = DiscordUser.objects._bot_client()
|
||||
if nickname:
|
||||
client = DiscordUser.objects._bot_client()
|
||||
success = client.modify_guild_member(
|
||||
guild_id=DISCORD_GUILD_ID,
|
||||
user_id=self.uid,
|
||||
@@ -92,14 +92,14 @@ class DiscordUser(models.Model):
|
||||
else:
|
||||
logger.warning('Failed to update nickname for %s', self.user)
|
||||
return success
|
||||
|
||||
|
||||
else:
|
||||
return False
|
||||
|
||||
def update_groups(self, state_name: str = None) -> bool:
|
||||
"""update groups for a user based on his current group memberships.
|
||||
"""update groups for a user based on his current group memberships.
|
||||
Will add or remove roles of a user as needed.
|
||||
|
||||
|
||||
Params:
|
||||
- state_name: optional state name to be used
|
||||
|
||||
@@ -107,13 +107,13 @@ class DiscordUser(models.Model):
|
||||
- True on success
|
||||
- None if user is no longer a member of the Discord server
|
||||
- False on error or raises exception
|
||||
"""
|
||||
client = DiscordUser.objects._bot_client()
|
||||
"""
|
||||
client = DiscordUser.objects._bot_client()
|
||||
member_info = client.guild_member(guild_id=DISCORD_GUILD_ID, user_id=self.uid)
|
||||
if member_info is None:
|
||||
if member_info is None:
|
||||
# User is no longer a member
|
||||
return None
|
||||
|
||||
|
||||
guild_roles = DiscordRoles(client.guild_roles(guild_id=DISCORD_GUILD_ID))
|
||||
logger.debug('Current guild roles: %s', guild_roles.ids())
|
||||
if 'roles' in member_info:
|
||||
@@ -124,17 +124,17 @@ class DiscordUser(models.Model):
|
||||
if not guild_roles.has_roles(member_info['roles']):
|
||||
raise RuntimeError(
|
||||
'Member %s has unknown roles: %s' % (
|
||||
self.user,
|
||||
self.user,
|
||||
set(member_info['roles']).difference(guild_roles.ids())
|
||||
)
|
||||
)
|
||||
member_roles = guild_roles.subset(member_info['roles'])
|
||||
else:
|
||||
raise RuntimeError('member_info from %s is not valid' % self.user)
|
||||
|
||||
|
||||
requested_roles = match_or_create_roles_from_names(
|
||||
client=client,
|
||||
guild_id=DISCORD_GUILD_ID,
|
||||
client=client,
|
||||
guild_id=DISCORD_GUILD_ID,
|
||||
role_names=DiscordUser.objects.user_group_names(
|
||||
user=self.user, state_name=state_name
|
||||
)
|
||||
@@ -142,7 +142,7 @@ class DiscordUser(models.Model):
|
||||
logger.debug(
|
||||
'Requested roles for user %s: %s', self.user, requested_roles.ids()
|
||||
)
|
||||
logger.debug('Current roles user %s: %s', self.user, member_roles.ids())
|
||||
logger.debug('Current roles user %s: %s', self.user, member_roles.ids())
|
||||
member_roles_managed = member_roles.subset(managed_only=True)
|
||||
if requested_roles != member_roles.difference(member_roles_managed):
|
||||
logger.debug('Need to update roles for user %s', self.user)
|
||||
@@ -163,25 +163,25 @@ class DiscordUser(models.Model):
|
||||
return True
|
||||
|
||||
def update_username(self) -> bool:
|
||||
"""Updates the username incl. the discriminator
|
||||
"""Updates the username incl. the discriminator
|
||||
from the Discord server and saves it
|
||||
|
||||
|
||||
Returns:
|
||||
- True on success
|
||||
- None if user is no longer a member of the Discord server
|
||||
- False on error or raises exception
|
||||
"""
|
||||
|
||||
client = DiscordUser.objects._bot_client()
|
||||
"""
|
||||
|
||||
client = DiscordUser.objects._bot_client()
|
||||
user_info = client.guild_member(guild_id=DISCORD_GUILD_ID, user_id=self.uid)
|
||||
if user_info is None:
|
||||
success = None
|
||||
elif (
|
||||
user_info
|
||||
and 'user' in user_info
|
||||
and 'username' in user_info['user']
|
||||
user_info
|
||||
and 'user' in user_info
|
||||
and 'username' in user_info['user']
|
||||
and 'discriminator' in user_info['user']
|
||||
):
|
||||
):
|
||||
self.username = user_info['user']['username']
|
||||
self.discriminator = user_info['user']['discriminator']
|
||||
self.save()
|
||||
@@ -191,22 +191,22 @@ class DiscordUser(models.Model):
|
||||
logger.warning('Failed to update username for %s', self.user)
|
||||
success = False
|
||||
return success
|
||||
|
||||
|
||||
def delete_user(
|
||||
self,
|
||||
notify_user: bool = False,
|
||||
self,
|
||||
notify_user: bool = False,
|
||||
is_rate_limited: bool = True,
|
||||
handle_api_exceptions: bool = False
|
||||
) -> bool:
|
||||
"""Deletes the Discount user both on the server and locally
|
||||
|
||||
Params:
|
||||
- notify_user: When True will sent a notification to the user
|
||||
- notify_user: When True will sent a notification to the user
|
||||
informing him about the deleting of his account
|
||||
- is_rate_limited: When False will disable default rate limiting (use with care)
|
||||
- handle_api_exceptions: When True method will return False
|
||||
- handle_api_exceptions: When True method will return False
|
||||
when an API exception occurs
|
||||
|
||||
|
||||
Returns True when successful, otherwise False or raises exceptions
|
||||
Return None if user does no longer exist
|
||||
"""
|
||||
@@ -221,8 +221,8 @@ class DiscordUser(models.Model):
|
||||
if deleted_count > 0:
|
||||
if notify_user:
|
||||
notify(
|
||||
user=_user,
|
||||
title=gettext_lazy('Discord Account Disabled'),
|
||||
user=_user,
|
||||
title=gettext_lazy('Discord Account Disabled'),
|
||||
message=gettext_lazy(
|
||||
'Your Discord account was disabled automatically '
|
||||
'by Auth. If you think this was a mistake, '
|
||||
@@ -235,18 +235,18 @@ class DiscordUser(models.Model):
|
||||
else:
|
||||
logger.debug('Account for user %s was already deleted.', _user)
|
||||
return None
|
||||
|
||||
|
||||
else:
|
||||
logger.warning(
|
||||
'Failed to remove user %s from the Discord server', _user
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
except (HTTPError, ConnectionError, DiscordApiBackoff) as ex:
|
||||
if handle_api_exceptions:
|
||||
logger.exception(
|
||||
'Failed to remove user %s from Discord server: %s',self.user, ex
|
||||
)
|
||||
return False
|
||||
return False
|
||||
else:
|
||||
raise ex
|
||||
|
||||
@@ -29,11 +29,11 @@ BULK_TASK_PRIORITY = 6
|
||||
)
|
||||
def update_groups(self, user_pk: int, state_name: str = None) -> None:
|
||||
"""Update roles on Discord for given user according to his current groups
|
||||
|
||||
|
||||
Params:
|
||||
- user_pk: PK of given user
|
||||
- state_name: optional state name to be used
|
||||
"""
|
||||
"""
|
||||
_task_perform_user_action(self, user_pk, 'update_groups', state_name=state_name)
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ def update_groups(self, user_pk: int, state_name: str = None) -> None:
|
||||
)
|
||||
def update_nickname(self, user_pk: int, nickname: str = None) -> None:
|
||||
"""Set nickname on Discord for given user to his main character name
|
||||
|
||||
|
||||
Params:
|
||||
- user_pk: PK of given user
|
||||
- nickname: optional nickname to be used instead of user's main
|
||||
@@ -55,7 +55,7 @@ def update_nickname(self, user_pk: int, nickname: str = None) -> None:
|
||||
)
|
||||
def update_username(self, user_pk: int) -> None:
|
||||
"""Update locally stored Discord username from Discord server for given user
|
||||
|
||||
|
||||
Params:
|
||||
- user_pk: PK of given user
|
||||
"""
|
||||
@@ -67,7 +67,7 @@ def update_username(self, user_pk: int) -> None:
|
||||
)
|
||||
def delete_user(self, user_pk: int, notify_user: bool = False) -> None:
|
||||
"""Delete Discord user
|
||||
|
||||
|
||||
Params:
|
||||
- user_pk: PK of given user
|
||||
"""
|
||||
@@ -77,13 +77,13 @@ def delete_user(self, user_pk: int, notify_user: bool = False) -> None:
|
||||
def _task_perform_user_action(self, user_pk: int, method: str, **kwargs) -> None:
|
||||
"""perform a user related action incl. managing all exceptions"""
|
||||
logger.debug("Starting %s for user with pk %s", method, user_pk)
|
||||
user = User.objects.get(pk=user_pk)
|
||||
user = User.objects.get(pk=user_pk)
|
||||
# logger.debug("user %s has state %s", user, user.profile.state)
|
||||
if DiscordUser.objects.user_has_account(user):
|
||||
logger.info("Running %s for user %s", method, user)
|
||||
try:
|
||||
success = getattr(user.discord, method)(**kwargs)
|
||||
|
||||
|
||||
except DiscordApiBackoff as bo:
|
||||
logger.info(
|
||||
"API back off for %s wth user %s due to %r, retrying in %s seconds",
|
||||
@@ -92,26 +92,26 @@ def _task_perform_user_action(self, user_pk: int, method: str, **kwargs) -> None
|
||||
bo,
|
||||
bo.retry_after_seconds
|
||||
)
|
||||
raise self.retry(countdown=bo.retry_after_seconds)
|
||||
|
||||
raise self.retry(countdown=bo.retry_after_seconds)
|
||||
|
||||
except AttributeError:
|
||||
raise ValueError(f'{method} not a valid method for DiscordUser')
|
||||
|
||||
except (HTTPError, ConnectionError):
|
||||
except (HTTPError, ConnectionError):
|
||||
logger.warning(
|
||||
'%s failed for user %s, retrying in %d secs',
|
||||
'%s failed for user %s, retrying in %d secs',
|
||||
method,
|
||||
user,
|
||||
user,
|
||||
DISCORD_TASKS_RETRY_PAUSE,
|
||||
exc_info=True
|
||||
)
|
||||
if self.request.retries < DISCORD_TASKS_MAX_RETRIES:
|
||||
raise self.retry(countdown=DISCORD_TASKS_RETRY_PAUSE)
|
||||
else:
|
||||
else:
|
||||
logger.error(
|
||||
'%s failed for user %s after max retries',
|
||||
method,
|
||||
user,
|
||||
user,
|
||||
exc_info=True
|
||||
)
|
||||
except Exception:
|
||||
@@ -120,8 +120,8 @@ def _task_perform_user_action(self, user_pk: int, method: str, **kwargs) -> None
|
||||
method,
|
||||
user,
|
||||
exc_info=True
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
else:
|
||||
if success is None and method != 'delete_user':
|
||||
delete_user.delay(user.pk, notify_user=True)
|
||||
@@ -134,14 +134,14 @@ def _task_perform_user_action(self, user_pk: int, method: str, **kwargs) -> None
|
||||
|
||||
@shared_task(name='discord.update_all_groups')
|
||||
def update_all_groups() -> None:
|
||||
"""Update roles for all known users with a Discord account."""
|
||||
"""Update roles for all known users with a Discord account."""
|
||||
discord_users_qs = DiscordUser.objects.all()
|
||||
_bulk_update_groups_for_users(discord_users_qs)
|
||||
|
||||
|
||||
@shared_task(name='discord.update_groups_bulk')
|
||||
def update_groups_bulk(user_pks: list) -> None:
|
||||
"""Update roles for list of users with a Discord account in bulk."""
|
||||
"""Update roles for list of users with a Discord account in bulk."""
|
||||
discord_users_qs = DiscordUser.objects\
|
||||
.filter(user__pk__in=user_pks)\
|
||||
.select_related()
|
||||
@@ -155,7 +155,7 @@ def _bulk_update_groups_for_users(discord_users_qs: QuerySet) -> None:
|
||||
update_groups_chain = list()
|
||||
for discord_user in discord_users_qs:
|
||||
update_groups_chain.append(update_groups.si(discord_user.user.pk))
|
||||
|
||||
|
||||
chain(update_groups_chain).apply_async(priority=BULK_TASK_PRIORITY)
|
||||
|
||||
|
||||
@@ -164,11 +164,11 @@ def update_all_nicknames() -> None:
|
||||
"""Update nicknames for all known users with a Discord account."""
|
||||
discord_users_qs = DiscordUser.objects.all()
|
||||
_bulk_update_nicknames_for_users(discord_users_qs)
|
||||
|
||||
|
||||
|
||||
@shared_task(name='discord.update_nicknames_bulk')
|
||||
def update_nicknames_bulk(user_pks: list) -> None:
|
||||
"""Update nicknames for list of users with a Discord account in bulk."""
|
||||
"""Update nicknames for list of users with a Discord account in bulk."""
|
||||
discord_users_qs = DiscordUser.objects\
|
||||
.filter(user__pk__in=user_pks)\
|
||||
.select_related()
|
||||
@@ -177,27 +177,27 @@ def update_nicknames_bulk(user_pks: list) -> None:
|
||||
|
||||
def _bulk_update_nicknames_for_users(discord_users_qs: QuerySet) -> None:
|
||||
logger.info(
|
||||
"Starting to bulk update discord nicknames for %d users",
|
||||
"Starting to bulk update discord nicknames for %d users",
|
||||
discord_users_qs.count()
|
||||
)
|
||||
update_nicknames_chain = list()
|
||||
for discord_user in discord_users_qs:
|
||||
update_nicknames_chain.append(update_nickname.si(discord_user.user.pk))
|
||||
|
||||
|
||||
chain(update_nicknames_chain).apply_async(priority=BULK_TASK_PRIORITY)
|
||||
|
||||
|
||||
def _task_perform_users_action(self, method: str, **kwargs) -> Any:
|
||||
"""Perform an action that concerns a group of users or the whole server
|
||||
def _task_perform_users_action(self, method: str, **kwargs) -> Any:
|
||||
"""Perform an action that concerns a group of users or the whole server
|
||||
and that hits the API
|
||||
"""
|
||||
"""
|
||||
result = None
|
||||
try:
|
||||
result = getattr(DiscordUser.objects, method)(**kwargs)
|
||||
|
||||
|
||||
except AttributeError:
|
||||
raise ValueError(f'{method} not a valid method for DiscordUser.objects')
|
||||
|
||||
|
||||
except DiscordApiBackoff as bo:
|
||||
logger.info(
|
||||
"API back off for %s due to %r, retrying in %s seconds",
|
||||
@@ -205,23 +205,23 @@ def _task_perform_users_action(self, method: str, **kwargs) -> Any:
|
||||
bo,
|
||||
bo.retry_after_seconds
|
||||
)
|
||||
raise self.retry(countdown=bo.retry_after_seconds)
|
||||
|
||||
except (HTTPError, ConnectionError):
|
||||
raise self.retry(countdown=bo.retry_after_seconds)
|
||||
|
||||
except (HTTPError, ConnectionError):
|
||||
logger.warning(
|
||||
'%s failed, retrying in %d secs',
|
||||
'%s failed, retrying in %d secs',
|
||||
method,
|
||||
DISCORD_TASKS_RETRY_PAUSE,
|
||||
exc_info=True
|
||||
)
|
||||
if self.request.retries < DISCORD_TASKS_MAX_RETRIES:
|
||||
raise self.retry(countdown=DISCORD_TASKS_RETRY_PAUSE)
|
||||
else:
|
||||
else:
|
||||
logger.error('%s failed after max retries', method, exc_info=True)
|
||||
|
||||
|
||||
except Exception:
|
||||
logger.error('%s failed due to unexpected exception', method, exc_info=True)
|
||||
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -235,17 +235,17 @@ def update_servername(self) -> None:
|
||||
|
||||
@shared_task(name='discord.update_all_usernames')
|
||||
def update_all_usernames() -> None:
|
||||
"""Update all usernames for all known users with a Discord account.
|
||||
"""Update all usernames for all known users with a Discord account.
|
||||
Also updates the server name
|
||||
"""
|
||||
update_servername.delay()
|
||||
discord_users_qs = DiscordUser.objects.all()
|
||||
_bulk_update_usernames_for_users(discord_users_qs)
|
||||
|
||||
|
||||
|
||||
@shared_task(name='discord.update_usernames_bulk')
|
||||
def update_usernames_bulk(user_pks: list) -> None:
|
||||
"""Update usernames for list of users with a Discord account in bulk."""
|
||||
"""Update usernames for list of users with a Discord account in bulk."""
|
||||
discord_users_qs = DiscordUser.objects\
|
||||
.filter(user__pk__in=user_pks)\
|
||||
.select_related()
|
||||
@@ -254,13 +254,13 @@ def update_usernames_bulk(user_pks: list) -> None:
|
||||
|
||||
def _bulk_update_usernames_for_users(discord_users_qs: QuerySet) -> None:
|
||||
logger.info(
|
||||
"Starting to bulk update discord usernames for %d users",
|
||||
"Starting to bulk update discord usernames for %d users",
|
||||
discord_users_qs.count()
|
||||
)
|
||||
update_usernames_chain = list()
|
||||
for discord_user in discord_users_qs:
|
||||
update_usernames_chain.append(update_username.si(discord_user.user.pk))
|
||||
|
||||
|
||||
chain(update_usernames_chain).apply_async(priority=BULK_TASK_PRIORITY)
|
||||
|
||||
|
||||
@@ -277,5 +277,5 @@ def update_all() -> None:
|
||||
update_all_chain.append(update_username.si(discord_user.user.pk))
|
||||
if DISCORD_SYNC_NAMES:
|
||||
update_all_chain.append(update_nickname.si(discord_user.user.pk))
|
||||
|
||||
|
||||
chain(update_all_chain).apply_async(priority=BULK_TASK_PRIORITY)
|
||||
|
||||
@@ -5,14 +5,14 @@ from ..discord_client.tests import ( # noqa
|
||||
TEST_USER_ID,
|
||||
TEST_USER_NAME,
|
||||
TEST_USER_DISCRIMINATOR,
|
||||
create_role,
|
||||
ROLE_ALPHA,
|
||||
ROLE_BRAVO,
|
||||
ROLE_CHARLIE,
|
||||
ROLE_MIKE,
|
||||
create_role,
|
||||
ROLE_ALPHA,
|
||||
ROLE_BRAVO,
|
||||
ROLE_CHARLIE,
|
||||
ROLE_MIKE,
|
||||
ALL_ROLES,
|
||||
create_user_info
|
||||
)
|
||||
)
|
||||
|
||||
DEFAULT_AUTH_GROUP = 'Member'
|
||||
MODULE_PATH = 'allianceauth.services.modules.discord'
|
||||
|
||||
@@ -53,21 +53,21 @@ def run_many_updates(runs):
|
||||
logger.info('Starting piloting_tasks for %d runs', runs)
|
||||
users = list()
|
||||
all_groups = Group.objects.all()
|
||||
for i in range(runs):
|
||||
for i in range(runs):
|
||||
if not users:
|
||||
users = list(User.objects.filter(discord__isnull=False))
|
||||
user = users.pop()
|
||||
logger.info('%d/%d: Starting run with user %s', i + 1, runs, user)
|
||||
# force change of nick
|
||||
# force change of nick
|
||||
new_nick = f'Testnick {uuid1().hex}'[:32]
|
||||
logger.info(
|
||||
'%d/%d: Changing nickname of %s to "%s"', i + 1, runs, user, new_nick
|
||||
)
|
||||
user.profile.main_character.character_name = new_nick
|
||||
user.profile.main_character.save()
|
||||
|
||||
user.profile.main_character.save()
|
||||
|
||||
# force change of groups
|
||||
user_groups = user.groups.all()
|
||||
user_groups = user.groups.all()
|
||||
user.groups.remove(random.choice(user_groups))
|
||||
while True:
|
||||
new_group = random.choice(all_groups)
|
||||
|
||||
@@ -9,9 +9,9 @@ from allianceauth.eveonline.models import (
|
||||
)
|
||||
|
||||
from ....admin import (
|
||||
user_profile_pic,
|
||||
user_username,
|
||||
user_main_organization,
|
||||
user_profile_pic,
|
||||
user_username,
|
||||
user_main_organization,
|
||||
ServicesUserAdmin,
|
||||
MainCorporationsFilter,
|
||||
MainAllianceFilter
|
||||
@@ -31,7 +31,7 @@ class TestDataMixin(TestCase):
|
||||
EveAllianceInfo.objects.all().delete()
|
||||
User.objects.all().delete()
|
||||
DiscordUser.objects.all().delete()
|
||||
|
||||
|
||||
# user 1 - corp and alliance, normal user
|
||||
cls.character_1 = EveCharacter.objects.create(
|
||||
character_id=1001,
|
||||
@@ -56,16 +56,16 @@ class TestDataMixin(TestCase):
|
||||
alliance = EveAllianceInfo.objects.create(
|
||||
alliance_id=3001,
|
||||
alliance_name='Wayne Enterprises',
|
||||
alliance_ticker='WE',
|
||||
alliance_ticker='WE',
|
||||
executor_corp_id=2001
|
||||
)
|
||||
EveCorporationInfo.objects.create(
|
||||
corporation_id=2001,
|
||||
corporation_name='Wayne Technologies',
|
||||
corporation_ticker='WT',
|
||||
corporation_ticker='WT',
|
||||
member_count=42,
|
||||
alliance=alliance
|
||||
)
|
||||
)
|
||||
cls.user_1 = User.objects.create_user(
|
||||
cls.character_1.character_name.replace(' ', '_'),
|
||||
'abc@example.com',
|
||||
@@ -103,7 +103,7 @@ class TestDataMixin(TestCase):
|
||||
EveCorporationInfo.objects.create(
|
||||
corporation_id=2002,
|
||||
corporation_name='Daily Plane',
|
||||
corporation_ticker='DP',
|
||||
corporation_ticker='DP',
|
||||
member_count=99,
|
||||
alliance=None
|
||||
)
|
||||
@@ -123,7 +123,7 @@ class TestDataMixin(TestCase):
|
||||
user=cls.user_2,
|
||||
uid=1002
|
||||
)
|
||||
|
||||
|
||||
# user 3 - no main, no group, superuser
|
||||
cls.character_3 = EveCharacter.objects.create(
|
||||
character_id=1101,
|
||||
@@ -136,7 +136,7 @@ class TestDataMixin(TestCase):
|
||||
EveCorporationInfo.objects.create(
|
||||
corporation_id=2101,
|
||||
corporation_name='Lex Corp',
|
||||
corporation_ticker='LC',
|
||||
corporation_ticker='LC',
|
||||
member_count=666,
|
||||
alliance=None
|
||||
)
|
||||
@@ -160,13 +160,13 @@ class TestDataMixin(TestCase):
|
||||
user=cls.user_3,
|
||||
uid=1003
|
||||
)
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.factory = RequestFactory()
|
||||
self.modeladmin = DiscordUserAdmin(
|
||||
model=DiscordUser, admin_site=AdminSite()
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
|
||||
class TestColumnRendering(TestDataMixin, TestCase):
|
||||
|
||||
@@ -230,12 +230,12 @@ class TestColumnRendering(TestDataMixin, TestCase):
|
||||
|
||||
|
||||
class TestFilters(TestDataMixin, TestCase):
|
||||
|
||||
|
||||
def test_filter_main_corporations(self):
|
||||
|
||||
class DiscordUserAdminTest(ServicesUserAdmin):
|
||||
|
||||
class DiscordUserAdminTest(ServicesUserAdmin):
|
||||
list_filter = (MainCorporationsFilter,)
|
||||
|
||||
|
||||
my_modeladmin = DiscordUserAdminTest(DiscordUser, AdminSite())
|
||||
|
||||
# Make sure the lookups are correct
|
||||
@@ -244,7 +244,7 @@ class TestFilters(TestDataMixin, TestCase):
|
||||
changelist = my_modeladmin.get_changelist_instance(request)
|
||||
filters = changelist.get_filters(request)
|
||||
filterspec = filters[0][0]
|
||||
expected = [
|
||||
expected = [
|
||||
(2002, 'Daily Planet'),
|
||||
(2001, 'Wayne Technologies'),
|
||||
]
|
||||
@@ -254,19 +254,19 @@ class TestFilters(TestDataMixin, TestCase):
|
||||
request = self.factory.get(
|
||||
'/', {'main_corporation_id__exact': self.character_1.corporation_id}
|
||||
)
|
||||
request.user = self.user_1
|
||||
request.user = self.user_1
|
||||
changelist = my_modeladmin.get_changelist_instance(request)
|
||||
queryset = changelist.get_queryset(request)
|
||||
expected = [self.user_1.discord]
|
||||
self.assertSetEqual(set(queryset), set(expected))
|
||||
|
||||
|
||||
def test_filter_main_alliances(self):
|
||||
|
||||
class DiscordUserAdminTest(ServicesUserAdmin):
|
||||
|
||||
class DiscordUserAdminTest(ServicesUserAdmin):
|
||||
list_filter = (MainAllianceFilter,)
|
||||
|
||||
|
||||
my_modeladmin = DiscordUserAdminTest(DiscordUser, AdminSite())
|
||||
|
||||
|
||||
# Make sure the lookups are correct
|
||||
request = self.factory.get('/')
|
||||
request.user = self.user_1
|
||||
@@ -282,7 +282,7 @@ class TestFilters(TestDataMixin, TestCase):
|
||||
request = self.factory.get(
|
||||
'/', {'main_alliance_id__exact': self.character_1.alliance_id}
|
||||
)
|
||||
request.user = self.user_1
|
||||
request.user = self.user_1
|
||||
changelist = my_modeladmin.get_changelist_instance(request)
|
||||
queryset = changelist.get_queryset(request)
|
||||
expected = [self.user_1.discord]
|
||||
|
||||
@@ -19,11 +19,11 @@ logger = set_logger_to_file(MODULE_PATH + '.auth_hooks', __file__)
|
||||
@override_settings(CELERY_ALWAYS_EAGER=True)
|
||||
class TestDiscordService(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
def setUp(self):
|
||||
self.member = AuthUtils.create_member(TEST_USER_NAME)
|
||||
DiscordUser.objects.create(
|
||||
user=self.member,
|
||||
uid=TEST_USER_ID,
|
||||
user=self.member,
|
||||
uid=TEST_USER_ID,
|
||||
username=TEST_USER_NAME,
|
||||
discriminator='1234'
|
||||
)
|
||||
@@ -34,33 +34,33 @@ class TestDiscordService(TestCase):
|
||||
Notification.objects.all().delete()
|
||||
|
||||
def test_service_enabled(self):
|
||||
service = self.service()
|
||||
service = self.service()
|
||||
self.assertTrue(service.service_active_for_user(self.member))
|
||||
self.assertFalse(service.service_active_for_user(self.none_member))
|
||||
|
||||
@patch(MODULE_PATH + '.tasks.update_all_groups')
|
||||
def test_update_all_groups(self, mock_update_all_groups):
|
||||
service = self.service()
|
||||
service.update_all_groups()
|
||||
service.update_all_groups()
|
||||
self.assertTrue(mock_update_all_groups.delay.called)
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.tasks.update_groups_bulk')
|
||||
def test_update_groups_bulk(self, mock_update_groups_bulk):
|
||||
service = self.service()
|
||||
service = self.service()
|
||||
service.update_groups_bulk([self.member])
|
||||
self.assertTrue(mock_update_groups_bulk.delay.called)
|
||||
self.assertTrue(mock_update_groups_bulk.delay.called)
|
||||
|
||||
@patch(MODULE_PATH + '.tasks.update_groups')
|
||||
def test_update_groups_for_member(self, mock_update_groups):
|
||||
service = self.service()
|
||||
def test_update_groups_for_member(self, mock_update_groups):
|
||||
service = self.service()
|
||||
service.update_groups(self.member)
|
||||
self.assertTrue(mock_update_groups.apply_async.called)
|
||||
self.assertTrue(mock_update_groups.apply_async.called)
|
||||
|
||||
@patch(MODULE_PATH + '.tasks.update_groups')
|
||||
def test_update_groups_for_none_member(self, mock_update_groups):
|
||||
def test_update_groups_for_none_member(self, mock_update_groups):
|
||||
service = self.service()
|
||||
service.update_groups(self.none_member)
|
||||
self.assertFalse(mock_update_groups.apply_async.called)
|
||||
self.assertFalse(mock_update_groups.apply_async.called)
|
||||
|
||||
@patch(MODULE_PATH + '.models.notify')
|
||||
@patch(MODULE_PATH + '.tasks.DiscordUser')
|
||||
@@ -69,52 +69,52 @@ class TestDiscordService(TestCase):
|
||||
self, mock_DiscordClient, mock_DiscordUser, mock_notify
|
||||
):
|
||||
mock_DiscordClient.return_value.remove_guild_member.return_value = True
|
||||
|
||||
|
||||
# Test member is not deleted
|
||||
service = self.service()
|
||||
service.validate_user(self.member)
|
||||
self.assertTrue(DiscordUser.objects.filter(user=self.member).exists())
|
||||
|
||||
# Test none member is deleted
|
||||
# Test none member is deleted
|
||||
DiscordUser.objects.create(user=self.none_member, uid=TEST_USER_ID)
|
||||
service.validate_user(self.none_member)
|
||||
service.validate_user(self.none_member)
|
||||
self.assertFalse(DiscordUser.objects.filter(user=self.none_member).exists())
|
||||
|
||||
@patch(MODULE_PATH + '.tasks.update_nickname')
|
||||
def test_sync_nickname(self, mock_update_nickname):
|
||||
service = self.service()
|
||||
service = self.service()
|
||||
service.sync_nickname(self.member)
|
||||
self.assertTrue(mock_update_nickname.apply_async.called)
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.tasks.update_nicknames_bulk')
|
||||
def test_sync_nicknames_bulk(self, mock_update_nicknames_bulk):
|
||||
service = self.service()
|
||||
service.sync_nicknames_bulk([self.member])
|
||||
service = self.service()
|
||||
service.sync_nicknames_bulk([self.member])
|
||||
self.assertTrue(mock_update_nicknames_bulk.delay.called)
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.managers.DiscordClient', spec=DiscordClient)
|
||||
def test_delete_user_is_member(self, mock_DiscordClient):
|
||||
def test_delete_user_is_member(self, mock_DiscordClient):
|
||||
mock_DiscordClient.return_value.remove_guild_member.return_value = True
|
||||
|
||||
service = self.service()
|
||||
service.delete_user(self.member, notify_user=True)
|
||||
|
||||
|
||||
self.assertTrue(mock_DiscordClient.return_value.remove_guild_member.called)
|
||||
self.assertFalse(DiscordUser.objects.filter(user=self.member).exists())
|
||||
self.assertFalse(DiscordUser.objects.filter(user=self.member).exists())
|
||||
self.assertTrue(Notification.objects.filter(user=self.member).exists())
|
||||
|
||||
@patch(MODULE_PATH + '.managers.DiscordClient', spec=DiscordClient)
|
||||
def test_delete_user_is_not_member(self, mock_DiscordClient):
|
||||
mock_DiscordClient.return_value.remove_guild_member.return_value = True
|
||||
|
||||
service = self.service()
|
||||
service = self.service()
|
||||
service.delete_user(self.none_member)
|
||||
|
||||
self.assertFalse(mock_DiscordClient.return_value.remove_guild_member.called)
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.managers.DiscordClient', spec=DiscordClient)
|
||||
def test_render_services_ctrl_with_username(self, mock_DiscordClient):
|
||||
service = self.service()
|
||||
service = self.service()
|
||||
request = self.factory.get('/services/')
|
||||
request.user = self.member
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@ from allianceauth.tests.auth_utils import AuthUtils
|
||||
|
||||
from . import (
|
||||
TEST_GUILD_ID,
|
||||
TEST_USER_NAME,
|
||||
TEST_USER_NAME,
|
||||
TEST_USER_ID,
|
||||
TEST_USER_DISCRIMINATOR,
|
||||
TEST_MAIN_NAME,
|
||||
TEST_MAIN_ID,
|
||||
TEST_USER_DISCRIMINATOR,
|
||||
TEST_MAIN_NAME,
|
||||
TEST_MAIN_ID,
|
||||
MODULE_PATH,
|
||||
add_permissions_to_members,
|
||||
ROLE_ALPHA,
|
||||
@@ -75,11 +75,11 @@ guild_member_request = DiscordRequest(
|
||||
add_guild_member_request = DiscordRequest(
|
||||
method='PUT',
|
||||
url=f'{DISCORD_API_BASE_URL}guilds/{TEST_GUILD_ID}/members/{TEST_USER_ID}'
|
||||
)
|
||||
)
|
||||
modify_guild_member_request = DiscordRequest(
|
||||
method='PATCH',
|
||||
url=f'{DISCORD_API_BASE_URL}guilds/{TEST_GUILD_ID}/members/{TEST_USER_ID}'
|
||||
)
|
||||
)
|
||||
remove_guild_member_request = DiscordRequest(
|
||||
method='DELETE',
|
||||
url=f'{DISCORD_API_BASE_URL}guilds/{TEST_GUILD_ID}/members/{TEST_USER_ID}'
|
||||
@@ -93,7 +93,7 @@ def clear_cache():
|
||||
logger.info('Cache flushed')
|
||||
|
||||
|
||||
def reset_testdata():
|
||||
def reset_testdata():
|
||||
AuthUtils.disconnect_signals()
|
||||
Group.objects.all().delete()
|
||||
User.objects.all().delete()
|
||||
@@ -112,15 +112,15 @@ class TestServiceFeatures(TransactionTestCase):
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.maxDiff = None
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""All tests: Given a user with member state,
|
||||
"""All tests: Given a user with member state,
|
||||
service permission and active Discord account
|
||||
"""
|
||||
clear_cache()
|
||||
reset_testdata()
|
||||
self.group_charlie = Group.objects.create(name='charlie')
|
||||
|
||||
self.group_charlie = Group.objects.create(name='charlie')
|
||||
|
||||
# States
|
||||
self.member_state = AuthUtils.get_member_state()
|
||||
self.guest_state = AuthUtils.get_guest_state()
|
||||
@@ -132,64 +132,64 @@ class TestServiceFeatures(TransactionTestCase):
|
||||
# Test user
|
||||
self.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
self.main = AuthUtils.add_main_character_2(
|
||||
self.user,
|
||||
TEST_MAIN_NAME,
|
||||
TEST_MAIN_ID,
|
||||
corp_id='2',
|
||||
corp_name='test_corp',
|
||||
self.user,
|
||||
TEST_MAIN_NAME,
|
||||
TEST_MAIN_ID,
|
||||
corp_id='2',
|
||||
corp_name='test_corp',
|
||||
corp_ticker='TEST',
|
||||
disconnect_signals=True
|
||||
)
|
||||
)
|
||||
self.member_state.member_characters.add(self.main)
|
||||
|
||||
|
||||
# verify user is a member and has an account
|
||||
self.user = User.objects.get(pk=self.user.pk)
|
||||
self.assertEqual(self.user.profile.state, self.member_state)
|
||||
|
||||
|
||||
self.discord_user = DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
|
||||
self.assertTrue(DiscordUser.objects.user_has_account(self.user))
|
||||
|
||||
|
||||
def test_when_name_of_main_changes_then_discord_nick_is_updated(
|
||||
self, requests_mocker
|
||||
):
|
||||
):
|
||||
requests_mocker.patch(modify_guild_member_request.url, status_code=204)
|
||||
|
||||
|
||||
# changing nick to trigger signals
|
||||
new_nick = f'Testnick {uuid1().hex}'[:32]
|
||||
self.user.profile.main_character.character_name = new_nick
|
||||
self.user.profile.main_character.save()
|
||||
|
||||
|
||||
# verify Discord nick was updates
|
||||
nick_updated = False
|
||||
for r in requests_mocker.request_history:
|
||||
my_request = DiscordRequest(r.method, r.url)
|
||||
for r in requests_mocker.request_history:
|
||||
my_request = DiscordRequest(r.method, r.url)
|
||||
if my_request == modify_guild_member_request and "nick" in r.json():
|
||||
nick_updated = True
|
||||
self.assertEqual(r.json()["nick"], new_nick)
|
||||
|
||||
|
||||
self.assertTrue(nick_updated)
|
||||
self.assertTrue(DiscordUser.objects.user_has_account(self.user))
|
||||
|
||||
def test_when_name_of_main_changes_and_user_deleted_then_account_is_deleted(
|
||||
self, requests_mocker
|
||||
):
|
||||
):
|
||||
requests_mocker.patch(
|
||||
modify_guild_member_request.url, status_code=404, json={'code': 10007}
|
||||
)
|
||||
)
|
||||
requests_mocker.delete(remove_guild_member_request.url, status_code=204)
|
||||
|
||||
|
||||
# changing nick to trigger signals
|
||||
new_nick = f'Testnick {uuid1().hex}'[:32]
|
||||
self.user.profile.main_character.character_name = new_nick
|
||||
self.user.profile.main_character.save()
|
||||
|
||||
|
||||
self.assertFalse(DiscordUser.objects.user_has_account(self.user))
|
||||
|
||||
def test_when_name_of_main_changes_and_and_rate_limited_then_dont_call_api(
|
||||
self, requests_mocker
|
||||
):
|
||||
):
|
||||
requests_mocker.patch(modify_guild_member_request.url, status_code=204)
|
||||
|
||||
|
||||
# exhausting rate limit
|
||||
client = DiscordUser.objects._bot_client()
|
||||
client._redis.set(
|
||||
@@ -197,7 +197,7 @@ class TestServiceFeatures(TransactionTestCase):
|
||||
value=0,
|
||||
px=2000
|
||||
)
|
||||
|
||||
|
||||
# changing nick to trigger signals
|
||||
new_nick = f'Testnick {uuid1().hex}'[:32]
|
||||
self.user.profile.main_character.character_name = new_nick
|
||||
@@ -207,55 +207,55 @@ class TestServiceFeatures(TransactionTestCase):
|
||||
requests_made = [
|
||||
DiscordRequest(r.method, r.url) for r in requests_mocker.request_history
|
||||
]
|
||||
|
||||
|
||||
self.assertListEqual(requests_made, list())
|
||||
|
||||
|
||||
def test_when_member_is_demoted_to_guest_then_his_account_is_deleted(
|
||||
self, requests_mocker
|
||||
):
|
||||
):
|
||||
requests_mocker.patch(modify_guild_member_request.url, status_code=204)
|
||||
requests_mocker.delete(remove_guild_member_request.url, status_code=204)
|
||||
|
||||
# our user is a member and has an account
|
||||
|
||||
# our user is a member and has an account
|
||||
self.assertTrue(self.user.has_perm('discord.access_discord'))
|
||||
|
||||
# now we demote him to guest
|
||||
|
||||
# now we demote him to guest
|
||||
self.member_state.member_characters.remove(self.main)
|
||||
|
||||
|
||||
# verify user is now guest
|
||||
self.user = User.objects.get(pk=self.user.pk)
|
||||
self.user = User.objects.get(pk=self.user.pk)
|
||||
self.assertEqual(self.user.profile.state, AuthUtils.get_guest_state())
|
||||
|
||||
|
||||
# verify user has no longer access to Discord and no account
|
||||
self.assertFalse(self.user.has_perm('discord.access_discord'))
|
||||
self.assertFalse(DiscordUser.objects.user_has_account(self.user))
|
||||
|
||||
self.assertFalse(DiscordUser.objects.user_has_account(self.user))
|
||||
|
||||
# verify account was actually deleted from Discord server
|
||||
requests_made = [
|
||||
DiscordRequest(r.method, r.url) for r in requests_mocker.request_history
|
||||
]
|
||||
]
|
||||
self.assertIn(remove_guild_member_request, requests_made)
|
||||
|
||||
|
||||
# verify user has been notified
|
||||
self.assertTrue(Notification.objects.filter(user=self.user).exists())
|
||||
|
||||
|
||||
def test_when_member_changes_to_blue_state_then_roles_are_updated_accordingly(
|
||||
self, requests_mocker
|
||||
):
|
||||
):
|
||||
# request mocks
|
||||
requests_mocker.get(
|
||||
guild_member_request.url,
|
||||
json={'user': create_user_info(), 'roles': ['3', '13', '99']}
|
||||
)
|
||||
)
|
||||
requests_mocker.get(
|
||||
guild_roles_request.url,
|
||||
json=[
|
||||
ROLE_ALPHA, ROLE_BRAVO, ROLE_CHARLIE, ROLE_MIKE, ROLE_MEMBER, ROLE_BLUE
|
||||
]
|
||||
)
|
||||
requests_mocker.post(create_guild_role_request.url, json=ROLE_CHARLIE)
|
||||
)
|
||||
requests_mocker.post(create_guild_role_request.url, json=ROLE_CHARLIE)
|
||||
requests_mocker.patch(modify_guild_member_request.url, status_code=204)
|
||||
|
||||
|
||||
AuthUtils.disconnect_signals()
|
||||
self.user.groups.add(self.group_charlie)
|
||||
AuthUtils.connect_signals()
|
||||
@@ -264,101 +264,101 @@ class TestServiceFeatures(TransactionTestCase):
|
||||
self.blue_state.member_characters.add(self.main)
|
||||
self.member_state.member_characters.remove(self.main)
|
||||
|
||||
# verify roles for user where updated
|
||||
# verify roles for user where updated
|
||||
roles_updated = False
|
||||
for r in requests_mocker.request_history:
|
||||
my_request = DiscordRequest(r.method, r.url)
|
||||
for r in requests_mocker.request_history:
|
||||
my_request = DiscordRequest(r.method, r.url)
|
||||
if my_request == modify_guild_member_request and "roles" in r.json():
|
||||
roles_updated = True
|
||||
self.assertSetEqual(set(r.json()["roles"]), {3, 13, 98})
|
||||
break
|
||||
|
||||
|
||||
self.assertTrue(roles_updated)
|
||||
self.assertTrue(DiscordUser.objects.user_has_account(self.user))
|
||||
|
||||
def test_when_group_added_to_member_and_role_known_then_his_roles_are_updated(
|
||||
self, requests_mocker
|
||||
):
|
||||
):
|
||||
requests_mocker.get(
|
||||
guild_member_request.url,
|
||||
json={
|
||||
'user': create_user_info(),
|
||||
'roles': ['13', '99']
|
||||
}
|
||||
)
|
||||
)
|
||||
requests_mocker.get(
|
||||
guild_roles_request.url,
|
||||
guild_roles_request.url,
|
||||
json=[ROLE_ALPHA, ROLE_BRAVO, ROLE_CHARLIE, ROLE_MIKE, ROLE_MEMBER]
|
||||
)
|
||||
requests_mocker.post(create_guild_role_request.url, json=ROLE_CHARLIE)
|
||||
)
|
||||
requests_mocker.post(create_guild_role_request.url, json=ROLE_CHARLIE)
|
||||
requests_mocker.patch(modify_guild_member_request.url, status_code=204)
|
||||
|
||||
|
||||
# adding new group to trigger signals
|
||||
self.user.groups.add(self.group_charlie)
|
||||
|
||||
|
||||
# verify roles for user where updated
|
||||
roles_updated = False
|
||||
for r in requests_mocker.request_history:
|
||||
my_request = DiscordRequest(r.method, r.url)
|
||||
for r in requests_mocker.request_history:
|
||||
my_request = DiscordRequest(r.method, r.url)
|
||||
if my_request == modify_guild_member_request and "roles" in r.json():
|
||||
roles_updated = True
|
||||
self.assertSetEqual(set(r.json()["roles"]), {3, 13, 99})
|
||||
break
|
||||
|
||||
|
||||
self.assertTrue(roles_updated)
|
||||
self.assertTrue(DiscordUser.objects.user_has_account(self.user))
|
||||
|
||||
def test_when_group_added_to_member_and_role_unknown_then_his_roles_are_updated(
|
||||
self, requests_mocker
|
||||
):
|
||||
):
|
||||
requests_mocker.get(
|
||||
guild_member_request.url,
|
||||
json={
|
||||
'user': {'id': str(TEST_USER_ID), 'username': TEST_MAIN_NAME},
|
||||
'roles': ['13', '99']
|
||||
}
|
||||
)
|
||||
)
|
||||
requests_mocker.get(
|
||||
guild_roles_request.url,
|
||||
guild_roles_request.url,
|
||||
json=[ROLE_ALPHA, ROLE_BRAVO, ROLE_MIKE, ROLE_MEMBER]
|
||||
)
|
||||
requests_mocker.post(create_guild_role_request.url, json=ROLE_CHARLIE)
|
||||
)
|
||||
requests_mocker.post(create_guild_role_request.url, json=ROLE_CHARLIE)
|
||||
requests_mocker.patch(modify_guild_member_request.url, status_code=204)
|
||||
|
||||
|
||||
# adding new group to trigger signals
|
||||
self.user.groups.add(self.group_charlie)
|
||||
self.user.refresh_from_db()
|
||||
|
||||
|
||||
# verify roles for user where updated
|
||||
roles_updated = False
|
||||
for r in requests_mocker.request_history:
|
||||
my_request = DiscordRequest(r.method, r.url)
|
||||
for r in requests_mocker.request_history:
|
||||
my_request = DiscordRequest(r.method, r.url)
|
||||
if my_request == modify_guild_member_request and "roles" in r.json():
|
||||
roles_updated = True
|
||||
self.assertSetEqual(set(r.json()["roles"]), {3, 13, 99})
|
||||
break
|
||||
|
||||
|
||||
self.assertTrue(roles_updated)
|
||||
self.assertTrue(DiscordUser.objects.user_has_account(self.user))
|
||||
|
||||
|
||||
|
||||
@override_settings(CELERY_ALWAYS_EAGER=True)
|
||||
@patch(MODULE_PATH + '.managers.DISCORD_GUILD_ID', TEST_GUILD_ID)
|
||||
@patch(MODULE_PATH + '.models.DISCORD_GUILD_ID', TEST_GUILD_ID)
|
||||
@requests_mock.Mocker()
|
||||
class StateTestCase(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
def setUp(self):
|
||||
clear_cache()
|
||||
reset_testdata()
|
||||
|
||||
|
||||
self.user = AuthUtils.create_user('test_user', disconnect_signals=True)
|
||||
AuthUtils.add_main_character(
|
||||
self.user,
|
||||
'Perm Test Character', '99',
|
||||
corp_id='100',
|
||||
self.user,
|
||||
'Perm Test Character', '99',
|
||||
corp_id='100',
|
||||
alliance_id='200',
|
||||
corp_name='Perm Test Corp',
|
||||
corp_name='Perm Test Corp',
|
||||
alliance_name='Perm Test Alliance'
|
||||
)
|
||||
self.test_character = EveCharacter.objects.get(character_id='99')
|
||||
@@ -369,7 +369,7 @@ class StateTestCase(TestCase):
|
||||
self.access_discord = AuthUtils.get_permission_by_name('discord.access_discord')
|
||||
self.member_state.permissions.add(self.access_discord)
|
||||
self.member_state.member_characters.add(self.test_character)
|
||||
|
||||
|
||||
def _add_discord_user(self):
|
||||
self.discord_user = DiscordUser.objects.create(
|
||||
user=self.user, uid="12345678910"
|
||||
@@ -434,57 +434,57 @@ class StateTestCase(TestCase):
|
||||
@patch(MODULE_PATH + '.models.DISCORD_GUILD_ID', TEST_GUILD_ID)
|
||||
@requests_mock.Mocker()
|
||||
class TestUserFeatures(WebTest):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
clear_cache()
|
||||
reset_testdata()
|
||||
self.member = AuthUtils.create_member(TEST_USER_NAME)
|
||||
AuthUtils.add_main_character_2(
|
||||
self.member,
|
||||
TEST_MAIN_NAME,
|
||||
self.member,
|
||||
TEST_MAIN_NAME,
|
||||
TEST_MAIN_ID,
|
||||
disconnect_signals=True
|
||||
)
|
||||
add_permissions_to_members()
|
||||
|
||||
@patch(MODULE_PATH + '.views.messages')
|
||||
@patch(MODULE_PATH + '.views.messages')
|
||||
@patch(MODULE_PATH + '.managers.OAuth2Session')
|
||||
def test_user_activation_normal(
|
||||
self, requests_mocker, mock_OAuth2Session, mock_messages
|
||||
):
|
||||
):
|
||||
# setup
|
||||
requests_mocker.get(
|
||||
guild_infos_request.url, json={'id': TEST_GUILD_ID, 'name': 'Test Guild'}
|
||||
)
|
||||
)
|
||||
requests_mocker.get(
|
||||
user_get_current_request.url,
|
||||
user_get_current_request.url,
|
||||
json=create_user_info(
|
||||
TEST_USER_ID, TEST_USER_NAME, TEST_USER_DISCRIMINATOR
|
||||
)
|
||||
)
|
||||
)
|
||||
requests_mocker.get(
|
||||
guild_roles_request.url,
|
||||
guild_roles_request.url,
|
||||
json=[ROLE_ALPHA, ROLE_BRAVO, ROLE_MIKE, ROLE_MEMBER]
|
||||
)
|
||||
)
|
||||
requests_mocker.put(add_guild_member_request.url, status_code=201)
|
||||
|
||||
authentication_code = 'auth_code'
|
||||
|
||||
authentication_code = 'auth_code'
|
||||
oauth_url = 'https://www.example.com/oauth'
|
||||
state = ''
|
||||
mock_OAuth2Session.return_value.authorization_url.return_value = \
|
||||
oauth_url, state
|
||||
|
||||
|
||||
# login
|
||||
self.app.set_user(self.member)
|
||||
|
||||
|
||||
# user opens services page
|
||||
services_page = self.app.get(reverse('services:services'))
|
||||
self.assertEqual(services_page.status_code, 200)
|
||||
|
||||
# user clicks Discord service activation link on page
|
||||
# user clicks Discord service activation link on page
|
||||
response = services_page.click(href=reverse('discord:activate'))
|
||||
|
||||
# check we got a redirect to Discord OAuth
|
||||
|
||||
# check we got a redirect to Discord OAuth
|
||||
self.assertRedirects(
|
||||
response, expected_url=oauth_url, fetch_redirect_response=False
|
||||
)
|
||||
@@ -493,66 +493,66 @@ class TestUserFeatures(WebTest):
|
||||
response = self.app.get(
|
||||
reverse('discord:callback'), params={'code': authentication_code}
|
||||
)
|
||||
|
||||
|
||||
# user got a success message
|
||||
self.assertTrue(mock_messages.success.called)
|
||||
self.assertFalse(mock_messages.error.called)
|
||||
|
||||
|
||||
requests_made = list()
|
||||
for r in requests_mocker.request_history:
|
||||
obj = DiscordRequest(r.method, r.url)
|
||||
for r in requests_mocker.request_history:
|
||||
obj = DiscordRequest(r.method, r.url)
|
||||
requests_made.append(obj)
|
||||
|
||||
|
||||
expected = [
|
||||
guild_infos_request,
|
||||
user_get_current_request,
|
||||
guild_roles_request,
|
||||
guild_infos_request,
|
||||
user_get_current_request,
|
||||
guild_roles_request,
|
||||
add_guild_member_request
|
||||
]
|
||||
self.assertListEqual(requests_made, expected)
|
||||
|
||||
@patch(MODULE_PATH + '.views.messages')
|
||||
@patch(MODULE_PATH + '.views.messages')
|
||||
@patch(MODULE_PATH + '.managers.OAuth2Session')
|
||||
def test_user_activation_failed(
|
||||
self, requests_mocker, mock_OAuth2Session, mock_messages
|
||||
):
|
||||
):
|
||||
# setup
|
||||
requests_mocker.get(
|
||||
guild_infos_request.url, json={'id': TEST_GUILD_ID, 'name': 'Test Guild'}
|
||||
)
|
||||
requests_mocker.get(
|
||||
user_get_current_request.url,
|
||||
user_get_current_request.url,
|
||||
json=create_user_info(
|
||||
TEST_USER_ID, TEST_USER_NAME, TEST_USER_DISCRIMINATOR
|
||||
)
|
||||
)
|
||||
)
|
||||
requests_mocker.get(
|
||||
guild_roles_request.url,
|
||||
guild_roles_request.url,
|
||||
json=[ROLE_ALPHA, ROLE_BRAVO, ROLE_MIKE, ROLE_MEMBER]
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
mock_exception = HTTPError('error')
|
||||
mock_exception.response = Mock()
|
||||
mock_exception.response.status_code = 503
|
||||
requests_mocker.put(add_guild_member_request.url, exc=mock_exception)
|
||||
|
||||
authentication_code = 'auth_code'
|
||||
|
||||
authentication_code = 'auth_code'
|
||||
oauth_url = 'https://www.example.com/oauth'
|
||||
state = ''
|
||||
mock_OAuth2Session.return_value.authorization_url.return_value = \
|
||||
oauth_url, state
|
||||
|
||||
|
||||
# login
|
||||
self.app.set_user(self.member)
|
||||
|
||||
# user opens services page
|
||||
services_page = self.app.get(reverse('services:services'))
|
||||
self.assertEqual(services_page.status_code, 200)
|
||||
|
||||
|
||||
# click activate on the service page
|
||||
response = services_page.click(href=reverse('discord:activate'))
|
||||
|
||||
# check we got a redirect to Discord OAuth
|
||||
|
||||
# check we got a redirect to Discord OAuth
|
||||
self.assertRedirects(
|
||||
response, expected_url=oauth_url, fetch_redirect_response=False
|
||||
)
|
||||
@@ -561,124 +561,124 @@ class TestUserFeatures(WebTest):
|
||||
response = self.app.get(
|
||||
reverse('discord:callback'), params={'code': authentication_code}
|
||||
)
|
||||
|
||||
|
||||
# user got a success message
|
||||
self.assertFalse(mock_messages.success.called)
|
||||
self.assertTrue(mock_messages.error.called)
|
||||
|
||||
|
||||
requests_made = list()
|
||||
for r in requests_mocker.request_history:
|
||||
obj = DiscordRequest(r.method, r.url)
|
||||
for r in requests_mocker.request_history:
|
||||
obj = DiscordRequest(r.method, r.url)
|
||||
requests_made.append(obj)
|
||||
|
||||
|
||||
expected = [
|
||||
guild_infos_request,
|
||||
user_get_current_request,
|
||||
guild_roles_request,
|
||||
user_get_current_request,
|
||||
guild_roles_request,
|
||||
add_guild_member_request
|
||||
]
|
||||
self.assertListEqual(requests_made, expected)
|
||||
|
||||
@patch(MODULE_PATH + '.views.messages')
|
||||
def test_user_deactivation_normal(self, requests_mocker, mock_messages):
|
||||
def test_user_deactivation_normal(self, requests_mocker, mock_messages):
|
||||
# setup
|
||||
requests_mocker.get(
|
||||
guild_infos_request.url, json={'id': TEST_GUILD_ID, 'name': 'Test Guild'}
|
||||
)
|
||||
)
|
||||
requests_mocker.delete(remove_guild_member_request.url, status_code=204)
|
||||
DiscordUser.objects.create(user=self.member, uid=TEST_USER_ID)
|
||||
|
||||
|
||||
# login
|
||||
self.app.set_user(self.member)
|
||||
|
||||
|
||||
# user opens services page
|
||||
services_page = self.app.get(reverse('services:services'))
|
||||
self.assertEqual(services_page.status_code, 200)
|
||||
|
||||
# click deactivate on the service page
|
||||
# click deactivate on the service page
|
||||
response = services_page.click(href=reverse('discord:deactivate'))
|
||||
|
||||
|
||||
# check we got a redirect to service page
|
||||
self.assertRedirects(response, expected_url=reverse('services:services'))
|
||||
|
||||
# user got a success message
|
||||
self.assertTrue(mock_messages.success.called)
|
||||
self.assertFalse(mock_messages.error.called)
|
||||
|
||||
|
||||
requests_made = list()
|
||||
for r in requests_mocker.request_history:
|
||||
obj = DiscordRequest(r.method, r.url)
|
||||
for r in requests_mocker.request_history:
|
||||
obj = DiscordRequest(r.method, r.url)
|
||||
requests_made.append(obj)
|
||||
|
||||
|
||||
expected = [guild_infos_request, remove_guild_member_request]
|
||||
self.assertListEqual(requests_made, expected)
|
||||
|
||||
@patch(MODULE_PATH + '.views.messages')
|
||||
def test_user_deactivation_fails(self, requests_mocker, mock_messages):
|
||||
def test_user_deactivation_fails(self, requests_mocker, mock_messages):
|
||||
# setup
|
||||
requests_mocker.get(
|
||||
guild_infos_request.url, json={'id': TEST_GUILD_ID, 'name': 'Test Guild'}
|
||||
)
|
||||
)
|
||||
mock_exception = HTTPError('error')
|
||||
mock_exception.response = Mock()
|
||||
mock_exception.response.status_code = 503
|
||||
requests_mocker.delete(remove_guild_member_request.url, exc=mock_exception)
|
||||
|
||||
|
||||
DiscordUser.objects.create(user=self.member, uid=TEST_USER_ID)
|
||||
|
||||
|
||||
# login
|
||||
self.app.set_user(self.member)
|
||||
|
||||
|
||||
# user opens services page
|
||||
services_page = self.app.get(reverse('services:services'))
|
||||
self.assertEqual(services_page.status_code, 200)
|
||||
|
||||
# click deactivate on the service page
|
||||
# click deactivate on the service page
|
||||
response = services_page.click(href=reverse('discord:deactivate'))
|
||||
|
||||
|
||||
# check we got a redirect to service page
|
||||
self.assertRedirects(response, expected_url=reverse('services:services'))
|
||||
|
||||
# user got a success message
|
||||
self.assertFalse(mock_messages.success.called)
|
||||
self.assertTrue(mock_messages.error.called)
|
||||
|
||||
|
||||
requests_made = list()
|
||||
for r in requests_mocker.request_history:
|
||||
obj = DiscordRequest(r.method, r.url)
|
||||
for r in requests_mocker.request_history:
|
||||
obj = DiscordRequest(r.method, r.url)
|
||||
requests_made.append(obj)
|
||||
|
||||
|
||||
expected = [guild_infos_request, remove_guild_member_request]
|
||||
self.assertListEqual(requests_made, expected)
|
||||
|
||||
@patch(MODULE_PATH + '.views.messages')
|
||||
def test_user_add_new_server(self, requests_mocker, mock_messages):
|
||||
# setup
|
||||
def test_user_add_new_server(self, requests_mocker, mock_messages):
|
||||
# setup
|
||||
mock_exception = HTTPError(Mock(**{"response.status_code": 400}))
|
||||
requests_mocker.get(guild_infos_request.url, exc=mock_exception)
|
||||
|
||||
# login
|
||||
|
||||
# login
|
||||
self.member.is_superuser = True
|
||||
self.member.is_staff = True
|
||||
self.member.save()
|
||||
self.app.set_user(self.member)
|
||||
|
||||
|
||||
# click deactivate on the service page
|
||||
response = self.app.get(reverse('services:services'))
|
||||
|
||||
|
||||
# check we got can see the page and the "link server" button
|
||||
self.assertEqual(response.status_int, 200)
|
||||
self.assertIsNotNone(response.html.find(id='btnLinkDiscordServer'))
|
||||
|
||||
|
||||
def test_when_server_name_fails_user_can_still_see_service_page(
|
||||
self, requests_mocker
|
||||
):
|
||||
):
|
||||
# setup
|
||||
requests_mocker.get(guild_infos_request.url, exc=DiscordApiBackoff(1000))
|
||||
|
||||
|
||||
# login
|
||||
self.app.set_user(self.member)
|
||||
|
||||
|
||||
# user opens services page
|
||||
services_page = self.app.get(reverse('services:services'))
|
||||
self.assertEqual(services_page.status_code, 200)
|
||||
@@ -686,7 +686,7 @@ class TestUserFeatures(WebTest):
|
||||
@override_settings(CELERY_ALWAYS_EAGER=True)
|
||||
def test_server_name_is_updated_by_task(
|
||||
self, requests_mocker
|
||||
):
|
||||
):
|
||||
# setup
|
||||
requests_mocker.get(
|
||||
guild_infos_request.url, json={'id': TEST_GUILD_ID, 'name': 'Test Guild'}
|
||||
@@ -696,11 +696,11 @@ class TestUserFeatures(WebTest):
|
||||
|
||||
# login
|
||||
self.app.set_user(self.member)
|
||||
|
||||
|
||||
# disable API call to make sure server name is not retrieved from API
|
||||
mock_exception = HTTPError(Mock(**{"response.status_code": 400}))
|
||||
requests_mocker.get(guild_infos_request.url, exc=mock_exception)
|
||||
|
||||
|
||||
# user opens services page
|
||||
services_page = self.app.get(reverse('services:services'))
|
||||
self.assertEqual(services_page.status_code, 200)
|
||||
|
||||
@@ -9,21 +9,21 @@ from django.test import TestCase
|
||||
from allianceauth.tests.auth_utils import AuthUtils
|
||||
|
||||
from . import (
|
||||
TEST_GUILD_ID,
|
||||
TEST_USER_NAME,
|
||||
TEST_USER_ID,
|
||||
TEST_MAIN_NAME,
|
||||
TEST_MAIN_ID,
|
||||
TEST_GUILD_ID,
|
||||
TEST_USER_NAME,
|
||||
TEST_USER_ID,
|
||||
TEST_MAIN_NAME,
|
||||
TEST_MAIN_ID,
|
||||
MODULE_PATH,
|
||||
ROLE_ALPHA,
|
||||
ROLE_BRAVO,
|
||||
ROLE_CHARLIE,
|
||||
ROLE_CHARLIE,
|
||||
)
|
||||
from ..discord_client.tests import create_matched_role
|
||||
from ..app_settings import (
|
||||
DISCORD_APP_ID,
|
||||
DISCORD_APP_SECRET,
|
||||
DISCORD_CALLBACK_URL,
|
||||
DISCORD_APP_ID,
|
||||
DISCORD_APP_SECRET,
|
||||
DISCORD_CALLBACK_URL,
|
||||
)
|
||||
from ..discord_client import DiscordClient, DiscordApiBackoff
|
||||
from ..models import DiscordUser
|
||||
@@ -39,32 +39,32 @@ logger = set_logger_to_file(MODULE_PATH + '.managers', __file__)
|
||||
@patch(MODULE_PATH + '.models.DiscordUser.objects.user_group_names')
|
||||
@patch(MODULE_PATH + '.models.DiscordUser.objects.user_formatted_nick')
|
||||
class TestAddUser(TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
self.user_info = {
|
||||
'id': TEST_USER_ID,
|
||||
'id': TEST_USER_ID,
|
||||
'name': TEST_USER_NAME,
|
||||
'username': TEST_USER_NAME,
|
||||
'discriminator': '1234',
|
||||
}
|
||||
self.access_token = 'accesstoken'
|
||||
|
||||
|
||||
def test_can_create_user_no_roles_no_nick(
|
||||
self,
|
||||
self,
|
||||
mock_user_formatted_nick,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_DiscordClient
|
||||
):
|
||||
mock_user_formatted_nick.return_value = None
|
||||
mock_user_group_names.return_value = []
|
||||
mock_user_group_names.return_value = []
|
||||
mock_exchange_auth_code_for_token.return_value = self.access_token
|
||||
mock_DiscordClient.return_value.current_user.return_value = self.user_info
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = []
|
||||
mock_DiscordClient.return_value.add_guild_member.return_value = True
|
||||
|
||||
|
||||
result = DiscordUser.objects.add_user(self.user, authorization_code='abcdef')
|
||||
self.assertTrue(result)
|
||||
self.assertTrue(
|
||||
@@ -79,25 +79,25 @@ class TestAddUser(TestCase):
|
||||
self.assertIsNone(kwargs['nick'])
|
||||
|
||||
def test_can_create_user_with_roles_no_nick(
|
||||
self,
|
||||
self,
|
||||
mock_user_formatted_nick,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_DiscordClient
|
||||
):
|
||||
roles = [
|
||||
create_matched_role(ROLE_ALPHA),
|
||||
create_matched_role(ROLE_BRAVO),
|
||||
create_matched_role(ROLE_ALPHA),
|
||||
create_matched_role(ROLE_BRAVO),
|
||||
create_matched_role(ROLE_CHARLIE)
|
||||
]
|
||||
mock_user_formatted_nick.return_value = None
|
||||
mock_user_group_names.return_value = ['a', 'b', 'c']
|
||||
mock_exchange_auth_code_for_token.return_value = self.access_token
|
||||
mock_user_group_names.return_value = ['a', 'b', 'c']
|
||||
mock_exchange_auth_code_for_token.return_value = self.access_token
|
||||
mock_DiscordClient.return_value.current_user.return_value = self.user_info
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = roles
|
||||
mock_DiscordClient.return_value.add_guild_member.return_value = True
|
||||
|
||||
|
||||
result = DiscordUser.objects.add_user(self.user, authorization_code='abcdef')
|
||||
self.assertTrue(result)
|
||||
self.assertTrue(
|
||||
@@ -113,20 +113,20 @@ class TestAddUser(TestCase):
|
||||
|
||||
@patch(MODULE_PATH + '.managers.DISCORD_SYNC_NAMES', True)
|
||||
def test_can_create_user_no_roles_with_nick(
|
||||
self,
|
||||
self,
|
||||
mock_user_formatted_nick,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_DiscordClient
|
||||
):
|
||||
):
|
||||
mock_user_formatted_nick.return_value = TEST_MAIN_NAME
|
||||
mock_user_group_names.return_value = []
|
||||
mock_user_group_names.return_value = []
|
||||
mock_exchange_auth_code_for_token.return_value = self.access_token
|
||||
mock_DiscordClient.return_value.current_user.return_value = self.user_info
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = []
|
||||
mock_DiscordClient.return_value.add_guild_member.return_value = True
|
||||
|
||||
|
||||
result = DiscordUser.objects.add_user(self.user, authorization_code='abcdef')
|
||||
self.assertTrue(result)
|
||||
self.assertTrue(
|
||||
@@ -142,20 +142,20 @@ class TestAddUser(TestCase):
|
||||
|
||||
@patch(MODULE_PATH + '.managers.DISCORD_SYNC_NAMES', False)
|
||||
def test_can_create_user_no_roles_and_without_nick_if_turned_off(
|
||||
self,
|
||||
self,
|
||||
mock_user_formatted_nick,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_DiscordClient
|
||||
):
|
||||
):
|
||||
mock_user_formatted_nick.return_value = TEST_MAIN_NAME
|
||||
mock_user_group_names.return_value = []
|
||||
mock_user_group_names.return_value = []
|
||||
mock_exchange_auth_code_for_token.return_value = self.access_token
|
||||
mock_DiscordClient.return_value.current_user.return_value = self.user_info
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = []
|
||||
mock_DiscordClient.return_value.add_guild_member.return_value = True
|
||||
|
||||
|
||||
result = DiscordUser.objects.add_user(self.user, authorization_code='abcdef')
|
||||
self.assertTrue(result)
|
||||
self.assertTrue(
|
||||
@@ -168,44 +168,44 @@ class TestAddUser(TestCase):
|
||||
self.assertEqual(kwargs['access_token'], self.access_token)
|
||||
self.assertIsNone(kwargs['role_ids'])
|
||||
self.assertIsNone(kwargs['nick'])
|
||||
|
||||
|
||||
def test_can_activate_existing_guild_member(
|
||||
self,
|
||||
self,
|
||||
mock_user_formatted_nick,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_DiscordClient
|
||||
):
|
||||
mock_user_formatted_nick.return_value = None
|
||||
mock_user_group_names.return_value = []
|
||||
mock_user_group_names.return_value = []
|
||||
mock_exchange_auth_code_for_token.return_value = self.access_token
|
||||
mock_DiscordClient.return_value.current_user.return_value = self.user_info
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = []
|
||||
mock_DiscordClient.return_value.add_guild_member.return_value = None
|
||||
|
||||
|
||||
result = DiscordUser.objects.add_user(self.user, authorization_code='abcdef')
|
||||
self.assertTrue(result)
|
||||
self.assertTrue(
|
||||
DiscordUser.objects.filter(user=self.user, uid=TEST_USER_ID).exists()
|
||||
)
|
||||
self.assertTrue(mock_DiscordClient.return_value.add_guild_member.called)
|
||||
|
||||
|
||||
def test_return_false_when_user_creation_fails(
|
||||
self,
|
||||
self,
|
||||
mock_user_formatted_nick,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_DiscordClient
|
||||
):
|
||||
):
|
||||
mock_user_formatted_nick.return_value = None
|
||||
mock_user_group_names.return_value = []
|
||||
mock_user_group_names.return_value = []
|
||||
mock_exchange_auth_code_for_token.return_value = self.access_token
|
||||
mock_DiscordClient.return_value.current_user.return_value = self.user_info
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = []
|
||||
mock_DiscordClient.return_value.add_guild_member.return_value = False
|
||||
|
||||
|
||||
result = DiscordUser.objects.add_user(self.user, authorization_code='abcdef')
|
||||
self.assertFalse(result)
|
||||
self.assertFalse(
|
||||
@@ -214,21 +214,21 @@ class TestAddUser(TestCase):
|
||||
self.assertTrue(mock_DiscordClient.return_value.add_guild_member.called)
|
||||
|
||||
def test_return_false_when_on_api_backoff(
|
||||
self,
|
||||
self,
|
||||
mock_user_formatted_nick,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_DiscordClient
|
||||
):
|
||||
):
|
||||
mock_user_formatted_nick.return_value = None
|
||||
mock_user_group_names.return_value = []
|
||||
mock_user_group_names.return_value = []
|
||||
mock_exchange_auth_code_for_token.return_value = self.access_token
|
||||
mock_DiscordClient.return_value.current_user.return_value = self.user_info
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = []
|
||||
mock_DiscordClient.return_value.add_guild_member.side_effect = \
|
||||
DiscordApiBackoff(999)
|
||||
|
||||
|
||||
result = DiscordUser.objects.add_user(self.user, authorization_code='abcdef')
|
||||
self.assertFalse(result)
|
||||
self.assertFalse(
|
||||
@@ -237,14 +237,14 @@ class TestAddUser(TestCase):
|
||||
self.assertTrue(mock_DiscordClient.return_value.add_guild_member.called)
|
||||
|
||||
def test_return_false_on_http_error(
|
||||
self,
|
||||
self,
|
||||
mock_user_formatted_nick,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_user_group_names,
|
||||
mock_exchange_auth_code_for_token,
|
||||
mock_DiscordClient
|
||||
):
|
||||
):
|
||||
mock_user_formatted_nick.return_value = None
|
||||
mock_user_group_names.return_value = []
|
||||
mock_user_group_names.return_value = []
|
||||
mock_exchange_auth_code_for_token.return_value = self.access_token
|
||||
mock_DiscordClient.return_value.current_user.return_value = self.user_info
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
@@ -253,18 +253,18 @@ class TestAddUser(TestCase):
|
||||
mock_exception.response = Mock()
|
||||
mock_exception.response.status_code = 500
|
||||
mock_DiscordClient.return_value.add_guild_member.side_effect = mock_exception
|
||||
|
||||
|
||||
result = DiscordUser.objects.add_user(self.user, authorization_code='abcdef')
|
||||
self.assertFalse(result)
|
||||
self.assertFalse(
|
||||
DiscordUser.objects.filter(user=self.user, uid=TEST_USER_ID).exists()
|
||||
)
|
||||
self.assertTrue(mock_DiscordClient.return_value.add_guild_member.called)
|
||||
|
||||
|
||||
|
||||
class TestOauthHelpers(TestCase):
|
||||
|
||||
@patch(MODULE_PATH + '.managers.DISCORD_APP_ID', '123456')
|
||||
|
||||
@patch(MODULE_PATH + '.managers.DISCORD_APP_ID', '123456')
|
||||
def test_generate_bot_add_url(self):
|
||||
bot_add_url = DiscordUser.objects.generate_bot_add_url()
|
||||
|
||||
@@ -303,18 +303,18 @@ class TestOauthHelpers(TestCase):
|
||||
|
||||
|
||||
class TestUserFormattedNick(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
def setUp(self):
|
||||
self.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
|
||||
|
||||
def test_return_nick_when_user_has_main(self):
|
||||
AuthUtils.add_main_character_2(self.user, TEST_MAIN_NAME, TEST_MAIN_ID)
|
||||
result = DiscordUser.objects.user_formatted_nick(self.user)
|
||||
expected = TEST_MAIN_NAME
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
def test_return_none_if_user_has_no_main(self):
|
||||
result = DiscordUser.objects.user_formatted_nick(self.user)
|
||||
def test_return_none_if_user_has_no_main(self):
|
||||
result = DiscordUser.objects.user_formatted_nick(self.user)
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
@@ -325,16 +325,16 @@ class TestUserGroupNames(TestCase):
|
||||
super().setUpClass()
|
||||
cls.group_1 = Group.objects.create(name='Group 1')
|
||||
cls.group_2 = Group.objects.create(name='Group 2')
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.user = AuthUtils.create_member(TEST_USER_NAME)
|
||||
self.user = AuthUtils.create_member(TEST_USER_NAME)
|
||||
|
||||
def test_return_groups_and_state_names_for_user(self):
|
||||
self.user.groups.add(self.group_1)
|
||||
result = DiscordUser.objects.user_group_names(self.user)
|
||||
expected = ['Group 1', 'Member']
|
||||
self.assertSetEqual(set(result), set(expected))
|
||||
|
||||
|
||||
def test_return_state_only_if_user_has_no_groups(self):
|
||||
result = DiscordUser.objects.user_group_names(self.user)
|
||||
expected = ['Member']
|
||||
@@ -355,11 +355,11 @@ class TestUserHasAccount(TestCase):
|
||||
def test_return_false_if_user_has_no_account(self):
|
||||
self.assertFalse(DiscordUser.objects.user_has_account(self.user))
|
||||
|
||||
def test_return_false_if_user_does_not_exist(self):
|
||||
def test_return_false_if_user_does_not_exist(self):
|
||||
my_user = User(username='Dummy')
|
||||
self.assertFalse(DiscordUser.objects.user_has_account(my_user))
|
||||
|
||||
def test_return_false_if_not_called_with_user_object(self):
|
||||
def test_return_false_if_not_called_with_user_object(self):
|
||||
self.assertFalse(DiscordUser.objects.user_has_account('abc'))
|
||||
|
||||
|
||||
@@ -371,7 +371,7 @@ class TestServerName(TestCase):
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
|
||||
|
||||
def test_returns_name_when_api_returns_it(self, mock_logger, mock_DiscordClient):
|
||||
server_name = "El Dorado"
|
||||
mock_DiscordClient.return_value.guild_name.return_value = server_name
|
||||
@@ -383,7 +383,7 @@ class TestServerName(TestCase):
|
||||
self, mock_logger, mock_DiscordClient
|
||||
):
|
||||
mock_exception = HTTPError('Test exception')
|
||||
mock_exception.response = Mock(**{"status_code": 440})
|
||||
mock_exception.response = Mock(**{"status_code": 440})
|
||||
mock_DiscordClient.return_value.guild_name.side_effect = mock_exception
|
||||
|
||||
self.assertEqual(DiscordUser.objects.server_name(), "")
|
||||
@@ -407,7 +407,7 @@ class TestServerName(TestCase):
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.managers.DiscordClient', spec=DiscordClient)
|
||||
class TestRoleForGroup(TestCase):
|
||||
class TestRoleForGroup(TestCase):
|
||||
def test_return_role_if_found(self, mock_DiscordClient):
|
||||
mock_DiscordClient.return_value.match_role_from_name.return_value = ROLE_ALPHA
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ from django.test import TestCase
|
||||
from allianceauth.tests.auth_utils import AuthUtils
|
||||
|
||||
from . import (
|
||||
TEST_USER_NAME,
|
||||
TEST_USER_ID,
|
||||
TEST_MAIN_NAME,
|
||||
TEST_MAIN_ID,
|
||||
TEST_USER_NAME,
|
||||
TEST_USER_ID,
|
||||
TEST_MAIN_NAME,
|
||||
TEST_MAIN_ID,
|
||||
MODULE_PATH,
|
||||
ROLE_ALPHA,
|
||||
ROLE_BRAVO,
|
||||
ROLE_CHARLIE,
|
||||
ROLE_MIKE
|
||||
ROLE_ALPHA,
|
||||
ROLE_BRAVO,
|
||||
ROLE_CHARLIE,
|
||||
ROLE_MIKE
|
||||
)
|
||||
from ..discord_client import DiscordClient, DiscordApiBackoff
|
||||
from ..discord_client.tests import create_matched_role
|
||||
@@ -44,39 +44,39 @@ class TestBasicsAndHelpers(TestCase):
|
||||
@patch(MODULE_PATH + '.managers.DiscordClient', spec=DiscordClient)
|
||||
class TestUpdateNick(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
def setUp(self):
|
||||
self.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
self.discord_user = DiscordUser.objects.create(
|
||||
user=self.user, uid=TEST_USER_ID
|
||||
)
|
||||
|
||||
|
||||
def test_can_update(self, mock_DiscordClient):
|
||||
AuthUtils.add_main_character_2(self.user, TEST_MAIN_NAME, TEST_MAIN_ID)
|
||||
AuthUtils.add_main_character_2(self.user, TEST_MAIN_NAME, TEST_MAIN_ID)
|
||||
mock_DiscordClient.return_value.modify_guild_member.return_value = True
|
||||
|
||||
|
||||
result = self.discord_user.update_nickname()
|
||||
self.assertTrue(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
|
||||
def test_dont_update_if_user_has_no_main(self, mock_DiscordClient):
|
||||
def test_dont_update_if_user_has_no_main(self, mock_DiscordClient):
|
||||
mock_DiscordClient.return_value.modify_guild_member.return_value = False
|
||||
|
||||
|
||||
result = self.discord_user.update_nickname()
|
||||
self.assertFalse(result)
|
||||
self.assertFalse(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
|
||||
|
||||
def test_return_none_if_user_no_longer_a_member(self, mock_DiscordClient):
|
||||
AuthUtils.add_main_character_2(self.user, TEST_MAIN_NAME, TEST_MAIN_ID)
|
||||
mock_DiscordClient.return_value.modify_guild_member.return_value = None
|
||||
|
||||
|
||||
result = self.discord_user.update_nickname()
|
||||
self.assertIsNone(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
self.assertTrue(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
|
||||
def test_return_false_if_api_returns_false(self, mock_DiscordClient):
|
||||
AuthUtils.add_main_character_2(self.user, TEST_MAIN_NAME, TEST_MAIN_ID)
|
||||
AuthUtils.add_main_character_2(self.user, TEST_MAIN_NAME, TEST_MAIN_ID)
|
||||
mock_DiscordClient.return_value.modify_guild_member.return_value = False
|
||||
|
||||
|
||||
result = self.discord_user.update_nickname()
|
||||
self.assertFalse(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
@@ -89,16 +89,16 @@ class TestUpdateUsername(TestCase):
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
|
||||
def setUp(self):
|
||||
|
||||
def setUp(self):
|
||||
self.discord_user = DiscordUser.objects.create(
|
||||
user=self.user,
|
||||
uid=TEST_USER_ID,
|
||||
username=TEST_MAIN_NAME,
|
||||
user=self.user,
|
||||
uid=TEST_USER_ID,
|
||||
username=TEST_MAIN_NAME,
|
||||
discriminator='1234'
|
||||
)
|
||||
|
||||
def test_can_update(self, mock_DiscordClient):
|
||||
|
||||
def test_can_update(self, mock_DiscordClient):
|
||||
new_username = 'New name'
|
||||
new_discriminator = '9876'
|
||||
user_info = {
|
||||
@@ -109,7 +109,7 @@ class TestUpdateUsername(TestCase):
|
||||
}
|
||||
}
|
||||
mock_DiscordClient.return_value.guild_member.return_value = user_info
|
||||
|
||||
|
||||
result = self.discord_user.update_username()
|
||||
self.assertTrue(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.guild_member.called)
|
||||
@@ -138,7 +138,7 @@ class TestUpdateUsername(TestCase):
|
||||
def test_return_false_if_api_returns_corrput_data_2(self, mock_DiscordClient):
|
||||
user_info = {
|
||||
'user': {
|
||||
'id': str(TEST_USER_ID),
|
||||
'id': str(TEST_USER_ID),
|
||||
'discriminator': '1234',
|
||||
}
|
||||
}
|
||||
@@ -150,7 +150,7 @@ class TestUpdateUsername(TestCase):
|
||||
def test_return_false_if_api_returns_corrput_data_3(self, mock_DiscordClient):
|
||||
user_info = {
|
||||
'user': {
|
||||
'id': str(TEST_USER_ID),
|
||||
'id': str(TEST_USER_ID),
|
||||
'username': TEST_USER_NAME,
|
||||
}
|
||||
}
|
||||
@@ -169,12 +169,12 @@ class TestDeleteUser(TestCase):
|
||||
super().setUpClass()
|
||||
cls.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
|
||||
def setUp(self):
|
||||
def setUp(self):
|
||||
self.discord_user = DiscordUser.objects.create(
|
||||
user=self.user, uid=TEST_USER_ID
|
||||
)
|
||||
|
||||
def test_can_delete_user(self, mock_DiscordClient, mock_notify):
|
||||
def test_can_delete_user(self, mock_DiscordClient, mock_notify):
|
||||
mock_DiscordClient.return_value.remove_guild_member.return_value = True
|
||||
result = self.discord_user.delete_user()
|
||||
self.assertTrue(result)
|
||||
@@ -192,7 +192,7 @@ class TestDeleteUser(TestCase):
|
||||
|
||||
def test_can_delete_user_when_member_is_unknown(
|
||||
self, mock_DiscordClient, mock_notify
|
||||
):
|
||||
):
|
||||
mock_DiscordClient.return_value.remove_guild_member.return_value = None
|
||||
result = self.discord_user.delete_user()
|
||||
self.assertTrue(result)
|
||||
@@ -219,7 +219,7 @@ class TestDeleteUser(TestCase):
|
||||
)
|
||||
self.assertTrue(mock_DiscordClient.return_value.remove_guild_member.called)
|
||||
self.assertFalse(mock_notify.called)
|
||||
|
||||
|
||||
def test_raise_exception_on_api_backoff(
|
||||
self, mock_DiscordClient, mock_notify
|
||||
):
|
||||
@@ -227,7 +227,7 @@ class TestDeleteUser(TestCase):
|
||||
DiscordApiBackoff(999)
|
||||
with self.assertRaises(DiscordApiBackoff):
|
||||
self.discord_user.delete_user()
|
||||
|
||||
|
||||
def test_return_false_on_api_backoff_and_exception_handling_on(
|
||||
self, mock_DiscordClient, mock_notify
|
||||
):
|
||||
@@ -244,9 +244,9 @@ class TestDeleteUser(TestCase):
|
||||
mock_exception.response.status_code = 500
|
||||
mock_DiscordClient.return_value.remove_guild_member.side_effect = \
|
||||
mock_exception
|
||||
|
||||
|
||||
with self.assertRaises(HTTPError):
|
||||
self.discord_user.delete_user()
|
||||
self.discord_user.delete_user()
|
||||
|
||||
def test_return_false_on_http_error_and_exception_handling_on(
|
||||
self, mock_DiscordClient, mock_notify
|
||||
@@ -264,7 +264,7 @@ class TestDeleteUser(TestCase):
|
||||
@patch(MODULE_PATH + '.models.DiscordUser.objects.user_group_names')
|
||||
class TestUpdateGroups(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
def setUp(self):
|
||||
self.user = AuthUtils.create_user(TEST_USER_NAME)
|
||||
self.discord_user = DiscordUser.objects.create(
|
||||
user=self.user, uid=TEST_USER_ID
|
||||
@@ -272,14 +272,14 @@ class TestUpdateGroups(TestCase):
|
||||
self.guild_roles = [ROLE_ALPHA, ROLE_BRAVO, ROLE_CHARLIE, ROLE_MIKE]
|
||||
self.roles_requested = [
|
||||
create_matched_role(ROLE_ALPHA), create_matched_role(ROLE_BRAVO)
|
||||
]
|
||||
|
||||
]
|
||||
|
||||
def test_update_if_needed(
|
||||
self,
|
||||
mock_user_group_names,
|
||||
self,
|
||||
mock_user_group_names,
|
||||
mock_DiscordClient
|
||||
):
|
||||
roles_current = [1]
|
||||
roles_current = [1]
|
||||
mock_user_group_names.return_value = []
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = self.roles_requested
|
||||
@@ -287,7 +287,7 @@ class TestUpdateGroups(TestCase):
|
||||
mock_DiscordClient.return_value.guild_member.return_value = \
|
||||
{'roles': roles_current}
|
||||
mock_DiscordClient.return_value.modify_guild_member.return_value = True
|
||||
|
||||
|
||||
result = self.discord_user.update_groups()
|
||||
self.assertTrue(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
@@ -295,11 +295,11 @@ class TestUpdateGroups(TestCase):
|
||||
self.assertEqual(set(kwargs['role_ids']), {1, 2})
|
||||
|
||||
def test_update_if_needed_and_preserve_managed_roles(
|
||||
self,
|
||||
mock_user_group_names,
|
||||
self,
|
||||
mock_user_group_names,
|
||||
mock_DiscordClient
|
||||
):
|
||||
roles_current = [1, 13]
|
||||
roles_current = [1, 13]
|
||||
mock_user_group_names.return_value = []
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = self.roles_requested
|
||||
@@ -307,7 +307,7 @@ class TestUpdateGroups(TestCase):
|
||||
mock_DiscordClient.return_value.guild_member.return_value = \
|
||||
{'roles': roles_current}
|
||||
mock_DiscordClient.return_value.modify_guild_member.return_value = True
|
||||
|
||||
|
||||
result = self.discord_user.update_groups()
|
||||
self.assertTrue(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
@@ -315,28 +315,28 @@ class TestUpdateGroups(TestCase):
|
||||
self.assertEqual(set(kwargs['role_ids']), {1, 2, 13})
|
||||
|
||||
def test_dont_update_if_not_needed(
|
||||
self,
|
||||
mock_user_group_names,
|
||||
self,
|
||||
mock_user_group_names,
|
||||
mock_DiscordClient
|
||||
):
|
||||
roles_current = [1, 2, 13]
|
||||
roles_current = [1, 2, 13]
|
||||
mock_user_group_names.return_value = []
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = self.roles_requested
|
||||
mock_DiscordClient.return_value.guild_roles.return_value = self.guild_roles
|
||||
mock_DiscordClient.return_value.guild_member.return_value = \
|
||||
{'roles': roles_current}
|
||||
|
||||
|
||||
result = self.discord_user.update_groups()
|
||||
self.assertTrue(result)
|
||||
self.assertFalse(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
|
||||
def test_update_if_user_has_no_roles_on_discord(
|
||||
self,
|
||||
mock_user_group_names,
|
||||
self,
|
||||
mock_user_group_names,
|
||||
mock_DiscordClient
|
||||
):
|
||||
roles_current = []
|
||||
roles_current = []
|
||||
mock_user_group_names.return_value = []
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = self.roles_requested
|
||||
@@ -344,30 +344,30 @@ class TestUpdateGroups(TestCase):
|
||||
mock_DiscordClient.return_value.guild_member.return_value = \
|
||||
{'roles': roles_current}
|
||||
mock_DiscordClient.return_value.modify_guild_member.return_value = True
|
||||
|
||||
|
||||
result = self.discord_user.update_groups()
|
||||
self.assertTrue(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
args, kwargs = mock_DiscordClient.return_value.modify_guild_member.call_args
|
||||
self.assertEqual(set(kwargs['role_ids']), {1, 2})
|
||||
|
||||
|
||||
def test_return_none_if_user_no_longer_a_member(
|
||||
self,
|
||||
mock_user_group_names,
|
||||
self,
|
||||
mock_user_group_names,
|
||||
mock_DiscordClient
|
||||
):
|
||||
):
|
||||
mock_DiscordClient.return_value.guild_member.return_value = None
|
||||
|
||||
|
||||
result = self.discord_user.update_groups()
|
||||
self.assertIsNone(result)
|
||||
self.assertFalse(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
|
||||
def test_return_false_if_api_returns_false(
|
||||
self,
|
||||
mock_user_group_names,
|
||||
self,
|
||||
mock_user_group_names,
|
||||
mock_DiscordClient
|
||||
):
|
||||
roles_current = [1]
|
||||
roles_current = [1]
|
||||
mock_user_group_names.return_value = []
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = self.roles_requested
|
||||
@@ -375,17 +375,17 @@ class TestUpdateGroups(TestCase):
|
||||
mock_DiscordClient.return_value.guild_member.return_value = \
|
||||
{'roles': roles_current}
|
||||
mock_DiscordClient.return_value.modify_guild_member.return_value = False
|
||||
|
||||
|
||||
result = self.discord_user.update_groups()
|
||||
self.assertFalse(result)
|
||||
self.assertTrue(mock_DiscordClient.return_value.modify_guild_member.called)
|
||||
|
||||
def test_raise_exception_if_member_has_unknown_roles(
|
||||
self,
|
||||
mock_user_group_names,
|
||||
self,
|
||||
mock_user_group_names,
|
||||
mock_DiscordClient
|
||||
):
|
||||
roles_current = [99]
|
||||
roles_current = [99]
|
||||
mock_user_group_names.return_value = []
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = self.roles_requested
|
||||
@@ -393,21 +393,21 @@ class TestUpdateGroups(TestCase):
|
||||
mock_DiscordClient.return_value.guild_member.return_value = \
|
||||
{'roles': roles_current}
|
||||
mock_DiscordClient.return_value.modify_guild_member.return_value = True
|
||||
|
||||
|
||||
with self.assertRaises(RuntimeError):
|
||||
self.discord_user.update_groups()
|
||||
|
||||
def test_refresh_guild_roles_user_roles_dont_not_match(
|
||||
self,
|
||||
mock_user_group_names,
|
||||
self,
|
||||
mock_user_group_names,
|
||||
mock_DiscordClient
|
||||
):
|
||||
):
|
||||
def my_guild_roles(guild_id, use_cache=True):
|
||||
if use_cache:
|
||||
return [ROLE_ALPHA, ROLE_BRAVO, ROLE_MIKE]
|
||||
else:
|
||||
return [ROLE_ALPHA, ROLE_BRAVO, ROLE_CHARLIE, ROLE_MIKE]
|
||||
|
||||
|
||||
roles_current = [3]
|
||||
mock_user_group_names.return_value = []
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
@@ -421,10 +421,10 @@ class TestUpdateGroups(TestCase):
|
||||
self.assertEqual(mock_DiscordClient.return_value.guild_roles.call_count, 2)
|
||||
|
||||
def test_raise_exception_if_member_info_is_invalid(
|
||||
self,
|
||||
mock_user_group_names,
|
||||
self,
|
||||
mock_user_group_names,
|
||||
mock_DiscordClient
|
||||
):
|
||||
):
|
||||
mock_user_group_names.return_value = []
|
||||
mock_DiscordClient.return_value.match_or_create_roles_from_names\
|
||||
.return_value = self.roles_requested
|
||||
@@ -432,6 +432,6 @@ class TestUpdateGroups(TestCase):
|
||||
mock_DiscordClient.return_value.guild_member.return_value = \
|
||||
{'user': 'dummy'}
|
||||
mock_DiscordClient.return_value.modify_guild_member.return_value = True
|
||||
|
||||
|
||||
with self.assertRaises(RuntimeError):
|
||||
self.discord_user.update_groups()
|
||||
|
||||
@@ -23,7 +23,7 @@ logger = set_logger_to_file(MODULE_PATH, __file__)
|
||||
@patch(MODULE_PATH + '.DiscordUser.update_groups')
|
||||
@patch(MODULE_PATH + ".logger")
|
||||
class TestUpdateGroups(TestCase):
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
@@ -32,7 +32,7 @@ class TestUpdateGroups(TestCase):
|
||||
cls.group_2 = Group.objects.create(name='Group 2')
|
||||
cls.group_1.user_set.add(cls.user)
|
||||
cls.group_2.user_set.add(cls.user)
|
||||
|
||||
|
||||
def test_can_update_groups(self, mock_logger, mock_update_groups):
|
||||
DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
|
||||
tasks.update_groups(self.user.pk)
|
||||
@@ -43,7 +43,7 @@ class TestUpdateGroups(TestCase):
|
||||
):
|
||||
tasks.update_groups(self.user.pk)
|
||||
self.assertFalse(mock_update_groups.called)
|
||||
|
||||
|
||||
def test_retries_on_api_backoff(self, mock_logger, mock_update_groups):
|
||||
DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
|
||||
mock_exception = DiscordApiBackoff(999)
|
||||
@@ -63,7 +63,7 @@ class TestUpdateGroups(TestCase):
|
||||
tasks.update_groups(self.user.pk)
|
||||
|
||||
self.assertTrue(mock_logger.warning.called)
|
||||
|
||||
|
||||
def test_retry_on_http_error_404_when_user_not_deleted(
|
||||
self, mock_logger, mock_update_groups
|
||||
):
|
||||
@@ -77,8 +77,8 @@ class TestUpdateGroups(TestCase):
|
||||
tasks.update_groups(self.user.pk)
|
||||
|
||||
self.assertTrue(mock_logger.warning.called)
|
||||
|
||||
def test_retry_on_non_http_error(self, mock_logger, mock_update_groups):
|
||||
|
||||
def test_retry_on_non_http_error(self, mock_logger, mock_update_groups):
|
||||
DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
|
||||
mock_update_groups.side_effect = ConnectionError
|
||||
|
||||
@@ -86,23 +86,23 @@ class TestUpdateGroups(TestCase):
|
||||
tasks.update_groups(self.user.pk)
|
||||
|
||||
self.assertTrue(mock_logger.warning.called)
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.DISCORD_TASKS_MAX_RETRIES', 3)
|
||||
def test_log_error_if_retries_exhausted(self, mock_logger, mock_update_groups):
|
||||
DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
|
||||
DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
|
||||
mock_task = MagicMock(**{'request.retries': 3})
|
||||
mock_update_groups.side_effect = ConnectionError
|
||||
update_groups_inner = tasks.update_groups.__wrapped__.__func__
|
||||
|
||||
|
||||
update_groups_inner(mock_task, self.user.pk)
|
||||
self.assertTrue(mock_logger.error.called)
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.delete_user.delay')
|
||||
def test_delete_user_if_user_is_no_longer_member_of_discord_server(
|
||||
self, mock_delete_user, mock_logger, mock_update_groups
|
||||
):
|
||||
mock_update_groups.return_value = None
|
||||
|
||||
|
||||
DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
|
||||
tasks.update_groups(self.user.pk)
|
||||
self.assertTrue(mock_update_groups.called)
|
||||
@@ -111,45 +111,45 @@ class TestUpdateGroups(TestCase):
|
||||
|
||||
@patch(MODULE_PATH + '.DiscordUser.update_nickname')
|
||||
class TestUpdateNickname(TestCase):
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.user = AuthUtils.create_member(TEST_USER_NAME)
|
||||
AuthUtils.add_main_character_2(
|
||||
cls.user,
|
||||
TEST_MAIN_NAME,
|
||||
TEST_MAIN_ID,
|
||||
corp_id='2',
|
||||
corp_name='test_corp',
|
||||
cls.user,
|
||||
TEST_MAIN_NAME,
|
||||
TEST_MAIN_ID,
|
||||
corp_id='2',
|
||||
corp_name='test_corp',
|
||||
corp_ticker='TEST',
|
||||
disconnect_signals=True
|
||||
)
|
||||
cls.discord_user = DiscordUser.objects.create(user=cls.user, uid=TEST_USER_ID)
|
||||
|
||||
def test_can_update_nickname(self, mock_update_nickname):
|
||||
mock_update_nickname.return_value = True
|
||||
|
||||
def test_can_update_nickname(self, mock_update_nickname):
|
||||
mock_update_nickname.return_value = True
|
||||
|
||||
tasks.update_nickname(self.user.pk)
|
||||
self.assertTrue(mock_update_nickname.called)
|
||||
|
||||
def test_no_action_when_user_had_no_account(self, mock_update_nickname):
|
||||
my_user = AuthUtils.create_user('Dummy User')
|
||||
mock_update_nickname.return_value = False
|
||||
|
||||
|
||||
tasks.update_nickname(my_user.pk)
|
||||
self.assertFalse(mock_update_nickname.called)
|
||||
|
||||
def test_retries_on_api_backoff(self, mock_update_nickname):
|
||||
|
||||
def test_retries_on_api_backoff(self, mock_update_nickname):
|
||||
mock_exception = DiscordApiBackoff(999)
|
||||
mock_update_nickname.side_effect = mock_exception
|
||||
|
||||
|
||||
with self.assertRaises(Retry):
|
||||
tasks.update_nickname(self.user.pk)
|
||||
|
||||
def test_retries_on_general_exception(self, mock_update_nickname):
|
||||
def test_retries_on_general_exception(self, mock_update_nickname):
|
||||
mock_update_nickname.side_effect = ConnectionError
|
||||
|
||||
|
||||
with self.assertRaises(Retry):
|
||||
tasks.update_nickname(self.user.pk)
|
||||
|
||||
@@ -158,9 +158,9 @@ class TestUpdateNickname(TestCase):
|
||||
mock_task = MagicMock(**{'request.retries': 3})
|
||||
mock_update_nickname.side_effect = ConnectionError
|
||||
update_nickname_inner = tasks.update_nickname.__wrapped__.__func__
|
||||
|
||||
|
||||
update_nickname_inner(mock_task, self.user.pk)
|
||||
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.DiscordUser.update_username')
|
||||
class TestUpdateUsername(TestCase):
|
||||
@@ -206,7 +206,7 @@ class TestDeleteUser(TestCase):
|
||||
self, mock_delete_user_delay, mock_delete_user
|
||||
):
|
||||
mock_delete_user.return_value = None
|
||||
|
||||
|
||||
tasks.delete_user(self.user.pk)
|
||||
self.assertTrue(mock_delete_user.called)
|
||||
self.assertFalse(mock_delete_user_delay.called)
|
||||
@@ -218,15 +218,15 @@ class TestTaskPerformUserAction(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.user = AuthUtils.create_member('Peter Parker')
|
||||
cls.user = AuthUtils.create_member('Peter Parker')
|
||||
cls.discord_user = DiscordUser.objects.create(user=cls.user, uid=TEST_USER_ID)
|
||||
|
||||
def test_raise_value_error_on_unknown_method(self, mock_update_groups):
|
||||
mock_task = MagicMock(**{'request.retries': 0})
|
||||
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
tasks._task_perform_user_action(mock_task, self.user.pk, 'invalid_method')
|
||||
|
||||
|
||||
def test_catch_and_log_unexpected_exceptions(self, mock_update_groups):
|
||||
mock_task = MagicMock(**{'request.retries': 0})
|
||||
mock_update_groups.side_effect = RuntimeError
|
||||
@@ -253,8 +253,8 @@ class TestTaskUpdateServername(TestCase):
|
||||
|
||||
self.assertFalse(mock_logger.error.called)
|
||||
|
||||
def test_retry_on_http_error(self, mock_logger, mock_server_name):
|
||||
mock_exception = HTTPError(MagicMock(**{"response.status_code": 500}))
|
||||
def test_retry_on_http_error(self, mock_logger, mock_server_name):
|
||||
mock_exception = HTTPError(MagicMock(**{"response.status_code": 500}))
|
||||
mock_server_name.side_effect = mock_exception
|
||||
|
||||
with self.assertRaises(Retry):
|
||||
@@ -262,20 +262,20 @@ class TestTaskUpdateServername(TestCase):
|
||||
|
||||
self.assertTrue(mock_logger.warning.called)
|
||||
|
||||
def test_retry_on_connection_error(self, mock_logger, mock_server_name):
|
||||
def test_retry_on_connection_error(self, mock_logger, mock_server_name):
|
||||
mock_server_name.side_effect = ConnectionError
|
||||
|
||||
with self.assertRaises(Retry):
|
||||
tasks.update_servername()
|
||||
|
||||
self.assertTrue(mock_logger.warning.called)
|
||||
|
||||
|
||||
@patch(MODULE_PATH + '.DISCORD_TASKS_MAX_RETRIES', 3)
|
||||
def test_log_error_if_retries_exhausted(self, mock_logger, mock_server_name):
|
||||
mock_task = MagicMock(**{'request.retries': 3})
|
||||
mock_server_name.side_effect = ConnectionError
|
||||
update_groups_inner = tasks.update_servername.__wrapped__.__func__
|
||||
|
||||
|
||||
update_groups_inner(mock_task)
|
||||
self.assertTrue(mock_logger.error.called)
|
||||
|
||||
@@ -285,24 +285,24 @@ class TestTaskPerformUsersAction(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
super().setUpClass()
|
||||
|
||||
def test_raise_value_error_on_unknown_method(self, mock_server_name):
|
||||
mock_task = MagicMock(**{'request.retries': 0})
|
||||
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
tasks._task_perform_users_action(mock_task, 'invalid_method')
|
||||
|
||||
|
||||
def test_catch_and_log_unexpected_exceptions(self, mock_server_name):
|
||||
mock_server_name.side_effect = RuntimeError
|
||||
mock_task = MagicMock(**{'request.retries': 0})
|
||||
|
||||
|
||||
tasks._task_perform_users_action(mock_task, 'server_name')
|
||||
|
||||
|
||||
@override_settings(CELERY_ALWAYS_EAGER=True)
|
||||
class TestBulkTasks(TestCase):
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
@@ -321,7 +321,7 @@ class TestBulkTasks(TestCase):
|
||||
tasks.update_groups_bulk(expected_pks)
|
||||
self.assertEqual(mock_update_groups.call_count, 2)
|
||||
current_pks = [args[0][0] for args in mock_update_groups.call_args_list]
|
||||
|
||||
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
@patch(MODULE_PATH + '.update_groups.si')
|
||||
@@ -347,7 +347,7 @@ class TestBulkTasks(TestCase):
|
||||
self.assertEqual(mock_update_nickname.call_count, 2)
|
||||
current_pks = [
|
||||
args[0][0] for args in mock_update_nickname.call_args_list
|
||||
]
|
||||
]
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
@patch(MODULE_PATH + '.update_nickname.si')
|
||||
@@ -374,11 +374,11 @@ class TestBulkTasks(TestCase):
|
||||
tasks.update_usernames_bulk(expected_pks)
|
||||
self.assertEqual(mock_update_username.call_count, 2)
|
||||
current_pks = [args[0][0] for args in mock_update_username.call_args_list]
|
||||
|
||||
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
@patch(MODULE_PATH + '.update_username')
|
||||
@patch(MODULE_PATH + '.update_servername')
|
||||
@patch(MODULE_PATH + '.update_servername')
|
||||
def test_can_update_all_usernames(
|
||||
self, mock_update_servername, mock_update_username
|
||||
):
|
||||
@@ -405,7 +405,7 @@ class TestBulkTasks(TestCase):
|
||||
du_3 = DiscordUser.objects.create(user=self.user_3, uid=789)
|
||||
|
||||
tasks.update_all()
|
||||
self.assertEqual(mock_update_groups.si.call_count, 3)
|
||||
self.assertEqual(mock_update_groups.si.call_count, 3)
|
||||
current_pks = [args[0][0] for args in mock_update_groups.si.call_args_list]
|
||||
expected_pks = [du_1.pk, du_2.pk, du_3.pk]
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
@@ -415,7 +415,7 @@ class TestBulkTasks(TestCase):
|
||||
expected_pks = [du_1.pk, du_2.pk, du_3.pk]
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
self.assertEqual(mock_update_usernames.si.call_count, 3)
|
||||
self.assertEqual(mock_update_usernames.si.call_count, 3)
|
||||
current_pks = [args[0][0] for args in mock_update_usernames.si.call_args_list]
|
||||
expected_pks = [du_1.pk, du_2.pk, du_3.pk]
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
@@ -432,14 +432,14 @@ class TestBulkTasks(TestCase):
|
||||
du_3 = DiscordUser.objects.create(user=self.user_3, uid=789)
|
||||
|
||||
tasks.update_all()
|
||||
self.assertEqual(mock_update_groups.si.call_count, 3)
|
||||
self.assertEqual(mock_update_groups.si.call_count, 3)
|
||||
current_pks = [args[0][0] for args in mock_update_groups.si.call_args_list]
|
||||
expected_pks = [du_1.pk, du_2.pk, du_3.pk]
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
self.assertEqual(mock_update_nickname.si.call_count, 0)
|
||||
|
||||
self.assertEqual(mock_update_usernames.si.call_count, 3)
|
||||
self.assertEqual(mock_update_usernames.si.call_count, 3)
|
||||
current_pks = [args[0][0] for args in mock_update_usernames.si.call_args_list]
|
||||
expected_pks = [du_1.pk, du_2.pk, du_3.pk]
|
||||
self.assertSetEqual(set(current_pks), set(expected_pks))
|
||||
|
||||
@@ -9,19 +9,19 @@ MODULE_PATH = 'allianceauth.services.modules.discord.utils'
|
||||
class TestCleanSetting(TestCase):
|
||||
|
||||
@patch(MODULE_PATH + '.settings')
|
||||
def test_default_if_not_set(self, mock_settings):
|
||||
def test_default_if_not_set(self, mock_settings):
|
||||
mock_settings.TEST_SETTING_DUMMY = Mock(spec=None)
|
||||
result = clean_setting(
|
||||
'TEST_SETTING_DUMMY',
|
||||
False,
|
||||
'TEST_SETTING_DUMMY',
|
||||
False,
|
||||
)
|
||||
self.assertEqual(result, False)
|
||||
|
||||
@patch(MODULE_PATH + '.settings')
|
||||
def test_default_if_not_set_for_none(self, mock_settings):
|
||||
def test_default_if_not_set_for_none(self, mock_settings):
|
||||
mock_settings.TEST_SETTING_DUMMY = Mock(spec=None)
|
||||
result = clean_setting(
|
||||
'TEST_SETTING_DUMMY',
|
||||
'TEST_SETTING_DUMMY',
|
||||
None,
|
||||
required_type=int
|
||||
)
|
||||
@@ -31,8 +31,8 @@ class TestCleanSetting(TestCase):
|
||||
def test_true_stays_true(self, mock_settings):
|
||||
mock_settings.TEST_SETTING_DUMMY = True
|
||||
result = clean_setting(
|
||||
'TEST_SETTING_DUMMY',
|
||||
False,
|
||||
'TEST_SETTING_DUMMY',
|
||||
False,
|
||||
)
|
||||
self.assertEqual(result, True)
|
||||
|
||||
@@ -40,7 +40,7 @@ class TestCleanSetting(TestCase):
|
||||
def test_false_stays_false(self, mock_settings):
|
||||
mock_settings.TEST_SETTING_DUMMY = False
|
||||
result = clean_setting(
|
||||
'TEST_SETTING_DUMMY',
|
||||
'TEST_SETTING_DUMMY',
|
||||
False
|
||||
)
|
||||
self.assertEqual(result, False)
|
||||
@@ -49,7 +49,7 @@ class TestCleanSetting(TestCase):
|
||||
def test_default_for_invalid_type_bool(self, mock_settings):
|
||||
mock_settings.TEST_SETTING_DUMMY = 'invalid type'
|
||||
result = clean_setting(
|
||||
'TEST_SETTING_DUMMY',
|
||||
'TEST_SETTING_DUMMY',
|
||||
False
|
||||
)
|
||||
self.assertEqual(result, False)
|
||||
@@ -58,7 +58,7 @@ class TestCleanSetting(TestCase):
|
||||
def test_default_for_invalid_type_int(self, mock_settings):
|
||||
mock_settings.TEST_SETTING_DUMMY = 'invalid type'
|
||||
result = clean_setting(
|
||||
'TEST_SETTING_DUMMY',
|
||||
'TEST_SETTING_DUMMY',
|
||||
50
|
||||
)
|
||||
self.assertEqual(result, 50)
|
||||
@@ -67,7 +67,7 @@ class TestCleanSetting(TestCase):
|
||||
def test_default_if_below_minimum_1(self, mock_settings):
|
||||
mock_settings.TEST_SETTING_DUMMY = -5
|
||||
result = clean_setting(
|
||||
'TEST_SETTING_DUMMY',
|
||||
'TEST_SETTING_DUMMY',
|
||||
default_value=50
|
||||
)
|
||||
self.assertEqual(result, 50)
|
||||
@@ -76,7 +76,7 @@ class TestCleanSetting(TestCase):
|
||||
def test_default_if_below_minimum_2(self, mock_settings):
|
||||
mock_settings.TEST_SETTING_DUMMY = -50
|
||||
result = clean_setting(
|
||||
'TEST_SETTING_DUMMY',
|
||||
'TEST_SETTING_DUMMY',
|
||||
default_value=50,
|
||||
min_value=-10
|
||||
)
|
||||
@@ -86,7 +86,7 @@ class TestCleanSetting(TestCase):
|
||||
def test_default_for_invalid_type_int_2(self, mock_settings):
|
||||
mock_settings.TEST_SETTING_DUMMY = 1000
|
||||
result = clean_setting(
|
||||
'TEST_SETTING_DUMMY',
|
||||
'TEST_SETTING_DUMMY',
|
||||
default_value=50,
|
||||
max_value=100
|
||||
)
|
||||
@@ -97,6 +97,6 @@ class TestCleanSetting(TestCase):
|
||||
mock_settings.TEST_SETTING_DUMMY = 'invalid type'
|
||||
with self.assertRaises(ValueError):
|
||||
clean_setting(
|
||||
'TEST_SETTING_DUMMY',
|
||||
'TEST_SETTING_DUMMY',
|
||||
default_value=None
|
||||
)
|
||||
|
||||
@@ -11,10 +11,10 @@ from ..discord_client import DiscordClient
|
||||
from ..models import DiscordUser
|
||||
from ..utils import set_logger_to_file
|
||||
from ..views import (
|
||||
discord_callback,
|
||||
reset_discord,
|
||||
deactivate_discord,
|
||||
discord_add_bot,
|
||||
discord_callback,
|
||||
reset_discord,
|
||||
deactivate_discord,
|
||||
discord_add_bot,
|
||||
activate_discord
|
||||
)
|
||||
|
||||
@@ -49,10 +49,10 @@ class TestActivateDiscord(SetupClassMixin, TestCase):
|
||||
@patch(MODULE_PATH + '.views.messages')
|
||||
@patch(MODULE_PATH + '.managers.DiscordClient', spec=DiscordClient)
|
||||
class TestDeactivateDiscord(SetupClassMixin, TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
|
||||
|
||||
|
||||
def test_when_successful_show_success_message(
|
||||
self, mock_DiscordClient, mock_messages
|
||||
):
|
||||
@@ -81,7 +81,7 @@ class TestDeactivateDiscord(SetupClassMixin, TestCase):
|
||||
@patch(MODULE_PATH + '.views.messages')
|
||||
@patch(MODULE_PATH + '.managers.DiscordClient')
|
||||
class TestResetDiscord(SetupClassMixin, TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
|
||||
|
||||
@@ -93,7 +93,7 @@ class TestResetDiscord(SetupClassMixin, TestCase):
|
||||
request.user = self.user
|
||||
response = reset_discord(request)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse("discord:activate"))
|
||||
self.assertEqual(response.url, reverse("discord:activate"))
|
||||
self.assertFalse(mock_messages.error.called)
|
||||
|
||||
def test_when_unsuccessful_message_error_and_redirect_to_service(
|
||||
@@ -111,7 +111,7 @@ class TestResetDiscord(SetupClassMixin, TestCase):
|
||||
@patch(MODULE_PATH + '.views.messages')
|
||||
@patch(MODULE_PATH + '.views.DiscordUser.objects.add_user')
|
||||
class TestDiscordCallback(SetupClassMixin, TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
|
||||
|
||||
@@ -126,7 +126,7 @@ class TestDiscordCallback(SetupClassMixin, TestCase):
|
||||
self.assertEqual(response.url, self.services_url)
|
||||
self.assertTrue(mock_messages.success.called)
|
||||
self.assertFalse(mock_messages.error.called)
|
||||
|
||||
|
||||
def test_handle_no_code(self, mock_add_user, mock_messages):
|
||||
mock_add_user.return_value = True
|
||||
request = self.factory.get(
|
||||
@@ -138,7 +138,7 @@ class TestDiscordCallback(SetupClassMixin, TestCase):
|
||||
self.assertEqual(response.url, self.services_url)
|
||||
self.assertFalse(mock_messages.success.called)
|
||||
self.assertTrue(mock_messages.error.called)
|
||||
|
||||
|
||||
def test_error_message_when_user_creation_failed(
|
||||
self, mock_add_user, mock_messages
|
||||
):
|
||||
@@ -156,7 +156,7 @@ class TestDiscordCallback(SetupClassMixin, TestCase):
|
||||
|
||||
@patch(MODULE_PATH + '.views.DiscordUser.objects.generate_bot_add_url')
|
||||
class TestDiscordAddBot(TestCase):
|
||||
|
||||
|
||||
def test_add_bot(self, mock_generate_bot_add_url):
|
||||
bot_url = 'https://www.example.com/bot'
|
||||
mock_generate_bot_add_url.return_value = bot_url
|
||||
|
||||
@@ -15,7 +15,7 @@ class LoggerAddTag(logging.LoggerAdapter):
|
||||
|
||||
def process(self, msg, kwargs):
|
||||
return '[%s] %s' % (self.prefix, msg), kwargs
|
||||
|
||||
|
||||
|
||||
def clean_setting(
|
||||
name: str,
|
||||
@@ -58,7 +58,7 @@ def clean_setting(
|
||||
'You setting for %s it not valid. Please correct it. '
|
||||
'Using default for now: %s',
|
||||
name,
|
||||
default_value
|
||||
default_value
|
||||
)
|
||||
cleaned_value = default_value
|
||||
return cleaned_value
|
||||
@@ -66,15 +66,15 @@ def clean_setting(
|
||||
|
||||
def set_logger_to_file(logger_name: str, name: str) -> object:
|
||||
"""set logger for current module to log into a file. Useful for tests.
|
||||
|
||||
|
||||
Args:
|
||||
- logger: current logger object
|
||||
- name: name of current module, e.g. __file__
|
||||
|
||||
|
||||
Returns:
|
||||
- amended logger
|
||||
"""
|
||||
|
||||
|
||||
# reconfigure logger so we get logging from tested module
|
||||
f_format = logging.Formatter(
|
||||
'%(asctime)s - %(levelname)s - %(module)s:%(funcName)s - %(message)s'
|
||||
|
||||
@@ -47,11 +47,11 @@ def reset_discord(request):
|
||||
):
|
||||
logger.info(
|
||||
"Successfully deleted discord user for user %s - "
|
||||
"forwarding to discord activation.",
|
||||
"forwarding to discord activation.",
|
||||
request.user
|
||||
)
|
||||
return redirect("discord:activate")
|
||||
|
||||
|
||||
logger.error(
|
||||
"Unsuccessful attempt to reset discord for user %s", request.user
|
||||
)
|
||||
@@ -74,7 +74,7 @@ def discord_callback(request):
|
||||
logger.debug(
|
||||
"Received Discord callback for activation of user %s", request.user
|
||||
)
|
||||
authorization_code = request.GET.get('code', None)
|
||||
authorization_code = request.GET.get('code', None)
|
||||
if not authorization_code:
|
||||
logger.warning(
|
||||
"Did not receive OAuth code from callback for user %s", request.user
|
||||
@@ -82,34 +82,34 @@ def discord_callback(request):
|
||||
success = False
|
||||
else:
|
||||
if DiscordUser.objects.add_user(
|
||||
user=request.user,
|
||||
authorization_code=authorization_code,
|
||||
user=request.user,
|
||||
authorization_code=authorization_code,
|
||||
is_rate_limited=False
|
||||
):
|
||||
logger.info(
|
||||
"Successfully activated Discord account for user %s", request.user
|
||||
)
|
||||
success = True
|
||||
|
||||
|
||||
else:
|
||||
logger.error(
|
||||
"Failed to activate Discord account for user %s", request.user
|
||||
)
|
||||
success = False
|
||||
|
||||
|
||||
if success:
|
||||
messages.success(
|
||||
request, _('Your Discord account has been successfully activated.')
|
||||
)
|
||||
else:
|
||||
messages.error(
|
||||
request,
|
||||
request,
|
||||
_(
|
||||
'An error occurred while trying to activate your Discord account. '
|
||||
'Please try again.'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,6 @@ from ...admin import ServicesUserAdmin
|
||||
|
||||
@admin.register(DiscourseUser)
|
||||
class DiscourseUserAdmin(ServicesUserAdmin):
|
||||
list_display = ServicesUserAdmin.list_display + (
|
||||
'enabled',
|
||||
)
|
||||
list_display = ServicesUserAdmin.list_display + (
|
||||
'enabled',
|
||||
)
|
||||
|
||||
@@ -27,7 +27,7 @@ class ExampleService(ServicesHook):
|
||||
urls = self.Urls()
|
||||
# urls.auth_activate = 'auth_example_activate'
|
||||
# urls.auth_deactivate = 'auth_example_deactivate'
|
||||
# urls.auth_reset_password = 'auth_example_reset_password'
|
||||
# urls.auth_reset_password = 'auth_example_reset_password'
|
||||
# urls.auth_set_password = 'auth_example_set_password'
|
||||
return render_to_string(self.service_ctrl_template, {
|
||||
'service_name': self.title,
|
||||
|
||||
@@ -17,7 +17,7 @@ def migrate_service_enabled(apps, schema_editor):
|
||||
app_config.models_module = True
|
||||
create_permissions(app_config, apps=apps, verbosity=0)
|
||||
app_config.models_module = None
|
||||
|
||||
|
||||
Group = apps.get_model("auth", "Group")
|
||||
Permission = apps.get_model("auth", "Permission")
|
||||
Ips4User = apps.get_model("ips4", "Ips4User")
|
||||
|
||||
@@ -5,12 +5,12 @@ from ...admin import ServicesUserAdmin
|
||||
|
||||
|
||||
@admin.register(MumbleUser)
|
||||
class MumbleUserAdmin(ServicesUserAdmin):
|
||||
list_display = ServicesUserAdmin.list_display + (
|
||||
'username',
|
||||
class MumbleUserAdmin(ServicesUserAdmin):
|
||||
list_display = ServicesUserAdmin.list_display + (
|
||||
'username',
|
||||
'groups',
|
||||
)
|
||||
search_fields = ServicesUserAdmin.search_fields + (
|
||||
)
|
||||
search_fields = ServicesUserAdmin.search_fields + (
|
||||
'username',
|
||||
'groups'
|
||||
)
|
||||
|
||||
@@ -44,7 +44,7 @@ class MumbleService(ServicesHook):
|
||||
logger.debug("Updating %s nickname for %s" % (self.name, user))
|
||||
if MumbleTasks.has_account(user):
|
||||
MumbleTasks.update_display_name.apply_async(args=[user.pk], countdown=5) # cooldown on this task to ensure DB clean when syncing
|
||||
|
||||
|
||||
def validate_user(self, user):
|
||||
if MumbleTasks.has_account(user) and not self.service_active_for_user(user):
|
||||
self.delete_user(user, notify_user=True)
|
||||
|
||||
@@ -18,11 +18,11 @@ class MumbleManager(models.Manager):
|
||||
def get_display_name(user):
|
||||
from .auth_hooks import MumbleService
|
||||
return NameFormatter(MumbleService(), user).format_name()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_username(user):
|
||||
return user.profile.main_character.character_name # main character as the user.username may be incorect
|
||||
|
||||
|
||||
@staticmethod
|
||||
def sanitise_username(username):
|
||||
return username.replace(" ", "_")
|
||||
|
||||
@@ -6,6 +6,6 @@ from ...admin import ServicesUserAdmin
|
||||
|
||||
@admin.register(OpenfireUser)
|
||||
class OpenfireUserAdmin(ServicesUserAdmin):
|
||||
list_display = ServicesUserAdmin.list_display + ('username',)
|
||||
list_display = ServicesUserAdmin.list_display + ('username',)
|
||||
search_fields = ServicesUserAdmin.search_fields + ('username', )
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ def migrate_service_enabled(apps, schema_editor):
|
||||
app_config.models_module = True
|
||||
create_permissions(app_config, apps=apps, verbosity=0)
|
||||
app_config.models_module = None
|
||||
|
||||
|
||||
Group = apps.get_model("auth", "Group")
|
||||
Permission = apps.get_model("auth", "Permission")
|
||||
OpenfireUser = apps.get_model("openfire", "OpenfireUser")
|
||||
|
||||
@@ -5,5 +5,5 @@ from ...admin import ServicesUserAdmin
|
||||
|
||||
@admin.register(Phpbb3User)
|
||||
class Phpbb3UserAdmin(ServicesUserAdmin):
|
||||
list_display = ServicesUserAdmin.list_display + ('username',)
|
||||
list_display = ServicesUserAdmin.list_display + ('username',)
|
||||
search_fields = ServicesUserAdmin.search_fields + ('username', )
|
||||
@@ -6,5 +6,5 @@ from ...admin import ServicesUserAdmin
|
||||
|
||||
@admin.register(SmfUser)
|
||||
class SmfUserAdmin(ServicesUserAdmin):
|
||||
list_display = ServicesUserAdmin.list_display + ('username',)
|
||||
list_display = ServicesUserAdmin.list_display + ('username',)
|
||||
search_fields = ServicesUserAdmin.search_fields + ('username', )
|
||||
@@ -102,7 +102,7 @@ class SmfManager:
|
||||
|
||||
@classmethod
|
||||
def add_avatar(cls, member_name, characterid):
|
||||
logger.debug("Adding EVE character id %s portrait as smf avatar for user %s" % (characterid, member_name))
|
||||
logger.debug("Adding EVE character id %s portrait as smf avatar for user %s" % (characterid, member_name))
|
||||
avatar_url = EveCharacter.generic_portrait_url(characterid, 64)
|
||||
cursor = connections['smf'].cursor()
|
||||
id_member = cls.get_user_id(member_name)
|
||||
|
||||
@@ -17,7 +17,7 @@ def migrate_service_enabled(apps, schema_editor):
|
||||
app_config.models_module = True
|
||||
create_permissions(app_config, apps=apps, verbosity=0)
|
||||
app_config.models_module = None
|
||||
|
||||
|
||||
Group = apps.get_model("auth", "Group")
|
||||
Permission = apps.get_model("auth", "Permission")
|
||||
SmfUser = apps.get_model("smf", "SmfUser")
|
||||
|
||||
@@ -5,28 +5,28 @@ from ...admin import ServicesUserAdmin
|
||||
|
||||
|
||||
@admin.register(Teamspeak3User)
|
||||
class Teamspeak3UserAdmin(ServicesUserAdmin):
|
||||
list_display = ServicesUserAdmin.list_display + (
|
||||
class Teamspeak3UserAdmin(ServicesUserAdmin):
|
||||
list_display = ServicesUserAdmin.list_display + (
|
||||
'uid',
|
||||
'perm_key'
|
||||
'perm_key'
|
||||
)
|
||||
search_fields = ServicesUserAdmin.search_fields + ('uid', )
|
||||
|
||||
|
||||
|
||||
@admin.register(AuthTS)
|
||||
class AuthTSgroupAdmin(admin.ModelAdmin):
|
||||
ordering = ('auth_group__name', )
|
||||
list_select_related = True
|
||||
|
||||
list_select_related = True
|
||||
|
||||
list_display = ('auth_group', '_ts_group')
|
||||
list_filter = ('ts_group', )
|
||||
|
||||
|
||||
fields = ('auth_group', 'ts_group')
|
||||
filter_horizontal = ('ts_group',)
|
||||
|
||||
def _ts_group(self, obj):
|
||||
return [x for x in obj.ts_group.all().order_by('ts_group_id')]
|
||||
|
||||
|
||||
_ts_group.short_description = 'ts groups'
|
||||
#_ts_group.admin_order_field = 'profile__state'
|
||||
|
||||
|
||||
@@ -304,21 +304,20 @@ class Teamspeak3ManagerTestCase(TestCase):
|
||||
|
||||
@mock.patch.object(Teamspeak3Manager, '_group_list')
|
||||
@mock.patch.object(Teamspeak3Manager, '_group_id_by_name')
|
||||
def test_add_user_exception(self, _group_id_by_name, _group_list):
|
||||
def test_add_user_exception(self, _group_id_by_name, _group_list):
|
||||
"""test 1st exception occuring in add_user()"""
|
||||
# set mocks in Teamspeak3Manager class
|
||||
_group_list.return_value = ['Member', 'Guest']
|
||||
_group_id_by_name.return_value = 99
|
||||
_group_id_by_name.return_value = 99
|
||||
manager = Teamspeak3Manager()
|
||||
server = mock.MagicMock()
|
||||
server._connected.return_value = True
|
||||
server.send_command = mock.Mock(side_effect=Teamspeak3ManagerTestCase.my_side_effect)
|
||||
manager._server = server
|
||||
|
||||
# create test data
|
||||
# create test data
|
||||
user = User.objects.create_user("dummy")
|
||||
user.profile.state = State.objects.filter(name="Member").first()
|
||||
|
||||
|
||||
# perform test
|
||||
manager.add_user(user, "Dummy User")
|
||||
|
||||
@@ -6,5 +6,5 @@ from ...admin import ServicesUserAdmin
|
||||
|
||||
@admin.register(XenforoUser)
|
||||
class XenforoUserAdmin(ServicesUserAdmin):
|
||||
list_display = ServicesUserAdmin.list_display + ('username',)
|
||||
list_display = ServicesUserAdmin.list_display + ('username',)
|
||||
search_fields = ServicesUserAdmin.search_fields + ('username', )
|
||||
@@ -125,7 +125,7 @@ def m2m_changed_state_permissions(sender, instance, action, pk_set, *args, **kwa
|
||||
|
||||
@receiver(state_changed)
|
||||
def check_service_accounts_state_changed(sender, user, state, **kwargs):
|
||||
logger.debug("Received state_changed from %s to state %s" % (user, state))
|
||||
logger.debug("Received state_changed from %s to state %s" % (user, state))
|
||||
for svc in ServicesHook.get_services():
|
||||
svc.validate_user(user)
|
||||
svc.update_groups(user)
|
||||
@@ -154,7 +154,7 @@ def disable_services_on_inactive(sender, instance, *args, **kwargs):
|
||||
|
||||
|
||||
@receiver(pre_save, sender=UserProfile)
|
||||
def process_main_character_change(sender, instance, *args, **kwargs):
|
||||
def process_main_character_change(sender, instance, *args, **kwargs):
|
||||
if not instance.pk:
|
||||
# ignore new model being created
|
||||
return
|
||||
@@ -169,9 +169,9 @@ def process_main_character_change(sender, instance, *args, **kwargs):
|
||||
instance.user
|
||||
)
|
||||
disable_user(instance.user)
|
||||
elif old_instance.main_character != instance.main_character:
|
||||
elif old_instance.main_character != instance.main_character:
|
||||
logger.info(
|
||||
"Updating Names due to change of main character for user %s",
|
||||
"Updating Names due to change of main character for user %s",
|
||||
instance.user
|
||||
)
|
||||
for svc in ServicesHook.get_services():
|
||||
@@ -181,8 +181,8 @@ def process_main_character_change(sender, instance, *args, **kwargs):
|
||||
except:
|
||||
logger.exception(
|
||||
"Exception running sync_nickname for services module %s "
|
||||
"on user %s",
|
||||
svc,
|
||||
"on user %s",
|
||||
svc,
|
||||
instance
|
||||
)
|
||||
|
||||
@@ -192,10 +192,10 @@ def process_main_character_change(sender, instance, *args, **kwargs):
|
||||
|
||||
@receiver(pre_save, sender=EveCharacter)
|
||||
def process_main_character_update(sender, instance, *args, **kwargs):
|
||||
try:
|
||||
try:
|
||||
if instance.userprofile:
|
||||
logger.debug(
|
||||
"Received pre_save from %s for process_main_character_update",
|
||||
"Received pre_save from %s for process_main_character_update",
|
||||
instance
|
||||
)
|
||||
old_instance = EveCharacter.objects.get(pk=instance.pk)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
CSS for allianceauth admin site
|
||||
/*
|
||||
CSS for allianceauth admin site
|
||||
*/
|
||||
|
||||
.img-circle { border-radius: 50%; }
|
||||
|
||||
@@ -22,7 +22,7 @@ class DjangoBackend:
|
||||
@staticmethod
|
||||
def raise_or_lock(key, timeout):
|
||||
acquired = cache.add(key=key, value="lock", timeout=timeout)
|
||||
if not acquired:
|
||||
if not acquired:
|
||||
raise AlreadyQueued(int(cache.ttl(key)))
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<li>
|
||||
<a class="{% navactive request item.navactive|join:' ' %}" href="{% url item.url_name %}">
|
||||
<i class="{{ item.classes }}"></i> {% trans item.text %}
|
||||
<i class="{{ item.classes }}"></i> {% trans item.text %}
|
||||
{% if item.count != None %}
|
||||
<span class="badge">{{ item.count }}</span>
|
||||
{% endif %}
|
||||
|
||||
@@ -198,10 +198,10 @@ class ServicesSignalsTestCase(TestCase):
|
||||
# Assert
|
||||
self.assertTrue(services_hook.get_services.called)
|
||||
|
||||
self.assertTrue(svc.validate_user.called)
|
||||
self.assertTrue(svc.validate_user.called)
|
||||
args, kwargs = svc.validate_user.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
|
||||
self.assertTrue(svc.update_groups.called)
|
||||
args, kwargs = svc.update_groups.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
@@ -217,11 +217,11 @@ class ServicesSignalsTestCase(TestCase):
|
||||
svc.access_perm = 'auth.access_testsvc'
|
||||
|
||||
services_hook.get_services.return_value = [svc]
|
||||
|
||||
|
||||
new_main = EveCharacter.objects.create(
|
||||
character_id=123,
|
||||
character_name="Alter Ego",
|
||||
corporation_id=987,
|
||||
character_id=123,
|
||||
character_name="Alter Ego",
|
||||
corporation_id=987,
|
||||
corporation_name="ABC"
|
||||
)
|
||||
self.member.profile.main_character = new_main
|
||||
@@ -230,17 +230,17 @@ class ServicesSignalsTestCase(TestCase):
|
||||
# Assert
|
||||
self.assertTrue(services_hook.get_services.called)
|
||||
|
||||
self.assertTrue(svc.validate_user.called)
|
||||
self.assertTrue(svc.validate_user.called)
|
||||
args, kwargs = svc.validate_user.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
|
||||
self.assertTrue(svc.sync_nickname.called)
|
||||
args, kwargs = svc.sync_nickname.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
@mock.patch('allianceauth.services.signals.ServicesHook')
|
||||
def test_state_changed_services_validation_and_groups_update_2(self, services_hook):
|
||||
"""Test a user changing main has service does not have accounts validated
|
||||
"""Test a user changing main has service does not have accounts validated
|
||||
and sync updated if the new main is equal to the old main
|
||||
"""
|
||||
svc = mock.Mock()
|
||||
@@ -249,7 +249,7 @@ class ServicesSignalsTestCase(TestCase):
|
||||
svc.access_perm = 'auth.access_testsvc'
|
||||
|
||||
services_hook.get_services.return_value = [svc]
|
||||
|
||||
|
||||
# this creates a clone of the Django object
|
||||
new_main = deepcopy(self.member.profile.main_character)
|
||||
self.assertIsNot(new_main, self.member.profile.main_character)
|
||||
@@ -258,5 +258,5 @@ class ServicesSignalsTestCase(TestCase):
|
||||
|
||||
# Assert
|
||||
self.assertFalse(services_hook.get_services.called)
|
||||
self.assertFalse(svc.validate_user.called)
|
||||
self.assertFalse(svc.validate_user.called)
|
||||
self.assertFalse(svc.sync_nickname.called)
|
||||
@@ -34,28 +34,28 @@ class TestDjangoBackend(TestCase):
|
||||
|
||||
TEST_KEY = "my-django-backend-test-key"
|
||||
TIMEOUT = 1800
|
||||
|
||||
|
||||
def setUp(self) -> None:
|
||||
cache.delete(self.TEST_KEY)
|
||||
self.backend = DjangoBackend(dict())
|
||||
|
||||
|
||||
def test_can_get_lock(self):
|
||||
"""
|
||||
when lock can be acquired
|
||||
when lock can be acquired
|
||||
then set it with timetout
|
||||
"""
|
||||
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
||||
self.assertIsNotNone(cache.get(self.TEST_KEY))
|
||||
self.assertAlmostEqual(cache.ttl(self.TEST_KEY), self.TIMEOUT, delta=2)
|
||||
|
||||
|
||||
def test_when_cant_get_lock_raise_exception(self):
|
||||
"""
|
||||
when lock can bot be acquired
|
||||
when lock can bot be acquired
|
||||
then raise AlreadyQueued exception with countdown
|
||||
"""
|
||||
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
||||
|
||||
try:
|
||||
try:
|
||||
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
||||
except Exception as ex:
|
||||
self.assertIsInstance(ex, AlreadyQueued)
|
||||
@@ -64,7 +64,7 @@ class TestDjangoBackend(TestCase):
|
||||
def test_can_clear_lock(self):
|
||||
"""
|
||||
when a lock exists
|
||||
then can get a new lock after clearing it
|
||||
then can get a new lock after clearing it
|
||||
"""
|
||||
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user