From 1420c71ec50095f0222a05673add6dfd74a1dfe1 Mon Sep 17 00:00:00 2001 From: ErikKalkoken Date: Sat, 15 May 2021 13:58:23 +0200 Subject: [PATCH 1/7] Improve get_character_by_id() --- allianceauth/eveonline/managers.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/allianceauth/eveonline/managers.py b/allianceauth/eveonline/managers.py index ea574189..19337886 100644 --- a/allianceauth/eveonline/managers.py +++ b/allianceauth/eveonline/managers.py @@ -32,10 +32,12 @@ class EveCharacterManager(models.Manager): def update_character(self, character_id): return self.get(character_id=character_id).update_character() - def get_character_by_id(self, char_id): - if self.filter(character_id=char_id).exists(): - return self.get(character_id=char_id) - return None + def get_character_by_id(self, character_id: int): + """Return character by character ID or None if not found.""" + try: + return self.get(character_id=character_id) + except self.model.DoesNotExist: + return None class EveAllianceProviderManager: From 26236f5886c9e4bbc21729484f81bb937a380607 Mon Sep 17 00:00:00 2001 From: Peter Pfeufer Date: Sat, 15 May 2021 15:27:50 +0200 Subject: [PATCH 2/7] Added a quick hint that it's ok to leave the SQL shell, and some commas --- docs/installation/allianceauth.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/installation/allianceauth.md b/docs/installation/allianceauth.md index 4e2b084a..678f8091 100644 --- a/docs/installation/allianceauth.md +++ b/docs/installation/allianceauth.md @@ -104,6 +104,8 @@ CREATE DATABASE alliance_auth CHARACTER SET utf8mb4; GRANT ALL PRIVILEGES ON alliance_auth . * TO 'allianceserver'@'localhost'; ``` +Once your database is set up, you can leave the SQL shell with `exit`. + Add timezone tables to your mysql installation: ```bash @@ -177,7 +179,7 @@ source /home/allianceserver/venv/auth/bin/activate You need to have a dedicated Eve SSO app for Alliance auth. Please go to [EVE Developer](https://developers.eveonline.com/applications) to create one. -For **scopes** your SSO app needs to have at least `publicData`. Additional scopes depends on which Alliance Auth apps you will be using. For convenience we recommend adding all available ESO scopes to your SSO app. Note that Alliance Auth will always ask the users to approve specific scopes before they are used. +For **scopes** your SSO app needs to have at least `publicData`. Additional scopes depends on which Alliance Auth apps you will be using. For convenience, we recommend adding all available ESO scopes to your SSO app. Note that Alliance Auth will always ask the users to approve specific scopes before they are used. As **callback URL** you want to define the URL of your Alliance Auth site plus the route: `/sso/callback`. Example for a valid callback URL: `https://auth.example.com/sso/callback` @@ -236,7 +238,7 @@ Check to ensure your settings are valid. python /home/allianceserver/myauth/manage.py check ``` -And finally ensure the allianceserver user has read/write permissions to this directory before proceeding. +Finally, ensure the allianceserver user has read/write permissions to this directory before proceeding. ```bash chown -R allianceserver:allianceserver /home/allianceserver/myauth @@ -244,7 +246,7 @@ chown -R allianceserver:allianceserver /home/allianceserver/myauth ## Services -Alliance Auth needs some additional services to run, which we will setup and configure next. +Alliance Auth needs some additional services to run, which we will set up and configure next. ### Gunicorn @@ -275,7 +277,7 @@ systemctl enable supervisord.service systemctl start supervisord.service ``` -Once installed it needs a configuration file to know which processes to watch. Your Alliance Auth project comes with a ready-to-use template which will ensure the Celery workers, Celery task scheduler and Gunicorn are all running. +Once installed, it needs a configuration file to know which processes to watch. Your Alliance Auth project comes with a ready-to-use template which will ensure the Celery workers, Celery task scheduler and Gunicorn are all running. Ubuntu: @@ -289,7 +291,7 @@ CentOS: ln -s /home/allianceserver/myauth/supervisor.conf /etc/supervisord.d/myauth.ini ``` -And activate it with `supervisorctl reload`. +Activate it with `supervisorctl reload`. You can check the status of the processes with `supervisorctl status`. Logs from these processes are available in `/home/allianceserver/myauth/log` named by process. @@ -304,11 +306,11 @@ You can check the status of the processes with `supervisorctl status`. Logs from Once installed, decide on whether you're going to use [NGINX](nginx.md) or [Apache](apache.md) and follow the respective guide. -Note that Alliance Auth is designed to run with web servers on HTTPS. While running on HTTP is technically possible, it is not recommended for production use and some functions (e.g. Email confirmation links) will not work properly. +Note that Alliance Auth is designed to run with web servers on HTTPS. While running on HTTP is technically possible, it is not recommended for production use, and some functions (e.g. Email confirmation links) will not work properly. ## Superuser -Before using your auth site it is essential to create a superuser account. This account will have all permissions in Alliance Auth. It's OK to use this as your personal auth account. +Before using your auth site, it is essential to create a superuser account. This account will have all permissions in Alliance Auth. It's OK to use this as your personal auth account. ```bash python /home/allianceserver/myauth/manage.py createsuperuser @@ -316,7 +318,7 @@ python /home/allianceserver/myauth/manage.py createsuperuser The superuser account is accessed by logging in via the admin site at `https://example.com/admin`. -If you intend to use this account as your personal auth account you need to add a main character. Navigate to the normal user dashboard (at `https://example.com`) after logging in via the admin site and select `Change Main`. Once a main character has been added it is possible to use SSO to login to this account. +If you intend to use this account as your personal auth account you need to add a main character. Navigate to the normal user dashboard (at `https://example.com`) after logging in via the admin site and select `Change Main`. Once a main character has been added, it is possible to use SSO to login to this account. ## Updating @@ -340,7 +342,7 @@ Some releases come with new or changed models. Update your database to reflect t python /home/allianceserver/myauth/manage.py migrate ``` -Finally some releases come with new or changed static files. Run the following command to update your static files folder: +Finally, some releases come with new or changed static files. Run the following command to update your static files folder: ```bash python /home/allianceserver/myauth/manage.py collectstatic From 3df664351369f8d299edfdd4f51da7856f2fefd4 Mon Sep 17 00:00:00 2001 From: Peter Pfeufer Date: Mon, 17 May 2021 17:41:28 +0200 Subject: [PATCH 3/7] this is a shell command ... --- docs/maintenance/apps.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/maintenance/apps.md b/docs/maintenance/apps.md index fd2250ad..9707777a 100644 --- a/docs/maintenance/apps.md +++ b/docs/maintenance/apps.md @@ -17,8 +17,8 @@ Mature Alliance Auth installations, or those with actively developed extensions This can make it confusing for admins to apply the right permissions, contribute to larger queries in backend management or simply look unsightly. -```python - python manage.py remove_stale_contenttypes --include-stale-apps +```shell +python manage.py remove_stale_contenttypes --include-stale-apps ``` This inbuilt Django command will step through each contenttype and offer to delete it, displaying what exactly this will cascade to delete. Pay attention and ensure you understand exactly what is being removed before answering `yes`. From e4b515c1d5032e0b1a68de6eca60eb357d63aefe Mon Sep 17 00:00:00 2001 From: Erik Kalkoken Date: Tue, 1 Jun 2021 11:38:24 +0000 Subject: [PATCH 4/7] Add button to update TS3 groups to admin page --- .../services/modules/teamspeak3/admin.py | 3 ++- .../admin/teamspeak3/authts/change_list.html | 11 +++++++++++ .../services/modules/teamspeak3/tests.py | 18 ++++++++++++++++++ .../services/modules/teamspeak3/urls.py | 14 ++++++++------ .../services/modules/teamspeak3/views.py | 9 +++++++++ docs/features/services/teamspeak3.md | 18 +++++++++++++++--- 6 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 allianceauth/services/modules/teamspeak3/templates/admin/teamspeak3/authts/change_list.html diff --git a/allianceauth/services/modules/teamspeak3/admin.py b/allianceauth/services/modules/teamspeak3/admin.py index 9b562ecc..942498f3 100644 --- a/allianceauth/services/modules/teamspeak3/admin.py +++ b/allianceauth/services/modules/teamspeak3/admin.py @@ -15,6 +15,7 @@ class Teamspeak3UserAdmin(ServicesUserAdmin): @admin.register(AuthTS) class AuthTSgroupAdmin(admin.ModelAdmin): + change_list_template = 'admin/teamspeak3/authts/change_list.html' ordering = ('auth_group__name', ) list_select_related = True @@ -28,7 +29,7 @@ class AuthTSgroupAdmin(admin.ModelAdmin): 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' + # _ts_group.admin_order_field = 'profile__state' @admin.register(StateGroup) diff --git a/allianceauth/services/modules/teamspeak3/templates/admin/teamspeak3/authts/change_list.html b/allianceauth/services/modules/teamspeak3/templates/admin/teamspeak3/authts/change_list.html new file mode 100644 index 00000000..5911ba5b --- /dev/null +++ b/allianceauth/services/modules/teamspeak3/templates/admin/teamspeak3/authts/change_list.html @@ -0,0 +1,11 @@ +{% extends "admin/change_list.html" %} +{% load i18n static %} + +{% block object-tools-items %} +{{ block.super }} +
  • + + Update TS3 groups + +
  • +{% endblock %} \ No newline at end of file diff --git a/allianceauth/services/modules/teamspeak3/tests.py b/allianceauth/services/modules/teamspeak3/tests.py index 44654ec9..9584a34a 100644 --- a/allianceauth/services/modules/teamspeak3/tests.py +++ b/allianceauth/services/modules/teamspeak3/tests.py @@ -216,6 +216,24 @@ class Teamspeak3ViewsTestCase(TestCase): self.assertEqual(ts3_user.perm_key, '123abc') self.assertTrue(tasks_manager.return_value.__enter__.return_value.update_groups.called) + @mock.patch(MODULE_PATH + '.views.Teamspeak3Tasks') + @mock.patch(MODULE_PATH + '.views.messages') + def test_should_update_ts_groups(self, messages, Teamspeak3Tasks): + # given + self.member.is_superuser = True + self.member.is_staff = True + self.member.save() + self.login() + # when + response = self.client.get(urls.reverse('teamspeak3:admin_update_ts3_groups')) + # then + self.assertRedirects( + response, urls.reverse('admin:teamspeak3_authts_changelist'), + target_status_code=200 + ) + self.assertTrue(messages.info.called) + self.assertTrue(Teamspeak3Tasks.run_ts3_group_update.delay.called) + class Teamspeak3SignalsTestCase(TestCase): def setUp(self): diff --git a/allianceauth/services/modules/teamspeak3/urls.py b/allianceauth/services/modules/teamspeak3/urls.py index 4cc91c6c..1f4282ff 100644 --- a/allianceauth/services/modules/teamspeak3/urls.py +++ b/allianceauth/services/modules/teamspeak3/urls.py @@ -6,12 +6,14 @@ app_name = 'teamspeak3' module_urls = [ # Teamspeak3 service control - url(r'^activate/$', views.activate_teamspeak3, - name='activate'), - url(r'^deactivate/$', views.deactivate_teamspeak3, - name='deactivate'), - url(r'^reset_perm/$', views.reset_teamspeak3_perm, - name='reset_perm'), + url(r'^activate/$', views.activate_teamspeak3, name='activate'), + url(r'^deactivate/$', views.deactivate_teamspeak3, name='deactivate'), + url(r'^reset_perm/$', views.reset_teamspeak3_perm, name='reset_perm'), + url( + r'^admin_update_ts3_groups/$', + views.admin_update_ts3_groups, + name='admin_update_ts3_groups' + ), # Teamspeak Urls url(r'^verify/$', views.verify_teamspeak3, name='verify'), diff --git a/allianceauth/services/modules/teamspeak3/views.py b/allianceauth/services/modules/teamspeak3/views.py index f72ed3e0..5a1226d0 100644 --- a/allianceauth/services/modules/teamspeak3/views.py +++ b/allianceauth/services/modules/teamspeak3/views.py @@ -1,6 +1,7 @@ import logging from django.contrib import messages +from django.contrib.admin.views.decorators import staff_member_required from django.contrib.auth.decorators import login_required, permission_required from django.shortcuts import render, redirect from django.conf import settings @@ -99,3 +100,11 @@ def reset_teamspeak3_perm(request): logger.error("Unsuccessful attempt to reset TS3 permission key for user %s" % request.user) messages.error(request, _('An error occurred while processing your TeamSpeak3 account.')) return redirect("services:services") + + +@login_required +@staff_member_required +def admin_update_ts3_groups(request): + Teamspeak3Tasks.run_ts3_group_update.delay() + messages.info(request, "Started updating TS3 server groups...") + return redirect("admin:teamspeak3_authts_changelist") diff --git a/docs/features/services/teamspeak3.md b/docs/features/services/teamspeak3.md index ef4880f4..80c7dad3 100644 --- a/docs/features/services/teamspeak3.md +++ b/docs/features/services/teamspeak3.md @@ -105,7 +105,9 @@ Click the URL provided to automatically connect to our server. It will prompt yo Now we need to make groups. AllianceAuth handles groups in teamspeak differently: instead of creating groups it creates an association between groups in TeamSpeak and groups in AllianceAuth. Go ahead and make the groups you want to associate with auth groups, keeping in mind multiple TeamSpeak groups can be associated with a single auth group. -Navigate back to the AllianceAuth admin interface (example.com/admin) and under `Services`, select `Auth / TS Groups`. In the top-right corner click `Add`. +Navigate back to the AllianceAuth admin interface (example.com/admin) and under `Teamspeak3`, select `Auth / TS Groups`. + +In the top-right corner click, first click on `Update TS3 Groups` to fetch the newly created server groups from TS3 (this may take a minute to complete). Then click on `Add Auth / TS Group` to link Auth groups with TS3 server groups. The dropdown box provides all auth groups. Select one and assign TeamSpeak groups from the panels below. If these panels are empty, wait a minute for the database update to run, or see the [troubleshooting section](#ts-group-models-not-populating-on-admin-site) below. @@ -119,13 +121,23 @@ To enable advanced permissions, on your client go to the `Tools` menu, `Applicat ### TS group models not populating on admin site -The method which populates these runs every 30 minutes. To populate manually, start a django shell: +The method which populates these runs every 30 minutes. To populate manually you start the process from the admin site or from the Django shell. + +#### Admin Site + +Navigate to the AllianceAuth admin interface and under `Teamspeak3`, select `Auth / TS Groups`. + +Then, in the top-right corner click, click on `Update TS3 Groups` to start the process of fetching the server groups from TS3 (this may take a minute to complete). + +#### Django Shell + +Start a django shell with: ```bash python manage.py shell ``` -And execute the update: +And execute the update as follows: ```python from allianceauth.services.modules.teamspeak3.tasks import Teamspeak3Tasks From 0c14e35d15e353017de20026ddd5da9428786a86 Mon Sep 17 00:00:00 2001 From: Erik Kalkoken Date: Tue, 1 Jun 2021 11:40:32 +0000 Subject: [PATCH 5/7] Admin performance tuning for group and state --- allianceauth/authentication/admin.py | 8 +++++--- allianceauth/groupmanagement/admin.py | 11 ++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/allianceauth/authentication/admin.py b/allianceauth/authentication/admin.py index 5191981c..6b45ec80 100644 --- a/allianceauth/authentication/admin.py +++ b/allianceauth/authentication/admin.py @@ -399,7 +399,7 @@ class UserAdmin(BaseUserAdmin): def formfield_for_manytomany(self, db_field, request, **kwargs): """overriding this formfield to have sorted lists in the form""" if db_field.name == "groups": - kwargs["queryset"] = Group.objects.all().order_by(Lower('name')) + kwargs["queryset"] = Group.objects.all().order_by(Lower('name')) return super().formfield_for_manytomany(db_field, request, **kwargs) @@ -438,7 +438,7 @@ class StateAdmin(admin.ModelAdmin): ] def formfield_for_manytomany(self, db_field, request, **kwargs): - """overriding this formfield to have sorted lists in the form""" + """overriding this formfield to have sorted lists in the form""" if db_field.name == "member_characters": kwargs["queryset"] = EveCharacter.objects.all()\ .order_by(Lower('character_name')) @@ -448,8 +448,10 @@ class StateAdmin(admin.ModelAdmin): elif db_field.name == "member_alliances": kwargs["queryset"] = EveAllianceInfo.objects.all()\ .order_by(Lower('alliance_name')) + elif db_field.name == "permissions": + kwargs["queryset"] = Permission.objects.select_related("content_type").all() return super().formfield_for_manytomany(db_field, request, **kwargs) - + def has_delete_permission(self, request, obj=None): if obj == get_guest_state(): return False diff --git a/allianceauth/groupmanagement/admin.py b/allianceauth/groupmanagement/admin.py index 3f5b4a39..37fa1e37 100644 --- a/allianceauth/groupmanagement/admin.py +++ b/allianceauth/groupmanagement/admin.py @@ -1,4 +1,5 @@ from django.apps import apps +from django.contrib.auth.models import Permission from django.contrib import admin from django.contrib.auth.models import Group as BaseGroup, User from django.db.models import Count @@ -96,8 +97,7 @@ class HasLeaderFilter(admin.SimpleListFilter): return queryset -class GroupAdmin(admin.ModelAdmin): - list_select_related = ('authgroup',) +class GroupAdmin(admin.ModelAdmin): ordering = ('name',) list_display = ( 'name', @@ -122,7 +122,7 @@ class GroupAdmin(admin.ModelAdmin): qs = super().get_queryset(request) if _has_auto_groups: qs = qs.prefetch_related('managedalliancegroup_set', 'managedcorpgroup_set') - qs = qs.prefetch_related('authgroup__group_leaders') + qs = qs.prefetch_related('authgroup__group_leaders').select_related('authgroup') qs = qs.annotate( member_count=Count('user', distinct=True), ) @@ -168,6 +168,11 @@ class GroupAdmin(admin.ModelAdmin): filter_horizontal = ('permissions',) inlines = (AuthGroupInlineAdmin,) + def formfield_for_manytomany(self, db_field, request, **kwargs): + if db_field.name == "permissions": + kwargs["queryset"] = Permission.objects.select_related("content_type").all() + return super().formfield_for_manytomany(db_field, request, **kwargs) + class Group(BaseGroup): class Meta: From e6037f168045ef8260f74486f56b93b6255b705f Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Mon, 21 Jun 2021 10:23:40 +0000 Subject: [PATCH 6/7] Typo (Allince Date: Mon, 21 Jun 2021 10:39:56 +0000 Subject: [PATCH 7/7] Improve messages --- allianceauth/templates/allianceauth/base.html | 10 +--------- .../templates/allianceauth/messages.html | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 allianceauth/templates/allianceauth/messages.html diff --git a/allianceauth/templates/allianceauth/base.html b/allianceauth/templates/allianceauth/base.html index e3d4e85f..da29954a 100644 --- a/allianceauth/templates/allianceauth/base.html +++ b/allianceauth/templates/allianceauth/base.html @@ -30,15 +30,7 @@
    {% include 'allianceauth/side-menu.html' %}
    - {% if messages %} -
    - {% for message in messages %} -
    {{ message }}
    - {% if not forloop.last %} -
    - {% endif %} - {% endfor %} - {% endif %} + {% include 'allianceauth/messages.html' %} {% block content %} {% endblock content %}
    diff --git a/allianceauth/templates/allianceauth/messages.html b/allianceauth/templates/allianceauth/messages.html new file mode 100644 index 00000000..16d6c8e4 --- /dev/null +++ b/allianceauth/templates/allianceauth/messages.html @@ -0,0 +1,20 @@ +{% if messages %} +
    + {% for message in messages %} + + {% endfor %} +{% endif %} \ No newline at end of file