mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-13 18:46:25 +01:00
Compare commits
115 Commits
v4.0.0
...
63fb449060
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63fb449060 | ||
|
|
235675fa9b | ||
|
|
a065f043eb | ||
|
|
0839920032 | ||
|
|
29ad4acff7 | ||
|
|
3a5b84d1f9 | ||
|
|
bbcb94021e | ||
|
|
d50f13528b | ||
|
|
c88521af88 | ||
|
|
2bd5ff8723 | ||
|
|
84484cebcb | ||
|
|
5ee34fcb2d | ||
|
|
046473def1 | ||
|
|
6aaba2bf3d | ||
|
|
acff3695bc | ||
|
|
43ec8514aa | ||
|
|
4c629b193f | ||
|
|
c651da4011 | ||
|
|
da382cffd1 | ||
|
|
4ecfc3afd8 | ||
|
|
4eb7dbbe62 | ||
|
|
c96ba65296 | ||
|
|
ff2f60f7f3 | ||
|
|
3000545c98 | ||
|
|
f3ad092ef2 | ||
|
|
a012e7df2f | ||
|
|
1fa77412c0 | ||
|
|
e56caeb22b | ||
|
|
ceb07ebc67 | ||
|
|
237075d45c | ||
|
|
7099b1946d | ||
|
|
e416ab8ff2 | ||
|
|
2802ed03a5 | ||
|
|
4af73c76fe | ||
|
|
b6149979aa | ||
|
|
cb20288427 | ||
|
|
db6f4c91dc | ||
|
|
57ac7a5277 | ||
|
|
136438f9c2 | ||
|
|
e2be8b3440 | ||
|
|
04f3473ef3 | ||
|
|
255cb0da8d | ||
|
|
069352fb0f | ||
|
|
66e8ddb684 | ||
|
|
179c26975c | ||
|
|
e17f6e799b | ||
|
|
7cd8294104 | ||
|
|
ede5540335 | ||
|
|
747279b773 | ||
|
|
44f8b1c477 | ||
|
|
7c6ebd9bf6 | ||
|
|
430469b708 | ||
|
|
efbb3cee31 | ||
|
|
21094ed4dd | ||
|
|
5f326efc7e | ||
|
|
b6e34ace35 | ||
|
|
fe4a8965e3 | ||
|
|
23371c233d | ||
|
|
7a3bbf0d7f | ||
|
|
89a1bec9c1 | ||
|
|
1c1e70619a | ||
|
|
0ff4374efa | ||
|
|
18d0e58a48 | ||
|
|
84f44338dc | ||
|
|
2ba0412890 | ||
|
|
2326522b29 | ||
|
|
a7cb6ee434 | ||
|
|
2aeef63565 | ||
|
|
3c9e7335ef | ||
|
|
49067de325 | ||
|
|
471e7e29ae | ||
|
|
3ec5775406 | ||
|
|
e804d2b60d | ||
|
|
742438a95d | ||
|
|
5c60086baa | ||
|
|
e49041bb14 | ||
|
|
f3cbe91883 | ||
|
|
ea439a2176 | ||
|
|
56e1e76f11 | ||
|
|
634e7357be | ||
|
|
08dc88da1a | ||
|
|
3d206e445c | ||
|
|
64686cdad1 | ||
|
|
d7fe09bdf1 | ||
|
|
6da50da92f | ||
|
|
51e4dd986f | ||
|
|
bee6522182 | ||
|
|
1711a9dd33 | ||
|
|
3914626379 | ||
|
|
df276cb32d | ||
|
|
daad7d8b10 | ||
|
|
3bf5bc0fe3 | ||
|
|
96abae553a | ||
|
|
f9cbfb1562 | ||
|
|
8eaa94e179 | ||
|
|
4f876b648b | ||
|
|
cd738137c0 | ||
|
|
5605eb129d | ||
|
|
87ef0f21a3 | ||
|
|
a1c7ce827e | ||
|
|
97466bcdfb | ||
|
|
ff3096b106 | ||
|
|
98f0d77f3f | ||
|
|
92548ba402 | ||
|
|
c46741d311 | ||
|
|
7c7c1abf7c | ||
|
|
fc303b1b0a | ||
|
|
4e220a9679 | ||
|
|
b17b1f7504 | ||
|
|
7081fc0e76 | ||
|
|
68e4574f19 | ||
|
|
e6e0a70012 | ||
|
|
13e38da942 | ||
|
|
468c1de26b | ||
|
|
22ef5ac0e5 |
@@ -25,7 +25,7 @@ before_script:
|
|||||||
pre-commit-check:
|
pre-commit-check:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
stage: pre-commit
|
stage: pre-commit
|
||||||
image: python:3.11-bullseye
|
image: python:3.11-bookworm
|
||||||
# variables:
|
# variables:
|
||||||
# PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
|
# PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
|
||||||
# cache:
|
# cache:
|
||||||
@@ -51,33 +51,9 @@ secret_detection:
|
|||||||
stage: gitlab
|
stage: gitlab
|
||||||
before_script: []
|
before_script: []
|
||||||
|
|
||||||
test-3.8-core:
|
|
||||||
<<: *only-default
|
|
||||||
image: python:3.8-bullseye
|
|
||||||
script:
|
|
||||||
- tox -e py38-core
|
|
||||||
artifacts:
|
|
||||||
when: always
|
|
||||||
reports:
|
|
||||||
coverage_report:
|
|
||||||
coverage_format: cobertura
|
|
||||||
path: coverage.xml
|
|
||||||
|
|
||||||
test-3.9-core:
|
|
||||||
<<: *only-default
|
|
||||||
image: python:3.9-bullseye
|
|
||||||
script:
|
|
||||||
- tox -e py39-core
|
|
||||||
artifacts:
|
|
||||||
when: always
|
|
||||||
reports:
|
|
||||||
coverage_report:
|
|
||||||
coverage_format: cobertura
|
|
||||||
path: coverage.xml
|
|
||||||
|
|
||||||
test-3.10-core:
|
test-3.10-core:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
image: python:3.10-bullseye
|
image: python:3.10-bookworm
|
||||||
script:
|
script:
|
||||||
- tox -e py310-core
|
- tox -e py310-core
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -89,7 +65,7 @@ test-3.10-core:
|
|||||||
|
|
||||||
test-3.11-core:
|
test-3.11-core:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
image: python:3.11-bullseye
|
image: python:3.11-bookworm
|
||||||
script:
|
script:
|
||||||
- tox -e py311-core
|
- tox -e py311-core
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -101,7 +77,7 @@ test-3.11-core:
|
|||||||
|
|
||||||
test-3.12-core:
|
test-3.12-core:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
image: python:3.12-rc-bullseye
|
image: python:3.12-bookworm
|
||||||
script:
|
script:
|
||||||
- tox -e py312-core
|
- tox -e py312-core
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -111,33 +87,22 @@ test-3.12-core:
|
|||||||
coverage_format: cobertura
|
coverage_format: cobertura
|
||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
|
|
||||||
test-3.8-all:
|
test-3.13-core:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
image: python:3.8-bullseye
|
image: python:3.13-rc-bookworm
|
||||||
script:
|
script:
|
||||||
- tox -e py38-all
|
- tox -e py313-core
|
||||||
artifacts:
|
|
||||||
when: always
|
|
||||||
reports:
|
|
||||||
coverage_report:
|
|
||||||
coverage_format: cobertura
|
|
||||||
path: coverage.xml
|
|
||||||
|
|
||||||
test-3.9-all:
|
|
||||||
<<: *only-default
|
|
||||||
image: python:3.9-bullseye
|
|
||||||
script:
|
|
||||||
- tox -e py39-all
|
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
reports:
|
reports:
|
||||||
coverage_report:
|
coverage_report:
|
||||||
coverage_format: cobertura
|
coverage_format: cobertura
|
||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
test-3.10-all:
|
test-3.10-all:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
image: python:3.10-bullseye
|
image: python:3.10-bookworm
|
||||||
script:
|
script:
|
||||||
- tox -e py310-all
|
- tox -e py310-all
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -149,7 +114,7 @@ test-3.10-all:
|
|||||||
|
|
||||||
test-3.11-all:
|
test-3.11-all:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
image: python:3.11-bullseye
|
image: python:3.11-bookworm
|
||||||
script:
|
script:
|
||||||
- tox -e py311-all
|
- tox -e py311-all
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -162,7 +127,7 @@ test-3.11-all:
|
|||||||
|
|
||||||
test-3.12-all:
|
test-3.12-all:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
image: python:3.12-rc-bullseye
|
image: python:3.12-bookworm
|
||||||
script:
|
script:
|
||||||
- tox -e py312-all
|
- tox -e py312-all
|
||||||
artifacts:
|
artifacts:
|
||||||
@@ -172,9 +137,22 @@ test-3.12-all:
|
|||||||
coverage_format: cobertura
|
coverage_format: cobertura
|
||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
|
|
||||||
|
test-3.13-all:
|
||||||
|
<<: *only-default
|
||||||
|
image: python:3.13-rc-bookworm
|
||||||
|
script:
|
||||||
|
- tox -e py313-all
|
||||||
|
artifacts:
|
||||||
|
when: always
|
||||||
|
reports:
|
||||||
|
coverage_report:
|
||||||
|
coverage_format: cobertura
|
||||||
|
path: coverage.xml
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
build-test:
|
build-test:
|
||||||
stage: test
|
stage: test
|
||||||
image: python:3.11-bullseye
|
image: python:3.12-bookworm
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- python -m pip install --upgrade pip
|
- python -m pip install --upgrade pip
|
||||||
@@ -193,13 +171,13 @@ build-test:
|
|||||||
|
|
||||||
test-docs:
|
test-docs:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
image: python:3.11-bullseye
|
image: python:3.12-bookworm
|
||||||
script:
|
script:
|
||||||
- tox -e docs
|
- tox -e docs
|
||||||
|
|
||||||
deploy_production:
|
deploy_production:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
image: python:3.11-bullseye
|
image: python:3.12-bookworm
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- python -m pip install --upgrade pip
|
- python -m pip install --upgrade pip
|
||||||
@@ -215,10 +193,10 @@ deploy_production:
|
|||||||
|
|
||||||
build-image:
|
build-image:
|
||||||
before_script: []
|
before_script: []
|
||||||
image: docker:24.0
|
image: docker:27.0
|
||||||
stage: docker
|
stage: docker
|
||||||
services:
|
services:
|
||||||
- docker:24.0-dind
|
- docker:27-dind
|
||||||
script: |
|
script: |
|
||||||
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
||||||
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_COMMIT_SHORT_SHA
|
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_COMMIT_SHORT_SHA
|
||||||
@@ -239,10 +217,10 @@ build-image:
|
|||||||
|
|
||||||
build-image-dev:
|
build-image-dev:
|
||||||
before_script: []
|
before_script: []
|
||||||
image: docker:24.0
|
image: docker:27
|
||||||
stage: docker
|
stage: docker
|
||||||
services:
|
services:
|
||||||
- docker:24.0-dind
|
- docker:27-dind
|
||||||
script: |
|
script: |
|
||||||
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
||||||
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_COMMIT_BRANCH-$CI_COMMIT_SHORT_SHA
|
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_COMMIT_BRANCH-$CI_COMMIT_SHORT_SHA
|
||||||
@@ -260,10 +238,10 @@ build-image-dev:
|
|||||||
|
|
||||||
build-image-mr:
|
build-image-mr:
|
||||||
before_script: []
|
before_script: []
|
||||||
image: docker:24.0
|
image: docker:27
|
||||||
stage: docker
|
stage: docker
|
||||||
services:
|
services:
|
||||||
- docker:24.0-dind
|
- docker:27-dind
|
||||||
script: |
|
script: |
|
||||||
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
||||||
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME-$CI_COMMIT_SHORT_SHA
|
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME-$CI_COMMIT_SHORT_SHA
|
||||||
|
|||||||
@@ -4,8 +4,21 @@
|
|||||||
# pre-commit autoupdate
|
# pre-commit autoupdate
|
||||||
|
|
||||||
repos:
|
repos:
|
||||||
|
# Code Upgrades
|
||||||
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
|
rev: v3.15.2
|
||||||
|
hooks:
|
||||||
|
- id: pyupgrade
|
||||||
|
args: [--py310-plus]
|
||||||
|
- repo: https://github.com/adamchainz/django-upgrade
|
||||||
|
rev: 1.17.0
|
||||||
|
hooks:
|
||||||
|
- id: django-upgrade
|
||||||
|
args: [--target-version=4.2]
|
||||||
|
|
||||||
|
# Formatting
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.5.0
|
rev: v4.6.0
|
||||||
hooks:
|
hooks:
|
||||||
# Identify invalid files
|
# Identify invalid files
|
||||||
- id: check-ast
|
- id: check-ast
|
||||||
@@ -13,27 +26,24 @@ repos:
|
|||||||
- id: check-json
|
- id: check-json
|
||||||
- id: check-toml
|
- id: check-toml
|
||||||
- id: check-xml
|
- id: check-xml
|
||||||
|
|
||||||
# git checks
|
# git checks
|
||||||
- id: check-merge-conflict
|
- id: check-merge-conflict
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
args: [ --maxkb=1000 ]
|
args: [--maxkb=1000]
|
||||||
- id: detect-private-key
|
- id: detect-private-key
|
||||||
- id: check-case-conflict
|
- id: check-case-conflict
|
||||||
|
|
||||||
# Python checks
|
# Python checks
|
||||||
# - id: check-docstring-first
|
# - id: check-docstring-first
|
||||||
- id: debug-statements
|
- id: debug-statements
|
||||||
# - id: requirements-txt-fixer
|
# - id: requirements-txt-fixer
|
||||||
- id: fix-encoding-pragma
|
- id: fix-encoding-pragma
|
||||||
args: [ --remove ]
|
args: [--remove]
|
||||||
- id: fix-byte-order-marker
|
- id: fix-byte-order-marker
|
||||||
|
|
||||||
# General quality checks
|
# General quality checks
|
||||||
- id: mixed-line-ending
|
- id: mixed-line-ending
|
||||||
args: [ --fix=lf ]
|
args: [--fix=lf]
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
args: [ --markdown-linebreak-ext=md ]
|
args: [--markdown-linebreak-ext=md]
|
||||||
exclude: |
|
exclude: |
|
||||||
(?x)(
|
(?x)(
|
||||||
\.min\.css|
|
\.min\.css|
|
||||||
@@ -52,7 +62,6 @@ repos:
|
|||||||
\.mo|
|
\.mo|
|
||||||
swagger\.json
|
swagger\.json
|
||||||
)
|
)
|
||||||
|
|
||||||
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
|
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
|
||||||
rev: 2.7.3
|
rev: 2.7.3
|
||||||
hooks:
|
hooks:
|
||||||
@@ -65,21 +74,26 @@ repos:
|
|||||||
\.mo|
|
\.mo|
|
||||||
swagger\.json
|
swagger\.json
|
||||||
)
|
)
|
||||||
|
- repo: https://github.com/igorshubovych/markdownlint-cli
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
rev: v0.41.0
|
||||||
rev: v3.15.1
|
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: markdownlint
|
||||||
args: [ --py38-plus ]
|
args:
|
||||||
|
- --disable=MD013
|
||||||
- repo: https://github.com/adamchainz/django-upgrade
|
# Infrastructure
|
||||||
rev: 1.16.0
|
- repo: https://github.com/tox-dev/pyproject-fmt
|
||||||
|
rev: 2.1.3
|
||||||
hooks:
|
hooks:
|
||||||
- id: django-upgrade
|
- id: pyproject-fmt
|
||||||
args: [--target-version=4.2]
|
name: pyproject.toml formatter
|
||||||
|
description: "Format the pyproject.toml file."
|
||||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
args:
|
||||||
rev: v2.5.0
|
- --indent=4
|
||||||
|
additional_dependencies:
|
||||||
|
- tox==4.15.0 # https://github.com/tox-dev/tox/releases/latest
|
||||||
|
- repo: https://github.com/abravalheri/validate-pyproject
|
||||||
|
rev: v0.18
|
||||||
hooks:
|
hooks:
|
||||||
- id: setup-cfg-fmt
|
- id: validate-pyproject
|
||||||
args: [ --include-version-classifiers ]
|
name: Validate pyproject.toml
|
||||||
|
description: "Validate the pyproject.toml file."
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ version: 2
|
|||||||
|
|
||||||
# Set the version of Python and other tools you might need
|
# Set the version of Python and other tools you might need
|
||||||
build:
|
build:
|
||||||
os: ubuntu-22.04
|
os: ubuntu-24.04
|
||||||
apt_packages:
|
apt_packages:
|
||||||
- redis
|
- redis
|
||||||
tools:
|
tools:
|
||||||
python: "3.11"
|
python: "3.12"
|
||||||
jobs:
|
jobs:
|
||||||
post_system_dependencies:
|
post_system_dependencies:
|
||||||
- redis-server --daemonize yes
|
- redis-server --daemonize yes
|
||||||
|
|||||||
10
.tx/config
10
.tx/config
@@ -1,10 +0,0 @@
|
|||||||
[main]
|
|
||||||
host = https://app.transifex.com
|
|
||||||
lang_map = zh-Hans: zh_Hans
|
|
||||||
|
|
||||||
[o:alliance-auth:p:alliance-auth:r:django-po]
|
|
||||||
file_filter = allianceauth/locale/<lang>/LC_MESSAGES/django.po
|
|
||||||
source_file = allianceauth/locale/en/LC_MESSAGES/django.po
|
|
||||||
source_lang = en
|
|
||||||
type = PO
|
|
||||||
minimum_perc = 0
|
|
||||||
@@ -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.0.0'
|
__version__ = '4.2.2'
|
||||||
__title__ = 'Alliance Auth'
|
__title__ = 'Alliance Auth'
|
||||||
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
|
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
|
||||||
NAME = f'{__title__} v{__version__}'
|
NAME = f'{__title__} v{__version__}'
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ from .utils import (
|
|||||||
install_stat_tokens,
|
install_stat_tokens,
|
||||||
install_stat_users)
|
install_stat_users)
|
||||||
|
|
||||||
|
from allianceauth import __version__
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
BASE_URL = "https://www.google-analytics.com"
|
BASE_URL = "https://www.google-analytics.com"
|
||||||
@@ -99,11 +101,38 @@ def analytics_daily_stats():
|
|||||||
event_type='Stats')
|
event_type='Stats')
|
||||||
|
|
||||||
for appconfig in apps.get_app_configs():
|
for appconfig in apps.get_app_configs():
|
||||||
analytics_event(namespace='allianceauth.analytics',
|
if appconfig.label in [
|
||||||
task='send_extension_stats',
|
"django_celery_beat",
|
||||||
label=appconfig.label,
|
"bootstrapform",
|
||||||
value=1,
|
"messages",
|
||||||
event_type='Stats')
|
"sessions",
|
||||||
|
"auth",
|
||||||
|
"staticfiles",
|
||||||
|
"users",
|
||||||
|
"addons",
|
||||||
|
"admin",
|
||||||
|
"humanize",
|
||||||
|
"contenttypes",
|
||||||
|
"sortedm2m",
|
||||||
|
"django_bootstrap5",
|
||||||
|
"tokens",
|
||||||
|
"authentication",
|
||||||
|
"services",
|
||||||
|
"framework",
|
||||||
|
"notifications"
|
||||||
|
"eveonline",
|
||||||
|
"navhelper",
|
||||||
|
"analytics",
|
||||||
|
"menu",
|
||||||
|
"theme"
|
||||||
|
]:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
analytics_event(namespace='allianceauth.analytics',
|
||||||
|
task='send_extension_stats',
|
||||||
|
label=appconfig.label,
|
||||||
|
value=1,
|
||||||
|
event_type='Stats')
|
||||||
|
|
||||||
|
|
||||||
@shared_task()
|
@shared_task()
|
||||||
@@ -139,7 +168,7 @@ def send_ga_tracking_celery_event(
|
|||||||
'client_id': AnalyticsIdentifier.objects.get(id=1).identifier.hex,
|
'client_id': AnalyticsIdentifier.objects.get(id=1).identifier.hex,
|
||||||
"user_properties": {
|
"user_properties": {
|
||||||
"allianceauth_version": {
|
"allianceauth_version": {
|
||||||
"value": "allianceauth_version"
|
"value": __version__
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'non_personalized_ads': True,
|
'non_personalized_ads': True,
|
||||||
|
|||||||
@@ -5,26 +5,5 @@ from django.core.checks import Warning, Error, register
|
|||||||
class AllianceAuthConfig(AppConfig):
|
class AllianceAuthConfig(AppConfig):
|
||||||
name = 'allianceauth'
|
name = 'allianceauth'
|
||||||
|
|
||||||
|
def ready(self) -> None:
|
||||||
@register()
|
import allianceauth.checks # noqa
|
||||||
def check_settings(app_configs, **kwargs):
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
errors = []
|
|
||||||
if hasattr(settings, "SITE_URL"):
|
|
||||||
if settings.SITE_URL[-1] == "/":
|
|
||||||
errors.append(Warning(
|
|
||||||
"'SITE_URL' Has a trailing slash. This may lead to incorrect links being generated by Auth."))
|
|
||||||
else:
|
|
||||||
errors.append(Error(
|
|
||||||
"No 'SITE_URL' found is settings. This may lead to incorrect links being generated by Auth or Errors in 3rd party modules."))
|
|
||||||
if hasattr(settings, "CSRF_TRUSTED_ORIGINS"):
|
|
||||||
if hasattr(settings, "SITE_URL"):
|
|
||||||
if settings.SITE_URL not in settings.CSRF_TRUSTED_ORIGINS:
|
|
||||||
errors.append(Warning(
|
|
||||||
"'SITE_URL' not found in 'CSRF_TRUSTED_ORIGINS'. Auth may not load pages correctly until this is rectified."))
|
|
||||||
else:
|
|
||||||
errors.append(Error(
|
|
||||||
"No 'CSRF_TRUSTED_ORIGINS' found is settings, Auth may not load pages correctly until this is rectified"))
|
|
||||||
|
|
||||||
return errors
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from django.conf import settings
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def active_tasks_count() -> Optional[int]:
|
def active_tasks_count() -> int | None:
|
||||||
"""Return count of currently active tasks
|
"""Return count of currently active tasks
|
||||||
or None if celery workers are not online.
|
or None if celery workers are not online.
|
||||||
"""
|
"""
|
||||||
@@ -20,7 +20,7 @@ def active_tasks_count() -> Optional[int]:
|
|||||||
return _tasks_count(inspect.active())
|
return _tasks_count(inspect.active())
|
||||||
|
|
||||||
|
|
||||||
def _tasks_count(data: dict) -> Optional[int]:
|
def _tasks_count(data: dict) -> int | None:
|
||||||
"""Return count of tasks in data from celery inspect API."""
|
"""Return count of tasks in data from celery inspect API."""
|
||||||
try:
|
try:
|
||||||
tasks = itertools.chain(*data.values())
|
tasks = itertools.chain(*data.values())
|
||||||
@@ -29,7 +29,7 @@ def _tasks_count(data: dict) -> Optional[int]:
|
|||||||
return len(list(tasks))
|
return len(list(tasks))
|
||||||
|
|
||||||
|
|
||||||
def queued_tasks_count() -> Optional[int]:
|
def queued_tasks_count() -> int | None:
|
||||||
"""Return count of queued tasks. Return None if there was an error."""
|
"""Return count of queued tasks. Return None if there was an error."""
|
||||||
try:
|
try:
|
||||||
with current_app.connection_or_acquire() as conn:
|
with current_app.connection_or_acquire() as conn:
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ from django.urls import include
|
|||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import Callable, Iterable, Optional
|
from typing import Optional
|
||||||
|
from collections.abc import Callable, Iterable
|
||||||
|
|
||||||
from django.urls import include
|
from django.urls import include
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
@@ -17,7 +18,7 @@ def user_has_main_character(user):
|
|||||||
|
|
||||||
|
|
||||||
def decorate_url_patterns(
|
def decorate_url_patterns(
|
||||||
urls, decorator: Callable, excluded_views: Optional[Iterable] = None
|
urls, decorator: Callable, excluded_views: Iterable | None = None
|
||||||
):
|
):
|
||||||
"""Decorate views given in url patterns except when they are explicitly excluded.
|
"""Decorate views given in url patterns except when they are explicitly excluded.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.13 on 2024-05-12 09:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('authentication', '0022_userprofile_theme'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='userprofile',
|
||||||
|
name='language',
|
||||||
|
field=models.CharField(blank=True, choices=[('en', 'English'), ('de', 'German'), ('es', 'Spanish'), ('zh-hans', 'Chinese Simplified'), ('ru', 'Russian'), ('ko', 'Korean'), ('fr', 'French'), ('ja', 'Japanese'), ('it', 'Italian'), ('uk', 'Ukrainian'), ('pl', 'Polish')], default='', max_length=10, verbose_name='Language'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -78,6 +78,7 @@ class UserProfile(models.Model):
|
|||||||
JAPANESE = 'ja', _('Japanese')
|
JAPANESE = 'ja', _('Japanese')
|
||||||
ITALIAN = 'it', _('Italian')
|
ITALIAN = 'it', _('Italian')
|
||||||
UKRAINIAN = 'uk', _('Ukrainian')
|
UKRAINIAN = 'uk', _('Ukrainian')
|
||||||
|
POLISH = 'pl', _("Polish")
|
||||||
|
|
||||||
user = models.OneToOneField(
|
user = models.OneToOneField(
|
||||||
User,
|
User,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class _TaskCounts(NamedTuple):
|
|||||||
retried: int
|
retried: int
|
||||||
failed: int
|
failed: int
|
||||||
total: int
|
total: int
|
||||||
earliest_task: Optional[dt.datetime]
|
earliest_task: dt.datetime | None
|
||||||
hours: int
|
hours: int
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class EventSeries:
|
|||||||
|
|
||||||
_ROOT_KEY = "ALLIANCEAUTH_EVENT_SERIES"
|
_ROOT_KEY = "ALLIANCEAUTH_EVENT_SERIES"
|
||||||
|
|
||||||
def __init__(self, key_id: str, redis: Optional[Redis] = None) -> None:
|
def __init__(self, key_id: str, redis: Redis | None = None) -> None:
|
||||||
self._redis = get_redis_client_or_stub() if not redis else redis
|
self._redis = get_redis_client_or_stub() if not redis else redis
|
||||||
self._key_id = str(key_id)
|
self._key_id = str(key_id)
|
||||||
self.clear()
|
self.clear()
|
||||||
@@ -46,7 +46,7 @@ class EventSeries:
|
|||||||
my_id = self._redis.incr(self._key_counter)
|
my_id = self._redis.incr(self._key_counter)
|
||||||
self._redis.zadd(self._key_sorted_set, {my_id: event_time.timestamp()})
|
self._redis.zadd(self._key_sorted_set, {my_id: event_time.timestamp()})
|
||||||
|
|
||||||
def all(self) -> List[dt.datetime]:
|
def all(self) -> list[dt.datetime]:
|
||||||
"""List of all known events."""
|
"""List of all known events."""
|
||||||
return [
|
return [
|
||||||
event[1]
|
event[1]
|
||||||
@@ -75,7 +75,7 @@ class EventSeries:
|
|||||||
maximum = "+inf" if not latest else latest.timestamp()
|
maximum = "+inf" if not latest else latest.timestamp()
|
||||||
return self._redis.zcount(self._key_sorted_set, min=minimum, max=maximum)
|
return self._redis.zcount(self._key_sorted_set, min=minimum, max=maximum)
|
||||||
|
|
||||||
def first_event(self, earliest: dt.datetime = None) -> Optional[dt.datetime]:
|
def first_event(self, earliest: dt.datetime = None) -> dt.datetime | None:
|
||||||
"""Date/Time of first event. Returns `None` if series has no events.
|
"""Date/Time of first event. Returns `None` if series has no events.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
{% translate "Dashboard" %}
|
{% translate "Dashboard" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="d-flex justify-content-around align-self-center flex-wrap">
|
<div class="row">
|
||||||
{% for dash in views %}
|
{% for dash in views %}
|
||||||
{{ dash | safe }}
|
{{ dash | safe }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<div id="aa-dashboard-panel-characters" class="col-12 col-xl-8 align-self-stretch p-2 ps-0 pe-0 ps-xl-0 pe-xl-2">
|
<div id="aa-dashboard-panel-characters" class="col-12 col-xl-8 mb-3">
|
||||||
<div class="card">
|
<div class="card h-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex align-items-center">
|
{% translate "Characters" as widget_title %}
|
||||||
<h4 class="ms-auto me-auto">
|
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||||
{% translate "Characters" %}
|
|
||||||
</h4>
|
<div>
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div style="height: 300px; overflow-y:auto;">
|
<div style="height: 300px; overflow-y:auto;">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<a href="{% url 'authentication:add_character' %}" class="btn btn-primary flex-fill m-1" title="{% translate 'Add Character' %}">
|
<a href="{% url 'authentication:add_character' %}" class="btn btn-primary flex-fill m-1" title="{% translate 'Add Character' %}">
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<div id="aa-dashboard-panel-membership" class="col-12 col-xl-4 align-self-stretch py-2 ps-xl-2">
|
<div id="aa-dashboard-panel-membership" class="col-12 col-xl-4 mb-3">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title text-center">{% translate "Membership" %}</h4>
|
{% translate "Membership" as widget_title %}
|
||||||
<div class="card-body">
|
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||||
|
|
||||||
|
<div>
|
||||||
<div style="height: 300px; overflow-y:auto;">
|
<div style="height: 300px; overflow-y:auto;">
|
||||||
<h5 class="text-center">{% translate "State:" %} {{ request.user.profile.state }}</h5>
|
<h5 class="text-center">{% translate "State:" %} {{ request.user.profile.state }}</h5>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
|
|||||||
186
allianceauth/checks.py
Normal file
186
allianceauth/checks.py
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
from django import db
|
||||||
|
from django.core.checks import CheckMessage, Error, register, Warning
|
||||||
|
from allianceauth.utils.cache import get_redis_client
|
||||||
|
from django.utils import timezone
|
||||||
|
from packaging.version import InvalidVersion, Version as Pep440Version
|
||||||
|
from celery import current_app
|
||||||
|
from django.conf import settings
|
||||||
|
from sqlite3.dbapi2 import sqlite_version_info
|
||||||
|
import datetime
|
||||||
|
"""
|
||||||
|
A = System Packages
|
||||||
|
B = Configuration
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@register()
|
||||||
|
def django_settings(app_configs, **kwargs) -> list[CheckMessage]:
|
||||||
|
errors: list[CheckMessage] = []
|
||||||
|
if hasattr(settings, "SITE_URL"):
|
||||||
|
if settings.SITE_URL[-1] == "/":
|
||||||
|
errors.append(Warning("'SITE_URL' Has a trailing slash. This may lead to incorrect links being generated by Auth.", hint="", id="allianceauth.checks.B005"))
|
||||||
|
else:
|
||||||
|
errors.append(Error("No 'SITE_URL' found is settings. This may lead to incorrect links being generated by Auth or Errors in 3rd party modules.", hint="", id="allianceauth.checks.B006"))
|
||||||
|
|
||||||
|
if hasattr(settings, "CSRF_TRUSTED_ORIGINS") and hasattr(settings, "SITE_URL"):
|
||||||
|
if settings.SITE_URL not in settings.CSRF_TRUSTED_ORIGINS:
|
||||||
|
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("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]:
|
||||||
|
errors: list[CheckMessage] = []
|
||||||
|
try:
|
||||||
|
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=datetime.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(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(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(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]:
|
||||||
|
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))
|
||||||
|
except InvalidVersion:
|
||||||
|
errors.append(Warning("Unable to confirm MySQL Version"))
|
||||||
|
return errors
|
||||||
|
|
||||||
|
# MySQL 8
|
||||||
|
if mysql_version.major == 8 and mysql_version.minor == 4 and timezone.now() > timezone.datetime(year=2032, month=4, day=30, tzinfo=datetime.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=datetime.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]:
|
||||||
|
errors: list[CheckMessage] = []
|
||||||
|
|
||||||
|
for connection in db.connections.all():
|
||||||
|
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))
|
||||||
|
except InvalidVersion:
|
||||||
|
errors.append(Warning("Unable to confirm MariaDB Version"))
|
||||||
|
return errors
|
||||||
|
|
||||||
|
# MariaDB 11
|
||||||
|
if mariadb_version.major == 11 and mariadb_version.minor == 4 and timezone.now() > timezone.datetime(year=2029, month=5, day=19, tzinfo=datetime.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=datetime.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=datetime.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 and mariadb_version.minor == 11 and timezone.now() > timezone.datetime(year=2028, month=2, day=10, tzinfo=datetime.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=datetime.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=datetime.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]:
|
||||||
|
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))
|
||||||
|
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(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]:
|
||||||
|
errors: list[CheckMessage] = []
|
||||||
|
for connection in db.connections.all():
|
||||||
|
if connection.vendor == "mysql":
|
||||||
|
try:
|
||||||
|
if connection.settings_dict["OPTIONS"]["charset"] != "utf8mb4":
|
||||||
|
errors.append(Error(f"SQL Charset is not set to utf8mb4 DB:{connection.alias}", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
|
||||||
|
except KeyError:
|
||||||
|
errors.append(Error(f"SQL Charset is not set to utf8mb4 DB:{connection.alias}", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
|
||||||
|
|
||||||
|
# This hasn't actually been set on AA yet
|
||||||
|
# try:
|
||||||
|
# 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(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":
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
@register()
|
||||||
|
def celery_settings(app_configs, **kwargs) -> list[CheckMessage]:
|
||||||
|
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("Celery Priorities are not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc", id="allianceauth.checks.B003"))
|
||||||
|
except KeyError:
|
||||||
|
errors.append(Error("Celery Priorities are not set", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc", id="allianceauth.checks.B003"))
|
||||||
|
|
||||||
|
try:
|
||||||
|
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("Celery broker_connection_retry_on_startup not set", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280", id="allianceauth.checks.B004"))
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
# IDEAS
|
||||||
|
|
||||||
|
# Any other celery things weve manually changed over the years
|
||||||
|
# I'd be happy to add Community App checks, old versions the owners dont want to support etc.
|
||||||
|
|
||||||
|
|
||||||
|
# Check Default Collation on DB
|
||||||
|
# Check Charset Collation on all tables
|
||||||
@@ -235,7 +235,7 @@ class EveCharacter(models.Model):
|
|||||||
return self.corporation_id == DOOMHEIM_CORPORATION_ID
|
return self.corporation_id == DOOMHEIM_CORPORATION_ID
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def alliance(self) -> Union[EveAllianceInfo, None]:
|
def alliance(self) -> EveAllianceInfo | None:
|
||||||
"""
|
"""
|
||||||
Pseudo foreign key from alliance_id to EveAllianceInfo
|
Pseudo foreign key from alliance_id to EveAllianceInfo
|
||||||
:raises: EveAllianceInfo.DoesNotExist
|
:raises: EveAllianceInfo.DoesNotExist
|
||||||
@@ -255,7 +255,7 @@ class EveCharacter(models.Model):
|
|||||||
return EveCorporationInfo.objects.get(corporation_id=self.corporation_id)
|
return EveCorporationInfo.objects.get(corporation_id=self.corporation_id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def faction(self) -> Union[EveFactionInfo, None]:
|
def faction(self) -> EveFactionInfo | None:
|
||||||
"""
|
"""
|
||||||
Pseudo foreign key from faction_id to EveFactionInfo
|
Pseudo foreign key from faction_id to EveFactionInfo
|
||||||
:raises: EveFactionInfo.DoesNotExist
|
:raises: EveFactionInfo.DoesNotExist
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from allianceauth.framework.api.user import get_sentinel_user
|
|||||||
|
|
||||||
def get_main_character_from_evecharacter(
|
def get_main_character_from_evecharacter(
|
||||||
character: EveCharacter,
|
character: EveCharacter,
|
||||||
) -> Optional[EveCharacter]:
|
) -> EveCharacter | None:
|
||||||
"""
|
"""
|
||||||
Get the main character for a given EveCharacter or None when no main character is set
|
Get the main character for a given EveCharacter or None when no main character is set
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ def get_all_characters_from_user(user: User) -> list:
|
|||||||
return characters
|
return characters
|
||||||
|
|
||||||
|
|
||||||
def get_main_character_from_user(user: User) -> Optional[EveCharacter]:
|
def get_main_character_from_user(user: User) -> EveCharacter | None:
|
||||||
"""
|
"""
|
||||||
Get the main character from a user
|
Get the main character from a user
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{#Usage:#}
|
||||||
|
{# {% include "framework/dashboard/widget-title.html" with title="Foobar" %}#}
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<h4 class="ms-auto me-auto mb-3">
|
||||||
|
{{ title }}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
{% if subtitle %}
|
{% if subtitle %}
|
||||||
<br>
|
<br>
|
||||||
<small>{{ subtitle }}</small>
|
<small class="text-muted">{{ subtitle }}</small>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ class AuthGroup(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.group.name
|
return self.group.name
|
||||||
|
|
||||||
def group_request_approvers(self) -> Set[User]:
|
def group_request_approvers(self) -> set[User]:
|
||||||
"""Return all users who can approve a group request."""
|
"""Return all users who can approve a group request."""
|
||||||
return set(
|
return set(
|
||||||
self.group_leaders.all()
|
self.group_leaders.all()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from typing import Optional
|
|||||||
|
|
||||||
class ApplicationManager(models.Manager):
|
class ApplicationManager(models.Manager):
|
||||||
|
|
||||||
def pending_requests_count_for_user(self, user: User) -> Optional[int]:
|
def pending_requests_count_for_user(self, user: User) -> int | None:
|
||||||
"""Returns the number of pending group requests for the given user"""
|
"""Returns the number of pending group requests for the given user"""
|
||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
return self.filter(approved__isnull=True).count()
|
return self.filter(approved__isnull=True).count()
|
||||||
|
|||||||
BIN
allianceauth/locale/cs/LC_MESSAGES/django.mo
Normal file
BIN
allianceauth/locale/cs/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
2776
allianceauth/locale/cs/LC_MESSAGES/django.po
Normal file
2776
allianceauth/locale/cs/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-13 19:10+1000\n"
|
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
|
||||||
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
||||||
"Last-Translator: Peter Pfeufer, 2024\n"
|
"Last-Translator: Peter Pfeufer, 2024\n"
|
||||||
"Language-Team: German (https://app.transifex.com/alliance-auth/teams/107430/de/)\n"
|
"Language-Team: German (https://app.transifex.com/alliance-auth/teams/107430/de/)\n"
|
||||||
@@ -1449,6 +1449,8 @@ msgid "Sign Out"
|
|||||||
msgstr "Ausloggen"
|
msgstr "Ausloggen"
|
||||||
|
|
||||||
#: allianceauth/menu/templates/menu/menu-user.html:84
|
#: allianceauth/menu/templates/menu/menu-user.html:84
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
|
||||||
msgid "Sign In"
|
msgid "Sign In"
|
||||||
msgstr "Einloggen"
|
msgstr "Einloggen"
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-13 19:10+1000\n"
|
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -1385,6 +1385,8 @@ msgid "Sign Out"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/menu/templates/menu/menu-user.html:84
|
#: allianceauth/menu/templates/menu/menu-user.html:84
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
|
||||||
msgid "Sign In"
|
msgid "Sign In"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-13 19:10+1000\n"
|
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
|
||||||
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
||||||
"Last-Translator: trenus, 2023\n"
|
"Last-Translator: trenus, 2023\n"
|
||||||
"Language-Team: Spanish (https://app.transifex.com/alliance-auth/teams/107430/es/)\n"
|
"Language-Team: Spanish (https://app.transifex.com/alliance-auth/teams/107430/es/)\n"
|
||||||
@@ -1439,6 +1439,8 @@ msgid "Sign Out"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/menu/templates/menu/menu-user.html:84
|
#: allianceauth/menu/templates/menu/menu-user.html:84
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
|
||||||
msgid "Sign In"
|
msgid "Sign In"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# Mickael Gr4vity, 2023
|
# Mickael Gr4vity, 2023
|
||||||
# rockclodbuster, 2023
|
# rockclodbuster, 2023
|
||||||
@@ -12,15 +12,16 @@
|
|||||||
# draktanar KarazGrong <umbre@fallenstarscreations.com>, 2023
|
# draktanar KarazGrong <umbre@fallenstarscreations.com>, 2023
|
||||||
# Geoffrey Fabbro, 2023
|
# Geoffrey Fabbro, 2023
|
||||||
# Idea, 2024
|
# Idea, 2024
|
||||||
#
|
# Joel Falknau <ozirascal@gmail.com>, 2024
|
||||||
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-13 19:10+1000\n"
|
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
|
||||||
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
||||||
"Last-Translator: Idea, 2024\n"
|
"Last-Translator: Joel Falknau <ozirascal@gmail.com>, 2024\n"
|
||||||
"Language-Team: French (France) (https://app.transifex.com/alliance-auth/teams/107430/fr_FR/)\n"
|
"Language-Team: French (France) (https://app.transifex.com/alliance-auth/teams/107430/fr_FR/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@@ -1458,6 +1459,8 @@ msgid "Sign Out"
|
|||||||
msgstr "Se Déconnecter"
|
msgstr "Se Déconnecter"
|
||||||
|
|
||||||
#: allianceauth/menu/templates/menu/menu-user.html:84
|
#: allianceauth/menu/templates/menu/menu-user.html:84
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
|
||||||
msgid "Sign In"
|
msgid "Sign In"
|
||||||
msgstr "Se Connecter"
|
msgstr "Se Connecter"
|
||||||
|
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
# Translators:
|
# Translators:
|
||||||
# Alessandro Cresti, 2023
|
# Alessandro Cresti, 2023
|
||||||
# Linus Hope, 2023
|
# Linus Hope, 2023
|
||||||
# Thomas Turini, 2024
|
# Tuz, 2024
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-13 19:10+1000\n"
|
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
|
||||||
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
||||||
"Last-Translator: Thomas Turini, 2024\n"
|
"Last-Translator: Tuz, 2024\n"
|
||||||
"Language-Team: Italian (Italy) (https://app.transifex.com/alliance-auth/teams/107430/it_IT/)\n"
|
"Language-Team: Italian (Italy) (https://app.transifex.com/alliance-auth/teams/107430/it_IT/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@@ -1456,6 +1456,8 @@ msgid "Sign Out"
|
|||||||
msgstr "Sign Out"
|
msgstr "Sign Out"
|
||||||
|
|
||||||
#: allianceauth/menu/templates/menu/menu-user.html:84
|
#: allianceauth/menu/templates/menu/menu-user.html:84
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
|
||||||
msgid "Sign In"
|
msgid "Sign In"
|
||||||
msgstr "Sign In"
|
msgstr "Sign In"
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-13 19:10+1000\n"
|
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
|
||||||
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
||||||
"Last-Translator: kotaneko, 2024\n"
|
"Last-Translator: kotaneko, 2024\n"
|
||||||
"Language-Team: Japanese (https://app.transifex.com/alliance-auth/teams/107430/ja/)\n"
|
"Language-Team: Japanese (https://app.transifex.com/alliance-auth/teams/107430/ja/)\n"
|
||||||
@@ -1405,6 +1405,8 @@ msgid "Sign Out"
|
|||||||
msgstr "サインアウト"
|
msgstr "サインアウト"
|
||||||
|
|
||||||
#: allianceauth/menu/templates/menu/menu-user.html:84
|
#: allianceauth/menu/templates/menu/menu-user.html:84
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
|
||||||
msgid "Sign In"
|
msgid "Sign In"
|
||||||
msgstr "サインイン"
|
msgstr "サインイン"
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-13 19:10+1000\n"
|
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
|
||||||
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
||||||
"Last-Translator: Woojin Kang, 2024\n"
|
"Last-Translator: Woojin Kang, 2024\n"
|
||||||
"Language-Team: Korean (Korea) (https://app.transifex.com/alliance-auth/teams/107430/ko_KR/)\n"
|
"Language-Team: Korean (Korea) (https://app.transifex.com/alliance-auth/teams/107430/ko_KR/)\n"
|
||||||
@@ -1414,6 +1414,8 @@ msgid "Sign Out"
|
|||||||
msgstr "탈퇴"
|
msgstr "탈퇴"
|
||||||
|
|
||||||
#: allianceauth/menu/templates/menu/menu-user.html:84
|
#: allianceauth/menu/templates/menu/menu-user.html:84
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
|
||||||
msgid "Sign In"
|
msgid "Sign In"
|
||||||
msgstr "가입"
|
msgstr "가입"
|
||||||
|
|
||||||
|
|||||||
BIN
allianceauth/locale/nl/LC_MESSAGES/django.mo
Normal file
BIN
allianceauth/locale/nl/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
2789
allianceauth/locale/nl/LC_MESSAGES/django.po
Normal file
2789
allianceauth/locale/nl/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
BIN
allianceauth/locale/pl_PL/LC_MESSAGES/django.mo
Normal file
BIN
allianceauth/locale/pl_PL/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
2848
allianceauth/locale/pl_PL/LC_MESSAGES/django.po
Normal file
2848
allianceauth/locale/pl_PL/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,22 +2,23 @@
|
|||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# Андрей Зубков <and.vareba81@gmail.com>, 2023
|
# Андрей Зубков <and.vareba81@gmail.com>, 2023
|
||||||
# Yuriy K <thedjcooltv@gmail.com>, 2023
|
# Yuriy K <thedjcooltv@gmail.com>, 2023
|
||||||
# Alexander Gess <de.alex.gess@gmail.com>, 2023
|
# Alexander Gess <de.alex.gess@gmail.com>, 2023
|
||||||
# Filipp Chertiev <f@fzfx.ru>, 2023
|
# Filipp Chertiev <f@fzfx.ru>, 2023
|
||||||
# Ruslan Virchich, 2024
|
# Ruslan Virchich, 2024
|
||||||
#
|
# Joel Falknau <ozirascal@gmail.com>, 2024
|
||||||
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-13 19:10+1000\n"
|
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
|
||||||
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
||||||
"Last-Translator: Ruslan Virchich, 2024\n"
|
"Last-Translator: Joel Falknau <ozirascal@gmail.com>, 2024\n"
|
||||||
"Language-Team: Russian (https://app.transifex.com/alliance-auth/teams/107430/ru/)\n"
|
"Language-Team: Russian (https://app.transifex.com/alliance-auth/teams/107430/ru/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@@ -1435,6 +1436,8 @@ msgid "Sign Out"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/menu/templates/menu/menu-user.html:84
|
#: allianceauth/menu/templates/menu/menu-user.html:84
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
|
||||||
msgid "Sign In"
|
msgid "Sign In"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-13 19:10+1000\n"
|
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
|
||||||
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
||||||
"Last-Translator: Andrii Yukhymchak, 2024\n"
|
"Last-Translator: Andrii Yukhymchak, 2024\n"
|
||||||
"Language-Team: Ukrainian (https://app.transifex.com/alliance-auth/teams/107430/uk/)\n"
|
"Language-Team: Ukrainian (https://app.transifex.com/alliance-auth/teams/107430/uk/)\n"
|
||||||
@@ -1454,6 +1454,8 @@ msgid "Sign Out"
|
|||||||
msgstr "Вийти"
|
msgstr "Вийти"
|
||||||
|
|
||||||
#: allianceauth/menu/templates/menu/menu-user.html:84
|
#: allianceauth/menu/templates/menu/menu-user.html:84
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
|
||||||
msgid "Sign In"
|
msgid "Sign In"
|
||||||
msgstr "Увійти"
|
msgstr "Увійти"
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-13 19:10+1000\n"
|
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
|
||||||
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
|
||||||
"Last-Translator: Joel Falknau <ozirascal@gmail.com>, 2023\n"
|
"Last-Translator: Joel Falknau <ozirascal@gmail.com>, 2023\n"
|
||||||
"Language-Team: Chinese Simplified (https://app.transifex.com/alliance-auth/teams/107430/zh-Hans/)\n"
|
"Language-Team: Chinese Simplified (https://app.transifex.com/alliance-auth/teams/107430/zh-Hans/)\n"
|
||||||
@@ -1391,6 +1391,8 @@ msgid "Sign Out"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/menu/templates/menu/menu-user.html:84
|
#: allianceauth/menu/templates/menu/menu-user.html:84
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
|
||||||
msgid "Sign In"
|
msgid "Sign In"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ class MenuItemAdmin(admin.ModelAdmin):
|
|||||||
]
|
]
|
||||||
ordering = ["parent", "order", "text"]
|
ordering = ["parent", "order", "text"]
|
||||||
|
|
||||||
def get_form(self, request: HttpRequest, obj: Optional[MenuItem] = None, **kwargs):
|
def get_form(self, request: HttpRequest, obj: MenuItem | None = None, **kwargs):
|
||||||
kwargs["form"] = self._choose_form(request, obj)
|
kwargs["form"] = self._choose_form(request, obj)
|
||||||
return super().get_form(request, obj, **kwargs)
|
return super().get_form(request, obj, **kwargs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _choose_form(cls, request: HttpRequest, obj: Optional[MenuItem]):
|
def _choose_form(cls, request: HttpRequest, obj: MenuItem | None):
|
||||||
"""Return the form for the current menu item type."""
|
"""Return the form for the current menu item type."""
|
||||||
if obj: # change
|
if obj: # change
|
||||||
if obj.hook_hash:
|
if obj.hook_hash:
|
||||||
@@ -104,7 +104,7 @@ class MenuItemAdmin(admin.ModelAdmin):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _type_from_request(
|
def _type_from_request(
|
||||||
request: HttpRequest, default=None
|
request: HttpRequest, default=None
|
||||||
) -> Optional[MenuItemType]:
|
) -> MenuItemType | None:
|
||||||
try:
|
try:
|
||||||
return MenuItemType(request.GET.get("type"))
|
return MenuItemType(request.GET.get("type"))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ class MenuItemHookCustom(MenuItemHook):
|
|||||||
text: str,
|
text: str,
|
||||||
classes: str,
|
classes: str,
|
||||||
url_name: str,
|
url_name: str,
|
||||||
order: Optional[int] = None,
|
order: int | None = None,
|
||||||
navactive: Optional[List[str]] = None,
|
navactive: list[str] | None = None,
|
||||||
):
|
):
|
||||||
super().__init__(text, classes, url_name, order, navactive)
|
super().__init__(text, classes, url_name, order, navactive)
|
||||||
self.url = ""
|
self.url = ""
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ class MenuItemHook:
|
|||||||
text: str,
|
text: str,
|
||||||
classes: str,
|
classes: str,
|
||||||
url_name: str,
|
url_name: str,
|
||||||
order: Optional[int] = None,
|
order: int | None = None,
|
||||||
navactive: Optional[List[str]] = None,
|
navactive: list[str] | None = None,
|
||||||
):
|
):
|
||||||
self.text = text
|
self.text = text
|
||||||
self.classes = classes
|
self.classes = classes
|
||||||
|
|||||||
@@ -60,15 +60,17 @@
|
|||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="https://discord.gg/fjnHAmk" title="Alliance Auth Discord"><i class="fa-brands fa-discord fa-fw"></i> Alliance Auth Discord</a>
|
<a class="dropdown-item" href="https://discord.gg/fjnHAmk" title="Alliance Auth Discord"><i class="fa-brands fa-discord fa-fw"></i> Alliance Auth Discord</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="https://gitlab.com/allianceauth/allianceauth" title="Alliance Auth Git"><i class="fa-brands fa-gitlab fa-fw"></i> Alliance Auth Git</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="{% url 'admin:index' %}">
|
<a class="dropdown-item" href="https://gitlab.com/allianceauth/allianceauth" title="Alliance Auth Git"><i class="fa-brands fa-gitlab fa-fw"></i> Alliance Auth Git</a>
|
||||||
<i class="fa-solid fa-gear fa-fw"></i> {% translate "Admin" %}
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if user.is_staff %}
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" href="{% url 'admin:index' %}">
|
||||||
|
<i class="fa-solid fa-gear fa-fw"></i> {% translate "Admin" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
<li><hr class="dropdown-divider"></li>
|
<li><hr class="dropdown-divider"></li>
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ class RenderedMenuItem:
|
|||||||
|
|
||||||
menu_item: MenuItem
|
menu_item: MenuItem
|
||||||
|
|
||||||
children: List["RenderedMenuItem"] = field(default_factory=list)
|
children: list["RenderedMenuItem"] = field(default_factory=list)
|
||||||
count: Optional[int] = None
|
count: int | None = None
|
||||||
html: str = ""
|
html: str = ""
|
||||||
html_id: str = ""
|
html_id: str = ""
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ class RenderedMenuItem:
|
|||||||
self.html_id = hook_obj.html_id
|
self.html_id = hook_obj.html_id
|
||||||
|
|
||||||
|
|
||||||
def render_menu(request: HttpRequest) -> List[RenderedMenuItem]:
|
def render_menu(request: HttpRequest) -> list[RenderedMenuItem]:
|
||||||
"""Return the rendered side menu for including in a template.
|
"""Return the rendered side menu for including in a template.
|
||||||
|
|
||||||
This function is creating BS5 style menus.
|
This function is creating BS5 style menus.
|
||||||
@@ -88,7 +88,7 @@ def render_menu(request: HttpRequest) -> List[RenderedMenuItem]:
|
|||||||
# Menu items needs to be rendered with the new BS5 template
|
# Menu items needs to be rendered with the new BS5 template
|
||||||
bs5_template = "menu/menu-item-bs5.html"
|
bs5_template = "menu/menu-item-bs5.html"
|
||||||
|
|
||||||
rendered_items: Dict[int, RenderedMenuItem] = {}
|
rendered_items: dict[int, RenderedMenuItem] = {}
|
||||||
menu_items: QuerySet[MenuItem] = MenuItem.objects.order_by(
|
menu_items: QuerySet[MenuItem] = MenuItem.objects.order_by(
|
||||||
"parent", "order", "text"
|
"parent", "order", "text"
|
||||||
)
|
)
|
||||||
@@ -131,7 +131,7 @@ def render_menu(request: HttpRequest) -> List[RenderedMenuItem]:
|
|||||||
return list(rendered_items.values())
|
return list(rendered_items.values())
|
||||||
|
|
||||||
|
|
||||||
def _gather_menu_items_from_hooks() -> Dict[str, MenuItemHook]:
|
def _gather_menu_items_from_hooks() -> dict[str, MenuItemHook]:
|
||||||
hook_items = {}
|
hook_items = {}
|
||||||
for hook in get_hooks("menu_item_hook"):
|
for hook in get_hooks("menu_item_hook"):
|
||||||
f = hook()
|
f = hook()
|
||||||
@@ -161,14 +161,14 @@ def _render_link_item(
|
|||||||
|
|
||||||
|
|
||||||
def _render_folder_items(
|
def _render_folder_items(
|
||||||
request: HttpRequest, rendered_items: Dict[int, RenderedMenuItem], new_template: str
|
request: HttpRequest, rendered_items: dict[int, RenderedMenuItem], new_template: str
|
||||||
):
|
):
|
||||||
for item in rendered_items.values():
|
for item in rendered_items.values():
|
||||||
if item.menu_item.is_folder:
|
if item.menu_item.is_folder:
|
||||||
item.update_html(request=request, template=new_template)
|
item.update_html(request=request, template=new_template)
|
||||||
|
|
||||||
|
|
||||||
def _remove_empty_folders(rendered_items: Dict[int, RenderedMenuItem]):
|
def _remove_empty_folders(rendered_items: dict[int, RenderedMenuItem]):
|
||||||
ids_to_remove = []
|
ids_to_remove = []
|
||||||
for item_id, item in rendered_items.items():
|
for item_id, item in rendered_items.items():
|
||||||
if item.is_folder and not item.children:
|
if item.is_folder and not item.children:
|
||||||
|
|||||||
@@ -347,9 +347,9 @@ class TestRenderedMenuItem(TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class _ParsedMenuItem(NamedTuple):
|
class _ParsedMenuItem(NamedTuple):
|
||||||
classes: List[str]
|
classes: list[str]
|
||||||
text: str
|
text: str
|
||||||
count: Optional[int]
|
count: int | None
|
||||||
|
|
||||||
|
|
||||||
def parse_html(obj: RenderedMenuItem) -> _ParsedMenuItem:
|
def parse_html(obj: RenderedMenuItem) -> _ParsedMenuItem:
|
||||||
|
|||||||
@@ -1,41 +1,40 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load evelinks %}
|
{% load evelinks %}
|
||||||
|
|
||||||
<div class="col-12 align-self-stretch py-2">
|
<div class="col-12 mb-3">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title text-center">{% translate "Upcoming Fleets" %}</h4>
|
{% translate "Upcoming Fleets" as widget_title %}
|
||||||
|
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||||
|
|
||||||
<div class="card-body">
|
<div>
|
||||||
<div>
|
<table class="table">
|
||||||
<table class="table">
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
|
<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>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{% for ops in timers %}
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center">{% translate "Operation" %}</th>
|
<td class="text-center">
|
||||||
<th class="text-center">{% translate "Type" %}</th>
|
{{ ops.operation_name }}
|
||||||
<th class="text-center">{% translate "Form Up System" %}</th>
|
</td>
|
||||||
<th class="text-center">{% translate "EVE Time" %}</th>
|
<td class="text-center">
|
||||||
|
{{ ops.type }}
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<a href="{{ ops.system|dotlan_solar_system_url }}">{{ ops.system }}</a>
|
||||||
|
</td>
|
||||||
|
<td class="text-center" nowrap>{{ ops.start | date:"Y-m-d H:i" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
<tbody>
|
</table>
|
||||||
{% for ops in timers %}
|
|
||||||
<tr>
|
|
||||||
<td class="text-center">
|
|
||||||
{{ ops.operation_name }}
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
|
||||||
{{ ops.type }}
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<a href="{{ ops.system|dotlan_solar_system_url }}">{{ ops.system }}</a>
|
|
||||||
</td>
|
|
||||||
<td class="text-center" nowrap>{{ ops.start | date:"Y-m-d H:i" }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ LANGUAGES = (
|
|||||||
("ja", "Japanese"),
|
("ja", "Japanese"),
|
||||||
("it", "Italian"),
|
("it", "Italian"),
|
||||||
("uk", "Ukrainian"),
|
("uk", "Ukrainian"),
|
||||||
|
("pl", "Polish"),
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from string import Formatter
|
from string import Formatter
|
||||||
from django.urls import include, re_path
|
from django.urls import include, re_path
|
||||||
from typing import Iterable, Optional
|
from typing import Optional
|
||||||
|
from collections.abc import Iterable
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
@@ -175,7 +176,7 @@ class UrlHook:
|
|||||||
urls,
|
urls,
|
||||||
namespace: str,
|
namespace: str,
|
||||||
base_url: str,
|
base_url: str,
|
||||||
excluded_views : Optional[Iterable[str]] = None
|
excluded_views : Iterable[str] | None = None
|
||||||
):
|
):
|
||||||
self.include_pattern = re_path(base_url, include(urls, namespace=namespace))
|
self.include_pattern = re_path(base_url, include(urls, namespace=namespace))
|
||||||
self.excluded_views = set(excluded_views or [])
|
self.excluded_views = set(excluded_views or [])
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ from .models import DiscordUser # noqa
|
|||||||
__all__ = ["create_bot_client", "group_to_role", "server_name", "DiscordUser", "Role"]
|
__all__ = ["create_bot_client", "group_to_role", "server_name", "DiscordUser", "Role"]
|
||||||
|
|
||||||
|
|
||||||
def discord_guild_id() -> Optional[int]:
|
def discord_guild_id() -> int | None:
|
||||||
"""Guild ID of configured Discord server.
|
"""Guild ID of configured Discord server.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ def calculate_roles_for_user(
|
|||||||
client: DiscordClient,
|
client: DiscordClient,
|
||||||
discord_uid: int,
|
discord_uid: int,
|
||||||
state_name: str = None,
|
state_name: str = None,
|
||||||
) -> Tuple[RolesSet, Optional[bool]]:
|
) -> tuple[RolesSet, bool | None]:
|
||||||
"""Calculate current Discord roles for an Auth user.
|
"""Calculate current Discord roles for an Auth user.
|
||||||
|
|
||||||
Takes into account reserved groups and existing managed roles (e.g. nitro).
|
Takes into account reserved groups and existing managed roles (e.g. nitro).
|
||||||
@@ -68,7 +68,7 @@ def calculate_roles_for_user(
|
|||||||
return roles_calculated.union(roles_persistent), True
|
return roles_calculated.union(roles_persistent), True
|
||||||
|
|
||||||
|
|
||||||
def _user_group_names(user: User, state_name: str = None) -> List[str]:
|
def _user_group_names(user: User, state_name: str = None) -> list[str]:
|
||||||
"""Names of groups and state the given user is a member of."""
|
"""Names of groups and state the given user is a member of."""
|
||||||
if not state_name:
|
if not state_name:
|
||||||
state_name = user.profile.state.name
|
state_name = user.profile.state.name
|
||||||
@@ -77,7 +77,7 @@ def _user_group_names(user: User, state_name: str = None) -> List[str]:
|
|||||||
return group_names
|
return group_names
|
||||||
|
|
||||||
|
|
||||||
def user_formatted_nick(user: User) -> Optional[str]:
|
def user_formatted_nick(user: User) -> str | None:
|
||||||
"""Name of the given user's main character with name formatting applied.
|
"""Name of the given user's main character with name formatting applied.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -90,7 +90,7 @@ def user_formatted_nick(user: User) -> Optional[str]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def group_to_role(group: Group) -> Optional[Role]:
|
def group_to_role(group: Group) -> Role | None:
|
||||||
"""Fetch the Discord role matching the given Django group by name.
|
"""Fetch the Discord role matching the given Django group by name.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ from enum import IntEnum
|
|||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from typing import Iterable, List, Optional, Set, Tuple
|
from typing import List, Optional, Set, Tuple
|
||||||
|
from collections.abc import Iterable
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
from uuid import uuid1
|
from uuid import uuid1
|
||||||
|
|
||||||
@@ -233,7 +234,7 @@ class DiscordClient:
|
|||||||
|
|
||||||
# guild roles
|
# guild roles
|
||||||
|
|
||||||
def guild_roles(self, guild_id: int, use_cache: bool = True) -> Set[Role]:
|
def guild_roles(self, guild_id: int, use_cache: bool = True) -> set[Role]:
|
||||||
"""Fetch all roles for this guild.
|
"""Fetch all roles for this guild.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -268,7 +269,7 @@ class DiscordClient:
|
|||||||
|
|
||||||
def create_guild_role(
|
def create_guild_role(
|
||||||
self, guild_id: int, role_name: str, **kwargs
|
self, guild_id: int, role_name: str, **kwargs
|
||||||
) -> Optional[Role]:
|
) -> Role | None:
|
||||||
"""Create a new guild role with the given name.
|
"""Create a new guild role with the given name.
|
||||||
|
|
||||||
See official documentation for additional optional parameters.
|
See official documentation for additional optional parameters.
|
||||||
@@ -318,7 +319,7 @@ class DiscordClient:
|
|||||||
gen_key = cls._generate_hash(f'{guild_id}')
|
gen_key = cls._generate_hash(f'{guild_id}')
|
||||||
return f'{cls._KEYPREFIX_GUILD_ROLES}__{gen_key}'
|
return f'{cls._KEYPREFIX_GUILD_ROLES}__{gen_key}'
|
||||||
|
|
||||||
def match_role_from_name(self, guild_id: int, role_name: str) -> Optional[Role]:
|
def match_role_from_name(self, guild_id: int, role_name: str) -> Role | None:
|
||||||
"""Fetch Discord role matching the given name (cached).
|
"""Fetch Discord role matching the given name (cached).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -333,7 +334,7 @@ class DiscordClient:
|
|||||||
|
|
||||||
def match_or_create_roles_from_names(
|
def match_or_create_roles_from_names(
|
||||||
self, guild_id: int, role_names: Iterable[str]
|
self, guild_id: int, role_names: Iterable[str]
|
||||||
) -> List[Tuple[Role, bool]]:
|
) -> list[tuple[Role, bool]]:
|
||||||
"""Fetch or create Discord roles matching the given names (cached).
|
"""Fetch or create Discord roles matching the given names (cached).
|
||||||
|
|
||||||
Will try to match with existing roles names
|
Will try to match with existing roles names
|
||||||
@@ -361,7 +362,7 @@ class DiscordClient:
|
|||||||
|
|
||||||
def match_or_create_role_from_name(
|
def match_or_create_role_from_name(
|
||||||
self, guild_id: int, role_name: str, guild_roles: RolesSet = None
|
self, guild_id: int, role_name: str, guild_roles: RolesSet = None
|
||||||
) -> Tuple[Role, bool]:
|
) -> tuple[Role, bool]:
|
||||||
"""Fetch or create Discord role matching the given name.
|
"""Fetch or create Discord role matching the given name.
|
||||||
|
|
||||||
Will try to match with existing roles names
|
Will try to match with existing roles names
|
||||||
@@ -418,7 +419,7 @@ class DiscordClient:
|
|||||||
access_token: str,
|
access_token: str,
|
||||||
role_ids: list = None,
|
role_ids: list = None,
|
||||||
nick: str = None
|
nick: str = None
|
||||||
) -> Optional[bool]:
|
) -> bool | None:
|
||||||
"""Adds a user to the guild.
|
"""Adds a user to the guild.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -442,7 +443,7 @@ class DiscordClient:
|
|||||||
return None
|
return None
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def guild_member(self, guild_id: int, user_id: int) -> Optional[GuildMember]:
|
def guild_member(self, guild_id: int, user_id: int) -> GuildMember | None:
|
||||||
"""Fetch info for a guild member.
|
"""Fetch info for a guild member.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -461,8 +462,8 @@ class DiscordClient:
|
|||||||
return GuildMember.from_dict(r.json())
|
return GuildMember.from_dict(r.json())
|
||||||
|
|
||||||
def modify_guild_member(
|
def modify_guild_member(
|
||||||
self, guild_id: int, user_id: int, role_ids: List[int] = None, nick: str = None
|
self, guild_id: int, user_id: int, role_ids: list[int] = None, nick: str = None
|
||||||
) -> Optional[bool]:
|
) -> bool | None:
|
||||||
"""Set properties of a guild member.
|
"""Set properties of a guild member.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -501,7 +502,7 @@ class DiscordClient:
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def remove_guild_member(self, guild_id: int, user_id: int) -> Optional[bool]:
|
def remove_guild_member(self, guild_id: int, user_id: int) -> bool | None:
|
||||||
"""Remove a member from a guild.
|
"""Remove a member from a guild.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -529,7 +530,7 @@ class DiscordClient:
|
|||||||
|
|
||||||
def add_guild_member_role(
|
def add_guild_member_role(
|
||||||
self, guild_id: int, user_id: int, role_id: int
|
self, guild_id: int, user_id: int, role_id: int
|
||||||
) -> Optional[bool]:
|
) -> bool | None:
|
||||||
"""Adds a role to a guild member
|
"""Adds a role to a guild member
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -549,7 +550,7 @@ class DiscordClient:
|
|||||||
|
|
||||||
def remove_guild_member_role(
|
def remove_guild_member_role(
|
||||||
self, guild_id: int, user_id: int, role_id: int
|
self, guild_id: int, user_id: int, role_id: int
|
||||||
) -> Optional[bool]:
|
) -> bool | None:
|
||||||
"""Remove a role to a guild member
|
"""Remove a role to a guild member
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -572,7 +573,7 @@ class DiscordClient:
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def guild_member_roles(self, guild_id: int, user_id: int) -> Optional[RolesSet]:
|
def guild_member_roles(self, guild_id: int, user_id: int) -> RolesSet | None:
|
||||||
"""Fetch the current guild roles of a guild member.
|
"""Fetch the current guild roles of a guild member.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -821,6 +822,6 @@ class DiscordClient:
|
|||||||
return md5(key.encode('utf-8')).hexdigest()
|
return md5(key.encode('utf-8')).hexdigest()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _sanitize_role_ids(role_ids: Iterable[int]) -> List[int]:
|
def _sanitize_role_ids(role_ids: Iterable[int]) -> list[int]:
|
||||||
"""Sanitize a list of role IDs, i.e. make sure its a list of unique integers."""
|
"""Sanitize a list of role IDs, i.e. make sure its a list of unique integers."""
|
||||||
return [int(role_id) for role_id in set(role_ids)]
|
return [int(role_id) for role_id in set(role_ids)]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from typing import Iterable, List, Optional, Set, Tuple
|
from typing import List, Optional, Set, Tuple
|
||||||
|
from collections.abc import Iterable
|
||||||
|
|
||||||
from .models import Role
|
from .models import Role
|
||||||
|
|
||||||
@@ -50,7 +51,7 @@ class RolesSet:
|
|||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self._roles.keys())
|
return len(self._roles.keys())
|
||||||
|
|
||||||
def has_roles(self, role_ids: Set[int]) -> bool:
|
def has_roles(self, role_ids: set[int]) -> bool:
|
||||||
"""True if this objects contains all roles defined by given role_ids
|
"""True if this objects contains all roles defined by given role_ids
|
||||||
incl. managed roles.
|
incl. managed roles.
|
||||||
"""
|
"""
|
||||||
@@ -58,7 +59,7 @@ class RolesSet:
|
|||||||
all_role_ids = self._roles.keys()
|
all_role_ids = self._roles.keys()
|
||||||
return role_ids.issubset(all_role_ids)
|
return role_ids.issubset(all_role_ids)
|
||||||
|
|
||||||
def ids(self) -> Set[int]:
|
def ids(self) -> set[int]:
|
||||||
"""Set of all role IDs."""
|
"""Set of all role IDs."""
|
||||||
return set(self._roles.keys())
|
return set(self._roles.keys())
|
||||||
|
|
||||||
@@ -114,7 +115,7 @@ class RolesSet:
|
|||||||
new_ids = self.ids().difference(other.ids())
|
new_ids = self.ids().difference(other.ids())
|
||||||
return self.subset(role_ids=new_ids)
|
return self.subset(role_ids=new_ids)
|
||||||
|
|
||||||
def role_by_name(self, role_name: str) -> Optional[Role]:
|
def role_by_name(self, role_name: str) -> Role | None:
|
||||||
"""Role if one with matching name is found else None."""
|
"""Role if one with matching name is found else None."""
|
||||||
role_name = Role.sanitize_name(role_name)
|
role_name = Role.sanitize_name(role_name)
|
||||||
if role_name in self._roles_by_name:
|
if role_name in self._roles_by_name:
|
||||||
@@ -123,7 +124,7 @@ class RolesSet:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_from_matched_roles(
|
def create_from_matched_roles(
|
||||||
cls, matched_roles: List[Tuple[Role, bool]]
|
cls, matched_roles: list[tuple[Role, bool]]
|
||||||
) -> "RolesSet":
|
) -> "RolesSet":
|
||||||
"""Create new instance from the given list of matches roles.
|
"""Create new instance from the given list of matches roles.
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class Guild:
|
|||||||
|
|
||||||
id: int
|
id: int
|
||||||
name: str
|
name: str
|
||||||
roles: FrozenSet[Role]
|
roles: frozenset[Role]
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
object.__setattr__(self, "id", int(self.id))
|
object.__setattr__(self, "id", int(self.id))
|
||||||
@@ -95,7 +95,7 @@ class GuildMember:
|
|||||||
|
|
||||||
_NICK_MAX_CHARS = 32
|
_NICK_MAX_CHARS = 32
|
||||||
|
|
||||||
roles: FrozenSet[int]
|
roles: frozenset[int]
|
||||||
nick: str = None
|
nick: str = None
|
||||||
user: User = None
|
user: User = None
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class DiscordUser(models.Model):
|
|||||||
logger.warning('Failed to update nickname for %s', self.user)
|
logger.warning('Failed to update nickname for %s', self.user)
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def update_groups(self, state_name: str = None) -> Optional[bool]:
|
def update_groups(self, state_name: str = None) -> bool | None:
|
||||||
"""update groups for a user based on his current group memberships.
|
"""update groups for a user based on his current group memberships.
|
||||||
Will add or remove roles of a user as needed.
|
Will add or remove roles of a user as needed.
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ class DiscordUser(models.Model):
|
|||||||
logger.info('No need to update roles for user %s', self.user)
|
logger.info('No need to update roles for user %s', self.user)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def update_username(self) -> Optional[bool]:
|
def update_username(self) -> bool | None:
|
||||||
"""Updates the username incl. the discriminator
|
"""Updates the username incl. the discriminator
|
||||||
from the Discord server and saves it
|
from the Discord server and saves it
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ class DiscordUser(models.Model):
|
|||||||
notify_user: bool = False,
|
notify_user: bool = False,
|
||||||
is_rate_limited: bool = True,
|
is_rate_limited: bool = True,
|
||||||
handle_api_exceptions: bool = False
|
handle_api_exceptions: bool = False
|
||||||
) -> Optional[bool]:
|
) -> bool | None:
|
||||||
"""Deletes the Discount user both on the server and locally
|
"""Deletes the Discount user both on the server and locally
|
||||||
|
|
||||||
Params:
|
Params:
|
||||||
|
|||||||
@@ -438,7 +438,7 @@ class TestUserHasAccount(NoSocketsTestCase):
|
|||||||
self.assertFalse(DiscordUser.objects.user_has_account(self.user))
|
self.assertFalse(DiscordUser.objects.user_has_account(self.user))
|
||||||
|
|
||||||
def test_return_false_if_user_does_not_exist(self):
|
def test_return_false_if_user_does_not_exist(self):
|
||||||
my_user = User(username='Dummy')
|
my_user = AuthUtils.create_user("test_return_false_if_user_does_not_exist")
|
||||||
self.assertFalse(DiscordUser.objects.user_has_account(my_user))
|
self.assertFalse(DiscordUser.objects.user_has_account(my_user))
|
||||||
|
|
||||||
def test_return_false_if_not_called_with_user_object(self):
|
def test_return_false_if_not_called_with_user_object(self):
|
||||||
|
|||||||
@@ -7,7 +7,9 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block url %}
|
{% block url %}
|
||||||
<a href="{{ service_url }}">{{ service_url }}</a>
|
{% if username != '' %}
|
||||||
|
<a href="mumble://{{ connect_url }}">{{ service_url }}</a>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block user %}
|
{% block user %}
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ class SmfManager:
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_user(cls, username, email_address, groups, main_character: EveCharacter) -> Tuple:
|
def add_user(cls, username, email_address, groups, main_character: EveCharacter) -> tuple:
|
||||||
"""
|
"""
|
||||||
Add a user to SMF
|
Add a user to SMF
|
||||||
:param username:
|
:param username:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<div id="esi-alert" class="col-12 align-self-stretch py-2 collapse">
|
<div id="esi-alert" class="col-12 collapse">
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
<p class="text-center ">{% translate 'Your Server received an ESI error response code of ' %}<b id="esi-code">?</b></p>
|
<p class="text-center ">{% translate 'Your Server received an ESI error response code of ' %}<b id="esi-code">?</b></p>
|
||||||
<hr>
|
<hr>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
console.log("ESI Check: ", JSON.stringify(responseJson, null, 2));
|
console.log("ESI Check: ", JSON.stringify(responseJson, null, 2));
|
||||||
|
|
||||||
const status = responseJson.status;
|
const status = responseJson.status;
|
||||||
if (status != 200) {
|
if (status !== 200) {
|
||||||
elemCode.textContent = status
|
elemCode.textContent = status
|
||||||
elemMessage.textContent = responseJson.data.error;
|
elemMessage.textContent = responseJson.data.error;
|
||||||
new bootstrap.Collapse(elemCard, {
|
new bootstrap.Collapse(elemCard, {
|
||||||
|
|||||||
@@ -2,48 +2,43 @@
|
|||||||
{% load humanize %}
|
{% load humanize %}
|
||||||
|
|
||||||
{% if notifications %}
|
{% if notifications %}
|
||||||
<div id="aa-dashboard-panel-admin-notifications" class="col-12 align-self-stretch pb-2">
|
<div id="aa-dashboard-panel-admin-notifications" class="col-12 mb-3">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex align-items-center">
|
{% translate "Alliance Auth Notifications" as widget_title %}
|
||||||
<div class="w-100 align-self-stretch">
|
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||||
<h4 class="ms-auto me-auto text-center">
|
|
||||||
{% translate "Alliance Auth Notifications" %}
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
<div class="card-body">
|
<div>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
{% for notif in notifications %}
|
{% for notif in notifications %}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
{% if notif.state == 'opened' %}
|
{% if notif.state == 'opened' %}
|
||||||
<span class="badge bg-success">{% translate "Open" %}</span>
|
<span class="badge bg-success me-2">{% translate "Open" %}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="badge bg-danger">{% translate "Closed" %}</span>
|
<span class="badge bg-danger me-2">{% translate "Closed" %}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a>
|
<a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<div class="alert alert-primary" role="alert">
|
<div class="alert alert-primary" role="alert">
|
||||||
{% translate "No notifications at this time" %}
|
{% translate "No notifications at this time" %}
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="text-end">
|
|
||||||
<a href="https://gitlab.com/allianceauth/allianceauth/issues" target="_blank" class="me-1">
|
|
||||||
<span class="badge" style="background-color: rgb(230 83 40);">
|
|
||||||
<i class="fab fa-gitlab" aria-hidden="true"></i>
|
|
||||||
{% translate 'Powered by GitLab' %}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<a href="https://discord.com/invite/fjnHAmk" target="_blank">
|
|
||||||
<span class="badge" style="background-color: rgb(110 133 211);">
|
|
||||||
<i class="fab fa-discord" aria-hidden="true"></i>
|
|
||||||
{% translate 'Support Discord' %}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="text-end pt-3">
|
||||||
|
<a href="https://gitlab.com/allianceauth/allianceauth/issues" target="_blank" class="me-1 text-decoration-none">
|
||||||
|
<span class="badge" style="background-color: rgb(230 83 40);">
|
||||||
|
<i class="fab fa-gitlab" aria-hidden="true"></i>
|
||||||
|
{% translate 'Powered by GitLab' %}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a href="https://discord.com/invite/fjnHAmk" target="_blank" class="text-decoration-none">
|
||||||
|
<span class="badge" style="background-color: rgb(110 133 211);">
|
||||||
|
<i class="fab fa-discord" aria-hidden="true"></i>
|
||||||
|
{% translate 'Support Discord' %}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -51,15 +46,14 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="col-12 align-self-stretch pb-2">
|
<div class="col-12 mb-3">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body d-flex flex-row flex-wrap">
|
<div class="card-body row">
|
||||||
<div id="aa-dashboard-panel-software-version" class="col-xl-6 col-lg-12 col-md-12 col-sm-12">
|
<div id="aa-dashboard-panel-software-version" class="col-xl-6 col-lg-12 col-md-12 col-sm-12">
|
||||||
<h4 class="ms-auto me-auto text-center">
|
{% translate "Software Version" as widget_title %}
|
||||||
{% translate "Software Version" %}
|
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||||
</h4>
|
|
||||||
|
|
||||||
<div class="card-body">
|
<div>
|
||||||
<ul class="list-group list-group-horizontal w-100" role="group" aria-label="{% translate 'Software Version' %}">
|
<ul class="list-group list-group-horizontal w-100" role="group" aria-label="{% translate 'Software Version' %}">
|
||||||
<li class="list-group-item w-100">
|
<li class="list-group-item w-100">
|
||||||
<div class="btn h-100 w-100 cursor-default">
|
<div class="btn h-100 w-100 cursor-default">
|
||||||
@@ -98,11 +92,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="aa-dashboard-panel-task-queue" class="col-xl-6 col-lg-12 col-md-12 col-sm-12">
|
<div id="aa-dashboard-panel-task-queue" class="col-xl-6 col-lg-12 col-md-12 col-sm-12">
|
||||||
<h4 class="ms-auto me-auto text-center">
|
{% translate "Task Queue" as widget_title %}
|
||||||
{% translate "Task Queue" %}
|
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||||
</h4>
|
|
||||||
|
|
||||||
<div class="card-body">
|
<div>
|
||||||
<p>
|
<p>
|
||||||
{% blocktranslate with total=tasks_total|intcomma latest=earliest_task|timesince|default:"?" %}
|
{% blocktranslate with total=tasks_total|intcomma latest=earliest_task|timesince|default:"?" %}
|
||||||
Status of {{ total }} processed tasks • last {{ latest }}
|
Status of {{ total }} processed tasks • last {{ latest }}
|
||||||
|
|||||||
@@ -29,56 +29,53 @@
|
|||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
.nav-padding {
|
||||||
.nav-padding {
|
padding-top: {% header_padding_size %} !important;
|
||||||
padding-top: {% header_padding_size %} !important;
|
}
|
||||||
}
|
|
||||||
{% endif %}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
{% block extra_css %}{% endblock extra_css %}
|
{% block extra_css %}{% endblock extra_css %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
{% if user.is_authenticated %}
|
<!-- Top Menu, Blocks don't work in "include" tagged views -->
|
||||||
<!-- Top Menu, Blocks don't work in "include" tagged views -->
|
<nav class="navbar navbar-expand-lg navbar-dark fixed-top bg-primary">
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark fixed-top bg-primary">
|
<div class="container-fluid justify-content-start">
|
||||||
<div class="container-fluid justify-content-start">
|
<a class="navbar-brand" data-bs-toggle="collapse" data-bs-target="#sidebar" role="button">
|
||||||
{% if user.is_authenticated %}
|
<i class="fa-solid fa-bars ms-2 me-2"></i>
|
||||||
<a class="navbar-brand" data-bs-toggle="collapse" data-bs-target="#sidebar" role="button">
|
</a>
|
||||||
<i class="fa-solid fa-bars ms-2 me-2"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="navbar-brand">
|
<div class="navbar-brand">
|
||||||
{% block header_nav_brand %}{{ SITE_NAME }}{% endblock %}
|
{% block header_nav_brand %}{{ SITE_NAME }}{% endblock %}
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="collapse navbar-collapse ms-2 px-2" id="navbarexpand">
|
|
||||||
<ul id="nav-left" class="nav navbar-nav me-auto">
|
|
||||||
{% block header_nav_collapse_left %}
|
|
||||||
{% endblock %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul id="nav-right" class="nav navbar-nav">
|
|
||||||
{% block header_nav_collapse_right %}
|
|
||||||
{% endblock %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul id="nav-right-character-control" class="nav navbar-nav">
|
|
||||||
{% block header_nav_user_character_control %} <!-- Default to add char and swap main -->
|
|
||||||
{% include 'allianceauth/top-menu-rh-default.html' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% include 'menu/menu-notification-block.html' %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a class="navbar-toggler navbar-brand border-0 collapsed" data-bs-toggle="collapse" data-bs-target="#navbarexpand" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation" style="margin-left: auto;">
|
|
||||||
<i class="fa-solid fa-chevron-up"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
|
||||||
{% endif %}
|
<div class="collapse navbar-collapse ms-2 px-2" id="navbarexpand">
|
||||||
|
<ul id="nav-left" class="nav navbar-nav me-auto">
|
||||||
|
{% block header_nav_collapse_left %}
|
||||||
|
{% endblock %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul id="nav-right" class="nav navbar-nav">
|
||||||
|
{% block header_nav_collapse_right %}
|
||||||
|
{% endblock %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul id="nav-right-character-control" class="nav navbar-nav">
|
||||||
|
{% block header_nav_user_character_control %} <!-- Default to add char and swap main -->
|
||||||
|
{% include 'allianceauth/top-menu-rh-default.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
{% include 'menu/menu-notification-block.html' %}
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="navbar-toggler navbar-brand border-0 collapsed" data-bs-toggle="collapse" data-bs-target="#navbarexpand" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation" style="margin-left: auto;">
|
||||||
|
<i class="fa-solid fa-chevron-up"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
<!-- End Top Menu -->
|
<!-- End Top Menu -->
|
||||||
|
|
||||||
<!-- Body -->
|
<!-- Body -->
|
||||||
|
|||||||
@@ -1,31 +1,37 @@
|
|||||||
{% extends "allianceauth/base-bs5.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
|
{% load theme_tags %}
|
||||||
|
|
||||||
{% block page_title %}
|
{% block page_title %}
|
||||||
{{ error_title }}
|
{{ error_title }}
|
||||||
{% endblock page_title %}
|
{% endblock page_title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div>
|
<div class="d-flex flex-column" style="height: calc(100vh - {% header_padding_size %}); margin-top: -1rem; margin-bottom: -1rem;">
|
||||||
{% include "framework/header/page-header.html" with title=error_title %}
|
<div class="d-flex flex-grow-1 justify-content-center align-items-center">
|
||||||
|
<div>
|
||||||
|
{% include "framework/header/page-header.html" with title=error_title %}
|
||||||
|
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="150"
|
width="150"
|
||||||
height="150"
|
height="150"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
class="bi bi-exclamation-triangle"
|
class="bi bi-exclamation-triangle"
|
||||||
viewBox="0 0 16 16"
|
viewBox="0 0 16 16"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.146.146 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.163.163 0 0 1-.054.06.116.116 0 0 1-.066.017H1.146a.115.115 0 0 1-.066-.017.163.163 0 0 1-.054-.06.176.176 0 0 1 .002-.183L7.884 2.073a.147.147 0 0 1 .054-.057zm1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566z"
|
d="M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.146.146 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.163.163 0 0 1-.054.06.116.116 0 0 1-.066.017H1.146a.115.115 0 0 1-.066-.017.163.163 0 0 1-.054-.06.176.176 0 0 1 .002-.183L7.884 2.073a.147.147 0 0 1 .054-.057zm1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566z"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995z"
|
d="M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-center">{{ error_message }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-center">{{ error_message }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% if user.is_authenticated %}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="{% url 'authentication:add_character' %}" class="nav-link" title="{% translate 'Add Character' %}">
|
<a href="{% url 'authentication:add_character' %}" class="nav-link" title="{% translate 'Add Character' %}">
|
||||||
<i class="fa-solid fa-plus"></i>
|
<i class="fa-solid fa-plus"></i>
|
||||||
@@ -12,3 +12,10 @@
|
|||||||
<span class="d-lg-none d-md-inline m-2">{% translate "Change Main" %}</span>
|
<span class="d-lg-none d-md-inline m-2">{% translate "Change Main" %}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="{% url 'authentication:login' %}" class="nav-link" title="{% translate 'Sign In' %}">
|
||||||
|
<i class="fa-solid fa-right-to-bracket fa-fw "></i> {% translate "Sign In" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ class AuthUtils:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_permissions_to_user_by_name(
|
def add_permissions_to_user_by_name(
|
||||||
cls, perms: List[str], user: User, disconnect_signals: bool = True
|
cls, perms: list[str], user: User, disconnect_signals: bool = True
|
||||||
) -> User:
|
) -> User:
|
||||||
"""Add permissions given by name to a user
|
"""Add permissions given by name to a user
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ class ThemeHook:
|
|||||||
def __init__(self,
|
def __init__(self,
|
||||||
name: str,
|
name: str,
|
||||||
description: str,
|
description: str,
|
||||||
css: List[dict],
|
css: list[dict],
|
||||||
js: List[dict],
|
js: list[dict],
|
||||||
css_template: Optional[str] = None,
|
css_template: str | None = None,
|
||||||
js_template: Optional[str] = None,
|
js_template: str | None = None,
|
||||||
html_tags: Optional[str] = "",
|
html_tags: str | None = "",
|
||||||
header_padding: Optional[str] = "4em"):
|
header_padding: str | None = "4em"):
|
||||||
"""
|
"""
|
||||||
:param name: Theme python name
|
:param name: Theme python name
|
||||||
:type name: str
|
:type name: str
|
||||||
|
|||||||
@@ -1,59 +1,59 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load evelinks %}
|
{% load evelinks %}
|
||||||
|
|
||||||
<div class="col-12 align-self-stretch py-2">
|
<div class="col-12 mb-3">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title text-center">{% translate "Upcoming Timers" %}</h4>
|
{% translate "Upcoming Timers" as widget_title %}
|
||||||
<div class="card-body">
|
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||||
<div>
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="text-center">{% translate "Details" %}</th>
|
|
||||||
<th class="text-center">{% translate "Timer" %}</th>
|
|
||||||
<th class="text-center">{% translate "Type" %}</th>
|
|
||||||
<th class="text-center">{% translate "System" %}</th>
|
|
||||||
<th class="text-center">{% translate "EVE Time" %}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
<div>
|
||||||
{% for timer in timers %}
|
<table class="table">
|
||||||
<tr>
|
<thead>
|
||||||
<td class="text-center">
|
<tr>
|
||||||
{{ timer.details }}
|
<th class="text-center">{% translate "Details" %}</th>
|
||||||
</td>
|
<th class="text-center">{% translate "Timer" %}</th>
|
||||||
<td class="text-center">
|
<th class="text-center">{% translate "Type" %}</th>
|
||||||
{{ timer.get_timer_type_display }}
|
<th class="text-center">{% translate "System" %}</th>
|
||||||
</td>
|
<th class="text-center">{% translate "EVE Time" %}</th>
|
||||||
<td class="text-center" nowrap>
|
</tr>
|
||||||
{% if timer.objective == "Hostile" %}
|
</thead>
|
||||||
<div class="badge bg-danger">
|
|
||||||
{% translate "Hostile" %}
|
<tbody>
|
||||||
</div>
|
{% for timer in timers %}
|
||||||
{% endif %}
|
<tr>
|
||||||
{% if timer.objective == "Friendly" %}
|
<td class="text-center">
|
||||||
<div class="badge bg-primary">
|
{{ timer.details }}
|
||||||
{% translate "Friendly" %}
|
</td>
|
||||||
</div>
|
<td class="text-center">
|
||||||
{% endif %}
|
{{ timer.get_timer_type_display }}
|
||||||
{% if timer.objective == "Neutral" %}
|
</td>
|
||||||
<div class="badge bg-default">
|
<td class="text-center" nowrap>
|
||||||
{% translate "Neutral" %}
|
{% if timer.objective == "Hostile" %}
|
||||||
</div>
|
<div class="badge bg-danger">
|
||||||
{% endif %}
|
{% translate "Hostile" %}
|
||||||
</td>
|
</div>
|
||||||
<td class="text-center"><a href="{{ timer.system|dotlan_solar_system_url }}">
|
{% endif %}
|
||||||
{{ timer.system }} {{ timer.planet_moon }}
|
{% if timer.objective == "Friendly" %}
|
||||||
</a>
|
<div class="badge bg-primary">
|
||||||
</td>
|
{% translate "Friendly" %}
|
||||||
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
|
</div>
|
||||||
</tr>
|
{% endif %}
|
||||||
{% endfor %}
|
{% if timer.objective == "Neutral" %}
|
||||||
</tbody>
|
<div class="badge bg-default">
|
||||||
</table>
|
{% translate "Neutral" %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="text-center"><a href="{{ timer.system|dotlan_solar_system_url }}">
|
||||||
|
{{ timer.system }} {{ timer.planet_moon }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,9 +19,9 @@
|
|||||||
|
|
||||||
{% for timer in timers %}
|
{% for timer in timers %}
|
||||||
{% if timer.important == True %}
|
{% if timer.important == True %}
|
||||||
<tr class="danger">
|
<tr class="bg-danger bg-opacity-25">
|
||||||
{% else %}
|
{% else %}
|
||||||
<tr class="info">
|
<tr class="bg-info bg-opacity-25">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<td style="width: 150px;" class="text-center">
|
<td style="width: 150px;" class="text-center">
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class EditTimerView(TimerManagementView, AddUpdateMixin, UpdateView):
|
|||||||
|
|
||||||
|
|
||||||
class RemoveTimerView(TimerManagementView, DeleteView):
|
class RemoveTimerView(TimerManagementView, DeleteView):
|
||||||
form_class = TimerForm
|
pass
|
||||||
|
|
||||||
|
|
||||||
def dashboard_timers(request):
|
def dashboard_timers(request):
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from typing import List, Iterable, Callable
|
from typing import List
|
||||||
|
from collections.abc import Iterable, Callable
|
||||||
|
|
||||||
from django.urls import include
|
from django.urls import include
|
||||||
import esi.urls
|
import esi.urls
|
||||||
@@ -24,8 +25,8 @@ admin.site.site_header = NAME
|
|||||||
|
|
||||||
|
|
||||||
def urls_from_apps(
|
def urls_from_apps(
|
||||||
apps_hook_functions: Iterable[Callable], public_views_allowed: List[str]
|
apps_hook_functions: Iterable[Callable], public_views_allowed: list[str]
|
||||||
) -> List[URLPattern]:
|
) -> list[URLPattern]:
|
||||||
"""Return urls from apps and add default decorators."""
|
"""Return urls from apps and add default decorators."""
|
||||||
|
|
||||||
url_patterns = []
|
url_patterns = []
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class ItemCounter:
|
|||||||
DEFAULT_CACHE_TIMEOUT = 24 * 3600
|
DEFAULT_CACHE_TIMEOUT = 24 * 3600
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, name: str, minimum: Optional[int] = None, redis: Optional[Redis] = None
|
self, name: str, minimum: int | None = None, redis: Redis | None = None
|
||||||
) -> None:
|
) -> None:
|
||||||
if not name:
|
if not name:
|
||||||
raise ValueError("Must define a name")
|
raise ValueError("Must define a name")
|
||||||
@@ -60,6 +60,6 @@ class ItemCounter:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def value(self) -> Optional[int]:
|
def value(self) -> int | None:
|
||||||
"""Return current value or None if not yet initialized."""
|
"""Return current value or None if not yet initialized."""
|
||||||
return cache.get(self._cache_key)
|
return cache.get(self._cache_key)
|
||||||
|
|||||||
@@ -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.0.0
|
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v4.2.2
|
||||||
|
|
||||||
# Nginx Proxy Manager
|
# Nginx Proxy Manager
|
||||||
PROXY_HTTP_PORT=80
|
PROXY_HTTP_PORT=80
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
ARG AUTH_VERSION=v4.0.0
|
ARG AUTH_VERSION=v4.2.2
|
||||||
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
|
||||||
@@ -9,21 +9,21 @@ ENV AUTH_HOME=/home/allianceauth
|
|||||||
|
|
||||||
# Setup user and directory permissions
|
# Setup user and directory permissions
|
||||||
SHELL ["/bin/bash", "-c"]
|
SHELL ["/bin/bash", "-c"]
|
||||||
RUN groupadd -g 61000 ${AUTH_GROUP}
|
RUN groupadd -g 61000 ${AUTH_GROUP} && \
|
||||||
RUN useradd -g 61000 -l -M -s /bin/false -u 61000 ${AUTH_USER}
|
useradd -g 61000 -l -m -s /bin/false -u 61000 ${AUTH_USER}
|
||||||
RUN mkdir -p ${STATIC_BASE} \
|
|
||||||
&& chown ${AUTH_USERGROUP} ${STATIC_BASE} \
|
|
||||||
&& mkdir -p ${AUTH_HOME} \
|
|
||||||
&& chown ${AUTH_USERGROUP} ${AUTH_HOME}
|
|
||||||
|
|
||||||
# Install build dependencies
|
RUN mkdir -p ${STATIC_BASE}/myauth/static \
|
||||||
RUN apt-get update && apt-get upgrade -y && apt-get install -y \
|
&& chown ${AUTH_USERGROUP} ${STATIC_BASE}/myauth/static
|
||||||
libmariadb-dev gcc git pkg-config
|
|
||||||
|
|
||||||
# Install python dependencies
|
# Install Build Dependencies
|
||||||
RUN pip install --upgrade pip
|
RUN apt-get update \
|
||||||
RUN pip install wheel gunicorn
|
&& apt-get upgrade -y \
|
||||||
RUN pip install ${AUTH_PACKAGE}
|
&& apt-get install -y --no-install-recommends libmariadb-dev gcc git pkg-config \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install AA and Dependencies
|
||||||
|
RUN pip install --no-cache-dir ${AUTH_PACKAGE} gunicorn
|
||||||
|
|
||||||
# Switch to non-root user
|
# Switch to non-root user
|
||||||
USER ${AUTH_USER}
|
USER ${AUTH_USER}
|
||||||
@@ -33,7 +33,6 @@ WORKDIR ${AUTH_HOME}
|
|||||||
RUN allianceauth start myauth
|
RUN allianceauth start myauth
|
||||||
COPY /allianceauth/project_template/project_name/settings/local.py ${AUTH_HOME}/myauth/myauth/settings/local.py
|
COPY /allianceauth/project_template/project_name/settings/local.py ${AUTH_HOME}/myauth/myauth/settings/local.py
|
||||||
RUN allianceauth update myauth
|
RUN allianceauth update myauth
|
||||||
RUN mkdir -p ${STATIC_BASE}/myauth/static
|
|
||||||
|
|
||||||
RUN echo 'alias auth="python $AUTH_HOME/myauth/manage.py"' >> ~/.bashrc && \
|
RUN echo 'alias auth="python $AUTH_HOME/myauth/manage.py"' >> ~/.bashrc && \
|
||||||
source ~/.bashrc
|
source ~/.bashrc
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ from django.conf import settings # noqa
|
|||||||
|
|
||||||
app = Celery('myauth')
|
app = Celery('myauth')
|
||||||
|
|
||||||
|
# Automatically try to establish the connection to the AMQP broker on
|
||||||
|
# Celery startup if it is unavailable.
|
||||||
|
app.conf.broker_connection_retry_on_startup = True
|
||||||
|
|
||||||
# Using a string here means the worker don't have to serialize
|
# Using a string here means the worker don't have to serialize
|
||||||
# the configuration object to child processes.
|
# the configuration object to child processes.
|
||||||
app.config_from_object('django.conf:settings')
|
app.config_from_object('django.conf:settings')
|
||||||
|
|||||||
@@ -1,20 +1,28 @@
|
|||||||
server {
|
events {}
|
||||||
listen 80;
|
http {
|
||||||
location = /favicon.ico { access_log off; log_not_found off; }
|
include mime.types;
|
||||||
location /static {
|
default_type application/octet-stream;
|
||||||
alias /var/www/myauth/static;
|
|
||||||
autoindex off;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /robots.txt {
|
sendfile on;
|
||||||
alias /var/www/myauth/static/robots.txt;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
server {
|
||||||
proxy_pass http://allianceauth_gunicorn:8000;
|
listen 80;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
location = /favicon.ico { access_log off; log_not_found off; }
|
||||||
proxy_set_header Host $host;
|
location /static {
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
alias /var/www/myauth/static;
|
||||||
proxy_redirect off;
|
autoindex off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /robots.txt {
|
||||||
|
alias /var/www/myauth/static/robots.txt;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://allianceauth_gunicorn:8000;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_redirect off;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
ARG AA_DOCKER_TAG
|
ARG AA_DOCKER_TAG
|
||||||
FROM $AA_DOCKER_TAG
|
FROM $AA_DOCKER_TAG
|
||||||
|
|
||||||
RUN cd /home/allianceauth
|
WORKDIR ${AUTH_HOME}
|
||||||
|
|
||||||
COPY /conf/requirements.txt requirements.txt
|
COPY /conf/requirements.txt requirements.txt
|
||||||
RUN pip install -r requirements.txt
|
RUN --mount=type=cache,target=~/.cache \
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|||||||
@@ -62,10 +62,10 @@ services:
|
|||||||
max-file: "5"
|
max-file: "5"
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:1.25
|
image: nginx:stable
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- ./conf/nginx.conf:/etc/nginx/conf.d/default.conf
|
- ./conf/nginx.conf:/etc/nginx/nginx.conf
|
||||||
- static-volume:/var/www/myauth/static
|
- static-volume:/var/www/myauth/static
|
||||||
depends_on:
|
depends_on:
|
||||||
- allianceauth_gunicorn
|
- allianceauth_gunicorn
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ from allianceauth.framework.api.evecharacter import get_user_from_evecharacter
|
|||||||
user = get_user_from_evecharacter(character=my_evecharacter)
|
user = get_user_from_evecharacter(character=my_evecharacter)
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, `user` is a `User` object, or the sentinel username (see [get_sentinel_user](#get-sentinel-user))
|
Now, `user` is a `User` object, or the sentinel username (see [get_sentinel_user](#get_sentinel_user))
|
||||||
if the `EveCharacter` has no user.
|
if the `EveCharacter` has no user.
|
||||||
|
|
||||||
## User API
|
## User API
|
||||||
@@ -88,7 +88,7 @@ main_character = get_main_character_name_from_user(user=my_user)
|
|||||||
|
|
||||||
Now, `main_character` is a `string` containing the user's main character name.
|
Now, `main_character` is a `string` containing the user's main character name.
|
||||||
If the user has no main character, the username will be returned. If the user is `None`,
|
If the user has no main character, the username will be returned. If the user is `None`,
|
||||||
the sentinel username (see [get_sentinel_user](#get-sentinel-user)) will be returned.
|
the sentinel username (see [get_sentinel_user](#get_sentinel_user)) will be returned.
|
||||||
|
|
||||||
### get_sentinel_user
|
### get_sentinel_user
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ have to load specific CSS or JavaScript yourself.
|
|||||||
|
|
||||||
These bundles include DataTables CSS and JS, jQuery Datepicker CSS and JS, jQueryUI CSS and JS, and more.
|
These bundles include DataTables CSS and JS, jQuery Datepicker CSS and JS, jQueryUI CSS and JS, and more.
|
||||||
|
|
||||||
A full list of bundles we provide can be found here: https://gitlab.com/allianceauth/allianceauth/-/tree/master/allianceauth/templates/bundles
|
A full list of bundles we provide can be found here: <https://gitlab.com/allianceauth/allianceauth/-/tree/master/allianceauth/templates/bundles>
|
||||||
|
|
||||||
To use a bundle, you can use the following code in your template (Example for jQueryUI):
|
To use a bundle, you can use the following code in your template (Example for jQueryUI):
|
||||||
|
|
||||||
@@ -28,6 +28,27 @@ To ensure a unified style language throughout Alliance Auth and Community Apps,
|
|||||||
we also provide a couple of template partials. This collection is bound to grow over
|
we also provide a couple of template partials. This collection is bound to grow over
|
||||||
time, so best have an eye on this page.
|
time, so best have an eye on this page.
|
||||||
|
|
||||||
|
### Dashboard Widget Title
|
||||||
|
|
||||||
|
To ensure the dashboard widgets have a unified style, we provide a template partial for the widget title.
|
||||||
|
|
||||||
|
To use it, you can use the following code in your dashboard widget template:
|
||||||
|
|
||||||
|
```django
|
||||||
|
<div id="my-app-dashboard-widget" class="col-12 mb-3">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
{% translate "My Widget Title" as widget_title %}
|
||||||
|
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p>My widget content</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
### Page Header
|
### Page Header
|
||||||
|
|
||||||
On some pages you want to have a page header. To make this easier, we provide a template partial for this.
|
On some pages you want to have a page header. To make this easier, we provide a template partial for this.
|
||||||
@@ -38,7 +59,8 @@ To use it, you can use the following code in your template:
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div>
|
<div>
|
||||||
{% translate "My Page Header" as page_header %}
|
{% translate "My Page Header" as page_header %}
|
||||||
{% include "framework/header/page-header.html" with title=page_header %}
|
{% translate "My Page Header Subtitle" as optional_subtitle %}
|
||||||
|
{% include "framework/header/page-header.html" with title=page_header subtitle=optional_subtitle %}
|
||||||
|
|
||||||
<p>My page content</p>
|
<p>My page content</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -122,10 +122,6 @@ class MyService(ServiceHook):
|
|||||||
|
|
||||||
All of your apps defined urlpatterns will then be included in the `URLconf` when the core application starts.
|
All of your apps defined urlpatterns will then be included in the `URLconf` when the core application starts.
|
||||||
|
|
||||||
#### self.service_ctrl_template
|
|
||||||
|
|
||||||
This is provided as a courtesy and defines the default template to be used with [render_service_ctrl](#render_service_ctrl). You are free to redefine or not use this variable at all.
|
|
||||||
|
|
||||||
#### title
|
#### title
|
||||||
|
|
||||||
This is a property which provides a user-friendly display of your service's name. It will usually do a reasonably good job unless your service name has punctuation or odd capitalization. If this is the case, you should override this method and return a string.
|
This is a property which provides a user-friendly display of your service's name. It will usually do a reasonably good job unless your service name has punctuation or odd capitalization. If this is the case, you should override this method and return a string.
|
||||||
@@ -134,7 +130,7 @@ This is a property which provides a user-friendly display of your service's name
|
|||||||
|
|
||||||
#### self.service_ctrl_template
|
#### self.service_ctrl_template
|
||||||
|
|
||||||
This is provided as a courtesy and defines the default template to be used with [render_service_ctrl](#render-service-ctrl). You are free to redefine or not use this variable at all.
|
This is provided as a courtesy and defines the default template to be used with [render_service_ctrl](#render_service_ctrl). You are free to redefine or not use this variable at all.
|
||||||
|
|
||||||
#### delete_user
|
#### delete_user
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ The `MenuItemHook` class specifies some parameters/instance variables required f
|
|||||||
:undoc-members:
|
:undoc-members:
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
### text
|
### text
|
||||||
|
|
||||||
The text shown as menu item, e.g., usually the name of the app.
|
The text shown as menu item, e.g., usually the name of the app.
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ def register_urls():
|
|||||||
return UrlHook(app_name.urls, 'app_name', r^'app_name/')
|
return UrlHook(app_name.urls, 'app_name', r^'app_name/')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
#### urls
|
#### urls
|
||||||
|
|
||||||
The urls module to include. See [the Django docs](https://docs.djangoproject.com/en/dev/topics/http/urls/#example) for designing urlpatterns.
|
The urls module to include. See [the Django docs](https://docs.djangoproject.com/en/dev/topics/http/urls/#example) for designing urlpatterns.
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ Update your auth project's settings file, inputting the server ID as `DISCORD_GU
|
|||||||
:::{note}
|
:::{note}
|
||||||
If you already have a Discord server, skip the creation step, but be sure to retrieve the server ID
|
If you already have a Discord server, skip the creation step, but be sure to retrieve the server ID
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Registering an Application
|
### Registering an Application
|
||||||
|
|
||||||
Navigate to the [Discord Developers site.](https://discord.com/developers/applications/me) Press the plus sign to create a new application.
|
Navigate to the [Discord Developers site.](https://discord.com/developers/applications/me) Press the plus sign to create a new application.
|
||||||
@@ -112,6 +113,7 @@ Role names on Discord are case-sensitive, while reserved group names on Auth are
|
|||||||
.. seealso::
|
.. seealso::
|
||||||
For more information see :ref:`ref-reserved-group-names`.
|
For more information see :ref:`ref-reserved-group-names`.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tasks
|
## Tasks
|
||||||
|
|
||||||
The Discord service contains a number of tasks that can be run to manually perform updates to all users.
|
The Discord service contains a number of tasks that can be run to manually perform updates to all users.
|
||||||
@@ -132,6 +134,7 @@ Name Description
|
|||||||
`update_all` Update groups, nicknames, usernames of all users
|
`update_all` Update groups, nicknames, usernames of all users
|
||||||
======================== ====================================================
|
======================== ====================================================
|
||||||
```
|
```
|
||||||
|
|
||||||
:::{note}
|
:::{note}
|
||||||
Depending on how many users you have, running these tasks can take considerable time to finish. You can calculate roughly 1 sec per user for all tasks, except update_all, which needs roughly 3 secs per user.
|
Depending on how many users you have, running these tasks can take considerable time to finish. You can calculate roughly 1 sec per user for all tasks, except update_all, which needs roughly 3 secs per user.
|
||||||
:::
|
:::
|
||||||
@@ -156,6 +159,7 @@ Name Description
|
|||||||
`DISCORD_TASKS_MAX_RETRIES` max retries of tasks after an error occurred `3`
|
`DISCORD_TASKS_MAX_RETRIES` max retries of tasks after an error occurred `3`
|
||||||
=================================== ============================================================================================= =======
|
=================================== ============================================================================================= =======
|
||||||
```
|
```
|
||||||
|
|
||||||
## Permissions
|
## Permissions
|
||||||
|
|
||||||
To use this service, users will require some of the following.
|
To use this service, users will require some of the following.
|
||||||
@@ -167,6 +171,7 @@ To use this service, users will require some of the following.
|
|||||||
| discord.access_discord | None | Can Access the Discord Service |
|
| discord.access_discord | None | Can Access the Discord Service |
|
||||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||||
```
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### "Unknown Error" on Discord site when activating service
|
### "Unknown Error" on Discord site when activating service
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Mumble
|
# Mumble (Docker)
|
||||||
|
|
||||||
An alternate install guide for Mumble using Docker, better suited to an Alliance Auth Docker install
|
An alternate install guide for Mumble using Docker, better suited to an Alliance Auth Docker install
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ MUMBLE_URL = "mumble.example.com"
|
|||||||
|
|
||||||
Add the following lines to your `.env` file
|
Add the following lines to your `.env` file
|
||||||
|
|
||||||
```env
|
```bash
|
||||||
# Mumble
|
# Mumble
|
||||||
MUMBLE_SUPERUSER_PASSWORD = superuser_password
|
MUMBLE_SUPERUSER_PASSWORD = superuser_password
|
||||||
MUMBLE_ICESECRETWRITE = icesecretwrite
|
MUMBLE_ICESECRETWRITE = icesecretwrite
|
||||||
@@ -67,7 +67,7 @@ Add the following to your `docker-compose.yml` under the `services:` section
|
|||||||
max-file: "5"
|
max-file: "5"
|
||||||
|
|
||||||
mumble-authenticator:
|
mumble-authenticator:
|
||||||
build
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./mumble-authenticator/Dockerfile
|
dockerfile: ./mumble-authenticator/Dockerfile
|
||||||
restart: always
|
restart: always
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ Currently, the following services support custom name formats:
|
|||||||
| Xenforo | Username | ``{character_name}`` |
|
| Xenforo | Username | ``{character_name}`` |
|
||||||
+-------------+-----------+-------------------------------------+
|
+-------------+-----------+-------------------------------------+
|
||||||
```
|
```
|
||||||
|
|
||||||
:::{note}
|
:::{note}
|
||||||
It's important to note here, before we get into what you can do with a name formatter, that before the generated name is passed off to the service to create an account it will be sanitized to remove characters (the letters and numbers etc.) that the service cannot support. This means that, despite what you configured, the service may display something different. It is up to you to test your formatter and understand how your format may be disrupted by a certain services sanitization function.
|
It's important to note here, before we get into what you can do with a name formatter, that before the generated name is passed off to the service to create an account it will be sanitized to remove characters (the letters and numbers etc.) that the service cannot support. This means that, despite what you configured, the service may display something different. It is up to you to test your formatter and understand how your format may be disrupted by a certain services sanitization function.
|
||||||
:::
|
:::
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Openfire
|
# Openfire (Docker)
|
||||||
|
|
||||||
An alternate install guide for Openfire using Docker, better suited to an Alliance Auth Docker install
|
An alternate install guide for Openfire using Docker, better suited to an Alliance Auth Docker install
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ BROADCAST_SERVICE_NAME = "broadcast"
|
|||||||
|
|
||||||
Add the following lines to your `.env` file
|
Add the following lines to your `.env` file
|
||||||
|
|
||||||
```env
|
```bash
|
||||||
# Openfire
|
# Openfire
|
||||||
OPENFIRE_SECRET_KEY = superuser_password
|
OPENFIRE_SECRET_KEY = superuser_password
|
||||||
BROADCAST_USER_PASSWORD = icesecretwrite
|
BROADCAST_USER_PASSWORD = icesecretwrite
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ PHPBB3_URL = ''
|
|||||||
DATABASES['phpbb3'] = {
|
DATABASES['phpbb3'] = {
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'NAME': 'alliance_forum',
|
'NAME': 'alliance_forum',
|
||||||
'USER': 'allianceserver-phpbb3',
|
'USER': 'allianceserver',
|
||||||
'PASSWORD': 'password',
|
'PASSWORD': 'password',
|
||||||
'HOST': '127.0.0.1',
|
'HOST': '127.0.0.1',
|
||||||
'PORT': '3306',
|
'PORT': '3306',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# TeamSpeak 3
|
# TeamSpeak 3 (Docker)
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ CELERYBEAT_SCHEDULE['run_ts3_group_update'] = {
|
|||||||
|
|
||||||
Add the following lines to your `.env` file
|
Add the following lines to your `.env` file
|
||||||
|
|
||||||
```env
|
```bash
|
||||||
# Temspeak
|
# Temspeak
|
||||||
TEAMSPEAK3_SERVERQUERY_USER = "serverquery"
|
TEAMSPEAK3_SERVERQUERY_USER = "serverquery"
|
||||||
TEAMSPEAK3_SERVERQUERY_PASSWORD = ""
|
TEAMSPEAK3_SERVERQUERY_PASSWORD = ""
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ There are a handful of ways to add packages:
|
|||||||
|
|
||||||
Using a custom docker image is the preferred approach, as it gives you the stability of packages only changing when you tell them to, along with packages not having to be downloaded every time your container restarts
|
Using a custom docker image is the preferred approach, as it gives you the stability of packages only changing when you tell them to, along with packages not having to be downloaded every time your container restarts
|
||||||
|
|
||||||
1. Add each additional package that you want to install to a single line in `conf/requirements.txt`. It is recommended, but not required, that you include a version number as well. This will keep your packages from magically updating. You can lookup packages on <https://package.wiki>, and copy everything after `pip install` from the top of the page to use the most recent version. It should look something like `allianceauth-signal-pings==0.0.7`. Every entry in this file should be on a separate line
|
1. Add each additional package that you want to install to a single line in `conf/requirements.txt`. It is recommended, but not required, that you include a version number as well. This will keep your packages from magically updating. You can lookup packages on <https://pypi.org>, and copy from the title at the top of the page to use the most recent version. It should look something like `allianceauth-signal-pings==0.0.7`. Every entry in this file should be on a separate line
|
||||||
1. Modify `docker-compose.yml`, as follows.
|
1. Modify `docker-compose.yml`, as follows.
|
||||||
* Comment out the `image` line under `allianceauth`
|
* Comment out the `image` line under `allianceauth`
|
||||||
* Uncomment the `build` section
|
* Uncomment the `build` section
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ Take a complete backup of your local.py, docker-compose and SQL database.
|
|||||||
|
|
||||||
`docker compose down`
|
`docker compose down`
|
||||||
|
|
||||||
Replace your conf/nginx.conf with the contents of <https://gitlab.com/allianceauth/allianceauth/-/blob/v4.x/docker/conf/nginx.conf>
|
Replace your conf/nginx.conf with the contents of <https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/conf/nginx.conf>
|
||||||
|
|
||||||
Replace your docker-compose.yml with the contents of <https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/docker-compose.yml>
|
Replace your docker-compose.yml with the contents of <https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/docker-compose.yml>
|
||||||
|
|
||||||
V3.x installs likely used a dedicated database for Nginx Proxy Manager, you can either setup NPM again without a database, or uncomment the sections noted to maintain this configuration
|
V3.x installs likely used a dedicated database for Nginx Proxy Manager, you can either setup NPM again without a database, or uncomment the sections noted to maintain this configuration
|
||||||
|
|
||||||
```docker-compose
|
```docker
|
||||||
proxy:
|
proxy:
|
||||||
...
|
...
|
||||||
# Uncomment this section to use a dedicated database for Nginx Proxy Manager
|
# Uncomment this section to use a dedicated database for Nginx Proxy Manager
|
||||||
@@ -64,7 +64,7 @@ V3.x installs likely used a dedicated database for Nginx Proxy Manager, you can
|
|||||||
|
|
||||||
You will need to add some entries to your .env file
|
You will need to add some entries to your .env file
|
||||||
|
|
||||||
```env
|
```bash
|
||||||
AA_DB_CHARSET=utf8mb4
|
AA_DB_CHARSET=utf8mb4
|
||||||
GF_SECURITY_ADMIN_USERNAME=admin
|
GF_SECURITY_ADMIN_USERNAME=admin
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -181,13 +181,17 @@ If you don't plan on running the database on the same server as auth you still n
|
|||||||
|
|
||||||
### Redis and Other Tools
|
### Redis and Other Tools
|
||||||
|
|
||||||
A few extra utilities are also required for installation of packages.
|
A few extra utilities are also required for the installation of packages.
|
||||||
|
|
||||||
::::{tabs}
|
::::{tabs}
|
||||||
|
|
||||||
:::{group-tab} Ubuntu 2004, 2204
|
:::{group-tab} Ubuntu 2004, 2204
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
|
||||||
|
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
|
||||||
|
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
|
||||||
|
sudo apt-get update
|
||||||
sudo apt-get install unzip git redis-server curl libssl-dev libbz2-dev libffi-dev build-essential pkg-config
|
sudo apt-get install unzip git redis-server curl libssl-dev libbz2-dev libffi-dev build-essential pkg-config
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -11,21 +11,28 @@ If you're using a small VPS to host services with very limited memory, consider
|
|||||||
::::{tabs}
|
::::{tabs}
|
||||||
|
|
||||||
:::{group-tab} Ubuntu 2004, 2204
|
:::{group-tab} Ubuntu 2004, 2204
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
apt-get install apache2
|
apt-get install apache2
|
||||||
```
|
```
|
||||||
|
|
||||||
:::
|
:::
|
||||||
:::{group-tab} CentOS 7
|
:::{group-tab} CentOS 7
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
yum install httpd
|
yum install httpd
|
||||||
```
|
```
|
||||||
|
|
||||||
:::
|
:::
|
||||||
:::{group-tab} CentOS Stream 8
|
:::{group-tab} CentOS Stream 8
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
dnf install httpd
|
dnf install httpd
|
||||||
```
|
```
|
||||||
|
|
||||||
:::
|
:::
|
||||||
:::{group-tab} CentOS Stream 9
|
:::{group-tab} CentOS Stream 9
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
systemctl enable httpd
|
systemctl enable httpd
|
||||||
systemctl start httpd
|
systemctl start httpd
|
||||||
@@ -36,7 +43,6 @@ systemctl start httpd
|
|||||||
|
|
||||||
CentOS 7, Stream 8, Stream 9
|
CentOS 7, Stream 8, Stream 9
|
||||||
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### Permissions
|
### Permissions
|
||||||
@@ -116,7 +122,7 @@ a2dissite 000-default.conf
|
|||||||
|
|
||||||
## Sample Config File
|
## Sample Config File
|
||||||
|
|
||||||
```ini
|
```apacheconf
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
ServerName auth.example.com
|
ServerName auth.example.com
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,47 @@ In its default configuration, your auth project logs INFO and higher messages to
|
|||||||
|
|
||||||
To record DEBUG messages in the log file, alter a setting in your auth project's settings file: `LOGGING['handlers']['log_file']['level'] = 'DEBUG'`. After restarting gunicorn and celery, your log file will record all logging messages.
|
To record DEBUG messages in the log file, alter a setting in your auth project's settings file: `LOGGING['handlers']['log_file']['level'] = 'DEBUG'`. After restarting gunicorn and celery, your log file will record all logging messages.
|
||||||
|
|
||||||
|
## Steps to Check Logs for Errors
|
||||||
|
|
||||||
|
### Locate the Logs
|
||||||
|
|
||||||
|
The logs are located within the `myauth/log/` directory of your Alliance Auth project.
|
||||||
|
|
||||||
|
### Access the Logs
|
||||||
|
|
||||||
|
Use a text editor or terminal commands (like `tail -f <filename>`) to open the relevant log files.
|
||||||
|
|
||||||
|
_(The `tail -f` command displays the last few lines of a file and then continues to monitor the file, printing any new lines that are added in real-time. Useful to watch while actively testing a troublesome feature while troubleshooting.)_
|
||||||
|
|
||||||
|
Consider the following:
|
||||||
|
|
||||||
|
`allianceauth.log` is the primary log for general troubleshooting. Tracks user actions, changes made, and potential errors.
|
||||||
|
|
||||||
|
`worker.log` is important for issues related to background tasks.(Such as services(Discord)).
|
||||||
|
|
||||||
|
`beat.log` if you suspect scheduler problems.
|
||||||
|
|
||||||
|
`gunicorn.log` for web-specific or Gunicorn worker errors.
|
||||||
|
|
||||||
|
### Search for Errors
|
||||||
|
|
||||||
|
Look for keywords like `ERROR`, `WARNING`, `EXCEPTION`, or `CRITICAL`. Examine timestamps to correlate errors with user actions or events. Read the error messages carefully for clues about the problem's nature.
|
||||||
|
|
||||||
|
Troubleshooting Tips:
|
||||||
|
|
||||||
|
**Filter Logs:** Use tools like `grep` to filter logs based on keywords or timeframes, making it easier to focus on relevant information.
|
||||||
|
|
||||||
|
**Example**: `tail -f worker.log | grep -i 'discord'`. This will isolate lines containing discord. Making it easier to see among the other logs.
|
||||||
|
|
||||||
|
**Debug Mode:** For in-depth troubleshooting, temporarily enable DEBUG logging in your `local.py` to get more detailed messages. Remember to set it back to `False` after debugging.
|
||||||
|
|
||||||
|
**Important Note: Before sharing logs publicly, sanitize any sensitive information such as usernames, passwords, or API keys.**
|
||||||
|
|
||||||
## Common Problems
|
## Common Problems
|
||||||
|
|
||||||
### I'm getting error 500 when trying to connect to the website on a new installation
|
### I'm getting error 500 when trying to connect to the website on a new installation
|
||||||
|
|
||||||
*Great.* Error 500 is the generic message given by your web server when *anything* breaks. The actual error message is hidden in one of your auth project's log files. Read them to identify it.
|
_Great._ Error 500 is the generic message given by your web server when _anything_ breaks. The actual error message is hidden in one of your auth project's log files. Read them to identify it.
|
||||||
|
|
||||||
### Failed to configure log handler
|
### Failed to configure log handler
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
# Gunicorn
|
|
||||||
|
|
||||||
## Number of workers
|
|
||||||
|
|
||||||
The default installation will have 3 workers configured for Gunicorn. This will be fine on most systems, but if your system as more than one core than you might want to increase the number of workers to get better response times. Note that more workers will also need more RAM though.
|
|
||||||
|
|
||||||
The number you set this to will depend on your own server environment, how many visitors you have etc. Gunicorn suggests `(2 x $num_cores) + 1` for the number of workers. So for example, if you have 2 cores, you want 2 x 2 + 1 = 5 workers. See [here](https://docs.gunicorn.org/en/stable/design.html#how-many-workers) for the official discussion on this topic.
|
|
||||||
|
|
||||||
For example, to get 5 workers change the setting `--workers=5` in your `supervisor.conf` file and then reload the supervisor with the following command to activate the change (Ubuntu):
|
|
||||||
|
|
||||||
```shell
|
|
||||||
systemctl restart supervisor
|
|
||||||
```
|
|
||||||
@@ -9,7 +9,7 @@ Tuning usually has benefits and costs and should only be performed by experience
|
|||||||
:::{toctree}
|
:::{toctree}
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
gunicorn
|
web
|
||||||
celery
|
celery
|
||||||
redis
|
redis
|
||||||
python
|
python
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
156
docs/maintenance/tuning/web.md
Normal file
156
docs/maintenance/tuning/web.md
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
# Web Tuning
|
||||||
|
|
||||||
|
## Gunicorn
|
||||||
|
|
||||||
|
### Number of workers
|
||||||
|
|
||||||
|
The default installation will have 3 workers configured for Gunicorn. This will be fine on most systems, but if your system as more than one core than you might want to increase the number of workers to get better response times. Note that more workers will also need more RAM though.
|
||||||
|
|
||||||
|
The number you set this to will depend on your own server environment, how many visitors you have etc. Gunicorn suggests `(2 x $num_cores) + 1` for the number of workers. So for example, if you have 2 cores, you want 2 x 2 + 1 = 5 workers. See [here](https://docs.gunicorn.org/en/stable/design.html#how-many-workers) for the official discussion on this topic.
|
||||||
|
|
||||||
|
::::{tabs}
|
||||||
|
:::{group-tab} Ubuntu 2204, 2404
|
||||||
|
To have 5 workers change the setting `--workers=x` to `--workers=5` in your `supervisor.conf` file and then reload the supervisor with the following command to activate the change
|
||||||
|
|
||||||
|
```shell
|
||||||
|
systemctl restart supervisor
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
:::{group-tab} CentOS / RHEL
|
||||||
|
To have 5 workers change the setting `--workers=x` to `--workers=5` in your `supervisor.conf` file and then reload the supervisor with the following command to activate the change
|
||||||
|
|
||||||
|
```shell
|
||||||
|
systemctl restart supervisor
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
:::{group-tab} Docker Compose
|
||||||
|
To have 5 workers change the setting `--workers=3` to `--workers=5` in your `docker-compose.yml` file and then restart the container as follows
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
::::
|
||||||
|
|
||||||
|
## nginx
|
||||||
|
|
||||||
|
### nginx repo
|
||||||
|
|
||||||
|
We can use the Nginx repositories for a slightly more cutting edge version of Nginx, with more features. Install it to enable the below features
|
||||||
|
|
||||||
|
::::{tabs}
|
||||||
|
:::{group-tab} Ubuntu 2204, 2404
|
||||||
|
<https://nginx.org/en/linux_packages.html#Ubuntu>
|
||||||
|
:::
|
||||||
|
:::{group-tab} CentOS / RHEL
|
||||||
|
<https://nginx.org/en/linux_packages.html#RHEL>
|
||||||
|
:::
|
||||||
|
:::{group-tab} Docker
|
||||||
|
No package necessary, simply increase `docker compose pull` and `docker compose up -d` to update.
|
||||||
|
:::
|
||||||
|
::::
|
||||||
|
|
||||||
|
### Brotli Compression
|
||||||
|
|
||||||
|
Brotli is a modern compression algorithm designed for the web. Use this with Pre-Compression and E2E Cloudflare compression for best results.
|
||||||
|
|
||||||
|
::::{tabs}
|
||||||
|
:::{group-tab} Ubuntu 2204, 2404
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-static
|
||||||
|
:::
|
||||||
|
:::{group-tab} CentOS
|
||||||
|
WIP
|
||||||
|
:::
|
||||||
|
:::{group-tab} Docker
|
||||||
|
Pull a custom dockerfile
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir nginx
|
||||||
|
curl -o my-nginx/Dockerfile https://raw.githubusercontent.com/nginxinc/docker-nginx/master/modules/Dockerfile
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace the nginx service in your docker-compose as follows
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
nginx:
|
||||||
|
build:
|
||||||
|
context: ./nginx/
|
||||||
|
args:
|
||||||
|
ENABLED_MODULES: brotli
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./conf/nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
- static-volume:/var/www/myauth/static
|
||||||
|
depends_on:
|
||||||
|
- allianceauth_gunicorn
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "10Mb"
|
||||||
|
max-file: "5"
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
::::
|
||||||
|
|
||||||
|
Modify your nginx.conf as follows
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
load_module modules/ngx_http_brotli_static_module.so;
|
||||||
|
load_module modules/ngx_http_brotli_filter_module.so;
|
||||||
|
...
|
||||||
|
http {
|
||||||
|
...
|
||||||
|
server {
|
||||||
|
...
|
||||||
|
location /static {
|
||||||
|
...
|
||||||
|
brotli_static on;
|
||||||
|
brotli_types application/javascript text/css font/woff2 image/png image/svg+xml font/woff image/gif;
|
||||||
|
brotli_comp_level 11;
|
||||||
|
}
|
||||||
|
...
|
||||||
|
location / {
|
||||||
|
...
|
||||||
|
brotli on;
|
||||||
|
brotli_comp_level 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Staticfile Pre-Compression
|
||||||
|
|
||||||
|
We can use a small library to pre-compress staticfiles for Nginx to deliver.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
pip install django-static-compress
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the following lines to local.py
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Tuning / Compression
|
||||||
|
STORAGES = {
|
||||||
|
"staticfiles": {
|
||||||
|
"BACKEND": "static_compress.CompressedStaticFilesStorage",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC_COMPRESS_FILE_EXTS = ['js', 'css', 'woff2', 'png', 'svg', 'woff', 'gif']
|
||||||
|
STATIC_COMPRESS_METHODS = ['gz', 'br']
|
||||||
|
STATIC_COMPRESS_KEEP_ORIGINAL = True
|
||||||
|
STATIC_COMPRESS_MIN_SIZE_KB = 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cloudflare
|
||||||
|
|
||||||
|
### Brotli E2E Compression
|
||||||
|
|
||||||
|
Soon to be turned on by default. Refer to <https://developers.cloudflare.com/speed/optimization/content/brotli/enable/>
|
||||||
|
|
||||||
|
In order for cloudflare to seamlessly pass on your brotli compressed pages (End to End), ensure minification, rocket loader and other features are _off_ <https://developers.cloudflare.com/speed/optimization/content/brotli/enable/#notes-about-end-to-end-compression>. Else cloudflare will need to uncompress, modify, then recompress your pages.
|
||||||
@@ -1,86 +1,85 @@
|
|||||||
[build-system]
|
[build-system]
|
||||||
requires = ["flit_core >=3.2,<4"]
|
|
||||||
build-backend = "flit_core.buildapi"
|
build-backend = "flit_core.buildapi"
|
||||||
|
requires = [
|
||||||
|
"flit-core<4,>=3.2",
|
||||||
|
]
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "allianceauth"
|
name = "allianceauth"
|
||||||
dynamic = ["version", "description"]
|
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = {file = "LICENSE"}
|
|
||||||
requires-python = ">=3.8"
|
|
||||||
authors = [
|
|
||||||
{ name = "Alliance Auth", email = "adarnof@gmail.com" },
|
|
||||||
]
|
|
||||||
keywords = [
|
keywords = [
|
||||||
"allianceauth",
|
"allianceauth",
|
||||||
"eveonline",
|
"eveonline",
|
||||||
]
|
]
|
||||||
|
license = { file = "LICENSE" }
|
||||||
|
authors = [
|
||||||
|
{ name = "Alliance Auth", email = "adarnof@gmail.com" },
|
||||||
|
]
|
||||||
|
requires-python = ">=3.10"
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Environment :: Web Environment",
|
"Environment :: Web Environment",
|
||||||
|
"Framework :: Celery",
|
||||||
"Framework :: Django",
|
"Framework :: Django",
|
||||||
"Framework :: Django :: 4.2",
|
"Framework :: Django :: 4.2",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"License :: OSI Approved :: GNU General Public License v2 (GPLv2)",
|
"License :: OSI Approved :: GNU General Public License v2 (GPLv2)",
|
||||||
"Operating System :: POSIX :: Linux",
|
"Operating System :: POSIX :: Linux",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 3.8",
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
"Programming Language :: Python :: 3.9",
|
|
||||||
"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",
|
||||||
"Topic :: Internet :: WWW/HTTP",
|
"Topic :: Internet :: WWW/HTTP",
|
||||||
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
||||||
]
|
]
|
||||||
|
dynamic = [
|
||||||
|
"description",
|
||||||
|
"version",
|
||||||
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
"beautifulsoup4",
|
"beautifulsoup4",
|
||||||
|
"celery<6,>=5.2",
|
||||||
"celery-once>=3.0.1",
|
"celery-once>=3.0.1",
|
||||||
"celery>=5.2.0,<6",
|
"django<5.2,>=5.1",
|
||||||
'django-bootstrap5>=23.3',
|
|
||||||
"django-bootstrap-form",
|
"django-bootstrap-form",
|
||||||
"django-celery-beat>=2.3.0",
|
"django-bootstrap5>=23.3",
|
||||||
"django-esi>=5.0.0",
|
"django-celery-beat>=2.7",
|
||||||
"django-redis>=5.2.0",
|
"django-esi>=5",
|
||||||
"django-registration>=3.3,<3.4",
|
"django-redis>=5.2",
|
||||||
|
"django-registration<3.4,>=3.3",
|
||||||
"django-sortedm2m",
|
"django-sortedm2m",
|
||||||
"django>=4.2,<5",
|
|
||||||
"dnspython",
|
"dnspython",
|
||||||
"mysqlclient>=2.1.0",
|
"mysqlclient>=2.1",
|
||||||
"openfire-restapi",
|
"openfire-restapi",
|
||||||
"packaging>=21.0",
|
"packaging>=21",
|
||||||
"passlib",
|
"passlib",
|
||||||
"pydiscourse",
|
"pydiscourse",
|
||||||
"python-slugify>=1.2",
|
"python-slugify>=1.2",
|
||||||
"redis>=4.0.0",
|
"redis>=4",
|
||||||
"requests-oauthlib",
|
|
||||||
"requests>=2.9.1",
|
"requests>=2.9.1",
|
||||||
|
"requests-oauthlib",
|
||||||
"semantic-version",
|
"semantic-version",
|
||||||
"slixmpp",
|
"slixmpp",
|
||||||
]
|
]
|
||||||
|
optional-dependencies.docs = [
|
||||||
[project.optional-dependencies]
|
"myst-parser",
|
||||||
test = [
|
"sphinx",
|
||||||
|
"sphinx-copybutton",
|
||||||
|
"sphinx-rtd-theme<3,>=2",
|
||||||
|
"sphinx-tabs",
|
||||||
|
"sphinxcontrib-django",
|
||||||
|
]
|
||||||
|
optional-dependencies.test = [
|
||||||
"coverage>=4.3.1",
|
"coverage>=4.3.1",
|
||||||
"django-webtest",
|
"django-webtest",
|
||||||
"requests-mock>=1.2.0"
|
"requests-mock>=1.2",
|
||||||
]
|
]
|
||||||
docs = [
|
urls.Documentation = "https://allianceauth.readthedocs.io/"
|
||||||
"sphinx",
|
urls.Homepage = "https://gitlab.com/allianceauth/allianceauth"
|
||||||
"sphinx_rtd_theme>=2.0.0,<3.0.0",
|
urls.Source = "https://gitlab.com/allianceauth/allianceauth"
|
||||||
"myst-parser",
|
urls.Tracker = "https://gitlab.com/allianceauth/allianceauth/-/issues"
|
||||||
"sphinxcontrib-django",
|
scripts.allianceauth = "allianceauth.bin.allianceauth:main"
|
||||||
"sphinx-copybutton",
|
|
||||||
"sphinx-tabs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[project.scripts]
|
|
||||||
allianceauth = "allianceauth.bin.allianceauth:main"
|
|
||||||
|
|
||||||
[project.urls]
|
|
||||||
Homepage = "https://gitlab.com/allianceauth/allianceauth"
|
|
||||||
Documentation = "https://allianceauth.readthedocs.io/"
|
|
||||||
Source = "https://gitlab.com/allianceauth/allianceauth"
|
|
||||||
Tracker = "https://gitlab.com/allianceauth/allianceauth/-/issues"
|
|
||||||
|
|
||||||
[tool.flit.module]
|
[tool.flit.module]
|
||||||
name = "allianceauth"
|
name = "allianceauth"
|
||||||
@@ -94,8 +93,12 @@ sections = [
|
|||||||
"DJANGO",
|
"DJANGO",
|
||||||
"ESI",
|
"ESI",
|
||||||
"FIRSTPARTY",
|
"FIRSTPARTY",
|
||||||
"LOCALFOLDER"
|
"LOCALFOLDER",
|
||||||
|
]
|
||||||
|
known_esi = [
|
||||||
|
"esi",
|
||||||
|
]
|
||||||
|
known_django = [
|
||||||
|
"django",
|
||||||
]
|
]
|
||||||
known_esi = ["esi"]
|
|
||||||
known_django = ["django"]
|
|
||||||
skip_gitignore = true
|
skip_gitignore = true
|
||||||
|
|||||||
9
tox.ini
9
tox.ini
@@ -1,19 +1,18 @@
|
|||||||
[tox]
|
[tox]
|
||||||
isolated_build = True
|
isolated_build = true
|
||||||
skipsdist = true
|
skipsdist = true
|
||||||
usedevelop = true
|
usedevelop = true
|
||||||
envlist = py{38,39,310,311,312}-{all,core}, docs
|
envlist = py{310,311,312,313}-{all,core}, docs
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
setenv =
|
setenv =
|
||||||
all: DJANGO_SETTINGS_MODULE = tests.settings_all
|
all: DJANGO_SETTINGS_MODULE = tests.settings_all
|
||||||
core: DJANGO_SETTINGS_MODULE = tests.settings_core
|
core: DJANGO_SETTINGS_MODULE = tests.settings_core
|
||||||
basepython =
|
basepython =
|
||||||
py38: python3.8
|
|
||||||
py39: python3.9
|
|
||||||
py310: python3.10
|
py310: python3.10
|
||||||
py311: python3.11
|
py311: python3.11
|
||||||
py312: python3.12
|
py312: python3.12
|
||||||
|
py313: python3.13
|
||||||
deps=
|
deps=
|
||||||
coverage
|
coverage
|
||||||
install_command = pip install -e ".[test]" -U {opts} {packages}
|
install_command = pip install -e ".[test]" -U {opts} {packages}
|
||||||
@@ -25,7 +24,7 @@ commands =
|
|||||||
|
|
||||||
[testenv:docs]
|
[testenv:docs]
|
||||||
description = invoke sphinx-build to build the HTML docs
|
description = invoke sphinx-build to build the HTML docs
|
||||||
basepython = python3.11
|
basepython = python3.12
|
||||||
install_command = pip install -e ".[docs]" -U {opts} {packages}
|
install_command = pip install -e ".[docs]" -U {opts} {packages}
|
||||||
commands =
|
commands =
|
||||||
sphinx-build -T -E -b html -d "{toxworkdir}/docs_doctree" -D language=en docs "{toxworkdir}/docs_out" {posargs}
|
sphinx-build -T -E -b html -d "{toxworkdir}/docs_doctree" -D language=en docs "{toxworkdir}/docs_out" {posargs}
|
||||||
|
|||||||
Reference in New Issue
Block a user