mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-13 14:30:17 +02:00
Stop using the patch method for setting roles.
Switch to dedicated add/remove endpoints. Allow setting max cache age to None for infinite. Apparently patch has issues. Thanks @TargetZ3R0 and Discord devs <3
This commit is contained in:
parent
b4c395f116
commit
21e896642a
@ -32,7 +32,7 @@ SCOPES = [
|
|||||||
'guilds.join',
|
'guilds.join',
|
||||||
]
|
]
|
||||||
|
|
||||||
GROUP_CACHE_MAX_AGE = int(getattr(settings, 'DISCORD_GROUP_CACHE_MAX_AGE', 2 * 60 * 60)) # 2 hours default
|
GROUP_CACHE_MAX_AGE = getattr(settings, 'DISCORD_GROUP_CACHE_MAX_AGE', 2 * 60 * 60) # 2 hours default
|
||||||
|
|
||||||
|
|
||||||
class DiscordApiException(Exception):
|
class DiscordApiException(Exception):
|
||||||
@ -301,13 +301,38 @@ class DiscordOAuthManager:
|
|||||||
def _create_group(name):
|
def _create_group(name):
|
||||||
return DiscordOAuthManager.__generate_role(name)
|
return DiscordOAuthManager.__generate_role(name)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_user(user_id):
|
||||||
|
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||||
|
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
||||||
|
r = requests.get(path, headers=custom_headers)
|
||||||
|
r.raise_for_status()
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_user_roles(user_id):
|
||||||
|
user = DiscordOAuthManager._get_user(user_id)
|
||||||
|
return user['roles']
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _modify_user_role(user_id, role_id, method):
|
||||||
|
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||||
|
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id) + "/roles/" + str(
|
||||||
|
role_id)
|
||||||
|
r = getattr(requests, method)(path, headers=custom_headers)
|
||||||
|
r.raise_for_status()
|
||||||
|
logger.debug("%s role %s for user %s" % (method, role_id, user_id))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@api_backoff
|
@api_backoff
|
||||||
def update_groups(user_id, groups):
|
def update_groups(user_id, groups):
|
||||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
|
||||||
group_ids = [DiscordOAuthManager._group_name_to_id(DiscordOAuthManager._sanitize_group_name(g)) for g in groups]
|
group_ids = [DiscordOAuthManager._group_name_to_id(DiscordOAuthManager._sanitize_group_name(g)) for g in groups]
|
||||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
user_group_ids = DiscordOAuthManager._get_user_roles(user_id)
|
||||||
data = {'roles': group_ids}
|
for g in group_ids:
|
||||||
r = requests.patch(path, headers=custom_headers, json=data)
|
if g not in user_group_ids:
|
||||||
logger.debug("Received status code %s after setting user roles" % r.status_code)
|
DiscordOAuthManager._modify_user_role(user_id, g, 'put')
|
||||||
r.raise_for_status()
|
time.sleep(1) # we're gonna be hammering the API here
|
||||||
|
for g in user_group_ids:
|
||||||
|
if g not in group_ids:
|
||||||
|
DiscordOAuthManager._modify_user_role(user_id, g, 'delete')
|
||||||
|
time.sleep(1)
|
||||||
|
@ -327,54 +327,54 @@ class DiscordManagerTestCase(TestCase):
|
|||||||
# Assert
|
# Assert
|
||||||
self.assertTrue(result)
|
self.assertTrue(result)
|
||||||
|
|
||||||
|
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_user_roles')
|
||||||
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_groups')
|
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_groups')
|
||||||
@requests_mock.Mocker()
|
@requests_mock.Mocker()
|
||||||
def test_update_groups(self, group_cache, m):
|
def test_update_groups(self, group_cache, user_roles, m):
|
||||||
# Arrange
|
# Arrange
|
||||||
groups = ['Member', 'Blue', 'SpecialGroup']
|
groups = ['Member', 'Blue', 'SpecialGroup']
|
||||||
|
|
||||||
group_cache.return_value = [{'id': 111, 'name': 'Member'},
|
group_cache.return_value = [{'id': '111', 'name': 'Member'},
|
||||||
{'id': 222, 'name': 'Blue'},
|
{'id': '222', 'name': 'Blue'},
|
||||||
{'id': 333, 'name': 'SpecialGroup'},
|
{'id': '333', 'name': 'SpecialGroup'},
|
||||||
{'id': 444, 'name': 'NotYourGroup'}]
|
{'id': '444', 'name': 'NotYourGroup'}]
|
||||||
|
user_roles.return_value = ['444']
|
||||||
|
|
||||||
headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||||
user_id = 12345
|
user_id = 12345
|
||||||
request_url = '{}/guilds/{}/members/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id)
|
user_request_url = '{}/guilds/{}/members/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id)
|
||||||
|
group_request_urls = ['{}/guilds/{}/members/{}/roles/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id, g['id']) for g in group_cache.return_value]
|
||||||
|
|
||||||
m.patch(request_url,
|
m.patch(user_request_url, request_headers=headers)
|
||||||
request_headers=headers)
|
[m.put(url, request_headers=headers) for url in group_request_urls[:-1]]
|
||||||
|
m.delete(group_request_urls[-1], request_headers=headers)
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
DiscordOAuthManager.update_groups(user_id, groups)
|
DiscordOAuthManager.update_groups(user_id, groups)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(len(m.request_history), 1, 'Must be one HTTP call made')
|
self.assertEqual(len(m.request_history), 4, 'Must be 4 HTTP calls made')
|
||||||
history = json.loads(m.request_history[0].text)
|
|
||||||
self.assertIn('roles', history, "'The request must send JSON object with the 'roles' key")
|
|
||||||
self.assertIn(111, history['roles'], 'The group id 111 must be added to the request')
|
|
||||||
self.assertIn(222, history['roles'], 'The group id 222 must be added to the request')
|
|
||||||
self.assertIn(333, history['roles'], 'The group id 333 must be added to the request')
|
|
||||||
self.assertNotIn(444, history['roles'], 'The group id 444 must NOT be added to the request')
|
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.manager.cache')
|
@mock.patch(MODULE_PATH + '.manager.cache')
|
||||||
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_groups')
|
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_user_roles')
|
||||||
|
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._group_name_to_id')
|
||||||
@requests_mock.Mocker()
|
@requests_mock.Mocker()
|
||||||
def test_update_groups_backoff(self, group_cache, djcache, m):
|
def test_update_groups_backoff(self, name_to_id, user_groups, djcache, m):
|
||||||
# Arrange
|
# Arrange
|
||||||
groups = ['Member']
|
groups = ['Member']
|
||||||
group_cache.return_value = [{'id': 111, 'name': 'Member'}]
|
user_groups.return_value = []
|
||||||
|
name_to_id.return_value = '111'
|
||||||
|
|
||||||
headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||||
user_id = 12345
|
user_id = 12345
|
||||||
request_url = '{}/guilds/{}/members/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id)
|
request_url = '{}/guilds/{}/members/{}/roles/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id, name_to_id.return_value)
|
||||||
|
|
||||||
djcache.get.return_value = None # No existing backoffs in cache
|
djcache.get.return_value = None # No existing backoffs in cache
|
||||||
|
|
||||||
m.patch(request_url,
|
m.put(request_url,
|
||||||
request_headers=headers,
|
request_headers=headers,
|
||||||
headers={'Retry-After': '200000'},
|
headers={'Retry-After': '200000'},
|
||||||
status_code=429)
|
status_code=429)
|
||||||
|
|
||||||
# Act & Assert
|
# Act & Assert
|
||||||
with self.assertRaises(manager.DiscordApiBackoff) as bo:
|
with self.assertRaises(manager.DiscordApiBackoff) as bo:
|
||||||
@ -391,23 +391,25 @@ class DiscordManagerTestCase(TestCase):
|
|||||||
self.assertTrue(datetime.datetime.strptime(args[1], manager.cache_time_format) > datetime.datetime.now())
|
self.assertTrue(datetime.datetime.strptime(args[1], manager.cache_time_format) > datetime.datetime.now())
|
||||||
|
|
||||||
@mock.patch(MODULE_PATH + '.manager.cache')
|
@mock.patch(MODULE_PATH + '.manager.cache')
|
||||||
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_groups')
|
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_user_roles')
|
||||||
|
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._group_name_to_id')
|
||||||
@requests_mock.Mocker()
|
@requests_mock.Mocker()
|
||||||
def test_update_groups_global_backoff(self, group_cache, djcache, m):
|
def test_update_groups_global_backoff(self, name_to_id, user_groups, djcache, m):
|
||||||
# Arrange
|
# Arrange
|
||||||
groups = ['Member']
|
groups = ['Member']
|
||||||
group_cache.return_value = [{'id': 111, 'name': 'Member'}]
|
user_groups.return_value = []
|
||||||
|
name_to_id.return_value = '111'
|
||||||
|
|
||||||
headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||||
user_id = 12345
|
user_id = 12345
|
||||||
request_url = '{}/guilds/{}/members/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id)
|
request_url = '{}/guilds/{}/members/{}/roles/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id, name_to_id.return_value)
|
||||||
|
|
||||||
djcache.get.return_value = None # No existing backoffs in cache
|
djcache.get.return_value = None # No existing backoffs in cache
|
||||||
|
|
||||||
m.patch(request_url,
|
m.put(request_url,
|
||||||
request_headers=headers,
|
request_headers=headers,
|
||||||
headers={'Retry-After': '200000', 'X-RateLimit-Global': 'true'},
|
headers={'Retry-After': '200000', 'X-RateLimit-Global': 'true'},
|
||||||
status_code=429)
|
status_code=429)
|
||||||
|
|
||||||
# Act & Assert
|
# Act & Assert
|
||||||
with self.assertRaises(manager.DiscordApiBackoff) as bo:
|
with self.assertRaises(manager.DiscordApiBackoff) as bo:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user