Compare commits

..

13 Commits

Author SHA1 Message Date
Ariel Rin
da93940e13 Just an empty Tag Commit, because 2.11.2 bump went wonky 2022-03-29 14:48:39 +10:00
Ariel Rin
f53b43d9dc Merge branch 'master' of https://gitlab.com/allianceauth/allianceauth into v2.11.x 2022-03-29 14:47:40 +10:00
Ariel Rin
497a167ca7 Version Bump v2.11.2 2022-03-29 14:46:59 +10:00
Ariel Rin
852c5a3037 Bump Django-ESI to 4.x, inc breaking CCP change in 4.0.1 2022-03-29 14:40:30 +10:00
Ariel Rin
90f6777a7a Version Bump 2.11.1 2022-03-20 14:42:39 +10:00
Ariel Rin
a8d890abaf Merge branch 'improve_task_statistics' into 'master'
Improve task statistics

See merge request allianceauth/allianceauth!1409
2022-03-09 10:04:14 +00:00
Erik Kalkoken
79379b444c Improve task statistics 2022-03-09 10:04:13 +00:00
Ariel Rin
ace1de5c68 Merge branch 'fix-docker-new-redis' into 'master'
Fix docker for new redis

See merge request allianceauth/allianceauth!1406
2022-03-09 10:02:01 +00:00
Kevin McKernan
5d6128e9ea remove collectstatic command from dockerfile 2022-03-01 13:23:49 -07:00
Ariel Rin
131cc5ed0a Version Bump 2.11.0 2022-02-26 17:26:55 +10:00
Ariel Rin
9297bed43f Version Bump 2.10.2 2022-02-26 16:37:20 +10:00
Ariel Rin
b2fddc683a Merge branch 'master' of https://gitlab.com/allianceauth/allianceauth into v2.10.x 2022-02-26 16:32:45 +10:00
Ariel Rin
00f5e3e1e0 Version Bump 2.10.1 2022-02-21 00:02:12 +10:00
114 changed files with 527 additions and 986 deletions

View File

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

View File

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

View File

@@ -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__ = '3.0.0a1' __version__ = '2.11.2'
__title__ = 'Alliance Auth' __title__ = 'Alliance Auth'
__url__ = 'https://gitlab.com/allianceauth/allianceauth' __url__ = 'https://gitlab.com/allianceauth/allianceauth'
NAME = f'{__title__} v{__version__}' NAME = f'{__title__} v{__version__}'

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,45 +0,0 @@
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

@@ -1,23 +0,0 @@
# 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,10 +2,9 @@ import logging
from django.contrib.auth.models import User, Permission from django.contrib.auth.models import User, Permission
from django.db import models, transaction from django.db import models, transaction
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo, EveAllianceInfo, EveFactionInfo from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo, EveAllianceInfo, EveFactionInfo
from allianceauth.notifications import notify from allianceauth.notifications import notify
from django.conf import settings
from .managers import CharacterOwnershipManager, StateManager from .managers import CharacterOwnershipManager, StateManager
@@ -63,39 +62,9 @@ class UserProfile(models.Model):
class Meta: class Meta:
default_permissions = ('change',) default_permissions = ('change',)
user = models.OneToOneField( user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE)
User, main_character = models.OneToOneField(EveCharacter, blank=True, null=True, on_delete=models.SET_NULL)
related_name='profile', state = models.ForeignKey(State, on_delete=models.SET_DEFAULT, default=get_guest_state_pk)
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): def assign_state(self, state=None, commit=True):
if not state: if not state:
@@ -124,6 +93,8 @@ class UserProfile(models.Model):
def __str__(self): def __str__(self):
return str(self.user) return str(self.user)
class CharacterOwnership(models.Model): class CharacterOwnership(models.Model):
class Meta: class Meta:
default_permissions = ('change', 'delete') default_permissions = ('change', 'delete')

View File

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

View File

@@ -0,0 +1,40 @@
from collections import namedtuple
import datetime as dt
from .event_series import EventSeries
"""Global series for counting task events."""
succeeded_tasks = EventSeries("SUCCEEDED_TASKS")
retried_tasks = EventSeries("RETRIED_TASKS")
failed_tasks = EventSeries("FAILED_TASKS")
_TaskCounts = namedtuple(
"_TaskCounts", ["succeeded", "retried", "failed", "total", "earliest_task", "hours"]
)
def dashboard_results(hours: int) -> _TaskCounts:
"""Counts of all task events within the given timeframe."""
def earliest_if_exists(events: EventSeries, earliest: dt.datetime) -> list:
my_earliest = events.first_event(earliest=earliest)
return [my_earliest] if my_earliest else []
earliest = dt.datetime.utcnow() - dt.timedelta(hours=hours)
earliest_events = list()
succeeded_count = succeeded_tasks.count(earliest=earliest)
earliest_events += earliest_if_exists(succeeded_tasks, earliest)
retried_count = retried_tasks.count(earliest=earliest)
earliest_events += earliest_if_exists(retried_tasks, earliest)
failed_count = failed_tasks.count(earliest=earliest)
earliest_events += earliest_if_exists(failed_tasks, earliest)
return _TaskCounts(
succeeded=succeeded_count,
retried=retried_count,
failed=failed_count,
total=succeeded_count + retried_count + failed_count,
earliest_task=min(earliest_events) if earliest_events else None,
hours=hours,
)

View File

@@ -1,74 +1,34 @@
import datetime as dt import datetime as dt
from collections import namedtuple
from typing import Optional, List from typing import Optional, List
from redis import Redis from redis import Redis
from pytz import utc from pytz import utc
from django_redis import get_redis_connection from django.core.cache import cache
_TaskCounts = namedtuple(
"_TaskCounts", ["succeeded", "retried", "failed", "total", "earliest_task", "hours"]
)
def dashboard_results(hours: int) -> _TaskCounts:
"""Counts of all task events within the given timeframe."""
def earliest_if_exists(events: EventSeries, earliest: dt.datetime) -> list:
my_earliest = events.first_event(earliest=earliest)
return [my_earliest] if my_earliest else []
earliest = dt.datetime.utcnow() - dt.timedelta(hours=hours)
earliest_events = list()
succeeded = SucceededTaskSeries()
succeeded_count = succeeded.count(earliest=earliest)
earliest_events += earliest_if_exists(succeeded, earliest)
retried = RetriedTaskSeries()
retried_count = retried.count(earliest=earliest)
earliest_events += earliest_if_exists(retried, earliest)
failed = FailedTaskSeries()
failed_count = failed.count(earliest=earliest)
earliest_events += earliest_if_exists(failed, earliest)
return _TaskCounts(
succeeded=succeeded_count,
retried=retried_count,
failed=failed_count,
total=succeeded_count + retried_count + failed_count,
earliest_task=min(earliest_events) if earliest_events else None,
hours=hours,
)
class EventSeries: class EventSeries:
"""Base class for recording and analysing a series of events. """API for recording and analysing a series of events."""
This class must be inherited from and the child class must define KEY_ID. _ROOT_KEY = "ALLIANCEAUTH_EVENT_SERIES"
"""
_ROOT_KEY = "ALLIANCEAUTH_TASK_SERIES" def __init__(self, key_id: str, redis: Redis = None) -> None:
self._redis = cache.get_master_client() if not redis else redis
def __init__(
self,
redis: Redis = None,
) -> None:
if type(self) == EventSeries:
raise TypeError("Can not instantiate base class.")
if not hasattr(self, "KEY_ID"):
raise ValueError("KEY_ID not defined")
self._redis = get_redis_connection("default") if not redis else redis
if not isinstance(self._redis, Redis): if not isinstance(self._redis, Redis):
raise TypeError( raise TypeError(
"This class requires a Redis client, but none was provided " "This class requires a Redis client, but none was provided "
"and the default Django cache backend is not Redis either." "and the default Django cache backend is not Redis either."
) )
self._key_id = str(key_id)
self.clear()
@property @property
def _key_counter(self): def _key_counter(self):
return f"{self._ROOT_KEY}_{self.KEY_ID}_COUNTER" return f"{self._ROOT_KEY}_{self._key_id}_COUNTER"
@property @property
def _key_sorted_set(self): def _key_sorted_set(self):
return f"{self._ROOT_KEY}_{self.KEY_ID}_SORTED_SET" return f"{self._ROOT_KEY}_{self._key_id}_SORTED_SET"
def add(self, event_time: dt.datetime = None) -> None: def add(self, event_time: dt.datetime = None) -> None:
"""Add event. """Add event.
@@ -133,21 +93,3 @@ class EventSeries:
@staticmethod @staticmethod
def _cast_scores_to_dt(score) -> dt.datetime: def _cast_scores_to_dt(score) -> dt.datetime:
return dt.datetime.fromtimestamp(float(score), tz=utc) return dt.datetime.fromtimestamp(float(score), tz=utc)
class SucceededTaskSeries(EventSeries):
"""A task has succeeded."""
KEY_ID = "SUCCEEDED"
class RetriedTaskSeries(EventSeries):
"""A task has been retried."""
KEY_ID = "RETRIED"
class FailedTaskSeries(EventSeries):
"""A task has failed."""
KEY_ID = "FAILED"

View File

@@ -1,15 +1,21 @@
from celery.signals import task_failure, task_retry, task_success, worker_ready from celery.signals import (
task_failure,
task_internal_error,
task_retry,
task_success,
worker_ready
)
from django.conf import settings from django.conf import settings
from .event_series import FailedTaskSeries, RetriedTaskSeries, SucceededTaskSeries from .counters import failed_tasks, retried_tasks, succeeded_tasks
def reset_counters(): def reset_counters():
"""Reset all counters for the celery status.""" """Reset all counters for the celery status."""
SucceededTaskSeries().clear() succeeded_tasks.clear()
FailedTaskSeries().clear() failed_tasks.clear()
RetriedTaskSeries().clear() retried_tasks.clear()
def is_enabled() -> bool: def is_enabled() -> bool:
@@ -27,16 +33,22 @@ def reset_counters_when_celery_restarted(*args, **kwargs):
@task_success.connect @task_success.connect
def record_task_succeeded(*args, **kwargs): def record_task_succeeded(*args, **kwargs):
if is_enabled(): if is_enabled():
SucceededTaskSeries().add() succeeded_tasks.add()
@task_retry.connect @task_retry.connect
def record_task_retried(*args, **kwargs): def record_task_retried(*args, **kwargs):
if is_enabled(): if is_enabled():
RetriedTaskSeries().add() retried_tasks.add()
@task_failure.connect @task_failure.connect
def record_task_failed(*args, **kwargs): def record_task_failed(*args, **kwargs):
if is_enabled(): if is_enabled():
FailedTaskSeries().add() failed_tasks.add()
@task_internal_error.connect
def record_task_internal_error(*args, **kwargs):
if is_enabled():
failed_tasks.add()

View File

@@ -0,0 +1,51 @@
import datetime as dt
from django.test import TestCase
from django.utils.timezone import now
from allianceauth.authentication.task_statistics.counters import (
dashboard_results,
succeeded_tasks,
retried_tasks,
failed_tasks,
)
class TestDashboardResults(TestCase):
def test_should_return_counts_for_given_timeframe_only(self):
# given
earliest_task = now() - dt.timedelta(minutes=15)
succeeded_tasks.clear()
succeeded_tasks.add(now() - dt.timedelta(hours=1, seconds=1))
succeeded_tasks.add(earliest_task)
succeeded_tasks.add()
succeeded_tasks.add()
retried_tasks.clear()
retried_tasks.add(now() - dt.timedelta(hours=1, seconds=1))
retried_tasks.add(now() - dt.timedelta(seconds=30))
retried_tasks.add()
failed_tasks.clear()
failed_tasks.add(now() - dt.timedelta(hours=1, seconds=1))
failed_tasks.add()
# when
results = dashboard_results(hours=1)
# then
self.assertEqual(results.succeeded, 3)
self.assertEqual(results.retried, 2)
self.assertEqual(results.failed, 1)
self.assertEqual(results.total, 6)
self.assertEqual(results.earliest_task, earliest_task)
def test_should_work_with_no_data(self):
# given
succeeded_tasks.clear()
retried_tasks.clear()
failed_tasks.clear()
# when
results = dashboard_results(hours=1)
# then
self.assertEqual(results.succeeded, 0)
self.assertEqual(results.retried, 0)
self.assertEqual(results.failed, 0)
self.assertEqual(results.total, 0)
self.assertIsNone(results.earliest_task)

View File

@@ -4,46 +4,13 @@ from pytz import utc
from django.test import TestCase from django.test import TestCase
from django.utils.timezone import now from django.utils.timezone import now
from allianceauth.authentication.task_statistics.event_series import ( from allianceauth.authentication.task_statistics.event_series import EventSeries
EventSeries,
FailedTaskSeries,
RetriedTaskSeries,
SucceededTaskSeries,
dashboard_results,
)
class TestEventSeries(TestCase): class TestEventSeries(TestCase):
"""Testing EventSeries class."""
class IncompleteEvents(EventSeries):
"""Child class without KEY ID"""
class MyEventSeries(EventSeries):
KEY_ID = "TEST"
def test_should_create_object(self):
# when
events = self.MyEventSeries()
# then
self.assertIsInstance(events, self.MyEventSeries)
def test_should_abort_when_redis_client_invalid(self):
with self.assertRaises(TypeError):
self.MyEventSeries(redis="invalid")
def test_should_not_allow_instantiation_of_base_class(self):
with self.assertRaises(TypeError):
EventSeries()
def test_should_not_allow_creating_child_class_without_key_id(self):
with self.assertRaises(ValueError):
self.IncompleteEvents()
def test_should_add_event(self): def test_should_add_event(self):
# given # given
events = self.MyEventSeries() events = EventSeries("dummy")
events.clear()
# when # when
events.add() events.add()
# then # then
@@ -53,8 +20,7 @@ class TestEventSeries(TestCase):
def test_should_add_event_with_specified_time(self): def test_should_add_event_with_specified_time(self):
# given # given
events = self.MyEventSeries() events = EventSeries("dummy")
events.clear()
my_time = dt.datetime(2021, 11, 1, 12, 15, tzinfo=utc) my_time = dt.datetime(2021, 11, 1, 12, 15, tzinfo=utc)
# when # when
events.add(my_time) events.add(my_time)
@@ -65,8 +31,7 @@ class TestEventSeries(TestCase):
def test_should_count_events(self): def test_should_count_events(self):
# given # given
events = self.MyEventSeries() events = EventSeries("dummy")
events.clear()
events.add() events.add()
events.add() events.add()
# when # when
@@ -76,8 +41,7 @@ class TestEventSeries(TestCase):
def test_should_count_zero(self): def test_should_count_zero(self):
# given # given
events = self.MyEventSeries() events = EventSeries("dummy")
events.clear()
# when # when
result = events.count() result = events.count()
# then # then
@@ -85,8 +49,7 @@ class TestEventSeries(TestCase):
def test_should_count_events_within_timeframe_1(self): def test_should_count_events_within_timeframe_1(self):
# given # given
events = self.MyEventSeries() events = EventSeries("dummy")
events.clear()
events.add(dt.datetime(2021, 12, 1, 12, 0, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 0, tzinfo=utc))
events.add(dt.datetime(2021, 12, 1, 12, 10, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 10, tzinfo=utc))
events.add(dt.datetime(2021, 12, 1, 12, 15, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 15, tzinfo=utc))
@@ -101,8 +64,7 @@ class TestEventSeries(TestCase):
def test_should_count_events_within_timeframe_2(self): def test_should_count_events_within_timeframe_2(self):
# given # given
events = self.MyEventSeries() events = EventSeries("dummy")
events.clear()
events.add(dt.datetime(2021, 12, 1, 12, 0, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 0, tzinfo=utc))
events.add(dt.datetime(2021, 12, 1, 12, 10, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 10, tzinfo=utc))
events.add(dt.datetime(2021, 12, 1, 12, 15, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 15, tzinfo=utc))
@@ -114,8 +76,7 @@ class TestEventSeries(TestCase):
def test_should_count_events_within_timeframe_3(self): def test_should_count_events_within_timeframe_3(self):
# given # given
events = self.MyEventSeries() events = EventSeries("dummy")
events.clear()
events.add(dt.datetime(2021, 12, 1, 12, 0, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 0, tzinfo=utc))
events.add(dt.datetime(2021, 12, 1, 12, 10, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 10, tzinfo=utc))
events.add(dt.datetime(2021, 12, 1, 12, 15, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 15, tzinfo=utc))
@@ -127,8 +88,7 @@ class TestEventSeries(TestCase):
def test_should_clear_events(self): def test_should_clear_events(self):
# given # given
events = self.MyEventSeries() events = EventSeries("dummy")
events.clear()
events.add() events.add()
events.add() events.add()
# when # when
@@ -138,8 +98,7 @@ class TestEventSeries(TestCase):
def test_should_return_date_of_first_event(self): def test_should_return_date_of_first_event(self):
# given # given
events = self.MyEventSeries() events = EventSeries("dummy")
events.clear()
events.add(dt.datetime(2021, 12, 1, 12, 0, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 0, tzinfo=utc))
events.add(dt.datetime(2021, 12, 1, 12, 10, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 10, tzinfo=utc))
events.add(dt.datetime(2021, 12, 1, 12, 15, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 15, tzinfo=utc))
@@ -151,8 +110,7 @@ class TestEventSeries(TestCase):
def test_should_return_date_of_first_event_with_range(self): def test_should_return_date_of_first_event_with_range(self):
# given # given
events = self.MyEventSeries() events = EventSeries("dummy")
events.clear()
events.add(dt.datetime(2021, 12, 1, 12, 0, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 0, tzinfo=utc))
events.add(dt.datetime(2021, 12, 1, 12, 10, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 10, tzinfo=utc))
events.add(dt.datetime(2021, 12, 1, 12, 15, tzinfo=utc)) events.add(dt.datetime(2021, 12, 1, 12, 15, tzinfo=utc))
@@ -166,57 +124,10 @@ class TestEventSeries(TestCase):
def test_should_return_all_events(self): def test_should_return_all_events(self):
# given # given
events = self.MyEventSeries() events = EventSeries("dummy")
events.clear()
events.add() events.add()
events.add() events.add()
# when # when
results = events.all() results = events.all()
# then # then
self.assertEqual(len(results), 2) self.assertEqual(len(results), 2)
class TestDashboardResults(TestCase):
def test_should_return_counts_for_given_timeframe_only(self):
# given
earliest_task = now() - dt.timedelta(minutes=15)
succeeded = SucceededTaskSeries()
succeeded.clear()
succeeded.add(now() - dt.timedelta(hours=1, seconds=1))
succeeded.add(earliest_task)
succeeded.add()
succeeded.add()
retried = RetriedTaskSeries()
retried.clear()
retried.add(now() - dt.timedelta(hours=1, seconds=1))
retried.add(now() - dt.timedelta(seconds=30))
retried.add()
failed = FailedTaskSeries()
failed.clear()
failed.add(now() - dt.timedelta(hours=1, seconds=1))
failed.add()
# when
results = dashboard_results(hours=1)
# then
self.assertEqual(results.succeeded, 3)
self.assertEqual(results.retried, 2)
self.assertEqual(results.failed, 1)
self.assertEqual(results.total, 6)
self.assertEqual(results.earliest_task, earliest_task)
def test_should_work_with_no_data(self):
# given
succeeded = SucceededTaskSeries()
succeeded.clear()
retried = RetriedTaskSeries()
retried.clear()
failed = FailedTaskSeries()
failed.clear()
# when
results = dashboard_results(hours=1)
# then
self.assertEqual(results.succeeded, 0)
self.assertEqual(results.retried, 0)
self.assertEqual(results.failed, 0)
self.assertEqual(results.total, 0)
self.assertIsNone(results.earliest_task)

View File

@@ -4,10 +4,10 @@ from celery.exceptions import Retry
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from allianceauth.authentication.task_statistics.event_series import ( from allianceauth.authentication.task_statistics.counters import (
FailedTaskSeries, failed_tasks,
RetriedTaskSeries, retried_tasks,
SucceededTaskSeries, succeeded_tasks,
) )
from allianceauth.authentication.task_statistics.signals import ( from allianceauth.authentication.task_statistics.signals import (
reset_counters, reset_counters,
@@ -17,15 +17,16 @@ from allianceauth.eveonline.tasks import update_character
@override_settings( @override_settings(
CELERY_ALWAYS_EAGER=True, ALLIANCEAUTH_DASHBOARD_TASK_STATISTICS_DISABLED=False CELERY_ALWAYS_EAGER=True,ALLIANCEAUTH_DASHBOARD_TASK_STATISTICS_DISABLED=False
) )
class TestTaskSignals(TestCase): class TestTaskSignals(TestCase):
fixtures = ["disable_analytics"] fixtures = ["disable_analytics"]
def test_should_record_successful_task(self): def test_should_record_successful_task(self):
# given # given
events = SucceededTaskSeries() succeeded_tasks.clear()
events.clear() retried_tasks.clear()
failed_tasks.clear()
# when # when
with patch( with patch(
"allianceauth.eveonline.tasks.EveCharacter.objects.update_character" "allianceauth.eveonline.tasks.EveCharacter.objects.update_character"
@@ -33,12 +34,15 @@ class TestTaskSignals(TestCase):
mock_update.return_value = None mock_update.return_value = None
update_character.delay(1) update_character.delay(1)
# then # then
self.assertEqual(events.count(), 1) self.assertEqual(succeeded_tasks.count(), 1)
self.assertEqual(retried_tasks.count(), 0)
self.assertEqual(failed_tasks.count(), 0)
def test_should_record_retried_task(self): def test_should_record_retried_task(self):
# given # given
events = RetriedTaskSeries() succeeded_tasks.clear()
events.clear() retried_tasks.clear()
failed_tasks.clear()
# when # when
with patch( with patch(
"allianceauth.eveonline.tasks.EveCharacter.objects.update_character" "allianceauth.eveonline.tasks.EveCharacter.objects.update_character"
@@ -46,12 +50,15 @@ class TestTaskSignals(TestCase):
mock_update.side_effect = Retry mock_update.side_effect = Retry
update_character.delay(1) update_character.delay(1)
# then # then
self.assertEqual(events.count(), 1) self.assertEqual(succeeded_tasks.count(), 0)
self.assertEqual(failed_tasks.count(), 0)
self.assertEqual(retried_tasks.count(), 1)
def test_should_record_failed_task(self): def test_should_record_failed_task(self):
# given # given
events = FailedTaskSeries() succeeded_tasks.clear()
events.clear() retried_tasks.clear()
failed_tasks.clear()
# when # when
with patch( with patch(
"allianceauth.eveonline.tasks.EveCharacter.objects.update_character" "allianceauth.eveonline.tasks.EveCharacter.objects.update_character"
@@ -59,28 +66,21 @@ class TestTaskSignals(TestCase):
mock_update.side_effect = RuntimeError mock_update.side_effect = RuntimeError
update_character.delay(1) update_character.delay(1)
# then # then
self.assertEqual(events.count(), 1) self.assertEqual(succeeded_tasks.count(), 0)
self.assertEqual(retried_tasks.count(), 0)
self.assertEqual(failed_tasks.count(), 1)
@override_settings(ALLIANCEAUTH_DASHBOARD_TASK_STATISTICS_DISABLED=False)
class TestResetCounters(TestCase):
def test_should_reset_counters(self): def test_should_reset_counters(self):
# given # given
succeeded = SucceededTaskSeries() succeeded_tasks.add()
succeeded.clear() retried_tasks.add()
succeeded.add() failed_tasks.add()
retried = RetriedTaskSeries()
retried.clear()
retried.add()
failed = FailedTaskSeries()
failed.clear()
failed.add()
# when # when
reset_counters() reset_counters()
# then # then
self.assertEqual(succeeded.count(), 0) self.assertEqual(succeeded_tasks.count(), 0)
self.assertEqual(retried.count(), 0) self.assertEqual(retried_tasks.count(), 0)
self.assertEqual(failed.count(), 0) self.assertEqual(failed_tasks.count(), 0)
class TestIsEnabled(TestCase): class TestIsEnabled(TestCase):

View File

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

View File

@@ -1,17 +1,4 @@
from django.db.models.signals import (
m2m_changed,
post_save,
pre_delete,
pre_save
)
from django.urls import reverse 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: def get_admin_change_view_url(obj: object) -> str:

View File

@@ -1,175 +0,0 @@
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

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

View File

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

View File

@@ -1,11 +1,12 @@
from django.urls import path from django.conf.urls import url
from . import views from . import views
app_name = 'corputils' app_name = 'corputils'
urlpatterns = [ urlpatterns = [
path('', views.corpstats_view, name='view'), url(r'^$', views.corpstats_view, name='view'),
path('add/', views.corpstats_add, name='add'), url(r'^add/$', views.corpstats_add, name='add'),
path('<int:corp_id>/', views.corpstats_view, name='view_corp'), url(r'^(?P<corp_id>(\d)*)/$', views.corpstats_view, name='view_corp'),
path('<int:corp_id>/update/', views.corpstats_update, name='update'), url(r'^(?P<corp_id>(\d)+)/update/$', views.corpstats_update, name='update'),
path('search/', views.corpstats_search, name='search'), url(r'^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.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.db import IntegrityError from django.db import IntegrityError
from django.shortcuts import render, redirect, get_object_or_404 from django.shortcuts import render, redirect, get_object_or_404
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from esi.decorators import token_required from esi.decorators import token_required
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,30 +1,30 @@
from django.urls import path from django.conf.urls import url
from . import views from . import views
app_name = 'fleetactivitytracking' app_name = 'fleetactivitytracking'
urlpatterns = [ urlpatterns = [
# FleetActivityTracking (FAT) # FleetActivityTracking (FAT)
path('', views.fatlink_view, name='view'), url(r'^$', views.fatlink_view, name='view'),
path('statistics/', views.fatlink_statistics_view, name='statistics'), url(r'^statistics/$', views.fatlink_statistics_view, name='statistics'),
path('statistics/corp/<int:corpid>/', views.fatlink_statistics_corp_view, url(r'^statistics/corp/(\w+)$', views.fatlink_statistics_corp_view,
name='statistics_corp'), name='statistics_corp'),
path('statistics/corp/<int:corpid>/<int:year>/<int:month>/', url(r'^statistics/corp/(?P<corpid>\w+)/(?P<year>[0-9]+)/(?P<month>[0-9]+)/',
views.fatlink_statistics_corp_view, views.fatlink_statistics_corp_view,
name='statistics_corp_month'), name='statistics_corp_month'),
path('statistics/<int:year>/<int:month>/', views.fatlink_statistics_view, url(r'^statistics/(?P<year>[0-9]+)/(?P<month>[0-9]+)/$', views.fatlink_statistics_view,
name='statistics_month'), name='statistics_month'),
path('user/statistics/', views.fatlink_personal_statistics_view, url(r'^user/statistics/$', views.fatlink_personal_statistics_view,
name='personal_statistics'), name='personal_statistics'),
path('user/statistics/<int:year>/', views.fatlink_personal_statistics_view, url(r'^user/statistics/(?P<year>[0-9]+)/$', views.fatlink_personal_statistics_view,
name='personal_statistics_year'), name='personal_statistics_year'),
path('user/statistics/<int:year>/<int:month>/', url(r'^user/statistics/(?P<year>[0-9]+)/(?P<month>[0-9]+)/$',
views.fatlink_monthly_personal_statistics_view, views.fatlink_monthly_personal_statistics_view,
name='personal_statistics_month'), name='personal_statistics_month'),
path('user/<int:char_id>/statistics/<int:year>/<int:month>/', url(r'^user/(?P<char_id>[0-9]+)/statistics/(?P<year>[0-9]+)/(?P<month>[0-9]+)/$',
views.fatlink_monthly_personal_statistics_view, views.fatlink_monthly_personal_statistics_view,
name='user_statistics_month'), name='user_statistics_month'),
path('create/', views.create_fatlink_view, name='create'), url(r'^create/$', views.create_fatlink_view, name='create'),
path('modify/<str:fat_hash>/', views.modify_fatlink_view, name='modify'), url(r'^modify/(?P<fat_hash>[a-zA-Z0-9_-]+)/$', views.modify_fatlink_view, name='modify'),
path('link/<str:fat_hash>/', views.click_fatlink_view, name='click'), url(r'^link/(?P<fat_hash>[a-zA-Z0-9]+)/$', 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.core.exceptions import ValidationError, ObjectDoesNotExist
from django.shortcuts import render, redirect, get_object_or_404, Http404 from django.shortcuts import render, redirect, get_object_or_404, Http404
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from esi.decorators import token_required from esi.decorators import token_required
from allianceauth.eveonline.providers import provider from allianceauth.eveonline.providers import provider
from .forms import FatlinkForm from .forms import FatlinkForm

View File

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

View File

@@ -1,50 +1,51 @@
from django.urls import path
from . import views from . import views
from django.conf.urls import url
app_name = "groupmanagement" app_name = "groupmanagement"
urlpatterns = [ urlpatterns = [
# groups # groups
path("groups", views.groups_view, name="groups"), url(r"^groups/$", views.groups_view, name="groups"),
path("group/request/join/<int:group_id>/", views.group_request_add, name="request_add"), url(r"^group/request/join/(\w+)/$", views.group_request_add, name="request_add"),
path( url(
"group/request/leave/<int:group_id>/", views.group_request_leave, name="request_leave" r"^group/request/leave/(\w+)/$", views.group_request_leave, name="request_leave"
), ),
# group management # group management
path("groupmanagement/requests/", views.group_management, name="management"), url(r"^groupmanagement/requests/$", views.group_management, name="management"),
path("groupmanagement/membership/", views.group_membership, name="membership"), url(r"^groupmanagement/membership/$", views.group_membership, name="membership"),
path( url(
"groupmanagement/membership/<int:group_id>/", r"^groupmanagement/membership/(\w+)/$",
views.group_membership_list, views.group_membership_list,
name="membership", name="membership",
), ),
path( url(
"groupmanagement/membership/<int:group_id>/audit-log/", r"^groupmanagement/membership/(\w+)/audit-log/$",
views.group_membership_audit, views.group_membership_audit,
name="audit_log", name="audit_log",
), ),
path( url(
"groupmanagement/membership/<int:group_id>/remove/<int:user_id>/", r"^groupmanagement/membership/(\w+)/remove/(\w+)/$",
views.group_membership_remove, views.group_membership_remove,
name="membership_remove", name="membership_remove",
), ),
path( url(
"groupmanagement/request/join/accept/<int:group_request_id>/", r"^groupmanagement/request/join/accept/(\w+)/$",
views.group_accept_request, views.group_accept_request,
name="accept_request", name="accept_request",
), ),
path( url(
"groupmanagement/request/join/reject/<int:group_request_id>/", r"^groupmanagement/request/join/reject/(\w+)/$",
views.group_reject_request, views.group_reject_request,
name="reject_request", name="reject_request",
), ),
path( url(
"groupmanagement/request/leave/accept/<int:group_request_id>/", r"^groupmanagement/request/leave/accept/(\w+)/$",
views.group_leave_accept_request, views.group_leave_accept_request,
name="leave_accept_request", name="leave_accept_request",
), ),
path( url(
"groupmanagement/request/leave/reject/<int:group_request_id>/", r"^groupmanagement/request/leave/reject/(\w+)/$",
views.group_leave_reject_request, views.group_leave_reject_request,
name="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.db.models import Count
from django.http import Http404 from django.http import Http404
from django.shortcuts import render, redirect, get_object_or_404 from django.shortcuts import render, redirect, get_object_or_404
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from allianceauth.notifications import notify from allianceauth.notifications import notify

View File

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

View File

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

View File

@@ -19,8 +19,8 @@
<div cass="text-center">{{ question.help_text }}</div> <div cass="text-center">{{ question.help_text }}</div>
{% endif %} {% endif %}
{% for choice in question.choices.all %} {% 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 }}"> <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> <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% empty %} {% empty %}
<textarea class="form-control" cols="30" id="id_{{ question.pk }}" name="{{ question.pk }}" rows="4"></textarea> <textarea class="form-control" cols="30" id="id_{{ question.pk }}" name="{{ question.pk }}" rows="4"></textarea>
{% endfor %} {% endfor %}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,12 +1,12 @@
from django.urls import path from django.conf.urls import url
from . import views from . import views
app_name = 'optimer' app_name = 'optimer'
urlpatterns = [ urlpatterns = [
path('', views.optimer_view, name='view'), url(r'^$', views.optimer_view, name='view'),
path('add/', views.add_optimer_view, name='add'), url(r'^add$', views.add_optimer_view, name='add'),
path('<int:optimer_id>/remove/', views.remove_optimer, name='remove'), url(r'^(\w+)/remove$', views.remove_optimer, name='remove'),
path('<int:optimer_id>/edit/', views.edit_optimer, name='edit'), url(r'^(\w+)/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 get_object_or_404
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from .form import OpForm from .form import OpForm
from .models import OpTimer, OpTimerType from .models import OpTimer, OpTimerType

View File

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

View File

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

View File

@@ -61,13 +61,6 @@ EMAIL_HOST_PASSWORD = ''
EMAIL_USE_TLS = True EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = '' 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. # # Add any custom settings below here. #
####################################### #######################################

View File

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

View File

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

View File

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

View File

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

View File

@@ -85,24 +85,28 @@ class TestBasicsAndHelpers(TestCase):
client = DiscordClient(TEST_BOT_TOKEN, mock_redis, is_rate_limited=True) client = DiscordClient(TEST_BOT_TOKEN, mock_redis, is_rate_limited=True)
self.assertTrue(client.is_rate_limited) self.assertTrue(client.is_rate_limited)
@patch(MODULE_PATH + '.get_redis_connection') @patch(MODULE_PATH + '.caches')
def test_use_default_redis_if_none_provided(self, mock_caches): def test_use_default_redis_if_none_provided(self, mock_caches):
my_redis = MagicMock(spec=Redis) my_redis = MagicMock(spec=Redis)
mock_caches.return_value = my_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__
client = DiscordClient(TEST_BOT_TOKEN) client = DiscordClient(TEST_BOT_TOKEN)
self.assertTrue(mock_caches.called) self.assertTrue(mock_default_cache.get_master_client.called)
self.assertEqual(client._redis, my_redis) self.assertEqual(client._redis, my_redis)
@patch(MODULE_PATH + '.get_redis_connection') @patch(MODULE_PATH + '.caches')
def test_raise_exception_if_default_cache_is_not_redis(self, mock_caches): def test_raise_exception_if_default_cache_is_not_redis(self, mock_caches):
my_redis = MagicMock() my_redis = MagicMock()
mock_caches.return_value = my_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__
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
DiscordClient(TEST_BOT_TOKEN) DiscordClient(TEST_BOT_TOKEN)
self.assertTrue(mock_caches.called) self.assertTrue(mock_default_cache.get_master_client.called)
@requests_mock.Mocker() @requests_mock.Mocker()

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,4 @@
from django.conf.urls import include from django.conf.urls import url, include
from django.urls import path
from . import views from . import views
@@ -7,12 +6,12 @@ app_name = 'ips4'
module_urls = [ module_urls = [
# IPS4 Service Control # IPS4 Service Control
path('activate/', views.activate_ips4, name='activate'), url(r'^activate/$', views.activate_ips4, name='activate'),
path('deactivate/', views.deactivate_ips4, name='deactivate'), url(r'^deactivate/$', views.deactivate_ips4, name='deactivate'),
path('reset_password/', views.reset_ips4_password, name='reset_password'), url(r'^reset_password/$', views.reset_ips4_password, name='reset_password'),
path('set_password/', views.set_ips4_password, name='set_password'), url(r'^set_password/$', views.set_ips4_password, name='set_password'),
] ]
urlpatterns = [ urlpatterns = [
path('ips4/', include((module_urls, app_name), namespace=app_name)) url(r'^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">{{ username }}</td>
<td class="text-center"><a href="mumble://{{ service_url }}">{{ service_url }}</a></td> <td class="text-center"><a href="mumble://{{ service_url }}">{{ service_url }}</a></td>
<td class="text-center"> <td class="text-center">
{% if username == "" %} {% ifequal username "" %}
<a href="{% url urls.auth_activate %}" title="Activate" class="btn btn-warning"> <a href="{% url urls.auth_activate %}" title="Activate" class="btn btn-warning">
<span class="glyphicon glyphicon-ok"></span> <span class="glyphicon glyphicon-ok"></span>
</a> </a>
@@ -20,6 +20,6 @@
<a href="mumble://{{ connect_url }}" class="btn btn-success" title="Connect"> <a href="mumble://{{ connect_url }}" class="btn btn-success" title="Connect">
<span class="glyphicon glyphicon-arrow-right"></span> <span class="glyphicon glyphicon-arrow-right"></span>
</a> </a>
{% endif %} {% endifequal %}
</td> </td>
</tr> </tr>

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ import random
import string import string
from urllib.parse import urlparse from urllib.parse import urlparse
import slixmpp import sleekxmpp
from django.conf import settings from django.conf import settings
from ofrestapi.users import Users as ofUsers from ofrestapi.users import Users as ofUsers
from ofrestapi import exception from ofrestapi import exception
@@ -172,13 +172,13 @@ class OpenfireManager:
raise PingBotException("Unable to connect to jabber server.") raise PingBotException("Unable to connect to jabber server.")
class PingBot(slixmpp.ClientXMPP): class PingBot(sleekxmpp.ClientXMPP):
""" """
A copy-paste of the example client bot from A copy-paste of the example client bot from
http://sleekxmpp.com/getting_started/sendlogout.html http://sleekxmpp.com/getting_started/sendlogout.html
""" """
def __init__(self, jid, password, recipient, message): def __init__(self, jid, password, recipient, message):
slixmpp.ClientXMPP.__init__(self, jid, password) sleekxmpp.ClientXMPP.__init__(self, jid, password)
self.reconnect_max_attempts = 5 self.reconnect_max_attempts = 5
self.auto_reconnect = False 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;"> <form class="form-signin" role="form" action="" method="POST" onsubmit="submitbutton.disabled = true; return true;">
{% csrf_token %} {% csrf_token %}
{{ form|bootstrap }} {{ form|bootstrap }}
<br> <br/>
<button class="btn btn-lg btn-primary btn-block" name="submitbutton" type="submit">{% translate "Broadcast" %} <button class="btn btn-lg btn-primary btn-block" name="submitbutton" type="submit">{% translate "Broadcast" %}
</button> </button>
</form> </form>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -12,11 +12,11 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="col-md-4 col-md-offset-4"> <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> <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"> <form class="form-signin" role="form" action="{% url 'teamspeak3:verify' %}" method="POST">
{% csrf_token %} {% csrf_token %}
{{ form|bootstrap }} {{ form|bootstrap }}
<br> <br/>
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Continue" %}</button> <button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Continue" %}</button>
</form> </form>
</div> </div>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,6 @@
aria-valuenow="{% widthratio tasks_count tasks_total 100 %}" aria-valuenow="{% widthratio tasks_count tasks_total 100 %}"
aria-valuemin="0" aria-valuemin="0"
aria-valuemax="100" aria-valuemax="100"
style="width: {% widthratio tasks_count tasks_total 100 %}%;" style="width: {% widthratio tasks_count tasks_total 100 %}%;">
title="{{ tasks_count|intcomma }} {{ label }}">
{% widthratio tasks_count tasks_total 100 %}% {% widthratio tasks_count tasks_total 100 %}%
</div> </div>

View File

@@ -78,10 +78,15 @@
<div class="panel-heading text-center"><h3 class="panel-title">{% translate "Task Queue" %}</h3></div> <div class="panel-heading text-center"><h3 class="panel-title">{% translate "Task Queue" %}</h3></div>
<div class="panel-body flex-center-horizontal"> <div class="panel-body flex-center-horizontal">
<p> <p>
{% blocktranslate with total=tasks_total|intcomma latest=earliest_task|timesince|default_if_none:"?" %} {% blocktranslate with total=tasks_total|intcomma latest=earliest_task|timesince|default:"?" %}
Status of {{ total }} processed tasks • last {{ latest }}</p> Status of {{ total }} processed tasks • last {{ latest }}
{% endblocktranslate %} {% endblocktranslate %}
<div class="progress" style="height: 21px;"> </p>
<div
class="progress"
style="height: 21px;"
title="{{ tasks_succeeded|intcomma }} succeeded, {{ tasks_retried|intcomma }} retried, {{ tasks_failed|intcomma }} failed"
>
{% include "allianceauth/admin-status/celery_bar_partial.html" with label="suceeded" level="success" tasks_count=tasks_succeeded %} {% include "allianceauth/admin-status/celery_bar_partial.html" with label="suceeded" level="success" tasks_count=tasks_succeeded %}
{% include "allianceauth/admin-status/celery_bar_partial.html" with label="retried" level="info" tasks_count=tasks_retried %} {% include "allianceauth/admin-status/celery_bar_partial.html" with label="retried" level="info" tasks_count=tasks_retried %}
{% include "allianceauth/admin-status/celery_bar_partial.html" with label="failed" level="danger" tasks_count=tasks_failed %} {% include "allianceauth/admin-status/celery_bar_partial.html" with label="failed" level="danger" tasks_count=tasks_failed %}

View File

@@ -3,17 +3,17 @@
{% if NIGHT_MODE %} {% if NIGHT_MODE %}
{% if debug %} {% if debug %}
<!-- In template debug, loading less file instead of CSS --> <!-- 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 %} <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 %} {% endif %}
{% else %} {% else %}
{% if debug %} {% if debug %}
<!-- In template debug, loading less file instead of CSS --> <!-- 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> <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 %} {% 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 %}
{% endif %} {% endif %}
<!-- End Bootstrap CSS --> <!-- End Bootstrap CSS -->

View File

@@ -1,3 +1,3 @@
<!-- Start Datatables-css from cdnjs --> <!-- 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 --> <!-- End Datatables-css from cdnjs -->

View File

@@ -1,3 +1,3 @@
<!-- Start FontAwesome CSS from cdnjs --> <!-- 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 --> <!-- End FontAwesome CSS from cdnjs -->

View File

@@ -1,3 +1,3 @@
<!-- Start jQuery-DateTimePicker CSS from cdnjs --> <!-- 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 --> <!-- End jQuery-DateTimePicker CSS from cdnjs -->

View File

@@ -1,5 +1,5 @@
{% load static %} {% load static %}
<!-- Start jQuery UI CSS from Alliance Auth --> <!-- 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 --> <!-- 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 --> <!-- End jQuery UI CSS from aa-gdpr -->

View File

@@ -1,3 +1,3 @@
<!-- Start X-editable CSS from cdnjs --> <!-- 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 --> <!-- End X-editable CSS from cdnjs -->

View File

@@ -13,7 +13,7 @@ from django.core.cache import cache
from allianceauth import __version__ from allianceauth import __version__
from ..authentication.task_statistics.event_series import dashboard_results from ..authentication.task_statistics.counters import dashboard_results
register = template.Library() register = template.Library()

View File

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

View File

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

View File

@@ -17,7 +17,7 @@
<form action="" method="post"> <form action="" method="post">
{% csrf_token %} {% csrf_token %}
<p>{% blocktrans %}Are you sure you want to delete timer "{{ object }}"?{% endblocktrans %}</p> <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> </form>
</div> </div>
</div> </div>

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