mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-12 01:56:25 +01:00
Compare commits
67 Commits
v4.6.2a
...
b02827cb3f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b02827cb3f | ||
|
|
2bcc0570ad | ||
|
|
a3ea0c65a1 | ||
|
|
5e526da11c | ||
|
|
5c79265f90 | ||
|
|
eb0134e716 | ||
|
|
afde1f4729 | ||
|
|
5c6dda0eac | ||
|
|
af453bc772 | ||
|
|
e13674e886 | ||
|
|
e3e856b826 | ||
|
|
9d1cd23a8f | ||
|
|
148f7c116f | ||
|
|
33e7134d6f | ||
|
|
fb799551aa | ||
|
|
7b95051fe1 | ||
|
|
efb6a6db4f | ||
|
|
478aa1aa12 | ||
|
|
751e55ed6c | ||
|
|
9dad53f763 | ||
|
|
2d57064a7a | ||
|
|
833d12cf66 | ||
|
|
7b56caa4cb | ||
|
|
5752644122 | ||
|
|
cadc0cb534 | ||
|
|
dcdab5ae1f | ||
|
|
d64e896288 | ||
|
|
500d8ede32 | ||
|
|
f4c5c7f6db | ||
|
|
43e1be4032 | ||
|
|
702def2a4d | ||
|
|
a34baf4154 | ||
|
|
4de0774f15 | ||
|
|
83d2dfc7d9 | ||
|
|
c93afd2d68 | ||
|
|
b7bacd11af | ||
|
|
f26835fae0 | ||
|
|
4edb7cb678 | ||
|
|
2ce9ba997f | ||
|
|
055077fa77 | ||
|
|
f342ccbc6a | ||
|
|
37ffd0a1ac | ||
|
|
a1f705381e | ||
|
|
c0970ad4fa | ||
|
|
3818d0c6d1 | ||
|
|
95411c79cb | ||
|
|
eeccbbacfc | ||
|
|
f6c4180502 | ||
|
|
f4d3d6c0b1 | ||
|
|
e9d2d11297 | ||
|
|
96204b29e8 | ||
|
|
47842c1243 | ||
|
|
9b494106bc | ||
|
|
d51e730a7f | ||
|
|
363909c0c4 | ||
|
|
82273f68fe | ||
|
|
12fa38b446 | ||
|
|
c26af593ff | ||
|
|
8e9a53c494 | ||
|
|
5559ce5fbb | ||
|
|
faa529a55b | ||
|
|
4ccfe20c14 | ||
|
|
3acb651650 | ||
|
|
2de57b334b | ||
|
|
0498f5bb1b | ||
|
|
929485a8f9 | ||
|
|
28cb62f373 |
@@ -5,7 +5,7 @@ manage online service access.
|
|||||||
# 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__ = '4.6.2a'
|
__version__ = '4.6.4'
|
||||||
__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__}'
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class AnalyticsConfig(AppConfig):
|
class AnalyticsConfig(AppConfig):
|
||||||
name = 'allianceauth.analytics'
|
name = 'allianceauth.analytics'
|
||||||
label = 'analytics'
|
label = 'analytics'
|
||||||
|
verbose_name = _('Analytics')
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from allianceauth.authentication.models import User
|
from allianceauth.authentication.models import User
|
||||||
from allianceauth.analytics.utils import install_stat_users, install_stat_addons
|
from esi.models import Token
|
||||||
|
from allianceauth.analytics.utils import install_stat_users, install_stat_tokens, install_stat_addons
|
||||||
|
|
||||||
from django.test.testcases import TestCase
|
from django.test.testcases import TestCase
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
from django.core.checks import register, Tags
|
from django.core.checks import register, Tags
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class AuthenticationConfig(AppConfig):
|
class AuthenticationConfig(AppConfig):
|
||||||
name = "allianceauth.authentication"
|
name = "allianceauth.authentication"
|
||||||
label = "authentication"
|
label = "authentication"
|
||||||
|
verbose_name = _("Authentication")
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
from allianceauth.authentication import checks, signals # noqa: F401
|
from allianceauth.authentication import checks, signals # noqa: F401
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
from django.urls import include
|
||||||
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import Callable, Iterable, Optional
|
from typing import Callable, Iterable, Optional
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
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 gettext_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
|
||||||
|
|
||||||
@@ -26,7 +28,7 @@ class State(models.Model):
|
|||||||
help_text="Factions to whose members this state is available.")
|
help_text="Factions to whose members this state is available.")
|
||||||
public = models.BooleanField(default=False, help_text="Make this state available to any character.")
|
public = models.BooleanField(default=False, help_text="Make this state available to any character.")
|
||||||
|
|
||||||
objects = StateManager()
|
objects: ClassVar[StateManager] = StateManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['-priority']
|
ordering = ['-priority']
|
||||||
@@ -136,8 +138,10 @@ class UserProfile(models.Model):
|
|||||||
sender=self.__class__, user=self.user, state=self.state
|
sender=self.__class__, user=self.user, state=self.state
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
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')
|
||||||
@@ -147,7 +151,7 @@ class CharacterOwnership(models.Model):
|
|||||||
owner_hash = models.CharField(max_length=28, unique=True)
|
owner_hash = models.CharField(max_length=28, unique=True)
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='character_ownerships')
|
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='character_ownerships')
|
||||||
|
|
||||||
objects = CharacterOwnershipManager()
|
objects: ClassVar[CharacterOwnershipManager] = CharacterOwnershipManager()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.user}: {self.character}"
|
return f"{self.user}: {self.character}"
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
{% load theme_tags %}
|
{% load theme_tags %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en" {% theme_html_tags %}>
|
||||||
<head>
|
<head>
|
||||||
|
<!-- Required meta tags -->
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="description" content="">
|
<!-- End Required meta tags -->
|
||||||
<meta name="author" content="">
|
|
||||||
<!-- TODO Bundle all the site specific stuff up into its own template for easy override -->
|
|
||||||
<meta property="og:title" content="{{ SITE_NAME }}">
|
|
||||||
<meta property="og:image" content="{{ SITE_URL }}{% static 'allianceauth/icons/apple-touch-icon.png' %}">
|
|
||||||
<meta property="og:description" content="Alliance Auth - An auth system for EVE Online to help in-game organizations manage online service access.">
|
|
||||||
|
|
||||||
|
<!-- Meta tags -->
|
||||||
|
{% include 'allianceauth/opengraph.html' %}
|
||||||
{% include 'allianceauth/icons.html' %}
|
{% include 'allianceauth/icons.html' %}
|
||||||
|
<!-- Meta tags -->
|
||||||
|
|
||||||
<title>{% block title %}{% block page_title %}{% endblock page_title %} - {{ SITE_NAME }}{% endblock title %}</title>
|
<title>{% block title %}{% block page_title %}{% endblock page_title %} - {{ SITE_NAME }}{% endblock title %}</title>
|
||||||
|
|
||||||
{% theme_css %}
|
{% theme_css %}
|
||||||
|
|
||||||
{% include 'bundles/fontawesome.html' %}
|
{% include 'bundles/fontawesome.html' %}
|
||||||
|
{% include 'bundles/auth-framework-css.html' %}
|
||||||
|
|
||||||
{% block extra_include %}
|
{% block extra_include %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
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
|
from unittest import mock
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from unittest import mock
|
||||||
from allianceauth.authentication.middleware import UserSettingsMiddleware
|
from allianceauth.authentication.middleware import UserSettingsMiddleware
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
|||||||
@@ -4,10 +4,16 @@ from allianceauth.eveonline.models import (
|
|||||||
EveCorporationInfo,
|
EveCorporationInfo,
|
||||||
EveAllianceInfo
|
EveAllianceInfo
|
||||||
)
|
)
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import (
|
||||||
|
pre_save,
|
||||||
|
post_save,
|
||||||
|
pre_delete,
|
||||||
|
m2m_changed
|
||||||
|
)
|
||||||
from allianceauth.tests.auth_utils import AuthUtils
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
|
||||||
from django.test.testcases import TestCase
|
from django.test.testcases import TestCase
|
||||||
|
from unittest.mock import Mock
|
||||||
from . import patch
|
from . import patch
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from django.conf import settings
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import authenticate, login
|
from django.contrib.auth import authenticate, login
|
||||||
from django.contrib.auth.decorators import login_required, user_passes_test
|
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.core import signing
|
from django.core import signing
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
"""
|
||||||
|
Django system checks for Alliance Auth
|
||||||
|
"""
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
from django import db
|
from django import db
|
||||||
from django.core.checks import CheckMessage, Error, register, Warning
|
from django.core.checks import CheckMessage, Error, register, Warning
|
||||||
@@ -16,48 +20,172 @@ B = Configuration
|
|||||||
|
|
||||||
@register()
|
@register()
|
||||||
def django_settings(app_configs, **kwargs) -> List[CheckMessage]:
|
def django_settings(app_configs, **kwargs) -> List[CheckMessage]:
|
||||||
errors: List[CheckMessage] = []
|
"""
|
||||||
if hasattr(settings, "SITE_URL"):
|
Check that Django settings are correctly configured
|
||||||
if settings.SITE_URL[-1] == "/":
|
|
||||||
errors.append(Warning("'SITE_URL' Has a trailing slash. This may lead to incorrect links being generated by Auth.", hint="", id="allianceauth.checks.B005"))
|
|
||||||
else:
|
|
||||||
errors.append(Error("No 'SITE_URL' found is settings. This may lead to incorrect links being generated by Auth or Errors in 3rd party modules.", hint="", id="allianceauth.checks.B006"))
|
|
||||||
|
|
||||||
if hasattr(settings, "CSRF_TRUSTED_ORIGINS") and hasattr(settings, "SITE_URL"):
|
:param app_configs:
|
||||||
if settings.SITE_URL not in settings.CSRF_TRUSTED_ORIGINS:
|
:type app_configs:
|
||||||
errors.append(Warning("'SITE_URL' not found in 'CSRF_TRUSTED_ORIGINS'. Auth may not load pages correctly until this is rectified.", hint="", id="allianceauth.checks.B007"))
|
:param kwargs:
|
||||||
|
:type kwargs:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
errors: List[CheckMessage] = []
|
||||||
|
|
||||||
|
# Check for SITE_URL
|
||||||
|
if hasattr(settings, "SITE_URL"):
|
||||||
|
# Check if SITE_URL is empty
|
||||||
|
if settings.SITE_URL == "":
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg="'SITE_URL' is empty.",
|
||||||
|
hint="Make sure to set 'SITE_URL' to the URL of your Auth instance. (Without trailing slash)",
|
||||||
|
id="allianceauth.checks.B011",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# Check if SITE_URL has a trailing slash
|
||||||
|
elif settings.SITE_URL[-1] == "/":
|
||||||
|
errors.append(
|
||||||
|
Warning(
|
||||||
|
msg="'SITE_URL' has a trailing slash. This may lead to incorrect links being generated by Auth.",
|
||||||
|
hint="",
|
||||||
|
id="allianceauth.checks.B005",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# SITE_URL not found
|
||||||
else:
|
else:
|
||||||
errors.append(Error("No 'CSRF_TRUSTED_ORIGINS' found is settings, Auth may not load pages correctly until this is rectified", hint="", id="allianceauth.checks.B008"))
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg="No 'SITE_URL' found is settings. This may lead to incorrect links being generated by Auth or Errors in 3rd party modules.",
|
||||||
|
hint="",
|
||||||
|
id="allianceauth.checks.B006",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check for CSRF_TRUSTED_ORIGINS
|
||||||
|
if hasattr(settings, "CSRF_TRUSTED_ORIGINS") and hasattr(settings, "SITE_URL"):
|
||||||
|
# Check if SITE_URL is not in CSRF_TRUSTED_ORIGINS
|
||||||
|
if settings.SITE_URL not in settings.CSRF_TRUSTED_ORIGINS:
|
||||||
|
errors.append(
|
||||||
|
Warning(
|
||||||
|
msg="'SITE_URL' not found in 'CSRF_TRUSTED_ORIGINS'. Auth may not load pages correctly until this is rectified.",
|
||||||
|
hint="",
|
||||||
|
id="allianceauth.checks.B007",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# CSRF_TRUSTED_ORIGINS not found
|
||||||
|
else:
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg="No 'CSRF_TRUSTED_ORIGINS' found is settings, Auth may not load pages correctly until this is rectified",
|
||||||
|
hint="",
|
||||||
|
id="allianceauth.checks.B008",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check for ESI_USER_CONTACT_EMAIL
|
||||||
|
if hasattr(settings, "ESI_USER_CONTACT_EMAIL"):
|
||||||
|
# Check if ESI_USER_CONTACT_EMAIL is empty
|
||||||
|
if settings.ESI_USER_CONTACT_EMAIL == "":
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg="'ESI_USER_CONTACT_EMAIL' is empty. A valid email is required as maintainer contact for CCP.",
|
||||||
|
hint="",
|
||||||
|
id="allianceauth.checks.B009",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# ESI_USER_CONTACT_EMAIL not found
|
||||||
|
else:
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg="No 'ESI_USER_CONTACT_EMAIL' found is settings. A valid email is required as maintainer contact for CCP.",
|
||||||
|
hint="",
|
||||||
|
id="allianceauth.checks.B010",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
def system_package_redis(app_configs, **kwargs) -> List[CheckMessage]:
|
def system_package_redis(app_configs, **kwargs) -> List[CheckMessage]:
|
||||||
|
"""
|
||||||
|
Check that Redis is a supported version
|
||||||
|
|
||||||
|
:param app_configs:
|
||||||
|
:type app_configs:
|
||||||
|
:param kwargs:
|
||||||
|
:type kwargs:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
allianceauth_redis_install_link = "https://allianceauth.readthedocs.io/en/latest/installation/allianceauth.html#redis-and-other-tools"
|
allianceauth_redis_install_link = "https://allianceauth.readthedocs.io/en/latest/installation/allianceauth.html#redis-and-other-tools"
|
||||||
|
|
||||||
errors: List[CheckMessage] = []
|
errors: List[CheckMessage] = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
redis_version = Pep440Version(get_redis_client().info()['redis_version'])
|
redis_version = Pep440Version(get_redis_client().info()["redis_version"])
|
||||||
except InvalidVersion:
|
except InvalidVersion:
|
||||||
errors.append(Warning("Unable to confirm Redis Version"))
|
errors.append(Warning("Unable to confirm Redis Version"))
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
if redis_version.major == 7 and redis_version.minor == 2 and timezone.now() > timezone.datetime(year=2025, month=8, day=31, tzinfo=timezone.utc):
|
if (
|
||||||
errors.append(Error(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint=allianceauth_redis_install_link, id="allianceauth.checks.A001"))
|
redis_version.major == 7
|
||||||
|
and redis_version.minor == 2
|
||||||
|
and timezone.now()
|
||||||
|
> timezone.datetime(year=2025, month=8, day=31, tzinfo=timezone.utc)
|
||||||
|
):
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"Redis {redis_version.public} in Security Support only, Updating Suggested",
|
||||||
|
hint=allianceauth_redis_install_link,
|
||||||
|
id="allianceauth.checks.A001",
|
||||||
|
)
|
||||||
|
)
|
||||||
elif redis_version.major == 7 and redis_version.minor == 0:
|
elif redis_version.major == 7 and redis_version.minor == 0:
|
||||||
errors.append(Warning(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint=allianceauth_redis_install_link, id="allianceauth.checks.A002"))
|
errors.append(
|
||||||
|
Warning(
|
||||||
|
msg=f"Redis {redis_version.public} in Security Support only, Updating Suggested",
|
||||||
|
hint=allianceauth_redis_install_link,
|
||||||
|
id="allianceauth.checks.A002",
|
||||||
|
)
|
||||||
|
)
|
||||||
elif redis_version.major == 6 and redis_version.minor == 2:
|
elif redis_version.major == 6 and redis_version.minor == 2:
|
||||||
errors.append(Warning(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint=allianceauth_redis_install_link, id="allianceauth.checks.A018"))
|
errors.append(
|
||||||
|
Warning(
|
||||||
|
msg=f"Redis {redis_version.public} in Security Support only, Updating Suggested",
|
||||||
|
hint=allianceauth_redis_install_link,
|
||||||
|
id="allianceauth.checks.A018",
|
||||||
|
)
|
||||||
|
)
|
||||||
elif redis_version.major in [6, 5]:
|
elif redis_version.major in [6, 5]:
|
||||||
errors.append(Error(f"Redis {redis_version.public} EOL", hint=allianceauth_redis_install_link, id="allianceauth.checks.A003"))
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"Redis {redis_version.public} EOL",
|
||||||
|
hint=allianceauth_redis_install_link,
|
||||||
|
id="allianceauth.checks.A003",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
def system_package_mysql(app_configs, **kwargs) -> List[CheckMessage]:
|
def system_package_mysql(app_configs, **kwargs) -> List[CheckMessage]:
|
||||||
|
"""
|
||||||
|
Check that MySQL is a supported version
|
||||||
|
|
||||||
|
:param app_configs:
|
||||||
|
:type app_configs:
|
||||||
|
:param kwargs:
|
||||||
|
:type kwargs:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
mysql_quick_guide_link = "https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/"
|
mysql_quick_guide_link = "https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/"
|
||||||
|
|
||||||
errors: List[CheckMessage] = []
|
errors: List[CheckMessage] = []
|
||||||
@@ -65,108 +193,302 @@ def system_package_mysql(app_configs, **kwargs) -> List[CheckMessage]:
|
|||||||
for connection in db.connections.all():
|
for connection in db.connections.all():
|
||||||
if connection.vendor == "mysql":
|
if connection.vendor == "mysql":
|
||||||
try:
|
try:
|
||||||
mysql_version = Pep440Version(".".join(str(i) for i in connection.mysql_version))
|
mysql_version = Pep440Version(
|
||||||
|
".".join(str(i) for i in connection.mysql_version)
|
||||||
|
)
|
||||||
except InvalidVersion:
|
except InvalidVersion:
|
||||||
errors.append(Warning("Unable to confirm MySQL Version"))
|
errors.append(Warning("Unable to confirm MySQL Version"))
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
# MySQL 8
|
# MySQL 8
|
||||||
if mysql_version.major == 8:
|
if mysql_version.major == 8:
|
||||||
if mysql_version.minor == 4 and timezone.now() > timezone.datetime(year=2032, month=4, day=30, tzinfo=timezone.utc):
|
if mysql_version.minor == 4 and timezone.now() > timezone.datetime(
|
||||||
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint=mysql_quick_guide_link, id="allianceauth.checks.A004"))
|
year=2032, month=4, day=30, tzinfo=timezone.utc
|
||||||
|
):
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"MySQL {mysql_version.public} EOL",
|
||||||
|
hint=mysql_quick_guide_link,
|
||||||
|
id="allianceauth.checks.A004",
|
||||||
|
)
|
||||||
|
)
|
||||||
elif mysql_version.minor == 3:
|
elif mysql_version.minor == 3:
|
||||||
errors.append(Warning(f"MySQL {mysql_version.public} Non LTS", hint=mysql_quick_guide_link, id="allianceauth.checks.A005"))
|
errors.append(
|
||||||
|
Warning(
|
||||||
|
msg=f"MySQL {mysql_version.public} Non LTS",
|
||||||
|
hint=mysql_quick_guide_link,
|
||||||
|
id="allianceauth.checks.A005",
|
||||||
|
)
|
||||||
|
)
|
||||||
elif mysql_version.minor == 2:
|
elif mysql_version.minor == 2:
|
||||||
errors.append(Warning(f"MySQL {mysql_version.public} Non LTS", hint=mysql_quick_guide_link, id="allianceauth.checks.A006"))
|
errors.append(
|
||||||
|
Warning(
|
||||||
|
msg=f"MySQL {mysql_version.public} Non LTS",
|
||||||
|
hint=mysql_quick_guide_link,
|
||||||
|
id="allianceauth.checks.A006",
|
||||||
|
)
|
||||||
|
)
|
||||||
elif mysql_version.minor == 1:
|
elif mysql_version.minor == 1:
|
||||||
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint=mysql_quick_guide_link, id="allianceauth.checks.A007"))
|
errors.append(
|
||||||
elif mysql_version.minor == 0 and timezone.now() > timezone.datetime(year=2026, month=4, day=30, tzinfo=timezone.utc):
|
Error(
|
||||||
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint=mysql_quick_guide_link, id="allianceauth.checks.A008"))
|
msg=f"MySQL {mysql_version.public} EOL",
|
||||||
|
hint=mysql_quick_guide_link,
|
||||||
|
id="allianceauth.checks.A007",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif mysql_version.minor == 0 and timezone.now() > timezone.datetime(
|
||||||
|
year=2026, month=4, day=30, tzinfo=timezone.utc
|
||||||
|
):
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"MySQL {mysql_version.public} EOL",
|
||||||
|
hint=mysql_quick_guide_link,
|
||||||
|
id="allianceauth.checks.A008",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# MySQL below 8
|
# MySQL below 8
|
||||||
# This will also catch Mariadb 5.x
|
# This will also catch Mariadb 5.x
|
||||||
elif mysql_version.major < 8:
|
elif mysql_version.major < 8:
|
||||||
errors.append(Error(f"MySQL or MariaDB {mysql_version.public} EOL", hint=mysql_quick_guide_link, id="allianceauth.checks.A009"))
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"MySQL or MariaDB {mysql_version.public} EOL",
|
||||||
|
hint=mysql_quick_guide_link,
|
||||||
|
id="allianceauth.checks.A009",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
def system_package_mariadb(app_configs, **kwargs) -> List[CheckMessage]:
|
def system_package_mariadb(app_configs, **kwargs) -> List[CheckMessage]:
|
||||||
|
"""
|
||||||
|
Check that MariaDB is a supported version
|
||||||
|
|
||||||
|
:param app_configs:
|
||||||
|
:type app_configs:
|
||||||
|
:param kwargs:
|
||||||
|
:type kwargs:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
mariadb_download_link = "https://mariadb.org/download/?t=repo-config"
|
mariadb_download_link = "https://mariadb.org/download/?t=repo-config"
|
||||||
|
|
||||||
errors: List[CheckMessage] = []
|
errors: List[CheckMessage] = []
|
||||||
|
|
||||||
for connection in db.connections.all():
|
for connection in db.connections.all():
|
||||||
if connection.vendor == "mysql": # Still to find a way to determine MySQL vs MariaDB
|
# TODO: Find a way to determine MySQL vs. MariaDB
|
||||||
|
if connection.vendor == "mysql":
|
||||||
try:
|
try:
|
||||||
mariadb_version = Pep440Version(".".join(str(i) for i in connection.mysql_version))
|
mariadb_version = Pep440Version(
|
||||||
|
".".join(str(i) for i in connection.mysql_version)
|
||||||
|
)
|
||||||
except InvalidVersion:
|
except InvalidVersion:
|
||||||
errors.append(Warning("Unable to confirm MariaDB Version"))
|
errors.append(Warning("Unable to confirm MariaDB Version"))
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
# MariaDB 11
|
# MariaDB 11
|
||||||
if mariadb_version.major == 11:
|
if mariadb_version.major == 11:
|
||||||
if mariadb_version.minor == 4 and timezone.now() > timezone.datetime(year=2029, month=5, day=19, tzinfo=timezone.utc):
|
if mariadb_version.minor == 4 and timezone.now() > timezone.datetime(
|
||||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A010"))
|
year=2029, month=5, day=19, tzinfo=timezone.utc
|
||||||
|
):
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"MariaDB {mariadb_version.public} EOL",
|
||||||
|
hint=mariadb_download_link,
|
||||||
|
id="allianceauth.checks.A010",
|
||||||
|
)
|
||||||
|
)
|
||||||
elif mariadb_version.minor == 2:
|
elif mariadb_version.minor == 2:
|
||||||
errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint=mariadb_download_link, id="allianceauth.checks.A018"))
|
errors.append(
|
||||||
|
Warning(
|
||||||
|
msg=f"MariaDB {mariadb_version.public} Non LTS",
|
||||||
|
hint=mariadb_download_link,
|
||||||
|
id="allianceauth.checks.A018",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if timezone.now() > timezone.datetime(year=2024, month=11, day=21, tzinfo=timezone.utc):
|
if timezone.now() > timezone.datetime(
|
||||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A011"))
|
year=2024, month=11, day=21, tzinfo=timezone.utc
|
||||||
|
):
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"MariaDB {mariadb_version.public} EOL",
|
||||||
|
hint=mariadb_download_link,
|
||||||
|
id="allianceauth.checks.A011",
|
||||||
|
)
|
||||||
|
)
|
||||||
elif mariadb_version.minor == 1:
|
elif mariadb_version.minor == 1:
|
||||||
errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint=mariadb_download_link, id="allianceauth.checks.A019"))
|
errors.append(
|
||||||
|
Warning(
|
||||||
|
msg=f"MariaDB {mariadb_version.public} Non LTS",
|
||||||
|
hint=mariadb_download_link,
|
||||||
|
id="allianceauth.checks.A019",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if timezone.now() > timezone.datetime(year=2024, month=8, day=21, tzinfo=timezone.utc):
|
if timezone.now() > timezone.datetime(
|
||||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A012"))
|
year=2024, month=8, day=21, tzinfo=timezone.utc
|
||||||
elif mariadb_version.minor in [0, 3]: # Demote versions down here once EOL
|
):
|
||||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A013"))
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"MariaDB {mariadb_version.public} EOL",
|
||||||
|
hint=mariadb_download_link,
|
||||||
|
id="allianceauth.checks.A012",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# Demote versions down here once EOL
|
||||||
|
elif mariadb_version.minor in [0, 3]:
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"MariaDB {mariadb_version.public} EOL",
|
||||||
|
hint=mariadb_download_link,
|
||||||
|
id="allianceauth.checks.A013",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# MariaDB 10
|
# MariaDB 10
|
||||||
elif mariadb_version.major == 10:
|
elif mariadb_version.major == 10:
|
||||||
if mariadb_version.minor == 11 and timezone.now() > timezone.datetime(year=2028, month=2, day=10, tzinfo=timezone.utc):
|
if mariadb_version.minor == 11 and timezone.now() > timezone.datetime(
|
||||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A014"))
|
year=2028, month=2, day=10, tzinfo=timezone.utc
|
||||||
elif mariadb_version.minor == 6 and timezone.now() > timezone.datetime(year=2026, month=7, day=6, tzinfo=timezone.utc):
|
):
|
||||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A0015"))
|
errors.append(
|
||||||
elif mariadb_version.minor == 5 and timezone.now() > timezone.datetime(year=2025, month=6, day=24, tzinfo=timezone.utc):
|
Error(
|
||||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A016"))
|
msg=f"MariaDB {mariadb_version.public} EOL",
|
||||||
elif mariadb_version.minor in [0, 1, 2, 3, 4, 7, 9, 10]: # Demote versions down here once EOL
|
hint=mariadb_download_link,
|
||||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A017"))
|
id="allianceauth.checks.A014",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif mariadb_version.minor == 6 and timezone.now() > timezone.datetime(
|
||||||
|
year=2026, month=7, day=6, tzinfo=timezone.utc
|
||||||
|
):
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"MariaDB {mariadb_version.public} EOL",
|
||||||
|
hint=mariadb_download_link,
|
||||||
|
id="allianceauth.checks.A0015",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif mariadb_version.minor == 5 and timezone.now() > timezone.datetime(
|
||||||
|
year=2025, month=6, day=24, tzinfo=timezone.utc
|
||||||
|
):
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"MariaDB {mariadb_version.public} EOL",
|
||||||
|
hint=mariadb_download_link,
|
||||||
|
id="allianceauth.checks.A016",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# Demote versions down here once EOL
|
||||||
|
elif mariadb_version.minor in [0, 1, 2, 3, 4, 7, 9, 10]:
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"MariaDB {mariadb_version.public} EOL",
|
||||||
|
hint=mariadb_download_link,
|
||||||
|
id="allianceauth.checks.A017",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
def system_package_sqlite(app_configs, **kwargs) -> List[CheckMessage]:
|
def system_package_sqlite(app_configs, **kwargs) -> List[CheckMessage]:
|
||||||
|
"""
|
||||||
|
Check that SQLite is a supported version
|
||||||
|
|
||||||
|
:param app_configs:
|
||||||
|
:type app_configs:
|
||||||
|
:param kwargs:
|
||||||
|
:type kwargs:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
errors: List[CheckMessage] = []
|
errors: List[CheckMessage] = []
|
||||||
|
|
||||||
for connection in db.connections.all():
|
for connection in db.connections.all():
|
||||||
if connection.vendor == "sqlite":
|
if connection.vendor == "sqlite":
|
||||||
try:
|
try:
|
||||||
sqlite_version = Pep440Version(".".join(str(i) for i in sqlite_version_info))
|
sqlite_version = Pep440Version(
|
||||||
|
".".join(str(i) for i in sqlite_version_info)
|
||||||
|
)
|
||||||
except InvalidVersion:
|
except InvalidVersion:
|
||||||
errors.append(Warning("Unable to confirm SQLite Version"))
|
errors.append(Warning("Unable to confirm SQLite Version"))
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
if sqlite_version.major == 3 and sqlite_version.minor < 27:
|
if sqlite_version.major == 3 and sqlite_version.minor < 27:
|
||||||
errors.append(Error(f"SQLite {sqlite_version.public} Unsupported by Django", hint="https://pkgs.org/download/sqlite3", id="allianceauth.checks.A020"))
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"SQLite {sqlite_version.public} Unsupported by Django",
|
||||||
|
hint="https://pkgs.org/download/sqlite3",
|
||||||
|
id="allianceauth.checks.A020",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
def sql_settings(app_configs, **kwargs) -> List[CheckMessage]:
|
def sql_settings(app_configs, **kwargs) -> List[CheckMessage]:
|
||||||
|
"""
|
||||||
|
Check that SQL settings are correctly configured
|
||||||
|
|
||||||
|
:param app_configs:
|
||||||
|
:type app_configs:
|
||||||
|
:param kwargs:
|
||||||
|
:type kwargs:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
errors: List[CheckMessage] = []
|
errors: List[CheckMessage] = []
|
||||||
|
|
||||||
for connection in db.connections.all():
|
for connection in db.connections.all():
|
||||||
if connection.vendor == "mysql":
|
if connection.vendor == "mysql":
|
||||||
try:
|
try:
|
||||||
if connection.settings_dict["OPTIONS"]["charset"] != "utf8mb4":
|
if connection.settings_dict["OPTIONS"]["charset"] != "utf8mb4":
|
||||||
errors.append(Error(f"SQL Charset is not set to utf8mb4 DB:{connection.alias}", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"SQL Charset is not set to utf8mb4 DB: {connection.alias}",
|
||||||
|
hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8",
|
||||||
|
id="allianceauth.checks.B001",
|
||||||
|
)
|
||||||
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
errors.append(Error(f"SQL Charset is not set to utf8mb4 DB:{connection.alias}", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg=f"SQL Charset is not set to utf8mb4 DB: {connection.alias}",
|
||||||
|
hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8",
|
||||||
|
id="allianceauth.checks.B001",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# This hasn't actually been set on AA yet
|
# This hasn't actually been set on AA yet
|
||||||
# try:
|
# try:
|
||||||
# if connection.settings_dict["OPTIONS"]["collation"] != "utf8mb4_unicode_ci":
|
# if (
|
||||||
# errors.append(Error(f"SQL Collation is not set to utf8mb4_unicode_ci DB:{connection.alias}", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
|
# connection.settings_dict["OPTIONS"]["collation"]
|
||||||
|
# != "utf8mb4_unicode_ci"
|
||||||
|
# ):
|
||||||
|
# errors.append(
|
||||||
|
# Error(
|
||||||
|
# msg=f"SQL Collation is not set to utf8mb4_unicode_ci DB:{connection.alias}",
|
||||||
|
# hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8",
|
||||||
|
# id="allianceauth.checks.B001",
|
||||||
|
# )
|
||||||
|
# )
|
||||||
# except KeyError:
|
# except KeyError:
|
||||||
# errors.append(Error(f"SQL Collation is not set to utf8mb4_unicode_ci DB:{connection.alias}", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
|
# errors.append(
|
||||||
|
# Error(
|
||||||
|
# msg=f"SQL Collation is not set to utf8mb4_unicode_ci DB:{connection.alias}",
|
||||||
|
# hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8",
|
||||||
|
# id="allianceauth.checks.B001",
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
|
||||||
# if connection.vendor == "sqlite":
|
# if connection.vendor == "sqlite":
|
||||||
|
|
||||||
@@ -175,19 +497,57 @@ def sql_settings(app_configs, **kwargs) -> List[CheckMessage]:
|
|||||||
|
|
||||||
@register()
|
@register()
|
||||||
def celery_settings(app_configs, **kwargs) -> List[CheckMessage]:
|
def celery_settings(app_configs, **kwargs) -> List[CheckMessage]:
|
||||||
|
"""
|
||||||
|
Check that Celery settings are correctly configured
|
||||||
|
|
||||||
|
:param app_configs:
|
||||||
|
:type app_configs:
|
||||||
|
:param kwargs:
|
||||||
|
:type kwargs:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
errors: List[CheckMessage] = []
|
errors: List[CheckMessage] = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if current_app.conf.broker_transport_options != {'priority_steps': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 'queue_order_strategy': 'priority'}:
|
if current_app.conf.broker_transport_options != {
|
||||||
errors.append(Error("Celery Priorities are not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc", id="allianceauth.checks.B003"))
|
"priority_steps": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||||
|
"queue_order_strategy": "priority",
|
||||||
|
}:
|
||||||
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg="Celery Priorities are not set correctly",
|
||||||
|
hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc",
|
||||||
|
id="allianceauth.checks.B003",
|
||||||
|
)
|
||||||
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
errors.append(Error("Celery Priorities are not set", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc", id="allianceauth.checks.B003"))
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg="Celery Priorities are not set",
|
||||||
|
hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc",
|
||||||
|
id="allianceauth.checks.B003",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if current_app.conf.broker_connection_retry_on_startup != True:
|
if not current_app.conf.broker_connection_retry_on_startup:
|
||||||
errors.append(Error("Celery broker_connection_retry_on_startup not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280", id="allianceauth.checks.B004"))
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg="Celery broker_connection_retry_on_startup not set correctly",
|
||||||
|
hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280",
|
||||||
|
id="allianceauth.checks.B004",
|
||||||
|
)
|
||||||
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
errors.append(Error("Celery broker_connection_retry_on_startup not set", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280", id="allianceauth.checks.B004"))
|
errors.append(
|
||||||
|
Error(
|
||||||
|
msg="Celery broker_connection_retry_on_startup not set",
|
||||||
|
hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280",
|
||||||
|
id="allianceauth.checks.B004",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class CorpUtilsConfig(AppConfig):
|
class CorpUtilsConfig(AppConfig):
|
||||||
name = 'allianceauth.corputils'
|
name = 'allianceauth.corputils'
|
||||||
label = 'corputils'
|
label = 'corputils'
|
||||||
|
verbose_name = _('Corporation Stats')
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
from allianceauth.authentication.models import CharacterOwnership, UserProfile
|
from allianceauth.authentication.models import CharacterOwnership, UserProfile
|
||||||
from bravado.exception import HTTPForbidden
|
from bravado.exception import HTTPForbidden
|
||||||
@@ -40,9 +41,9 @@ class CorpStats(models.Model):
|
|||||||
verbose_name = "corp stats"
|
verbose_name = "corp stats"
|
||||||
verbose_name_plural = "corp stats"
|
verbose_name_plural = "corp stats"
|
||||||
|
|
||||||
objects = CorpStatsManager()
|
objects: ClassVar[CorpStatsManager] = CorpStatsManager()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return f"{self.__class__.__name__} for {self.corp}"
|
return f"{self.__class__.__name__} for {self.corp}"
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ Crontab App Config
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class CrontabConfig(AppConfig):
|
class CrontabConfig(AppConfig):
|
||||||
@@ -12,3 +13,4 @@ class CrontabConfig(AppConfig):
|
|||||||
|
|
||||||
name = "allianceauth.crontab"
|
name = "allianceauth.crontab"
|
||||||
label = "crontab"
|
label = "crontab"
|
||||||
|
verbose_name = _("Crontab")
|
||||||
|
|||||||
@@ -40,10 +40,11 @@ class OffsetDatabaseScheduler(DatabaseScheduler):
|
|||||||
|
|
||||||
for name, entry_fields in mapping.items():
|
for name, entry_fields in mapping.items():
|
||||||
try:
|
try:
|
||||||
apply_offset = entry_fields.pop("apply_offset", False) # Ensure this pops before django tries to save to ORM
|
apply_offset = entry_fields.pop("apply_offset", False) # Ensure this pops before django tries to save to ORM
|
||||||
entry = self.Entry.from_entry(name, app=self.app, **entry_fields)
|
entry = self.Entry.from_entry(name, app=self.app, **entry_fields)
|
||||||
|
|
||||||
if apply_offset:
|
if apply_offset:
|
||||||
|
entry_fields.update({"apply_offset": apply_offset}) # Reapply this as its gets pulled from config inconsistently.
|
||||||
schedule_obj = entry.schedule
|
schedule_obj = entry.schedule
|
||||||
if isinstance(schedule_obj, schedules.crontab):
|
if isinstance(schedule_obj, schedules.crontab):
|
||||||
offset_cs = CrontabSchedule.from_schedule(offset_cron(schedule_obj))
|
offset_cs = CrontabSchedule.from_schedule(offset_cron(schedule_obj))
|
||||||
@@ -55,6 +56,7 @@ class OffsetDatabaseScheduler(DatabaseScheduler):
|
|||||||
day_of_week=offset_cs.day_of_week,
|
day_of_week=offset_cs.day_of_week,
|
||||||
timezone=offset_cs.timezone,
|
timezone=offset_cs.timezone,
|
||||||
)
|
)
|
||||||
|
entry.schedule = offset_cron(schedule_obj) # This gets passed into Celery Beats Memory, important to keep it in sync with the model/DB
|
||||||
entry.model.crontab = offset_cs
|
entry.model.crontab = offset_cs
|
||||||
entry.model.save()
|
entry.model.save()
|
||||||
logger.debug(f"Offset applied for '{name}' due to 'apply_offset' = True.")
|
logger.debug(f"Offset applied for '{name}' due to 'apply_offset' = True.")
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# myapp/tests/test_tasks.py
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ Form widgets for custom_css app
|
|||||||
# Django
|
# Django
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
|
# Alliance Auth
|
||||||
|
from allianceauth.custom_css.models import CustomCSS
|
||||||
|
|
||||||
|
|
||||||
class CssEditorWidget(forms.Textarea):
|
class CssEditorWidget(forms.Textarea):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class EveonlineConfig(AppConfig):
|
class EveonlineConfig(AppConfig):
|
||||||
name = 'allianceauth.eveonline'
|
name = 'allianceauth.eveonline'
|
||||||
label = 'eveonline'
|
label = 'eveonline'
|
||||||
|
verbose_name = _('EVE Online')
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class EveAutogroupsConfig(AppConfig):
|
class EveAutogroupsConfig(AppConfig):
|
||||||
name = 'allianceauth.eveonline.autogroups'
|
name = 'allianceauth.eveonline.autogroups'
|
||||||
label = 'eve_autogroups'
|
label = 'eve_autogroups'
|
||||||
|
verbose_name = _('EVE Online Autogroups')
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
import allianceauth.eveonline.autogroups.signals
|
import allianceauth.eveonline.autogroups.signals
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from typing import ClassVar
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group, User
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
@@ -78,7 +79,7 @@ class AutogroupsConfig(models.Model):
|
|||||||
max_length=10, default='', blank=True,
|
max_length=10, default='', blank=True,
|
||||||
help_text='Any spaces in the group name will be replaced with this.')
|
help_text='Any spaces in the group name will be replaced with this.')
|
||||||
|
|
||||||
objects = AutogroupsConfigManager()
|
objects: ClassVar[AutogroupsConfigManager] = AutogroupsConfigManager()
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
from allianceauth.tests.auth_utils import AuthUtils
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from ...models import EveCharacter, EveCorporationInfo, EveAllianceInfo
|
||||||
from .. import dotlan, zkillboard, evewho, eveimageserver
|
from .. import dotlan, zkillboard, evewho, eveimageserver
|
||||||
|
from ...templatetags import evelinks
|
||||||
|
|
||||||
|
|
||||||
class TestEveWho(TestCase):
|
class TestEveWho(TestCase):
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ class EveCharacterProviderManager:
|
|||||||
class EveCharacterManager(models.Manager):
|
class EveCharacterManager(models.Manager):
|
||||||
provider = EveCharacterProviderManager()
|
provider = EveCharacterProviderManager()
|
||||||
|
|
||||||
def create_character(self, character_id):
|
def create_character(self, character_id) -> models.Model:
|
||||||
return self.create_character_obj(self.provider.get_character(character_id))
|
return self.create_character_obj(self.provider.get_character(character_id))
|
||||||
|
|
||||||
def create_character_obj(self, character: providers.Character):
|
def create_character_obj(self, character: providers.Character) -> models.Model:
|
||||||
return self.create(
|
return self.create(
|
||||||
character_id=character.id,
|
character_id=character.id,
|
||||||
character_name=character.name,
|
character_name=character.name,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Union
|
from typing import ClassVar, Union
|
||||||
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db import models
|
from django.db import models
|
||||||
@@ -75,8 +75,8 @@ class EveAllianceInfo(models.Model):
|
|||||||
alliance_ticker = models.CharField(max_length=254)
|
alliance_ticker = models.CharField(max_length=254)
|
||||||
executor_corp_id = models.PositiveIntegerField()
|
executor_corp_id = models.PositiveIntegerField()
|
||||||
|
|
||||||
objects = EveAllianceManager()
|
objects: ClassVar[EveAllianceManager] = EveAllianceManager()
|
||||||
provider = EveAllianceProviderManager()
|
provider: ClassVar[EveAllianceProviderManager] = EveAllianceProviderManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
indexes = [models.Index(fields=['executor_corp_id',])]
|
indexes = [models.Index(fields=['executor_corp_id',])]
|
||||||
@@ -147,7 +147,7 @@ class EveCorporationInfo(models.Model):
|
|||||||
EveAllianceInfo, blank=True, null=True, on_delete=models.SET_NULL
|
EveAllianceInfo, blank=True, null=True, on_delete=models.SET_NULL
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = EveCorporationManager()
|
objects: ClassVar[EveCorporationManager] = EveCorporationManager()
|
||||||
provider = EveCorporationProviderManager()
|
provider = EveCorporationProviderManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -214,7 +214,7 @@ class EveCharacter(models.Model):
|
|||||||
faction_id = models.PositiveIntegerField(blank=True, null=True, default=None)
|
faction_id = models.PositiveIntegerField(blank=True, null=True, default=None)
|
||||||
faction_name = models.CharField(max_length=254, blank=True, null=True, default='')
|
faction_name = models.CharField(max_length=254, blank=True, null=True, default='')
|
||||||
|
|
||||||
objects = EveCharacterManager()
|
objects: ClassVar[EveCharacterManager] = EveCharacterManager()
|
||||||
provider = EveCharacterProviderManager()
|
provider = EveCharacterProviderManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
@@ -723,5 +723,5 @@ class TestEveSwaggerProvider(TestCase):
|
|||||||
my_client = my_provider.client
|
my_client = my_provider.client
|
||||||
operation = my_client.Universe.get_universe_factions()
|
operation = my_client.Universe.get_universe_factions()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
operation.future.request.headers['User-Agent'], 'allianceauth v1.0.0'
|
operation.future.request.headers['User-Agent'], 'allianceauth v1.0.0 dummy@example.net'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class FatConfig(AppConfig):
|
class FatConfig(AppConfig):
|
||||||
name = 'allianceauth.fleetactivitytracking'
|
name = 'allianceauth.fleetactivitytracking'
|
||||||
label = 'fleetactivitytracking'
|
label = 'fleetactivitytracking'
|
||||||
|
verbose_name = _('Fleet Activity Tracking')
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<th class="text-center">{% translate "Character" %}</th>
|
<th class="text-center">{% translate "Character" %}</th>
|
||||||
<th class="text-center">{% translate "System" %}</th>
|
<th class="text-center">{% translate "System" %}</th>
|
||||||
<th class="text-center">{% translate "Ship" %}</th>
|
<th class="text-center">{% translate "Ship" %}</th>
|
||||||
<th class="text-center">{% translate "Eve Time" %}</th>
|
<th class="text-center">{% translate "EVE time" %}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th class="text-center">{% translate "Fleet" %}</th>
|
<th class="text-center">{% translate "Fleet" %}</th>
|
||||||
<th class="text-center">{% translate "Creator" %}</th>
|
<th class="text-center">{% translate "Creator" %}</th>
|
||||||
<th class="text-center">{% translate "Eve Time" %}</th>
|
<th class="text-center">{% translate "EVE time" %}</th>
|
||||||
<th class="text-center">{% translate "Duration" %}</th>
|
<th class="text-center">{% translate "Duration" %}</th>
|
||||||
<th class="text-center">{% translate "Edit" %}</th>
|
<th class="text-center">{% translate "Edit" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
<th scope="col" class="text-center">{% translate "Character" %}</th>
|
<th scope="col" class="text-center">{% translate "Character" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "System" %}</th>
|
<th scope="col" class="text-center">{% translate "System" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Ship" %}</th>
|
<th scope="col" class="text-center">{% translate "Ship" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Eve Time" %}</th>
|
<th scope="col" class="text-center">{% translate "EVE time" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for fat in fats %}
|
{% for fat in fats %}
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
<th scope="col" class="text-center">{% translate "Name" %}</th>
|
<th scope="col" class="text-center">{% translate "Name" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Creator" %}</th>
|
<th scope="col" class="text-center">{% translate "Creator" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Fleet" %}</th>
|
<th scope="col" class="text-center">{% translate "Fleet" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Eve Time" %}</th>
|
<th scope="col" class="text-center">{% translate "EVE time" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Duration" %}</th>
|
<th scope="col" class="text-center">{% translate "Duration" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Edit" %}</th>
|
<th scope="col" class="text-center">{% translate "Edit" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from django.contrib.auth.decorators import permission_required
|
from django.contrib.auth.decorators import permission_required
|
||||||
from django.contrib.auth.models import User
|
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
|
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 gettext_lazy as _
|
||||||
from esi.decorators import token_required
|
from esi.decorators import token_required
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ Framework App Config
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class FrameworkConfig(AppConfig):
|
class FrameworkConfig(AppConfig):
|
||||||
@@ -12,3 +13,4 @@ class FrameworkConfig(AppConfig):
|
|||||||
|
|
||||||
name = "allianceauth.framework"
|
name = "allianceauth.framework"
|
||||||
label = "framework"
|
label = "framework"
|
||||||
|
verbose_name = _("Framework")
|
||||||
|
|||||||
@@ -5,6 +5,24 @@
|
|||||||
* to be used throughout Alliance Auth and its Community Apps
|
* to be used throughout Alliance Auth and its Community Apps
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* General
|
||||||
|
------------------------------------------------------------------------------------- */
|
||||||
|
@media all {
|
||||||
|
.navbar-toggler.collapsed {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul#nav-right:has(li) + ul#nav-right-character-control > li:first-child {
|
||||||
|
display: list-item !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (max-width: 991px) {
|
||||||
|
ul#nav-left:has(li) + ul#nav-right + ul#nav-right-character-control > li:first-child {
|
||||||
|
display: list-item !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Bootstrap fixes
|
/* Bootstrap fixes
|
||||||
------------------------------------------------------------------------------------- */
|
------------------------------------------------------------------------------------- */
|
||||||
@media all {
|
@media all {
|
||||||
|
|||||||
@@ -2,12 +2,14 @@
|
|||||||
{# {% include "framework/header/page-header.html" with title="Foobar" subtitle="Barfoo" %}#}
|
{# {% include "framework/header/page-header.html" with title="Foobar" subtitle="Barfoo" %}#}
|
||||||
|
|
||||||
{% if title %}
|
{% if title %}
|
||||||
<h1 class="page-header text-center mb-3">
|
<header class="aa-page-header mb-3">
|
||||||
{{ title }}
|
<h1 class="page-header text-center">
|
||||||
|
{{ title }}
|
||||||
|
|
||||||
{% if subtitle %}
|
{% if subtitle %}
|
||||||
<br>
|
<br>
|
||||||
<small class="text-muted">{{ subtitle }}</small>
|
<small class="text-muted">{{ subtitle }}</small>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
|
</header>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class GroupManagementConfig(AppConfig):
|
class GroupManagementConfig(AppConfig):
|
||||||
name = 'allianceauth.groupmanagement'
|
name = 'allianceauth.groupmanagement'
|
||||||
label = 'groupmanagement'
|
label = 'groupmanagement'
|
||||||
verbose_name = 'Group Management'
|
verbose_name = _('Group Management')
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
from . import signals # noqa: F401
|
from . import signals # noqa: F401
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class HRApplicationsConfig(AppConfig):
|
class HRApplicationsConfig(AppConfig):
|
||||||
name = 'allianceauth.hrapplications'
|
name = 'allianceauth.hrapplications'
|
||||||
label = 'hrapplications'
|
label = 'hrapplications'
|
||||||
|
verbose_name = _('HR Applications')
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from typing import ClassVar
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from sortedm2m.fields import SortedManyToManyField
|
from sortedm2m.fields import SortedManyToManyField
|
||||||
@@ -40,7 +41,7 @@ class Application(models.Model):
|
|||||||
reviewer_character = models.ForeignKey(EveCharacter, on_delete=models.SET_NULL, blank=True, null=True)
|
reviewer_character = models.ForeignKey(EveCharacter, on_delete=models.SET_NULL, blank=True, null=True)
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
objects = ApplicationManager()
|
objects: ClassVar[ApplicationManager] = ApplicationManager()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.user) + " Application To " + str(self.form)
|
return str(self.user) + " Application To " + str(self.form)
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ logger = logging.getLogger(__name__)
|
|||||||
class MenuConfig(AppConfig):
|
class MenuConfig(AppConfig):
|
||||||
name = "allianceauth.menu"
|
name = "allianceauth.menu"
|
||||||
label = "menu"
|
label = "menu"
|
||||||
|
verbose_name = _("Menu")
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
from allianceauth.menu.core import smart_sync
|
from allianceauth.menu.core import smart_sync
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from typing import ClassVar
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ class MenuItem(models.Model):
|
|||||||
help_text=_("External URL this menu items will link to"),
|
help_text=_("External URL this menu items will link to"),
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = MenuItemManager()
|
objects: ClassVar[MenuItemManager] = MenuItemManager()
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.text
|
return self.text
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ class TestRenderDefaultMenu(TestCase):
|
|||||||
classes = "fa-solid fa-users-gear"
|
classes = "fa-solid fa-users-gear"
|
||||||
url_name = "groupmanagement:management"
|
url_name = "groupmanagement:management"
|
||||||
|
|
||||||
def render(self, request):
|
def render(Self, request):
|
||||||
# simulate no perms
|
# simulate no perms
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class NotificationsConfig(AppConfig):
|
class NotificationsConfig(AppConfig):
|
||||||
name = 'allianceauth.notifications'
|
name = 'allianceauth.notifications'
|
||||||
label = 'notifications'
|
label = 'notifications'
|
||||||
|
verbose_name = _('Notifications')
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
@@ -56,7 +57,7 @@ class Notification(models.Model):
|
|||||||
timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
|
timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
|
||||||
viewed = models.BooleanField(default=False, db_index=True)
|
viewed = models.BooleanField(default=False, db_index=True)
|
||||||
|
|
||||||
objects = NotificationManager()
|
objects: ClassVar[NotificationManager] = NotificationManager()
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"{self.user}: {self.title}"
|
return f"{self.user}: {self.title}"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch, Mock
|
||||||
|
|
||||||
from django.test import TestCase, override_settings
|
from django.test import TestCase, override_settings
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch, Mock
|
||||||
|
|
||||||
from django.test import TestCase, RequestFactory
|
from django.test import TestCase, RequestFactory
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class OptimerConfig(AppConfig):
|
class OptimerConfig(AppConfig):
|
||||||
name = 'allianceauth.optimer'
|
name = 'allianceauth.optimer'
|
||||||
label = 'optimer'
|
label = 'optimer'
|
||||||
|
verbose_name = _('Fleet Operations')
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<th class="text-center">{% translate "Operation" %}</th>
|
<th class="text-center">{% translate "Operation" %}</th>
|
||||||
<th class="text-center">{% translate "Type" %}</th>
|
<th class="text-center">{% translate "Type" %}</th>
|
||||||
<th class="text-center">{% translate "Form Up System" %}</th>
|
<th class="text-center">{% translate "Form Up System" %}</th>
|
||||||
<th class="text-center">{% translate "EVE Time" %}</th>
|
<th class="text-center">{% translate "EVE time" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="text-center mb-3">
|
<div class="text-center mb-3">
|
||||||
<div class="badge bg-primary text-start">
|
<div class="badge bg-primary text-start">
|
||||||
<b>{% translate "Current Eve Time:" %}</b>
|
<b>{% translate "Current EVE time:" %}</b>
|
||||||
<span id="current-time"></span>
|
<span id="current-time"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -127,8 +127,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current Eve time as a string
|
* Get the current EVE time as a string
|
||||||
* @returns {string} Eve time string
|
* @returns {string} EVE time string
|
||||||
*/
|
*/
|
||||||
const updateClock = () => {
|
const updateClock = () => {
|
||||||
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class PermissionsToolConfig(AppConfig):
|
class PermissionsToolConfig(AppConfig):
|
||||||
name = 'allianceauth.permissions_tool'
|
name = 'allianceauth.permissions_tool'
|
||||||
label = 'permissions_tool'
|
label = 'permissions_tool'
|
||||||
|
verbose_name = _('Permissions Audit')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission, User
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.shortcuts import render, Http404
|
from django.shortcuts import render, Http404
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ CELERYBEAT_SCHEDULE = {
|
|||||||
'esi_cleanup_token': {
|
'esi_cleanup_token': {
|
||||||
'task': 'esi.tasks.cleanup_token',
|
'task': 'esi.tasks.cleanup_token',
|
||||||
'schedule': crontab(minute='0', hour='0'),
|
'schedule': crontab(minute='0', hour='0'),
|
||||||
|
'apply_offset': True,
|
||||||
},
|
},
|
||||||
'run_model_update': {
|
'run_model_update': {
|
||||||
'task': 'allianceauth.eveonline.tasks.run_model_update',
|
'task': 'allianceauth.eveonline.tasks.run_model_update',
|
||||||
@@ -119,7 +120,12 @@ LANGUAGES = ( # Sorted by Language Code alphabetical order + English at top
|
|||||||
|
|
||||||
# Django's language codes are different from some of the libraries we use,
|
# Django's language codes are different from some of the libraries we use,
|
||||||
# so we need to map them.
|
# so we need to map them.
|
||||||
|
# When adding a new language, please remember to add it to the mapping
|
||||||
|
# and add the language files to their respective directories under `allianceauth/static/allianceauth/libs/`.
|
||||||
LANGUAGE_MAPPING = {
|
LANGUAGE_MAPPING = {
|
||||||
|
# See https://github.com/DataTables/Plugins/tree/master/i18n for available languages
|
||||||
|
# (We use the JSON files)
|
||||||
|
# `allianceauth/static/allianceauth/libs/DataTables/Plugins/{version}/i18n/` for the files
|
||||||
"DataTables": {
|
"DataTables": {
|
||||||
"cs-cz": "cs",
|
"cs-cz": "cs",
|
||||||
"de": "de-DE",
|
"de": "de-DE",
|
||||||
@@ -134,6 +140,8 @@ LANGUAGE_MAPPING = {
|
|||||||
"uk": "uk",
|
"uk": "uk",
|
||||||
"zh-hans": "zh-HANT",
|
"zh-hans": "zh-HANT",
|
||||||
},
|
},
|
||||||
|
# See https://github.com/moment/moment/tree/master/locale for available languages
|
||||||
|
# `allianceauth/static/allianceauth/libs/moment.js/{version}/locale/` for the files
|
||||||
"MomentJS": {
|
"MomentJS": {
|
||||||
"cs-cz": "cs",
|
"cs-cz": "cs",
|
||||||
"de": "de",
|
"de": "de",
|
||||||
|
|||||||
@@ -1,49 +1,48 @@
|
|||||||
[program:beat]
|
[program:beat]
|
||||||
command={{ celery }} -A {{ project_name }} beat
|
command = {{ celery }} -A {{ project_name }} beat
|
||||||
directory={{ project_directory }}
|
directory = {{ project_directory }}
|
||||||
user=allianceserver
|
user = allianceserver
|
||||||
stdout_logfile={{ project_directory }}/log/beat.log
|
stdout_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
stderr_logfile={{ project_directory }}/log/beat.log
|
stderr_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
autostart=true
|
autostart = true
|
||||||
autorestart=true
|
autorestart = true
|
||||||
startsecs=10
|
startsecs = 10
|
||||||
priority=998
|
priority = 998
|
||||||
|
|
||||||
[program:worker]
|
[program:worker]
|
||||||
command={{ celery }} -A {{ project_name }} worker --pool=threads --concurrency=5 -n %(program_name)s_%(process_num)02d
|
command = {{ celery }} -A {{ project_name }} worker --pool=threads --concurrency=5 -n %(program_name)s_%(process_num)02d
|
||||||
directory={{ project_directory }}
|
directory = {{ project_directory }}
|
||||||
user=allianceserver
|
user = allianceserver
|
||||||
numprocs=1
|
numprocs = 1
|
||||||
process_name=%(program_name)s_%(process_num)02d
|
process_name = %(program_name)s_%(process_num)02d
|
||||||
stdout_logfile={{ project_directory }}/log/worker.log
|
stdout_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
stderr_logfile={{ project_directory }}/log/worker.log
|
stderr_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
autostart=true
|
autostart = true
|
||||||
autorestart=true
|
autorestart = true
|
||||||
startsecs=10
|
startsecs = 10
|
||||||
stopwaitsecs = 600
|
stopwaitsecs = 600
|
||||||
killasgroup=true
|
killasgroup = true
|
||||||
priority=998
|
priority = 998
|
||||||
|
|
||||||
{% if gunicorn %}
|
{% if gunicorn %}
|
||||||
[program:gunicorn]
|
[program:gunicorn]
|
||||||
user = allianceserver
|
user = allianceserver
|
||||||
directory={{ project_directory }}
|
directory = {{ project_directory }}
|
||||||
command={{ gunicorn }} {{ project_name }}.wsgi --workers=3 --timeout 120
|
command = {{ gunicorn }} {{ project_name }}.wsgi --workers=3 --timeout 120
|
||||||
stdout_logfile={{ project_directory }}/log/gunicorn.log
|
stdout_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
stderr_logfile={{ project_directory }}/log/gunicorn.log
|
stderr_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
autostart=true
|
autostart = true
|
||||||
autorestart=true
|
autorestart = true
|
||||||
stopsignal=INT
|
stopsignal = INT
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
[eventlistener:memmon]
|
[eventlistener:memmon]
|
||||||
command={{ memmon }} -p worker_00=256MB -p gunicorn=256MB
|
command = {{ memmon }} -p worker_00=256MB -p gunicorn=256MB
|
||||||
directory={{ project_directory }}
|
directory = {{ project_directory }}
|
||||||
events=TICK_60
|
events = TICK_60
|
||||||
stdout_logfile={{ project_directory }}/log/memmon.log
|
stdout_logfile = {{ project_directory }}/log/memmon.log
|
||||||
stderr_logfile={{ project_directory }}/log/memmon.log
|
stderr_logfile = {{ project_directory }}/log/memmon.log
|
||||||
|
|
||||||
[group:{{ project_name }}]
|
[group:{{ project_name }}]
|
||||||
programs=beat,worker{% if gunicorn %},gunicorn{% endif %}
|
programs = beat,worker{% if gunicorn %},gunicorn{% endif %}
|
||||||
priority=999
|
priority = 999
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class ServicesConfig(AppConfig):
|
class ServicesConfig(AppConfig):
|
||||||
name = 'allianceauth.services'
|
name = 'allianceauth.services'
|
||||||
label = 'services'
|
label = 'services'
|
||||||
|
verbose_name = _('Services')
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
from . import signals
|
from . import signals
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
from string import Formatter
|
from string import Formatter
|
||||||
|
from django.urls import include, re_path
|
||||||
from typing import Iterable, Optional
|
from typing import Iterable, Optional
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.template.loader import render_to_string
|
||||||
|
from django.urls import include, re_path
|
||||||
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
from allianceauth.hooks import get_hooks
|
from allianceauth.hooks import get_hooks
|
||||||
from allianceauth.menu.hooks import MenuItemHook
|
from allianceauth.menu.hooks import MenuItemHook
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class DiscordServiceConfig(AppConfig):
|
class DiscordServiceConfig(AppConfig):
|
||||||
name = 'allianceauth.services.modules.discord'
|
name = 'allianceauth.services.modules.discord'
|
||||||
label = 'discord'
|
label = 'discord'
|
||||||
|
verbose_name = _('Discord Service')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import ClassVar, Optional
|
||||||
|
|
||||||
from requests.exceptions import HTTPError
|
from requests.exceptions import HTTPError
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ class DiscordUser(models.Model):
|
|||||||
help_text='Date & time this service account was activated'
|
help_text='Date & time this service account was activated'
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = DiscordUserManager()
|
objects: ClassVar[DiscordUserManager] = DiscordUserManager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
permissions = (
|
permissions = (
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import random
|
|||||||
|
|
||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User, Group
|
||||||
|
|
||||||
|
from allianceauth.services.modules.discord.models import DiscordUser
|
||||||
from allianceauth.utils.cache import get_redis_client
|
from allianceauth.utils.cache import get_redis_client
|
||||||
|
|
||||||
logger = logging.getLogger('allianceauth')
|
logger = logging.getLogger('allianceauth')
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class DiscourseServiceConfig(AppConfig):
|
class DiscourseServiceConfig(AppConfig):
|
||||||
name = 'allianceauth.services.modules.discourse'
|
name = 'allianceauth.services.modules.discourse'
|
||||||
label = 'discourse'
|
label = 'discourse'
|
||||||
|
verbose_name = _('Discourse Service')
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
import requests
|
||||||
import re
|
import re
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .manager import DiscourseManager
|
from .manager import DiscourseManager
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class ExampleServiceConfig(AppConfig):
|
class ExampleServiceConfig(AppConfig):
|
||||||
name = 'allianceauth.services.modules.example'
|
name = 'allianceauth.services.modules.example'
|
||||||
label = 'example_service'
|
label = 'example_service'
|
||||||
|
verbose_name = _('Example Service')
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class Ips4ServiceConfig(AppConfig):
|
class Ips4ServiceConfig(AppConfig):
|
||||||
name = 'allianceauth.services.modules.ips4'
|
name = 'allianceauth.services.modules.ips4'
|
||||||
label = 'ips4'
|
label = 'ips4'
|
||||||
|
verbose_name = _('IPS4 Service')
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from django.conf import settings
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
from allianceauth.services.hooks import NameFormatter
|
from allianceauth.services.hooks import NameFormatter
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class MumbleServiceConfig(AppConfig):
|
class MumbleServiceConfig(AppConfig):
|
||||||
name = 'allianceauth.services.modules.mumble'
|
name = 'allianceauth.services.modules.mumble'
|
||||||
label = 'mumble'
|
label = 'mumble'
|
||||||
|
verbose_name = _('Mumble Service')
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
from typing import ClassVar
|
||||||
from passlib.hash import bcrypt_sha256
|
from passlib.hash import bcrypt_sha256
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
@@ -116,7 +117,7 @@ class MumbleUser(AbstractServiceModel):
|
|||||||
help_text="Timestamp of the users Last Disconnection to Mumble"
|
help_text="Timestamp of the users Last Disconnection to Mumble"
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = MumbleManager()
|
objects: ClassVar[MumbleManager] = MumbleManager()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.username
|
return self.username
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
{% endblock page_title %}
|
{% endblock page_title %}
|
||||||
|
|
||||||
{% block header_nav_brand %}
|
{% block header_nav_brand %}
|
||||||
<a class="navbar-brand">{% trans "Mumble History" %} - {{ mumble_url }}</a>
|
{% trans "Mumble History" %} - {{ mumble_url }}
|
||||||
{% endblock header_nav_brand %}
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block header_nav_collapse_left %}
|
{% block header_nav_collapse_left %}
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
const MUMBLESTATS_DATETIME_FORMAT = 'YYYY-MM-DD, HH:mm';
|
const MUMBLESTATS_DATETIME_FORMAT = 'LLL';
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@@ -104,15 +104,33 @@
|
|||||||
{ data: 'version' },
|
{ data: 'version' },
|
||||||
{
|
{
|
||||||
data: 'last_connect',
|
data: 'last_connect',
|
||||||
render: (data) => {
|
render: {
|
||||||
return moment(data).utc().format(MUMBLESTATS_DATETIME_FORMAT);
|
_: (data) => {
|
||||||
|
return data === null
|
||||||
|
? ''
|
||||||
|
: moment(data)
|
||||||
|
.utc()
|
||||||
|
.format(MUMBLESTATS_DATETIME_FORMAT);
|
||||||
|
},
|
||||||
|
sort: (data) => {
|
||||||
|
return data === null ? '' : data;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
className: 'text-end',
|
className: 'text-end',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data: 'last_disconnect',
|
data: 'last_disconnect',
|
||||||
render: (data) => {
|
render: {
|
||||||
return moment(data).utc().format(MUMBLESTATS_DATETIME_FORMAT);
|
_: (data) => {
|
||||||
|
return data === null
|
||||||
|
? ''
|
||||||
|
: moment(data)
|
||||||
|
.utc()
|
||||||
|
.format(MUMBLESTATS_DATETIME_FORMAT);
|
||||||
|
},
|
||||||
|
sort: (data) => {
|
||||||
|
return data === null ? '' : data;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
className: 'text-end',
|
className: 'text-end',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -48,9 +48,9 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.user.is_superuser %}
|
{% if perms.mumble.view_connection_history %}
|
||||||
<a class="btn btn-primary" type="button" id="btnMumbleConnectionHistory" href="{% url 'mumble:connection_history' %}" title="{% translate 'Mumble Connection History' %}">
|
<a class="btn btn-primary" type="button" id="btnMumbleConnectionHistory" href="{% url 'mumble:connection_history' %}" title="{% translate 'Mumble Connection History' %}">
|
||||||
<i class="fa-solid fa-clock-rotate-left"></i> History
|
<i class="fa-solid fa-clock-rotate-left"></i> History
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class OpenfireServiceConfig(AppConfig):
|
class OpenfireServiceConfig(AppConfig):
|
||||||
name = 'allianceauth.services.modules.openfire'
|
name = 'allianceauth.services.modules.openfire'
|
||||||
label = 'openfire'
|
label = 'openfire'
|
||||||
|
verbose_name = _('Openfire Service')
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class Phpbb3ServiceConfig(AppConfig):
|
class Phpbb3ServiceConfig(AppConfig):
|
||||||
name = 'allianceauth.services.modules.phpbb3'
|
name = 'allianceauth.services.modules.phpbb3'
|
||||||
label = 'phpbb3'
|
label = 'phpbb3'
|
||||||
|
verbose_name = _('phpBB3 Service')
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class SmfServiceConfig(AppConfig):
|
class SmfServiceConfig(AppConfig):
|
||||||
name = 'allianceauth.services.modules.smf'
|
name = 'allianceauth.services.modules.smf'
|
||||||
label = 'smf'
|
label = 'smf'
|
||||||
|
verbose_name = _('SMF Service')
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class Teamspeak3ServiceConfig(AppConfig):
|
class Teamspeak3ServiceConfig(AppConfig):
|
||||||
name = 'allianceauth.services.modules.teamspeak3'
|
name = 'allianceauth.services.modules.teamspeak3'
|
||||||
label = 'teamspeak3'
|
label = 'teamspeak3'
|
||||||
|
verbose_name = _('TeamSpeak 3 Service')
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
from . import signals
|
from . import signals
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class XenforoServiceConfig(AppConfig):
|
class XenforoServiceConfig(AppConfig):
|
||||||
name = 'allianceauth.services.modules.xenforo'
|
name = 'allianceauth.services.modules.xenforo'
|
||||||
label = 'xenforo'
|
label = 'xenforo'
|
||||||
|
verbose_name = _('Xenforo Service')
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
<div class="card text-center m-2" style="min-width: 18rem; min-height: 18rem;">
|
<div class="card text-center mx-2 mb-3" style="min-width: 18rem; min-height: 18rem;">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">{% block title %}{% endblock title %}</h5>
|
<h5 class="card-title">{% block title %}{% endblock title %}</h5>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class SRPConfig(AppConfig):
|
class SRPConfig(AppConfig):
|
||||||
name = 'allianceauth.srp'
|
name = 'allianceauth.srp'
|
||||||
label = 'srp'
|
label = 'srp'
|
||||||
|
verbose_name = _('Ship Replacement')
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ ul.list-group.list-group-horizontal > li.list-group-item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eve time in navbar
|
/* EVE time in navbar
|
||||||
------------------------------------------------------------------------------------- */
|
------------------------------------------------------------------------------------- */
|
||||||
@media all {
|
@media all {
|
||||||
.nav-item-eve-time .eve-time-wrapper {
|
.nav-item-eve-time .eve-time-wrapper {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ $(document).ready(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the Eve time clock in the top menu bar
|
* Start the EVE time clock in the top menu bar
|
||||||
*/
|
*/
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
renderClock($('.eve-time-wrapper .eve-time-clock'));
|
renderClock($('.eve-time-wrapper .eve-time-clock'));
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const getDurationString = (duration) => { // eslint-disable-line no-unused-vars
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the current eve time as a formatted string
|
* returns the current EVE time as a formatted string
|
||||||
*
|
*
|
||||||
* condition:
|
* condition:
|
||||||
* only if moment.js is loaded before,
|
* only if moment.js is loaded before,
|
||||||
|
|||||||
@@ -12,11 +12,7 @@
|
|||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
{% for notif in notifications %}
|
{% for notif in notifications %}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
{% if notif.state == 'opened' %}
|
<span class="badge bg-success me-2">{% translate "Open" %}</span>
|
||||||
<span class="badge bg-success me-2">{% translate "Open" %}</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-danger me-2">{% translate "Closed" %}</span>
|
|
||||||
{% endif %}
|
|
||||||
<a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a>
|
<a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
|
|||||||
@@ -12,11 +12,10 @@
|
|||||||
<!-- End Required meta tags -->
|
<!-- End Required meta tags -->
|
||||||
|
|
||||||
<!-- Meta tags -->
|
<!-- Meta tags -->
|
||||||
<!-- TODO Bundle all the site specific stuff up into its own template for easy override -->
|
{% include 'allianceauth/opengraph.html' %}
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="author" content="">
|
|
||||||
{% include 'allianceauth/icons.html' %}
|
{% include 'allianceauth/icons.html' %}
|
||||||
<!-- Meta tags -->
|
<!-- Meta tags -->
|
||||||
|
|
||||||
<title>{% block title %}{% block page_title %}{% endblock page_title %} - {{ SITE_NAME }}{% endblock title %}</title>
|
<title>{% block title %}{% block page_title %}{% endblock page_title %} - {{ SITE_NAME }}{% endblock title %}</title>
|
||||||
|
|
||||||
{% theme_css %}
|
{% theme_css %}
|
||||||
@@ -25,12 +24,11 @@
|
|||||||
{% include 'bundles/auth-framework-css.html' %}
|
{% include 'bundles/auth-framework-css.html' %}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.navbar-toggler.collapsed{
|
@media all {
|
||||||
transform: rotate(180deg);
|
.nav-padding {
|
||||||
}
|
margin-top: {% header_padding_size %} !important;
|
||||||
|
max-height: calc(100vh - {% header_padding_size %}) !important;
|
||||||
.nav-padding {
|
}
|
||||||
padding-top: {% header_padding_size %} !important;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -63,6 +61,11 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul id="nav-right-character-control" class="nav navbar-nav">
|
<ul id="nav-right-character-control" class="nav navbar-nav">
|
||||||
|
<li class="nav-item ms-lg-2 py-2 py-lg-1 col-12 col-lg-auto d-none">
|
||||||
|
<div class="vr d-none d-lg-flex h-100 mx-2 text-white-50"></div>
|
||||||
|
<hr class="d-lg-none my-2 text-body text-white-50">
|
||||||
|
</li>
|
||||||
|
|
||||||
{% block header_nav_user_character_control %} <!-- Default to add char and swap main -->
|
{% block header_nav_user_character_control %} <!-- Default to add char and swap main -->
|
||||||
{% include 'allianceauth/top-menu-rh-default.html' %}
|
{% include 'allianceauth/top-menu-rh-default.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
8
allianceauth/templates/allianceauth/opengraph.html
Normal file
8
allianceauth/templates/allianceauth/opengraph.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{% load static %}
|
||||||
|
|
||||||
|
<meta property="og:title" content="{{ SITE_NAME }}">
|
||||||
|
<meta property="og:image" content="{{ SITE_URL }}{% static 'allianceauth/icons/apple-touch-icon.png' %}">
|
||||||
|
<meta property="og:description" content="Alliance Auth - An auth system for EVE Online to help in-game organizations manage online service access.">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:site_name" content="{{ request.META.HTTP_HOST }}">
|
||||||
|
<meta property="og:url" content="{{ request.path }}">
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
<div class="collapse navbar-collapse auth-menus-collapse">
|
<div class="collapse navbar-collapse auth-menus-collapse">
|
||||||
<ul class="nav navbar-nav navbar-right navbar-pills">
|
<ul class="nav navbar-nav navbar-right navbar-pills">
|
||||||
<li class="nav-item-eve-time">
|
<li class="nav-item-eve-time">
|
||||||
<div class="eve-time-wrapper">{% translate "Eve Time" %}: <span class="eve-time-clock"></span></div>
|
<div class="eve-time-wrapper">{% translate "EVE time" %}: <span class="eve-time-clock"></span></div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
<img src="{% static 'allianceauth/images/auth-logo.svg' %}" width="{{ logo_width|default:"128px" }}" height="{% if logo_height %}{{ logo_ }}{% else %}{{ logo_width|default:"128px" }}{% endif %}" alt="{{ SITE_NAME }}">
|
<img src="{% static 'allianceauth/images/auth-logo.svg' %}" width="{{ logo_width|default:"128px" }}" height="{% if logo_height %}{{ logo_height }}{% else %}{{ logo_width|default:"128px" }}{% endif %}" alt="{{ SITE_NAME }}">
|
||||||
|
|||||||
@@ -67,6 +67,26 @@ def get_datatables_language_static(language: str) -> str:
|
|||||||
|
|
||||||
return static_url
|
return static_url
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def get_relative_datatables_language_path(language: str) -> str:
|
||||||
|
"""
|
||||||
|
Get the correct language code URL for DataTables (relative path to the static folder)
|
||||||
|
|
||||||
|
:param language: Django's language code
|
||||||
|
:type language: str
|
||||||
|
:return: Mapped language code
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
|
||||||
|
mapped_language = get_datatable_language_code(language)
|
||||||
|
static_url = (
|
||||||
|
f"allianceauth/libs/DataTables/Plugins/2.2.1/i18n/{mapped_language}.json"
|
||||||
|
if mapped_language
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
return static_url
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def get_momentjs_language_static(language: str) -> str:
|
def get_momentjs_language_static(language: str) -> str:
|
||||||
@@ -88,3 +108,24 @@ def get_momentjs_language_static(language: str) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
return static_url
|
return static_url
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def get_relative_momentjs_language_path(language: str) -> str:
|
||||||
|
"""
|
||||||
|
Get the correct language code URL for Moment.JS (relative path to the static folder)
|
||||||
|
|
||||||
|
:param language: Django's language code
|
||||||
|
:type language: str
|
||||||
|
:return: Mapped language code path
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
|
||||||
|
mapped_language = get_momentjs_language_code(language)
|
||||||
|
|
||||||
|
static_url = (
|
||||||
|
f"allianceauth/libs/moment.js/2.29.4/locale/{mapped_language}.js"
|
||||||
|
if mapped_language
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
return static_url
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.contrib.auth.models import User, Group, Permission
|
from django.contrib.auth.models import User, Group, Permission
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from allianceauth.eveonline.models import (
|
||||||
|
EveCorporationInfo, EveAllianceInfo, EveCharacter
|
||||||
|
)
|
||||||
|
|
||||||
from .auth_utils import AuthUtils
|
from .auth_utils import AuthUtils
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user