This commit is contained in:
Ariel Rin 2021-12-28 21:58:38 +10:00
commit ff610efc84
20 changed files with 255 additions and 106 deletions

View File

@ -76,6 +76,27 @@ test-3.10-core:
reports: reports:
cobertura: coverage.xml cobertura: coverage.xml
test-3.11-core:
<<: *only-default
image: python:3.11-rc-bullseye
script:
- tox -e py311-core
artifacts:
when: always
reports:
cobertura: coverage.xml
allow_failure: true
test-3.7-all:
<<: *only-default
image: python:3.7-bullseye
script:
- tox -e py37-all
artifacts:
when: always
reports:
cobertura: coverage.xml
test-3.8-all: test-3.8-all:
<<: *only-default <<: *only-default
image: python:3.8-bullseye image: python:3.8-bullseye
@ -106,6 +127,17 @@ test-3.10-all:
reports: reports:
cobertura: coverage.xml cobertura: coverage.xml
test-3.11-all:
<<: *only-default
image: python:3.11-rc-bullseye
script:
- tox -e py311-all
artifacts:
when: always
reports:
cobertura: coverage.xml
allow_failure: true
deploy_production: deploy_production:
stage: deploy stage: deploy
image: python:3.10-bullseye image: python:3.10-bullseye

View File

@ -13,17 +13,18 @@ from allianceauth import __version__
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname( SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(
os.path.abspath(__file__)), 'swagger.json' os.path.abspath(__file__)), 'swagger.json'
) )
"""
Swagger spec operations:
get_alliances_alliance_id # for the love of Bob please add operations you use here. I'm tired of breaking undocumented things.
get_alliances_alliance_id_corporations ESI_OPERATIONS=[
get_corporations_corporation_id 'get_alliances_alliance_id',
get_characters_character_id 'get_alliances_alliance_id_corporations',
get_universe_types_type_id 'get_corporations_corporation_id',
post_character_affiliation 'get_characters_character_id',
get_universe_factions 'post_characters_affiliation',
""" 'get_universe_types_type_id',
'get_universe_factions',
'post_universe_names',
]
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

File diff suppressed because one or more lines are too long

View File

@ -49,7 +49,6 @@ def run_model_update():
for alliance in EveAllianceInfo.objects.all().values('alliance_id'): for alliance in EveAllianceInfo.objects.all().values('alliance_id'):
update_alliance.apply_async(args=[alliance['alliance_id']], priority=TASK_PRIORITY) update_alliance.apply_async(args=[alliance['alliance_id']], priority=TASK_PRIORITY)
#update existing character models if required
# update existing character models # update existing character models
character_ids = EveCharacter.objects.all().values_list('character_id', flat=True) character_ids = EveCharacter.objects.all().values_list('character_id', flat=True)
for character_ids_chunk in chunks(character_ids, CHUNK_SIZE): for character_ids_chunk in chunks(character_ids, CHUNK_SIZE):

View File

@ -29,6 +29,8 @@
{% endif %} {% endif %}
</a> </a>
</li> </li>
{% if not auto_leave %}
<li> <li>
<a data-toggle="tab" href="#leave"> <a data-toggle="tab" href="#leave">
{% translate "Leave Requests" %} {% translate "Leave Requests" %}
@ -38,6 +40,7 @@
{% endif %} {% endif %}
</a> </a>
</li> </li>
{% endif %}
</ul> </ul>
<div class="panel panel-default panel-tabs-aa"> <div class="panel panel-default panel-tabs-aa">
@ -100,6 +103,7 @@
{% endif %} {% endif %}
</div> </div>
{% if not auto_leave %}
<div id="leave" class="tab-pane"> <div id="leave" class="tab-pane">
{% if leaverequests %} {% if leaverequests %}
<div class="table-responsive"> <div class="table-responsive">
@ -155,6 +159,7 @@
<div class="alert alert-warning text-center">{% translate "No group leave requests." %}</div> <div class="alert alert-warning text-center">{% translate "No group leave requests." %}</div>
{% endif %} {% endif %}
</div> </div>
{% endif %}
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,4 +1,4 @@
from django.test import RequestFactory, TestCase from django.test import RequestFactory, TestCase, override_settings
from django.urls import reverse from django.urls import reverse
from allianceauth.tests.auth_utils import AuthUtils from allianceauth.tests.auth_utils import AuthUtils
@ -6,14 +6,80 @@ from allianceauth.tests.auth_utils import AuthUtils
from .. import views from .. import views
def response_content_to_str(response) -> str:
return response.content.decode(response.charset)
class TestViews(TestCase): class TestViews(TestCase):
def setUp(self): def setUp(self):
self.factory = RequestFactory() self.factory = RequestFactory()
self.user = AuthUtils.create_user('Bruce Wayne') self.user = AuthUtils.create_user('Peter Parker')
self.user_with_manage_permission = AuthUtils.create_user('Bruce Wayne')
# set permissions
AuthUtils.add_permission_to_user_by_name(
'auth.group_management', self.user_with_manage_permission
)
def test_groups_view_can_load(self): def test_groups_view_can_load(self):
request = self.factory.get(reverse('groupmanagement:groups')) request = self.factory.get(reverse('groupmanagement:groups'))
request.user = self.user request.user = self.user
response = views.groups_view(request) response = views.groups_view(request)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_management_view_can_load_for_user_with_permissions(self):
"""
Test if user with management permissions can access the management view
:return:
"""
request = self.factory.get(reverse('groupmanagement:management'))
request.user = self.user_with_manage_permission
response = views.group_management(request)
self.assertEqual(response.status_code, 200)
def test_management_view_doesnt_load_for_user_without_permissions(self):
"""
Test if user without management permissions can't access the management view
:return:
"""
request = self.factory.get(reverse('groupmanagement:management'))
request.user = self.user
response = views.group_management(request)
self.assertEqual(response.status_code, 302)
@override_settings(GROUPMANAGEMENT_AUTO_LEAVE=False)
def test_leave_requests_tab_visible(self):
"""
Test if the leave requests tab is visible when GROUPMANAGEMENT_AUTO_LEAVE = False
:return:
"""
request = self.factory.get(reverse('groupmanagement:management'))
request.user = self.user_with_manage_permission
response = views.group_management(request)
content = response_content_to_str(response)
self.assertEqual(response.status_code, 200)
self.assertIn('<a data-toggle="tab" href="#leave">', content)
self.assertIn('<div id="leave" class="tab-pane">', content)
@override_settings(GROUPMANAGEMENT_AUTO_LEAVE=True)
def test_leave_requests_tab_hidden(self):
"""
Test if the leave requests tab is hidden when GROUPMANAGEMENT_AUTO_LEAVE = True
:return:
"""
request = self.factory.get(reverse('groupmanagement:management'))
request.user = self.user_with_manage_permission
response = views.group_management(request)
content = response_content_to_str(response)
self.assertEqual(response.status_code, 200)
self.assertNotIn('<a data-toggle="tab" href="#leave">', content)
self.assertNotIn('<div id="leave" class="tab-pane">', content)

View File

@ -45,7 +45,11 @@ def group_management(request):
logger.debug("Providing user {} with {} acceptrequests and {} leaverequests.".format( logger.debug("Providing user {} with {} acceptrequests and {} leaverequests.".format(
request.user, len(acceptrequests), len(leaverequests))) request.user, len(acceptrequests), len(leaverequests)))
render_items = {'acceptrequests': acceptrequests, 'leaverequests': leaverequests} render_items = {
'acceptrequests': acceptrequests,
'leaverequests': leaverequests,
'auto_leave': getattr(settings, 'GROUPMANAGEMENT_AUTO_LEAVE', False),
}
return render(request, 'groupmanagement/index.html', context=render_items) return render(request, 'groupmanagement/index.html', context=render_items)

View File

@ -49,19 +49,22 @@ class NotificationManager(models.Manager):
logger.info("Created notification %s", obj) logger.info("Created notification %s", obj)
return obj return obj
def _max_notifications_per_user(self): def _max_notifications_per_user(self) -> int:
"""return the maximum number of notifications allowed per user""" """Maximum number of notifications allowed per user."""
max_notifications = getattr(settings, 'NOTIFICATIONS_MAX_PER_USER', None) max_notifications = getattr(
if ( settings,
max_notifications is None "NOTIFICATIONS_MAX_PER_USER",
or not isinstance(max_notifications, int) self.model.NOTIFICATIONS_MAX_PER_USER_DEFAULT
or max_notifications < 0 )
): try:
max_notifications = int(max_notifications)
except ValueError:
max_notifications = None
if max_notifications is None or max_notifications < 0:
logger.warning( logger.warning(
'NOTIFICATIONS_MAX_PER_USER setting is invalid. Using default.' "NOTIFICATIONS_MAX_PER_USER setting is invalid. Using default."
) )
max_notifications = self.model.NOTIFICATIONS_MAX_PER_USER_DEFAULT max_notifications = self.model.NOTIFICATIONS_MAX_PER_USER_DEFAULT
return max_notifications return max_notifications
def user_unread_count(self, user_pk: int) -> int: def user_unread_count(self, user_pk: int) -> int:

View File

@ -1,5 +1,6 @@
from unittest.mock import patch from unittest.mock import patch
from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
@ -113,29 +114,53 @@ class TestUserNotify(TestCase):
self.assertSetEqual(result, expected) self.assertSetEqual(result, expected)
@patch("allianceauth.notifications.managers.logger")
@patch( @patch(
MODULE_PATH + '.Notification.NOTIFICATIONS_MAX_PER_USER_DEFAULT', MODULE_PATH + ".Notification.NOTIFICATIONS_MAX_PER_USER_DEFAULT",
NOTIFICATIONS_MAX_PER_USER_DEFAULT NOTIFICATIONS_MAX_PER_USER_DEFAULT
) )
class TestMaxNotificationsPerUser(TestCase): class TestMaxNotificationsPerUser(TestCase):
@override_settings(NOTIFICATIONS_MAX_PER_USER=42)
@override_settings(NOTIFICATIONS_MAX_PER_USER=None) def test_should_use_custom_integer_setting(self, mock_logger):
def test_reset_to_default_if_not_defined(self): # when
result = Notification.objects._max_notifications_per_user() result = Notification.objects._max_notifications_per_user()
expected = NOTIFICATIONS_MAX_PER_USER_DEFAULT # then
self.assertEqual(result, expected) self.assertEqual(result, 42)
self.assertFalse(mock_logger.warning.called)
@override_settings(NOTIFICATIONS_MAX_PER_USER='11') @override_settings(NOTIFICATIONS_MAX_PER_USER="42")
def test_reset_to_default_if_not_int(self): def test_should_use_custom_string_setting(self, mock_logger):
# when
result = Notification.objects._max_notifications_per_user() result = Notification.objects._max_notifications_per_user()
expected = NOTIFICATIONS_MAX_PER_USER_DEFAULT # then
self.assertEqual(result, expected) self.assertEqual(result, 42)
self.assertFalse(mock_logger.warning.called)
@override_settings()
def test_should_use_default_if_not_defined(self, mock_logger):
# given
del settings.NOTIFICATIONS_MAX_PER_USER
# when
result = Notification.objects._max_notifications_per_user()
# then
self.assertEqual(result, NOTIFICATIONS_MAX_PER_USER_DEFAULT)
self.assertFalse(mock_logger.warning.called)
@override_settings(NOTIFICATIONS_MAX_PER_USER="abc")
def test_should_reset_to_default_if_not_int(self, mock_logger):
# when
result = Notification.objects._max_notifications_per_user()
# then
self.assertEqual(result, NOTIFICATIONS_MAX_PER_USER_DEFAULT)
self.assertTrue(mock_logger.warning.called)
@override_settings(NOTIFICATIONS_MAX_PER_USER=-1) @override_settings(NOTIFICATIONS_MAX_PER_USER=-1)
def test_reset_to_default_if_lt_zero(self): def test_should_reset_to_default_if_lt_zero(self, mock_logger):
# when
result = Notification.objects._max_notifications_per_user() result = Notification.objects._max_notifications_per_user()
expected = NOTIFICATIONS_MAX_PER_USER_DEFAULT # then
self.assertEqual(result, expected) self.assertEqual(result, NOTIFICATIONS_MAX_PER_USER_DEFAULT)
self.assertTrue(mock_logger.warning.called)
@patch('allianceauth.notifications.managers.cache') @patch('allianceauth.notifications.managers.cache')

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,5 @@
<!-- Start jQuery UI CSS from cdnjs --> {% load static %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" integrity="sha512-aOG0c6nPNzGk+5zjwyJaoRUgCdOrfSDhmMID2u4+OIslr0GjpLKo7Xm0Ao3xmpM4T8AmIouRkqwj1nrdVsLKEQ==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <!-- Start jQuery UI CSS from Alliance Auth -->
<!-- End jQuery UI CSS from cdnjs --> <!-- CDNs all contain theme.css, which is not supposed to be in the base CSS, Which is why this is uniquely bundled in not using a CDN -->
<link rel="stylesheet" href="{% static 'js/jquery-ui/1.12.1/css/jquery-ui.min.css' %}" integrity="sha512-7smZe1765O+Mm1UZH46SzaFClbRX7dEs01lB9lqU91oocmugWWfQXVQNVr5tEwktYSqwJMErEfr4GvflXMgTPA==" crossorigin="anonymous" referrerpolicy="no-referrer"/>
<!-- End jQuery UI CSS from aa-gdpr -->

View File

@ -52,7 +52,7 @@ services:
- auth_mysql - auth_mysql
grafana: grafana:
image: grafana/grafana:8.2 image: grafana/grafana-oss:8.2
restart: always restart: always
depends_on: depends_on:
- auth_mysql - auth_mysql

View File

@ -90,11 +90,16 @@ This allows you to more finely control who has access to manage which groups.
### Auto Leave ### Auto Leave
By default in AA, Both requests and leaves for non-open groups must be approved by a group manager. If you wish to allow users to leave groups without requiring approvals, add the following lines to your `local.py` By default, in AA both requests and leaves for non-open groups must be approved by a group manager. If you wish to allow users to leave groups without requiring approvals, add the following lines to your `local.py`
```python ```python
## Allows users to freely leave groups without requiring approval. ## Allows users to freely leave groups without requiring approval.
AUTO_LEAVE = True GROUPMANAGEMENT_AUTO_LEAVE = True
```
```eval_rst
.. note::
Before you set `GROUPMANAGEMENT_AUTO_LEAVE = True`, make sure there are no pending leave requests, as this option will hide the "Leave Requests" tab.
``` ```
## Settings ## Settings

View File

@ -1,7 +1,7 @@
[tox] [tox]
skipsdist = true skipsdist = true
usedevelop = true usedevelop = true
envlist = py{38,39,310}-{all,core} envlist = py{38,39,310,311}-{all,core}
[testenv] [testenv]
setenv = setenv =
@ -12,6 +12,7 @@ basepython =
py38: python3.8 py38: python3.8
py39: python3.9 py39: python3.9
py310: python3.10 py310: python3.10
py311: python3.11
deps= deps=
coverage coverage
install_command = pip install -e ".[testing]" -U {opts} {packages} install_command = pip install -e ".[testing]" -U {opts} {packages}