Compare commits

...

24 Commits

Author SHA1 Message Date
Joel Falknau
960c9625fe Version Bump 4.6.2a 2025-02-25 19:29:36 +10:00
Ariel Rin
7b92d103d6 Merge branch 'crontab' into 'master'
Crontab fixes

See merge request allianceauth/allianceauth!1686
2025-02-25 09:16:59 +00:00
Ariel Rin
c1e2449084 Crontab fixes 2025-02-25 09:16:59 +00:00
Ariel Rin
02214b74d0 Merge branch 'cleanup-unused-imports' into 'master'
[REMOVE] Unused imports

See merge request allianceauth/allianceauth!1684
2025-02-16 23:25:58 +00:00
Peter Pfeufer
f497c18e5b [REMOVE] Unused imports 2025-02-16 23:20:36 +01:00
Ariel Rin
cb57d922e6 Merge branch 'pre-commit-updates' into 'master'
Pre commit updates

See merge request allianceauth/allianceauth!1682
2025-02-11 05:15:48 +00:00
Ariel Rin
805d138b09 Merge branch 'fix-timerboard-initial-sort-order' into 'master'
[FIX] Timerboard initial sort order

See merge request allianceauth/allianceauth!1681
2025-02-11 05:14:48 +00:00
Ariel Rin
09a583fb1d Merge branch 'authorized-apps-url' into 'master'
[CHANGE] Update URL to apps management

See merge request allianceauth/allianceauth!1683
2025-02-09 08:18:23 +00:00
Peter Pfeufer
146c4c8d94 [CHANGE] Update URL to apps management 2025-02-09 08:55:51 +01:00
Peter Pfeufer
c2ae680f72 [CHANGE] Apply new pre-commit config 2025-02-01 16:22:36 +01:00
Peter Pfeufer
b5ad1c8a1a [CHANGE] Use global exclude instead of per hook 2025-02-01 16:18:08 +01:00
Peter Pfeufer
8be2760fc4 [CHANGNE] Update repos and dependencies 2025-02-01 16:14:36 +01:00
Peter Pfeufer
f047943eb7 [CHANGE] Define language versions 2025-02-01 16:11:44 +01:00
Peter Pfeufer
43906f41b3 [FIX] Timerboard initial sort order 2025-02-01 16:00:03 +01:00
Ariel Rin
a18ec98877 Merge branch 'django-checks' into 'master'
Improve Django checks

See merge request allianceauth/allianceauth!1679
2025-01-28 09:16:14 +00:00
Ariel Rin
14163d2c0c Merge branch 'fix-menu-chevron' into 'master'
[FIX] Active menu chevron

See merge request allianceauth/allianceauth!1680
2025-01-28 09:13:20 +00:00
Peter Pfeufer
81d9c41cf6 [FIX] Active menu chevron 2025-01-26 19:24:24 +01:00
Peter Pfeufer
58f5a5b41d [CHANGE] elif to safe potential if checks and time 2025-01-22 04:23:19 +01:00
Peter Pfeufer
6363bb706a [CHANGE] Put some of the hint links in variables 2025-01-22 04:12:33 +01:00
Peter Pfeufer
baf3be4cb2 [CHANGE] Simplify if blocks for MariaDB and MySQL checks 2025-01-22 04:05:02 +01:00
Joel Falknau
e69444fe79 Version Bump 4.6.1 2025-01-20 19:03:17 +10:00
Ariel Rin
7483fcb876 Merge branch 'offsetfix' into 'master'
Cron Offset Fix

See merge request allianceauth/allianceauth!1678
2025-01-20 08:58:24 +00:00
Joel Falknau
a57d55504d Cosmetic fix to * cron 2025-01-20 18:45:37 +10:00
Joel Falknau
affb30e9f4 add migration 2025-01-20 18:37:22 +10:00
40 changed files with 403 additions and 390 deletions

View File

@@ -3,22 +3,41 @@
# Update this file: # Update this file:
# pre-commit autoupdate # pre-commit autoupdate
# Set the default language versions for the hooks
default_language_version:
python: python3 # Force all Python hooks to use Python 3
node: 22.12.0 # Force all Node hooks to use Node 22.12.0
# Globally exclude files
# https://pre-commit.com/#top_level-exclude
exclude: |
(?x)(
LICENSE|
allianceauth\/static\/allianceauth\/css\/themes\/bootstrap-locals.less|
\.min\.css|
\.min\.js|
\.po|
\.mo|
swagger\.json|
static/(.*)/libs/
)
repos: repos:
# Code Upgrades # Code Upgrades
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v3.15.2 rev: v3.19.1
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: [--py38-plus] args: [--py38-plus]
- repo: https://github.com/adamchainz/django-upgrade - repo: https://github.com/adamchainz/django-upgrade
rev: 1.17.0 rev: 1.22.2
hooks: hooks:
- id: django-upgrade - id: django-upgrade
args: [--target-version=4.2] args: [--target-version=4.2]
# Formatting # Formatting
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0 rev: v5.0.0
hooks: hooks:
# Identify invalid files # Identify invalid files
- id: check-ast - id: check-ast
@@ -44,48 +63,22 @@ repos:
args: [--fix=lf] args: [--fix=lf]
- id: trailing-whitespace - id: trailing-whitespace
args: [--markdown-linebreak-ext=md] args: [--markdown-linebreak-ext=md]
exclude: |
(?x)(
\.min\.css|
\.min\.js|
\.po|
\.mo|
swagger\.json|
static/(.*)/libs/
)
- id: check-executables-have-shebangs - id: check-executables-have-shebangs
- id: end-of-file-fixer - id: end-of-file-fixer
exclude: |
(?x)(
\.min\.css|
\.min\.js|
\.po|
\.mo|
swagger\.json|
static/(.*)/libs/
)
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python - repo: https://github.com/editorconfig-checker/editorconfig-checker.python
rev: 2.7.3 rev: 3.2.0
hooks: hooks:
- id: editorconfig-checker - id: editorconfig-checker
exclude: |
(?x)(
LICENSE|
allianceauth\/static\/allianceauth\/css\/themes\/bootstrap-locals.less|
\.po|
\.mo|
swagger\.json|
static/(.*)/libs/
)
- repo: https://github.com/igorshubovych/markdownlint-cli - repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.41.0 rev: v0.44.0
hooks: hooks:
- id: markdownlint - id: markdownlint
language: node
args: args:
- --disable=MD013 - --disable=MD013
# Infrastructure # Infrastructure
- repo: https://github.com/tox-dev/pyproject-fmt - repo: https://github.com/tox-dev/pyproject-fmt
rev: 2.1.3 rev: v2.5.0
hooks: hooks:
- id: pyproject-fmt - id: pyproject-fmt
name: pyproject.toml formatter name: pyproject.toml formatter
@@ -93,9 +86,9 @@ repos:
args: args:
- --indent=4 - --indent=4
additional_dependencies: additional_dependencies:
- tox==4.15.0 # https://github.com/tox-dev/tox/releases/latest - tox==4.24.1 # https://github.com/tox-dev/tox/releases/latest
- repo: https://github.com/abravalheri/validate-pyproject - repo: https://github.com/abravalheri/validate-pyproject
rev: v0.18 rev: v0.23
hooks: hooks:
- id: validate-pyproject - id: validate-pyproject
name: Validate pyproject.toml name: Validate pyproject.toml

View File

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

View File

@@ -1,7 +1,6 @@
from django.apps import apps from django.apps import apps
from allianceauth.authentication.models import User from allianceauth.authentication.models import User
from esi.models import Token from allianceauth.analytics.utils import install_stat_users, install_stat_addons
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

View File

@@ -1,6 +1,3 @@
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

View File

@@ -5,7 +5,6 @@ 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

View File

@@ -14,7 +14,7 @@
{% block content %} {% block content %}
<div> <div>
<p class="mb-3"> <p class="mb-3">
{% translate "This page is a best attempt, but backups or database logs can still contain your tokens. Always revoke tokens on https://community.eveonline.com/support/third-party-applications/ where possible."|urlize %} {% translate "This page is a best attempt, but backups or database logs can still contain your tokens. Always revoke tokens on https://developers.eveonline.com/authorized-apps where possible."|urlize %}
</p> </p>
<table class="table w-100" id="table_tokens"> <table class="table w-100" id="table_tokens">

View File

@@ -29,7 +29,7 @@
</p> </p>
<p class="text-center"> <p class="text-center">
<a class="text-reset" href="https://community.eveonline.com/support/third-party-applications/" target="_blank" rel="noopener noreferrer"> <a class="text-reset" href="https://developers.eveonline.com/authorized-apps" target="_blank" rel="noopener noreferrer">
{% translate "Manage ESI Applications" %} {% translate "Manage ESI Applications" %}
</a> </a>
</p> </p>

View File

@@ -1,9 +1,3 @@
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

View File

@@ -1,4 +1,3 @@
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

View File

@@ -4,16 +4,10 @@ from allianceauth.eveonline.models import (
EveCorporationInfo, EveCorporationInfo,
EveAllianceInfo EveAllianceInfo
) )
from django.db.models.signals import ( from django.db.models.signals import post_save
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

View File

@@ -11,7 +11,6 @@ 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

View File

@@ -34,7 +34,10 @@ def django_settings(app_configs, **kwargs) -> List[CheckMessage]:
@register() @register()
def system_package_redis(app_configs, **kwargs) -> List[CheckMessage]: def system_package_redis(app_configs, **kwargs) -> List[CheckMessage]:
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:
@@ -42,19 +45,21 @@ def system_package_redis(app_configs, **kwargs) -> List[CheckMessage]:
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 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(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint="https://allianceauth.readthedocs.io/en/latest/installation/allianceauth.html#redis-and-other-tools", id="allianceauth.checks.A001")) errors.append(Error(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="https://allianceauth.readthedocs.io/en/latest/installation/allianceauth.html#redis-and-other-tools", id="allianceauth.checks.A002")) errors.append(Warning(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="https://allianceauth.readthedocs.io/en/latest/installation/allianceauth.html#redis-and-other-tools", id="allianceauth.checks.A018")) errors.append(Warning(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="https://allianceauth.readthedocs.io/en/latest/installation/allianceauth.html#redis-and-other-tools", id="allianceauth.checks.A003")) errors.append(Error(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]:
mysql_quick_guide_link = "https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/"
errors: List[CheckMessage] = [] errors: List[CheckMessage] = []
for connection in db.connections.all(): for connection in db.connections.all():
@@ -65,24 +70,30 @@ def system_package_mysql(app_configs, **kwargs) -> List[CheckMessage]:
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 and mysql_version.minor == 4 and timezone.now() > timezone.datetime(year=2032, month=4, day=30, tzinfo=timezone.utc): if mysql_version.major == 8:
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A004")) if mysql_version.minor == 4 and timezone.now() > timezone.datetime(year=2032, month=4, day=30, tzinfo=timezone.utc):
elif mysql_version.major == 8 and mysql_version.minor == 3: errors.append(Error(f"MySQL {mysql_version.public} EOL", hint=mysql_quick_guide_link, id="allianceauth.checks.A004"))
errors.append(Warning(f"MySQL {mysql_version.public} Non LTS", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A005")) elif mysql_version.minor == 3:
elif mysql_version.major == 8 and mysql_version.minor == 2: errors.append(Warning(f"MySQL {mysql_version.public} Non LTS", hint=mysql_quick_guide_link, id="allianceauth.checks.A005"))
errors.append(Warning(f"MySQL {mysql_version.public} Non LTS", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A006")) elif mysql_version.minor == 2:
elif mysql_version.major == 8 and mysql_version.minor == 1: errors.append(Warning(f"MySQL {mysql_version.public} Non LTS", hint=mysql_quick_guide_link, id="allianceauth.checks.A006"))
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A007")) elif mysql_version.minor == 1:
elif mysql_version.major == 8 and mysql_version.minor == 0 and timezone.now() > timezone.datetime(year=2026, month=4, day=30, tzinfo=timezone.utc): errors.append(Error(f"MySQL {mysql_version.public} EOL", hint=mysql_quick_guide_link, id="allianceauth.checks.A007"))
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A008")) elif mysql_version.minor == 0 and timezone.now() > timezone.datetime(year=2026, month=4, day=30, tzinfo=timezone.utc):
elif mysql_version.major < 8: # This will also catch Mariadb 5.x errors.append(Error(f"MySQL {mysql_version.public} EOL", hint=mysql_quick_guide_link, id="allianceauth.checks.A008"))
errors.append(Error(f"MySQL or MariaDB {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A009"))
# MySQL below 8
# This will also catch Mariadb 5.x
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"))
return errors return errors
@register() @register()
def system_package_mariadb(app_configs, **kwargs) -> List[CheckMessage]: def system_package_mariadb(app_configs, **kwargs) -> List[CheckMessage]:
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():
@@ -94,28 +105,32 @@ def system_package_mariadb(app_configs, **kwargs) -> List[CheckMessage]:
return errors return errors
# MariaDB 11 # MariaDB 11
if mariadb_version.major == 11 and mariadb_version.minor == 4 and timezone.now() > timezone.datetime(year=2029, month=5, day=19, tzinfo=timezone.utc): if mariadb_version.major == 11:
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A010")) if mariadb_version.minor == 4 and timezone.now() > timezone.datetime(year=2029, month=5, day=19, tzinfo=timezone.utc):
elif mariadb_version.major == 11 and mariadb_version.minor == 2: errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A010"))
errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A018")) elif mariadb_version.minor == 2:
if timezone.now() > timezone.datetime(year=2024, month=11, day=21, tzinfo=timezone.utc): errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint=mariadb_download_link, id="allianceauth.checks.A018"))
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A011"))
elif mariadb_version.major == 11 and mariadb_version.minor == 1: if timezone.now() > timezone.datetime(year=2024, month=11, day=21, tzinfo=timezone.utc):
errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A019")) errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A011"))
if timezone.now() > timezone.datetime(year=2024, month=8, day=21, tzinfo=timezone.utc): elif mariadb_version.minor == 1:
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A012")) errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint=mariadb_download_link, id="allianceauth.checks.A019"))
elif mariadb_version.major == 11 and mariadb_version.minor in [0, 3]: # Demote versions down here once EOL
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config.", id="allianceauth.checks.A013")) if timezone.now() > timezone.datetime(year=2024, month=8, day=21, tzinfo=timezone.utc):
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A012"))
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"))
# MariaDB 10 # MariaDB 10
elif mariadb_version.major == 10 and mariadb_version.minor == 11 and timezone.now() > timezone.datetime(year=2028, month=2, day=10, tzinfo=timezone.utc): elif mariadb_version.major == 10:
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config.", id="allianceauth.checks.A014")) if mariadb_version.minor == 11 and timezone.now() > timezone.datetime(year=2028, month=2, day=10, tzinfo=timezone.utc):
elif mariadb_version.major == 10 and 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.A014"))
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A0015")) elif mariadb_version.minor == 6 and timezone.now() > timezone.datetime(year=2026, month=7, day=6, tzinfo=timezone.utc):
elif mariadb_version.major == 10 and mariadb_version.minor == 5 and timezone.now() > timezone.datetime(year=2025, month=6, day=24, tzinfo=timezone.utc): errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A0015"))
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A016")) elif mariadb_version.minor == 5 and timezone.now() > timezone.datetime(year=2025, month=6, day=24, tzinfo=timezone.utc):
elif mariadb_version.major == 10 and mariadb_version.minor in [0, 1, 2, 3, 4, 7, 9, 10]: # Demote versions down here once EOL errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A016"))
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A017")) elif mariadb_version.minor in [0, 1, 2, 3, 4, 7, 9, 10]: # Demote versions down here once EOL
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint=mariadb_download_link, id="allianceauth.checks.A017"))
return errors return errors

View File

@@ -0,0 +1,29 @@
# Generated by Django 4.2.16 on 2025-01-20 06:16
import allianceauth.crontab.models
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='CronOffset',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('minute', models.FloatField(default=allianceauth.crontab.models.random_default, verbose_name='Minute Offset')),
('hour', models.FloatField(default=allianceauth.crontab.models.random_default, verbose_name='Hour Offset')),
('day_of_month', models.FloatField(default=allianceauth.crontab.models.random_default, verbose_name='Day of Month Offset')),
('month_of_year', models.FloatField(default=allianceauth.crontab.models.random_default, verbose_name='Month of Year Offset')),
('day_of_week', models.FloatField(default=allianceauth.crontab.models.random_default, verbose_name='Day of Week Offset')),
],
options={
'verbose_name': 'Cron Offsets',
},
),
]

View File

@@ -20,6 +20,10 @@ class OffsetDatabaseScheduler(DatabaseScheduler):
Takes the Celery Schedule from local.py and applies our AA Framework Cron Offset, if apply_offset is true Takes the Celery Schedule from local.py and applies our AA Framework Cron Offset, if apply_offset is true
Otherwise it passes it through as normal Otherwise it passes it through as normal
""" """
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
def update_from_dict(self, mapping): def update_from_dict(self, mapping):
s = {} s = {}
@@ -36,10 +40,10 @@ 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) 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 entry.model.enabled and apply_offset: if apply_offset:
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,7 +59,8 @@ class OffsetDatabaseScheduler(DatabaseScheduler):
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.")
s[name] = entry if entry.model.enabled:
s[name] = entry
except Exception as e: except Exception as e:
logger.exception("Error updating schedule for %s: %r", name, e) logger.exception("Error updating schedule for %s: %r", name, e)

View File

@@ -1,5 +1,3 @@
# 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

View File

@@ -19,8 +19,17 @@ def offset_cron(schedule: crontab) -> crontab:
try: try:
cron_offset = CronOffset.get_solo() cron_offset = CronOffset.get_solo()
new_minute = [(m + (round(60 * cron_offset.minute))) % 60 for m in schedule.minute]
new_hour = [(m + (round(24 * cron_offset.hour))) % 24 for m in schedule.hour] # Stops this shit from happening 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
# It is only cosmetic, but still annoying
if schedule._orig_minute == '*':
new_minute = '*'
else:
new_minute = [(m + (round(60 * cron_offset.minute))) % 60 for m in schedule.minute]
if schedule._orig_hour == '*':
new_hour = '*'
else:
new_hour = [(m + (round(24 * cron_offset.hour))) % 24 for m in schedule.hour]
return crontab( return crontab(
minute=",".join(str(m) for m in sorted(new_minute)), minute=",".join(str(m) for m in sorted(new_minute)),

View File

@@ -5,9 +5,6 @@ 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):
""" """

View File

@@ -1,6 +1,5 @@
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

View File

@@ -1,8 +1,6 @@
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):

View File

@@ -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, Http404 from django.shortcuts import render, redirect, get_object_or_404
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

View File

@@ -49,14 +49,14 @@
} }
/* Chevron icons */ /* Chevron icons */
#sidebar-menu [data-bs-toggle="collapse"] > i.fa-chevron-down, #sidebar-menu span[data-bs-toggle="collapse"][aria-expanded="true"] > i.fa-chevron-down,
#sidebar-menu [data-bs-toggle="collapse"].collapsed > i.fa-chevron-right { #sidebar-menu span[data-bs-toggle="collapse"][aria-expanded="false"] > i.fa-chevron-right {
display: block; display: block;
width: 16px; width: 16px;
} }
#sidebar-menu [data-bs-toggle="collapse"] > i.fa-chevron-right, #sidebar-menu span[data-bs-toggle="collapse"][aria-expanded="true"] > i.fa-chevron-right,
#sidebar-menu [data-bs-toggle="collapse"].collapsed > i.fa-chevron-down { #sidebar-menu span[data-bs-toggle="collapse"][aria-expanded="false"] > i.fa-chevron-down {
display: none; display: none;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -11,8 +11,8 @@
data-bs-target="#{{ item.html_id }}" data-bs-target="#{{ item.html_id }}"
aria-expanded="false" aria-expanded="false"
aria-controls="" aria-controls=""
{% endif %}> {% endif %}
</i> ></i>
<a <a
class="nav-link flex-fill align-self-center me-auto {% if item.navactive %}{% navactive request item.navactive|join:' ' %}{% endif %}" class="nav-link flex-fill align-self-center me-auto {% if item.navactive %}{% navactive request item.navactive|join:' ' %}{% endif %}"
{% if item.is_folder %} {% if item.is_folder %}
@@ -36,7 +36,7 @@
{% if item.is_folder %} {% if item.is_folder %}
<span <span
class="pill m-2 align-self-center collapsed" class="pill m-2 align-self-center"
type="button" type="button"
data-bs-toggle="collapse" data-bs-toggle="collapse"
data-bs-target="#{{ item.html_id }}" data-bs-target="#{{ item.html_id }}"

View File

@@ -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 ""

View File

@@ -1,4 +1,4 @@
from unittest.mock import patch, Mock from unittest.mock import patch
from django.test import TestCase, override_settings from django.test import TestCase, override_settings

View File

@@ -1,6 +1,6 @@
import json import json
from unittest.mock import patch, Mock from unittest.mock import patch
from django.test import TestCase, RequestFactory from django.test import TestCase, RequestFactory
from django.urls import reverse from django.urls import reverse

View File

@@ -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, User from django.contrib.auth.models import Permission
from django.db.models import Count from django.db.models import Count
from django.shortcuts import render, Http404 from django.shortcuts import render, Http404

View File

@@ -1,13 +1,6 @@
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

View File

@@ -37,7 +37,6 @@ 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')

View File

@@ -1,5 +1,4 @@
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

View File

@@ -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 render, redirect from django.shortcuts import 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

View File

@@ -1,4 +1,3 @@
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

View File

@@ -101,22 +101,30 @@
const sidebar = document.getElementById('sidebar'); const sidebar = document.getElementById('sidebar');
sidebar.addEventListener('shown.bs.collapse', () => { sidebar.addEventListener('shown.bs.collapse', () => {
localStorage.removeItem('sidebar_' + sidebar.id); localStorage.removeItem(`sidebar_${sidebar.id}`);
}); });
sidebar.addEventListener('hidden.bs.collapse', () => { sidebar.addEventListener('hidden.bs.collapse', () => {
localStorage.setItem('sidebar_' + sidebar.id, 'closed'); localStorage.setItem(`sidebar_${sidebar.id}`, 'closed');
}); });
if (localStorage.getItem('sidebar_' + sidebar.id) === 'closed') { if (localStorage.getItem(`sidebar_${sidebar.id}`) === 'closed') {
sidebar.classList.remove('show') sidebar.classList.remove('show')
} else { } else {
sidebar.classList.add("show") sidebar.classList.add("show")
} }
const activeChildMenuItem = document.querySelector('#sidebar-menu li ul li a.active'); const activeChildMenuItem = document.querySelector('#sidebar-menu li ul li a.active');
if (activeChildMenuItem) { if (activeChildMenuItem) {
activeChildMenuItem.parentElement.parentElement.classList.add('show'); const activeChildMenuUl = activeChildMenuItem.parentElement.parentElement;
const elementsToToggle = document.querySelectorAll(`[data-bs-target^="#${activeChildMenuUl.id}"]`);
activeChildMenuUl.classList.add('show');
elementsToToggle.forEach((element) => {
element.setAttribute('aria-expanded', true);
});
} }
})(); })();
</script> </script>

View File

@@ -1,12 +1,6 @@
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

View File

@@ -180,6 +180,9 @@
$(document).ready(() => { $(document).ready(() => {
const dtOptions = { const dtOptions = {
language: {url: '{{ DT_LANG_PATH }}'}, language: {url: '{{ DT_LANG_PATH }}'},
order: [
[4, 'asc']
],
}; };
{% if perms.auth.timer_management %} {% if perms.auth.timer_management %}

View File

@@ -1,6 +1,5 @@
from typing import List, Iterable, Callable from typing import List, Iterable, Callable
from django.urls import include
import esi.urls import esi.urls
from django.conf import settings from django.conf import settings
from django.contrib import admin from django.contrib import admin

View File

@@ -1,7 +1,7 @@
PROTOCOL=https:// PROTOCOL=https://
AUTH_SUBDOMAIN=%AUTH_SUBDOMAIN% AUTH_SUBDOMAIN=%AUTH_SUBDOMAIN%
DOMAIN=%DOMAIN% DOMAIN=%DOMAIN%
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v4.6.0 AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v4.6.2a
# Nginx Proxy Manager # Nginx Proxy Manager
PROXY_HTTP_PORT=80 PROXY_HTTP_PORT=80

View File

@@ -1,5 +1,5 @@
FROM python:3.11-slim FROM python:3.11-slim
ARG AUTH_VERSION=v4.6.0 ARG AUTH_VERSION=v4.6.2a
ARG AUTH_PACKAGE=allianceauth==${AUTH_VERSION} ARG AUTH_PACKAGE=allianceauth==${AUTH_VERSION}
ENV AUTH_USER=allianceauth ENV AUTH_USER=allianceauth
ENV AUTH_GROUP=allianceauth ENV AUTH_GROUP=allianceauth

View File

@@ -1,7 +1,7 @@
[build-system] [build-system]
build-backend = "flit_core.buildapi" build-backend = "flit_core.buildapi"
requires = [ requires = [
"flit-core<4,>=3.2", "flit-core>=3.2,<4",
] ]
[project] [project]
@@ -31,6 +31,7 @@ classifiers = [
"Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
] ]
@@ -41,15 +42,15 @@ dynamic = [
dependencies = [ dependencies = [
"bcrypt", "bcrypt",
"beautifulsoup4", "beautifulsoup4",
"celery<6,>=5.2", "celery>=5.2,<6",
"celery-once>=3.0.1", "celery-once>=3.0.1",
"django<5,>=4.2", "django>=4.2,<5",
"django-bootstrap-form", "django-bootstrap-form",
"django-bootstrap5>=23.3", "django-bootstrap5>=23.3",
"django-celery-beat>=2.3", "django-celery-beat>=2.3",
"django-esi>=5", "django-esi>=5",
"django-redis>=5.2", "django-redis>=5.2",
"django-registration<3.4,>=3.3", "django-registration>=3.3,<3.4",
"django-solo", "django-solo",
"django-sortedm2m", "django-sortedm2m",
"django-sri", "django-sri",
@@ -70,7 +71,7 @@ optional-dependencies.docs = [
"myst-parser", "myst-parser",
"sphinx", "sphinx",
"sphinx-copybutton", "sphinx-copybutton",
"sphinx-rtd-theme<3,>=2", "sphinx-rtd-theme>=2,<3",
"sphinx-tabs", "sphinx-tabs",
"sphinxcontrib-django", "sphinxcontrib-django",
] ]