mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-09 20:40:17 +02:00
Merge branch 'master' of https://gitlab.com/allianceauth/allianceauth into v3.x
This commit is contained in:
commit
236c70316c
@ -5,7 +5,7 @@ from typing import List, Optional
|
|||||||
from pytz import utc
|
from pytz import utc
|
||||||
from redis import Redis, RedisError
|
from redis import Redis, RedisError
|
||||||
|
|
||||||
from django_redis import get_redis_connection
|
from allianceauth.utils.cache import get_redis_client
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ class EventSeries:
|
|||||||
_ROOT_KEY = "ALLIANCEAUTH_EVENT_SERIES"
|
_ROOT_KEY = "ALLIANCEAUTH_EVENT_SERIES"
|
||||||
|
|
||||||
def __init__(self, key_id: str, redis: Redis = None) -> None:
|
def __init__(self, key_id: str, redis: Redis = None) -> None:
|
||||||
self._redis = get_redis_connection("default") if not redis else redis
|
self._redis = get_redis_client() if not redis else redis
|
||||||
try:
|
try:
|
||||||
if not self._redis.ping():
|
if not self._redis.ping():
|
||||||
raise RuntimeError()
|
raise RuntimeError()
|
||||||
|
@ -18,7 +18,7 @@ MODULE_PATH = "allianceauth.authentication.task_statistics.event_series"
|
|||||||
class TestEventSeries(TestCase):
|
class TestEventSeries(TestCase):
|
||||||
def test_should_abort_without_redis_client(self):
|
def test_should_abort_without_redis_client(self):
|
||||||
# when
|
# when
|
||||||
with patch(MODULE_PATH + ".get_redis_connection") as mock:
|
with patch(MODULE_PATH + ".get_redis_client") as mock:
|
||||||
mock.return_value = None
|
mock.return_value = None
|
||||||
events = EventSeries("dummy")
|
events = EventSeries("dummy")
|
||||||
# then
|
# then
|
||||||
@ -27,8 +27,8 @@ class TestEventSeries(TestCase):
|
|||||||
|
|
||||||
def test_should_disable_itself_if_redis_not_available_1(self):
|
def test_should_disable_itself_if_redis_not_available_1(self):
|
||||||
# when
|
# when
|
||||||
with patch(MODULE_PATH + ".get_redis_connection") as mock_get_redis_connection:
|
with patch(MODULE_PATH + ".get_redis_client") as mock_get_master_client:
|
||||||
mock_get_redis_connection.return_value.ping.side_effect = RedisError
|
mock_get_master_client.return_value.ping.side_effect = RedisError
|
||||||
events = EventSeries("dummy")
|
events = EventSeries("dummy")
|
||||||
# then
|
# then
|
||||||
self.assertIsInstance(events._redis, _RedisStub)
|
self.assertIsInstance(events._redis, _RedisStub)
|
||||||
@ -36,8 +36,8 @@ class TestEventSeries(TestCase):
|
|||||||
|
|
||||||
def test_should_disable_itself_if_redis_not_available_2(self):
|
def test_should_disable_itself_if_redis_not_available_2(self):
|
||||||
# when
|
# when
|
||||||
with patch(MODULE_PATH + ".get_redis_connection") as mock_get_redis_connection:
|
with patch(MODULE_PATH + ".get_redis_client") as mock_get_master_client:
|
||||||
mock_get_redis_connection.return_value.ping.return_value = False
|
mock_get_master_client.return_value.ping.return_value = False
|
||||||
events = EventSeries("dummy")
|
events = EventSeries("dummy")
|
||||||
# then
|
# then
|
||||||
self.assertIsInstance(events._redis, _RedisStub)
|
self.assertIsInstance(events._redis, _RedisStub)
|
||||||
|
@ -8,7 +8,7 @@ from uuid import uuid1
|
|||||||
from redis import Redis
|
from redis import Redis
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from django_redis import get_redis_connection
|
from allianceauth.utils.cache import get_redis_client
|
||||||
|
|
||||||
from allianceauth import __title__ as AUTH_TITLE, __url__, __version__
|
from allianceauth import __title__ as AUTH_TITLE, __url__, __version__
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ class DiscordClient:
|
|||||||
self._access_token = str(access_token)
|
self._access_token = str(access_token)
|
||||||
self._is_rate_limited = bool(is_rate_limited)
|
self._is_rate_limited = bool(is_rate_limited)
|
||||||
if not redis:
|
if not redis:
|
||||||
self._redis = get_redis_connection("default")
|
self._redis = get_redis_client()
|
||||||
if not isinstance(self._redis, Redis):
|
if not isinstance(self._redis, Redis):
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
'This class requires a Redis client, but none was provided '
|
'This class requires a Redis client, but none was provided '
|
||||||
|
@ -85,25 +85,18 @@ class TestBasicsAndHelpers(TestCase):
|
|||||||
client = DiscordClient(TEST_BOT_TOKEN, mock_redis, is_rate_limited=True)
|
client = DiscordClient(TEST_BOT_TOKEN, mock_redis, is_rate_limited=True)
|
||||||
self.assertTrue(client.is_rate_limited)
|
self.assertTrue(client.is_rate_limited)
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.get_redis_connection')
|
def test_use_default_redis_if_none_provided(self):
|
||||||
def test_use_default_redis_if_none_provided(self, mock_caches):
|
|
||||||
my_redis = MagicMock(spec=Redis)
|
|
||||||
mock_caches.return_value = my_redis
|
|
||||||
|
|
||||||
client = DiscordClient(TEST_BOT_TOKEN)
|
client = DiscordClient(TEST_BOT_TOKEN)
|
||||||
self.assertTrue(mock_caches.called)
|
self.assertIsInstance(client._redis, Redis)
|
||||||
self.assertEqual(client._redis, my_redis)
|
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.get_redis_connection')
|
|
||||||
def test_raise_exception_if_default_cache_is_not_redis(self, mock_caches):
|
|
||||||
my_redis = MagicMock()
|
|
||||||
mock_caches.return_value = my_redis
|
|
||||||
|
|
||||||
|
@patch(MODULE_PATH + '.get_redis_client')
|
||||||
|
def test_raise_exception_if_redis_client_not_found(self, mock_get_redis_client):
|
||||||
|
# given
|
||||||
|
mock_get_redis_client.return_value = None
|
||||||
|
# when
|
||||||
with self.assertRaises(RuntimeError):
|
with self.assertRaises(RuntimeError):
|
||||||
DiscordClient(TEST_BOT_TOKEN)
|
DiscordClient(TEST_BOT_TOKEN)
|
||||||
|
|
||||||
self.assertTrue(mock_caches.called)
|
|
||||||
|
|
||||||
|
|
||||||
@requests_mock.Mocker()
|
@requests_mock.Mocker()
|
||||||
class TestOtherMethods(TestCase):
|
class TestOtherMethods(TestCase):
|
||||||
|
@ -35,17 +35,17 @@ import logging
|
|||||||
from uuid import uuid1
|
from uuid import uuid1
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from django.core.cache import caches
|
|
||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User, Group
|
||||||
|
|
||||||
from allianceauth.services.modules.discord.models import DiscordUser
|
from allianceauth.services.modules.discord.models import DiscordUser
|
||||||
|
from allianceauth.utils.cache import get_redis_client
|
||||||
|
|
||||||
logger = logging.getLogger('allianceauth')
|
logger = logging.getLogger('allianceauth')
|
||||||
MAX_RUNS = 3
|
MAX_RUNS = 3
|
||||||
|
|
||||||
|
|
||||||
def clear_cache():
|
def clear_cache():
|
||||||
default_cache = caches['default']
|
redis = get_redis_client()
|
||||||
redis = default_cache.get_master_client()
|
|
||||||
redis.flushall()
|
redis.flushall()
|
||||||
logger.info('Cache flushed')
|
logger.info('Cache flushed')
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ from requests.exceptions import HTTPError
|
|||||||
import requests_mock
|
import requests_mock
|
||||||
|
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group, User
|
||||||
from django_redis import get_redis_connection
|
|
||||||
from django.shortcuts import reverse
|
from django.shortcuts import reverse
|
||||||
from django.test import TransactionTestCase, TestCase
|
from django.test import TransactionTestCase, TestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
@ -23,6 +22,7 @@ from allianceauth.authentication.models import State
|
|||||||
from allianceauth.eveonline.models import EveCharacter
|
from allianceauth.eveonline.models import EveCharacter
|
||||||
from allianceauth.notifications.models import Notification
|
from allianceauth.notifications.models import Notification
|
||||||
from allianceauth.tests.auth_utils import AuthUtils
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
from allianceauth.utils.cache import get_redis_client
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
TEST_GUILD_ID,
|
TEST_GUILD_ID,
|
||||||
@ -87,7 +87,7 @@ remove_guild_member_request = DiscordRequest(
|
|||||||
|
|
||||||
|
|
||||||
def clear_cache():
|
def clear_cache():
|
||||||
redis = get_redis_connection('default')
|
redis = get_redis_client()
|
||||||
redis.flushall()
|
redis.flushall()
|
||||||
logger.info('Cache flushed')
|
logger.info('Cache flushed')
|
||||||
|
|
||||||
@ -108,7 +108,6 @@ def reset_testdata():
|
|||||||
class TestServiceFeatures(TransactionTestCase):
|
class TestServiceFeatures(TransactionTestCase):
|
||||||
fixtures = ['disable_analytics.json']
|
fixtures = ['disable_analytics.json']
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
super().setUpClass()
|
super().setUpClass()
|
||||||
|
0
allianceauth/utils/__init__.py
Normal file
0
allianceauth/utils/__init__.py
Normal file
21
allianceauth/utils/cache.py
Normal file
21
allianceauth/utils/cache.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
from redis import Redis
|
||||||
|
|
||||||
|
from django.core.cache import caches
|
||||||
|
|
||||||
|
try:
|
||||||
|
import django_redis
|
||||||
|
except ImportError:
|
||||||
|
django_redis = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_redis_client() -> Redis:
|
||||||
|
"""Get the configured redis client used by Django for caching.
|
||||||
|
|
||||||
|
This function is a wrapper designed to work for both AA2 and AA3
|
||||||
|
and should always be used to ensure backwards compatibility.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return django_redis.get_redis_connection("default")
|
||||||
|
except AttributeError:
|
||||||
|
default_cache = caches["default"]
|
||||||
|
return default_cache.get_master_client()
|
0
allianceauth/utils/tests/__init__.py
Normal file
0
allianceauth/utils/tests/__init__.py
Normal file
39
allianceauth/utils/tests/test_cache.py
Normal file
39
allianceauth/utils/tests/test_cache.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from allianceauth.utils.cache import get_redis_client
|
||||||
|
|
||||||
|
MODULE_PATH = "allianceauth.utils.cache"
|
||||||
|
|
||||||
|
|
||||||
|
class RedisClientStub:
|
||||||
|
"""Substitute for a Redis client."""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetRedisClient(TestCase):
|
||||||
|
def test_should_work_with_aa2_api(self):
|
||||||
|
# given
|
||||||
|
mock_django_cache = MagicMock()
|
||||||
|
mock_django_cache.get_master_client.return_value = RedisClientStub()
|
||||||
|
# when
|
||||||
|
with patch(MODULE_PATH + ".django_redis", None), patch.dict(
|
||||||
|
MODULE_PATH + ".caches", {"default": mock_django_cache}
|
||||||
|
):
|
||||||
|
client = get_redis_client()
|
||||||
|
# then
|
||||||
|
self.assertIsInstance(client, RedisClientStub)
|
||||||
|
|
||||||
|
def test_should_work_with_aa3_api(self):
|
||||||
|
# given
|
||||||
|
mock_django_redis = MagicMock()
|
||||||
|
mock_django_redis.get_redis_connection.return_value = RedisClientStub()
|
||||||
|
# when
|
||||||
|
with patch(MODULE_PATH + ".django_redis", mock_django_redis), patch.dict(
|
||||||
|
MODULE_PATH + ".caches", {"default": None}
|
||||||
|
):
|
||||||
|
client = get_redis_client()
|
||||||
|
# then
|
||||||
|
self.assertIsInstance(client, RedisClientStub)
|
@ -44,6 +44,8 @@ extensions = [
|
|||||||
'sphinx.ext.autodoc',
|
'sphinx.ext.autodoc',
|
||||||
'sphinx.ext.napoleon',
|
'sphinx.ext.napoleon',
|
||||||
'recommonmark',
|
'recommonmark',
|
||||||
|
'sphinxcontrib_django2',
|
||||||
|
'sphinx.ext.viewcode',
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
@ -4,36 +4,4 @@ django-esi
|
|||||||
|
|
||||||
The django-esi package provides an interface for easy access to the ESI.
|
The django-esi package provides an interface for easy access to the ESI.
|
||||||
|
|
||||||
Location: ``esi``
|
This is an external package. Please see `here <https://django-esi.readthedocs.io/en/latest/>`_ for it's documentation.
|
||||||
|
|
||||||
This is an external package. Please also see `here <https://gitlab.com/allianceauth/django-esi>`_ for it's official documentation.
|
|
||||||
|
|
||||||
clients
|
|
||||||
===========
|
|
||||||
|
|
||||||
.. automodule:: esi.clients
|
|
||||||
:members: esi_client_factory
|
|
||||||
:undoc-members:
|
|
||||||
|
|
||||||
decorators
|
|
||||||
===========
|
|
||||||
|
|
||||||
.. automodule:: esi.decorators
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
|
|
||||||
errors
|
|
||||||
===========
|
|
||||||
|
|
||||||
.. automodule:: esi.errors
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
|
|
||||||
|
|
||||||
models
|
|
||||||
===========
|
|
||||||
|
|
||||||
.. automodule:: esi.models
|
|
||||||
:members: Scope, Token
|
|
||||||
:exclude-members: objects, provider
|
|
||||||
:undoc-members:
|
|
||||||
|
@ -11,5 +11,4 @@ models
|
|||||||
|
|
||||||
.. automodule:: allianceauth.eveonline.models
|
.. automodule:: allianceauth.eveonline.models
|
||||||
:members:
|
:members:
|
||||||
:exclude-members: objects, provider
|
:exclude-members: DoesNotExist, MultipleObjectsReturned
|
||||||
:undoc-members:
|
|
||||||
|
@ -11,4 +11,5 @@ To reduce redundancy and help speed up development we encourage developers to ut
|
|||||||
eveonline
|
eveonline
|
||||||
notifications
|
notifications
|
||||||
testutils
|
testutils
|
||||||
|
utils
|
||||||
```
|
```
|
||||||
|
@ -13,7 +13,8 @@ models
|
|||||||
===========
|
===========
|
||||||
|
|
||||||
.. autoclass:: allianceauth.notifications.models.Notification
|
.. autoclass:: allianceauth.notifications.models.Notification
|
||||||
:members: Level, mark_viewed, set_level
|
:members:
|
||||||
|
:exclude-members: DoesNotExist, MultipleObjectsReturned, save
|
||||||
|
|
||||||
managers
|
managers
|
||||||
===========
|
===========
|
||||||
|
14
docs/development/tech_docu/api/utils.rst
Normal file
14
docs/development/tech_docu/api/utils.rst
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
=============================
|
||||||
|
utils
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Utilities and helper functions.
|
||||||
|
|
||||||
|
Location: ``allianceauth.utils``
|
||||||
|
|
||||||
|
cache
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. automodule:: allianceauth.utils.cache
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
@ -4,6 +4,7 @@ sphinx_rtd_theme>=1.0.0,<2.0.0
|
|||||||
recommonmark==0.7.1
|
recommonmark==0.7.1
|
||||||
Jinja2<3.1
|
Jinja2<3.1
|
||||||
docutils==0.16
|
docutils==0.16
|
||||||
|
sphinxcontrib-django2
|
||||||
|
|
||||||
# Autodoc dependencies
|
# Autodoc dependencies
|
||||||
celery>=5.2.0,<6.0.0
|
celery>=5.2.0,<6.0.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user