Compare commits

...

49 Commits

Author SHA1 Message Date
Ariel Rin
1e9f5e6430 Version Bump 3.0.0a1 2022-02-26 06:26:36 +00:00
Ariel Rin
ceaa064e62 Merge branch 'usersettings' into 'v3.x'
Persistent User Settings

See merge request allianceauth/allianceauth!1333
2022-02-26 06:19:38 +00:00
Ariel Rin
1aad3e4512 Persistent User Settings 2022-02-26 06:19:38 +00:00
Ariel Rin
f83c3c2811 Merge branch 'ErikKalkoken/allianceauth-fix_character_names' into v3.x 2022-02-26 15:53:46 +10:00
Ariel Rin
a23ec6d318 switch new task module to new redis method 2022-02-26 15:52:15 +10:00
Ariel Rin
ecc53888bc Merge branch 'master' of https://gitlab.com/allianceauth/allianceauth into v3.x 2022-02-26 15:23:01 +10:00
Ariel Rin
e54f72091f specific known working dependency commit 2022-02-26 14:27:00 +10:00
Ariel Rin
75b5b28804 use Django-ESI 4.0.0a1, instead of Ariels branch 2022-02-20 23:24:26 +10:00
Ariel Rin
f81a2ed237 Merge branch 'django4' into 'v3.x'
dropin replace sleeksmpp with slixmpp, alter test

See merge request allianceauth/allianceauth!1399
2022-02-20 13:19:19 +00:00
Ariel Rin
49e01157e7 dropin replace sleeksmpp with slixmpp, alter test 2022-02-20 13:19:19 +00:00
Ariel Rin
28420a729e Merge branch 'html5-fixes' into 'v3.x'
[FIX] Use proper HTML5 tags instead of self-closing XML/(X)HTML tags

See merge request allianceauth/allianceauth!1398
2022-02-11 02:10:48 +00:00
Peter Pfeufer
52a4cf8d52 [FIX] Use proper HTML5 tags instead of self-closing XML/XHTML tags 2022-02-08 20:22:53 +01:00
Ariel Rin
703c2392a9 Merge branch 'django4' into 'v3.x'
v2.10.x Uplifts, DJ4, Py3.8 + More

See merge request allianceauth/allianceauth!1387
2022-02-08 13:04:45 +00:00
Ariel Rin
18c9a66437 Merge branch 'fix-ifequal-errors' into 'django4'
Fix ifequal errors

See merge request soratidus999/allianceauth!9
2022-02-06 07:16:56 +00:00
Ariel Rin
9687d57de9 Merge branch 'update-url-configs' into 'django4'
Switch to `path`, use `re_path` only when really needed

See merge request soratidus999/allianceauth!8
2022-02-06 07:16:46 +00:00
Peter Pfeufer
60c2e57d83 Fix ifequal errors 2022-02-02 16:12:43 +01:00
Peter Pfeufer
b14bff0145 We should do this properly .. 2022-02-02 15:28:36 +01:00
Peter Pfeufer
9166886665 That one slipped through the cracks ... 2022-02-02 15:27:07 +01:00
Peter Pfeufer
c74010d441 Docs updated 2022-02-02 15:25:45 +01:00
Peter Pfeufer
640a21e4db Switch to path, use re_path only when really needed 2022-02-02 15:09:48 +01:00
Ariel Rin
fd442a5735 django.conf.urls.url is deprecated 2022-02-02 21:56:01 +10:00
Ariel Rin
c7b99044bc django.conf.urls.url is deprecated, more to fix 2022-02-02 21:39:37 +10:00
Ariel Rin
234451a7d4 temporarily use django-esi MR 2022-02-02 21:37:01 +10:00
Ariel Rin
ffff904ab1 Pull specific commit from git temporarily 2022-02-02 15:18:20 +10:00
Ariel Rin
d71a26220c Merge branch 'v3.x' of https://gitlab.com/allianceauth/allianceauth into django4 2022-02-02 14:24:47 +10:00
Ariel Rin
beeeb8dc5d Merge branch 'v3.x' of https://gitlab.com/allianceauth/allianceauth into v3.x 2022-02-02 14:17:15 +10:00
Ariel Rin
19244cc4c6 Merge branch 'master' of https://gitlab.com/allianceauth/allianceauth into v3.x 2022-02-02 14:16:46 +10:00
Ariel Rin
cc94ba6b5e ensure latest django patch 2022-02-02 14:16:33 +10:00
Ariel Rin
c9926cc877 Merge tag 'v2.10.0' of https://gitlab.com/allianceauth/allianceauth into django4 2022-02-02 14:15:32 +10:00
Ariel Rin
1d14e1b0af Merge branch 'rediscache' into 'v3.x'
Swap the Redis Cache client

See merge request allianceauth/allianceauth!1394
2022-02-02 04:12:04 +00:00
Aaron Kable
297da44a5a Swap the Redis Cache client 2022-02-02 04:12:04 +00:00
Ariel Rin
402ff53a5c Merge branch 'master' of https://gitlab.com/allianceauth/allianceauth into django4 2022-02-02 12:38:24 +10:00
ErikKalkoken
2d6e4a0df1 Merge branch 'master' into fix_character_names 2022-02-01 00:31:25 +01:00
ErikKalkoken
defcfa3316 Character names are not unique 2022-01-05 19:47:15 +01:00
ErikKalkoken
3209b71b0a Fix imports and flake8 issues 2022-01-05 19:28:44 +01:00
Ariel Rin
80b3ca0a1e Merge branch 'v2.10.x' of https://gitlab.com/allianceauth/allianceauth into django4 2021-12-29 16:35:37 +10:00
Ariel Rin
8351bd2fa3 Forgot to remove a 3.7 test 2021-12-29 16:34:14 +10:00
Ariel Rin
255966ed3b Secret Detection was split from SAST 2021-12-29 16:32:42 +10:00
Ariel Rin
8d6ebf4770 Merge branch 'v2.10.x' of https://gitlab.com/allianceauth/allianceauth into django4 2021-12-29 15:52:39 +10:00
Ariel Rin
2ca752bf78 Merge branch 'master' of https://gitlab.com/allianceauth/allianceauth into django4 2021-12-29 15:52:01 +10:00
Ariel Rin
79e1192f67 Update Pre-Commit 2021-12-29 15:45:33 +10:00
Ariel Rin
ff610efc84 Merge branch 'master' of https://gitlab.com/allianceauth/allianceauth into v2.10.x 2021-12-28 21:58:38 +10:00
Ariel Rin
6b68a739ef Initial spam of version bumps 2021-12-24 17:43:15 +10:00
Ariel Rin
909bd0ba15 Fix deprecations removed in dj4 2021-12-24 17:42:53 +10:00
Ariel Rin
05110abc59 remove 3.7 testing 2021-12-24 16:25:29 +10:00
Ariel Rin
a64d99eb91 Target Py3.8 2021-12-24 14:48:30 +10:00
Ariel Rin
0e45403195 Merge branch 'master' of https://gitlab.com/allianceauth/allianceauth into v2.10.x 2021-12-24 14:41:09 +10:00
Ariel Rin
e16a9ffe65 update pre-commit 2021-12-24 14:26:15 +10:00
Ariel Rin
57de122ef8 Move away frfom 3.6 even for pre-commit 2021-12-24 14:23:41 +10:00
103 changed files with 773 additions and 355 deletions

View File

@@ -14,6 +14,7 @@ stages:
include:
- template: Dependency-Scanning.gitlab-ci.yml
- template: Security/SAST.gitlab-ci.yml
- template: Security/Secret-Detection.gitlab-ci.yml
before_script:
- apt-get update && apt-get install redis-server -y
@@ -24,7 +25,7 @@ before_script:
pre-commit-check:
<<: *only-default
stage: pre-commit
image: python:3.6-buster
image: python:3.8-bullseye
variables:
PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
cache:
@@ -46,16 +47,6 @@ dependency_scanning:
- python -V
- pip install wheel tox
test-3.7-core:
<<: *only-default
image: python:3.7-bullseye
script:
- tox -e py37-core
artifacts:
when: always
reports:
cobertura: coverage.xml
test-3.8-core:
<<: *only-default
image: python:3.8-bullseye
@@ -97,16 +88,6 @@ test-3.11-core:
cobertura: coverage.xml
allow_failure: true
test-3.7-all:
<<: *only-default
image: python:3.7-bullseye
script:
- tox -e py37-all
artifacts:
when: always
reports:
cobertura: coverage.xml
test-3.8-all:
<<: *only-default
image: python:3.8-bullseye

View File

@@ -5,7 +5,7 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
rev: v4.1.0
hooks:
- id: check-case-conflict
- id: check-json
@@ -22,13 +22,13 @@ repos:
args: [ '--remove' ]
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
rev: 2.3.54
rev: 2.4.0
hooks:
- id: editorconfig-checker
exclude: ^(LICENSE|allianceauth\/static\/css\/themes\/bootstrap-locals.less|allianceauth\/eveonline\/swagger.json|(.*.po)|(.*.mo))
- repo: https://github.com/asottile/pyupgrade
rev: v2.29.0
rev: v2.30.0
hooks:
- id: pyupgrade
args: [ --py37-plus ]
args: [ --py38-plus ]

View File

@@ -1,7 +1,7 @@
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
__version__ = '2.10.0'
__version__ = '3.0.0a1'
__title__ = 'Alliance Auth'
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
NAME = f'{__title__} v{__version__}'

View File

@@ -1,5 +1,6 @@
from allianceauth.analytics.middleware import AnalyticsMiddleware
from unittest.mock import Mock
from django.http import HttpResponse
from django.test.testcases import TestCase
@@ -7,7 +8,7 @@ from django.test.testcases import TestCase
class TestAnalyticsMiddleware(TestCase):
def setUp(self):
self.middleware = AnalyticsMiddleware()
self.middleware = AnalyticsMiddleware(HttpResponse)
self.request = Mock()
self.request.headers = {
"User-Agent": "AUTOMATED TEST"

View File

@@ -13,8 +13,12 @@ from django.utils.html import format_html
from django.urls import reverse
from django.utils.text import slugify
from allianceauth.authentication.models import State, get_guest_state,\
CharacterOwnership, UserProfile, OwnershipRecord
from allianceauth.authentication.models import (
State,
get_guest_state,
CharacterOwnership,
UserProfile,
OwnershipRecord)
from allianceauth.hooks import get_hooks
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo,\
EveAllianceInfo, EveFactionInfo

View File

@@ -1,5 +1,5 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from allianceauth.authentication.models import User
class RegistrationForm(forms.Form):
email = forms.EmailField(label=_('Email'), max_length=254, required=True)

View File

@@ -1,14 +1,16 @@
from django.conf.urls import url, include
from django.conf.urls import include
from allianceauth.authentication import views
from django.urls import re_path
from django.urls import path
urlpatterns = [
url(r'^activate/complete/$', views.activation_complete, name='registration_activation_complete'),
path('activate/complete/', views.activation_complete, name='registration_activation_complete'),
# The activation key can make use of any character from the
# URL-safe base64 alphabet, plus the colon as a separator.
url(r'^activate/(?P<activation_key>[-:\w]+)/$', views.ActivationView.as_view(), name='registration_activate'),
url(r'^register/$', views.RegistrationView.as_view(), name='registration_register'),
url(r'^register/complete/$', views.registration_complete, name='registration_complete'),
url(r'^register/closed/$', views.registration_closed, name='registration_disallowed'),
url(r'', include('django.contrib.auth.urls')),
re_path(r'^activate/(?P<activation_key>[-:\w]+)/$', views.ActivationView.as_view(), name='registration_activate'),
path('register/', views.RegistrationView.as_view(), name='registration_register'),
path('register/complete/', views.registration_complete, name='registration_complete'),
path('register/closed/', views.registration_closed, name='registration_disallowed'),
path('', include('django.contrib.auth.urls')),
]

View File

@@ -0,0 +1,45 @@
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
import logging
logger = logging.getLogger(__name__)
class UserSettingsMiddleware(MiddlewareMixin):
def process_response(self, request, response):
"""Django Middleware: User Settings."""
# Intercept the built in django /setlang/ view and also save it to Database.
# Note the annoymous user check, only logged in users will ever hit the DB here
if request.path == '/i18n/setlang/' and not request.user.is_anonymous:
try:
request.user.profile.language = request.POST['language']
request.user.profile.save()
except Exception as e:
logger.exception(e)
# Only act during the login flow, _after_ user is activated (step 2: post-sso)
elif request.path == '/sso/login' and not request.user.is_anonymous:
# Set the Language Cookie, if it doesnt match the DB
# Null = hasnt been set by the user ever, dont act.
try:
if request.user.profile.language != request.LANGUAGE_CODE and request.user.profile.language is not None:
response.set_cookie(key=settings.LANGUAGE_COOKIE_NAME,
value=request.user.profile.language,
max_age=settings.LANGUAGE_COOKIE_AGE)
except Exception as e:
logger.exception(e)
# Set our Night mode flag from the DB
# Null = hasnt been set by the user ever, dont act.
#
# Night mode intercept is not needed in this middleware.
# is saved direct to DB in NightModeRedirectView
try:
if request.user.profile.night_mode is not None:
request.session["NIGHT_MODE"] = request.user.profile.night_mode
except Exception as e:
logger.exception(e)
return response

View File

@@ -0,0 +1,23 @@
# Generated by Django 4.0.2 on 2022-02-26 03:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authentication', '0019_merge_20211026_0919'),
]
operations = [
migrations.AddField(
model_name='userprofile',
name='language',
field=models.CharField(blank=True, choices=[('en', 'English'), ('de', 'German'), ('es', 'Spanish'), ('zh-hans', 'Chinese Simplified'), ('ru', 'Russian'), ('ko', 'Korean'), ('fr', 'French'), ('ja', 'Japanese'), ('it', 'Italian')], default='', max_length=10, verbose_name='Language'),
),
migrations.AddField(
model_name='userprofile',
name='night_mode',
field=models.BooleanField(blank=True, null=True, verbose_name='Night Mode'),
),
]

View File

@@ -2,9 +2,10 @@ import logging
from django.contrib.auth.models import User, Permission
from django.db import models, transaction
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo, EveAllianceInfo, EveFactionInfo
from allianceauth.notifications import notify
from django.conf import settings
from .managers import CharacterOwnershipManager, StateManager
@@ -62,9 +63,39 @@ class UserProfile(models.Model):
class Meta:
default_permissions = ('change',)
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE)
main_character = models.OneToOneField(EveCharacter, blank=True, null=True, on_delete=models.SET_NULL)
state = models.ForeignKey(State, on_delete=models.SET_DEFAULT, default=get_guest_state_pk)
user = models.OneToOneField(
User,
related_name='profile',
on_delete=models.CASCADE)
main_character = models.OneToOneField(
EveCharacter,
blank=True,
null=True,
on_delete=models.SET_NULL)
state = models.ForeignKey(
State,
on_delete=models.SET_DEFAULT,
default=get_guest_state_pk)
LANGUAGE_CHOICES = [
('en', _('English')),
('de', _('German')),
('es', _('Spanish')),
('zh-hans', _('Chinese Simplified')),
('ru', _('Russian')),
('ko', _('Korean')),
('fr', _('French')),
('ja', _('Japanese')),
('it', _('Italian')),
]
language = models.CharField(
_("Language"), max_length=10,
choices=LANGUAGE_CHOICES,
blank=True,
default='')
night_mode = models.BooleanField(
_("Night Mode"),
blank=True,
null=True)
def assign_state(self, state=None, commit=True):
if not state:
@@ -93,8 +124,6 @@ class UserProfile(models.Model):
def __str__(self):
return str(self.user)
class CharacterOwnership(models.Model):
class Meta:
default_permissions = ('change', 'delete')

View File

@@ -1,6 +1,11 @@
import logging
from .models import CharacterOwnership, UserProfile, get_guest_state, State, OwnershipRecord
from .models import (
CharacterOwnership,
UserProfile,
get_guest_state,
State,
OwnershipRecord)
from django.contrib.auth.models import User
from django.db.models import Q
from django.db.models.signals import pre_save, post_save, pre_delete, post_delete, m2m_changed
@@ -11,7 +16,7 @@ from allianceauth.eveonline.models import EveCharacter
logger = logging.getLogger(__name__)
state_changed = Signal(providing_args=['user', 'state'])
state_changed = Signal()
def trigger_state_check(state):
@@ -71,7 +76,7 @@ def reassess_on_profile_save(sender, instance, created, *args, **kwargs):
@receiver(post_save, sender=User)
def create_required_models(sender, instance, created, *args, **kwargs):
# ensure all users have a model
# ensure all users have our Sub-Models
if created:
logger.debug(f'User {instance} created. Creating default UserProfile.')
UserProfile.objects.get_or_create(user=instance)

View File

@@ -5,7 +5,7 @@ from typing import Optional, List
from redis import Redis
from pytz import utc
from django.core.cache import cache
from django_redis import get_redis_connection
_TaskCounts = namedtuple(
"_TaskCounts", ["succeeded", "retried", "failed", "total", "earliest_task", "hours"]
@@ -55,7 +55,7 @@ class EventSeries:
raise TypeError("Can not instantiate base class.")
if not hasattr(self, "KEY_ID"):
raise ValueError("KEY_ID not defined")
self._redis = cache.get_master_client() if not redis else redis
self._redis = get_redis_connection("default") if not redis else redis
if not isinstance(self._redis, Redis):
raise TypeError(
"This class requires a Redis client, but none was provided "

View File

@@ -7,8 +7,8 @@
<form class="form-signin" role="form" action="" method="POST">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Submit" %}</button>
<br/>
<br>
</form>
{% endblock %}

View File

@@ -1,4 +1,17 @@
from django.db.models.signals import (
m2m_changed,
post_save,
pre_delete,
pre_save
)
from django.urls import reverse
from unittest import mock
MODULE_PATH = 'allianceauth.authentication'
def patch(target, *args, **kwargs):
return mock.patch(f'{MODULE_PATH}{target}', *args, **kwargs)
def get_admin_change_view_url(obj: object) -> str:

View File

@@ -0,0 +1,175 @@
from unittest import mock
from allianceauth.authentication.middleware import UserSettingsMiddleware
from unittest.mock import Mock
from django.http import HttpResponse
from django.test.testcases import TestCase
class TestUserSettingsMiddlewareSaveLang(TestCase):
def setUp(self):
self.middleware = UserSettingsMiddleware(HttpResponse)
self.request = Mock()
self.request.headers = {
"User-Agent": "AUTOMATED TEST"
}
self.request.path = '/i18n/setlang/'
self.request.POST = {
'language': 'fr'
}
self.request.user.profile.language = 'de'
self.request.user.is_anonymous = False
self.response = Mock()
self.response.content = 'hello world'
def test_middleware_passthrough(self):
"""
Simply tests the middleware runs cleanly
"""
response = self.middleware.process_response(
self.request,
self.response
)
self.assertEqual(self.response, response)
def test_middleware_save_language_false_anonymous(self):
"""
Ensures the middleware wont change the usersettings
of a non-existent (anonymous) user
"""
self.request.user.is_anonymous = True
response = self.middleware.process_response(
self.request,
self.response
)
self.assertEqual(self.request.user.profile.language, 'de')
self.assertFalse(self.request.user.profile.save.called)
self.assertEqual(self.request.user.profile.save.call_count, 0)
def test_middleware_save_language_new(self):
"""
does the middleware change a language not set in the DB
"""
self.request.user.profile.language = None
response = self.middleware.process_response(
self.request,
self.response
)
self.assertEqual(self.request.user.profile.language, 'fr')
self.assertTrue(self.request.user.profile.save.called)
self.assertEqual(self.request.user.profile.save.call_count, 1)
def test_middleware_save_language_changed(self):
"""
Tests the middleware will change a language setting
"""
response = self.middleware.process_response(
self.request,
self.response
)
self.assertEqual(self.request.user.profile.language, 'fr')
self.assertTrue(self.request.user.profile.save.called)
self.assertEqual(self.request.user.profile.save.call_count, 1)
class TestUserSettingsMiddlewareLoginFlow(TestCase):
def setUp(self):
self.middleware = UserSettingsMiddleware(HttpResponse)
self.request = Mock()
self.request.headers = {
"User-Agent": "AUTOMATED TEST"
}
self.request.path = '/sso/login'
self.request.session = {
'NIGHT_MODE': False
}
self.request.LANGUAGE_CODE = 'en'
self.request.user.profile.language = 'de'
self.request.user.profile.night_mode = True
self.request.user.is_anonymous = False
self.response = Mock()
self.response.content = 'hello world'
def test_middleware_passthrough(self):
"""
Simply tests the middleware runs cleanly
"""
middleware_response = self.middleware.process_response(
self.request,
self.response
)
self.assertEqual(self.response, middleware_response)
def test_middleware_sets_language_cookie_true_no_cookie(self):
"""
tests the middleware will set a cookie, while none is set
"""
self.request.LANGUAGE_CODE = None
middleware_response = self.middleware.process_response(
self.request,
self.response
)
self.assertTrue(middleware_response.set_cookie.called)
self.assertEqual(middleware_response.set_cookie.call_count, 1)
args, kwargs = middleware_response.set_cookie.call_args
self.assertEqual(kwargs['value'], 'de')
def test_middleware_sets_language_cookie_true_wrong_cookie(self):
"""
tests the middleware will set a cookie, while a different value is set
"""
middleware_response = self.middleware.process_response(
self.request,
self.response
)
self.assertTrue(middleware_response.set_cookie.called)
self.assertEqual(middleware_response.set_cookie.call_count, 1)
args, kwargs = middleware_response.set_cookie.call_args
self.assertEqual(kwargs['value'], 'de')
def test_middleware_sets_language_cookie_false_anonymous(self):
"""
ensures the middleware wont set a value for a non existent user (anonymous)
"""
self.request.user.is_anonymous = True
middleware_response = self.middleware.process_response(
self.request,
self.response
)
self.assertFalse = middleware_response.set_cookie.called
self.assertEqual(middleware_response.set_cookie.call_count, 0)
def test_middleware_sets_language_cookie_false_already_set(self):
"""
tests the middleware skips setting the cookie, if its already set correctly
"""
self.request.user.profile.language = 'en'
middleware_response = self.middleware.process_response(
self.request,
self.response
)
self.assertFalse = middleware_response.set_cookie.called
self.assertEqual(middleware_response.set_cookie.call_count, 0)
def test_middleware_sets_night_mode_not_set(self):
"""
tests the middleware will set night_mode if not set
"""
self.request.session = {}
response = self.middleware.process_response(
self.request,
self.response
)
self.assertEqual(self.request.session["NIGHT_MODE"], True)
def test_middleware_sets_night_mode_set(self):
"""
tests the middleware will set night_mode if set.
"""
response = self.middleware.process_response(
self.request,
self.response
)
self.assertEqual(self.request.session["NIGHT_MODE"], True)

View File

@@ -0,0 +1,94 @@
from allianceauth.authentication.models import User, UserProfile
from allianceauth.eveonline.models import (
EveCharacter,
EveCorporationInfo,
EveAllianceInfo
)
from django.db.models.signals import (
pre_save,
post_save,
pre_delete,
m2m_changed
)
from allianceauth.tests.auth_utils import AuthUtils
from django.test.testcases import TestCase
from unittest.mock import Mock
from . import patch
class TestUserProfileSignals(TestCase):
def setUp(self):
state = AuthUtils.get_member_state()
self.char = EveCharacter.objects.create(
character_id='1234',
character_name='test character',
corporation_id='2345',
corporation_name='test corp',
corporation_ticker='tickr',
alliance_id='3456',
alliance_name='alliance name',
)
self.alliance = EveAllianceInfo.objects.create(
alliance_id='3456',
alliance_name='alliance name',
alliance_ticker='TIKR',
executor_corp_id='2345',
)
self.corp = EveCorporationInfo.objects.create(
corporation_id='2345',
corporation_name='corp name',
corporation_ticker='TIKK',
member_count=10,
alliance=self.alliance,
)
state.member_alliances.add(self.alliance)
state.member_corporations.add(self.corp)
self.member = AuthUtils.create_user('test user')
self.member.profile.main_character = self.char
self.member.profile.save()
@patch('.signals.create_required_models')
def test_create_required_models_triggered_true(
self, create_required_models):
"""
Create a User object here,
to generate UserProfile models
"""
post_save.connect(create_required_models, sender=User)
AuthUtils.create_user('test_create_required_models_triggered')
self.assertTrue = create_required_models.called
self.assertEqual(create_required_models.call_count, 1)
user = User.objects.get(username='test_create_required_models_triggered')
self.assertIsNot(UserProfile.objects.get(user=user), False)
@patch('.signals.create_required_models')
def test_create_required_models_triggered_false(
self, create_required_models):
"""
Only call a User object Update here,
which does not need to generate UserProfile models
"""
post_save.connect(create_required_models, sender=User)
char = EveCharacter.objects.create(
character_id='1266',
character_name='test character2',
corporation_id='2345',
corporation_name='test corp',
corporation_ticker='tickr',
alliance_id='3456',
alliance_name='alliance name',
)
self.member.profile.main_character = char
self.member.profile.save()
self.assertTrue = create_required_models.called
self.assertEqual(create_required_models.call_count, 0)
self.assertIsNot(UserProfile.objects.get(user=self.member), False)

View File

@@ -1,5 +1,4 @@
from django.conf.urls import url
from django.contrib.auth.decorators import login_required
from django.urls import path
from django.views.generic.base import TemplateView
from . import views
@@ -7,21 +6,21 @@ from . import views
app_name = 'authentication'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(
r'^account/login/$',
path('', views.index, name='index'),
path(
'account/login/',
TemplateView.as_view(template_name='public/login.html'),
name='login'
),
url(
r'^account/characters/main/$',
path(
'account/characters/main/',
views.main_character_change,
name='change_main_character'
),
url(
r'^account/characters/add/$',
path(
'account/characters/add/',
views.add_character,
name='add_character'
),
url(r'^dashboard/$', views.dashboard, name='dashboard'),
path('dashboard/', views.dashboard, name='dashboard'),
]

View File

@@ -1,5 +1,5 @@
from allianceauth.services.hooks import MenuItemHook, UrlHook
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from allianceauth import hooks
from allianceauth.corputils import urls

View File

@@ -1,12 +1,11 @@
from django.conf.urls import url
from django.urls import path
from . import views
app_name = 'corputils'
urlpatterns = [
url(r'^$', views.corpstats_view, name='view'),
url(r'^add/$', views.corpstats_add, name='add'),
url(r'^(?P<corp_id>(\d)*)/$', views.corpstats_view, name='view_corp'),
url(r'^(?P<corp_id>(\d)+)/update/$', views.corpstats_update, name='update'),
url(r'^search/$', views.corpstats_search, name='search'),
]
path('', views.corpstats_view, name='view'),
path('add/', views.corpstats_add, name='add'),
path('<int:corp_id>/', views.corpstats_view, name='view_corp'),
path('<int:corp_id>/update/', views.corpstats_update, name='update'),
path('search/', views.corpstats_search, name='search'),
]

View File

@@ -6,7 +6,7 @@ from django.contrib.auth.decorators import login_required, permission_required,
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.db import IntegrityError
from django.shortcuts import render, redirect, get_object_or_404
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from esi.decorators import token_required
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.10 on 2022-01-05 18:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('eveonline', '0015_factions'),
]
operations = [
migrations.AlterField(
model_name='evecharacter',
name='character_name',
field=models.CharField(db_index=True, max_length=254),
),
]

View File

@@ -25,6 +25,8 @@ DOOMHEIM_CORPORATION_ID = 1000001
class EveFactionInfo(models.Model):
"""A faction in Eve Online."""
faction_id = models.PositiveIntegerField(unique=True, db_index=True)
faction_name = models.CharField(max_length=254, unique=True)
@@ -66,6 +68,8 @@ class EveFactionInfo(models.Model):
class EveAllianceInfo(models.Model):
"""An alliance in Eve Online."""
alliance_id = models.PositiveIntegerField(unique=True)
alliance_name = models.CharField(max_length=254, unique=True)
alliance_ticker = models.CharField(max_length=254)
@@ -132,6 +136,8 @@ class EveAllianceInfo(models.Model):
class EveCorporationInfo(models.Model):
"""A corporation in Eve Online."""
corporation_id = models.PositiveIntegerField(unique=True)
corporation_name = models.CharField(max_length=254, unique=True)
corporation_ticker = models.CharField(max_length=254)
@@ -195,9 +201,10 @@ class EveCorporationInfo(models.Model):
class EveCharacter(models.Model):
"""Character in Eve Online"""
"""A character in Eve Online."""
character_id = models.PositiveIntegerField(unique=True)
character_name = models.CharField(max_length=254, unique=True)
character_name = models.CharField(max_length=254, db_index=True)
corporation_id = models.PositiveIntegerField()
corporation_name = models.CharField(max_length=254)
corporation_ticker = models.CharField(max_length=5)

View File

@@ -40,7 +40,7 @@ def update_character(character_id: int) -> None:
def run_model_update():
"""Update all alliances, corporations and characters from ESI"""
# update existing corp models
#update existing corp models
for corp in EveCorporationInfo.objects.all().values('corporation_id'):
update_corp.apply_async(args=[corp['corporation_id']], priority=TASK_PRIORITY)

View File

@@ -1,5 +1,5 @@
from . import urls
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from allianceauth import hooks
from allianceauth.services.hooks import MenuItemHook, UrlHook

View File

@@ -1,5 +1,5 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
class FatlinkForm(forms.Form):

View File

@@ -21,7 +21,7 @@
<form class="form-signin" role="form" action="" method="POST">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit" name="submit_fat">{% translate "Create fatlink" %}</button>
</form>
</div>

View File

@@ -1,30 +1,30 @@
from django.conf.urls import url
from django.urls import path
from . import views
app_name = 'fleetactivitytracking'
urlpatterns = [
# FleetActivityTracking (FAT)
url(r'^$', views.fatlink_view, name='view'),
url(r'^statistics/$', views.fatlink_statistics_view, name='statistics'),
url(r'^statistics/corp/(\w+)$', views.fatlink_statistics_corp_view,
path('', views.fatlink_view, name='view'),
path('statistics/', views.fatlink_statistics_view, name='statistics'),
path('statistics/corp/<int:corpid>/', views.fatlink_statistics_corp_view,
name='statistics_corp'),
url(r'^statistics/corp/(?P<corpid>\w+)/(?P<year>[0-9]+)/(?P<month>[0-9]+)/',
path('statistics/corp/<int:corpid>/<int:year>/<int:month>/',
views.fatlink_statistics_corp_view,
name='statistics_corp_month'),
url(r'^statistics/(?P<year>[0-9]+)/(?P<month>[0-9]+)/$', views.fatlink_statistics_view,
path('statistics/<int:year>/<int:month>/', views.fatlink_statistics_view,
name='statistics_month'),
url(r'^user/statistics/$', views.fatlink_personal_statistics_view,
path('user/statistics/', views.fatlink_personal_statistics_view,
name='personal_statistics'),
url(r'^user/statistics/(?P<year>[0-9]+)/$', views.fatlink_personal_statistics_view,
path('user/statistics/<int:year>/', views.fatlink_personal_statistics_view,
name='personal_statistics_year'),
url(r'^user/statistics/(?P<year>[0-9]+)/(?P<month>[0-9]+)/$',
path('user/statistics/<int:year>/<int:month>/',
views.fatlink_monthly_personal_statistics_view,
name='personal_statistics_month'),
url(r'^user/(?P<char_id>[0-9]+)/statistics/(?P<year>[0-9]+)/(?P<month>[0-9]+)/$',
path('user/<int:char_id>/statistics/<int:year>/<int:month>/',
views.fatlink_monthly_personal_statistics_view,
name='user_statistics_month'),
url(r'^create/$', views.create_fatlink_view, name='create'),
url(r'^modify/(?P<fat_hash>[a-zA-Z0-9_-]+)/$', views.modify_fatlink_view, name='modify'),
url(r'^link/(?P<fat_hash>[a-zA-Z0-9]+)/$', views.click_fatlink_view, name='click'),
path('create/', views.create_fatlink_view, name='create'),
path('modify/<str:fat_hash>/', views.modify_fatlink_view, name='modify'),
path('link/<str:fat_hash>/', views.click_fatlink_view, name='click'),
]

View File

@@ -10,7 +10,7 @@ from django.contrib.auth.models import User
from django.core.exceptions import ValidationError, ObjectDoesNotExist
from django.shortcuts import render, redirect, get_object_or_404, Http404
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from esi.decorators import token_required
from allianceauth.eveonline.providers import provider
from .forms import FatlinkForm

View File

@@ -1,4 +1,4 @@
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from allianceauth.services.hooks import MenuItemHook, UrlHook
from allianceauth import hooks

View File

@@ -1,51 +1,50 @@
from django.urls import path
from . import views
from django.conf.urls import url
app_name = "groupmanagement"
urlpatterns = [
# groups
url(r"^groups/$", views.groups_view, name="groups"),
url(r"^group/request/join/(\w+)/$", views.group_request_add, name="request_add"),
url(
r"^group/request/leave/(\w+)/$", views.group_request_leave, name="request_leave"
path("groups", views.groups_view, name="groups"),
path("group/request/join/<int:group_id>/", views.group_request_add, name="request_add"),
path(
"group/request/leave/<int:group_id>/", views.group_request_leave, name="request_leave"
),
# group management
url(r"^groupmanagement/requests/$", views.group_management, name="management"),
url(r"^groupmanagement/membership/$", views.group_membership, name="membership"),
url(
r"^groupmanagement/membership/(\w+)/$",
path("groupmanagement/requests/", views.group_management, name="management"),
path("groupmanagement/membership/", views.group_membership, name="membership"),
path(
"groupmanagement/membership/<int:group_id>/",
views.group_membership_list,
name="membership",
),
url(
r"^groupmanagement/membership/(\w+)/audit-log/$",
path(
"groupmanagement/membership/<int:group_id>/audit-log/",
views.group_membership_audit,
name="audit_log",
),
url(
r"^groupmanagement/membership/(\w+)/remove/(\w+)/$",
path(
"groupmanagement/membership/<int:group_id>/remove/<int:user_id>/",
views.group_membership_remove,
name="membership_remove",
),
url(
r"^groupmanagement/request/join/accept/(\w+)/$",
path(
"groupmanagement/request/join/accept/<int:group_request_id>/",
views.group_accept_request,
name="accept_request",
),
url(
r"^groupmanagement/request/join/reject/(\w+)/$",
path(
"groupmanagement/request/join/reject/<int:group_request_id>/",
views.group_reject_request,
name="reject_request",
),
url(
r"^groupmanagement/request/leave/accept/(\w+)/$",
path(
"groupmanagement/request/leave/accept/<int:group_request_id>/",
views.group_leave_accept_request,
name="leave_accept_request",
),
url(
r"^groupmanagement/request/leave/reject/(\w+)/$",
path(
"groupmanagement/request/leave/reject/<int:group_request_id>/",
views.group_leave_reject_request,
name="leave_reject_request",
),

View File

@@ -9,7 +9,7 @@ from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.db.models import Count
from django.http import Http404
from django.shortcuts import render, redirect, get_object_or_404
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from allianceauth.notifications import notify

View File

@@ -1,4 +1,4 @@
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from allianceauth import hooks
from allianceauth.services.hooks import MenuItemHook, UrlHook

View File

@@ -1,5 +1,5 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
class HRApplicationCommentForm(forms.Form):

View File

@@ -19,8 +19,8 @@
<div cass="text-center">{{ question.help_text }}</div>
{% endif %}
{% for choice in question.choices.all %}
<input type={% if question.multi_select == False %}"radio"{% else %}"checkbox"{% endif %} name="{{ question.pk }}" id="id_{{ question.pk }}" value="{{ choice.choice_text }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
<input type={% if question.multi_select == False %}"radio"{% else %}"checkbox"{% endif %} name="{{ question.pk }}" id="id_{{ question.pk }}" value="{{ choice.choice_text }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% empty %}
<textarea class="form-control" cols="30" id="id_{{ question.pk }}" name="{{ question.pk }}" rows="4"></textarea>
{% endfor %}

View File

@@ -181,7 +181,7 @@
<form class="form-signin" role="form" action={% url 'hrapplications:search' %} method="POST">
{% csrf_token %}
{{ search_form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Search" %}</button>
</form>
</div>

View File

@@ -67,7 +67,7 @@
<form class="form-signin" role="form" action={% url 'hrapplications:search' %} method="POST">
{% csrf_token %}
{{ search_form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Search" %}</button>
</form>
</div>

View File

@@ -140,7 +140,7 @@
<form class="form-signin" role="form" action="" method="POST">
{% csrf_token %}
{{ comment_form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Add Comment" %}</button>
</form>
</div>

View File

@@ -1,31 +1,31 @@
from django.conf.urls import url
from django.urls import path
from . import views
app_name = 'hrapplications'
urlpatterns = [
url(r'^$', views.hr_application_management_view,
path('', views.hr_application_management_view,
name="index"),
url(r'^create/$', views.hr_application_create_view,
path('create/', views.hr_application_create_view,
name="create_view"),
url(r'^create/(\d+)', views.hr_application_create_view,
path('create/<int:form_id>/', views.hr_application_create_view,
name="create_view"),
url(r'^remove/(\w+)', views.hr_application_remove,
path('remove/<int:app_id>/', views.hr_application_remove,
name="remove"),
url(r'^view/(\w+)', views.hr_application_view,
path('view/<int:app_id>/', views.hr_application_view,
name="view"),
url(r'^personal/view/(\w+)', views.hr_application_personal_view,
path('personal/view/<int:app_id>/', views.hr_application_personal_view,
name="personal_view"),
url(r'^personal/removal/(\w+)',
path('personal/removal/<int:app_id>/',
views.hr_application_personal_removal,
name="personal_removal"),
url(r'^approve/(\w+)', views.hr_application_approve,
path('approve/<int:app_id>/', views.hr_application_approve,
name="approve"),
url(r'^reject/(\w+)', views.hr_application_reject,
path('reject/<int:app_id>/', views.hr_application_reject,
name="reject"),
url(r'^search/', views.hr_application_search,
path('search/', views.hr_application_search,
name="search"),
url(r'^mark_in_progress/(\w+)', views.hr_application_mark_in_progress,
path('mark_in_progress/<int:app_id>/', views.hr_application_mark_in_progress,
name="mark_in_progress"),
]
]

View File

@@ -1,16 +1,16 @@
from django.conf.urls import url
from django.urls import path
from . import views
app_name = 'notifications'
# Notifications
urlpatterns = [
url(r'^remove_notifications/(\w+)/$', views.remove_notification, name='remove'),
url(r'^notifications/mark_all_read/$', views.mark_all_read, name='mark_all_read'),
url(r'^notifications/delete_all_read/$', views.delete_all_read, name='delete_all_read'),
url(r'^notifications/$', views.notification_list, name='list'),
url(r'^notifications/(\w+)/$', views.notification_view, name='view'),
url(
r'^user_notifications_count/(?P<user_pk>\d+)/$',
path('remove_notifications/<int:notif_id>/', views.remove_notification, name='remove'),
path('notifications/mark_all_read/', views.mark_all_read, name='mark_all_read'),
path('notifications/delete_all_read/', views.delete_all_read, name='delete_all_read'),
path('notifications/', views.notification_list, name='list'),
path('notifications/<int:notif_id>/', views.notification_view, name='view'),
path(
'user_notifications_count/<int:user_pk>/',
views.user_notifications_count,
name='user_notifications_count'
),

View File

@@ -1,5 +1,5 @@
from allianceauth.services.hooks import MenuItemHook, UrlHook
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from allianceauth import hooks
from . import urls

View File

@@ -1,5 +1,5 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from allianceauth.optimer.form_widgets import DataListWidget

View File

@@ -19,7 +19,7 @@
<form class="form-signin" role="form" action="" method="POST">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Create Fleet Operation" %}</button>
</form>
</div>

View File

@@ -21,7 +21,7 @@
<b>{% translate "Current Eve Time:" %} </b>
</div>
<strong class="label label-info text-left" id="current-time"></strong>
<br />
<br>
</div>
<h4><b>{% translate "Next Fleet Operations" %}</b></h4>

View File

@@ -24,7 +24,7 @@
<form class="form-signin" role="form" action="" method="POST">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Update Fleet Operation" %}
</button>
</form>

View File

@@ -1,12 +1,12 @@
from django.conf.urls import url
from django.urls import path
from . import views
app_name = 'optimer'
urlpatterns = [
url(r'^$', views.optimer_view, name='view'),
url(r'^add$', views.add_optimer_view, name='add'),
url(r'^(\w+)/remove$', views.remove_optimer, name='remove'),
url(r'^(\w+)/edit$', views.edit_optimer, name='edit'),
]
path('', views.optimer_view, name='view'),
path('add/', views.add_optimer_view, name='add'),
path('<int:optimer_id>/remove/', views.remove_optimer, name='remove'),
path('<int:optimer_id>/edit/', views.edit_optimer, name='edit'),
]

View File

@@ -6,7 +6,7 @@ from django.contrib.auth.decorators import permission_required
from django.shortcuts import get_object_or_404
from django.shortcuts import render, redirect
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from .form import OpForm
from .models import OpTimer, OpTimerType

View File

@@ -1,11 +1,12 @@
from django.conf.urls import url
from django.urls import re_path
from django.urls import path
from . import views
app_name = 'permissions_tool'
urlpatterns = [
url(r'^overview/$', views.permissions_overview, name='overview'),
url(r'^audit/(?P<app_label>[\w\-_]+)/(?P<model>[\w\-_]+)/(?P<codename>[\w\-_]+)/$', views.permissions_audit,
path('overview/', views.permissions_overview, name='overview'),
re_path(r'^audit/(?P<app_label>[\w\-_]+)/(?P<model>[\w\-_]+)/(?P<codename>[\w\-_]+)/$', views.permissions_audit,
name='audit'),
]

View File

@@ -68,6 +68,7 @@ BASE_DIR = os.path.dirname(PROJECT_DIR)
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'allianceauth.authentication.middleware.UserSettingsMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
@@ -172,11 +173,8 @@ MESSAGE_TAGS = {
CACHES = {
"default": {
"BACKEND": "redis_cache.RedisCache",
"LOCATION": "localhost:6379",
"OPTIONS": {
"DB": 1,
}
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1" # change the 1 here to change the database used
}
}

View File

@@ -61,6 +61,13 @@ EMAIL_HOST_PASSWORD = ''
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = ''
# Cache compression can help on bigger auths where ram starts to become an issue.
# Uncomment the following 3 lines to enable.
#CACHES["default"]["OPTIONS"] = {
# "COMPRESSOR": "django_redis.compressors.lzma.LzmaCompressor",
#}
#######################################
# Add any custom settings below here. #
#######################################

View File

@@ -1,8 +1,9 @@
from django.conf.urls import include, url
from django.conf.urls import include
from allianceauth import urls
from django.urls import re_path
urlpatterns = [
url(r'', include(urls)),
re_path(r'', include(urls)),
]
handler500 = 'allianceauth.views.Generic500Redirect'

View File

@@ -1,5 +1,5 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
class FleetFormatterForm(forms.Form):

View File

@@ -1,4 +1,5 @@
from django.conf.urls import include, url
from django.conf.urls import include
from django.urls import re_path
from django.core.exceptions import ObjectDoesNotExist
from django.template.loader import render_to_string
from django.utils.functional import cached_property
@@ -9,7 +10,6 @@ from allianceauth.hooks import get_hooks
from .models import NameFormatConfig
def get_extension_logger(name):
"""
Takes the name of a plugin/extension and generates a child logger of the extensions logger
@@ -157,7 +157,7 @@ class MenuItemHook:
class UrlHook:
def __init__(self, urls, namespace, base_url):
self.include_pattern = url(base_url, include(urls, namespace=namespace))
self.include_pattern = re_path(base_url, include(urls, namespace=namespace))
class NameFormatter:

View File

@@ -8,7 +8,7 @@ from uuid import uuid1
from redis import Redis
import requests
from django.core.cache import caches
from django_redis import get_redis_connection
from allianceauth import __title__ as AUTH_TITLE, __url__, __version__
@@ -103,8 +103,7 @@ class DiscordClient:
self._access_token = str(access_token)
self._is_rate_limited = bool(is_rate_limited)
if not redis:
default_cache = caches['default']
self._redis = default_cache.get_master_client()
self._redis = get_redis_connection("default")
if not isinstance(self._redis, Redis):
raise RuntimeError(
'This class requires a Redis client, but none was provided '

View File

@@ -85,28 +85,24 @@ class TestBasicsAndHelpers(TestCase):
client = DiscordClient(TEST_BOT_TOKEN, mock_redis, is_rate_limited=True)
self.assertTrue(client.is_rate_limited)
@patch(MODULE_PATH + '.caches')
@patch(MODULE_PATH + '.get_redis_connection')
def test_use_default_redis_if_none_provided(self, mock_caches):
my_redis = MagicMock(spec=Redis)
mock_default_cache = MagicMock(**{'get_master_client.return_value': my_redis})
my_dict = {'default': mock_default_cache}
mock_caches.__getitem__.side_effect = my_dict.__getitem__
mock_caches.return_value = my_redis
client = DiscordClient(TEST_BOT_TOKEN)
self.assertTrue(mock_default_cache.get_master_client.called)
self.assertTrue(mock_caches.called)
self.assertEqual(client._redis, my_redis)
@patch(MODULE_PATH + '.caches')
@patch(MODULE_PATH + '.get_redis_connection')
def test_raise_exception_if_default_cache_is_not_redis(self, mock_caches):
my_redis = MagicMock()
mock_default_cache = MagicMock(**{'get_master_client.return_value': my_redis})
my_dict = {'default': mock_default_cache}
mock_caches.__getitem__.side_effect = my_dict.__getitem__
mock_caches.return_value = my_redis
with self.assertRaises(RuntimeError):
DiscordClient(TEST_BOT_TOKEN)
self.assertTrue(mock_default_cache.get_master_client.called)
self.assertTrue(mock_caches.called)
@requests_mock.Mocker()

View File

@@ -14,7 +14,7 @@ from requests.exceptions import HTTPError
import requests_mock
from django.contrib.auth.models import Group, User
from django.core.cache import caches
from django_redis import get_redis_connection
from django.shortcuts import reverse
from django.test import TransactionTestCase, TestCase
from django.test.utils import override_settings
@@ -87,8 +87,7 @@ remove_guild_member_request = DiscordRequest(
def clear_cache():
default_cache = caches['default']
redis = default_cache.get_master_client()
redis = get_redis_connection('default')
redis.flushall()
logger.info('Cache flushed')

View File

@@ -1,4 +1,5 @@
from django.conf.urls import url, include
from django.conf.urls import include
from django.urls import path
from . import views
@@ -6,13 +7,13 @@ app_name = 'discord'
module_urls = [
# Discord Service Control
url(r'^activate/$', views.activate_discord, name='activate'),
url(r'^deactivate/$', views.deactivate_discord, name='deactivate'),
url(r'^reset/$', views.reset_discord, name='reset'),
url(r'^callback/$', views.discord_callback, name='callback'),
url(r'^add_bot/$', views.discord_add_bot, name='add_bot'),
path('activate/', views.activate_discord, name='activate'),
path('deactivate/', views.deactivate_discord, name='deactivate'),
path('reset/', views.reset_discord, name='reset'),
path('callback/', views.discord_callback, name='callback'),
path('add_bot/', views.discord_add_bot, name='add_bot'),
]
urlpatterns = [
url(r'^discord/', include((module_urls, app_name), namespace=app_name))
path('discord/', include((module_urls, app_name), namespace=app_name))
]

View File

@@ -1,8 +1,8 @@
from django.conf.urls import url
from django.urls import path
from . import views
urlpatterns = [
# Discourse Service Control
url(r'^discourse/sso$', views.discourse_sso, name='auth_discourse_sso'),
path('discourse/sso', views.discourse_sso, name='auth_discourse_sso'),
]

View File

@@ -1,4 +1,5 @@
from django.conf.urls import url, include
from django.conf.urls import include
from django.urls import path
app_name = 'example'
@@ -7,5 +8,5 @@ module_urls = [
]
urlpatterns = [
url(r'^example/', include((module_urls, app_name), namespace=app_name)),
path('example/', include((module_urls, app_name), namespace=app_name)),
]

View File

@@ -1,4 +1,5 @@
from django.conf.urls import url, include
from django.conf.urls import include
from django.urls import path
from . import views
@@ -6,12 +7,12 @@ app_name = 'ips4'
module_urls = [
# IPS4 Service Control
url(r'^activate/$', views.activate_ips4, name='activate'),
url(r'^deactivate/$', views.deactivate_ips4, name='deactivate'),
url(r'^reset_password/$', views.reset_ips4_password, name='reset_password'),
url(r'^set_password/$', views.set_ips4_password, name='set_password'),
path('activate/', views.activate_ips4, name='activate'),
path('deactivate/', views.deactivate_ips4, name='deactivate'),
path('reset_password/', views.reset_ips4_password, name='reset_password'),
path('set_password/', views.set_ips4_password, name='set_password'),
]
urlpatterns = [
url(r'^ips4/', include((module_urls, app_name), namespace=app_name))
path('ips4/', include((module_urls, app_name), namespace=app_name))
]

View File

@@ -3,7 +3,7 @@
<td class="text-center">{{ username }}</td>
<td class="text-center"><a href="mumble://{{ service_url }}">{{ service_url }}</a></td>
<td class="text-center">
{% ifequal username "" %}
{% if username == "" %}
<a href="{% url urls.auth_activate %}" title="Activate" class="btn btn-warning">
<span class="glyphicon glyphicon-ok"></span>
</a>
@@ -20,6 +20,6 @@
<a href="mumble://{{ connect_url }}" class="btn btn-success" title="Connect">
<span class="glyphicon glyphicon-arrow-right"></span>
</a>
{% endifequal %}
{% endif %}
</td>
</tr>

View File

@@ -1,4 +1,5 @@
from django.conf.urls import url, include
from django.conf.urls import include
from django.urls import path
from . import views
@@ -6,12 +7,12 @@ app_name = 'mumble'
module_urls = [
# Mumble service control
url(r'^activate/$', views.CreateAccountMumbleView.as_view(), name='activate'),
url(r'^deactivate/$', views.DeleteMumbleView.as_view(), name='deactivate'),
url(r'^reset_password/$', views.ResetPasswordMumbleView.as_view(), name='reset_password'),
url(r'^set_password/$', views.SetPasswordMumbleView.as_view(), name='set_password'),
path('activate/', views.CreateAccountMumbleView.as_view(), name='activate'),
path('deactivate/', views.DeleteMumbleView.as_view(), name='deactivate'),
path('reset_password/', views.ResetPasswordMumbleView.as_view(), name='reset_password'),
path('set_password/', views.SetPasswordMumbleView.as_view(), name='set_password'),
]
urlpatterns = [
url(r'^mumble/', include((module_urls, app_name), namespace=app_name))
path('mumble/', include((module_urls, app_name), namespace=app_name))
]

View File

@@ -1,5 +1,5 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
class JabberBroadcastForm(forms.Form):

View File

@@ -3,7 +3,7 @@ import random
import string
from urllib.parse import urlparse
import sleekxmpp
import slixmpp
from django.conf import settings
from ofrestapi.users import Users as ofUsers
from ofrestapi import exception
@@ -172,13 +172,13 @@ class OpenfireManager:
raise PingBotException("Unable to connect to jabber server.")
class PingBot(sleekxmpp.ClientXMPP):
class PingBot(slixmpp.ClientXMPP):
"""
A copy-paste of the example client bot from
http://sleekxmpp.com/getting_started/sendlogout.html
"""
def __init__(self, jid, password, recipient, message):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
slixmpp.ClientXMPP.__init__(self, jid, password)
self.reconnect_max_attempts = 5
self.auto_reconnect = False

View File

@@ -19,7 +19,7 @@
<form class="form-signin" role="form" action="" method="POST" onsubmit="submitbutton.disabled = true; return true;">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" name="submitbutton" type="submit">{% translate "Broadcast" %}
</button>
</form>

View File

@@ -1,4 +1,5 @@
from django.conf.urls import url, include
from django.conf.urls import include
from django.urls import path
from . import views
@@ -6,13 +7,13 @@ app_name = 'openfire'
module_urls = [
# Jabber Service Control
url(r'^activate/$', views.activate_jabber, name='activate'),
url(r'^deactivate/$', views.deactivate_jabber, name='deactivate'),
url(r'^reset_password/$', views.reset_jabber_password, name='reset_password'),
url(r'^set_password/$', views.set_jabber_password, name='set_password'),
url(r'^broadcast/$', views.jabber_broadcast_view, name='broadcast'),
path('activate/', views.activate_jabber, name='activate'),
path('deactivate/', views.deactivate_jabber, name='deactivate'),
path('reset_password/', views.reset_jabber_password, name='reset_password'),
path('set_password/', views.set_jabber_password, name='set_password'),
path('broadcast/', views.jabber_broadcast_view, name='broadcast'),
]
urlpatterns = [
url(r'^openfire/', include((module_urls, app_name), namespace=app_name)),
path('openfire/', include((module_urls, app_name), namespace=app_name)),
]

View File

@@ -1,4 +1,5 @@
from django.conf.urls import url, include
from django.conf.urls import include
from django.urls import path
from . import views
@@ -6,12 +7,12 @@ app_name = 'phpbb3'
module_urls = [
# Forum Service Control
url(r'^activate/$', views.activate_forum, name='activate'),
url(r'^deactivate/$', views.deactivate_forum, name='deactivate'),
url(r'^reset_password/$', views.reset_forum_password, name='reset_password'),
url(r'^set_password/$', views.set_forum_password, name='set_password'),
path('activate/', views.activate_forum, name='activate'),
path('deactivate/', views.deactivate_forum, name='deactivate'),
path('reset_password/', views.reset_forum_password, name='reset_password'),
path('set_password/', views.set_forum_password, name='set_password'),
]
urlpatterns = [
url(r'^phpbb3/', include((module_urls, app_name), namespace=app_name))
path('phpbb3/', include((module_urls, app_name), namespace=app_name))
]

View File

@@ -1,4 +1,5 @@
from django.conf.urls import url, include
from django.conf.urls import include
from django.urls import path
from . import views
@@ -6,12 +7,12 @@ app_name = 'smf'
module_urls = [
# SMF Service Control
url(r'^activate/$', views.activate_smf, name='activate'),
url(r'^deactivate/$', views.deactivate_smf, name='deactivate'),
url(r'^reset_password/$', views.reset_smf_password, name='reset_password'),
url(r'^set_password/$', views.set_smf_password, name='set_password'),
path('activate/', views.activate_smf, name='activate'),
path('deactivate/', views.deactivate_smf, name='deactivate'),
path('reset_password/', views.reset_smf_password, name='reset_password'),
path('set_password/', views.set_smf_password, name='set_password'),
]
urlpatterns = [
url(r'^smf/', include((module_urls, app_name), namespace=app_name)),
path('smf/', include((module_urls, app_name), namespace=app_name)),
]

View File

@@ -1,5 +1,5 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from .manager import Teamspeak3Manager

View File

@@ -5,7 +5,7 @@
<td class="text-center">{{ authinfo.teamspeak3_uid }}</td>
<td class="text-center"><a href="ts3server://{{ TEAMSPEAK3_PUBLIC_URL }}">{{ TEAMSPEAK3_PUBLIC_URL }}</a></td>
<td class="text-center">
{% ifequal authinfo.teamspeak3_uid "" %}
{% if authinfo.teamspeak3_uid == "" %}
<a href="{% url 'teamspeak3:activate' %}" title="Activate" class="btn btn-warning">
<span class="glyphicon glyphicon-ok"></span>
</a>
@@ -22,6 +22,6 @@
<a href="ts3server://{{ TEAMSPEAK3_PUBLIC_URL }}?nickname={{ authinfo.teamspeak3_uid }}" title="Connect" class="btn btn-success">
<span class="glyphicon glyphicon-arrow-right"></span>
</a>
{% endifequal %}
{% endif %}
</td>
</tr>

View File

@@ -12,11 +12,11 @@
<div class="container-fluid">
<div class="col-md-4 col-md-offset-4">
<a href="ts3server://{{ public_url }}?token={{ authinfo.teamspeak3_perm_key }}&nickname={{ authinfo.teamspeak3_uid }}" class="btn btn-primary btn-block btn-lg" title="Join">{% translate "Join Server" %}</a>
<br/>
<br>
<form class="form-signin" role="form" action="{% url 'teamspeak3:verify' %}" method="POST">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Continue" %}</button>
</form>
</div>

View File

@@ -1,4 +1,5 @@
from django.conf.urls import url, include
from django.conf.urls import include
from django.urls import path
from . import views
@@ -6,19 +7,19 @@ app_name = 'teamspeak3'
module_urls = [
# Teamspeak3 service control
url(r'^activate/$', views.activate_teamspeak3, name='activate'),
url(r'^deactivate/$', views.deactivate_teamspeak3, name='deactivate'),
url(r'^reset_perm/$', views.reset_teamspeak3_perm, name='reset_perm'),
url(
r'^admin_update_ts3_groups/$',
path('activate/', views.activate_teamspeak3, name='activate'),
path('deactivate/', views.deactivate_teamspeak3, name='deactivate'),
path('reset_perm/', views.reset_teamspeak3_perm, name='reset_perm'),
path(
'admin_update_ts3_groups/',
views.admin_update_ts3_groups,
name='admin_update_ts3_groups'
),
# Teamspeak Urls
url(r'^verify/$', views.verify_teamspeak3, name='verify'),
path('verify/', views.verify_teamspeak3, name='verify'),
]
urlpatterns = [
url(r'^teamspeak3/', include((module_urls, app_name), namespace=app_name)),
path('teamspeak3/', include((module_urls, app_name), namespace=app_name)),
]

View File

@@ -1,4 +1,5 @@
from django.conf.urls import url, include
from django.conf.urls import include
from django.urls import path
from . import views
@@ -6,12 +7,12 @@ app_name = 'xenforo'
module_urls = [
# XenForo service control
url(r'^activate/$', views.activate_xenforo_forum, name='activate'),
url(r'^deactivate/$', views.deactivate_xenforo_forum, name='deactivate'),
url(r'^reset_password/$', views.reset_xenforo_password, name='reset_password'),
url(r'^set_password/$', views.set_xenforo_password, name='set_password'),
path('activate/', views.activate_xenforo_forum, name='activate'),
path('deactivate/', views.deactivate_xenforo_forum, name='deactivate'),
path('reset_password/', views.reset_xenforo_password, name='reset_password'),
path('set_password/', views.set_xenforo_password, name='set_password'),
]
urlpatterns = [
url(r'^xenforo/', include((module_urls, app_name), namespace=app_name)),
path('xenforo/', include((module_urls, app_name), namespace=app_name)),
]

View File

@@ -20,9 +20,9 @@
<form class="form-signin" role="form" action="" method="POST">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Format" %}</button>
<br/>
<br>
</form>
</div>
</div>

View File

@@ -21,7 +21,7 @@
Are you sure you want to delete your {{ service_name }} account {{ object }}?
{% endblocktrans %}
</p>
<input class="btn btn-danger btn-block" type="submit" value="Confirm" />
<input class="btn btn-danger btn-block" type="submit" value="Confirm">
</form>
</div>
</div>

View File

@@ -14,7 +14,7 @@
<form class="form-signin" role="form" action="" method="POST" onsubmit="submitbutton.disabled = true; return true;">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" name="submitbutton" type="submit">{% translate "Set Password" %}</button>
</form>
</div>

View File

@@ -5,7 +5,7 @@
<td class="text-center">{{ username }}</td>
<td class="text-center"><a href="{{ service_url }}">{{ service_url }}</a></td>
<td class="text-center">
{% ifequal username "" %}
{% if username == "" %}
{% if urls.auth_activate %}
<a href="{% url urls.auth_activate %}" title="Activate" class="btn btn-warning">
<span class="glyphicon glyphicon-ok"></span>
@@ -27,6 +27,6 @@
<span class="glyphicon glyphicon-remove"></span>
</a>
{% endif %}
{% endifequal %}
{% endif %}
</td>
</tr>

View File

@@ -1,14 +1,15 @@
from django.conf.urls import include, url
from django.conf.urls import include
from allianceauth.hooks import get_hooks
from django.urls import path
from . import views
urlpatterns = [
# Services
url(r'^services/', include(([
url(r'^$', views.services_view, name='services'),
path('services/', include(([
path('', views.services_view, name='services'),
# Tools
url(r'^tool/fleet_formatter_tool/$', views.fleet_formatter_view, name='fleet_format_tool'),
path('tool/fleet_formatter_tool/', views.fleet_formatter_view, name='fleet_format_tool'),
], 'services'), namespace='services')),
]

View File

@@ -1,4 +1,4 @@
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from allianceauth import hooks
from allianceauth.services.hooks import MenuItemHook, UrlHook

View File

@@ -1,7 +1,7 @@
import re
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
class SrpFleetMainForm(forms.Form):

View File

@@ -20,7 +20,7 @@
<form class="form-signin" role="form" action="" method="POST">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Create SRP Fleet" %}</button>
</form>
{% else %}

View File

@@ -16,7 +16,7 @@
<form class="form-signin" role="form" action="" method="POST">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Create SRP Request" %}
</button>
</form>

View File

@@ -19,7 +19,7 @@
<form class="form-signin" role="form" action="" method="POST">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Update AAR Link" %}
</button>
</form>

View File

@@ -1,4 +1,4 @@
from django.conf.urls import url
from django.urls import path
from . import views
@@ -6,27 +6,27 @@ app_name = 'srp'
urlpatterns = [
# SRP URLS
url(r'^$', views.srp_management, name='management'),
url(r'^all/$', views.srp_management, {'all': True}, name='all'),
url(r'^(\w+)/view$', views.srp_fleet_view, name='fleet'),
url(r'^add/$', views.srp_fleet_add_view, name='add'),
url(r'^(\w+)/edit$', views.srp_fleet_edit_view, name='edit'),
url(r'^(\w+)/request', views.srp_request_view, name='request'),
path('', views.srp_management, name='management'),
path('all/', views.srp_management, {'all': True}, name='all'),
path('<int:fleet_id>/view/', views.srp_fleet_view, name='fleet'),
path('add/', views.srp_fleet_add_view, name='add'),
path('<int:fleet_id>/edit/', views.srp_fleet_edit_view, name='edit'),
path('<str:fleet_srp>/request', views.srp_request_view, name='request'),
# SRP URLS
url(r'^(\w+)/remove$', views.srp_fleet_remove, name='remove'),
url(r'^(\w+)/disable$', views.srp_fleet_disable, name='disable'),
url(r'^(\w+)/enable$', views.srp_fleet_enable, name='enable'),
url(r'^(\w+)/complete$', views.srp_fleet_mark_completed,
path('<int:fleet_id>/remove/', views.srp_fleet_remove, name='remove'),
path('<int:fleet_id>/disable/', views.srp_fleet_disable, name='disable'),
path('<int:fleet_id>/enable/', views.srp_fleet_enable, name='enable'),
path('<int:fleet_id>/complete/', views.srp_fleet_mark_completed,
name='mark_completed'),
url(r'^(\w+)/incomplete$', views.srp_fleet_mark_uncompleted,
path('<int:fleet_id>/incomplete/', views.srp_fleet_mark_uncompleted,
name='mark_uncompleted'),
url(r'^request/remove/', views.srp_request_remove,
path('request/remove/', views.srp_request_remove,
name="request_remove"),
url(r'^request/approve/', views.srp_request_approve,
path('request/approve/', views.srp_request_approve,
name='request_approve'),
url(r'^request/reject/', views.srp_request_reject,
path('request/reject/', views.srp_request_reject,
name='request_reject'),
url(r'^request/(\w+)/update', views.srp_request_update_amount,
path('request/<int:fleet_srp_request_id>/update', views.srp_request_update_amount,
name="request_update_amount"),
]

View File

@@ -3,17 +3,17 @@
{% if NIGHT_MODE %}
{% if debug %}
<!-- In template debug, loading less file instead of CSS -->
<link rel="stylesheet/less" type="text/css" href="{% static 'css/themes/darkly/darkly.less' %}" />
<link rel="stylesheet/less" type="text/css" href="{% static 'css/themes/darkly/darkly.less' %}">
<script src="https://cdnjs.cloudflare.com/ajax/libs/less.js/4.1.2/less.min.js" integrity="sha512-eXBn7AaMbUOWb3PSDhwcjByoM89FeO1SF9Jww6kqPYQkBrGZvqAKFbtqLHh5O95rYA/AOtWZ0QRO2S6rP+KsUw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> {% else %}
<link rel="stylesheet" type="text/css" href="{% static 'css/themes/darkly/darkly.min.css' %}" />
<link rel="stylesheet" type="text/css" href="{% static 'css/themes/darkly/darkly.min.css' %}">
{% endif %}
{% else %}
{% if debug %}
<!-- In template debug, loading less file instead of CSS -->
<link rel="stylesheet/less" type="text/css" href="{% static 'css/themes/flatly/flatly.less' %}" />
<link rel="stylesheet/less" type="text/css" href="{% static 'css/themes/flatly/flatly.less' %}">
<script src="https://cdnjs.cloudflare.com/ajax/libs/less.js/4.1.2/less.min.js" integrity="sha512-eXBn7AaMbUOWb3PSDhwcjByoM89FeO1SF9Jww6kqPYQkBrGZvqAKFbtqLHh5O95rYA/AOtWZ0QRO2S6rP+KsUw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
{% else %}
<link rel="stylesheet" type="text/css" href="{% static 'css/themes/flatly/flatly.min.css' %}" />
<link rel="stylesheet" type="text/css" href="{% static 'css/themes/flatly/flatly.min.css' %}">
{% endif %}
{% endif %}
<!-- End Bootstrap CSS -->

View File

@@ -1,3 +1,3 @@
<!-- Start Datatables-css from cdnjs -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/css/dataTables.bootstrap.min.css" integrity="sha512-BMbq2It2D3J17/C7aRklzOODG1IQ3+MHw3ifzBHMBwGO/0yUqYmsStgBjI0z5EYlaDEFnvYV7gNYdD3vFLRKsA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/css/dataTables.bootstrap.min.css" integrity="sha512-BMbq2It2D3J17/C7aRklzOODG1IQ3+MHw3ifzBHMBwGO/0yUqYmsStgBjI0z5EYlaDEFnvYV7gNYdD3vFLRKsA==" crossorigin="anonymous" referrerpolicy="no-referrer">
<!-- End Datatables-css from cdnjs -->

View File

@@ -1,3 +1,3 @@
<!-- Start FontAwesome CSS from cdnjs -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ==" crossorigin="anonymous" referrerpolicy="no-referrer">
<!-- End FontAwesome CSS from cdnjs -->

View File

@@ -1,3 +1,3 @@
<!-- Start jQuery-DateTimePicker CSS from cdnjs -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.min.css" integrity="sha512-f0tzWhCwVFS3WeYaofoLWkTP62ObhewQ1EZn65oSYDZUg1+CyywGKkWzm8BxaJj5HGKI72PnMH9jYyIFz+GH7g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.min.css" integrity="sha512-f0tzWhCwVFS3WeYaofoLWkTP62ObhewQ1EZn65oSYDZUg1+CyywGKkWzm8BxaJj5HGKI72PnMH9jYyIFz+GH7g==" crossorigin="anonymous" referrerpolicy="no-referrer">
<!-- End jQuery-DateTimePicker CSS from cdnjs -->

View File

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

View File

@@ -1,3 +1,3 @@
<!-- Start X-editable CSS from cdnjs -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.1/bootstrap3-editable/css/bootstrap-editable.css" integrity="sha512-e0rbO6UJET0zDdXOHjwc6D44UpeKumn7cU7XR/fa4S0/Jso0bZqcCqlIF6mtvcimMbf846mkv8aSWFnTwABr/g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.1/bootstrap3-editable/css/bootstrap-editable.css" integrity="sha512-e0rbO6UJET0zDdXOHjwc6D44UpeKumn7cU7XR/fa4S0/Jso0bZqcCqlIF6mtvcimMbf846mkv8aSWFnTwABr/g==" crossorigin="anonymous" referrerpolicy="no-referrer">
<!-- End X-editable CSS from cdnjs -->

View File

@@ -3,7 +3,7 @@ import datetime
from django import forms
from django.utils import timezone
from django.core.validators import MaxValueValidator, MinValueValidator
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from .models import Timer, TimerType

View File

@@ -19,7 +19,7 @@
<form id="add-timer-form" class="form-signin" role="form" action="" method="POST">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">
{% block submit_button_text %}
{% endblock %}

View File

@@ -17,7 +17,7 @@
<form action="" method="post">
{% csrf_token %}
<p>{% blocktrans %}Are you sure you want to delete timer "{{ object }}"?{% endblocktrans %}</p>
<input class="btn btn-danger btn-block" type="submit" value="Confirm" />
<input class="btn btn-danger btn-block" type="submit" value="Confirm">
</form>
</div>
</div>

View File

@@ -1,12 +1,12 @@
from django.conf.urls import url
from django.urls import path
from . import views
app_name = 'timerboard'
urlpatterns = [
url(r'^$', views.TimerView.as_view(), name='view'),
url(r'^add/$', views.AddTimerView.as_view(), name='add'),
url(r'^remove/(?P<pk>\w+)$', views.RemoveTimerView.as_view(), name='delete'),
url(r'^edit/(?P<pk>\w+)$', views.EditTimerView.as_view(), name='edit'),
path('', views.TimerView.as_view(), name='view'),
path('add/', views.AddTimerView.as_view(), name='add'),
path('remove/<int:pk>/', views.RemoveTimerView.as_view(), name='delete'),
path('edit/<int:pk>/', views.EditTimerView.as_view(), name='edit'),
]

View File

@@ -9,7 +9,7 @@ from django.urls import reverse_lazy
from django.views.generic import CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from .form import TimerForm
from .models import Timer

View File

@@ -1,6 +1,7 @@
from django.urls import path
import esi.urls
from django.conf.urls import include, url
from django.conf.urls import include
from django.contrib import admin
from django.views.generic.base import TemplateView
@@ -21,35 +22,35 @@ admin.site.site_header = NAME
# Functional/Untranslated URL's
urlpatterns = [
# Locale
url(r'^i18n/', include('django.conf.urls.i18n')),
path('i18n/', include('django.conf.urls.i18n')),
# Authentication
url(r'', include(allianceauth.authentication.urls)),
url(r'^account/login/$', TemplateView.as_view(template_name='public/login.html'), name='auth_login_user'),
url(r'^account/', include(hmac_urls)),
path('', include(allianceauth.authentication.urls)),
path('account/login/', TemplateView.as_view(template_name='public/login.html'), name='auth_login_user'),
path('account/', include(hmac_urls)),
# Admin urls
url(r'^admin/', admin.site.urls),
path('admin/', admin.site.urls),
# SSO
url(r'^sso/', include((esi.urls, 'esi'), namespace='esi')),
url(r'^sso/login$', allianceauth.authentication.views.sso_login, name='auth_sso_login'),
path('sso/', include((esi.urls, 'esi'), namespace='esi')),
path('sso/login', allianceauth.authentication.views.sso_login, name='auth_sso_login'),
# Notifications
url(r'', include(allianceauth.notifications.urls)),
path('', include(allianceauth.notifications.urls)),
# Groups
url(r'', include(allianceauth.groupmanagement.urls)),
path('', include(allianceauth.groupmanagement.urls)),
# Services
url(r'', decorate_url_patterns(allianceauth.services.urls.urlpatterns, main_character_required)),
path('', decorate_url_patterns(allianceauth.services.urls.urlpatterns, main_character_required)),
# Night mode
url(r'^night/', views.NightModeRedirectView.as_view(), name='nightmode')
path('night/', views.NightModeRedirectView.as_view(), name='nightmode')
]
# Append app urls
app_urls = get_hooks('url_hook')
for app in app_urls:
urlpatterns += [url(r'', decorate_url_patterns([app().include_pattern], main_character_required))]
urlpatterns += [path('', decorate_url_patterns([app().include_pattern], main_character_required))]

View File

@@ -3,12 +3,23 @@ from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.contrib import messages
import logging
logger = logging.getLogger(__name__)
class NightModeRedirectView(View):
SESSION_VAR = "NIGHT_MODE"
def get(self, request, *args, **kwargs):
request.session[self.SESSION_VAR] = not self.night_mode_state(request)
if not request.user.is_anonymous:
try:
request.user.profile.night_mode = request.session[self.SESSION_VAR]
request.user.profile.save()
except Exception as e:
logger.exception(e)
return HttpResponseRedirect(request.GET.get("next", "/"))
@classmethod

View File

@@ -30,10 +30,13 @@ It is possible to overload static and templates shipped with Django or Alliance
It is possible to add or override URLs with your auth project's URL config file. Upon install it is of the form:
```python
from django.urls import re_path
from django.urls import include
import allianceauth.urls
urlpatterns = [
url(r'', include(allianceauth.urls)),
re_path(r'', include(allianceauth.urls)),
]
```
@@ -42,23 +45,29 @@ This means every request gets passed to the Alliance Auth URL config to be inter
If you wanted to add a URL pointing to a custom view, it can be added anywhere in the list if not already used by Alliance Auth:
```python
from django.urls import re_path
from django.urls import include, path
import allianceauth.urls
import myauth.views
urlpatterns = [
url(r'', include(allianceauth.urls)),
url(r'myview/$', myauth.views.myview, name='myview'),
re_path(r'', include(allianceauth.urls)),
path('myview/', myauth.views.myview, name='myview'),
]
```
Additionally you can override URLs used by Alliance Auth here:
```python
from django.urls import re_path
from django.urls import include, path
import allianceauth.urls
import myauth.views
urlpatterns = [
url(r'account/login/$', myauth.views.login, name='auth_login_user'),
url(r'', include(allianceauth.urls)),
path('account/login/', myauth.views.login, name='auth_login_user'),
re_path(r'', include(allianceauth.urls)),
]
```

View File

@@ -34,12 +34,12 @@ An app called `plugin` provides a single view:
The app's `urls.py` would look like so:
from django.conf.urls import url
from django.urls import path
import plugin.views
urlpatterns = [
url(r^'index$', plugins.views.index, name='index'),
]
path('index/', plugins.views.index, name='index'),
]
Subsequently it would implement the UrlHook in a dedicated `auth_hooks.py` file like so:

View File

@@ -7,7 +7,7 @@ with open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
long_description = f.read()
install_requires = [
'mysqlclient',
'mysqlclient>=2.1.0',
'dnspython',
'passlib',
'requests>=2.9.1,<3.0.0',
@@ -18,22 +18,22 @@ install_requires = [
'packaging>=21.0,<22',
'beautifulsoup4',
'redis>=3.3.1,<4.0.0',
'celery>=4.3.0,<6.0.0,!=4.4.4', # 4.4.4 is missing a dependency
'celery_once>=2.0.1',
'redis>=4.0.0,<5.0.0',
'celery>=5.2.0,<6.0.0',
'celery_once>=3.0.1',
'django>=3.2.9,<4.0.0',
'django>=4.0.2,<5.0.0',
'django-bootstrap-form',
'django-registration>=3.1',
'django-registration>=3.2',
'django-sortedm2m',
'django-redis-cache>=3.0.0',
'django-celery-beat>=2.0.0',
'django-redis>=5.2.0<6.0.0',
'django-celery-beat @ git+https://github.com/celery/django-celery-beat.git@0806ab3c65e1615e9b617146779c21f49749067a',
'openfire-restapi',
'sleekxmpp<=1.3.2',
'slixmpp',
'pydiscourse',
'django-esi>=3.0.0,<4.0.0'
'django-esi>=4.0.0a1'
]
testing_extras = [
@@ -57,7 +57,7 @@ setup(
extras_require={
'testing': testing_extras
},
python_requires='~=3.7',
python_requires='~=3.8',
license='GPLv2',
packages=['allianceauth'],
url=allianceauth.__url__,
@@ -70,13 +70,12 @@ setup(
classifiers=[
'Environment :: Web Environment',
'Framework :: Django',
'Framework :: Django :: 3.2',
'Framework :: Django :: 4',
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',

View File

@@ -33,11 +33,8 @@ ROOT_URLCONF = 'tests.urls'
CACHES = {
"default": {
"BACKEND": "redis_cache.RedisCache",
"LOCATION": "localhost:6379",
"OPTIONS": {
"DB": 1,
}
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1"
}
}

Some files were not shown because too many files have changed in this diff Show More