mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-06 07:06:19 +01:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f320bc256 | ||
|
|
45b8d42b8e | ||
|
|
bd2d19f867 | ||
|
|
0be404baca | ||
|
|
e6cee9ac83 | ||
|
|
d173a59441 | ||
|
|
8f59f2549a | ||
|
|
630400fee4 | ||
|
|
1ec6929e91 | ||
|
|
8c6bdd8ae2 | ||
|
|
e04138bced | ||
|
|
db5ad85811 | ||
|
|
5b44fd376d |
@@ -7,37 +7,28 @@ include:
|
|||||||
- template: Dependency-Scanning.gitlab-ci.yml
|
- template: Dependency-Scanning.gitlab-ci.yml
|
||||||
- template: Security/SAST.gitlab-ci.yml
|
- template: Security/SAST.gitlab-ci.yml
|
||||||
|
|
||||||
before_script:
|
|
||||||
- apt-get update && apt-get install redis-server -y
|
|
||||||
- redis-server --daemonize yes
|
|
||||||
- python -V
|
|
||||||
- pip install wheel tox
|
|
||||||
|
|
||||||
sast:
|
sast:
|
||||||
stage: gitlab
|
stage: gitlab
|
||||||
before_script: []
|
|
||||||
|
|
||||||
dependency_scanning:
|
dependency_scanning:
|
||||||
stage: gitlab
|
stage: gitlab
|
||||||
before_script:
|
before_script:
|
||||||
- apt-get update && apt-get install redis-server libmariadbclient-dev -y
|
- apt-get update && apt-get install redis-server libmariadbclient-dev -y
|
||||||
- redis-server --daemonize yes
|
- redis-server --daemonize yes
|
||||||
|
- redis-cli ping
|
||||||
- python -V
|
- python -V
|
||||||
- pip install wheel tox
|
- pip install wheel tox
|
||||||
|
|
||||||
test-3.6-core:
|
|
||||||
image: python:3.6-buster
|
|
||||||
script:
|
|
||||||
- tox -e py36-core
|
|
||||||
artifacts:
|
|
||||||
when: always
|
|
||||||
reports:
|
|
||||||
cobertura: coverage.xml
|
|
||||||
|
|
||||||
test-3.7-core:
|
test-3.7-core:
|
||||||
image: python:3.7-buster
|
image: python:3.7-buster
|
||||||
script:
|
script:
|
||||||
- tox -e py37-core
|
- tox -e py37-core
|
||||||
|
before_script:
|
||||||
|
- apt-get update && apt-get install redis-server -y
|
||||||
|
- redis-server --daemonize yes
|
||||||
|
- redis-cli ping
|
||||||
|
- python -V
|
||||||
|
- pip install wheel tox
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
reports:
|
reports:
|
||||||
@@ -47,15 +38,27 @@ test-3.8-core:
|
|||||||
image: python:3.8-buster
|
image: python:3.8-buster
|
||||||
script:
|
script:
|
||||||
- tox -e py38-core
|
- tox -e py38-core
|
||||||
|
before_script:
|
||||||
|
- apt-get update && apt-get install redis-server -y
|
||||||
|
- redis-server --daemonize yes
|
||||||
|
- redis-cli ping
|
||||||
|
- python -V
|
||||||
|
- pip install wheel tox
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
reports:
|
reports:
|
||||||
cobertura: coverage.xml
|
cobertura: coverage.xml
|
||||||
|
|
||||||
test-3.6-all:
|
test-3.9-core:
|
||||||
image: python:3.6-buster
|
image: python:3.9-buster
|
||||||
script:
|
script:
|
||||||
- tox -e py36-all
|
- tox -e py39-core
|
||||||
|
before_script:
|
||||||
|
- apt-get update && apt-get install redis-server -y
|
||||||
|
- redis-server --daemonize yes
|
||||||
|
- redis-cli ping
|
||||||
|
- python -V
|
||||||
|
- pip install wheel tox
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
reports:
|
reports:
|
||||||
@@ -65,6 +68,12 @@ test-3.7-all:
|
|||||||
image: python:3.7-buster
|
image: python:3.7-buster
|
||||||
script:
|
script:
|
||||||
- tox -e py37-all
|
- tox -e py37-all
|
||||||
|
before_script:
|
||||||
|
- apt-get update && apt-get install redis-server -y
|
||||||
|
- redis-server --daemonize yes
|
||||||
|
- redis-cli ping
|
||||||
|
- python -V
|
||||||
|
- pip install wheel tox
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
reports:
|
reports:
|
||||||
@@ -74,6 +83,27 @@ test-3.8-all:
|
|||||||
image: python:3.8-buster
|
image: python:3.8-buster
|
||||||
script:
|
script:
|
||||||
- tox -e py38-all
|
- tox -e py38-all
|
||||||
|
before_script:
|
||||||
|
- apt-get update && apt-get install redis-server -y
|
||||||
|
- redis-server --daemonize yes
|
||||||
|
- redis-cli ping
|
||||||
|
- python -V
|
||||||
|
- pip install wheel tox
|
||||||
|
artifacts:
|
||||||
|
when: always
|
||||||
|
reports:
|
||||||
|
cobertura: coverage.xml
|
||||||
|
|
||||||
|
test-3.9-all:
|
||||||
|
image: python:3.9-buster
|
||||||
|
script:
|
||||||
|
- tox -e py39-all
|
||||||
|
before_script:
|
||||||
|
- apt-get update && apt-get install redis-server -y
|
||||||
|
- redis-server --daemonize yes
|
||||||
|
- redis-cli ping
|
||||||
|
- python -V
|
||||||
|
- pip install wheel tox
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
reports:
|
reports:
|
||||||
@@ -81,7 +111,7 @@ test-3.8-all:
|
|||||||
|
|
||||||
deploy_production:
|
deploy_production:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
image: python:3.8-buster
|
image: python:3.9-buster
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- pip install twine wheel
|
- pip install twine wheel
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# This will make sure the app is always imported when
|
# This will make sure the app is always imported when
|
||||||
# Django starts so that shared_task will use this app.
|
# Django starts so that shared_task will use this app.
|
||||||
|
|
||||||
__version__ = '2.8.4'
|
__version__ = '2.9.0a1'
|
||||||
__title__ = 'Alliance Auth'
|
__title__ = 'Alliance Auth'
|
||||||
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
|
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
|
||||||
NAME = '%s v%s' % (__title__, __version__)
|
NAME = '%s v%s' % (__title__, __version__)
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||||
from django.contrib.auth.models import User as BaseUser, \
|
from django.contrib.auth.models import User as BaseUser, \
|
||||||
Permission as BasePermission, Group
|
Permission as BasePermission, Group
|
||||||
from django.db.models import Count, Q
|
from django.db.models import Q, F
|
||||||
from allianceauth.services.hooks import ServicesHook
|
from allianceauth.services.hooks import ServicesHook
|
||||||
from django.db.models.signals import pre_save, post_save, pre_delete, \
|
from django.db.models.signals import pre_save, post_save, pre_delete, \
|
||||||
post_delete, m2m_changed
|
post_delete, m2m_changed
|
||||||
@@ -22,6 +24,11 @@ from allianceauth.eveonline.tasks import update_character
|
|||||||
from .app_settings import AUTHENTICATION_ADMIN_USERS_MAX_GROUPS, \
|
from .app_settings import AUTHENTICATION_ADMIN_USERS_MAX_GROUPS, \
|
||||||
AUTHENTICATION_ADMIN_USERS_MAX_CHARS
|
AUTHENTICATION_ADMIN_USERS_MAX_CHARS
|
||||||
|
|
||||||
|
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
||||||
|
_has_auto_groups = True
|
||||||
|
else:
|
||||||
|
_has_auto_groups = False
|
||||||
|
|
||||||
|
|
||||||
def make_service_hooks_update_groups_action(service):
|
def make_service_hooks_update_groups_action(service):
|
||||||
"""
|
"""
|
||||||
@@ -84,7 +91,8 @@ class UserProfileInline(admin.StackedInline):
|
|||||||
if request.user.is_superuser:
|
if request.user.is_superuser:
|
||||||
query |= Q(userprofile__isnull=True)
|
query |= Q(userprofile__isnull=True)
|
||||||
else:
|
else:
|
||||||
query |= Q(character_ownership__user=obj)
|
query |= Q(character_ownership__user=obj)
|
||||||
|
qs = EveCharacter.objects.filter(query)
|
||||||
formset = super().get_formset(request, obj=obj, **kwargs)
|
formset = super().get_formset(request, obj=obj, **kwargs)
|
||||||
|
|
||||||
def get_kwargs(self, index):
|
def get_kwargs(self, index):
|
||||||
@@ -113,8 +121,6 @@ def user_profile_pic(obj):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
user_profile_pic.short_description = ''
|
user_profile_pic.short_description = ''
|
||||||
|
|
||||||
|
|
||||||
@@ -146,7 +152,6 @@ def user_username(obj):
|
|||||||
user_obj.username,
|
user_obj.username,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
user_username.short_description = 'user / main'
|
user_username.short_description = 'user / main'
|
||||||
user_username.admin_order_field = 'username'
|
user_username.admin_order_field = 'username'
|
||||||
|
|
||||||
@@ -163,8 +168,7 @@ def user_main_organization(obj):
|
|||||||
else:
|
else:
|
||||||
corporation = user_obj.profile.main_character.corporation_name
|
corporation = user_obj.profile.main_character.corporation_name
|
||||||
if user_obj.profile.main_character.alliance_id:
|
if user_obj.profile.main_character.alliance_id:
|
||||||
result = format_html(
|
result = format_html('{}<br>{}',
|
||||||
'{}<br>{}',
|
|
||||||
corporation,
|
corporation,
|
||||||
user_obj.profile.main_character.alliance_name
|
user_obj.profile.main_character.alliance_name
|
||||||
)
|
)
|
||||||
@@ -172,7 +176,6 @@ def user_main_organization(obj):
|
|||||||
result = corporation
|
result = corporation
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
user_main_organization.short_description = 'Corporation / Alliance (Main)'
|
user_main_organization.short_description = 'Corporation / Alliance (Main)'
|
||||||
user_main_organization.admin_order_field = \
|
user_main_organization.admin_order_field = \
|
||||||
'profile__main_character__corporation_name'
|
'profile__main_character__corporation_name'
|
||||||
@@ -202,13 +205,13 @@ class MainCorporationsFilter(admin.SimpleListFilter):
|
|||||||
return qs.all()
|
return qs.all()
|
||||||
else:
|
else:
|
||||||
if qs.model == User:
|
if qs.model == User:
|
||||||
return qs.filter(
|
return qs\
|
||||||
profile__main_character__corporation_id=self.value()
|
.filter(profile__main_character__corporation_id=\
|
||||||
)
|
self.value())
|
||||||
else:
|
else:
|
||||||
return qs.filter(
|
return qs\
|
||||||
user__profile__main_character__corporation_id=self.value()
|
.filter(user__profile__main_character__corporation_id=\
|
||||||
)
|
self.value())
|
||||||
|
|
||||||
|
|
||||||
class MainAllianceFilter(admin.SimpleListFilter):
|
class MainAllianceFilter(admin.SimpleListFilter):
|
||||||
@@ -236,11 +239,12 @@ class MainAllianceFilter(admin.SimpleListFilter):
|
|||||||
return qs.all()
|
return qs.all()
|
||||||
else:
|
else:
|
||||||
if qs.model == User:
|
if qs.model == User:
|
||||||
return qs.filter(profile__main_character__alliance_id=self.value())
|
return qs\
|
||||||
|
.filter(profile__main_character__alliance_id=self.value())
|
||||||
else:
|
else:
|
||||||
return qs.filter(
|
return qs\
|
||||||
user__profile__main_character__alliance_id=self.value()
|
.filter(user__profile__main_character__alliance_id=\
|
||||||
)
|
self.value())
|
||||||
|
|
||||||
|
|
||||||
def update_main_character_model(modeladmin, request, queryset):
|
def update_main_character_model(modeladmin, request, queryset):
|
||||||
@@ -255,7 +259,6 @@ def update_main_character_model(modeladmin, request, queryset):
|
|||||||
'Update from ESI started for {} characters'.format(tasks_count)
|
'Update from ESI started for {} characters'.format(tasks_count)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
update_main_character_model.short_description = \
|
update_main_character_model.short_description = \
|
||||||
'Update main character model from ESI'
|
'Update main character model from ESI'
|
||||||
|
|
||||||
@@ -264,16 +267,32 @@ class UserAdmin(BaseUserAdmin):
|
|||||||
"""Extending Django's UserAdmin model
|
"""Extending Django's UserAdmin model
|
||||||
|
|
||||||
Behavior of groups and characters columns can be configured via settings
|
Behavior of groups and characters columns can be configured via settings
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Media:
|
class Media:
|
||||||
css = {
|
css = {
|
||||||
"all": ("authentication/css/admin.css",)
|
"all": ("authentication/css/admin.css",)
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_queryset(self, request):
|
class RealGroupsFilter(admin.SimpleListFilter):
|
||||||
qs = super().get_queryset(request)
|
"""Custom filter to get groups w/o Autogroups"""
|
||||||
return qs.prefetch_related("character_ownerships__character", "groups")
|
title = 'group'
|
||||||
|
parameter_name = 'group_id__exact'
|
||||||
|
|
||||||
|
def lookups(self, request, model_admin):
|
||||||
|
qs = Group.objects.all().order_by(Lower('name'))
|
||||||
|
if _has_auto_groups:
|
||||||
|
qs = qs\
|
||||||
|
.filter(managedalliancegroup__isnull=True)\
|
||||||
|
.filter(managedcorpgroup__isnull=True)
|
||||||
|
return tuple([(x.pk, x.name) for x in qs])
|
||||||
|
|
||||||
|
def queryset(self, request, queryset):
|
||||||
|
if self.value() is None:
|
||||||
|
return queryset.all()
|
||||||
|
else:
|
||||||
|
return queryset.filter(groups__pk=self.value())
|
||||||
|
|
||||||
def get_actions(self, request):
|
def get_actions(self, request):
|
||||||
actions = super(BaseUserAdmin, self).get_actions(request)
|
actions = super(BaseUserAdmin, self).get_actions(request)
|
||||||
@@ -322,9 +341,11 @@ class UserAdmin(BaseUserAdmin):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
inlines = BaseUserAdmin.inlines + [UserProfileInline]
|
inlines = BaseUserAdmin.inlines + [UserProfileInline]
|
||||||
ordering = ('username', )
|
|
||||||
list_select_related = ('profile__state', 'profile__main_character')
|
ordering = ('username', )
|
||||||
show_full_result_count = True
|
list_select_related = True
|
||||||
|
show_full_result_count = True
|
||||||
|
|
||||||
list_display = (
|
list_display = (
|
||||||
user_profile_pic,
|
user_profile_pic,
|
||||||
user_username,
|
user_username,
|
||||||
@@ -337,9 +358,10 @@ class UserAdmin(BaseUserAdmin):
|
|||||||
'_role'
|
'_role'
|
||||||
)
|
)
|
||||||
list_display_links = None
|
list_display_links = None
|
||||||
|
|
||||||
list_filter = (
|
list_filter = (
|
||||||
'profile__state',
|
'profile__state',
|
||||||
'groups',
|
RealGroupsFilter,
|
||||||
MainCorporationsFilter,
|
MainCorporationsFilter,
|
||||||
MainAllianceFilter,
|
MainAllianceFilter,
|
||||||
'is_active',
|
'is_active',
|
||||||
@@ -353,25 +375,41 @@ class UserAdmin(BaseUserAdmin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _characters(self, obj):
|
def _characters(self, obj):
|
||||||
character_ownerships = list(obj.character_ownerships.all())
|
my_characters = [
|
||||||
characters = [obj.character.character_name for obj in character_ownerships]
|
x.character.character_name
|
||||||
|
for x in CharacterOwnership.objects\
|
||||||
|
.filter(user=obj)\
|
||||||
|
.order_by('character__character_name')\
|
||||||
|
.select_related()
|
||||||
|
]
|
||||||
return self._list_2_html_w_tooltips(
|
return self._list_2_html_w_tooltips(
|
||||||
sorted(characters),
|
my_characters,
|
||||||
AUTHENTICATION_ADMIN_USERS_MAX_CHARS
|
AUTHENTICATION_ADMIN_USERS_MAX_CHARS
|
||||||
)
|
)
|
||||||
|
|
||||||
_characters.short_description = 'characters'
|
_characters.short_description = 'characters'
|
||||||
|
|
||||||
|
|
||||||
def _state(self, obj):
|
def _state(self, obj):
|
||||||
return obj.profile.state.name
|
return obj.profile.state.name
|
||||||
|
|
||||||
_state.short_description = 'state'
|
_state.short_description = 'state'
|
||||||
_state.admin_order_field = 'profile__state'
|
_state.admin_order_field = 'profile__state'
|
||||||
|
|
||||||
def _groups(self, obj):
|
def _groups(self, obj):
|
||||||
my_groups = sorted([group.name for group in list(obj.groups.all())])
|
if not _has_auto_groups:
|
||||||
|
my_groups = [x.name for x in obj.groups.order_by('name')]
|
||||||
|
else:
|
||||||
|
my_groups = [
|
||||||
|
x.name for x in obj.groups\
|
||||||
|
.filter(managedalliancegroup__isnull=True)\
|
||||||
|
.filter(managedcorpgroup__isnull=True)\
|
||||||
|
.order_by('name')
|
||||||
|
]
|
||||||
|
|
||||||
return self._list_2_html_w_tooltips(
|
return self._list_2_html_w_tooltips(
|
||||||
my_groups, AUTHENTICATION_ADMIN_USERS_MAX_GROUPS
|
my_groups,
|
||||||
|
AUTHENTICATION_ADMIN_USERS_MAX_GROUPS
|
||||||
)
|
)
|
||||||
|
|
||||||
_groups.short_description = 'groups'
|
_groups.short_description = 'groups'
|
||||||
@@ -408,14 +446,9 @@ class StateAdmin(admin.ModelAdmin):
|
|||||||
list_select_related = True
|
list_select_related = True
|
||||||
list_display = ('name', 'priority', '_user_count')
|
list_display = ('name', 'priority', '_user_count')
|
||||||
|
|
||||||
def get_queryset(self, request):
|
|
||||||
qs = super().get_queryset(request)
|
|
||||||
return qs.annotate(user_count=Count("userprofile__id"))
|
|
||||||
|
|
||||||
def _user_count(self, obj):
|
def _user_count(self, obj):
|
||||||
return obj.user_count
|
return obj.userprofile_set.all().count()
|
||||||
_user_count.short_description = 'Users'
|
_user_count.short_description = 'Users'
|
||||||
_user_count.admin_order_field = 'user_count'
|
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {
|
(None, {
|
||||||
@@ -471,8 +504,7 @@ class BaseOwnershipAdmin(admin.ModelAdmin):
|
|||||||
"all": ("authentication/css/admin.css",)
|
"all": ("authentication/css/admin.css",)
|
||||||
}
|
}
|
||||||
|
|
||||||
list_select_related = (
|
list_select_related = True
|
||||||
'user__profile__state', 'user__profile__main_character', 'character')
|
|
||||||
list_display = (
|
list_display = (
|
||||||
user_profile_pic,
|
user_profile_pic,
|
||||||
user_username,
|
user_username,
|
||||||
@@ -510,7 +542,6 @@ class CharacterOwnershipAdmin(BaseOwnershipAdmin):
|
|||||||
class PermissionAdmin(admin.ModelAdmin):
|
class PermissionAdmin(admin.ModelAdmin):
|
||||||
actions = None
|
actions = None
|
||||||
readonly_fields = [field.name for field in BasePermission._meta.fields]
|
readonly_fields = [field.name for field in BasePermission._meta.fields]
|
||||||
search_fields = ('codename', )
|
|
||||||
list_display = ('admin_name', 'name', 'codename', 'content_type')
|
list_display = ('admin_name', 'name', 'codename', 'content_type')
|
||||||
list_filter = ('content_type__app_label',)
|
list_filter = ('content_type__app_label',)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('authentication', '0017_remove_fleetup_permission'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='characterownership',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ownershiprecord',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='state',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='userprofile',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -10,10 +10,9 @@ def get_admin_change_view_url(obj: object) -> str:
|
|||||||
args=(obj.pk,)
|
args=(obj.pk,)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_admin_search_url(ModelClass: type) -> str:
|
def get_admin_search_url(ModelClass: type) -> str:
|
||||||
"""returns URL to search URL for model of given object"""
|
"""returns URL to search URL for model of given object"""
|
||||||
return '{}{}/'.format(
|
return '{}{}/'.format(
|
||||||
reverse('admin:app_list', args=(ModelClass._meta.app_label,)),
|
reverse('admin:app_list', args=(ModelClass._meta.app_label,)),
|
||||||
ModelClass.__name__.lower()
|
ModelClass.__name__.lower()
|
||||||
)
|
)
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import patch, MagicMock
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib import admin
|
||||||
from django.contrib.admin.sites import AdminSite
|
from django.contrib.admin.sites import AdminSite
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import User as BaseUser, Group
|
||||||
from django.test import TestCase, RequestFactory, Client
|
from django.test import TestCase, RequestFactory, Client
|
||||||
|
|
||||||
from allianceauth.authentication.models import (
|
from allianceauth.authentication.models import (
|
||||||
@@ -16,7 +18,8 @@ from allianceauth.tests.auth_utils import AuthUtils
|
|||||||
|
|
||||||
from ..admin import (
|
from ..admin import (
|
||||||
BaseUserAdmin,
|
BaseUserAdmin,
|
||||||
CharacterOwnershipAdmin,
|
CharacterOwnershipAdmin,
|
||||||
|
PermissionAdmin,
|
||||||
StateAdmin,
|
StateAdmin,
|
||||||
MainCorporationsFilter,
|
MainCorporationsFilter,
|
||||||
MainAllianceFilter,
|
MainAllianceFilter,
|
||||||
@@ -32,6 +35,11 @@ from ..admin import (
|
|||||||
)
|
)
|
||||||
from . import get_admin_change_view_url, get_admin_search_url
|
from . import get_admin_change_view_url, get_admin_search_url
|
||||||
|
|
||||||
|
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
||||||
|
_has_auto_groups = True
|
||||||
|
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
|
||||||
|
else:
|
||||||
|
_has_auto_groups = False
|
||||||
|
|
||||||
MODULE_PATH = 'allianceauth.authentication.admin'
|
MODULE_PATH = 'allianceauth.authentication.admin'
|
||||||
|
|
||||||
@@ -40,7 +48,6 @@ class MockRequest(object):
|
|||||||
def __init__(self, user=None):
|
def __init__(self, user=None):
|
||||||
self.user = user
|
self.user = user
|
||||||
|
|
||||||
|
|
||||||
class TestCaseWithTestData(TestCase):
|
class TestCaseWithTestData(TestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -272,7 +279,6 @@ class TestStateAdmin(TestCaseWithTestData):
|
|||||||
expected = 200
|
expected = 200
|
||||||
self.assertEqual(response.status_code, expected)
|
self.assertEqual(response.status_code, expected)
|
||||||
|
|
||||||
|
|
||||||
class TestUserAdmin(TestCaseWithTestData):
|
class TestUserAdmin(TestCaseWithTestData):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -281,12 +287,24 @@ class TestUserAdmin(TestCaseWithTestData):
|
|||||||
model=User, admin_site=AdminSite()
|
model=User, admin_site=AdminSite()
|
||||||
)
|
)
|
||||||
self.character_1 = self.user_1.character_ownerships.first().character
|
self.character_1 = self.user_1.character_ownerships.first().character
|
||||||
|
|
||||||
|
def _create_autogroups(self):
|
||||||
|
"""create autogroups for corps and alliances"""
|
||||||
|
if _has_auto_groups:
|
||||||
|
autogroups_config = AutogroupsConfig(
|
||||||
|
corp_groups = True,
|
||||||
|
alliance_groups = True
|
||||||
|
)
|
||||||
|
autogroups_config.save()
|
||||||
|
for state in State.objects.all():
|
||||||
|
autogroups_config.states.add(state)
|
||||||
|
autogroups_config.update_corp_group_membership(self.user_1)
|
||||||
|
|
||||||
|
# column rendering
|
||||||
|
|
||||||
def test_user_profile_pic_u1(self):
|
def test_user_profile_pic_u1(self):
|
||||||
expected = (
|
expected = ('<img src="https://images.evetech.net/characters/1001/'
|
||||||
'<img src="https://images.evetech.net/characters/1001/'
|
'portrait?size=32" class="img-circle">')
|
||||||
'portrait?size=32" class="img-circle">'
|
|
||||||
)
|
|
||||||
self.assertEqual(user_profile_pic(self.user_1), expected)
|
self.assertEqual(user_profile_pic(self.user_1), expected)
|
||||||
|
|
||||||
def test_user_profile_pic_u3(self):
|
def test_user_profile_pic_u3(self):
|
||||||
@@ -333,17 +351,37 @@ class TestUserAdmin(TestCaseWithTestData):
|
|||||||
result = self.modeladmin._characters(self.user_3)
|
result = self.modeladmin._characters(self.user_3)
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
def test_groups_u1(self):
|
def test_groups_u1(self):
|
||||||
|
self._create_autogroups()
|
||||||
expected = 'Group 1'
|
expected = 'Group 1'
|
||||||
result = self.modeladmin._groups(self.user_1)
|
result = self.modeladmin._groups(self.user_1)
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
def test_groups_u2(self):
|
def test_groups_u2(self):
|
||||||
|
self._create_autogroups()
|
||||||
expected = 'Group 2'
|
expected = 'Group 2'
|
||||||
result = self.modeladmin._groups(self.user_2)
|
result = self.modeladmin._groups(self.user_2)
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
def test_groups_u3(self):
|
def test_groups_u3(self):
|
||||||
|
self._create_autogroups()
|
||||||
|
result = self.modeladmin._groups(self.user_3)
|
||||||
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
@patch(MODULE_PATH + '._has_auto_groups', False)
|
||||||
|
def test_groups_u1_no_autogroups(self):
|
||||||
|
expected = 'Group 1'
|
||||||
|
result = self.modeladmin._groups(self.user_1)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
@patch(MODULE_PATH + '._has_auto_groups', False)
|
||||||
|
def test_groups_u2_no_autogroups(self):
|
||||||
|
expected = 'Group 2'
|
||||||
|
result = self.modeladmin._groups(self.user_2)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
@patch(MODULE_PATH + '._has_auto_groups', False)
|
||||||
|
def test_groups_u3_no_autogroups(self):
|
||||||
result = self.modeladmin._groups(self.user_3)
|
result = self.modeladmin._groups(self.user_3)
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
|
|
||||||
@@ -375,10 +413,8 @@ class TestUserAdmin(TestCaseWithTestData):
|
|||||||
|
|
||||||
def test_list_2_html_w_tooltips_w_cutoff(self):
|
def test_list_2_html_w_tooltips_w_cutoff(self):
|
||||||
items = ['one', 'two', 'three']
|
items = ['one', 'two', 'three']
|
||||||
expected = (
|
expected = ('<span data-tooltip="one, two, three" '
|
||||||
'<span data-tooltip="one, two, three" '
|
'class="tooltip">one, two, (...)</span>')
|
||||||
'class="tooltip">one, two, (...)</span>'
|
|
||||||
)
|
|
||||||
result = self.modeladmin._list_2_html_w_tooltips(items, 2)
|
result = self.modeladmin._list_2_html_w_tooltips(items, 2)
|
||||||
self.assertEqual(expected, result)
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
@@ -403,7 +439,63 @@ class TestUserAdmin(TestCaseWithTestData):
|
|||||||
self.assertTrue(mock_message_user.called)
|
self.assertTrue(mock_message_user.called)
|
||||||
|
|
||||||
# filters
|
# filters
|
||||||
|
|
||||||
|
def test_filter_real_groups_with_autogroups(self):
|
||||||
|
|
||||||
|
class UserAdminTest(BaseUserAdmin):
|
||||||
|
list_filter = (UserAdmin.RealGroupsFilter,)
|
||||||
|
|
||||||
|
self._create_autogroups()
|
||||||
|
my_modeladmin = UserAdminTest(User, AdminSite())
|
||||||
|
|
||||||
|
# Make sure the lookups are correct
|
||||||
|
request = self.factory.get('/')
|
||||||
|
request.user = self.user_1
|
||||||
|
changelist = my_modeladmin.get_changelist_instance(request)
|
||||||
|
filters = changelist.get_filters(request)
|
||||||
|
filterspec = filters[0][0]
|
||||||
|
expected = [
|
||||||
|
(self.group_1.pk, self.group_1.name),
|
||||||
|
(self.group_2.pk, self.group_2.name),
|
||||||
|
]
|
||||||
|
self.assertEqual(filterspec.lookup_choices, expected)
|
||||||
|
|
||||||
|
# Make sure the correct queryset is returned
|
||||||
|
request = self.factory.get('/', {'group_id__exact': self.group_1.pk})
|
||||||
|
request.user = self.user_1
|
||||||
|
changelist = my_modeladmin.get_changelist_instance(request)
|
||||||
|
queryset = changelist.get_queryset(request)
|
||||||
|
expected = User.objects.filter(groups__in=[self.group_1])
|
||||||
|
self.assertSetEqual(set(queryset), set(expected))
|
||||||
|
|
||||||
|
@patch(MODULE_PATH + '._has_auto_groups', False)
|
||||||
|
def test_filter_real_groups_no_autogroups(self):
|
||||||
|
|
||||||
|
class UserAdminTest(BaseUserAdmin):
|
||||||
|
list_filter = (UserAdmin.RealGroupsFilter,)
|
||||||
|
|
||||||
|
my_modeladmin = UserAdminTest(User, AdminSite())
|
||||||
|
|
||||||
|
# Make sure the lookups are correct
|
||||||
|
request = self.factory.get('/')
|
||||||
|
request.user = self.user_1
|
||||||
|
changelist = my_modeladmin.get_changelist_instance(request)
|
||||||
|
filters = changelist.get_filters(request)
|
||||||
|
filterspec = filters[0][0]
|
||||||
|
expected = [
|
||||||
|
(self.group_1.pk, self.group_1.name),
|
||||||
|
(self.group_2.pk, self.group_2.name),
|
||||||
|
]
|
||||||
|
self.assertEqual(filterspec.lookup_choices, expected)
|
||||||
|
|
||||||
|
# Make sure the correct queryset is returned
|
||||||
|
request = self.factory.get('/', {'group_id__exact': self.group_1.pk})
|
||||||
|
request.user = self.user_1
|
||||||
|
changelist = my_modeladmin.get_changelist_instance(request)
|
||||||
|
queryset = changelist.get_queryset(request)
|
||||||
|
expected = User.objects.filter(groups__in=[self.group_1])
|
||||||
|
self.assertSetEqual(set(queryset), set(expected))
|
||||||
|
|
||||||
def test_filter_main_corporations(self):
|
def test_filter_main_corporations(self):
|
||||||
|
|
||||||
class UserAdminTest(BaseUserAdmin):
|
class UserAdminTest(BaseUserAdmin):
|
||||||
@@ -511,6 +603,7 @@ class TestMakeServicesHooksActions(TestCaseWithTestData):
|
|||||||
def sync_nicknames_bulk(self, user):
|
def sync_nicknames_bulk(self, user):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_service_has_update_groups_only(self):
|
def test_service_has_update_groups_only(self):
|
||||||
service = self.MyServicesHookTypeA()
|
service = self.MyServicesHookTypeA()
|
||||||
mock_service = MagicMock(spec=service)
|
mock_service = MagicMock(spec=service)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from math import ceil
|
from math import ceil
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from requests import RequestException
|
||||||
import requests_mock
|
import requests_mock
|
||||||
from packaging.version import Version as Pep440Version
|
from packaging.version import Version as Pep440Version
|
||||||
|
|
||||||
from django.core.cache import cache
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from allianceauth.templatetags.admin_status import (
|
from allianceauth.templatetags.admin_status import (
|
||||||
@@ -12,7 +12,8 @@ from allianceauth.templatetags.admin_status import (
|
|||||||
_fetch_list_from_gitlab,
|
_fetch_list_from_gitlab,
|
||||||
_current_notifications,
|
_current_notifications,
|
||||||
_current_version_summary,
|
_current_version_summary,
|
||||||
_fetch_notification_issues_from_gitlab,
|
_fetch_notification_issues_from_gitlab,
|
||||||
|
_fetch_tags_from_gitlab,
|
||||||
_latests_versions
|
_latests_versions
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -102,51 +103,35 @@ class TestStatusOverviewTag(TestCase):
|
|||||||
|
|
||||||
class TestNotifications(TestCase):
|
class TestNotifications(TestCase):
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
cache.clear()
|
|
||||||
|
|
||||||
@requests_mock.mock()
|
@requests_mock.mock()
|
||||||
def test_fetch_notification_issues_from_gitlab(self, requests_mocker):
|
def test_fetch_notification_issues_from_gitlab(self, requests_mocker):
|
||||||
# given
|
|
||||||
url = (
|
url = (
|
||||||
'https://gitlab.com/api/v4/projects/allianceauth%2Fallianceauth/issues'
|
'https://gitlab.com/api/v4/projects/allianceauth%2Fallianceauth/issues'
|
||||||
'?labels=announcement'
|
'?labels=announcement'
|
||||||
)
|
)
|
||||||
requests_mocker.get(url, json=GITHUB_NOTIFICATION_ISSUES)
|
requests_mocker.get(url, json=GITHUB_NOTIFICATION_ISSUES)
|
||||||
# when
|
|
||||||
result = _fetch_notification_issues_from_gitlab()
|
result = _fetch_notification_issues_from_gitlab()
|
||||||
# then
|
|
||||||
self.assertEqual(result, GITHUB_NOTIFICATION_ISSUES)
|
self.assertEqual(result, GITHUB_NOTIFICATION_ISSUES)
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.admin_status.cache')
|
@patch(MODULE_PATH + '.admin_status.cache')
|
||||||
def test_current_notifications_normal(self, mock_cache):
|
def test_current_notifications_normal(self, mock_cache):
|
||||||
# given
|
|
||||||
mock_cache.get_or_set.return_value = GITHUB_NOTIFICATION_ISSUES
|
mock_cache.get_or_set.return_value = GITHUB_NOTIFICATION_ISSUES
|
||||||
# when
|
|
||||||
result = _current_notifications()
|
result = _current_notifications()
|
||||||
# then
|
|
||||||
self.assertEqual(result['notifications'], GITHUB_NOTIFICATION_ISSUES[:5])
|
self.assertEqual(result['notifications'], GITHUB_NOTIFICATION_ISSUES[:5])
|
||||||
|
|
||||||
@requests_mock.mock()
|
@patch(MODULE_PATH + '.admin_status.cache')
|
||||||
def test_current_notifications_failed(self, requests_mocker):
|
def test_current_notifications_failed(self, mock_cache):
|
||||||
# given
|
mock_cache.get_or_set.side_effect = RequestException
|
||||||
url = (
|
|
||||||
'https://gitlab.com/api/v4/projects/allianceauth%2Fallianceauth/issues'
|
|
||||||
'?labels=announcement'
|
|
||||||
)
|
|
||||||
requests_mocker.get(url, status_code=404)
|
|
||||||
# when
|
|
||||||
result = _current_notifications()
|
result = _current_notifications()
|
||||||
# then
|
|
||||||
self.assertEqual(result['notifications'], list())
|
self.assertEqual(result['notifications'], list())
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.admin_status.cache')
|
@patch(MODULE_PATH + '.admin_status.cache')
|
||||||
def test_current_notifications_is_none(self, mock_cache):
|
def test_current_notifications_is_none(self, mock_cache):
|
||||||
# given
|
|
||||||
mock_cache.get_or_set.return_value = None
|
mock_cache.get_or_set.return_value = None
|
||||||
# when
|
|
||||||
result = _current_notifications()
|
result = _current_notifications()
|
||||||
# then
|
|
||||||
self.assertEqual(result['notifications'], list())
|
self.assertEqual(result['notifications'], list())
|
||||||
|
|
||||||
|
|
||||||
@@ -158,17 +143,12 @@ class TestCeleryQueueLength(TestCase):
|
|||||||
|
|
||||||
class TestVersionTags(TestCase):
|
class TestVersionTags(TestCase):
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
cache.clear()
|
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.admin_status.__version__', TEST_VERSION)
|
@patch(MODULE_PATH + '.admin_status.__version__', TEST_VERSION)
|
||||||
@patch(MODULE_PATH + '.admin_status.cache')
|
@patch(MODULE_PATH + '.admin_status.cache')
|
||||||
def test_current_version_info_normal(self, mock_cache):
|
def test_current_version_info_normal(self, mock_cache):
|
||||||
# given
|
|
||||||
mock_cache.get_or_set.return_value = GITHUB_TAGS
|
mock_cache.get_or_set.return_value = GITHUB_TAGS
|
||||||
# when
|
|
||||||
result = _current_version_summary()
|
result = _current_version_summary()
|
||||||
# then
|
|
||||||
self.assertTrue(result['latest_major'])
|
self.assertTrue(result['latest_major'])
|
||||||
self.assertTrue(result['latest_minor'])
|
self.assertTrue(result['latest_minor'])
|
||||||
self.assertTrue(result['latest_patch'])
|
self.assertTrue(result['latest_patch'])
|
||||||
@@ -178,41 +158,32 @@ class TestVersionTags(TestCase):
|
|||||||
self.assertEqual(result['latest_beta_version'], '2.4.6a1')
|
self.assertEqual(result['latest_beta_version'], '2.4.6a1')
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.admin_status.__version__', TEST_VERSION)
|
@patch(MODULE_PATH + '.admin_status.__version__', TEST_VERSION)
|
||||||
@requests_mock.mock()
|
@patch(MODULE_PATH + '.admin_status.cache')
|
||||||
def test_current_version_info_failed(self, requests_mocker):
|
def test_current_version_info_failed(self, mock_cache):
|
||||||
# given
|
mock_cache.get_or_set.side_effect = RequestException
|
||||||
url = (
|
|
||||||
'https://gitlab.com/api/v4/projects/allianceauth%2Fallianceauth'
|
expected = {}
|
||||||
'/repository/tags'
|
|
||||||
)
|
|
||||||
requests_mocker.get(url, status_code=500)
|
|
||||||
# when
|
|
||||||
result = _current_version_summary()
|
result = _current_version_summary()
|
||||||
# then
|
self.assertEqual(result, expected)
|
||||||
self.assertEqual(result, {})
|
|
||||||
|
|
||||||
@requests_mock.mock()
|
@requests_mock.mock()
|
||||||
def test_fetch_tags_from_gitlab(self, requests_mocker):
|
def test_fetch_tags_from_gitlab(self, requests_mocker):
|
||||||
# given
|
|
||||||
url = (
|
url = (
|
||||||
'https://gitlab.com/api/v4/projects/allianceauth%2Fallianceauth'
|
'https://gitlab.com/api/v4/projects/allianceauth%2Fallianceauth'
|
||||||
'/repository/tags'
|
'/repository/tags'
|
||||||
)
|
)
|
||||||
requests_mocker.get(url, json=GITHUB_TAGS)
|
requests_mocker.get(url, json=GITHUB_TAGS)
|
||||||
# when
|
result = _fetch_tags_from_gitlab()
|
||||||
result = _current_version_summary()
|
self.assertEqual(result, GITHUB_TAGS)
|
||||||
# then
|
|
||||||
self.assertTrue(result)
|
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.admin_status.__version__', TEST_VERSION)
|
@patch(MODULE_PATH + '.admin_status.__version__', TEST_VERSION)
|
||||||
@patch(MODULE_PATH + '.admin_status.cache')
|
@patch(MODULE_PATH + '.admin_status.cache')
|
||||||
def test_current_version_info_return_no_data(self, mock_cache):
|
def test_current_version_info_return_no_data(self, mock_cache):
|
||||||
# given
|
mock_cache.get_or_set.return_value = None
|
||||||
mock_cache.get_or_set.return_value = None
|
|
||||||
# when
|
expected = {}
|
||||||
result = _current_version_summary()
|
result = _current_version_summary()
|
||||||
# then
|
self.assertEqual(result, expected)
|
||||||
self.assertEqual(result, {})
|
|
||||||
|
|
||||||
|
|
||||||
class TestLatestsVersion(TestCase):
|
class TestLatestsVersion(TestCase):
|
||||||
|
|||||||
23
allianceauth/corputils/migrations/0006_django_3_2_compat.py
Normal file
23
allianceauth/corputils/migrations/0006_django_3_2_compat.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('corputils', '0005_cleanup_permissions'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='corpmember',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='corpstats',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -96,62 +96,24 @@ class EveAllianceForm(EveEntityForm):
|
|||||||
|
|
||||||
@admin.register(EveCorporationInfo)
|
@admin.register(EveCorporationInfo)
|
||||||
class EveCorporationInfoAdmin(admin.ModelAdmin):
|
class EveCorporationInfoAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['corporation_name']
|
|
||||||
list_display = ('corporation_name', 'alliance')
|
|
||||||
list_select_related = ('alliance',)
|
|
||||||
list_filter = (('alliance', admin.RelatedOnlyFieldListFilter),)
|
|
||||||
ordering = ('corporation_name',)
|
|
||||||
|
|
||||||
def has_change_permission(self, request, obj=None):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
if not obj or not obj.pk:
|
if not obj or not obj.pk:
|
||||||
return EveCorporationForm
|
return EveCorporationForm
|
||||||
return super().get_form(request, obj=obj, **kwargs)
|
return super(EveCorporationInfoAdmin, self).get_form(request, obj=obj, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(EveAllianceInfo)
|
@admin.register(EveAllianceInfo)
|
||||||
class EveAllianceInfoAdmin(admin.ModelAdmin):
|
class EveAllianceInfoAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['alliance_name']
|
|
||||||
list_display = ('alliance_name',)
|
|
||||||
ordering = ('alliance_name',)
|
|
||||||
|
|
||||||
def has_change_permission(self, request, obj=None):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
if not obj or not obj.pk:
|
if not obj or not obj.pk:
|
||||||
return EveAllianceForm
|
return EveAllianceForm
|
||||||
return super().get_form(request, obj=obj, **kwargs)
|
return super(EveAllianceInfoAdmin, self).get_form(request, obj=obj, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(EveCharacter)
|
@admin.register(EveCharacter)
|
||||||
class EveCharacterAdmin(admin.ModelAdmin):
|
class EveCharacterAdmin(admin.ModelAdmin):
|
||||||
search_fields = [
|
search_fields = ['character_name', 'corporation_name', 'alliance_name', 'character_ownership__user__username']
|
||||||
'character_name',
|
list_display = ('character_name', 'corporation_name', 'alliance_name', 'user', 'main_character')
|
||||||
'corporation_name',
|
|
||||||
'alliance_name',
|
|
||||||
'character_ownership__user__username'
|
|
||||||
]
|
|
||||||
list_display = (
|
|
||||||
'character_name', 'corporation_name', 'alliance_name', 'user', 'main_character'
|
|
||||||
)
|
|
||||||
list_select_related = (
|
|
||||||
'character_ownership', 'character_ownership__user__profile__main_character'
|
|
||||||
)
|
|
||||||
list_filter = (
|
|
||||||
'corporation_name',
|
|
||||||
'alliance_name',
|
|
||||||
(
|
|
||||||
'character_ownership__user__profile__main_character',
|
|
||||||
admin.RelatedOnlyFieldListFilter
|
|
||||||
),
|
|
||||||
)
|
|
||||||
ordering = ('character_name', )
|
|
||||||
|
|
||||||
def has_change_permission(self, request, obj=None):
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def user(obj):
|
def user(obj):
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('eve_autogroups', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='autogroupsconfig',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='managedalliancegroup',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='managedcorpgroup',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
28
allianceauth/eveonline/migrations/0015_django_3_2_compat.py
Normal file
28
allianceauth/eveonline/migrations/0015_django_3_2_compat.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('eveonline', '0014_auto_20210105_1413'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='eveallianceinfo',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='evecharacter',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='evecorporationinfo',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('fleetactivitytracking', '0006_auto_20180803_0430'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='fat',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='fatlink',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -42,6 +42,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
$(document).ready(function(){
|
$(document).ready(function () {
|
||||||
$("[rel=tooltip]").tooltip();
|
$("[rel=tooltip]").tooltip();
|
||||||
|
});
|
||||||
{% endblock extra_script %}
|
{% endblock extra_script %}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
$(document).ready(function(){
|
$(document).ready(function () {
|
||||||
$("[rel=tooltip]").tooltip();
|
$("[rel=tooltip]").tooltip();
|
||||||
|
});
|
||||||
{% endblock extra_script %}
|
{% endblock extra_script %}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from django.apps import apps
|
from django.conf import settings
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.models import Group as BaseGroup, User
|
from django.contrib.auth.models import Group as BaseGroup, User
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
@@ -9,8 +10,9 @@ from django.dispatch import receiver
|
|||||||
|
|
||||||
from .models import AuthGroup
|
from .models import AuthGroup
|
||||||
from .models import GroupRequest
|
from .models import GroupRequest
|
||||||
|
from . import signals
|
||||||
|
|
||||||
if 'eve_autogroups' in apps.app_configs:
|
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
||||||
_has_auto_groups = True
|
_has_auto_groups = True
|
||||||
else:
|
else:
|
||||||
_has_auto_groups = False
|
_has_auto_groups = False
|
||||||
@@ -95,10 +97,9 @@ class HasLeaderFilter(admin.SimpleListFilter):
|
|||||||
else:
|
else:
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class GroupAdmin(admin.ModelAdmin):
|
class GroupAdmin(admin.ModelAdmin):
|
||||||
list_select_related = ('authgroup',)
|
list_select_related = True
|
||||||
ordering = ('name',)
|
ordering = ('name', )
|
||||||
list_display = (
|
list_display = (
|
||||||
'name',
|
'name',
|
||||||
'_description',
|
'_description',
|
||||||
@@ -117,12 +118,9 @@ class GroupAdmin(admin.ModelAdmin):
|
|||||||
list_filter.append(HasLeaderFilter)
|
list_filter.append(HasLeaderFilter)
|
||||||
|
|
||||||
search_fields = ('name', 'authgroup__description')
|
search_fields = ('name', 'authgroup__description')
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super().get_queryset(request)
|
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.annotate(
|
qs = qs.annotate(
|
||||||
member_count=Count('user', distinct=True),
|
member_count=Count('user', distinct=True),
|
||||||
)
|
)
|
||||||
@@ -175,29 +173,13 @@ class Group(BaseGroup):
|
|||||||
verbose_name = BaseGroup._meta.verbose_name
|
verbose_name = BaseGroup._meta.verbose_name
|
||||||
verbose_name_plural = BaseGroup._meta.verbose_name_plural
|
verbose_name_plural = BaseGroup._meta.verbose_name_plural
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
admin.site.unregister(BaseGroup)
|
admin.site.unregister(BaseGroup)
|
||||||
finally:
|
finally:
|
||||||
admin.site.register(Group, GroupAdmin)
|
admin.site.register(Group, GroupAdmin)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(GroupRequest)
|
admin.site.register(GroupRequest)
|
||||||
class GroupRequestAdmin(admin.ModelAdmin):
|
|
||||||
search_fields = ('user__username', )
|
|
||||||
list_display = ('id', 'group', 'user', '_leave_request', 'status')
|
|
||||||
list_filter = (
|
|
||||||
('group', admin.RelatedOnlyFieldListFilter),
|
|
||||||
('user', admin.RelatedOnlyFieldListFilter),
|
|
||||||
'leave_request',
|
|
||||||
'status'
|
|
||||||
)
|
|
||||||
|
|
||||||
def _leave_request(self, obj) -> True:
|
|
||||||
return obj.leave_request
|
|
||||||
|
|
||||||
_leave_request.short_description = 'is leave request'
|
|
||||||
_leave_request.boolean = True
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(pre_save, sender=Group)
|
@receiver(pre_save, sender=Group)
|
||||||
|
|||||||
@@ -5,6 +5,3 @@ class GroupManagementConfig(AppConfig):
|
|||||||
name = 'allianceauth.groupmanagement'
|
name = 'allianceauth.groupmanagement'
|
||||||
label = 'groupmanagement'
|
label = 'groupmanagement'
|
||||||
verbose_name = 'Group Management'
|
verbose_name = 'Group Management'
|
||||||
|
|
||||||
def ready(self):
|
|
||||||
from . import signals # noqa: F401
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('groupmanagement', '0015_make_descriptions_great_again'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='grouprequest',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='requestlog',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
|
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
$.fn.dataTable.moment = function(format, locale) {
|
$.fn.dataTable.moment = function(format, locale) {
|
||||||
var types = $.fn.dataTable.ext.type;
|
let types = $.fn.dataTable.ext.type;
|
||||||
|
|
||||||
// Add type detection
|
// Add type detection
|
||||||
types.detect.unshift(function(d) {
|
types.detect.unshift(function(d) {
|
||||||
|
|||||||
@@ -40,121 +40,120 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default panel-tabs-aa">
|
<div class="tab-content">
|
||||||
<div class="panel-body">
|
<div id="add" class="tab-pane fade in active panel panel-default">
|
||||||
<div class="tab-content">
|
<div class="panel-body">
|
||||||
|
{% if acceptrequests %}
|
||||||
<div id="add" class="tab-pane active">
|
<div class="table-responsive">
|
||||||
{% if acceptrequests %}
|
<table class="table table-aa">
|
||||||
<div class="table-responsive">
|
<thead>
|
||||||
<table class="table table-aa">
|
<tr>
|
||||||
<thead>
|
<th>{% trans "Character" %}</th>
|
||||||
|
<th>{% trans "Organization" %}</th>
|
||||||
|
<th>{% trans "Group" %}</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{% for acceptrequest in acceptrequests %}
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Character" %}</th>
|
<td>
|
||||||
<th>{% trans "Organization" %}</th>
|
<img src="{{ acceptrequest.main_char|character_portrait_url:32 }}" class="img-circle" style="margin-right: 1rem;">
|
||||||
<th>{% trans "Group" %}</th>
|
{% if acceptrequest.main_char %}
|
||||||
<th></th>
|
<a href="{{ acceptrequest.main_char|evewho_character_url }}" target="_blank">
|
||||||
|
{{ acceptrequest.main_char.character_name }}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
{{ acceptrequest.user.username }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if acceptrequest.main_char %}
|
||||||
|
<a href="{{ acceptrequest.main_char|dotlan_corporation_url }}" target="_blank">
|
||||||
|
{{ acceptrequest.main_char.corporation_name }}
|
||||||
|
</a><br>
|
||||||
|
{{ acceptrequest.main_char.alliance_name|default_if_none:"" }}
|
||||||
|
{% else %}
|
||||||
|
{% trans "(unknown)" %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{ acceptrequest.group.name }}</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="{% url 'groupmanagement:accept_request' acceptrequest.id %}" class="btn btn-success">
|
||||||
|
{% trans "Accept" %}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{% url 'groupmanagement:reject_request' acceptrequest.id %}" class="btn btn-danger">
|
||||||
|
{% trans "Reject" %}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-warning text-center">{% trans "No group add requests." %}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<tbody>
|
<div id="leave" class="tab-pane fade panel panel-default">
|
||||||
{% for acceptrequest in acceptrequests %}
|
<div class="panel-body">
|
||||||
<tr>
|
{% if leaverequests %}
|
||||||
<td>
|
<div class="table-responsive">
|
||||||
<img src="{{ acceptrequest.main_char|character_portrait_url:32 }}" class="img-circle" style="margin-right: 1rem;">
|
<table class="table table-aa">
|
||||||
{% if acceptrequest.main_char %}
|
<thead>
|
||||||
<a href="{{ acceptrequest.main_char|evewho_character_url }}" target="_blank">
|
<tr>
|
||||||
{{ acceptrequest.main_char.character_name }}
|
<th>{% trans "Character" %}</th>
|
||||||
</a>
|
<th>{% trans "Organization" %}</th>
|
||||||
{% else %}
|
<th>{% trans "Group" %}</th>
|
||||||
{{ acceptrequest.user.username }}
|
<th></th>
|
||||||
{% endif %}
|
</tr>
|
||||||
</td>
|
</thead>
|
||||||
<td>
|
|
||||||
{% if acceptrequest.main_char %}
|
|
||||||
<a href="{{ acceptrequest.main_char|dotlan_corporation_url }}" target="_blank">
|
|
||||||
{{ acceptrequest.main_char.corporation_name }}
|
|
||||||
</a><br>
|
|
||||||
{{ acceptrequest.main_char.alliance_name|default_if_none:"" }}
|
|
||||||
{% else %}
|
|
||||||
{% trans "(unknown)" %}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>{{ acceptrequest.group.name }}</td>
|
|
||||||
<td class="text-right">
|
|
||||||
<a href="{% url 'groupmanagement:accept_request' acceptrequest.id %}" class="btn btn-success">
|
|
||||||
{% trans "Accept" %}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="{% url 'groupmanagement:reject_request' acceptrequest.id %}" class="btn btn-danger">
|
<tbody>
|
||||||
{% trans "Reject" %}
|
{% for leaverequest in leaverequests %}
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="alert alert-warning text-center">{% trans "No group add requests." %}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="leave" class="tab-pane">
|
|
||||||
{% if leaverequests %}
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-aa">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Character" %}</th>
|
<td>
|
||||||
<th>{% trans "Organization" %}</th>
|
<img src="{{ leaverequest.main_char|character_portrait_url:32 }}" class="img-circle" style="margin-right: 1rem;">
|
||||||
<th>{% trans "Group" %}</th>
|
{% if leaverequest.main_char %}
|
||||||
<th></th>
|
<a href="{{ leaverequest.main_char|evewho_character_url }}" target="_blank">
|
||||||
|
{{ leaverequest.main_char.character_name }}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
{{ leaverequest.user.username }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if leaverequest.main_char %}
|
||||||
|
<a href="{{ leaverequest.main_char|dotlan_corporation_url }}" target="_blank">
|
||||||
|
{{ leaverequest.main_char.corporation_name }}
|
||||||
|
</a><br>
|
||||||
|
{{ leaverequest.main_char.alliance_name|default_if_none:"" }}
|
||||||
|
{% else %}
|
||||||
|
{% trans "(unknown)" %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{ leaverequest.group.name }}</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="{% url 'groupmanagement:leave_accept_request' leaverequest.id %}" class="btn btn-success">
|
||||||
|
{% trans "Accept" %}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{% url 'groupmanagement:leave_reject_request' leaverequest.id %}" class="btn btn-danger">
|
||||||
|
{% trans "Reject" %}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
<tbody>
|
</table>
|
||||||
{% for leaverequest in leaverequests %}
|
</div>
|
||||||
<tr>
|
{% else %}
|
||||||
<td>
|
<div class="alert alert-warning text-center">{% trans "No group leave requests." %}</div>
|
||||||
<img src="{{ leaverequest.main_char|character_portrait_url:32 }}" class="img-circle" style="margin-right: 1rem;">
|
{% endif %}
|
||||||
{% if leaverequest.main_char %}
|
|
||||||
<a href="{{ leaverequest.main_char|evewho_character_url }}" target="_blank">
|
|
||||||
{{ leaverequest.main_char.character_name }}
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
{{ leaverequest.user.username }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% if leaverequest.main_char %}
|
|
||||||
<a href="{{ leaverequest.main_char|dotlan_corporation_url }}" target="_blank">
|
|
||||||
{{ leaverequest.main_char.corporation_name }}
|
|
||||||
</a><br>
|
|
||||||
{{ leaverequest.main_char.alliance_name|default_if_none:"" }}
|
|
||||||
{% else %}
|
|
||||||
{% trans "(unknown)" %}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>{{ leaverequest.group.name }}</td>
|
|
||||||
<td class="text-right">
|
|
||||||
<a href="{% url 'groupmanagement:leave_accept_request' leaverequest.id %}" class="btn btn-success">
|
|
||||||
{% trans "Accept" %}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a href="{% url 'groupmanagement:leave_reject_request' leaverequest.id %}" class="btn btn-danger">
|
|
||||||
{% trans "Reject" %}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="alert alert-warning text-center">{% trans "No group leave requests." %}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('hrapplications', '0007_auto_20200918_1412'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='application',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='applicationchoice',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='applicationcomment',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='applicationform',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='applicationquestion',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='applicationresponse',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('notifications', '0004_performance_tuning'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='notification',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
allianceauth/optimer/migrations/0005_django_3_2_compat.py
Normal file
18
allianceauth/optimer/migrations/0005_django_3_2_compat.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('optimer', '0004_on_delete'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='optimer',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -34,17 +34,15 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
|
|
||||||
$('#id_start').datetimepicker({
|
$('#id_start').datetimepicker({
|
||||||
setlocale: '{{ LANGUAGE_CODE }}',
|
setlocale: '{{ LANGUAGE_CODE }}',
|
||||||
{% if NIGHT_MODE %}
|
{% if NIGHT_MODE %}
|
||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
{% else %}
|
{% else %}
|
||||||
theme: 'default',
|
theme: 'default',
|
||||||
{% endif %}
|
{% endif %}
|
||||||
mask: true,
|
mask: true,
|
||||||
format: 'Y-m-d H:i',
|
format: 'Y-m-d H:i',
|
||||||
minDate: 0
|
minDate: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
{% endblock extra_script %}
|
{% endblock extra_script %}
|
||||||
|
|||||||
@@ -41,9 +41,10 @@
|
|||||||
|
|
||||||
{% include 'bundles/moment-js.html' with locale=True %}
|
{% include 'bundles/moment-js.html' with locale=True %}
|
||||||
<script src="{% static 'js/timers.js' %}"></script>
|
<script src="{% static 'js/timers.js' %}"></script>
|
||||||
|
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
// Data
|
// Data
|
||||||
var timers = [
|
let timers = [
|
||||||
{% for op in optimer %}
|
{% for op in optimer %}
|
||||||
{
|
{
|
||||||
'id': {{ op.id }},
|
'id': {{ op.id }},
|
||||||
@@ -52,67 +53,66 @@
|
|||||||
},
|
},
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
];
|
];
|
||||||
</script>
|
|
||||||
<script type="application/javascript">
|
|
||||||
|
|
||||||
timedUpdate();
|
|
||||||
setAllLocalTimes();
|
|
||||||
|
|
||||||
// Start timed updates
|
|
||||||
setInterval(timedUpdate, 1000);
|
|
||||||
|
|
||||||
function timedUpdate() {
|
|
||||||
updateClock();
|
|
||||||
updateAllTimers();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateAllTimers () {
|
|
||||||
var l = timers.length;
|
|
||||||
for (var i=0; i < l; ++i) {
|
|
||||||
if (timers[i].expired) continue;
|
|
||||||
updateTimer(timers[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a timer
|
* Update a timer
|
||||||
* @param timer Timer information
|
* @param timer Timer information
|
||||||
* @param timer.start Date of the timer
|
|
||||||
* @param timer.id Id number of the timer
|
|
||||||
* @param timer.expired
|
|
||||||
*/
|
*/
|
||||||
function updateTimer(timer) {
|
let updateTimer = function (timer) {
|
||||||
if (timer.start.isAfter(Date.now())) {
|
if (timer.start.isAfter(Date.now())) {
|
||||||
var duration = moment.duration(timer.start - moment(), 'milliseconds');
|
let duration = moment.duration(timer.start - moment(), 'milliseconds');
|
||||||
|
|
||||||
document.getElementById("countdown" + timer.id).innerHTML = getDurationString(duration);
|
document.getElementById("countdown" + timer.id).innerHTML = getDurationString(duration);
|
||||||
} else {
|
} else {
|
||||||
timer.expired = true;
|
timer.expired = true;
|
||||||
|
|
||||||
document.getElementById("countdown" + timer.id).innerHTML = "";
|
document.getElementById("countdown" + timer.id).innerHTML = "";
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let updateAllTimers = function () {
|
||||||
|
let l = timers.length;
|
||||||
|
|
||||||
/**
|
|
||||||
* Set all local time fields
|
|
||||||
*/
|
|
||||||
function setAllLocalTimes() {
|
|
||||||
var l = timers.length;
|
|
||||||
for (var i=0; i < l; ++i) {
|
for (var i=0; i < l; ++i) {
|
||||||
setLocalTime(timers[i]);
|
if (timers[i].expired) continue;
|
||||||
|
|
||||||
|
updateTimer(timers[i]);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the local time info for the timer
|
* Set the local time info for the timer
|
||||||
* @param timer Timer information
|
* @param timer Timer information
|
||||||
* @param timer.start Date of the timer
|
|
||||||
* @param timer.id Id number of the timer
|
|
||||||
*/
|
*/
|
||||||
function setLocalTime(timer) {
|
let setLocalTime = function (timer) {
|
||||||
document.getElementById("localtime" + timer.id).innerHTML = timer.start.format("ddd @ LT");
|
document.getElementById("localtime" + timer.id).innerHTML = timer.start.format("ddd @ LT");
|
||||||
}
|
};
|
||||||
|
|
||||||
function updateClock() {
|
/**
|
||||||
|
* Set all local time fields
|
||||||
|
*/
|
||||||
|
let setAllLocalTimes = function () {
|
||||||
|
let l = timers.length;
|
||||||
|
|
||||||
|
for (var i=0; i < l; ++i) {
|
||||||
|
setLocalTime(timers[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let updateClock = function () {
|
||||||
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let timedUpdate = function () {
|
||||||
|
updateClock();
|
||||||
|
updateAllTimers();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set initial values
|
||||||
|
setAllLocalTimes();
|
||||||
|
timedUpdate();
|
||||||
|
|
||||||
|
// Start timed updates
|
||||||
|
setInterval(timedUpdate, 1000);
|
||||||
</script>
|
</script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for user in permission.users %}
|
{% for user in permission.users %}
|
||||||
{% include 'permissions_tool/audit_row.html' with type="User" name="Permission granted directlty" %}
|
{% include 'permissions_tool/audit_row.html' with type="User" name="Permission granted directlty" %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for group in permission.groups %}
|
{% for group in permission.groups %}
|
||||||
@@ -35,13 +35,13 @@
|
|||||||
{% for state in permission.states %}
|
{% for state in permission.states %}
|
||||||
{% for profile in state.userprofile_set.all %}
|
{% for profile in state.userprofile_set.all %}
|
||||||
{% with profile.user as user %}
|
{% with profile.user as user %}
|
||||||
{% include 'permissions_tool/audit_row.html' with type="State" name=state%}
|
{% include 'permissions_tool/audit_row.html' with type="State" name=state%}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
@@ -56,15 +56,16 @@
|
|||||||
|
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var groupColumn = 0;
|
let groupColumn = 0;
|
||||||
var table = $('#tab_permissions_audit').DataTable({
|
|
||||||
|
$('#tab_permissions_audit').DataTable({
|
||||||
columnDefs: [
|
columnDefs: [
|
||||||
{ "visible": false, "targets": groupColumn }
|
{ "visible": false, "targets": groupColumn }
|
||||||
],
|
],
|
||||||
order: [[ groupColumn, 'asc' ], [ 2, 'asc' ] ],
|
order: [[ groupColumn, 'asc' ], [ 2, 'asc' ] ],
|
||||||
filterDropDown:
|
filterDropDown:
|
||||||
{
|
{
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
idx: 0,
|
idx: 0,
|
||||||
title: 'Source'
|
title: 'Source'
|
||||||
@@ -73,20 +74,20 @@
|
|||||||
bootstrap: true
|
bootstrap: true
|
||||||
},
|
},
|
||||||
drawCallback: function ( settings ) {
|
drawCallback: function ( settings ) {
|
||||||
var api = this.api();
|
let api = this.api();
|
||||||
var rows = api.rows( {page:'current'} ).nodes();
|
let rows = api.rows( {page:'current'} ).nodes();
|
||||||
var last=null;
|
let last = null;
|
||||||
|
|
||||||
api.column(groupColumn, {page:'current'} ).data().each( function ( group, i ) {
|
api.column(groupColumn, {page:'current'} ).data().each( function ( group, i ) {
|
||||||
if ( last !== group ) {
|
if ( last !== group ) {
|
||||||
$(rows).eq( i ).before(
|
$(rows).eq( i ).before(
|
||||||
'<tr class="tr-group"><td colspan="3">' + group + '</td></tr>'
|
'<tr class="tr-group"><td colspan="3">' + group + '</td></tr>'
|
||||||
);
|
);
|
||||||
|
|
||||||
last = group;
|
last = group;
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<h1 class="page-header">{% trans "Permissions Overview" %}</h1>
|
<h1 class="page-header">{% trans "Permissions Overview" %}</h1>
|
||||||
<p>
|
<p>
|
||||||
{% if request.GET.all != 'yes' %}
|
{% if request.GET.all != 'yes' %}
|
||||||
{% blocktrans %}Showing only applied permissions{% endblocktrans %}
|
{% blocktrans %}Showing only applied permissions{% endblocktrans %}
|
||||||
<a href="{% url 'permissions_tool:overview' %}?all=yes" class="btn btn-primary">{% trans "Show All" %}</a>
|
<a href="{% url 'permissions_tool:overview' %}?all=yes" class="btn btn-primary">{% trans "Show All" %}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% blocktrans %}Showing all permissions{% endblocktrans %}
|
{% blocktrans %}Showing all permissions{% endblocktrans %}
|
||||||
<a href="{% url 'permissions_tool:overview' %}?all=no" class="btn btn-primary">{% trans "Show Applied" %}</a>
|
<a href="{% url 'permissions_tool:overview' %}?all=no" class="btn btn-primary">{% trans "Show Applied" %}</a>
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block extra_javascript %}
|
{% block extra_javascript %}
|
||||||
{% include 'bundles/datatables-js.html' %}
|
{% include 'bundles/datatables-js.html' %}
|
||||||
<script type="application/javascript" src="{% static 'js/filterDropDown/filterDropDown.min.js' %}"></script>
|
<script type="application/javascript" src="{% static 'js/filterDropDown/filterDropDown.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -89,15 +89,16 @@
|
|||||||
|
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var groupColumn = 0;
|
let groupColumn = 0;
|
||||||
var table = $('#tab_permissions_overview').DataTable({
|
|
||||||
|
$('#tab_permissions_overview').DataTable({
|
||||||
columnDefs: [
|
columnDefs: [
|
||||||
{ "visible": false, "targets": groupColumn }
|
{ "visible": false, "targets": groupColumn }
|
||||||
],
|
],
|
||||||
order: [[ groupColumn, 'asc' ], [ 1, 'asc' ], [ 2, 'asc' ] ],
|
order: [[ groupColumn, 'asc' ], [ 1, 'asc' ], [ 2, 'asc' ] ],
|
||||||
filterDropDown:
|
filterDropDown:
|
||||||
{
|
{
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
idx: 0
|
idx: 0
|
||||||
},
|
},
|
||||||
@@ -108,20 +109,20 @@
|
|||||||
bootstrap: true
|
bootstrap: true
|
||||||
},
|
},
|
||||||
drawCallback: function ( settings ) {
|
drawCallback: function ( settings ) {
|
||||||
var api = this.api();
|
let api = this.api();
|
||||||
var rows = api.rows( {page:'current'} ).nodes();
|
let rows = api.rows( {page:'current'} ).nodes();
|
||||||
var last=null;
|
let last = null;
|
||||||
|
|
||||||
api.column(groupColumn, {page:'current'} ).data().each( function ( group, i ) {
|
api.column(groupColumn, {page:'current'} ).data().each( function ( group, i ) {
|
||||||
if ( last !== group ) {
|
if ( last !== group ) {
|
||||||
$(rows).eq( i ).before(
|
$(rows).eq( i ).before(
|
||||||
'<tr class="tr-group"><td colspan="6">' + group + '</td></tr>'
|
'<tr class="tr-group"><td colspan="6">' + group + '</td></tr>'
|
||||||
);
|
);
|
||||||
|
|
||||||
last = group;
|
last = group;
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -262,3 +262,5 @@ LOGGING = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||||
|
|||||||
18
allianceauth/services/migrations/0004_django_3_2_compat.py
Normal file
18
allianceauth/services/migrations/0004_django_3_2_compat.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('services', '0003_remove_broken_link'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='nameformatconfig',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -12,20 +12,12 @@ import base64
|
|||||||
import hmac
|
import hmac
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
try:
|
from urllib.parse import unquote, urlencode, parse_qs
|
||||||
from urllib import unquote, urlencode
|
|
||||||
except ImportError: #py3
|
|
||||||
from urllib.parse import unquote, urlencode
|
|
||||||
try:
|
|
||||||
from urlparse import parse_qs
|
|
||||||
except ImportError: #py3
|
|
||||||
from urllib.parse import parse_qs
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
ACCESS_PERM = 'discourse.access_discourse'
|
ACCESS_PERM = 'discourse.access_discourse'
|
||||||
|
|
||||||
|
|
||||||
@@ -55,7 +47,7 @@ def discourse_sso(request):
|
|||||||
# Validate the payload
|
# Validate the payload
|
||||||
try:
|
try:
|
||||||
payload = unquote(payload).encode('utf-8')
|
payload = unquote(payload).encode('utf-8')
|
||||||
decoded = base64.decodestring(payload).decode('utf-8')
|
decoded = base64.decodebytes(payload).decode('utf-8')
|
||||||
assert 'nonce' in decoded
|
assert 'nonce' in decoded
|
||||||
assert len(payload) > 0
|
assert len(payload) > 0
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
@@ -86,7 +78,7 @@ def discourse_sso(request):
|
|||||||
if main_char:
|
if main_char:
|
||||||
params['avatar_url'] = main_char.portrait_url(256)
|
params['avatar_url'] = main_char.portrait_url(256)
|
||||||
|
|
||||||
return_payload = base64.encodestring(urlencode(params).encode('utf-8'))
|
return_payload = base64.encodebytes(urlencode(params).encode('utf-8'))
|
||||||
h = hmac.new(key, return_payload, digestmod=hashlib.sha256)
|
h = hmac.new(key, return_payload, digestmod=hashlib.sha256)
|
||||||
query_string = urlencode({'sso': return_payload, 'sig': h.hexdigest()})
|
query_string = urlencode({'sso': return_payload, 'sig': h.hexdigest()})
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
# Generated by Django 3.1.6 on 2021-03-23 13:10
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mumble', '0001_squashed_0011_auto_20201011_1009'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='mumbleuser',
|
|
||||||
name='last_connect',
|
|
||||||
field=models.DateTimeField(blank=True, editable=False, help_text='Timestamp of the users Last Connection to Mumble', max_length=254, null=True, verbose_name='Last Connection'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='mumbleuser',
|
|
||||||
name='last_disconnect',
|
|
||||||
field=models.DateTimeField(blank=True, editable=False, help_text='Timestamp of the users Last Disconnection to Mumble', max_length=254, null=True, verbose_name='Last Disconnection'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='mumbleuser',
|
|
||||||
name='release',
|
|
||||||
field=models.TextField(blank=True, editable=False, help_text='The Mumble Release the user last authenticated with', max_length=254, null=True, verbose_name='Mumble Release'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='mumbleuser',
|
|
||||||
name='version',
|
|
||||||
field=models.IntegerField(blank=True, editable=False, help_text='Client version. Major version in upper 16 bits, followed by 8 bits of minor version and 8 bits of patchlevel. Version 1.2.3 = 0x010203.', null=True, verbose_name='Mumble Version'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -74,41 +74,7 @@ class MumbleUser(AbstractServiceModel):
|
|||||||
editable=False,
|
editable=False,
|
||||||
help_text="Hash of Mumble client certificate as presented when user authenticates"
|
help_text="Hash of Mumble client certificate as presented when user authenticates"
|
||||||
)
|
)
|
||||||
display_name = models.CharField(
|
display_name = models.CharField(max_length=254, unique=True)
|
||||||
max_length=254,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
release = models.TextField(
|
|
||||||
verbose_name="Mumble Release",
|
|
||||||
max_length=254,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
editable=False,
|
|
||||||
help_text="The Mumble Release the user last authenticated with"
|
|
||||||
)
|
|
||||||
version = models.IntegerField(
|
|
||||||
verbose_name="Mumble Version",
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
editable=False,
|
|
||||||
help_text="Client version. Major version in upper 16 bits, followed by 8 bits of minor version and 8 bits of patchlevel. Version 1.2.3 = 0x010203."
|
|
||||||
)
|
|
||||||
last_connect = models.DateTimeField(
|
|
||||||
verbose_name="Last Connection",
|
|
||||||
max_length=254,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
editable=False,
|
|
||||||
help_text="Timestamp of the users Last Connection to Mumble"
|
|
||||||
)
|
|
||||||
last_disconnect = models.DateTimeField(
|
|
||||||
verbose_name="Last Disconnection",
|
|
||||||
max_length=254,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
editable=False,
|
|
||||||
help_text="Timestamp of the users Last Disconnection to Mumble"
|
|
||||||
)
|
|
||||||
|
|
||||||
objects = MumbleManager()
|
objects = MumbleManager()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('teamspeak3', '0005_stategroup'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='authts',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='stategroup',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='usertsgroup',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
23
allianceauth/srp/migrations/0005_django_3_2_compat.py
Normal file
23
allianceauth/srp/migrations/0005_django_3_2_compat.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('srp', '0004_on_delete'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='srpfleetmain',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='srpuserrequest',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -43,17 +43,15 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
|
|
||||||
$('#id_fleet_time').datetimepicker({
|
$('#id_fleet_time').datetimepicker({
|
||||||
setlocale: '{{ LANGUAGE_CODE }}',
|
setlocale: '{{ LANGUAGE_CODE }}',
|
||||||
{% if NIGHT_MODE %}
|
{% if NIGHT_MODE %}
|
||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
{% else %}
|
{% else %}
|
||||||
theme: 'default',
|
theme: 'default',
|
||||||
{% endif %}
|
{% endif %}
|
||||||
mask: true,
|
mask: true,
|
||||||
format: 'Y-m-d H:i',
|
format: 'Y-m-d H:i',
|
||||||
minDate: 0
|
minDate: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
{% endblock extra_script %}
|
{% endblock extra_script %}
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ ESC to cancel{% endblocktrans %}"id="blah"></i></th>
|
|||||||
{% include 'bundles/x-editable-js.html' %}
|
{% include 'bundles/x-editable-js.html' %}
|
||||||
{% include 'bundles/moment-js.html' %}
|
{% include 'bundles/moment-js.html' %}
|
||||||
{% include 'bundles/clipboard-js.html' %}
|
{% include 'bundles/clipboard-js.html' %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var clipboard = new ClipboardJS('.copy-text-fa-icon');
|
var clipboard = new ClipboardJS('.copy-text-fa-icon');
|
||||||
clipboard.on('success', function (e) {
|
clipboard.on('success', function (e) {
|
||||||
@@ -206,73 +206,71 @@ ESC to cancel{% endblocktrans %}"id="blah"></i></th>
|
|||||||
{% endblock extra_javascript %}
|
{% endblock extra_javascript %}
|
||||||
|
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$.fn.editable.defaults.mode = 'inline';
|
$.fn.editable.defaults.mode = 'inline';
|
||||||
$.fn.editable.defaults.showbuttons = false;
|
$.fn.editable.defaults.showbuttons = false;
|
||||||
$.fn.editable.defaults.highlight = "#AAFF80";
|
$.fn.editable.defaults.highlight = "#AAFF80";
|
||||||
|
|
||||||
|
$.fn.dataTable.moment = function(format, locale) {
|
||||||
|
let types = $.fn.dataTable.ext.type;
|
||||||
|
|
||||||
$('.srp').editable({
|
// Add type detection
|
||||||
display: function(value, response) {
|
types.detect.unshift(function(d) {
|
||||||
return false;
|
return moment(d, format, locale, true).isValid() ?
|
||||||
},
|
'moment-' + format :
|
||||||
success: function(response, newValue) {
|
null;
|
||||||
newValue = parseInt(newValue);
|
});
|
||||||
newvalue = newValue.toLocaleString() + " ISK";
|
|
||||||
$(this).html(newvalue.bold());
|
|
||||||
},
|
|
||||||
validate: function(value) {
|
|
||||||
if (value === null || value === '') {
|
|
||||||
return 'Empty values not allowed';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$('.srp').on('hidden', function(e, reason){
|
|
||||||
if(reason === 'save' || reason === 'nochange') {
|
|
||||||
var $next = $(this).closest('tr').next().find('.editable');
|
|
||||||
setTimeout(function() {
|
|
||||||
$next.editable('show');
|
|
||||||
}, 400);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).ready(function(){
|
// Add sorting method - use an integer for the sorting
|
||||||
$("[rel=tooltip]").tooltip({ placement: 'top'});
|
types.order[ 'moment-' + format+'-pre' ] = function(d) {
|
||||||
});
|
return moment(d, format, locale, true).unix();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
$.fn.dataTable.moment('YYYY-MMM-D, HH:mm');
|
||||||
|
|
||||||
$.fn.dataTable.moment = function(format, locale) {
|
$('.srp').editable({
|
||||||
var types = $.fn.dataTable.ext.type;
|
display: function(value, response) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
success: function(response, newValue) {
|
||||||
|
newValue = parseInt(newValue);
|
||||||
|
let newValueOutput = newValue.toLocaleString() + " ISK";
|
||||||
|
|
||||||
// Add type detection
|
$(this).html(newValueOutput.bold());
|
||||||
types.detect.unshift(function(d) {
|
},
|
||||||
return moment(d, format, locale, true).isValid() ?
|
validate: function(value) {
|
||||||
'moment-'+format :
|
if (value === null || value === '') {
|
||||||
null;
|
return 'Empty values not allowed';
|
||||||
} );
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Add sorting method - use an integer for the sorting
|
$('.srp').on('hidden', function(e, reason){
|
||||||
types.order[ 'moment-'+format+'-pre' ] = function(d) {
|
if(reason === 'save' || reason === 'nochange') {
|
||||||
return moment(d, format, locale, true).unix();
|
let $next = $(this).closest('tr').next().find('.editable');
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).ready( function(){
|
setTimeout(function() {
|
||||||
$.fn.dataTable.moment('YYYY-MMM-D, HH:mm');
|
$next.editable('show');
|
||||||
|
}, 400);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('table.srplist').DataTable({
|
$('table.srplist').DataTable({
|
||||||
"order": [[ 6, "asc" ]],
|
"order": [[ 6, "asc" ]],
|
||||||
"paging": false,
|
"paging": false,
|
||||||
"columnDefs": [{
|
"columnDefs": [
|
||||||
"targets": [1, 8],
|
{
|
||||||
"orderable": false
|
"targets": [1, 8],
|
||||||
},
|
"orderable": false
|
||||||
{
|
},
|
||||||
"targets": [4, 5],
|
{
|
||||||
"type": "num"
|
"targets": [4, 5],
|
||||||
}]
|
"type": "num"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// tooltip
|
||||||
|
$("[rel=tooltip]").tooltip({ placement: 'top'});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
{% endblock extra_script %}
|
{% endblock extra_script %}
|
||||||
|
|||||||
@@ -43,51 +43,27 @@ ul.list-group.list-group-horizontal > li.list-group-item {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media all {
|
/* style group headers within a table */
|
||||||
/* style nav tabs in dark mode*/
|
.tr-group {
|
||||||
.template-dark-mode .nav-tabs > li.active > a {
|
font-weight: bold;
|
||||||
background-color: rgb(70, 69, 69)!important;
|
background-color: #e6e6e6 !important;
|
||||||
color: rgb(255, 255, 255) !important;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.panel-tabs-aa {
|
/* default style for tables */
|
||||||
border-top: none;
|
.table-aa > thead > tr > th{
|
||||||
border-top-left-radius: 0%;
|
border-bottom: 1px solid #f2f2f2;
|
||||||
border-top-right-radius: 0%;
|
}
|
||||||
}
|
.table-aa > thead > tr > th{
|
||||||
|
vertical-align: middle;
|
||||||
/* style group headers within a table */
|
}
|
||||||
.template-light-mode .tr-group {
|
.table-aa > tbody > tr > td{
|
||||||
font-weight: bold;
|
border-bottom: 1px solid #f2f2f2;
|
||||||
background-color: #e6e6e6 !important;
|
}
|
||||||
}
|
.table-aa > tbody > tr > td {
|
||||||
.template-dark-mode .tr-group {
|
vertical-align: middle;
|
||||||
font-weight: bold;
|
}
|
||||||
background-color: rgb(105, 105, 105) !important;
|
.table-aa > tbody > tr:last-child {
|
||||||
}
|
border-bottom: none;
|
||||||
|
|
||||||
/* default style for tables */
|
|
||||||
.template-light-mode .table-aa > thead > tr > th{
|
|
||||||
border-bottom: 1px solid #f2f2f2;
|
|
||||||
}
|
|
||||||
.template-dark-mode .table-aa > thead > tr > th{
|
|
||||||
border-bottom: 1px solid rgb(70, 69, 69);
|
|
||||||
}
|
|
||||||
.table-aa > thead > tr > th{
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.template-light-mode .table-aa > tbody > tr > td{
|
|
||||||
border-bottom: 1px solid #f2f2f2;
|
|
||||||
}
|
|
||||||
.template-dark-mode .table-aa > tbody > tr > td{
|
|
||||||
border-bottom: 1px solid rgb(70, 69, 69);
|
|
||||||
}
|
|
||||||
.table-aa > tbody > tr > td {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.table-aa > tbody > tr:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* highlight active menu items
|
/* highlight active menu items
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* global notificationUPdateSettings */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This script refreshed the unread notification count in the top menu
|
This script refreshed the unread notification count in the top menu
|
||||||
on a regular basis so to keep the user apprised about newly arrived
|
on a regular basis so to keep the user apprised about newly arrived
|
||||||
@@ -6,70 +8,67 @@
|
|||||||
The refresh rate can be changes via the Django setting NOTIFICATIONS_REFRESH_TIME.
|
The refresh rate can be changes via the Django setting NOTIFICATIONS_REFRESH_TIME.
|
||||||
See documentation for details.
|
See documentation for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
var elem = document.getElementById("dataExport");
|
'use strict';
|
||||||
var notificationsListViewUrl = elem.getAttribute("data-notificationsListViewUrl");
|
|
||||||
var notificationsRefreshTime = elem.getAttribute("data-notificationsRefreshTime");
|
let notificationsListViewUrl = notificationUPdateSettings.notificationsListViewUrl;
|
||||||
var userNotificationsCountViewUrl = elem.getAttribute(
|
let notificationsRefreshTime = notificationUPdateSettings.notificationsRefreshTime;
|
||||||
"data-userNotificationsCountViewUrl"
|
let userNotificationsCountViewUrl = notificationUPdateSettings.userNotificationsCountViewUrl;
|
||||||
);
|
|
||||||
|
|
||||||
// update the notification unread count in the top menu
|
// update the notification unread count in the top menu
|
||||||
function update_notifications() {
|
let updateNotifications = function () {
|
||||||
$.getJSON(userNotificationsCountViewUrl, function (data, status) {
|
$.getJSON(userNotificationsCountViewUrl, function (data, status) {
|
||||||
if (status == 'success') {
|
if (status === 'success') {
|
||||||
var innerHtml = "";
|
let innerHtml = '';
|
||||||
var unread_count = data.unread_count;
|
let unreadCount = data.unread_count;
|
||||||
if (unread_count > 0) {
|
|
||||||
|
if (unreadCount > 0) {
|
||||||
innerHtml = (
|
innerHtml = (
|
||||||
`Notifications <span class="badge">${unread_count}</span>`
|
`Notifications <span class="badge">${unreadCount}</span>`
|
||||||
)
|
);
|
||||||
|
} else {
|
||||||
|
innerHtml = '<i class="far fa-bell"></i>';
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
innerHtml = '<i class="far fa-bell"></i>'
|
$('#menu_item_notifications').html(
|
||||||
}
|
|
||||||
$("#menu_item_notifications").html(
|
|
||||||
`<a href="${notificationsListViewUrl}">${innerHtml}</a>`
|
`<a href="${notificationsListViewUrl}">${innerHtml}</a>`
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
console.error(
|
console.error(
|
||||||
`Failed to load HTMl to render notifications item. Error: `
|
`Failed to load HTMl to render notifications item. Error: ${xhr.status}': '${xhr.statusText}`
|
||||||
`${xhr.status}': '${xhr.statusText}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
var myInterval;
|
let myInterval;
|
||||||
|
|
||||||
// activate automatic refreshing every x seconds
|
// activate automatic refreshing every x seconds
|
||||||
function activate_refreshing() {
|
let activateRefreshing = function () {
|
||||||
if (notificationsRefreshTime > 0) {
|
if (notificationsRefreshTime > 0) {
|
||||||
myInterval = setInterval(
|
myInterval = setInterval(
|
||||||
update_notifications, notificationsRefreshTime * 1000
|
updateNotifications, notificationsRefreshTime * 1000
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// deactivate automatic refreshing
|
// deactivate automatic refreshing
|
||||||
function deactivate_refreshing() {
|
let deactivateRefreshing = function () {
|
||||||
if ((notificationsRefreshTime > 0) && (typeof myInterval !== 'undefined')) {
|
if ((notificationsRefreshTime > 0) && (typeof myInterval !== 'undefined')) {
|
||||||
clearInterval(myInterval)
|
clearInterval(myInterval);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// refreshing only happens on active browser tab
|
// refreshing only happens on active browser tab
|
||||||
$(document).on({
|
$(document).on({
|
||||||
'show': function () {
|
'show': function () {
|
||||||
activate_refreshing()
|
activateRefreshing();
|
||||||
},
|
},
|
||||||
'hide': function () {
|
'hide': function () {
|
||||||
deactivate_refreshing()
|
deactivateRefreshing();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initial start of refreshing on script loading
|
// Initial start of refreshing on script loading
|
||||||
activate_refreshing()
|
activateRefreshing();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,23 +1,49 @@
|
|||||||
|
/* global moment */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a duration string like countdown.js
|
* Get a duration string like countdown.js
|
||||||
* e.g. "1y 2d 3h 4m 5s"
|
* e.g. "1y 2d 3h 4m 5s"
|
||||||
* @param duration moment.duration
|
*
|
||||||
*/
|
* @param duration
|
||||||
function getDurationString(duration) {
|
* @returns {string}
|
||||||
var out = "";
|
*/
|
||||||
|
let getDurationString = function (duration) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let out = '';
|
||||||
|
|
||||||
if (duration.years()) {
|
if (duration.years()) {
|
||||||
out += duration.years() + 'y ';
|
out += duration.years() + 'y ';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duration.months()) {
|
if (duration.months()) {
|
||||||
out += duration.months() + 'm ';
|
out += duration.months() + 'm ';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duration.days()) {
|
if (duration.days()) {
|
||||||
out += duration.days() + 'd ';
|
out += duration.days() + 'd ';
|
||||||
}
|
}
|
||||||
return out + duration.hours() + "h " + duration.minutes() + "m " + duration.seconds() + "s";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return out + duration.hours() + 'h ' + duration.minutes() + 'm ' + duration.seconds() + 's';
|
||||||
|
};
|
||||||
|
|
||||||
function getCurrentEveTimeString() {
|
/**
|
||||||
return moment().utc().format('dddd LL HH:mm:ss')
|
* returns the current eve time as a formatted string
|
||||||
}
|
*
|
||||||
|
* condition:
|
||||||
|
* only if moment.js is loaded before,
|
||||||
|
* if not this function returns an empty string to avoid JS errors from happening.
|
||||||
|
*
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
let getCurrentEveTimeString = function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let returnValue = '';
|
||||||
|
|
||||||
|
if (window.moment) {
|
||||||
|
returnValue = moment().utc().format('dddd LL HH:mm:ss');
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
};
|
||||||
|
|||||||
2
allianceauth/static/robots.txt
Normal file
2
allianceauth/static/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow: /
|
||||||
@@ -46,19 +46,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<!-- share data with JS part -->
|
|
||||||
<div
|
|
||||||
id="dataExport"
|
|
||||||
data-notificationsListViewUrl="{% url 'notifications:list' %}"
|
|
||||||
data-notificationsRefreshTime="{% notifications_refresh_time %}"
|
|
||||||
data-userNotificationsCountViewUrl="{% url 'notifications:user_notifications_count' request.user.pk %}"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
{% include 'bundles/bootstrap-js.html' %}
|
{% include 'bundles/bootstrap-js.html' %}
|
||||||
{% include 'bundles/jquery-visibility-js.html' %}
|
{% include 'bundles/jquery-visibility-js.html' %}
|
||||||
|
|
||||||
|
<script type="application/javascript">
|
||||||
|
let notificationUPdateSettings = {
|
||||||
|
notificationsListViewUrl: "{% url 'notifications:list' %}",
|
||||||
|
notificationsRefreshTime: "{% notifications_refresh_time %}",
|
||||||
|
userNotificationsCountViewUrl: "{% url 'notifications:user_notifications_count' request.user.pk %}"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
<script src="{% static 'js/refresh_notifications.js' %}"></script>
|
<script src="{% static 'js/refresh_notifications.js' %}"></script>
|
||||||
|
|
||||||
{% block extra_javascript %}
|
{% block extra_javascript %}
|
||||||
{% endblock extra_javascript %}
|
{% endblock extra_javascript %}
|
||||||
<script>
|
<script>
|
||||||
{% block extra_script %}
|
{% block extra_script %}
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ def _current_notifications() -> dict:
|
|||||||
_fetch_notification_issues_from_gitlab,
|
_fetch_notification_issues_from_gitlab,
|
||||||
NOTIFICATION_CACHE_TIME
|
NOTIFICATION_CACHE_TIME
|
||||||
)
|
)
|
||||||
except requests.HTTPError:
|
except requests.RequestException:
|
||||||
logger.warning('Error while getting gitlab notifications', exc_info=True)
|
logger.exception('Error while getting gitlab notifications')
|
||||||
top_notifications = []
|
top_notifications = []
|
||||||
else:
|
else:
|
||||||
if notifications:
|
if notifications:
|
||||||
@@ -95,8 +95,8 @@ def _current_version_summary() -> dict:
|
|||||||
tags = cache.get_or_set(
|
tags = cache.get_or_set(
|
||||||
'git_release_tags', _fetch_tags_from_gitlab, TAG_CACHE_TIME
|
'git_release_tags', _fetch_tags_from_gitlab, TAG_CACHE_TIME
|
||||||
)
|
)
|
||||||
except requests.HTTPError:
|
except requests.RequestException:
|
||||||
logger.warning('Error while getting gitlab release tags', exc_info=True)
|
logger.exception('Error while getting gitlab release tags')
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
if not tags:
|
if not tags:
|
||||||
|
|||||||
18
allianceauth/timerboard/migrations/0004_django_3_2_compat.py
Normal file
18
allianceauth/timerboard/migrations/0004_django_3_2_compat.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.2 on 2021-04-07 16:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('timerboard', '0003_on_delete'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='timer',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -526,9 +526,7 @@
|
|||||||
{% include 'bundles/moment-js.html' with locale=True %}
|
{% include 'bundles/moment-js.html' with locale=True %}
|
||||||
<script src="{% static 'js/timers.js' %}"></script>
|
<script src="{% static 'js/timers.js' %}"></script>
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
var locale = "{{ LANGUAGE_CODE }}";
|
let timers = [
|
||||||
|
|
||||||
var timers = [
|
|
||||||
{% for timer in timers %}
|
{% for timer in timers %}
|
||||||
{
|
{
|
||||||
'id': {{ timer.id }},
|
'id': {{ timer.id }},
|
||||||
@@ -545,67 +543,64 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
];
|
];
|
||||||
|
|
||||||
moment.locale(locale);
|
/**
|
||||||
|
* Update a timer
|
||||||
|
* @param timer Timer information
|
||||||
|
*/
|
||||||
|
let updateTimer = function (timer) {
|
||||||
|
if (timer.targetDate.isAfter(Date.now())) {
|
||||||
|
let duration = moment.duration(timer.targetDate - moment(), 'milliseconds');
|
||||||
|
|
||||||
// Set initial values
|
document.getElementById("countdown" + timer.id).innerHTML = getDurationString(duration);
|
||||||
setAllLocalTimes();
|
} else {
|
||||||
timedUpdate();
|
timer.expired = true;
|
||||||
|
|
||||||
// Start timed updates
|
document.getElementById("countdown" + timer.id).innerHTML = "";
|
||||||
setInterval(timedUpdate, 1000);
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let updateAllTimers = function () {
|
||||||
|
let l = timers.length;
|
||||||
|
|
||||||
|
for (var i=0; i < l; ++i) {
|
||||||
|
if (timers[i].expired) continue;
|
||||||
|
|
||||||
|
updateTimer(timers[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function timedUpdate() {
|
function timedUpdate() {
|
||||||
updateClock();
|
updateClock();
|
||||||
updateAllTimers();
|
updateAllTimers();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAllTimers () {
|
|
||||||
var l = timers.length;
|
|
||||||
for (var i=0; i < l; ++i) {
|
|
||||||
if (timers[i].expired) continue;
|
|
||||||
updateTimer(timers[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a timer
|
* Set the local time info for the timer
|
||||||
* @param timer Timer information
|
* @param timer Timer information
|
||||||
* @param timer.targetDate Date of the timer
|
|
||||||
* @param timer.id Id number of the timer
|
|
||||||
* @param timer.expired
|
|
||||||
*/
|
*/
|
||||||
function updateTimer(timer) {
|
let setLocalTime = function (timer) {
|
||||||
if (timer.targetDate.isAfter(Date.now())) {
|
document.getElementById("localtime" + timer.id).innerHTML = timer.targetDate.format("ddd @ LT");
|
||||||
duration = moment.duration(timer.targetDate - moment(), 'milliseconds');
|
};
|
||||||
document.getElementById("countdown" + timer.id).innerHTML = getDurationString(duration);
|
|
||||||
} else {
|
|
||||||
timer.expired = true;
|
|
||||||
document.getElementById("countdown" + timer.id).innerHTML = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set all local time fields
|
* Set all local time fields
|
||||||
*/
|
*/
|
||||||
function setAllLocalTimes() {
|
let setAllLocalTimes = function () {
|
||||||
var l = timers.length;
|
let l = timers.length;
|
||||||
|
|
||||||
for (var i=0; i < l; ++i) {
|
for (var i=0; i < l; ++i) {
|
||||||
setLocalTime(timers[i]);
|
setLocalTime(timers[i]);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
let updateClock = function () {
|
||||||
* Set the local time info for the timer
|
|
||||||
* @param timer Timer information
|
|
||||||
* @param timer.targetDate Date of the timer
|
|
||||||
* @param timer.id Id number of the timer
|
|
||||||
*/
|
|
||||||
function setLocalTime(timer) {
|
|
||||||
document.getElementById("localtime" + timer.id).innerHTML = timer.targetDate.format("ddd @ LT");
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateClock() {
|
|
||||||
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
||||||
}
|
};
|
||||||
|
// Set initial values
|
||||||
|
setAllLocalTimes();
|
||||||
|
timedUpdate();
|
||||||
|
|
||||||
|
// Start timed updates
|
||||||
|
setInterval(timedUpdate, 1000);
|
||||||
</script>
|
</script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ DISCORD_SYNC_NAMES = False
|
|||||||
|
|
||||||
CELERYBEAT_SCHEDULE['discord.update_all_usernames'] = {
|
CELERYBEAT_SCHEDULE['discord.update_all_usernames'] = {
|
||||||
'task': 'discord.update_all_usernames',
|
'task': 'discord.update_all_usernames',
|
||||||
'schedule': crontab(minute=0, hour='*/12'),
|
'schedule': crontab(hour='*/12'),
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -45,17 +45,25 @@ Place your virtual host configuration in the appropriate section within `/etc/ht
|
|||||||
```
|
```
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
ServerName auth.example.com
|
ServerName auth.example.com
|
||||||
|
|
||||||
ProxyPassMatch ^/static !
|
ProxyPassMatch ^/static !
|
||||||
|
ProxyPassMatch ^/robots.txt !
|
||||||
|
|
||||||
ProxyPass / http://127.0.0.1:8000/
|
ProxyPass / http://127.0.0.1:8000/
|
||||||
ProxyPassReverse / http://127.0.0.1:8000/
|
ProxyPassReverse / http://127.0.0.1:8000/
|
||||||
ProxyPreserveHost On
|
ProxyPreserveHost On
|
||||||
|
|
||||||
Alias "/static" "/var/www/myauth/static"
|
Alias "/static" "/var/www/myauth/static"
|
||||||
|
Alias "/robots.txt" "/var/www/myauth/static/robots.txt"
|
||||||
|
|
||||||
<Directory "/var/www/myauth/static">
|
<Directory "/var/www/myauth/static">
|
||||||
Require all granted
|
Require all granted
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
|
<Location "/robots.txt">
|
||||||
|
SetHandler None
|
||||||
|
Require all granted
|
||||||
|
</Location>
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,10 @@ server {
|
|||||||
autoindex off;
|
autoindex off;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /robots.txt {
|
||||||
|
alias /var/www/myauth/static/robots.txt;
|
||||||
|
}
|
||||||
|
|
||||||
# Gunicorn config goes below
|
# Gunicorn config goes below
|
||||||
location / {
|
location / {
|
||||||
include proxy_params;
|
include proxy_params;
|
||||||
|
|||||||
@@ -18,12 +18,17 @@ To run AA with a newer Python 3 version than your system's default you need to i
|
|||||||
|
|
||||||
```eval_rst
|
```eval_rst
|
||||||
.. note::
|
.. note::
|
||||||
For stability and performance we currently recommend to run AA with Python 3.7. Since at the time of writing Python 3.7 was not available for CentOS through yum install this guide will upgrade to Python 3.6. For Ubuntu one can just replace "3.6" with "3.7" in the installation commands to get Python 3.7.
|
For stability and performance we currently recommend to run AA with Python 3.7. It has proven to be the fastest and most stable version in use currently.
|
||||||
```
|
```
|
||||||
|
|
||||||
To install other Python versions than come with your distro you need to add a new installation repository. Then you can install the specific Python 3 to your system.
|
To install other Python versions than those included with your distribution, you need to add a new installation repository. Then you can install the specific Python 3 to your system.
|
||||||
|
|
||||||
Ubuntu:
|
Ubuntu 1604 1804:
|
||||||
|
|
||||||
|
```eval_rst
|
||||||
|
.. note::
|
||||||
|
Ubuntu 2004 ships with Python 3.8, No updates required.
|
||||||
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
add-apt-repository ppa:deadsnakes/ppa
|
add-apt-repository ppa:deadsnakes/ppa
|
||||||
@@ -34,23 +39,38 @@ apt-get update
|
|||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
apt-get install python3.6 python3.6-dev python3.6-venv
|
apt-get install python3.7 python3.7-dev python3.7-venv
|
||||||
```
|
```
|
||||||
|
|
||||||
CentOS:
|
CentOS 7/8:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yum install https://centos7.iuscommunity.org/ius-release.rpm
|
cd ~
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yum update
|
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yum install python36u python36u-pip python36u-devel
|
wget https://www.python.org/ftp/python/3.7.10/Python-3.7.10.tgz
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tar xvf Python-3.7.10.tgz
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd Python-3.7.10/
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./configure --enable-optimizations --enable-shared
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make altinstall
|
||||||
|
```
|
||||||
## Preparing your venv
|
## Preparing your venv
|
||||||
|
|
||||||
Before updating your venv it is important to make sure that your current installation is stable. Otherwise your new venv might not be consistent with your data, which might create problems.
|
Before updating your venv it is important to make sure that your current installation is stable. Otherwise your new venv might not be consistent with your data, which might create problems.
|
||||||
@@ -97,12 +117,6 @@ If you unsure which apps you have installed from repos check `INSTALLED_APPS` in
|
|||||||
pip list
|
pip list
|
||||||
```
|
```
|
||||||
|
|
||||||
Some AA installations might still be running an older version of django-celery-beat. We would recommend to upgrade to the current version before doing the Python update:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install -U 'django-celery-beat<2.00'
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
```
|
```
|
||||||
@@ -171,7 +185,7 @@ mv /home/allianceserver/venv/auth /home/allianceserver/venv/auth_old
|
|||||||
Now let's create our new venv with Python 3.6 and activate it:
|
Now let's create our new venv with Python 3.6 and activate it:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3.6 -m venv /home/allianceserver/venv/auth
|
python3.7 -m venv /home/allianceserver/venv/auth
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
13
setup.py
13
setup.py
@@ -22,7 +22,7 @@ install_requires = [
|
|||||||
'celery>=4.3.0,<5.0.0,!=4.4.4', # 4.4.4 is missing a dependency
|
'celery>=4.3.0,<5.0.0,!=4.4.4', # 4.4.4 is missing a dependency
|
||||||
'celery_once>=2.0.1',
|
'celery_once>=2.0.1',
|
||||||
|
|
||||||
'django>=3.1.1,<3.2.0',
|
'django>=3.1.1,<4.0.0',
|
||||||
'django-bootstrap-form',
|
'django-bootstrap-form',
|
||||||
'django-registration>=3.1',
|
'django-registration>=3.1',
|
||||||
'django-sortedm2m',
|
'django-sortedm2m',
|
||||||
@@ -58,7 +58,7 @@ setup(
|
|||||||
extras_require={
|
extras_require={
|
||||||
'testing': testing_extras
|
'testing': testing_extras
|
||||||
},
|
},
|
||||||
python_requires='~=3.6',
|
python_requires='~=3.7',
|
||||||
license='GPLv2',
|
license='GPLv2',
|
||||||
packages=['allianceauth'],
|
packages=['allianceauth'],
|
||||||
url=allianceauth.__url__,
|
url=allianceauth.__url__,
|
||||||
@@ -72,15 +72,20 @@ setup(
|
|||||||
'Environment :: Web Environment',
|
'Environment :: Web Environment',
|
||||||
'Framework :: Django',
|
'Framework :: Django',
|
||||||
'Framework :: Django :: 3.1',
|
'Framework :: Django :: 3.1',
|
||||||
|
'Framework :: Django :: 3.2',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
|
'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
|
||||||
'Operating System :: POSIX :: Linux',
|
'Operating System :: POSIX :: Linux',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.6',
|
|
||||||
'Programming Language :: Python :: 3.7',
|
'Programming Language :: Python :: 3.7',
|
||||||
'Programming Language :: Python :: 3.8',
|
'Programming Language :: Python :: 3.8',
|
||||||
|
'Programming Language :: Python :: 3.9',
|
||||||
'Topic :: Internet :: WWW/HTTP',
|
'Topic :: Internet :: WWW/HTTP',
|
||||||
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
|
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
|
||||||
],
|
],
|
||||||
|
project_urls={
|
||||||
|
'Documentation': 'https://allianceauth.readthedocs.io/',
|
||||||
|
},
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
4
tox.ini
4
tox.ini
@@ -1,16 +1,16 @@
|
|||||||
[tox]
|
[tox]
|
||||||
skipsdist = true
|
skipsdist = true
|
||||||
usedevelop = true
|
usedevelop = true
|
||||||
envlist = py{36,37,38}-{all}
|
envlist = py{37,38,39}-{all}
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
setenv =
|
setenv =
|
||||||
all: DJANGO_SETTINGS_MODULE = tests.settings_all
|
all: DJANGO_SETTINGS_MODULE = tests.settings_all
|
||||||
core: DJANGO_SETTINGS_MODULE = tests.settings_core
|
core: DJANGO_SETTINGS_MODULE = tests.settings_core
|
||||||
basepython =
|
basepython =
|
||||||
py36: python3.6
|
|
||||||
py37: python3.7
|
py37: python3.7
|
||||||
py38: python3.8
|
py38: python3.8
|
||||||
|
py39: python3.9
|
||||||
deps=
|
deps=
|
||||||
coverage
|
coverage
|
||||||
install_command = pip install -e ".[testing]" -U {opts} {packages}
|
install_command = pip install -e ".[testing]" -U {opts} {packages}
|
||||||
|
|||||||
Reference in New Issue
Block a user