Compare commits

..

9 Commits

Author SHA1 Message Date
Joel Falknau
156e7c891e document cron offsetting 2024-12-30 18:57:09 +10:00
Joel Falknau
6f2f39d7fa shift to custom Scheduler 2024-12-30 18:12:11 +10:00
Joel Falknau
a66aa6de80 rename submodule properly 2024-12-29 22:19:51 +10:00
Joel Falknau
d12d6e7cdb move to its own module 2024-12-29 22:04:52 +10:00
Joel Falknau
7022cb7050 not relevant comment 2024-12-29 15:14:29 +10:00
Joel Falknau
30a79362f4 remove development note 2024-12-29 15:13:13 +10:00
Joel Falknau
c3fa8acd8e Tweak migrations to use random function not preset 2024-12-29 15:05:53 +10:00
Joel Falknau
8fd1411f09 shift schedule to ready() in order to access DB 2024-12-29 14:51:57 +10:00
Joel Falknau
1aa90adac3 Cron Offset Module 2024-12-29 14:51:33 +10:00
174 changed files with 3333 additions and 8602 deletions

View File

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

View File

@@ -1,15 +1,15 @@
# Alliance Auth
[![License](https://img.shields.io/badge/license-GPLv2-green)](https://pypi.org/project/allianceauth/)
[![Python Versions](https://img.shields.io/pypi/pyversions/allianceauth)](https://pypi.org/project/allianceauth/)
[![Django Versions](https://img.shields.io/pypi/djversions/allianceauth?label=django)](https://pypi.org/project/allianceauth/)
[![Stable AA Version](https://img.shields.io/pypi/v/allianceauth?label=release)](https://pypi.org/project/allianceauth/)
[![Pipeline Status](https://gitlab.com/allianceauth/allianceauth/badges/master/pipeline.svg)](https://gitlab.com/allianceauth/allianceauth/commits/master)
[![license](https://img.shields.io/badge/license-GPLv2-green)](https://pypi.org/project/allianceauth/)
[![python](https://img.shields.io/pypi/pyversions/allianceauth)](https://pypi.org/project/allianceauth/)
[![django](https://img.shields.io/pypi/djversions/allianceauth?label=django)](https://pypi.org/project/allianceauth/)
[![version](https://img.shields.io/pypi/v/allianceauth?label=release)](https://pypi.org/project/allianceauth/)
[![pipeline status](https://gitlab.com/allianceauth/allianceauth/badges/master/pipeline.svg)](https://gitlab.com/allianceauth/allianceauth/commits/master)
[![Documentation Status](https://readthedocs.org/projects/allianceauth/badge/?version=latest)](https://allianceauth.readthedocs.io/?badge=latest)
[![Test Coverage Report](https://gitlab.com/allianceauth/allianceauth/badges/master/coverage.svg)](https://gitlab.com/allianceauth/allianceauth/commits/master)
[![coverage report](https://gitlab.com/allianceauth/allianceauth/badges/master/coverage.svg)](https://gitlab.com/allianceauth/allianceauth/commits/master)
[![Chat on Discord](https://img.shields.io/discord/399006117012832262.svg)](https://discord.gg/fjnHAmk)
A flexible authentication platform for EVE Online to help in-game organizations manage access to applications and services. AA provides both, a stable core, and a robust framework for community development and custom applications.
An auth system for EVE Online to help in-game organizations manage online service access.
## Content
@@ -22,17 +22,17 @@ A flexible authentication platform for EVE Online to help in-game organizations
## Overview
Alliance Auth (AA) is a platform that helps Eve Online organizations efficiently manage access to applications and services.
Alliance Auth (AA) is a web site that helps Eve Online organizations efficiently manage access to applications and services.
Main features:
- Automatically grants or revokes user access to external services (e.g.: Discord, Mumble) based on the user's current membership to [a variety of EVE Online affiliation](https://allianceauth.readthedocs.io/en/latest/features/core/states/) and [groups](https://allianceauth.readthedocs.io/en/latest/features/core/groups/)
- Automatically grants or revokes user access to external services (e.g. Discord, Mumble) and web apps (e.g. SRP requests) based on the user's current membership to [in-game organizations](https://allianceauth.readthedocs.io/en/latest/features/core/states/) and [groups](https://allianceauth.readthedocs.io/en/latest/features/core/groups/)
- Provides a central web site where users can directly access web apps (e.g. SRP requests, Fleet Schedule) and manage their access to external services and groups.
- Includes a set of connectors (called ["Services"](https://allianceauth.readthedocs.io/en/latest/features/services/)) for integrating access management with many popular external applications / services like Discord, Mumble, Teamspeak 3, SMF and others
- Includes a set of connectors (called ["services"](https://allianceauth.readthedocs.io/en/latest/features/services/)) for integrating access management with many popular external applications / services like Discord, Mumble, Teamspeak 3, SMF and others
- Includes a set of web [Apps](https://allianceauth.readthedocs.io/en/latest/features/apps/) which add many useful functions, e.g.: fleet schedule, timer board, SRP request management, fleet activity tracker
- Includes a set of web [apps](https://allianceauth.readthedocs.io/en/latest/features/apps/) which add many useful functions, e.g.: fleet schedule, timer board, SRP request management, fleet activity tracker
- Can be easily extended with additional services and apps. Many are provided by the community and can be found here: [Community Creations](https://gitlab.com/allianceauth/community-creations)
@@ -42,15 +42,9 @@ For further details about AA - including an installation guide and a full list o
## Screenshot
Here is an example of the Alliance Auth web site with a mixture of Services, Apps and Community Creations enabled:
Here is an example of the Alliance Auth web site with some plug-ins apps and services enabled:
### Flatly Theme
![Flatly Theme](docs/_static/images/promotion/SampleInstallation-Flatly.png)
### Darkly Theme
![Darkly Theme](docs/_static/images/promotion/SampleInstallation-Darkly.png)
![screenshot](https://i.imgur.com/2tnX9kD.png)
## Support

View File

@@ -5,7 +5,7 @@ manage online service access.
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
__version__ = '4.7.0'
__version__ = '4.5.0'
__title__ = 'Alliance Auth'
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
NAME = f'{__title__} v{__version__}'

View File

@@ -1,16 +1,15 @@
from django.contrib import admin
from .models import AnalyticsIdentifier, AnalyticsTokens
from solo.admin import SingletonModelAdmin
@admin.register(AnalyticsIdentifier)
class AnalyticsIdentifierAdmin(SingletonModelAdmin):
class AnalyticsIdentifierAdmin(admin.ModelAdmin):
search_fields = ['identifier', ]
list_display = ['identifier', ]
list_display = ('identifier',)
@admin.register(AnalyticsTokens)
class AnalyticsTokensAdmin(admin.ModelAdmin):
search_fields = ['name', ]
list_display = ['name', 'type', ]
list_display = ('name', 'type',)

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class AnalyticsConfig(AppConfig):
name = 'allianceauth.analytics'
label = 'analytics'
verbose_name = _('Analytics')

View File

@@ -1,17 +0,0 @@
# Generated by Django 4.2.16 on 2024-12-11 02:17
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('analytics', '0009_remove_analyticstokens_ignore_paths_and_more'),
]
operations = [
migrations.AlterModelOptions(
name='analyticsidentifier',
options={'verbose_name': 'Analytics Identifier'},
),
]

View File

@@ -1,19 +1,23 @@
from typing import Literal
from django.db import models
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from solo.models import SingletonModel
from uuid import uuid4
class AnalyticsIdentifier(SingletonModel):
class AnalyticsIdentifier(models.Model):
identifier = models.UUIDField(default=uuid4, editable=False)
identifier = models.UUIDField(
default=uuid4,
editable=False)
def __str__(self) -> Literal['Analytics Identifier']:
return "Analytics Identifier"
class Meta:
verbose_name = "Analytics Identifier"
def save(self, *args, **kwargs):
if not self.pk and AnalyticsIdentifier.objects.exists():
# Force a single object
raise ValidationError('There is can be only one \
AnalyticsIdentifier instance')
self.pk = self.id = 1 # If this happens to be deleted and recreated, force it to be 1
return super().save(*args, **kwargs)
class AnalyticsTokens(models.Model):

View File

@@ -5,7 +5,6 @@ from django.apps import apps
from celery import shared_task
from .models import AnalyticsTokens, AnalyticsIdentifier
from .utils import (
existence_baremetal_or_docker,
install_stat_addons,
install_stat_tokens,
install_stat_users)
@@ -68,8 +67,8 @@ def analytics_event(namespace: str,
value=value).apply_async(priority=9)
@shared_task
def analytics_daily_stats() -> None:
@shared_task()
def analytics_daily_stats():
"""Celery Task: Do not call directly
Gathers a series of daily statistics
@@ -78,7 +77,6 @@ def analytics_daily_stats() -> None:
users = install_stat_users()
tokens = install_stat_tokens()
addons = install_stat_addons()
existence_type = existence_baremetal_or_docker()
logger.debug("Running Daily Analytics Upload")
analytics_event(namespace='allianceauth.analytics',
@@ -86,11 +84,6 @@ def analytics_daily_stats() -> None:
label='existence',
value=1,
event_type='Stats')
analytics_event(namespace='allianceauth.analytics',
task='send_install_stats',
label=existence_type,
value=1,
event_type='Stats')
analytics_event(namespace='allianceauth.analytics',
task='send_install_stats',
label='users',
@@ -106,6 +99,7 @@ def analytics_daily_stats() -> None:
label='addons',
value=addons,
event_type='Stats')
for appconfig in apps.get_app_configs():
if appconfig.label in [
"django_celery_beat",
@@ -141,7 +135,7 @@ def analytics_daily_stats() -> None:
event_type='Stats')
@shared_task
@shared_task()
def send_ga_tracking_celery_event(
measurement_id: str,
secret: str,
@@ -171,7 +165,7 @@ def send_ga_tracking_celery_event(
}
payload = {
'client_id': AnalyticsIdentifier.get_solo().identifier.hex,
'client_id': AnalyticsIdentifier.objects.get(id=1).identifier.hex,
"user_properties": {
"allianceauth_version": {
"value": __version__

View File

@@ -1,8 +1,9 @@
from allianceauth.analytics.models import AnalyticsIdentifier
from django.core.exceptions import ValidationError
from django.test.testcases import TestCase
from uuid import uuid4
from uuid import UUID, uuid4
# Identifiers
@@ -13,4 +14,14 @@ uuid_2 = "7aa6bd70701f44729af5e3095ff4b55c"
class TestAnalyticsIdentifier(TestCase):
def test_identifier_random(self):
self.assertNotEqual(AnalyticsIdentifier.get_solo(), uuid4)
self.assertNotEqual(AnalyticsIdentifier.objects.get(), uuid4)
def test_identifier_singular(self):
AnalyticsIdentifier.objects.all().delete()
AnalyticsIdentifier.objects.create(identifier=uuid_1)
# Yeah i have multiple asserts here, they all do the same thing
with self.assertRaises(ValidationError):
AnalyticsIdentifier.objects.create(identifier=uuid_2)
self.assertEqual(AnalyticsIdentifier.objects.count(), 1)
self.assertEqual(AnalyticsIdentifier.objects.get(
pk=1).identifier, UUID(uuid_1))

View File

@@ -1,4 +1,3 @@
import os
from django.apps import apps
from allianceauth.authentication.models import User
from esi.models import Token
@@ -35,16 +34,3 @@ def install_stat_addons() -> int:
The Number of Installed Apps"""
addons = len(list(apps.get_app_configs()))
return addons
def existence_baremetal_or_docker() -> str:
"""Checks the Installation Type of an install
Returns
-------
str
existence_baremetal or existence_docker"""
docker_tag = os.getenv('AA_DOCKER_TAG')
if docker_tag:
return "existence_docker"
return "existence_baremetal"

View File

@@ -1,12 +1,10 @@
from django.apps import AppConfig
from django.core.checks import register, Tags
from django.utils.translation import gettext_lazy as _
class AuthenticationConfig(AppConfig):
name = "allianceauth.authentication"
label = "authentication"
verbose_name = _("Authentication")
def ready(self):
from allianceauth.authentication import checks, signals # noqa: F401

View File

@@ -1,5 +1,4 @@
import logging
from typing import ClassVar
from django.contrib.auth.models import User, Permission
from django.db import models, transaction
@@ -28,7 +27,7 @@ class State(models.Model):
help_text="Factions to whose members this state is available.")
public = models.BooleanField(default=False, help_text="Make this state available to any character.")
objects: ClassVar[StateManager] = StateManager()
objects = StateManager()
class Meta:
ordering = ['-priority']
@@ -138,10 +137,8 @@ class UserProfile(models.Model):
sender=self.__class__, user=self.user, state=self.state
)
def __str__(self) -> str:
def __str__(self):
return str(self.user)
class CharacterOwnership(models.Model):
class Meta:
default_permissions = ('change', 'delete')
@@ -151,7 +148,7 @@ class CharacterOwnership(models.Model):
owner_hash = models.CharField(max_length=28, unique=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='character_ownerships')
objects: ClassVar[CharacterOwnershipManager] = CharacterOwnershipManager()
objects = CharacterOwnershipManager()
def __str__(self):
return f"{self.user}: {self.character}"

View File

@@ -1,6 +1,5 @@
{% extends "allianceauth/base-bs5.html" %}
{% load aa_i18n %}
{% load i18n %}
{% block page_title %}
@@ -14,7 +13,7 @@
{% block content %}
<div>
<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://developers.eveonline.com/authorized-apps 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://community.eveonline.com/support/third-party-applications/ where possible."|urlize %}
</p>
<table class="table w-100" id="table_tokens">
@@ -31,7 +30,7 @@
<tr>
<td style="white-space:initial;">
{% for s in t.scopes.all %}
<span class="badge text-bg-secondary">{{ s.name }}</span>
<span class="badge bg-secondary">{{ s.name }}</span>
{% endfor %}
</td>
@@ -51,23 +50,20 @@
{% block extra_javascript %}
{% include "bundles/datatables-js-bs5.html" %}
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
<script>
$(document).ready(() => {
let grp = 2;
$('#table_tokens').DataTable({
"language": {"url": '{{ DT_LANG_PATH }}'},
const table = $('#table_tokens').DataTable({
'columnDefs': [{orderable: false, targets: [0, 1]}, {
'visible': false,
'targets': grp
}],
'order': [[grp, 'asc']],
'drawCallback': function (settings) {
const api = this.api();
const rows = api.rows({page: 'current'}).nodes();
let last = null;
var api = this.api();
var rows = api.rows({page: 'current'}).nodes();
var last = null;
api.column(grp, {page: 'current'})
.data()
.each((group, i) => {

View File

@@ -1,24 +1,24 @@
{% load theme_tags %}
{% load static %}
<!DOCTYPE html>
<html lang="en" {% theme_html_tags %}>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- End Required meta tags -->
<meta name="description" content="">
<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' %}
<!-- Meta tags -->
<title>{% block title %}{% block page_title %}{% endblock page_title %} - {{ SITE_NAME }}{% endblock title %}</title>
{% theme_css %}
{% include 'bundles/fontawesome.html' %}
{% include 'bundles/auth-framework-css.html' %}
{% block extra_include %}
{% endblock %}

View File

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

View File

@@ -1,7 +1,3 @@
"""
Django system checks for Alliance Auth
"""
from typing import List
from django import db
from django.core.checks import CheckMessage, Error, register, Warning
@@ -20,475 +16,142 @@ B = Configuration
@register()
def django_settings(app_configs, **kwargs) -> List[CheckMessage]:
"""
Check that Django settings are correctly configured
:param app_configs:
:type app_configs:
: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
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(
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",
)
)
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"))
# 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
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"))
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",
)
)
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"))
return errors
@register()
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"
errors: List[CheckMessage] = []
try:
redis_version = Pep440Version(get_redis_client().info()["redis_version"])
redis_version = Pep440Version(get_redis_client().info()['redis_version'])
except InvalidVersion:
errors.append(Warning("Unable to confirm Redis Version"))
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)
):
errors.append(
Error(
msg=f"Redis {redis_version.public} in Security Support only, Updating Suggested",
hint=allianceauth_redis_install_link,
id="allianceauth.checks.A001",
)
)
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"))
elif redis_version.major == 7 and redis_version.minor == 0:
errors.append(
Warning(
msg=f"Redis {redis_version.public} in Security Support only, Updating Suggested",
hint=allianceauth_redis_install_link,
id="allianceauth.checks.A002",
)
)
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"))
elif redis_version.major == 6 and redis_version.minor == 2:
errors.append(
Warning(
msg=f"Redis {redis_version.public} in Security Support only, Updating Suggested",
hint=allianceauth_redis_install_link,
id="allianceauth.checks.A018",
)
)
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"))
elif redis_version.major in [6, 5]:
errors.append(
Error(
msg=f"Redis {redis_version.public} EOL",
hint=allianceauth_redis_install_link,
id="allianceauth.checks.A003",
)
)
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"))
return errors
@register()
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/"
errors: List[CheckMessage] = []
for connection in db.connections.all():
if connection.vendor == "mysql":
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:
errors.append(Warning("Unable to confirm MySQL Version"))
return errors
# MySQL 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
):
errors.append(
Error(
msg=f"MySQL {mysql_version.public} EOL",
hint=mysql_quick_guide_link,
id="allianceauth.checks.A004",
)
)
elif mysql_version.minor == 3:
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:
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:
errors.append(
Error(
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
# This will also catch Mariadb 5.x
elif mysql_version.major < 8:
errors.append(
Error(
msg=f"MySQL or MariaDB {mysql_version.public} EOL",
hint=mysql_quick_guide_link,
id="allianceauth.checks.A009",
)
)
if mysql_version.major == 8 and mysql_version.minor == 4 and timezone.now() > timezone.datetime(year=2032, month=4, day=30, tzinfo=timezone.utc):
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"))
elif mysql_version.major == 8 and mysql_version.minor == 3:
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.major == 8 and mysql_version.minor == 2:
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.major == 8 and mysql_version.minor == 1:
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.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="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A008"))
elif mysql_version.major < 8: # This will also catch Mariadb 5.x
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"))
return errors
@register()
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"
errors: List[CheckMessage] = []
for connection in db.connections.all():
# TODO: Find a way to determine MySQL vs. MariaDB
if connection.vendor == "mysql":
if connection.vendor == "mysql": # Still to find a way to determine MySQL vs MariaDB
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:
errors.append(Warning("Unable to confirm MariaDB Version"))
return errors
# MariaDB 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
):
errors.append(
Error(
msg=f"MariaDB {mariadb_version.public} EOL",
hint=mariadb_download_link,
id="allianceauth.checks.A010",
)
)
elif mariadb_version.minor == 2:
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
):
errors.append(
Error(
msg=f"MariaDB {mariadb_version.public} EOL",
hint=mariadb_download_link,
id="allianceauth.checks.A011",
)
)
elif mariadb_version.minor == 1:
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
):
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",
)
)
if mariadb_version.major == 11 and mariadb_version.minor == 4 and timezone.now() > timezone.datetime(year=2029, month=5, day=19, tzinfo=timezone.utc):
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A010"))
elif mariadb_version.major == 11 and mariadb_version.minor == 2:
errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A018"))
if timezone.now() > timezone.datetime(year=2024, month=11, day=21, tzinfo=timezone.utc):
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:
errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A019"))
if timezone.now() > timezone.datetime(year=2024, month=8, day=21, tzinfo=timezone.utc):
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A012"))
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"))
# MariaDB 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
):
errors.append(
Error(
msg=f"MariaDB {mariadb_version.public} EOL",
hint=mariadb_download_link,
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",
)
)
elif mariadb_version.major == 10 and mariadb_version.minor == 11 and timezone.now() > timezone.datetime(year=2028, month=2, day=10, tzinfo=timezone.utc):
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config.", id="allianceauth.checks.A014"))
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="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A0015"))
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="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A016"))
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="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A017"))
return errors
@register()
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] = []
for connection in db.connections.all():
if connection.vendor == "sqlite":
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:
errors.append(Warning("Unable to confirm SQLite Version"))
return errors
if sqlite_version.major == 3 and sqlite_version.minor < 27:
errors.append(
Error(
msg=f"SQLite {sqlite_version.public} Unsupported by Django",
hint="https://pkgs.org/download/sqlite3",
id="allianceauth.checks.A020",
)
)
errors.append(Error(f"SQLite {sqlite_version.public} Unsupported by Django", hint="https://pkgs.org/download/sqlite3", id="allianceauth.checks.A020"))
return errors
@register()
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] = []
for connection in db.connections.all():
if connection.vendor == "mysql":
try:
if connection.settings_dict["OPTIONS"]["charset"] != "utf8mb4":
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",
)
)
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"))
except KeyError:
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",
)
)
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"))
# This hasn't actually been set on AA yet
# try:
# if (
# 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",
# )
# )
# if connection.settings_dict["OPTIONS"]["collation"] != "utf8mb4_unicode_ci":
# 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"))
# except KeyError:
# 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",
# )
# )
# 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"))
# if connection.vendor == "sqlite":
@@ -497,57 +160,19 @@ def sql_settings(app_configs, **kwargs) -> List[CheckMessage]:
@register()
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] = []
try:
if current_app.conf.broker_transport_options != {
"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",
)
)
if current_app.conf.broker_transport_options != {'priority_steps': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 'queue_order_strategy': 'priority'}:
errors.append(Error("Celery Priorities are not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc", id="allianceauth.checks.B003"))
except KeyError:
errors.append(
Error(
msg="Celery Priorities are not set",
hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc",
id="allianceauth.checks.B003",
)
)
errors.append(Error("Celery Priorities are not set", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc", id="allianceauth.checks.B003"))
try:
if not current_app.conf.broker_connection_retry_on_startup:
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",
)
)
if current_app.conf.broker_connection_retry_on_startup != True:
errors.append(Error("Celery broker_connection_retry_on_startup not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280", id="allianceauth.checks.B004"))
except KeyError:
errors.append(
Error(
msg="Celery broker_connection_retry_on_startup not set",
hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280",
id="allianceauth.checks.B004",
)
)
errors.append(Error("Celery broker_connection_retry_on_startup not set", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280", id="allianceauth.checks.B004"))
return errors

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class CorpUtilsConfig(AppConfig):
name = 'allianceauth.corputils'
label = 'corputils'
verbose_name = _('Corporation Stats')

View File

@@ -1,6 +1,5 @@
import logging
import os
from typing import ClassVar
from allianceauth.authentication.models import CharacterOwnership, UserProfile
from bravado.exception import HTTPForbidden
@@ -41,9 +40,9 @@ class CorpStats(models.Model):
verbose_name = "corp stats"
verbose_name_plural = "corp stats"
objects: ClassVar[CorpStatsManager] = CorpStatsManager()
objects = CorpStatsManager()
def __str__(self) -> str:
def __str__(self):
return f"{self.__class__.__name__} for {self.corp}"
def update(self):

View File

@@ -1,6 +1,5 @@
{% extends 'corputils/base.html' %}
{% load aa_i18n %}
{% load i18n %}
{% load humanize %}
@@ -138,7 +137,7 @@
<td style="width: 30%;">{{ alt.corporation_name }}</td>
<td style="width: 30%;">{{ alt.alliance_name|default_if_none:"" }}</td>
<td style="width: 5%;">
<a href="https://zkillboard.com/character/{{ alt.character_id }}/" class="badge text-bg-danger" target="_blank">
<a href="https://zkillboard.com/character/{{ alt.character_id }}/" class="badge bg-danger" target="_blank">
{% translate "Killboard" %}
</a>
</td>
@@ -175,7 +174,7 @@
<td><img src="{{ member.portrait_url }}" class="img-circle" alt="{{ member }}"></td>
<td>{{ member }}</td>
<td>
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="badge text-bg-danger" target="_blank">{% translate "Killboard" %}</a>
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="badge bg-danger" target="_blank">{% translate "Killboard" %}</a>
</td>
<td>{{ member.character_ownership.user.profile.main_character.character_name }}</td>
<td>{{ member.character_ownership.user.profile.main_character.corporation_name }}</td>
@@ -188,7 +187,7 @@
<td><img src="{{ member.portrait_url }}" class="img-circle" alt="{{ member.character_name }}"></td>
<td>{{ member.character_name }}</td>
<td>
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="badge text-bg-danger" target="_blank">{% translate "Killboard" %}</a>
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="badge bg-danger" target="_blank">{% translate "Killboard" %}</a>
</td>
<td></td>
<td></td>
@@ -219,7 +218,7 @@
<td><img src="{{ member.portrait_url }}" class="img-circle" alt="{{ member.character_name }}"></td>
<td>{{ member.character_name }}</td>
<td>
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="badge text-bg-danger" target="_blank">
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="badge bg-danger" target="_blank">
{% translate "Killboard" %}
</a>
</td>
@@ -239,12 +238,9 @@
{% block extra_javascript %}
{% include 'bundles/datatables-js-bs5.html' %}
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
<script>
$(document).ready(() => {
$('#table-mains').DataTable({
"language": {"url": '{{ DT_LANG_PATH }}'},
"columnDefs": [
{ "sortable": false, "targets": [1] },
],
@@ -253,7 +249,6 @@
});
$('#table-members').DataTable({
"language": {"url": '{{ DT_LANG_PATH }}'},
"columnDefs": [
{ "searchable": false, "targets": [0, 2] },
{ "sortable": false, "targets": [0, 2] },
@@ -264,7 +259,6 @@
});
$('#table-unregistered').DataTable({
"language": {"url": '{{ DT_LANG_PATH }}'},
"columnDefs": [
{ "searchable": false, "targets": [0, 2] },
{ "sortable": false, "targets": [0, 2] },

View File

@@ -1,6 +1,5 @@
{% extends "corputils/base.html" %}
{% load aa_i18n %}
{% load i18n %}
{% block member_data %}
@@ -28,7 +27,7 @@
<td><img src="{{ result.1.portrait_url }}" class="img-circle" alt="{{ result.1.character_name }}"></td>
<td>{{ result.1.character_name }}</td>
<td >{{ result.0.corp.corporation_name }}</td>
<td><a href="https://zkillboard.com/character/{{ result.1.character_id }}/" class="badge text-bg-danger" target="_blank">{% translate "Killboard" %}</a></td>
<td><a href="https://zkillboard.com/character/{{ result.1.character_id }}/" class="badge bg-danger" target="_blank">{% translate "Killboard" %}</a></td>
<td>{{ result.1.main_character.character_name }}</td>
<td>{{ result.1.main_character.corporation_name }}</td>
<td>{{ result.1.main_character.alliance_name }}</td>
@@ -43,12 +42,9 @@
{% block extra_javascript %}
{% include 'bundles/datatables-js-bs5.html' %}
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
<script>
$(document).ready(() => {
$('#table-search').DataTable({
"language": {"url": '{{ DT_LANG_PATH }}'},
"stateSave": true,
"stateDuration": 0
});

View File

@@ -3,7 +3,6 @@ Crontab App Config
"""
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class CrontabConfig(AppConfig):
@@ -13,4 +12,3 @@ class CrontabConfig(AppConfig):
name = "allianceauth.crontab"
label = "crontab"
verbose_name = _("Crontab")

View File

@@ -1,29 +0,0 @@
# 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,10 +20,6 @@ class OffsetDatabaseScheduler(DatabaseScheduler):
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
"""
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
def update_from_dict(self, mapping):
s = {}
@@ -40,11 +36,10 @@ class OffsetDatabaseScheduler(DatabaseScheduler):
for name, entry_fields in mapping.items():
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)
entry = self.Entry.from_entry(name, app=self.app, **entry_fields)
if apply_offset:
entry_fields.update({"apply_offset": apply_offset}) # Reapply this as its gets pulled from config inconsistently.
if entry.model.enabled and apply_offset:
schedule_obj = entry.schedule
if isinstance(schedule_obj, schedules.crontab):
offset_cs = CrontabSchedule.from_schedule(offset_cron(schedule_obj))
@@ -56,12 +51,10 @@ class OffsetDatabaseScheduler(DatabaseScheduler):
day_of_week=offset_cs.day_of_week,
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.save()
logger.debug(f"Offset applied for '{name}' due to 'apply_offset' = True.")
if entry.model.enabled:
s[name] = entry
except Exception as e:

View File

@@ -19,16 +19,7 @@ def offset_cron(schedule: crontab) -> crontab:
try:
cron_offset = CronOffset.get_solo()
# 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(

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class EveonlineConfig(AppConfig):
name = 'allianceauth.eveonline'
label = 'eveonline'
verbose_name = _('EVE Online')

View File

@@ -1,11 +1,9 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class EveAutogroupsConfig(AppConfig):
name = 'allianceauth.eveonline.autogroups'
label = 'eve_autogroups'
verbose_name = _('EVE Online Autogroups')
def ready(self):
import allianceauth.eveonline.autogroups.signals

View File

@@ -1,5 +1,4 @@
import logging
from typing import ClassVar
from django.db import models, transaction
from django.contrib.auth.models import Group, User
from django.core.exceptions import ObjectDoesNotExist
@@ -39,13 +38,13 @@ class AutogroupsConfigManager(models.Manager):
"""
if state is None:
state = user.profile.state
for config in self.filter(states=state):
# grant user new groups for their state
config.update_group_membership_for_user(user)
for config in self.exclude(states=state):
# ensure user does not have groups from previous state
config.remove_user_from_alliance_groups(user)
config.remove_user_from_corp_groups(user)
for config in self.filter(states=state):
# grant user new groups for their state
config.update_group_membership_for_user(user)
class AutogroupsConfig(models.Model):
@@ -79,7 +78,7 @@ class AutogroupsConfig(models.Model):
max_length=10, default='', blank=True,
help_text='Any spaces in the group name will be replaced with this.')
objects: ClassVar[AutogroupsConfigManager] = AutogroupsConfigManager()
objects = AutogroupsConfigManager()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

View File

@@ -1,4 +1,3 @@
from allianceauth.eveonline.models import EveCorporationInfo
from django.test import TestCase
from allianceauth.tests.auth_utils import AuthUtils
@@ -74,51 +73,3 @@ class AutogroupsConfigManagerTestCase(TestCase):
AutogroupsConfig.objects.update_groups_for_user(member)
self.assertTrue(update_groups.called)
def test_update_group_membership_corp_in_two_configs(self):
# given
member = AuthUtils.create_member('test member')
AuthUtils.add_main_character_2(
member,
character_id='1234',
name='test character',
corp_id='2345',
corp_name='corp name',
corp_ticker='TIKK',
)
corp = EveCorporationInfo.objects.create(
corporation_id='2345',
corporation_name='corp name',
corporation_ticker='TIKK',
member_count=10,
)
member_state = AuthUtils.get_member_state()
member_config = AutogroupsConfig.objects.create(corp_groups=True)
member_config.states.add(member_state)
blue_state = AuthUtils.get_blue_state()
blue_state.member_corporations.add(corp)
blue_config = AutogroupsConfig.objects.create(corp_groups=True)
blue_config.states.add(blue_state)
member.profile.state = blue_state
member.profile.save()
AutogroupsConfig.objects.update_groups_for_user(member)
# Checks before test that the role is correctly applied
group = blue_config.get_corp_group(corp)
self.assertIn(group, member.groups.all())
# when
blue_state.member_corporations.remove(corp)
member_state.member_corporations.add(corp)
member.profile.state = member_state
member.profile.save()
# then
AutogroupsConfig.objects.update_groups_for_user(member)
group = member_config.get_corp_group(corp)
self.assertIn(group, member.groups.all())

View File

@@ -14,10 +14,10 @@ class EveCharacterProviderManager:
class EveCharacterManager(models.Manager):
provider = EveCharacterProviderManager()
def create_character(self, character_id) -> models.Model:
def create_character(self, character_id):
return self.create_character_obj(self.provider.get_character(character_id))
def create_character_obj(self, character: providers.Character) -> models.Model:
def create_character_obj(self, character: providers.Character):
return self.create(
character_id=character.id,
character_name=character.name,

View File

@@ -1,5 +1,5 @@
import logging
from typing import ClassVar, Union
from typing import Union
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
@@ -75,8 +75,8 @@ class EveAllianceInfo(models.Model):
alliance_ticker = models.CharField(max_length=254)
executor_corp_id = models.PositiveIntegerField()
objects: ClassVar[EveAllianceManager] = EveAllianceManager()
provider: ClassVar[EveAllianceProviderManager] = EveAllianceProviderManager()
objects = EveAllianceManager()
provider = EveAllianceProviderManager()
class Meta:
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
)
objects: ClassVar[EveCorporationManager] = EveCorporationManager()
objects = EveCorporationManager()
provider = EveCorporationProviderManager()
class Meta:
@@ -214,7 +214,7 @@ class EveCharacter(models.Model):
faction_id = models.PositiveIntegerField(blank=True, null=True, default=None)
faction_name = models.CharField(max_length=254, blank=True, null=True, default='')
objects: ClassVar[EveCharacterManager] = EveCharacterManager()
objects = EveCharacterManager()
provider = EveCharacterProviderManager()
class Meta:

View File

@@ -723,5 +723,5 @@ class TestEveSwaggerProvider(TestCase):
my_client = my_provider.client
operation = my_client.Universe.get_universe_factions()
self.assertEqual(
operation.future.request.headers['User-Agent'], 'allianceauth v1.0.0 dummy@example.net'
operation.future.request.headers['User-Agent'], 'allianceauth v1.0.0'
)

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class FatConfig(AppConfig):
name = 'allianceauth.fleetactivitytracking'
label = 'fleetactivitytracking'
verbose_name = _('Fleet Activity Tracking')

View File

@@ -36,7 +36,7 @@
<th class="text-center">{% translate "Character" %}</th>
<th class="text-center">{% translate "System" %}</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>
</tr>

View File

@@ -72,7 +72,7 @@
<tr>
<th class="text-center">{% translate "Fleet" %}</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 "Edit" %}</th>
</tr>
@@ -80,7 +80,7 @@
{% for link in created_fats %}
<tr>
<td class="text-center">
<a href="{% url 'fatlink:click' link.hash %}" class="badge text-bg-primary">
<a href="{% url 'fatlink:click' link.hash %}" class="badge bg-primary">
{{ link.fleet }}
</a>
</td>

View File

@@ -41,7 +41,7 @@
<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 "Ship" %}</th>
<th scope="col" class="text-center">{% translate "EVE time" %}</th>
<th scope="col" class="text-center">{% translate "Eve Time" %}</th>
</tr>
{% for fat in fats %}
@@ -89,7 +89,7 @@
<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 "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 "Edit" %}</th>
</tr>
@@ -97,7 +97,7 @@
{% for link in fatlinks %}
<tr>
<td class="text-center">
<a href="{% url 'fatlink:click' link.hash %}" class="badge text-bg-primary">{{ link.fleet }}</a>
<a href="{% url 'fatlink:click' link.hash %}" class="badge bg-primary">{{ link.fleet }}</a>
</td>
<td class="text-center">{{ link.creator.username }}</td>
<td class="text-center">{{ link.fleet }}</td>

View File

@@ -3,7 +3,6 @@ Framework App Config
"""
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class FrameworkConfig(AppConfig):
@@ -13,4 +12,3 @@ class FrameworkConfig(AppConfig):
name = "allianceauth.framework"
label = "framework"
verbose_name = _("Framework")

View File

@@ -5,24 +5,6 @@
* 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
------------------------------------------------------------------------------------- */
@media all {
@@ -67,14 +49,14 @@
}
/* Chevron icons */
#sidebar-menu span[data-bs-toggle="collapse"][aria-expanded="true"] > i.fa-chevron-down,
#sidebar-menu span[data-bs-toggle="collapse"][aria-expanded="false"] > i.fa-chevron-right {
#sidebar-menu [data-bs-toggle="collapse"] > i.fa-chevron-down,
#sidebar-menu [data-bs-toggle="collapse"].collapsed > i.fa-chevron-right {
display: block;
width: 16px;
}
#sidebar-menu span[data-bs-toggle="collapse"][aria-expanded="true"] > i.fa-chevron-right,
#sidebar-menu span[data-bs-toggle="collapse"][aria-expanded="false"] > i.fa-chevron-down {
#sidebar-menu [data-bs-toggle="collapse"] > i.fa-chevron-right,
#sidebar-menu [data-bs-toggle="collapse"].collapsed > i.fa-chevron-down {
display: none;
}
}

View File

@@ -2,8 +2,7 @@
{# {% include "framework/header/page-header.html" with title="Foobar" subtitle="Barfoo" %}#}
{% if title %}
<header class="aa-page-header mb-3">
<h1 class="page-header text-center">
<h1 class="page-header text-center mb-3">
{{ title }}
{% if subtitle %}
@@ -11,5 +10,4 @@
<small class="text-muted">{{ subtitle }}</small>
{% endif %}
</h1>
</header>
{% endif %}

View File

@@ -1,11 +1,10 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class GroupManagementConfig(AppConfig):
name = 'allianceauth.groupmanagement'
label = 'groupmanagement'
verbose_name = _('Group Management')
verbose_name = 'Group Management'
def ready(self):
from . import signals # noqa: F401

View File

@@ -1,6 +1,5 @@
{% extends "allianceauth/base-bs5.html" %}
{% load aa_i18n %}
{% load static %}
{% load i18n %}
{% load navactive %}
@@ -74,8 +73,6 @@
{% include 'bundles/moment-js.html' with locale=True %}
{% include 'bundles/filterdropdown-js.html' %}
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
<script>
$.fn.dataTable.moment = (format, locale) => {
const types = $.fn.dataTable.ext.type;
@@ -97,7 +94,6 @@
$.fn.dataTable.moment('YYYY-MMM-D, HH:mm');
$('#log-entries').DataTable({
language: {url: '{{ DT_LANG_PATH }}'},
order: [[0, 'desc'], [1, 'asc']],
filterDropDown:
{

View File

@@ -1,7 +1,6 @@
{% extends "allianceauth/base-bs5.html" %}
{% load static %}
{% load aa_i18n %}
{% load i18n %}
{% load evelinks %}
{% load navactive %}
@@ -87,12 +86,9 @@
{% block extra_javascript %}
{% include 'bundles/datatables-js-bs5.html' %}
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
<script>
$(document).ready(() => {
$('#tab_group_members').DataTable({
language: {url: '{{ DT_LANG_PATH }}'},
order: [[0, "asc"]],
columnDefs: [
{

View File

@@ -39,12 +39,12 @@
<td>
{% if group.authgroup.hidden %}
<span class="badge text-bg-info">{% translate "Hidden" %}</span>
<span class="badge bg-info">{% translate "Hidden" %}</span>
{% endif %}
{% if group.authgroup.open %}
<span class="badge text-bg-success">{% translate "Open" %}</span>
<span class="badge bg-success">{% translate "Open" %}</span>
{% else %}
<span class="badge text-bg-secondary">{% translate "Requestable" %}</span>
<span class="badge bg-secondary">{% translate "Requestable" %}</span>
{% endif %}
</td>

View File

@@ -1,7 +1,6 @@
{% extends "allianceauth/base-bs5.html" %}
{% load static %}
{% load aa_i18n %}
{% load i18n %}
{% block page_title %}
@@ -17,7 +16,7 @@
<li class="nav-item">
<a class="nav-link" href="{% url 'groupmanagement:management' %}">{% translate "Group Management" %}
{% if req_count %}
<span class="badge text-bg-secondary">{{ req_count }}</span>
<span class="badge bg-secondary">{{ req_count }}</span>
{% endif %}
</a>
</li>
@@ -33,8 +32,8 @@
<th>{% translate "Description" %}</th>
<th>
{% translate "Leaders" %}<br>
<span class="my-1 me-1 fw-lighter badge text-bg-primary">{% translate "User" %}</span>
<span class="my-1 me-1 fw-lighter badge text-bg-secondary">{% translate "Group" %}</span>
<span class="my-1 me-1 fw-lighter badge bg-primary">{% translate "User" %}</span>
<span class="my-1 me-1 fw-lighter badge bg-secondary">{% translate "Group" %}</span>
</th>
<th></th>
</tr>
@@ -53,13 +52,13 @@
{% if g.group.authgroup.group_leaders.all.count %}
{% for leader in g.group.authgroup.group_leaders.all %}
{% if leader.profile.main_character %}
<span class="my-1 me-1 badge text-bg-primary">{{leader.profile.main_character}}</span>
<span class="my-1 me-1 badge bg-primary">{{leader.profile.main_character}}</span>
{% endif %}
{% endfor %}
{% endif %}
{% if g.group.authgroup.group_leader_groups.all.count %}
{% for group in g.group.authgroup.group_leader_groups.all %}
<span class="my-1 me-1 badge text-bg-secondary">{{group.name}}</span>
<span class="my-1 me-1 badge bg-secondary">{{group.name}}</span>
{% endfor %}
{% endif %}
</td>
@@ -104,13 +103,9 @@
{% block extra_javascript %}
{% include 'bundles/datatables-js-bs5.html' %}
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
<script>
$(document).ready(() => {
$('#groupsTable').DataTable({
language: {url: '{{ DT_LANG_PATH }}'},
});
$('#groupsTable').DataTable();
});
</script>
{% endblock %}

View File

@@ -19,7 +19,7 @@
{% translate "Join Requests" %}
{% if acceptrequests %}
<span class="badge text-bg-secondary">{{ acceptrequests|length }}</span>
<span class="badge bg-secondary">{{ acceptrequests|length }}</span>
{% endif %}
</a>
</li>
@@ -30,7 +30,7 @@
{% translate "Leave Requests" %}
{% if leaverequests %}
<span class="badge text-bg-secondary">{{ leaverequests|length }}</span>
<span class="badge bg-secondary">{{ leaverequests|length }}</span>
{% endif %}
</a>
</li>

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class HRApplicationsConfig(AppConfig):
name = 'allianceauth.hrapplications'
label = 'hrapplications'
verbose_name = _('HR Applications')

View File

@@ -1,4 +1,3 @@
from typing import ClassVar
from django.contrib.auth.models import User
from django.db import models
from sortedm2m.fields import SortedManyToManyField
@@ -41,7 +40,7 @@ class Application(models.Model):
reviewer_character = models.ForeignKey(EveCharacter, on_delete=models.SET_NULL, blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
objects: ClassVar[ApplicationManager] = ApplicationManager()
objects = ApplicationManager()
def __str__(self):
return str(self.user) + " Application To " + str(self.form)

View File

@@ -43,11 +43,11 @@
<td class="text-center">{{ personal_app.form.corp.corporation_name }}</td>
<td class="text-center">
{% if personal_app.approved == None %}
<div class="badge text-bg-warning">{% translate "Pending" %}</div>
<div class="badge bg-warning">{% translate "Pending" %}</div>
{% elif personal_app.approved == True %}
<div class="badge text-bg-success">{% translate "Approved" %}</div>
<div class="badge bg-success">{% translate "Approved" %}</div>
{% else %}
<div class="badge text-bg-danger">{% translate "Rejected" %}</div>
<div class="badge bg-danger">{% translate "Rejected" %}</div>
{% endif %}
</td>
<td class="text-center">
@@ -133,14 +133,14 @@
<td class="text-center">
{% if app.approved == None %}
{% if app.reviewer_str %}
<div class="badge text-bg-info">{% translate "Reviewer:" %} {{ app.reviewer_str }}</div>
<div class="badge bg-info">{% translate "Reviewer:" %} {{ app.reviewer_str }}</div>
{% else %}
<div class="badge text-bg-warning">{% translate "Pending" %}</div>
<div class="badge bg-warning">{% translate "Pending" %}</div>
{% endif %}
{% elif app.approved == True %}
<div class="badge text-bg-success">{% translate "Approved" %}</div>
<div class="badge bg-success">{% translate "Approved" %}</div>
{% else %}
<div class="badge text-bg-danger">{% translate "Rejected" %}</div>
<div class="badge bg-danger">{% translate "Rejected" %}</div>
{% endif %}
</td>
<td class="text-center">
@@ -177,14 +177,14 @@
<td class="text-center">
{% if app.approved == None %}
{% if app.reviewer_str %}
<div class="badge text-bg-info">{% translate "Reviewer:" %} {{ app.reviewer_str }}</div>
<div class="badge bg-info">{% translate "Reviewer:" %} {{ app.reviewer_str }}</div>
{% else %}
<div class="badge text-bg-warning">{% translate "Pending" %}</div>
<div class="badge bg-warning">{% translate "Pending" %}</div>
{% endif %}
{% elif app.approved == True %}
<div class="badge text-bg-success">{% translate "Approved" %}</div>
<div class="badge bg-success">{% translate "Approved" %}</div>
{% else %}
<div class="badge text-bg-danger">{% translate "Rejected" %}</div>
<div class="badge bg-danger">{% translate "Rejected" %}</div>
{% endif %}
</td>
<td class="text-center">

View File

@@ -43,11 +43,11 @@
<td>{{ app.form.corp }}</td>
<td class="text-center">
{% if app.approved == None %}
<div class="badge text-bg-warning">{% translate "Pending" %}</div>
<div class="badge bg-warning">{% translate "Pending" %}</div>
{% elif app.approved == True %}
<div class="badge text-bg-success">{% translate "Approved" %}</div>
<div class="badge bg-success">{% translate "Approved" %}</div>
{% else %}
<div class="badge text-bg-danger">{% translate "Rejected" %}</div>
<div class="badge bg-danger">{% translate "Rejected" %}</div>
{% endif %}
</td>
<td class="text-end">

View File

@@ -31,7 +31,7 @@
</div>
<div class="card mb-3">
<div class="card-header text-bg-info">
<div class="card-header bg-info">
<div class="card-title mb-0">{% translate "Applicant" %}</div>
</div>
@@ -50,7 +50,7 @@
</div>
<div class="card mb-3">
<div class="card-header text-bg-info">
<div class="card-header bg-info">
<div class="card-title mb-0">{% translate "Characters" %}</div>
</div>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,6 @@
import logging
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
logger = logging.getLogger(__name__)
@@ -13,7 +12,6 @@ logger = logging.getLogger(__name__)
class MenuConfig(AppConfig):
name = "allianceauth.menu"
label = "menu"
verbose_name = _("Menu")
def ready(self):
from allianceauth.menu.core import smart_sync

View File

@@ -1,4 +1,3 @@
from typing import ClassVar
from django.db import models
from django.utils.translation import gettext_lazy as _
@@ -69,7 +68,7 @@ class MenuItem(models.Model):
help_text=_("External URL this menu items will link to"),
)
objects: ClassVar[MenuItemManager] = MenuItemManager()
objects = MenuItemManager()
def __str__(self) -> str:
return self.text

View File

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

View File

@@ -2,8 +2,8 @@
{% load navactive %}
{% load auth_notifications %}
<li class="nav-item" id="menu_item_notifications">
<a class="nav-link {% navactive request 'notifications:' %}" href="{% url 'notifications:list' %}">
<li class="nav-item {% navactive request 'notifications:' %}" id="menu_item_notifications">
<a class="nav-link" href="{% url 'notifications:list' %}">
{% with unread_count=request.user|user_unread_notification_count %}
<i class="fa-solid fa-bell{% if unread_count %} text-danger{% endif %}"></i>
{% endwith %}

View File

@@ -5,7 +5,7 @@
<div class="col-auto px-0">
<div class="collapse collapse-horizontal" tabindex="-1" id="sidebar">
<div>
<div class="nav-padding navbar-dark text-bg-dark px-0 d-flex flex-column overflow-hidden vh-100 {% if not user.is_authenticated %}position-relative{% endif %}">
<div class="nav-padding navbar-dark bg-dark text-light px-0 d-flex flex-column overflow-hidden vh-100 {% if not user.is_authenticated %}position-relative{% endif %}">
{% if user.is_authenticated %}
<ul id="sidebar-menu" class="navbar-nav flex-column mb-auto overflow-auto pt-2">
<li class="d-flex flex-wrap m-2 p-2 pt-0 pb-0 mt-0 mb-0 me-0 pe-0">

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class NotificationsConfig(AppConfig):
name = 'allianceauth.notifications'
label = 'notifications'
verbose_name = _('Notifications')

View File

@@ -1,5 +1,4 @@
import logging
from typing import ClassVar
from django.db import models
from django.contrib.auth.models import User
@@ -57,7 +56,7 @@ class Notification(models.Model):
timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
viewed = models.BooleanField(default=False, db_index=True)
objects: ClassVar[NotificationManager] = NotificationManager()
objects = NotificationManager()
def __str__(self) -> str:
return f"{self.user}: {self.title}"

View File

@@ -15,14 +15,14 @@
<li class="nav-item">
<a class="nav-link active" id="unread-tab" data-bs-toggle="tab" data-bs-target="#unread" type="button" role="tab" aria-controls="unread" aria-selected="true">
{% translate "Unread" %}
<span class="badge text-bg-secondary">{{ unread|length }}</span>
<span class="badge bg-secondary">{{ unread|length }}</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" id="read-tab" data-bs-toggle="tab" data-bs-target="#read" type="button" role="tab" aria-controls="read" aria-selected="false">
{% translate "Read" %}
<span class="badge text-bg-secondary">{{ read|length }}</span>
<span class="badge bg-secondary">{{ read|length }}</span>
</a>
</li>
{% endblock %}

View File

@@ -17,7 +17,7 @@
</div>
<div class="card border-{{ notif.level }}">
<div class="card-header text-bg-{{ notif.level }}">
<div class="card-header bg-{{ notif.level }}">
{{ notif.timestamp }}
{{ notif.title }}
</div>

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class OptimerConfig(AppConfig):
name = 'allianceauth.optimer'
label = 'optimer'
verbose_name = _('Fleet Operations')

View File

@@ -14,7 +14,7 @@
<th class="text-center">{% translate "Operation" %}</th>
<th class="text-center">{% translate "Type" %}</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>
</thead>

View File

@@ -24,8 +24,8 @@
{% block content %}
<div>
<div class="text-center mb-3">
<div class="badge text-bg-primary text-start">
<b>{% translate "Current EVE time:" %}</b>
<div class="badge bg-primary text-start">
<b>{% translate "Current Eve Time:" %}</b>
<span id="current-time"></span>
</div>
</div>
@@ -127,8 +127,8 @@
};
/**
* Get the current EVE time as a string
* @returns {string} EVE time string
* Get the current Eve time as a string
* @returns {string} Eve time string
*/
const updateClock = () => {
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class PermissionsToolConfig(AppConfig):
name = 'allianceauth.permissions_tool'
label = 'permissions_tool'
verbose_name = _('Permissions Audit')

View File

@@ -1,6 +1,5 @@
{% extends "allianceauth/base-bs5.html" %}
{% load aa_i18n %}
{% load i18n %}
{% block page_title %}
@@ -58,14 +57,11 @@
{% include "bundles/datatables-js-bs5.html" %}
{% include "bundles/filterdropdown-js.html" %}
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
<script>
$(document).ready(() => {
const groupColumn = 0;
$('#tab_permissions_audit').DataTable({
language: {url: '{{ DT_LANG_PATH }}'},
columnDefs: [{
"visible": false,
"targets": groupColumn

View File

@@ -1,6 +1,5 @@
{% extends "allianceauth/base-bs5.html" %}
{% load aa_i18n %}
{% load i18n %}
{% block page_title %}
@@ -63,14 +62,11 @@
{% include "bundles/datatables-js-bs5.html" %}
{% include "bundles/filterdropdown-js.html" %}
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
<script>
$(document).ready(() => {
const groupColumn = 0;
$('#tab_permissions_overview').DataTable({
language: {url: '{{ DT_LANG_PATH }}'},
columnDefs: [{
"visible": false,
"targets": groupColumn

View File

@@ -44,10 +44,8 @@ INSTALLED_APPS = [
'allianceauth.theme.materia',
"allianceauth.custom_css",
'allianceauth.crontab',
'sri',
]
SRI_ALGORITHM = "sha512"
SECRET_KEY = "wow I'm a really bad default secret key"
# Celery configuration
@@ -61,7 +59,6 @@ CELERYBEAT_SCHEDULE = {
'esi_cleanup_token': {
'task': 'esi.tasks.cleanup_token',
'schedule': crontab(minute='0', hour='0'),
'apply_offset': True,
},
'run_model_update': {
'task': 'allianceauth.eveonline.tasks.run_model_update',
@@ -118,46 +115,6 @@ LANGUAGES = ( # Sorted by Language Code alphabetical order + English at top
("zh-hans", _("Simplified Chinese")),
)
# Django's language codes are different from some of the libraries we use,
# 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 = {
# 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": {
"cs-cz": "cs",
"de": "de-DE",
"es": "es-ES",
"fr-fr": "fr-FR",
"it-it": "it-IT",
"ja": "ja",
"ko-kr": "ko",
"nl-nl": "nl-NL",
"pl-pl": "pl",
"ru": "ru",
"uk": "uk",
"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": {
"cs-cz": "cs",
"de": "de",
"es": "es",
"fr-fr": "fr",
"it-it": "it",
"ja": "ja",
"ko-kr": "ko",
"nl-nl": "nl",
"pl-pl": "pl",
"ru": "ru",
"uk": "uk",
"zh-hans": "zh-cn",
},
}
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',

View File

@@ -2,8 +2,8 @@
command={{ celery }} -A {{ project_name }} beat
directory={{ project_directory }}
user=allianceserver
stdout_logfile = {{ project_directory }}/log/%(program_name)s.log
stderr_logfile = {{ project_directory }}/log/%(program_name)s.log
stdout_logfile={{ project_directory }}/log/beat.log
stderr_logfile={{ project_directory }}/log/beat.log
autostart=true
autorestart=true
startsecs=10
@@ -15,8 +15,8 @@ directory = {{ project_directory }}
user=allianceserver
numprocs=1
process_name=%(program_name)s_%(process_num)02d
stdout_logfile = {{ project_directory }}/log/%(program_name)s.log
stderr_logfile = {{ project_directory }}/log/%(program_name)s.log
stdout_logfile={{ project_directory }}/log/worker.log
stderr_logfile={{ project_directory }}/log/worker.log
autostart=true
autorestart=true
startsecs=10
@@ -29,11 +29,12 @@ priority = 998
user = allianceserver
directory={{ project_directory }}
command={{ gunicorn }} {{ project_name }}.wsgi --workers=3 --timeout 120
stdout_logfile = {{ project_directory }}/log/%(program_name)s.log
stderr_logfile = {{ project_directory }}/log/%(program_name)s.log
stdout_logfile={{ project_directory }}/log/gunicorn.log
stderr_logfile={{ project_directory }}/log/gunicorn.log
autostart=true
autorestart=true
stopsignal=INT
{% endif %}
[eventlistener:memmon]

View File

@@ -1,11 +1,9 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class ServicesConfig(AppConfig):
name = 'allianceauth.services'
label = 'services'
verbose_name = _('Services')
def ready(self):
from . import signals

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class DiscordServiceConfig(AppConfig):
name = 'allianceauth.services.modules.discord'
label = 'discord'
verbose_name = _('Discord Service')

View File

@@ -1,5 +1,5 @@
import logging
from typing import ClassVar, Optional
from typing import Optional
from requests.exceptions import HTTPError
@@ -59,7 +59,7 @@ class DiscordUser(models.Model):
help_text='Date & time this service account was activated'
)
objects: ClassVar[DiscordUserManager] = DiscordUserManager()
objects = DiscordUserManager()
class Meta:
permissions = (

View File

@@ -439,7 +439,6 @@ class TestUserHasAccount(NoSocketsTestCase):
def test_return_false_if_user_does_not_exist(self):
my_user = User(username='Dummy')
my_user.save()
self.assertFalse(DiscordUser.objects.user_has_account(my_user))
def test_return_false_if_not_called_with_user_object(self):

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class DiscourseServiceConfig(AppConfig):
name = 'allianceauth.services.modules.discourse'
label = 'discourse'
verbose_name = _('Discourse Service')

View File

@@ -14,7 +14,7 @@
{% endblock %}
{% block active %}
<span class="badge text-bg-success">
<span class="badge bg-success">
{% translate "SSO login active" %}
</span>
{% endblock %}

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class ExampleServiceConfig(AppConfig):
name = 'allianceauth.services.modules.example'
label = 'example_service'
verbose_name = _('Example Service')

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class Ips4ServiceConfig(AppConfig):
name = 'allianceauth.services.modules.ips4'
label = 'ips4'
verbose_name = _('IPS4 Service')

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class MumbleServiceConfig(AppConfig):
name = 'allianceauth.services.modules.mumble'
label = 'mumble'
verbose_name = _('Mumble Service')

View File

@@ -1,6 +1,5 @@
import random
import string
from typing import ClassVar
from passlib.hash import bcrypt_sha256
from django.db import models
@@ -117,7 +116,7 @@ class MumbleUser(AbstractServiceModel):
help_text="Timestamp of the users Last Disconnection to Mumble"
)
objects: ClassVar[MumbleManager] = MumbleManager()
objects = MumbleManager()
def __str__(self):
return self.username

View File

@@ -1,6 +1,5 @@
{% extends "allianceauth/base-bs5.html" %}
{% load aa_i18n %}
{% load i18n %}
{% block page_title %}
@@ -8,7 +7,7 @@
{% endblock page_title %}
{% block header_nav_brand %}
{% trans "Mumble History" %} - {{ mumble_url }}
<a class="navbar-brand">{% trans "Mumble History" %} - {{ mumble_url }}</a>
{% endblock header_nav_brand %}
{% block header_nav_collapse_left %}
@@ -83,16 +82,13 @@
{% include "bundles/chart-js.html" %}
{% include "bundles/moment-js.html" with locale=True %}
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
<script>
$(document).ready(function () {
const MUMBLESTATS_DATETIME_FORMAT = 'LLL';
const MUMBLESTATS_DATETIME_FORMAT = 'YYYY-MM-DD, HH:mm';
'use strict';
$("#table-mumble-connection-history").DataTable({
language: {url: '{{ DT_LANG_PATH }}'},
ajax: {
url: '{% url "mumble:connection_history_data" %}',
dataSrc: 'connection_history_data',
@@ -104,33 +100,15 @@
{ data: 'version' },
{
data: 'last_connect',
render: {
_: (data) => {
return data === null
? ''
: moment(data)
.utc()
.format(MUMBLESTATS_DATETIME_FORMAT);
},
sort: (data) => {
return data === null ? '' : data;
}
render: (data) => {
return moment(data).utc().format(MUMBLESTATS_DATETIME_FORMAT);
},
className: 'text-end',
},
{
data: 'last_disconnect',
render: {
_: (data) => {
return data === null
? ''
: moment(data)
.utc()
.format(MUMBLESTATS_DATETIME_FORMAT);
},
sort: (data) => {
return data === null ? '' : data;
}
render: (data) => {
return moment(data).utc().format(MUMBLESTATS_DATETIME_FORMAT);
},
className: 'text-end',
},
@@ -154,7 +132,6 @@
});
$("#table-mumble-connection-stats").DataTable({
language: {url: '{{ DT_LANG_PATH }}'},
ajax: {
url: '{% url "mumble:release_counts_data" %}',
dataSrc: 'release_counts_data',

View File

@@ -48,7 +48,7 @@
</a>
{% endif %}
{% endif %}
{% if perms.mumble.view_connection_history %}
{% if request.user.is_superuser %}
<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
</a>

View File

@@ -1,8 +1,6 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class OpenfireServiceConfig(AppConfig):
name = 'allianceauth.services.modules.openfire'
label = 'openfire'
verbose_name = _('Openfire Service')

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