mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-04 06:06:19 +01:00
Compare commits
129 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
ef2dc08958 | ||
|
|
6b84ffa16c | ||
|
|
d7a1096413 | ||
|
|
93b94a8bc2 | ||
|
|
9a95716105 | ||
|
|
dbfcf5d87a | ||
|
|
105d7d53b3 | ||
|
|
01cefe1457 | ||
|
|
7fe3db8017 | ||
|
|
e0945fac80 | ||
|
|
40fa190820 | ||
|
|
670580f8f3 | ||
|
|
323a0bcf16 | ||
|
|
6e995edd80 | ||
|
|
8d86e45b7a | ||
|
|
2aa6df4461 | ||
|
|
cf6f989502 | ||
|
|
3e1d8ae334 | ||
|
|
bcfe9484b5 | ||
|
|
5e4d1b9cfd | ||
|
|
3b463e7305 | ||
|
|
eedf5082fa | ||
|
|
2ea5b15175 | ||
|
|
7a9808aad3 | ||
|
|
a1d712694c | ||
|
|
ca11c726a3 | ||
|
|
6e0f7a35bd | ||
|
|
7375b001ca | ||
|
|
0287086633 | ||
|
|
9eb2becbb5 | ||
|
|
12f1444fe7 | ||
|
|
d6372bd093 | ||
|
|
f4d8ead54e | ||
|
|
7427e13505 | ||
|
|
445683c3d5 | ||
|
|
677c46c48a | ||
|
|
87b9e3f87a | ||
|
|
da2a5aff2f | ||
|
|
65d77743dc | ||
|
|
9f4bf13cc9 | ||
|
|
51b86f88b9 | ||
|
|
8184461b48 | ||
|
|
ca0cdd6e15 | ||
|
|
036a17ad3b | ||
|
|
2418023ddd |
@@ -25,7 +25,7 @@ before_script:
|
||||
pre-commit-check:
|
||||
<<: *only-default
|
||||
stage: pre-commit
|
||||
image: python:3.11-bullseye
|
||||
image: python:3.11-bookworm
|
||||
# variables:
|
||||
# PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
|
||||
# cache:
|
||||
@@ -53,7 +53,7 @@ secret_detection:
|
||||
|
||||
test-3.8-core:
|
||||
<<: *only-default
|
||||
image: python:3.8-bullseye
|
||||
image: python:3.8-bookworm
|
||||
script:
|
||||
- tox -e py38-core
|
||||
artifacts:
|
||||
@@ -65,7 +65,7 @@ test-3.8-core:
|
||||
|
||||
test-3.9-core:
|
||||
<<: *only-default
|
||||
image: python:3.9-bullseye
|
||||
image: python:3.9-bookworm
|
||||
script:
|
||||
- tox -e py39-core
|
||||
artifacts:
|
||||
@@ -77,7 +77,7 @@ test-3.9-core:
|
||||
|
||||
test-3.10-core:
|
||||
<<: *only-default
|
||||
image: python:3.10-bullseye
|
||||
image: python:3.10-bookworm
|
||||
script:
|
||||
- tox -e py310-core
|
||||
artifacts:
|
||||
@@ -89,7 +89,7 @@ test-3.10-core:
|
||||
|
||||
test-3.11-core:
|
||||
<<: *only-default
|
||||
image: python:3.11-bullseye
|
||||
image: python:3.11-bookworm
|
||||
script:
|
||||
- tox -e py311-core
|
||||
artifacts:
|
||||
@@ -101,7 +101,7 @@ test-3.11-core:
|
||||
|
||||
test-3.12-core:
|
||||
<<: *only-default
|
||||
image: python:3.12-rc-bullseye
|
||||
image: python:3.12-bookworm
|
||||
script:
|
||||
- tox -e py312-core
|
||||
artifacts:
|
||||
@@ -113,7 +113,7 @@ test-3.12-core:
|
||||
|
||||
test-3.8-all:
|
||||
<<: *only-default
|
||||
image: python:3.8-bullseye
|
||||
image: python:3.8-bookworm
|
||||
script:
|
||||
- tox -e py38-all
|
||||
artifacts:
|
||||
@@ -125,7 +125,7 @@ test-3.8-all:
|
||||
|
||||
test-3.9-all:
|
||||
<<: *only-default
|
||||
image: python:3.9-bullseye
|
||||
image: python:3.9-bookworm
|
||||
script:
|
||||
- tox -e py39-all
|
||||
artifacts:
|
||||
@@ -137,7 +137,7 @@ test-3.9-all:
|
||||
|
||||
test-3.10-all:
|
||||
<<: *only-default
|
||||
image: python:3.10-bullseye
|
||||
image: python:3.10-bookworm
|
||||
script:
|
||||
- tox -e py310-all
|
||||
artifacts:
|
||||
@@ -149,7 +149,7 @@ test-3.10-all:
|
||||
|
||||
test-3.11-all:
|
||||
<<: *only-default
|
||||
image: python:3.11-bullseye
|
||||
image: python:3.11-bookworm
|
||||
script:
|
||||
- tox -e py311-all
|
||||
artifacts:
|
||||
@@ -162,7 +162,7 @@ test-3.11-all:
|
||||
|
||||
test-3.12-all:
|
||||
<<: *only-default
|
||||
image: python:3.12-rc-bullseye
|
||||
image: python:3.12-bookworm
|
||||
script:
|
||||
- tox -e py312-all
|
||||
artifacts:
|
||||
@@ -174,7 +174,7 @@ test-3.12-all:
|
||||
|
||||
build-test:
|
||||
stage: test
|
||||
image: python:3.11-bullseye
|
||||
image: python:3.11-bookworm
|
||||
|
||||
before_script:
|
||||
- python -m pip install --upgrade pip
|
||||
@@ -193,13 +193,13 @@ build-test:
|
||||
|
||||
test-docs:
|
||||
<<: *only-default
|
||||
image: python:3.11-bullseye
|
||||
image: python:3.11-bookworm
|
||||
script:
|
||||
- tox -e docs
|
||||
|
||||
deploy_production:
|
||||
stage: deploy
|
||||
image: python:3.11-bullseye
|
||||
image: python:3.11-bookworm
|
||||
|
||||
before_script:
|
||||
- python -m pip install --upgrade pip
|
||||
|
||||
@@ -4,8 +4,21 @@
|
||||
# pre-commit autoupdate
|
||||
|
||||
repos:
|
||||
# Code Upgrades
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.15.2
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py38-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
|
||||
rev: v4.4.0
|
||||
rev: v4.6.0
|
||||
hooks:
|
||||
# Identify invalid files
|
||||
- id: check-ast
|
||||
@@ -13,27 +26,24 @@ repos:
|
||||
- id: check-json
|
||||
- id: check-toml
|
||||
- id: check-xml
|
||||
|
||||
# git checks
|
||||
- id: check-merge-conflict
|
||||
- id: check-added-large-files
|
||||
args: [ --maxkb=1000 ]
|
||||
args: [--maxkb=1000]
|
||||
- id: detect-private-key
|
||||
- id: check-case-conflict
|
||||
|
||||
# Python checks
|
||||
# - id: check-docstring-first
|
||||
# - id: check-docstring-first
|
||||
- id: debug-statements
|
||||
# - id: requirements-txt-fixer
|
||||
# - id: requirements-txt-fixer
|
||||
- id: fix-encoding-pragma
|
||||
args: [ --remove ]
|
||||
args: [--remove]
|
||||
- id: fix-byte-order-marker
|
||||
|
||||
# General quality checks
|
||||
- id: mixed-line-ending
|
||||
args: [ --fix=lf ]
|
||||
args: [--fix=lf]
|
||||
- id: trailing-whitespace
|
||||
args: [ --markdown-linebreak-ext=md ]
|
||||
args: [--markdown-linebreak-ext=md]
|
||||
exclude: |
|
||||
(?x)(
|
||||
\.min\.css|
|
||||
@@ -52,9 +62,8 @@ repos:
|
||||
\.mo|
|
||||
swagger\.json
|
||||
)
|
||||
|
||||
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
|
||||
rev: 2.7.2
|
||||
rev: 2.7.3
|
||||
hooks:
|
||||
- id: editorconfig-checker
|
||||
exclude: |
|
||||
@@ -65,21 +74,26 @@ repos:
|
||||
\.mo|
|
||||
swagger\.json
|
||||
)
|
||||
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.10.1
|
||||
- repo: https://github.com/igorshubovych/markdownlint-cli
|
||||
rev: v0.41.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [ --py38-plus ]
|
||||
|
||||
- repo: https://github.com/adamchainz/django-upgrade
|
||||
rev: 1.14.0
|
||||
- id: markdownlint
|
||||
args:
|
||||
- --disable=MD013
|
||||
# Infrastructure
|
||||
- repo: https://github.com/tox-dev/pyproject-fmt
|
||||
rev: 2.1.3
|
||||
hooks:
|
||||
- id: django-upgrade
|
||||
args: [--target-version=4.2]
|
||||
|
||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||
rev: v2.3.0
|
||||
- id: pyproject-fmt
|
||||
name: pyproject.toml formatter
|
||||
description: "Format the pyproject.toml file."
|
||||
args:
|
||||
- --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:
|
||||
- id: setup-cfg-fmt
|
||||
args: [ --include-version-classifiers ]
|
||||
- id: validate-pyproject
|
||||
name: Validate pyproject.toml
|
||||
description: "Validate the pyproject.toml file."
|
||||
|
||||
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
|
||||
# Django starts so that shared_task will use this app.
|
||||
|
||||
__version__ = '4.0.0b2'
|
||||
__version__ = '4.2.0'
|
||||
__title__ = 'Alliance Auth'
|
||||
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
|
||||
NAME = f'{__title__} v{__version__}'
|
||||
|
||||
@@ -9,6 +9,8 @@ from .utils import (
|
||||
install_stat_tokens,
|
||||
install_stat_users)
|
||||
|
||||
from allianceauth import __version__
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
BASE_URL = "https://www.google-analytics.com"
|
||||
@@ -99,11 +101,38 @@ def analytics_daily_stats():
|
||||
event_type='Stats')
|
||||
|
||||
for appconfig in apps.get_app_configs():
|
||||
analytics_event(namespace='allianceauth.analytics',
|
||||
task='send_extension_stats',
|
||||
label=appconfig.label,
|
||||
value=1,
|
||||
event_type='Stats')
|
||||
if appconfig.label in [
|
||||
"django_celery_beat",
|
||||
"bootstrapform",
|
||||
"messages",
|
||||
"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()
|
||||
@@ -139,7 +168,7 @@ def send_ga_tracking_celery_event(
|
||||
'client_id': AnalyticsIdentifier.objects.get(id=1).identifier.hex,
|
||||
"user_properties": {
|
||||
"allianceauth_version": {
|
||||
"value": "allianceauth_version"
|
||||
"value": __version__
|
||||
}
|
||||
},
|
||||
'non_personalized_ads': True,
|
||||
|
||||
@@ -5,26 +5,5 @@ from django.core.checks import Warning, Error, register
|
||||
class AllianceAuthConfig(AppConfig):
|
||||
name = 'allianceauth'
|
||||
|
||||
|
||||
@register()
|
||||
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
|
||||
def ready(self) -> None:
|
||||
import allianceauth.checks # noqa
|
||||
|
||||
@@ -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')
|
||||
ITALIAN = 'it', _('Italian')
|
||||
UKRAINIAN = 'uk', _('Ukrainian')
|
||||
POLISH = 'pl', _("Polish")
|
||||
|
||||
user = models.OneToOneField(
|
||||
User,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{% translate "Dashboard" %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-around align-self-center flex-wrap">
|
||||
<div class="row">
|
||||
{% for dash in views %}
|
||||
{{ dash | safe }}
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
{% 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 class="card">
|
||||
<div id="aa-dashboard-panel-characters" class="col-12 col-xl-8 mb-3">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<h4 class="ms-auto me-auto">
|
||||
{% translate "Characters" %}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% translate "Characters" as widget_title %}
|
||||
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||
|
||||
<div>
|
||||
<div style="height: 300px; overflow-y:auto;">
|
||||
<div class="d-flex">
|
||||
<a href="{% url 'authentication:add_character' %}" class="btn btn-primary flex-fill m-1" title="{% translate 'Add Character' %}">
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
{% 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-body">
|
||||
<h4 class="card-title text-center">{% translate "Membership" %}</h4>
|
||||
<div class="card-body">
|
||||
{% translate "Membership" as widget_title %}
|
||||
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||
|
||||
<div>
|
||||
<div style="height: 300px; overflow-y:auto;">
|
||||
<h5 class="text-center">{% translate "State:" %} {{ request.user.profile.state }}</h5>
|
||||
<table class="table">
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% load theme_tags %}
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@@ -16,7 +17,7 @@
|
||||
|
||||
<title>{% block title %}{% block page_title %}{% endblock page_title %} - {{ SITE_NAME }}{% endblock title %}</title>
|
||||
|
||||
{% include 'bundles/bootstrap-css-bs5.html' %}
|
||||
{% theme_css %}
|
||||
{% include 'bundles/fontawesome.html' %}
|
||||
|
||||
{% block extra_include %}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-4">
|
||||
<div class="col-md-6">
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.level_tag}}">{{ message }}</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card card-login border-secondary p-3">
|
||||
<div class="card-body">
|
||||
<form method="POST">
|
||||
|
||||
171
allianceauth/checks.py
Normal file
171
allianceauth/checks.py
Normal file
@@ -0,0 +1,171 @@
|
||||
from typing import List
|
||||
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
|
||||
|
||||
"""
|
||||
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=timezone.utc):
|
||||
errors.append(Error(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint="https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", 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://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", 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://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", id="allianceauth.checks.A018"))
|
||||
elif redis_version.major in [6, 5]:
|
||||
errors.append(Error(f"Redis {redis_version.public} EOL", hint="https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", 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=timezone.utc):
|
||||
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A004"))
|
||||
elif mysql_version.major == 8 and mysql_version.minor == 3:
|
||||
errors.append(Warning(f"MySQL {mysql_version.public} Non LTS", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A005"))
|
||||
elif mysql_version.major == 8 and mysql_version.minor == 2:
|
||||
errors.append(Warning(f"MySQL {mysql_version.public} Non LTS", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A006"))
|
||||
elif mysql_version.major == 8 and mysql_version.minor == 1:
|
||||
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A007"))
|
||||
elif mysql_version.major == 8 and mysql_version.minor == 0 and timezone.now() > timezone.datetime(year=2026, month=4, day=30, tzinfo=timezone.utc):
|
||||
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A008"))
|
||||
elif mysql_version.major < 8: # This will also catch Mariadb 5.x
|
||||
errors.append(Error(f"MySQL or MariaDB {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A009"))
|
||||
return errors
|
||||
|
||||
|
||||
@register()
|
||||
def system_package_mariadb(app_configs, **kwargs) -> List[CheckMessage]:
|
||||
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=timezone.utc):
|
||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A010"))
|
||||
elif mariadb_version.major == 11 and mariadb_version.minor == 2:
|
||||
errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A018"))
|
||||
if timezone.now() > timezone.datetime(year=2024, month=11, day=21, tzinfo=timezone.utc):
|
||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A011"))
|
||||
elif mariadb_version.major == 11 and mariadb_version.minor == 1:
|
||||
errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A019"))
|
||||
if timezone.now() > timezone.datetime(year=2024, month=8, day=21, tzinfo=timezone.utc):
|
||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A012"))
|
||||
elif mariadb_version.major == 11 and mariadb_version.minor in [0, 3]: # Demote versions down here once EOL
|
||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config.", id="allianceauth.checks.A013"))
|
||||
|
||||
# MariaDB 10
|
||||
elif mariadb_version.major == 10 and mariadb_version.minor == 11 and timezone.now() > timezone.datetime(year=2028, month=2, day=10, tzinfo=timezone.utc):
|
||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config.", id="allianceauth.checks.A014"))
|
||||
elif mariadb_version.major == 10 and mariadb_version.minor == 6 and timezone.now() > timezone.datetime(year=2026, month=7, day=6, tzinfo=timezone.utc):
|
||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A0015"))
|
||||
elif mariadb_version.major == 10 and mariadb_version.minor == 5 and timezone.now() > timezone.datetime(year=2025, month=6, day=24, tzinfo=timezone.utc):
|
||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A016"))
|
||||
elif mariadb_version.major == 10 and mariadb_version.minor in [0, 1, 2, 3, 4, 7, 9, 10]: # Demote versions down here once EOL
|
||||
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A017"))
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
@register()
|
||||
def system_package_sqlite(app_configs, **kwargs) -> List[CheckMessage]:
|
||||
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":
|
||||
if connection.settings_dict["OPTIONS"]["charset"] != "utf8mb4":
|
||||
errors.append(Error("SQL Charset is not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
|
||||
# This hasn't actually been set on AA yet
|
||||
# if connection.settings_dict["OPTIONS"]["charset"] != "utf8mb4_unicode_ci":
|
||||
# errors.append(Error("SQL Collation is not set correctly", hint="", id="allianceauth.checks.B002"))
|
||||
# if connection.vendor == "sqlite":
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
@register()
|
||||
def celery_settings(app_configs, **kwargs) -> List[CheckMessage]:
|
||||
errors: List[CheckMessage] = []
|
||||
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"))
|
||||
|
||||
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"))
|
||||
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
|
||||
@@ -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 %}
|
||||
<br>
|
||||
<small>{{ subtitle }}</small>
|
||||
<small class="text-muted">{{ subtitle }}</small>
|
||||
{% endif %}
|
||||
</h1>
|
||||
{% endif %}
|
||||
|
||||
@@ -92,6 +92,9 @@
|
||||
<a href="{% url 'groupmanagement:accept_request' acceptrequest.id %}" class="btn btn-success">
|
||||
{% translate "Accept" %}
|
||||
</a>
|
||||
<a href="{% url 'groupmanagement:reject_request' acceptrequest.id %}" class="btn btn-danger">
|
||||
{% translate "Reject" %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
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
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-02-17 20:02+1000\n"
|
||||
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -26,6 +26,15 @@ msgstr ""
|
||||
msgid "Google Analytics V4"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/constants.py:6
|
||||
msgid ""
|
||||
"This software has exceeded the error limit for ESI. If you are a user, "
|
||||
"please contact the maintainer of this software. If you are a developer/"
|
||||
"maintainer, please make a greater effort in the future to receive valid "
|
||||
"responses. For tips on how, come have a chat with us in ##3rd-party-dev-and-"
|
||||
"esi on the EVE Online Discord. https://www.eveonline.com/discord"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/decorators.py:52
|
||||
msgid "A main character is required to perform that action. Add one below."
|
||||
msgstr ""
|
||||
@@ -104,27 +113,34 @@ msgstr ""
|
||||
msgid "Your user's state is now: %(state)s"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:7
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:5
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:7
|
||||
#: allianceauth/menu/templates/menu/sortable-side-menu.html:14
|
||||
#: allianceauth/templates/allianceauth/side-menu.html:10
|
||||
msgid "Dashboard"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:7
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:33
|
||||
#: allianceauth/hrapplications/templates/hrapplications/view.html:54
|
||||
msgid "Characters"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:13
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:14
|
||||
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:13
|
||||
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:14
|
||||
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:4
|
||||
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:6
|
||||
msgid "Add Character"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:16
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:17
|
||||
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:16
|
||||
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:17
|
||||
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:10
|
||||
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:12
|
||||
msgid "Change Main"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:24
|
||||
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:24
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:89
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:23
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groups.html:31
|
||||
@@ -133,32 +149,25 @@ msgstr ""
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:25
|
||||
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:25
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:33
|
||||
msgid "Corp"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:26
|
||||
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:26
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:125
|
||||
#: allianceauth/hrapplications/templates/hrapplications/view.html:63
|
||||
msgid "Alliance"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.groups.html:5
|
||||
#: allianceauth/authentication/templates/authentication/dashboard_groups.html:5
|
||||
msgid "Membership"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.groups.html:8
|
||||
#: allianceauth/authentication/templates/authentication/dashboard_groups.html:8
|
||||
msgid "State:"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:5
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:7
|
||||
#: allianceauth/menu/templates/menu/sortable-side-menu.html:14
|
||||
#: allianceauth/templates/allianceauth/side-menu.html:10
|
||||
msgid "Dashboard"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/tokens.html:6
|
||||
#: allianceauth/authentication/templates/authentication/tokens.html:10
|
||||
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
|
||||
@@ -197,7 +206,7 @@ msgstr ""
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:29
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:28
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:115
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:118
|
||||
msgid "Character"
|
||||
msgstr ""
|
||||
|
||||
@@ -234,49 +243,49 @@ msgstr ""
|
||||
msgid "Invalid or expired activation link."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:147
|
||||
#: allianceauth/authentication/views.py:158
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Cannot change main character to %(char)s: character owned by a different "
|
||||
"account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:153
|
||||
#: allianceauth/authentication/views.py:165
|
||||
#, python-format
|
||||
msgid "Changed main character to %(char)s"
|
||||
msgid "Changed main character to %s"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:162
|
||||
#: allianceauth/authentication/views.py:179
|
||||
#, python-format
|
||||
msgid "Added %(name)s to your account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:164
|
||||
#: allianceauth/authentication/views.py:181
|
||||
#, python-format
|
||||
msgid "Failed to add %(name)s to your account: they already have an account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:207
|
||||
#: allianceauth/authentication/views.py:226
|
||||
msgid ""
|
||||
"Unable to authenticate as the selected character. Please log in with the "
|
||||
"main character associated with this account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:273
|
||||
#: allianceauth/authentication/views.py:293
|
||||
msgid "Registration token has expired."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:331
|
||||
#: allianceauth/authentication/views.py:354
|
||||
msgid ""
|
||||
"Sent confirmation email. Please follow the link to confirm your email "
|
||||
"address."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:336
|
||||
#: allianceauth/authentication/views.py:360
|
||||
msgid "Confirmed your email address. Please login to continue."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:341
|
||||
#: allianceauth/authentication/views.py:366
|
||||
msgid "Registration of new accounts is not allowed at this time."
|
||||
msgstr ""
|
||||
|
||||
@@ -495,7 +504,6 @@ msgstr ""
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:44
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:92
|
||||
#: allianceauth/templates/allianceauth/top-menu.html:23
|
||||
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:17
|
||||
#: allianceauth/timerboard/templates/timerboard/timertable.html:11
|
||||
msgid "Eve Time"
|
||||
msgstr ""
|
||||
@@ -833,7 +841,7 @@ msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:56
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:116
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:119
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:32
|
||||
msgid "Organization"
|
||||
msgstr ""
|
||||
@@ -845,7 +853,7 @@ msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:60
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:85
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:145
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:148
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit_row.html:18
|
||||
msgid "(unknown)"
|
||||
msgstr ""
|
||||
@@ -926,7 +934,7 @@ msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groups.html:36
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:57
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:117
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:120
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:29
|
||||
#: allianceauth/services/modules/openfire/forms.py:6
|
||||
msgid "Group"
|
||||
@@ -980,20 +988,21 @@ msgid "Group Membership"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:93
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:153
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:156
|
||||
msgid "Accept"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:103
|
||||
msgid "No group add requests."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:157
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:96
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:160
|
||||
#: allianceauth/hrapplications/templates/hrapplications/view.html:104
|
||||
msgid "Reject"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:166
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:106
|
||||
msgid "No group add requests."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:169
|
||||
msgid "No group leave requests."
|
||||
msgstr ""
|
||||
|
||||
@@ -1376,6 +1385,8 @@ msgid "Sign Out"
|
||||
msgstr ""
|
||||
|
||||
#: 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"
|
||||
msgstr ""
|
||||
|
||||
@@ -1458,7 +1469,6 @@ msgid "Doctrine"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/optimer/form.py:14
|
||||
#: allianceauth/optimer/templates/optimer/dashboard.ops.html:17
|
||||
#: allianceauth/optimer/templates/optimer/fleetoptable.html:13
|
||||
msgid "Start Time"
|
||||
msgstr ""
|
||||
@@ -1523,6 +1533,11 @@ msgstr ""
|
||||
msgid "Form Up System"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/optimer/templates/optimer/dashboard.ops.html:17
|
||||
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:17
|
||||
msgid "EVE Time"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/optimer/templates/optimer/fleetoptable.html:14
|
||||
#: allianceauth/timerboard/templates/timerboard/timertable.html:12
|
||||
msgid "Local Time"
|
||||
@@ -1568,17 +1583,17 @@ msgstr ""
|
||||
msgid "Update fleet operation"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/optimer/views.py:89
|
||||
#: allianceauth/optimer/views.py:91
|
||||
#, python-format
|
||||
msgid "Created operation timer for %(opname)s."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/optimer/views.py:118
|
||||
#: allianceauth/optimer/views.py:120
|
||||
#, python-format
|
||||
msgid "Removed operation timer for %(opname)s."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/optimer/views.py:169
|
||||
#: allianceauth/optimer/views.py:171
|
||||
#, python-format
|
||||
msgid "Saved changes to operation timer for %(opname)s."
|
||||
msgstr ""
|
||||
@@ -2367,6 +2382,10 @@ msgstr ""
|
||||
msgid "Saved changes to SRP fleet %(fleetname)s"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/templates/allianceauth/admin-status/esi_check.html:4
|
||||
msgid "Your Server received an ESI error response code of "
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/templates/allianceauth/admin-status/overview.html:11
|
||||
msgid "Alliance Auth Notifications"
|
||||
msgstr ""
|
||||
@@ -2693,12 +2712,12 @@ msgstr ""
|
||||
msgid "Past Timers"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/timerboard/views.py:78
|
||||
#: allianceauth/timerboard/views.py:85
|
||||
#, python-format
|
||||
msgid "Added new timer in %(system)s at %(time)s."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/timerboard/views.py:87
|
||||
#: allianceauth/timerboard/views.py:95
|
||||
msgid "Saved changes to the timer."
|
||||
msgstr ""
|
||||
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
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
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@
|
||||
{% endif %}>
|
||||
</i>
|
||||
<a
|
||||
class="nav-link flex-fill align-self-center me-auto"
|
||||
class="nav-link flex-fill align-self-center me-auto {% if item.navactive %}{% navactive request item.navactive|join:' ' %}{% endif %}"
|
||||
{% if item.is_folder %}
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
|
||||
@@ -60,15 +60,17 @@
|
||||
<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>
|
||||
</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>
|
||||
<a class="dropdown-item" href="{% url 'admin:index' %}">
|
||||
<i class="fa-solid fa-gear fa-fw"></i> {% translate "Admin" %}
|
||||
</a>
|
||||
<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>
|
||||
{% 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>
|
||||
{% if user.is_authenticated %}
|
||||
<li>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<ul id="sidebar-menu" class="navbar-nav flex-column mb-auto overflow-auto pt-2">
|
||||
<li class="d-flex flex-wrap m-2 p-2 pt-0 pb-0 mt-0 mb-0 me-0 pe-0">
|
||||
<i class="nav-link fas fa-tachometer-alt fa-fw align-self-center me-3 {% navactive request 'authentication:dashboard' %}"></i>
|
||||
<a class="nav-link flex-fill align-self-center" href="{% url 'authentication:dashboard' %}">
|
||||
<a class="nav-link flex-fill align-self-center {% navactive request 'authentication:dashboard' %}" href="{% url 'authentication:dashboard' %}">
|
||||
{% translate "Dashboard" %}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -98,6 +98,10 @@ def render_menu(request: HttpRequest) -> List[RenderedMenuItem]:
|
||||
|
||||
if item.is_app_item:
|
||||
rendered_item = _render_app_item(request, hook_items, item, bs5_template)
|
||||
if rendered_item.html == "":
|
||||
# If there is no content dont render it.
|
||||
# This item has probably been hidden by permissions
|
||||
continue
|
||||
elif item.is_link_item:
|
||||
rendered_item = _render_link_item(request, item, bs5_template)
|
||||
elif item.is_folder:
|
||||
|
||||
@@ -19,6 +19,11 @@ def create_user(permissions=None, **kwargs) -> User:
|
||||
return user
|
||||
|
||||
|
||||
def create_menu_item_hook_class(**kwargs) -> MenuItemHook:
|
||||
num = next(counter_menu_item_hook)
|
||||
return type(f"GeneratedMenuItem{num}", (MenuItemHook,), {})
|
||||
|
||||
|
||||
def create_menu_item_hook(**kwargs) -> MenuItemHook:
|
||||
num = next(counter_menu_item_hook)
|
||||
new_class = type(f"GeneratedMenuItem{num}", (MenuItemHook,), {})
|
||||
|
||||
@@ -14,6 +14,7 @@ from allianceauth.menu.tests.factories import (
|
||||
create_folder_menu_item,
|
||||
create_link_menu_item,
|
||||
create_menu_item_from_hook,
|
||||
create_menu_item_hook_class,
|
||||
create_menu_item_hook_function,
|
||||
create_rendered_menu_item,
|
||||
)
|
||||
@@ -177,6 +178,44 @@ class TestRenderDefaultMenu(TestCase):
|
||||
self.assertEqual(menu[0].menu_item.text, "Alpha")
|
||||
self.assertEqual(menu[1].menu_item.text, "Bravo")
|
||||
|
||||
def test_should_remove_empty_folders_with_items_hidden(self, mock_get_hooks):
|
||||
# given
|
||||
|
||||
class TestHook(create_menu_item_hook_class()):
|
||||
text = "Dummy App No Data"
|
||||
classes = "fa-solid fa-users-gear"
|
||||
url_name = "groupmanagement:management"
|
||||
|
||||
def render(Self, request):
|
||||
# simulate no perms
|
||||
return ""
|
||||
|
||||
params = {
|
||||
"text": "Alpha",
|
||||
"classes": "fa-solid fa-users-gear",
|
||||
"url_name": "groupmanagement:management",
|
||||
}
|
||||
|
||||
alpha = TestHook(**params)
|
||||
|
||||
hooks = [lambda: alpha]
|
||||
|
||||
mock_get_hooks.return_value = hooks
|
||||
|
||||
folder = create_folder_menu_item(text="Folder", order=2)
|
||||
create_menu_item_from_hook(hooks[0], parent=folder)
|
||||
create_link_menu_item(text="Bravo", order=3) # this is all that should show
|
||||
|
||||
request = self.factory.get("/")
|
||||
|
||||
# when
|
||||
result = render_menu(request)
|
||||
|
||||
# then
|
||||
menu = list(result)
|
||||
self.assertEqual(len(menu), 1)
|
||||
self.assertEqual(menu[0].menu_item.text, "Bravo")
|
||||
|
||||
def test_should_not_include_hidden_items(self, mock_get_hooks):
|
||||
# given
|
||||
mock_get_hooks.return_value = []
|
||||
@@ -196,7 +235,6 @@ class TestRenderDefaultMenu(TestCase):
|
||||
self.assertEqual(menu[1].menu_item.text, "Charlie")
|
||||
|
||||
def test_should_not_render_hidden_folders(self, mock_get_hooks):
|
||||
# given
|
||||
# given
|
||||
menu = [
|
||||
create_menu_item_hook_function(text="Charlie", count=42),
|
||||
|
||||
@@ -1,41 +1,40 @@
|
||||
{% load i18n %}
|
||||
{% 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-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 style="height: 300px; overflow-y:auto;">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<div>
|
||||
<table class="table">
|
||||
<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>
|
||||
<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 "Start Time" %}</th>
|
||||
<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>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,9 +14,11 @@ from .models import OpTimer, OpTimerType
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
OPS_VIEW_PERMISSION = 'auth.optimer_view'
|
||||
OPS_MANAGE_PERMISSION = 'auth.optimer_management'
|
||||
|
||||
@login_required
|
||||
@permission_required('auth.optimer_view')
|
||||
@permission_required(OPS_VIEW_PERMISSION)
|
||||
def optimer_view(request):
|
||||
"""
|
||||
View for the optimer management page
|
||||
@@ -39,7 +41,7 @@ def optimer_view(request):
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required('auth.optimer_management')
|
||||
@permission_required(OPS_MANAGE_PERMISSION)
|
||||
def add_optimer_view(request):
|
||||
"""
|
||||
View for the add optimer page
|
||||
@@ -98,7 +100,7 @@ def add_optimer_view(request):
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required('auth.optimer_management')
|
||||
@permission_required(OPS_MANAGE_PERMISSION)
|
||||
def remove_optimer(request, optimer_id):
|
||||
"""
|
||||
Remove optimer
|
||||
@@ -121,7 +123,7 @@ def remove_optimer(request, optimer_id):
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required('auth.optimer_management')
|
||||
@permission_required(OPS_MANAGE_PERMISSION)
|
||||
def edit_optimer(request, optimer_id):
|
||||
"""
|
||||
Edit optimer
|
||||
@@ -192,14 +194,22 @@ def dashboard_ops(request):
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
if request.user.has_perm(OPS_VIEW_PERMISSION):
|
||||
base_query = OpTimer.objects.select_related('eve_character', 'type')
|
||||
timers = base_query.filter(
|
||||
start__gte=timezone.now()
|
||||
)[:5]
|
||||
|
||||
base_query = OpTimer.objects.select_related('eve_character', 'type')
|
||||
timers = base_query.filter(start__gte=timezone.now())[:5]
|
||||
|
||||
if timers.count():
|
||||
context = {
|
||||
'timers': timers,
|
||||
}
|
||||
return render_to_string('optimer/dashboard.ops.html', context=context, request=request)
|
||||
if timers.count():
|
||||
context = {
|
||||
'timers': timers,
|
||||
}
|
||||
return render_to_string(
|
||||
'optimer/dashboard.ops.html',
|
||||
context=context,
|
||||
request=request
|
||||
)
|
||||
else:
|
||||
return ""
|
||||
else:
|
||||
return ""
|
||||
|
||||
@@ -102,6 +102,7 @@ LANGUAGES = (
|
||||
("ja", "Japanese"),
|
||||
("it", "Italian"),
|
||||
("uk", "Ukrainian"),
|
||||
("pl", "Polish"),
|
||||
)
|
||||
|
||||
TEMPLATES = [
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% 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">
|
||||
<p class="text-center ">{% translate 'Your Server received an ESI error response code of ' %}<b id="esi-code">?</b></p>
|
||||
<hr>
|
||||
@@ -23,7 +23,7 @@
|
||||
console.log("ESI Check: ", JSON.stringify(responseJson, null, 2));
|
||||
|
||||
const status = responseJson.status;
|
||||
if (status != 200) {
|
||||
if (status !== 200) {
|
||||
elemCode.textContent = status
|
||||
elemMessage.textContent = responseJson.data.error;
|
||||
new bootstrap.Collapse(elemCard, {
|
||||
|
||||
@@ -2,48 +2,43 @@
|
||||
{% load humanize %}
|
||||
|
||||
{% 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-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="w-100 align-self-stretch">
|
||||
<h4 class="ms-auto me-auto text-center">
|
||||
{% translate "Alliance Auth Notifications" %}
|
||||
</h4>
|
||||
{% translate "Alliance Auth Notifications" as widget_title %}
|
||||
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||
|
||||
<div class="card-body">
|
||||
<ul class="list-group">
|
||||
{% for notif in notifications %}
|
||||
<li class="list-group-item">
|
||||
{% if notif.state == 'opened' %}
|
||||
<span class="badge bg-success">{% translate "Open" %}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-danger">{% translate "Closed" %}</span>
|
||||
{% endif %}
|
||||
<a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a>
|
||||
</li>
|
||||
{% empty %}
|
||||
<div class="alert alert-primary" role="alert">
|
||||
{% 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>
|
||||
<ul class="list-group">
|
||||
{% for notif in notifications %}
|
||||
<li class="list-group-item">
|
||||
{% if notif.state == 'opened' %}
|
||||
<span class="badge bg-success">{% translate "Open" %}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-danger">{% translate "Closed" %}</span>
|
||||
{% endif %}
|
||||
<a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a>
|
||||
</li>
|
||||
{% empty %}
|
||||
<div class="alert alert-primary" role="alert">
|
||||
{% translate "No notifications at this time" %}
|
||||
</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>
|
||||
@@ -51,25 +46,24 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="col-12 align-self-stretch pb-2">
|
||||
<div class="col-12 mb-3">
|
||||
<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">
|
||||
<h4 class="ms-auto me-auto text-center">
|
||||
{% translate "Software Version" %}
|
||||
</h4>
|
||||
{% translate "Software Version" as widget_title %}
|
||||
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<ul class="list-group list-group-horizontal w-100" role="group" aria-label="{% translate 'Software Version' %}">
|
||||
<li class="list-group-item w-100">
|
||||
<div class="btn w-100 cursor-default">
|
||||
<div class="btn h-100 w-100 cursor-default">
|
||||
<h5 class="list-group-item-heading">{% translate "Current" %}</h5>
|
||||
<p class="list-group-item-text">{{ current_version }}</p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="list-group-item bg-{% if latest_patch %}success{% elif latest_minor %}warning{% else %}danger{% endif %} w-100">
|
||||
<a class="btn w-100" href="https://gitlab.com/allianceauth/allianceauth/-/releases/v{{ latest_patch_version }}">
|
||||
<a class="btn h-100 w-100" href="https://gitlab.com/allianceauth/allianceauth/-/releases/v{{ latest_patch_version }}">
|
||||
<h5 class="list-group-item-heading">{% translate "Latest Stable" %}</h5>
|
||||
|
||||
<p class="list-group-item-text">
|
||||
@@ -82,7 +76,7 @@
|
||||
|
||||
{% if latest_beta %}
|
||||
<li class="list-group-item bg-info w-100">
|
||||
<a class="btn w-100" href="https://gitlab.com/allianceauth/allianceauth/-/releases/v{{ latest_beta_version }}">
|
||||
<a class="btn h-100 w-100" href="https://gitlab.com/allianceauth/allianceauth/-/releases/v{{ latest_beta_version }}">
|
||||
<h5 class="list-group-item-heading">{% translate "Latest Pre-Release" %}</h5>
|
||||
|
||||
<p class="list-group-item-text">
|
||||
@@ -98,11 +92,10 @@
|
||||
</div>
|
||||
|
||||
<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" %}
|
||||
</h4>
|
||||
{% translate "Task Queue" as widget_title %}
|
||||
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<p>
|
||||
{% blocktranslate with total=tasks_total|intcomma latest=earliest_task|timesince|default:"?" %}
|
||||
Status of {{ total }} processed tasks • last {{ latest }}
|
||||
|
||||
@@ -29,56 +29,53 @@
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
.nav-padding {
|
||||
padding-top: {% header_padding_size %} !important;
|
||||
}
|
||||
{% endif %}
|
||||
.nav-padding {
|
||||
padding-top: {% header_padding_size %} !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% block extra_css %}{% endblock extra_css %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% if user.is_authenticated %}
|
||||
<!-- Top Menu, Blocks don't work in "include" tagged views -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark fixed-top bg-primary">
|
||||
<div class="container-fluid justify-content-start">
|
||||
{% if user.is_authenticated %}
|
||||
<a class="navbar-brand" data-bs-toggle="collapse" data-bs-target="#sidebar" role="button">
|
||||
<i class="fa-solid fa-bars ms-2 me-2"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
<!-- Top Menu, Blocks don't work in "include" tagged views -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark fixed-top bg-primary">
|
||||
<div class="container-fluid justify-content-start">
|
||||
<a class="navbar-brand" data-bs-toggle="collapse" data-bs-target="#sidebar" role="button">
|
||||
<i class="fa-solid fa-bars ms-2 me-2"></i>
|
||||
</a>
|
||||
|
||||
<div class="navbar-brand">
|
||||
{% 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 class="navbar-brand">
|
||||
{% block header_nav_brand %}{{ SITE_NAME }}{% endblock %}
|
||||
</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 -->
|
||||
|
||||
<!-- Body -->
|
||||
@@ -98,23 +95,27 @@
|
||||
|
||||
<script>
|
||||
(() => {
|
||||
// TODO Extend this to the groups in the sidebar too.
|
||||
// TODO Move to own JS file
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
|
||||
sidebar.addEventListener("shown.bs.collapse", () => {
|
||||
localStorage.removeItem("sidebar_" + sidebar.id);
|
||||
sidebar.addEventListener('shown.bs.collapse', () => {
|
||||
localStorage.removeItem('sidebar_' + sidebar.id);
|
||||
});
|
||||
|
||||
sidebar.addEventListener("hidden.bs.collapse", () => {
|
||||
localStorage.setItem("sidebar_" + sidebar.id, true);
|
||||
sidebar.addEventListener('hidden.bs.collapse', () => {
|
||||
localStorage.setItem('sidebar_' + sidebar.id, 'closed');
|
||||
});
|
||||
|
||||
if (localStorage.getItem("sidebar_" + sidebar.id) === "true") {
|
||||
sidebar.classList.remove("show")
|
||||
if (localStorage.getItem('sidebar_' + sidebar.id) === 'closed') {
|
||||
sidebar.classList.remove('show')
|
||||
} else {
|
||||
sidebar.classList.add("show")
|
||||
}
|
||||
|
||||
const activeChildMenuItem = document.querySelector('#sidebar-menu li ul li a.active');
|
||||
if (activeChildMenuItem) {
|
||||
activeChildMenuItem.parentElement.parentElement.classList.add('show');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,31 +1,37 @@
|
||||
{% extends "allianceauth/base-bs5.html" %}
|
||||
|
||||
{% load theme_tags %}
|
||||
|
||||
{% block page_title %}
|
||||
{{ error_title }}
|
||||
{% endblock page_title %}
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
{% include "framework/header/page-header.html" with title=error_title %}
|
||||
<div class="d-flex flex-column" style="height: calc(100vh - {% header_padding_size %}); margin-top: -1rem; margin-bottom: -1rem;">
|
||||
<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">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="150"
|
||||
height="150"
|
||||
fill="currentColor"
|
||||
class="bi bi-exclamation-triangle"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<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"
|
||||
/>
|
||||
<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"
|
||||
/>
|
||||
</svg>
|
||||
<div class="text-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="150"
|
||||
height="150"
|
||||
fill="currentColor"
|
||||
class="bi bi-exclamation-triangle"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<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"
|
||||
/>
|
||||
<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"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<p class="text-center">{{ error_message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-center">{{ error_message }}</p>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% load i18n %}
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<li class="nav-item">
|
||||
<a href="{% url 'authentication:add_character' %}" class="nav-link" title="{% translate 'Add Character' %}">
|
||||
<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>
|
||||
</a>
|
||||
</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 %}
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.apps import AppConfig
|
||||
class BootstrapThemeConfig(AppConfig):
|
||||
name = "allianceauth.theme.bootstrap"
|
||||
label = "bootstrap"
|
||||
version = "5.3.0"
|
||||
version = "5.3.3"
|
||||
verbose_name = f"Bootstrap v{version}"
|
||||
|
||||
def ready(self):
|
||||
|
||||
@@ -3,16 +3,16 @@ from allianceauth.theme.hooks import ThemeHook
|
||||
|
||||
|
||||
CSS_STATICS = [{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css",
|
||||
"integrity": "sha512-b2QcS5SsA8tZodcDtGRELiGv5SaKSk1vDHDaQRda0htPYWZ6046lr3kJ5bAAQdpV2mmA/4v0wQF9MyU6/pDIAg=="
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css",
|
||||
"integrity": "sha512-jnSuA4Ss2PkkikSOLtYs8BlYIeeIK1h99ty4YfvRPAlzr377vr3CXDb7sb7eEEBYjDtcYj+AjBH3FLv5uSJuXg=="
|
||||
}]
|
||||
|
||||
JS_STATICS = [{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
|
||||
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
|
||||
}, {
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.min.js",
|
||||
"integrity": "sha512-WW8/jxkELe2CAiE4LvQfwm1rajOS8PHasCCx+knHG0gBHt8EXxS6T6tJRTGuDQVnluuAvMxWF4j8SNFDKceLFg=="
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js",
|
||||
"integrity": "sha512-ykZ1QQr0Jy/4ZkvKuqWn4iF3lqPZyij9iRv6sGqLRdTPkY69YX6+7wvVGmsdBbiIfN/8OdsI7HABjvEok6ZopQ=="
|
||||
}]
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.apps import AppConfig
|
||||
class DarklyThemeConfig(AppConfig):
|
||||
name = "allianceauth.theme.darkly"
|
||||
label = "darkly"
|
||||
version = "5.3.0"
|
||||
version = "5.3.3"
|
||||
verbose_name = f"Bootswatch Darkly v{version}"
|
||||
|
||||
def ready(self):
|
||||
|
||||
@@ -14,15 +14,15 @@ class DarklyThemeHook(ThemeHook):
|
||||
"Darkly",
|
||||
"Flatly in night mode!",
|
||||
css=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.2.3/darkly/bootstrap.min.css",
|
||||
"integrity": "sha512-YRcmztDXzJQCCBk2YUiEAY+r74gu/c9UULMPTeLsAp/Tw5eXiGkYMPC4tc4Kp1jx/V9xjEOCVpBe4r6Lx6n5dA=="
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.3/darkly/bootstrap.min.css",
|
||||
"integrity": "sha512-HDszXqSUU0om4Yj5dZOUNmtwXGWDa5ppESlX98yzbBS+z+3HQ8a/7kcdI1dv+jKq+1V5b01eYurE7+yFjw6Rdg=="
|
||||
}],
|
||||
js=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
|
||||
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
|
||||
}, {
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/js/bootstrap.min.js",
|
||||
"integrity": "sha512-1/RvZTcCDEUjY/CypiMz+iqqtaoQfAITmNSJY17Myp4Ms5mdxPS5UV7iOfdZoxcGhzFbOm6sntTKJppjvuhg4g=="
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js",
|
||||
"integrity": "sha512-ykZ1QQr0Jy/4ZkvKuqWn4iF3lqPZyij9iRv6sGqLRdTPkY69YX6+7wvVGmsdBbiIfN/8OdsI7HABjvEok6ZopQ=="
|
||||
}],
|
||||
header_padding="4.5em"
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.apps import AppConfig
|
||||
class FlatlyThemeConfig(AppConfig):
|
||||
name = "allianceauth.theme.flatly"
|
||||
label = "flatly"
|
||||
version = "5.3.0"
|
||||
version = "5.3.3"
|
||||
verbose_name = f"Bootswatch Flatly v{version}"
|
||||
|
||||
def ready(self):
|
||||
|
||||
@@ -14,15 +14,15 @@ class FlatlyThemeHook(ThemeHook):
|
||||
"Flatly",
|
||||
"Flat and modern!",
|
||||
css=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.2/flatly/bootstrap.min.css",
|
||||
"integrity": "sha512-rx+BMEjKes84XHg1erhvtq7Mqxm/lm6w4WMoCtDAaTMtUzT5iK5hNTu8mc2+yPNSldAX5hheN/ZhtNQjjYy5nA=="
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.3/flatly/bootstrap.min.css",
|
||||
"integrity": "sha512-qoT4KwnRpAQ9uczPsw7GunsNmhRnYwSlE2KRCUPRQHSkDuLulCtDXuC2P/P6oqr3M5hoGagUG9pgHDPkD2zCDA=="
|
||||
}],
|
||||
js=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
|
||||
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
|
||||
}, {
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.min.js",
|
||||
"integrity": "sha512-WW8/jxkELe2CAiE4LvQfwm1rajOS8PHasCCx+knHG0gBHt8EXxS6T6tJRTGuDQVnluuAvMxWF4j8SNFDKceLFg=="
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js",
|
||||
"integrity": "sha512-ykZ1QQr0Jy/4ZkvKuqWn4iF3lqPZyij9iRv6sGqLRdTPkY69YX6+7wvVGmsdBbiIfN/8OdsI7HABjvEok6ZopQ=="
|
||||
}],
|
||||
header_padding="4.5em"
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.apps import AppConfig
|
||||
class MateriaThemeConfig(AppConfig):
|
||||
name = "allianceauth.theme.materia"
|
||||
label = "materia"
|
||||
version = "5.3.0"
|
||||
version = "5.3.3"
|
||||
verbose_name = f"Bootswatch Materia v{version}"
|
||||
|
||||
def ready(self):
|
||||
|
||||
@@ -14,15 +14,15 @@ class MateriaThemeHook(ThemeHook):
|
||||
"Materia",
|
||||
"Material is the metaphor",
|
||||
css=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.2/materia/bootstrap.min.css",
|
||||
"integrity": "sha512-4+PCWoNUxEeasuW2ipP8Avsr7X/oS61Kz2CLdwS6ZfHt7jLuzAAcIfPlWLg4aGaDNo0GSmTOmM9biaqnmo6P7g=="
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.3/materia/bootstrap.min.css",
|
||||
"integrity": "sha512-2S9Do+uTmZmmJpdmAcOKdUrK/YslcvAuRfIF2ws8+BW9AvZXMRZM+o8Wq+PZrfISD6ZlIaeCWWZAdeprXIoYuQ=="
|
||||
}],
|
||||
js=[{
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
|
||||
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
|
||||
}, {
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.min.js",
|
||||
"integrity": "sha512-WW8/jxkELe2CAiE4LvQfwm1rajOS8PHasCCx+knHG0gBHt8EXxS6T6tJRTGuDQVnluuAvMxWF4j8SNFDKceLFg=="
|
||||
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js",
|
||||
"integrity": "sha512-ykZ1QQr0Jy/4ZkvKuqWn4iF3lqPZyij9iRv6sGqLRdTPkY69YX6+7wvVGmsdBbiIfN/8OdsI7HABjvEok6ZopQ=="
|
||||
}],
|
||||
header_padding="5.25em"
|
||||
)
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
{% load i18n %}
|
||||
{% 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-body">
|
||||
<h4 class="card-title text-center">{% translate "Upcoming Timers" %}</h4>
|
||||
<div class="card-body">
|
||||
<div style="height: 300px; overflow-y:auto;">
|
||||
<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>
|
||||
{% translate "Upcoming Timers" as widget_title %}
|
||||
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
|
||||
|
||||
<tbody>
|
||||
{% for timer in timers %}
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
{{ timer.details }}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
{{ timer.get_timer_type_display }}
|
||||
</td>
|
||||
<td class="text-center" nowrap>
|
||||
{% if timer.objective == "Hostile" %}
|
||||
<div class="badge bg-danger">
|
||||
{% translate "Hostile" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.objective == "Friendly" %}
|
||||
<div class="badge bg-primary">
|
||||
{% translate "Friendly" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.objective == "Neutral" %}
|
||||
<div class="badge bg-default">
|
||||
{% translate "Neutral" %}
|
||||
</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>
|
||||
<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>
|
||||
{% for timer in timers %}
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
{{ timer.details }}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
{{ timer.get_timer_type_display }}
|
||||
</td>
|
||||
<td class="text-center" nowrap>
|
||||
{% if timer.objective == "Hostile" %}
|
||||
<div class="badge bg-danger">
|
||||
{% translate "Hostile" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.objective == "Friendly" %}
|
||||
<div class="badge bg-primary">
|
||||
{% translate "Friendly" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.objective == "Neutral" %}
|
||||
<div class="badge bg-default">
|
||||
{% translate "Neutral" %}
|
||||
</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>
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
{% for timer in timers %}
|
||||
{% if timer.important == True %}
|
||||
<tr class="danger">
|
||||
<tr class="bg-danger bg-opacity-25">
|
||||
{% else %}
|
||||
<tr class="info">
|
||||
<tr class="bg-info bg-opacity-25">
|
||||
{% endif %}
|
||||
|
||||
<td style="width: 150px;" class="text-center">
|
||||
|
||||
@@ -20,6 +20,9 @@ from allianceauth.timerboard.models import Timer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TIMER_VIEW_PERMISSION = 'auth.timer_view'
|
||||
TIMER_MANAGE_PERMISSION = 'auth.timer_management'
|
||||
|
||||
|
||||
class BaseTimerView(LoginRequiredMixin, PermissionRequiredMixin, View):
|
||||
pass
|
||||
@@ -27,7 +30,7 @@ class BaseTimerView(LoginRequiredMixin, PermissionRequiredMixin, View):
|
||||
|
||||
class TimerView(BaseTimerView):
|
||||
template_name = 'timerboard/view.html'
|
||||
permission_required = 'auth.timer_view'
|
||||
permission_required = TIMER_VIEW_PERMISSION
|
||||
|
||||
def get(self, request):
|
||||
logger.debug(f"timer_view called by user {request.user}")
|
||||
@@ -48,7 +51,7 @@ class TimerView(BaseTimerView):
|
||||
|
||||
|
||||
class TimerManagementView(BaseTimerView):
|
||||
permission_required = 'auth.timer_management'
|
||||
permission_required = TIMER_MANAGE_PERMISSION
|
||||
index_redirect = 'timerboard:view'
|
||||
success_url = reverse_lazy(index_redirect)
|
||||
model = Timer
|
||||
@@ -74,8 +77,13 @@ class AddTimerView(TimerManagementView, AddUpdateMixin, CreateView):
|
||||
def form_valid(self, form):
|
||||
result = super().form_valid(form)
|
||||
timer = self.object
|
||||
logger.info(f"Created new timer in {timer.system} at {timer.eve_time} by user {self.request.user}")
|
||||
messages.success(self.request, _('Added new timer in %(system)s at %(time)s.') % {"system": timer.system, "time": timer.eve_time})
|
||||
logger.info(
|
||||
f"Created new timer in {timer.system} at {timer.eve_time} by user {self.request.user}"
|
||||
)
|
||||
messages.success(
|
||||
self.request,
|
||||
_('Added new timer in %(system)s at %(time)s.') % {"system": timer.system, "time": timer.eve_time}
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@@ -89,22 +97,33 @@ class EditTimerView(TimerManagementView, AddUpdateMixin, UpdateView):
|
||||
|
||||
|
||||
class RemoveTimerView(TimerManagementView, DeleteView):
|
||||
form_class = TimerForm
|
||||
pass
|
||||
|
||||
|
||||
def dashboard_timers(request):
|
||||
try:
|
||||
corp = request.user.profile.main_character.corporation
|
||||
except (EveCorporationInfo.DoesNotExist, AttributeError):
|
||||
return ""
|
||||
if request.user.has_perm(TIMER_VIEW_PERMISSION):
|
||||
try:
|
||||
corp = request.user.profile.main_character.corporation
|
||||
except (EveCorporationInfo.DoesNotExist, AttributeError):
|
||||
return ""
|
||||
|
||||
timers = Timer.objects.select_related('eve_character').filter((Q(eve_corp__isnull=True) | Q(eve_corp=corp)) ,eve_time__gte=timezone.now())[:5]
|
||||
timers = Timer.objects.select_related(
|
||||
'eve_character'
|
||||
).filter(
|
||||
(Q(corp_timer=True) & Q(eve_corp=corp)) | Q(corp_timer=False),
|
||||
eve_time__gte=timezone.now()
|
||||
)[:5]
|
||||
|
||||
if timers.count():
|
||||
context = {
|
||||
'timers': timers,
|
||||
}
|
||||
if timers.count():
|
||||
context = {
|
||||
'timers': timers,
|
||||
}
|
||||
|
||||
return render_to_string(template_name='timerboard/dashboard.timers.html', context=context, request=request)
|
||||
return render_to_string(
|
||||
template_name='timerboard/dashboard.timers.html',
|
||||
context=context, request=request
|
||||
)
|
||||
else:
|
||||
return ""
|
||||
else:
|
||||
return ""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PROTOCOL=https://
|
||||
AUTH_SUBDOMAIN=%AUTH_SUBDOMAIN%
|
||||
DOMAIN=%DOMAIN%
|
||||
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v4.0.0b2
|
||||
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v4.2.0
|
||||
|
||||
# Nginx Proxy Manager
|
||||
PROXY_HTTP_PORT=80
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FROM python:3.11-slim
|
||||
ARG AUTH_VERSION=v4.0.0b2
|
||||
ARG AUTH_VERSION=v4.2.0
|
||||
ARG AUTH_PACKAGE=allianceauth==${AUTH_VERSION}
|
||||
ENV AUTH_USER=allianceauth
|
||||
ENV AUTH_GROUP=allianceauth
|
||||
@@ -9,21 +9,21 @@ ENV AUTH_HOME=/home/allianceauth
|
||||
|
||||
# Setup user and directory permissions
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
RUN groupadd -g 61000 ${AUTH_GROUP}
|
||||
RUN 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}
|
||||
RUN groupadd -g 61000 ${AUTH_GROUP} && \
|
||||
useradd -g 61000 -l -m -s /bin/false -u 61000 ${AUTH_USER}
|
||||
|
||||
# Install build dependencies
|
||||
RUN apt-get update && apt-get upgrade -y && apt-get install -y \
|
||||
libmariadb-dev gcc git pkg-config
|
||||
RUN mkdir -p ${STATIC_BASE}/myauth/static \
|
||||
&& chown ${AUTH_USERGROUP} ${STATIC_BASE}/myauth/static
|
||||
|
||||
# Install python dependencies
|
||||
RUN pip install --upgrade pip
|
||||
RUN pip install wheel gunicorn
|
||||
RUN pip install ${AUTH_PACKAGE}
|
||||
# Install Build Dependencies
|
||||
RUN apt-get update \
|
||||
&& apt-get upgrade -y \
|
||||
&& 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
|
||||
USER ${AUTH_USER}
|
||||
@@ -33,7 +33,6 @@ WORKDIR ${AUTH_HOME}
|
||||
RUN allianceauth start myauth
|
||||
COPY /allianceauth/project_template/project_name/settings/local.py ${AUTH_HOME}/myauth/myauth/settings/local.py
|
||||
RUN allianceauth update myauth
|
||||
RUN mkdir -p ${STATIC_BASE}/myauth/static
|
||||
|
||||
RUN echo 'alias auth="python $AUTH_HOME/myauth/manage.py"' >> ~/.bashrc && \
|
||||
source ~/.bashrc
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
server {
|
||||
listen 80;
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location /static {
|
||||
alias /var/www/myauth/static;
|
||||
autoindex off;
|
||||
}
|
||||
events {}
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
location /robots.txt {
|
||||
alias /var/www/myauth/static/robots.txt;
|
||||
}
|
||||
sendfile on;
|
||||
|
||||
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;
|
||||
server {
|
||||
listen 80;
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location /static {
|
||||
alias /var/www/myauth/static;
|
||||
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
|
||||
FROM $AA_DOCKER_TAG
|
||||
|
||||
RUN cd /home/allianceauth
|
||||
WORKDIR ${AUTH_HOME}
|
||||
|
||||
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"
|
||||
|
||||
nginx:
|
||||
image: nginx:1.25
|
||||
image: nginx:stable
|
||||
restart: always
|
||||
volumes:
|
||||
- ./conf/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
- ./conf/nginx.conf:/etc/nginx/nginx.conf
|
||||
- static-volume:/var/www/myauth/static
|
||||
depends_on:
|
||||
- allianceauth_gunicorn
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 85 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB |
35
docs/_static/css/rtd_dark.css
vendored
35
docs/_static/css/rtd_dark.css
vendored
@@ -24,8 +24,13 @@
|
||||
color: aliceblue;
|
||||
}
|
||||
|
||||
.method dt, .class dt, .data dt, .attribute dt, .function dt,
|
||||
.descclassname, .descname {
|
||||
.method dt,
|
||||
.class dt,
|
||||
.data dt,
|
||||
.attribute dt,
|
||||
.function dt,
|
||||
.descclassname,
|
||||
.descname {
|
||||
background-color: #525252 !important;
|
||||
color: white !important;
|
||||
}
|
||||
@@ -51,11 +56,13 @@
|
||||
background-color: #2b2b2b !important;
|
||||
}
|
||||
|
||||
.xref, .py-meth {
|
||||
.xref,
|
||||
.py-meth {
|
||||
color: #7ec3e6 !important;
|
||||
}
|
||||
|
||||
.admonition, .note {
|
||||
.admonition,
|
||||
.note {
|
||||
background-color: #2d2d2d !important;
|
||||
}
|
||||
|
||||
@@ -64,19 +71,27 @@
|
||||
border-bottom: 1px solid #fcfcfc;
|
||||
}
|
||||
|
||||
.wy-table thead, .rst-content table.docutils thead, .rst-content table.field-list thead {
|
||||
.wy-table thead,
|
||||
.rst-content table.docutils thead,
|
||||
.rst-content table.field-list thead {
|
||||
background-color: #b9b9b9;
|
||||
}
|
||||
|
||||
.wy-table thead th, .rst-content table.docutils thead th, .rst-content table.field-list thead th {
|
||||
.wy-table thead th,
|
||||
.rst-content table.docutils thead th,
|
||||
.rst-content table.field-list thead th {
|
||||
border: solid 2px #e1e4e5;
|
||||
}
|
||||
|
||||
.wy-table thead p, .rst-content table.docutils thead p, .rst-content table.field-list thead p {
|
||||
.wy-table thead p,
|
||||
.rst-content table.docutils thead p,
|
||||
.rst-content table.field-list thead p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wy-table-odd td, .wy-table-striped tr:nth-child(2n-1) td, .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
|
||||
.wy-table-odd td,
|
||||
.wy-table-striped tr:nth-child(2n-1) td,
|
||||
.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
|
||||
background-color: #343131;
|
||||
}
|
||||
|
||||
@@ -91,10 +106,6 @@
|
||||
|
||||
/* Name.Variable */
|
||||
|
||||
body {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.rst-content .section .admonition ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ from allianceauth.framework.api.evecharacter import get_user_from_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.
|
||||
|
||||
## 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.
|
||||
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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
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):
|
||||
|
||||
@@ -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
|
||||
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
|
||||
|
||||
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 %}
|
||||
<div>
|
||||
{% 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>
|
||||
</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.
|
||||
|
||||
#### 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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ The `MenuItemHook` class specifies some parameters/instance variables required f
|
||||
:undoc-members:
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
### text
|
||||
|
||||
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/')
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
#### urls
|
||||
|
||||
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}
|
||||
If you already have a Discord server, skip the creation step, but be sure to retrieve the server ID
|
||||
:::
|
||||
|
||||
### Registering an 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::
|
||||
For more information see :ref:`ref-reserved-group-names`.
|
||||
```
|
||||
|
||||
## Tasks
|
||||
|
||||
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
|
||||
======================== ====================================================
|
||||
```
|
||||
|
||||
:::{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.
|
||||
:::
|
||||
@@ -156,6 +159,7 @@ Name Description
|
||||
`DISCORD_TASKS_MAX_RETRIES` max retries of tasks after an error occurred `3`
|
||||
=================================== ============================================================================================= =======
|
||||
```
|
||||
|
||||
## Permissions
|
||||
|
||||
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 |
|
||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Unknown Error" on Discord site when activating service
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
discord
|
||||
discourse
|
||||
mumble
|
||||
mumble-docker
|
||||
openfire
|
||||
openfire-docker
|
||||
phpbb3
|
||||
smf
|
||||
teamspeak3
|
||||
teamspeak3-docker
|
||||
xenforo
|
||||
:::
|
||||
|
||||
|
||||
207
docs/features/services/mumble-docker.md
Normal file
207
docs/features/services/mumble-docker.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# Mumble
|
||||
|
||||
An alternate install guide for Mumble using Docker, better suited to an Alliance Auth Docker install
|
||||
|
||||
Mumble is a free voice chat server. While not as flashy as TeamSpeak, it has all the functionality and is easier to customize. And is better. I may be slightly biased.
|
||||
|
||||
## Configuring Auth
|
||||
|
||||
In your auth project's settings file (`aa-docker/conf/local.py`), do the following:
|
||||
|
||||
- Add `'allianceauth.services.modules.mumble',` to your `INSTALLED_APPS` list
|
||||
- Append the following to your auth project's settings file:
|
||||
|
||||
```python
|
||||
# Mumble Configuration
|
||||
MUMBLE_URL = "mumble.example.com"
|
||||
```
|
||||
|
||||
Add the following lines to your `.env` file
|
||||
|
||||
```env
|
||||
# Mumble
|
||||
MUMBLE_SUPERUSER_PASSWORD = superuser_password
|
||||
MUMBLE_ICESECRETWRITE = icesecretwrite
|
||||
MUMBLE_SERVERPASSWORD = serverpassword
|
||||
```
|
||||
|
||||
Finally, restart your stack and run migrations
|
||||
|
||||
```shell
|
||||
docker compose --env-file=.env up -d
|
||||
docker compose exec allianceauth_gunicorn bash
|
||||
auth migrate
|
||||
```
|
||||
|
||||
## Docker Installations
|
||||
|
||||
### Installing Mumble and Authenticator
|
||||
|
||||
Inside your `aa-docker` directory, clone the authenticator to a sub directory as follows
|
||||
|
||||
```shell
|
||||
git clone https://gitlab.com/allianceauth/mumble-authenticator.git
|
||||
```
|
||||
|
||||
Add the following to your `docker-compose.yml` under the `services:` section
|
||||
|
||||
```docker
|
||||
mumble-server:
|
||||
image: mumblevoip/mumble-server:latest
|
||||
restart: always
|
||||
environment:
|
||||
- MUMBLE_SUPERUSER_PASSWORD=${MUMBLE_SUPERUSER_PASSWORD}
|
||||
- MUMBLE_CONFIG_ice="tcp -h 127.0.0.1 -p 6502"
|
||||
- MUMBLE_CONFIG_icesecretwrite=${MUMBLE_ICESECRETWRITE}
|
||||
- MUMBLE_CONFIG_serverpassword=${MUMBLE_SERVERPASSWORD}
|
||||
- MUMBLE_CONFIG_opusthreshold=0
|
||||
- MUMBLE_CONFIG_suggestPushToTalk=true
|
||||
- MUMBLE_CONFIG_suggestVersion=1.4.0
|
||||
ports:
|
||||
- 64738:64738
|
||||
- 64738:64738/udp
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10Mb"
|
||||
max-file: "5"
|
||||
|
||||
mumble-authenticator:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./mumble-authenticator/Dockerfile
|
||||
restart: always
|
||||
volumes:
|
||||
- ./mumble-authenticator/authenticator.py:/authenticator.py
|
||||
- ./mumble-authenticator/authenticator.ini.docker:/authenticator.ini
|
||||
environment:
|
||||
- MUMBLE_SUPERUSER_PASSWORD=${MUMBLE_SUPERUSER_PASSWORD}
|
||||
- MUMBLE_CONFIG_ice="tcp -h 127.0.0.1 -p 6502"
|
||||
- MUMBLE_CONFIG_icesecretwrite=${MUMBLE_ICESECRETWRITE}
|
||||
- MUMBLE_CONFIG_serverpassword=${MUMBLE_SERVERPASSWORD}
|
||||
depends_on:
|
||||
- mumble-server
|
||||
- auth_mysql
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10Mb"
|
||||
max-file: "5"
|
||||
```
|
||||
|
||||
## Permissions
|
||||
|
||||
To use this service, users will require some of the following.
|
||||
|
||||
```{eval-rst}
|
||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||
| Permission | Admin Site | Auth Site |
|
||||
+=======================================+==================+==========================================================================+
|
||||
| mumble.access_mumble | None | Can Access the Mumble Service |
|
||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
## ACL configuration
|
||||
|
||||
On a freshly installed mumble server only your superuser has the right to configure ACLs and create channels. The credentials for logging in with your superuser are:
|
||||
|
||||
- user: `SuperUser`
|
||||
- password: *what you defined when configuring your mumble server*
|
||||
|
||||
## Optimizing a Mumble Server
|
||||
|
||||
The needs and available resources will vary between Alliance Auth installations. Consider yours when applying these settings.
|
||||
|
||||
### Bandwidth
|
||||
|
||||
<https://wiki.mumble.info/wiki/Murmur.ini#bandwidth>
|
||||
This is likely the most important setting for scaling a Mumble install, The default maximum Bandwidth is 72000bps Per User. Reducing this value will cause your clients to automatically scale back their bandwidth transmitted, while causing a reduction in voice quality. A value thats still high may cause robotic voices or users with bad connections to drop due entirely due to network load.
|
||||
|
||||
Please tune this value to your individual needs, the below scale may provide a rough starting point.
|
||||
72000 - Superior voice quality - Less than 50 users.
|
||||
54000 - No noticeable reduction in quality - 50+ Users or many channels with active audio.
|
||||
36000 - Mild reduction in quality - 100+ Users
|
||||
30000 - Noticeable reduction in quality but not function - 250+ Users
|
||||
|
||||
### Forcing Opus
|
||||
|
||||
<https://wiki.mumble.info/wiki/Murmur.ini#opusthreshold>
|
||||
A Mumble server by default, will fall back to the older CELT codec as soon as a single user connects with an old client. This will significantly reduce your audio quality and likely place higher load on your server. We *highly* reccommend setting this to Zero, to force OPUS to be used at all times. Be aware any users with Mumble clients prior to 1.2.4 (From 2013...) Will not hear any audio.
|
||||
|
||||
Our default config sets this as follows
|
||||
|
||||
```docker
|
||||
mumble-authenticator:
|
||||
environment:
|
||||
`MUMBLE_CONFIG_opusthreshold=0`
|
||||
```
|
||||
|
||||
### AutoBan and Rate Limiting
|
||||
|
||||
<https://wiki.mumble.info/wiki/Murmur.ini#autobanAttempts.2C_autobanTimeframe_and_autobanTime>
|
||||
The AutoBan feature has some sensible settings by default, You may wish to tune these if your users keep locking themselves out by opening two clients by mistake, or if you are receiving unwanted attention
|
||||
|
||||
<https://wiki.mumble.info/wiki/Murmur.ini#messagelimit_and_messageburst>
|
||||
This too, is set to a sensible configuration by default. Take note on upgrading older installs, as this may actually be set too restrictively and will rate-limit your admins accidentally, take note of the configuration in <https://github.com/mumble-voip/mumble/blob/master/scripts/murmur.ini#L156>
|
||||
|
||||
```docker
|
||||
mumble-authenticator:
|
||||
environment:
|
||||
MUMBLE_CONFIG_messagelimit=
|
||||
MUMBLE_CONFIG_messageburst=
|
||||
MUMBLE_CONFIG_autobanAttempts=10
|
||||
MUMBLE_CONFIG_autobanTimeframe=120
|
||||
MUMBLE_CONFIG_autobanTime=30
|
||||
MUMBLE_CONFIG_autobanSuccessfulConnections=false
|
||||
```
|
||||
|
||||
### "Suggest" Options
|
||||
|
||||
There is no way to force your users to update their clients or use Push to Talk, but these options will throw an error into their Mumble Client.
|
||||
|
||||
<https://wiki.mumble.info/wiki/Murmur.ini#Miscellany>
|
||||
|
||||
We suggest using Mumble 1.4.0+ for your server and Clients, you can tune this to the latest Patch version.
|
||||
If Push to Talk is to your tastes, configure the suggestion as follows
|
||||
|
||||
```docker
|
||||
mumble-authenticator:
|
||||
environment:
|
||||
MUMBLE_CONFIG_suggestVersion=s1.4.287
|
||||
MUMBLE_CONFIG_suggestPushToTalk=true
|
||||
|
||||
```
|
||||
|
||||
## General notes
|
||||
|
||||
### Server password
|
||||
|
||||
With the default Mumble configuration your mumble server is public. Meaning that everyone who has the address can at least connect to it and might also be able join all channels that don't have any permissions set (Depending on your ACL configured for the root channel).
|
||||
|
||||
We have changed this behaviour by setting a Server Password by default, to change this password modify `MUMBLE_SERVERPASSWORD` in `.env`.
|
||||
|
||||
Restart the container to apply the change.
|
||||
|
||||
```shell
|
||||
docker compose restart mumble-server
|
||||
```
|
||||
|
||||
It is not reccommended to share/use this password, instead use the Mumble Authenticator whenever possible.
|
||||
|
||||
As only registered member can join your mumble server. If you still want to allow guests to join you have 2 options.
|
||||
|
||||
- Allow the "Guest" state to activate the Mumble service in your Auth instance
|
||||
- Use [Mumble temporary links](https://github.com/pvyParts/allianceauth-mumble-temp)
|
||||
|
||||
### Enabling Avatars in Overlay (V1.0.0+)
|
||||
|
||||
Ensure you have an up to date Mumble-Authenticator, this feature was added in V1.0.0
|
||||
|
||||
Edit `authenticator.ini` and change (or add for older installs) This code block.
|
||||
|
||||
```ini
|
||||
;If enabled, textures are automatically set as player's EvE avatar for use on overlay.
|
||||
avatar_enable = True
|
||||
;Get EvE avatar images from this location. {charid} will be filled in.
|
||||
ccp_avatar_url = https://images.evetech.net/characters/{charid}/portrait?size=32
|
||||
```
|
||||
@@ -9,7 +9,8 @@ Note that this guide assumes that you have installed Auth with the official :doc
|
||||
:::{warning}
|
||||
This guide is currently for Ubuntu only.
|
||||
:::
|
||||
## Installations
|
||||
|
||||
## Bare Metal Installations
|
||||
|
||||
### Installing Mumble Server
|
||||
|
||||
@@ -35,7 +36,6 @@ sudo apt-get install python-software-properties mumble-server libqt5sql5-mysql
|
||||
:::
|
||||
::::
|
||||
|
||||
|
||||
### Installing Mumble Authenticator
|
||||
|
||||
Next, we need to download the latest authenticator release from the [authenticator repository](https://gitlab.com/allianceauth/mumble-authenticator).
|
||||
@@ -236,7 +236,7 @@ Please tune this value to your individual needs, the below scale may provide a r
|
||||
### Forcing Opus
|
||||
|
||||
<https://wiki.mumble.info/wiki/Murmur.ini#opusthreshold>
|
||||
A Mumble server, by default, will fall back to the older CELT codec as soon as a single user connects with an old client. This will significantly reduce your audio quality and likely place a higher load on your server. We _highly_ reccommend setting this to Zero, to force OPUS to be used at all times. Be aware any users with Mumble clients prior to 1.2.4 (From 2013...) Will not hear any audio.
|
||||
A Mumble server, by default, will fall back to the older CELT codec as soon as a single user connects with an old client. This will significantly reduce your audio quality and likely place a higher load on your server. We *highly* recommend setting this to Zero, to force OPUS to be used at all times. Be aware any users with Mumble clients prior to 1.2.4 (From 2013...) Will not hear any audio.
|
||||
|
||||
`opusthreshold=0`
|
||||
|
||||
@@ -255,7 +255,7 @@ There is no way to force your users to update their clients or use Push to Talk,
|
||||
<https://wiki.mumble.info/wiki/Murmur.ini#Miscellany>
|
||||
|
||||
We suggest using Mumble 1.4.0+ for your server and Clients, you can tune this to the latest Patch version.
|
||||
`suggestVersion=1.4.230`
|
||||
`suggestVersion=1.4.287`
|
||||
|
||||
If Push to Talk is to your tastes, configure the suggestion as follows
|
||||
`suggestPushToTalk=true`
|
||||
|
||||
@@ -29,6 +29,7 @@ Currently, the following services support custom name formats:
|
||||
| Xenforo | Username | ``{character_name}`` |
|
||||
+-------------+-----------+-------------------------------------+
|
||||
```
|
||||
|
||||
:::{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.
|
||||
:::
|
||||
|
||||
180
docs/features/services/openfire-docker.md
Normal file
180
docs/features/services/openfire-docker.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# Openfire
|
||||
|
||||
An alternate install guide for Openfire using Docker, better suited to an Alliance Auth Docker install
|
||||
|
||||
Openfire is a Jabber (XMPP) server.
|
||||
|
||||
## Configuring Auth
|
||||
|
||||
In your auth project's settings file (`aa-docker/conf/local.py`), do the following:
|
||||
|
||||
- Add `'allianceauth.services.modules.openfire',` to your `INSTALLED_APPS` list
|
||||
- Append the following to your auth project's settings file:
|
||||
|
||||
```python
|
||||
# Jabber Configuration
|
||||
JABBER_URL = SITE_URL
|
||||
JABBER_PORT = os.environ.get('JABBER_PORT', 5223)
|
||||
JABBER_SERVER = SITE_URL
|
||||
OPENFIRE_ADDRESS = SITE_URL
|
||||
OPENFIRE_SECRET_KEY = os.environ.get('OPENFIRE_SECRET_KEY', '')
|
||||
BROADCAST_USER = ""
|
||||
BROADCAST_USER_PASSWORD = os.environ.get('BROADCAST_USER_PASSWORD', '127.0.0.1')
|
||||
BROADCAST_SERVICE_NAME = "broadcast"
|
||||
```
|
||||
|
||||
Add the following lines to your `.env` file
|
||||
|
||||
```env
|
||||
# Openfire
|
||||
OPENFIRE_SECRET_KEY = superuser_password
|
||||
BROADCAST_USER_PASSWORD = icesecretwrite
|
||||
|
||||
```
|
||||
|
||||
Finally, restart your stack and run migrations
|
||||
|
||||
```shell
|
||||
docker compose --env-file=.env up -d
|
||||
docker compose exec allianceauth_gunicorn bash
|
||||
auth migrate
|
||||
```
|
||||
|
||||
## Docker Installation
|
||||
|
||||
Add the following to your `docker-compose.yml` under the `services:` section
|
||||
|
||||
```docker
|
||||
openfire:
|
||||
image: nasqueron/openfire:4.7.5
|
||||
ports:
|
||||
- "5222:5222/tcp"
|
||||
- "5223:5223/tcp"
|
||||
- "7777:7777/tcp"
|
||||
volumes:
|
||||
- openfire-data:/var/lib/openfire
|
||||
depends_on:
|
||||
- auth_mysql
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50Mb"
|
||||
max-file: "5"
|
||||
```
|
||||
|
||||
### Create Database
|
||||
|
||||
We have a Mariadb container already as part of the Alliance Auth stack, enter it and create a database for it.
|
||||
|
||||
```shell
|
||||
docker exec -it auth_mysql
|
||||
mysql -u root -p $AA_DB_ROOT_PASSWORD
|
||||
```
|
||||
|
||||
```sql
|
||||
create database alliance_jabber;
|
||||
grant all privileges on alliance_jabber . * to 'aauth'@'localhost';
|
||||
exit;
|
||||
exit
|
||||
```
|
||||
|
||||
### Configure Webserver
|
||||
|
||||
In Nginx Proxy Manager `http://yourdomain:81/`, go to `Proxy Hosts`, Click `Add Proxy Host`. You can refer to :doc:`/installation-containerized/docker`
|
||||
|
||||
Domain Name: `jabber.yourdomain`
|
||||
Forward Hostname `openfire`
|
||||
forward port `9090` for http, `9091` for https
|
||||
|
||||
### Web Configuration
|
||||
|
||||
The remainder of the setup occurs through Openfire’s web interface. Navigate to <http://jabber.yourdomain.com>
|
||||
|
||||
Select your language, our guide will assume English
|
||||
|
||||
Under Server Settings, set the Domain to `jabber.yourdomain.com` replacing it with your actual domain. Don’t touch the rest.
|
||||
|
||||
Under Database Settings, select `Standard Database Connection`
|
||||
|
||||
On the next page, select `MySQL` from the dropdown list and change the following:
|
||||
|
||||
- `[server]`: `auth_mysql`
|
||||
- `[database]`: `alliance_jabber`
|
||||
- `[user]`: `aauth`
|
||||
- `[password]`: Your database users password
|
||||
|
||||
If Openfire returns with a failed to connect error, re-check these settings. Note the lack of square brackets.
|
||||
|
||||
Under Profile Settings, leave `Default` selected.
|
||||
|
||||
Create an administrator account. The actual name is irrelevant, just don’t lose this login information.
|
||||
|
||||
Finally, log in to the console with your admin account.
|
||||
|
||||
Edit your auth project's settings file (`aa-docker/conf/local.py`) and enter the values you just set:
|
||||
|
||||
- `JABBER_URL` is the pubic address of your jabber server
|
||||
- `JABBER_PORT` is the port for clients to connect to (usually 5223)
|
||||
- `JABBER_SERVER` is the name of the jabber server. If you didn't alter it during install it'll usually be your domain (eg `jabber.example.com`)
|
||||
- `OPENFIRE_ADDRESS` is the web address of Openfire's web interface. Use http:// with port 9090 or https:// with port 9091 if you configure SSL in Openfire and Nginx Proxy Manager
|
||||
|
||||
### REST API Setup
|
||||
|
||||
Navigate to the `plugins` tab, and then `Available Plugins` on the left navigation bar. You’ll need to fetch the list of available plugins by clicking the link.
|
||||
|
||||
Once loaded, press the green plus on the right for `REST API`.
|
||||
|
||||
Navigate the `Server` tab, `Sever Settings` subtab. At the bottom of the left navigation bar select `REST API`.
|
||||
|
||||
Select `Enabled`, and `Secret Key Auth`. Update your auth project's settings with this secret key as `OPENFIRE_SECRET_KEY`.
|
||||
|
||||
### Broadcast Plugin Setup
|
||||
|
||||
Navigate to the `Users/Groups` tab and select `Create New User` from the left navigation bar.
|
||||
|
||||
Pick a username (e.g. `broadcast`) and password for your ping user. Enter these in your auth project's settings file as `BROADCAST_USER` and `BROADCAST_USER_PASSWORD`. Note that `BROADCAST_USER` needs to be in the format `user@example.com` matching your jabber server name. Press `Create User` to save this user.
|
||||
|
||||
Broadcasting requires a plugin. Navigate to the `plugins` tab, press the green plus for the `Broadcast` plugin.
|
||||
|
||||
Navigate to the `Server` tab, `Server Manager` subtab, and select `System Properties`. Enter the following:
|
||||
|
||||
- Name: `plugin.broadcast.disableGroupPermissions`
|
||||
- Value: `True`
|
||||
- Do not encrypt this property value
|
||||
- Name: `plugin.broadcast.allowedUsers`
|
||||
- Value: `broadcast@example.com`, replacing the domain name with yours
|
||||
- Do not encrypt this property value
|
||||
|
||||
If you have troubles getting broadcasts to work, you can try setting the optional (you will need to add it) `BROADCAST_IGNORE_INVALID_CERT` setting to `True`. This will allow invalid certificates to be used when connecting to the Openfire server to send a broadcast.
|
||||
|
||||
### Preparing Auth
|
||||
|
||||
Once all settings are entered, run migrations and restart Gunicorn and Celery.
|
||||
|
||||
### Group Chat
|
||||
|
||||
Channels are available which function like a chat room. Access can be controlled either by password or ACL (not unlike mumble).
|
||||
|
||||
Navigate to the `Group Chat` tab and select `Create New Room` from the left navigation bar.
|
||||
|
||||
- Room ID is a short, easy-to-type version of the room’s name users will connect to
|
||||
- Room Name is the full name for the room
|
||||
- Description is short text describing the room’s purpose
|
||||
- Set a password if you want password authentication
|
||||
- Every other setting is optional. Save changes.
|
||||
|
||||
Now select your new room. On the left navigation bar, select `Permissions`.
|
||||
|
||||
ACL is achieved by assigning groups to each of the three tiers: `Owners`, `Admins` and `Members`. `Outcast` is the blacklist. You’ll usually only be assigning groups to the `Member` category.
|
||||
|
||||
## Permissions
|
||||
|
||||
To use this service, users will require some of the following.
|
||||
|
||||
```{eval-rst}
|
||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||
| Permission | Admin Site | Auth Site |
|
||||
+=======================================+==================+==========================================================================+
|
||||
| openfire.access_openfire | None | Can Access the Openfire Service |
|
||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||
```
|
||||
@@ -21,7 +21,7 @@ PHPBB3_URL = ''
|
||||
DATABASES['phpbb3'] = {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 'alliance_forum',
|
||||
'USER': 'allianceserver-phpbb3',
|
||||
'USER': 'allianceserver',
|
||||
'PASSWORD': 'password',
|
||||
'HOST': '127.0.0.1',
|
||||
'PORT': '3306',
|
||||
|
||||
179
docs/features/services/teamspeak3-docker.md
Normal file
179
docs/features/services/teamspeak3-docker.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# TeamSpeak 3
|
||||
|
||||
## Overview
|
||||
|
||||
TeamSpeak3 is the most popular VOIP program for gamers.
|
||||
|
||||
But have you considered using Mumble? Not only is it free, but it has features and performance far superior to Teamspeak3.
|
||||
|
||||
## Setup
|
||||
|
||||
Sticking with TS3? Alright, I tried.
|
||||
|
||||
## Configuring Auth
|
||||
|
||||
In your auth project's settings file (`aa-docker/conf/local.py`), do the following:
|
||||
|
||||
- Add `'allianceauth.services.modules.teamspeak',` to your `INSTALLED_APPS` list
|
||||
- Append the following to your auth project's settings file:
|
||||
|
||||
```python
|
||||
# Teamspeak3 Configuration
|
||||
TEAMSPEAK3_SERVER_IP = os.environ.get('TEAMSPEAK3_SERVER_IP', '127.0.0.1')
|
||||
TEAMSPEAK3_SERVER_PORT = os.environ.get('TEAMSPEAK3_SERVER_PORT', 10011)
|
||||
TEAMSPEAK3_SERVERQUERY_USER = os.environ.get('TEAMSPEAK3_SERVERQUERY_USER', "serverquery")
|
||||
TEAMSPEAK3_SERVERQUERY_PASSWORD = os.environ.get('TEAMSPEAK3_SERVERQUERY_PASSWORD', "")
|
||||
TEAMSPEAK3_VIRTUAL_SERVER = os.environ.get('TEAMSPEAK3_VIRTUAL_SERVER', 1)
|
||||
TEAMSPEAK3_PUBLIC_URL = SITE_URL
|
||||
|
||||
CELERYBEAT_SCHEDULE['run_ts3_group_update'] = {
|
||||
'task': 'allianceauth.services.modules.teamspeak3.tasks.run_ts3_group_update',"
|
||||
'schedule': crontab(minute='*/30'),
|
||||
}
|
||||
```
|
||||
|
||||
Add the following lines to your `.env` file
|
||||
|
||||
```env
|
||||
# Temspeak
|
||||
TEAMSPEAK3_SERVERQUERY_USER = "serverquery"
|
||||
TEAMSPEAK3_SERVERQUERY_PASSWORD = ""
|
||||
```
|
||||
|
||||
## Docker Installation
|
||||
|
||||
Add the following to your `docker-compose.yml` under the `services:` section
|
||||
|
||||
```docker
|
||||
teamspeak:
|
||||
image: teamspeak:3.13
|
||||
restart: always
|
||||
environment:
|
||||
TS3SERVER_LICENSE: accept
|
||||
ports:
|
||||
- 9987:9987/udp
|
||||
- 30033:30033
|
||||
volumes:
|
||||
- teamspeak-data:/var/ts3server/
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10Mb"
|
||||
max-file: "5"
|
||||
```
|
||||
|
||||
### Update Settings
|
||||
|
||||
In (`aa-docker/conf/local.py`), update the following
|
||||
|
||||
- `TEAMSPEAK_VIRTUAL_SERVER` is the virtual server ID of the server to be managed - it will only ever not be 1 if your server is hosted by a professional company
|
||||
- `TEAMSPEAK3_PUBLIC_URL` is the public address of your TeamSpeak server. Do not include any leading http:// or teamspeak://
|
||||
|
||||
In your `.env` file, update the following, obtained from the logs of the Teamspeak server initaliztion `docker compose logs teamspeak`
|
||||
|
||||
- `TEAMSPEAK3_SERVERQUERY_USER` is `loginname` from the above bash command (usually `serveradmin`)
|
||||
- `TEAMSPEAK3_SERVERQUERY_PASSWORD` is `password` following the equals in `serveradmin_password=`
|
||||
|
||||
Once settings are entered, run migrations and restart your stack
|
||||
|
||||
```shell
|
||||
docker compose --env-file=.env up -d
|
||||
docker compose exec allianceauth_gunicorn bash
|
||||
auth migrate
|
||||
```
|
||||
|
||||
### Generate User Account
|
||||
|
||||
And now we can generate ourselves a user account. Navigate to the services in Alliance Auth for your user account and press the checkmark for TeamSpeak 3.
|
||||
|
||||
Click the URL provided to automatically connect to our server. It will prompt you to redeem the serveradmin token, enter the `token` from startup.
|
||||
|
||||
### Groups
|
||||
|
||||
Now we need to make groups. AllianceAuth handles groups in teamspeak differently: instead of creating groups it creates an association between groups in TeamSpeak and groups in AllianceAuth. Go ahead and make the groups you want to associate with auth groups, keeping in mind multiple TeamSpeak groups can be associated with a single auth group.
|
||||
|
||||
Navigate back to the AllianceAuth admin interface (example.com/admin) and under `Teamspeak3`, select `Auth / TS Groups`.
|
||||
|
||||
In the top-right corner click, first click on `Update TS3 Groups` to fetch the newly created server groups from TS3 (this may take a minute to complete). Then click on `Add Auth / TS Group` to link Auth groups with TS3 server groups.
|
||||
|
||||
The dropdown box provides all auth groups. Select one and assign TeamSpeak groups from the panels below. If these panels are empty, wait a minute for the database update to run, or see the [troubleshooting section](#ts-group-models-not-populating-on-admin-site) below.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### `Insufficient client permissions (failed on Invalid permission: 0x26)`
|
||||
|
||||
Using the advanced permissions editor, ensure the `Guest` group has the permission `Use Privilege Keys to gain permissions` (under `Virtual Server` expand the `Administration` section)
|
||||
|
||||
To enable advanced permissions, on your client go to the `Tools` menu, `Application`, and under the `Misc` section, tick `Advanced permission system`
|
||||
|
||||
### TS group models not populating on admin site
|
||||
|
||||
The method which populates these runs every 30 minutes. To populate manually you start the process from the admin site or from the Django shell.
|
||||
|
||||
#### Admin Site
|
||||
|
||||
Navigate to the AllianceAuth admin interface and under `Teamspeak3`, select `Auth / TS Groups`.
|
||||
|
||||
Then, in the top-right corner click, click on `Update TS3 Groups` to start the process of fetching the server groups from TS3 (this may take a minute to complete).
|
||||
|
||||
#### Django Shell
|
||||
|
||||
Start a django shell with:
|
||||
|
||||
```shell
|
||||
docker compose exec allianceauth_gunicorn bash
|
||||
auth shell
|
||||
```
|
||||
|
||||
And execute the update as follows:
|
||||
|
||||
```python
|
||||
from allianceauth.services.modules.teamspeak3.tasks import Teamspeak3Tasks
|
||||
Teamspeak3Tasks.run_ts3_group_update()
|
||||
```
|
||||
|
||||
Ensure that command does not return an error.
|
||||
|
||||
### `2564 access to default group is forbidden`
|
||||
|
||||
This usually occurs because auth is trying to remove a user from the `Guest` group (group ID 8). The guest group is only assigned to a user when they have no other groups, unless you have changed the default teamspeak server config.
|
||||
|
||||
Teamspeak servers v3.0.13 and up are especially susceptible to this. Ensure the Channel Admin Group is not set to `Guest (8)`. Check by right clicking on the server name, `Edit virtual server`, and in the middle of the panel select the `Misc` tab.
|
||||
|
||||
### `TypeError: string indices must be integers, not str`
|
||||
|
||||
This error generally means teamspeak returned an error message that went unhandled. The full traceback is required for proper debugging, which the logs do not record. Please check the superuser notifications for this record and get in touch with a developer.
|
||||
|
||||
### `3331 flood ban`
|
||||
|
||||
This most commonly happens when your teamspeak server is externally hosted. You need to add the auth server IP to the teamspeak serverquery whitelist. This varies by provider.
|
||||
|
||||
If you have SSH access to the server hosting it, you need to locate the teamspeak server folder and add the auth server IP on a new line in `query_ip_allowlist.txt` (named `query_ip_whitelist.txt` on older teamspeak versions).
|
||||
|
||||
### `520 invalid loginname or password`
|
||||
|
||||
The serverquery account login specified in local.py is incorrect. Please verify `TEAMSPEAK3_SERVERQUERY_USER` and `TEAMSPEAK3_SERVERQUERY_PASSWORD`. The [installation section](#update-settings) describes where to get them.
|
||||
|
||||
### `2568 insufficient client permissions`
|
||||
|
||||
This usually occurs if you've created a separate serverquery user to use with auth. It has not been assigned sufficient permissions to complete all the tasks required of it. The full list of required permissions is not known, so assign liberally.
|
||||
|
||||
## Permissions
|
||||
|
||||
To use and configure this service, users will require some of the following.
|
||||
|
||||
```{eval-rst}
|
||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||
| Permission | Admin Site | Auth Site |
|
||||
+=======================================+==================+==========================================================================+
|
||||
| teamspeak.access_teamspeak | None | Can Access the TeamSpeak Service |
|
||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||
| teamspeak.add_authts | Can Add Model | None |
|
||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||
| teamspeak.change_authts | Can Change Model | None |
|
||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||
| teamspeak.delete_authts | Can Delete Model | None |
|
||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||
| teamspeak.view_authts | Can View Model | None |
|
||||
+---------------------------------------+------------------+--------------------------------------------------------------------------+
|
||||
```
|
||||
@@ -8,13 +8,17 @@ You should have the following available on the system you are using to set this
|
||||
* git
|
||||
* curl
|
||||
|
||||
:::{hint}
|
||||
If at any point `docker compose` does not work, but `docker-compose` does, you have an older version of Docker (and Compose), please update before continuing. Be cautious of these two commands and any suggestions copy and pasted from the internet
|
||||
:::
|
||||
|
||||
## Setup Guide
|
||||
|
||||
1. run `bash <(curl -s https://gitlab.com/allianceauth/allianceauth/-/raw/master/docker/scripts/download.sh)`. This will download all the files you need to install Alliance Auth and place them in a directory named `aa-docker`. Feel free to rename/move this folder.
|
||||
1. run `./scripts/prepare-env.sh` to set up your environment
|
||||
1. (optional) Change `PROTOCOL` to `http://` if not using SSL in `.env`
|
||||
1. run `docker-compose --env-file=.env up -d` (NOTE: if this command hangs, follow the instructions [here](https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged))
|
||||
1. run `docker-compose exec allianceauth bash` to open up a terminal inside your auth container
|
||||
1. run `docker compose --env-file=.env up -d` (NOTE: if this command hangs, follow the instructions [here](https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged))
|
||||
1. run `docker compose exec allianceauth_gunicorn bash` to open up a terminal inside an auth container
|
||||
1. run `auth migrate`
|
||||
1. run `auth collectstatic`
|
||||
1. run `auth createsuperuser`
|
||||
@@ -24,7 +28,7 @@ You should have the following available on the system you are using to set this
|
||||
1. click "Add Proxy Host", with the following settings for auth. The example uses `auth.localhost` for the domain, but you'll want to use whatever address you have auth configured on
|
||||

|
||||
1. click "Add Proxy Host", with the following settings for grafana. The example uses `grafana.localhost` for the domain
|
||||
)
|
||||

|
||||
|
||||
Congrats! You should now see auth running at <http://auth.yourdomain> and grafana at <http://grafana.yourdomain>!
|
||||
|
||||
@@ -46,7 +50,7 @@ That's it! You should now be able to access your auth install at <https://auth.y
|
||||
|
||||
There are a handful of ways to add packages:
|
||||
|
||||
* Running `pip install` in the container
|
||||
* Running `pip install` in the containers
|
||||
* Modifying the container's initial command to install packages
|
||||
* Building a custom Docker image (recommended, and less scary than it sounds!)
|
||||
|
||||
@@ -54,10 +58,26 @@ 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
|
||||
|
||||
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. In `docker-compose.yml`, comment out the `image` line under `allianceauth` (line 36... ish) and uncomment the `build` section
|
||||
1. run `docker-compose --env-file=.env up -d`, your custom container will be built, and auth will have your new packages. Make sure to follow the package's instructions on config values that go in `local.py`
|
||||
1. run `docker-compose exec allianceauth_gunicorn bash` to open up a terminal inside your auth container
|
||||
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.
|
||||
* Comment out the `image` line under `allianceauth`
|
||||
* Uncomment the `build` section
|
||||
* e.g.
|
||||
|
||||
```docker
|
||||
x-allianceauth-base: &allianceauth-base
|
||||
# image: ${AA_DOCKER_TAG?err}
|
||||
build:
|
||||
context: .
|
||||
dockerfile: custom.dockerfile
|
||||
args:
|
||||
AA_DOCKER_TAG: ${AA_DOCKER_TAG?err}
|
||||
restart: always
|
||||
...
|
||||
```
|
||||
|
||||
1. run `docker compose --env-file=.env up -d`, your custom container will be built, and auth will have your new packages. Make sure to follow the package's instructions on config values that go in `local.py`
|
||||
1. run `docker compose exec allianceauth_gunicorn bash` to open up a terminal inside your auth container
|
||||
1. run `allianceauth update myauth`
|
||||
1. run `auth migrate`
|
||||
1. run `auth collectstatic`
|
||||
@@ -71,9 +91,9 @@ _NOTE: It is recommended that you put any secret values (API keys, database cred
|
||||
Whether you're using a custom image or not, the version of auth is dictated by $AA_DOCKER_TAG in your `.env` file.
|
||||
|
||||
1. To update to a new version of auth, update the version number at the end (or replace the whole value with the tag in the release notes).
|
||||
1. run `docker-compose pull`
|
||||
1. run `docker-compose --env-file=.env up -d`
|
||||
1. run `docker-compose exec allianceauth bash` to open up a terminal inside your auth container
|
||||
1. run `docker compose pull`
|
||||
1. run `docker compose --env-file=.env up -d`
|
||||
1. run `docker compose exec allianceauth_gunicorn bash` to open up a terminal inside your auth container
|
||||
1. run `allianceauth update myauth`
|
||||
1. run `auth migrate`
|
||||
1. run `auth collectstatic`
|
||||
@@ -83,5 +103,5 @@ _NOTE: If you specify a version of allianceauth in your `requirements.txt` in a
|
||||
### Custom Packages
|
||||
|
||||
1. Update the versions in your `requirements.txt` file
|
||||
1. Run `docker-compose build`
|
||||
1. Run `docker-compose --env-file=.env up -d`
|
||||
1. Run `docker compose build`
|
||||
1. Run `docker compose --env-file=.env up -d`
|
||||
|
||||
@@ -10,5 +10,7 @@ There are additional installation steps for activating services and apps that co
|
||||
|
||||
:::{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
docker
|
||||
v4_docker_migration
|
||||
:::
|
||||
|
||||
118
docs/installation-containerized/v4_docker_migration.md
Normal file
118
docs/installation-containerized/v4_docker_migration.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Migrating your Docker Compose stack from AA V3.x to AA v4.x
|
||||
|
||||
Our Docker Compose stack has both changed significantly, and simplified itself drastically depending on your level of familiarity with Docker.
|
||||
|
||||
We have Removed our need to run Supervisor inside the container to run the various tasks needed, and split the stack into multiple containers responsible for each task, as well as modernized many elements.
|
||||
|
||||
## aa-docker/conf/*
|
||||
|
||||
We are bundling a few often customized files along side our AA install for easier modification by users, you will need to download these into aa-docker/conf
|
||||
|
||||
```shell
|
||||
wget https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/conf/celery.py
|
||||
wget https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/conf/urls.py
|
||||
wget https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/conf/memory_check.sh
|
||||
wget https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/conf/redis_healthcheck.sh
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
|
||||
At this point you should take a copy of your docker-compose and take note of any additional volumes or configurations you have, and why.
|
||||
|
||||
Take a complete backup of your local.py, docker-compose and SQL database.
|
||||
|
||||
`docker compose down`
|
||||
|
||||
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>
|
||||
|
||||
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
|
||||
proxy:
|
||||
...
|
||||
# Uncomment this section to use a dedicated database for Nginx Proxy Manager
|
||||
environment:
|
||||
DB_MYSQL_HOST: "proxy-db"
|
||||
DB_MYSQL_PORT: 3306
|
||||
DB_MYSQL_USER: "npm"
|
||||
DB_MYSQL_PASSWORD: "${PROXY_MYSQL_PASS?err}"
|
||||
DB_MYSQL_NAME: "npm"
|
||||
...
|
||||
# Uncomment this section to use a dedicated database for Nginx Proxy Manager
|
||||
proxy-db:
|
||||
image: 'jc21/mariadb-aria:latest'
|
||||
restart: always
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: "${PROXY_MYSQL_PASS_ROOT?err}"
|
||||
MYSQL_DATABASE: 'npm'
|
||||
MYSQL_USER: 'npm'
|
||||
MYSQL_PASSWORD: "${PROXY_MYSQL_PASS?err}"
|
||||
ports:
|
||||
- 3306
|
||||
volumes:
|
||||
- proxy-db:/var/lib/mysql
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "1Mb"
|
||||
max-file: "5"
|
||||
```
|
||||
|
||||
## .env
|
||||
|
||||
You will need to add some entries to your .env file
|
||||
|
||||
```env
|
||||
AA_DB_CHARSET=utf8mb4
|
||||
GF_SECURITY_ADMIN_USERNAME=admin
|
||||
```
|
||||
|
||||
and
|
||||
`GF_SECURITY_ADMIN_PASSWORD`
|
||||
|
||||
The password field is intentionally not filled so that you create one. You can either use the grafana credentials you have been using, or create a suitably secure password now.
|
||||
|
||||
You will also need to update the `AA_DOCKER_TAG` to the version of V4.x you want to install. Either follow the pattern or check <https://gitlab.com/allianceauth/allianceauth/-/releases>
|
||||
|
||||
## (Optional) Build Custom Container
|
||||
|
||||
If you are using a docker container with a requirements.txt, You will need to reinstate some customizations.
|
||||
|
||||
Modify `docker-compose.yml`, as follows.
|
||||
|
||||
* Comment out the `image` line under `allianceauth`
|
||||
* Uncomment the `build` section
|
||||
* e.g.
|
||||
|
||||
```docker
|
||||
x-allianceauth-base: &allianceauth-base
|
||||
# image: ${AA_DOCKER_TAG?err}
|
||||
build:
|
||||
context: .
|
||||
dockerfile: custom.dockerfile
|
||||
args:
|
||||
AA_DOCKER_TAG: ${AA_DOCKER_TAG?err}
|
||||
restart: always
|
||||
...
|
||||
```
|
||||
|
||||
Now build your custom image
|
||||
|
||||
```shell
|
||||
docker compose pull
|
||||
docker compose build
|
||||
```
|
||||
|
||||
## Bring docker back up, migrate, collect static
|
||||
|
||||
```shell
|
||||
docker compose --env-file=.env up -d --remove-orphans
|
||||
|
||||
docker compose exec allianceauth_gunicorn bash
|
||||
|
||||
allianceauth update myauth
|
||||
auth migrate
|
||||
auth collectstatic --clear
|
||||
```
|
||||
@@ -85,9 +85,9 @@ We need to build Python from source
|
||||
```bash
|
||||
cd ~
|
||||
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
|
||||
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
|
||||
tar xvf Python-3.11.5.tgz
|
||||
cd Python-3.11.5/
|
||||
wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
|
||||
tar xvf Python-3.11.7.tgz
|
||||
cd Python-3.11.7/
|
||||
./configure --enable-optimizations --enable-shared
|
||||
sudo make altinstall
|
||||
```
|
||||
@@ -99,9 +99,9 @@ We need to build Python from source
|
||||
```bash
|
||||
cd ~
|
||||
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
|
||||
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
|
||||
tar xvf Python-3.11.5.tgz
|
||||
cd Python-3.11.5/
|
||||
wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
|
||||
tar xvf Python-3.11.7.tgz
|
||||
cd Python-3.11.7/
|
||||
./configure --enable-optimizations --enable-shared
|
||||
sudo make altinstall
|
||||
```
|
||||
@@ -113,9 +113,9 @@ We need to build Python from source
|
||||
```bash
|
||||
cd ~
|
||||
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
|
||||
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
|
||||
tar xvf Python-3.11.5.tgz
|
||||
cd Python-3.11.5/
|
||||
wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
|
||||
tar xvf Python-3.11.7.tgz
|
||||
cd Python-3.11.7/
|
||||
./configure --enable-optimizations --enable-shared
|
||||
sudo make altinstall
|
||||
```
|
||||
|
||||
@@ -11,21 +11,28 @@ If you're using a small VPS to host services with very limited memory, consider
|
||||
::::{tabs}
|
||||
|
||||
:::{group-tab} Ubuntu 2004, 2204
|
||||
|
||||
```shell
|
||||
apt-get install apache2
|
||||
```
|
||||
|
||||
:::
|
||||
:::{group-tab} CentOS 7
|
||||
|
||||
```shell
|
||||
yum install httpd
|
||||
```
|
||||
|
||||
:::
|
||||
:::{group-tab} CentOS Stream 8
|
||||
|
||||
```shell
|
||||
dnf install httpd
|
||||
```
|
||||
|
||||
:::
|
||||
:::{group-tab} CentOS Stream 9
|
||||
|
||||
```shell
|
||||
systemctl enable httpd
|
||||
systemctl start httpd
|
||||
@@ -36,7 +43,6 @@ systemctl start httpd
|
||||
|
||||
CentOS 7, Stream 8, Stream 9
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
### Permissions
|
||||
|
||||
@@ -15,7 +15,7 @@ To run AA with a newer Python 3 version than your system's default, you need to
|
||||
To install other Python versions than those included with your distribution, you need to add a new installation repository. Then you can install the specific Python 3 to your system.
|
||||
|
||||
:::{note}
|
||||
Ubuntu 2204 ships with Python 3.10 already
|
||||
Ubuntu 2204 ships with Python 3.10 already
|
||||
:::
|
||||
|
||||
Centos Stream 8/9:
|
||||
@@ -39,9 +39,9 @@ sudo apt-get install python3.11 python3.11-dev python3.11-venv
|
||||
```bash
|
||||
cd ~
|
||||
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
|
||||
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
|
||||
tar xvf Python-3.11.5.tgz
|
||||
cd Python-3.11.5/
|
||||
wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
|
||||
tar xvf Python-3.11.7.tgz
|
||||
cd Python-3.11.7/
|
||||
./configure --enable-optimizations --enable-shared
|
||||
sudo make altinstall
|
||||
```
|
||||
@@ -52,9 +52,9 @@ sudo make altinstall
|
||||
```bash
|
||||
cd ~
|
||||
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
|
||||
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
|
||||
tar xvf Python-3.11.5.tgz
|
||||
cd Python-3.11.5/
|
||||
wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
|
||||
tar xvf Python-3.11.7.tgz
|
||||
cd Python-3.11.7/
|
||||
./configure --enable-optimizations --enable-shared
|
||||
sudo make altinstall
|
||||
```
|
||||
@@ -65,9 +65,9 @@ sudo make altinstall
|
||||
```bash
|
||||
cd ~
|
||||
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
|
||||
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
|
||||
tar xvf Python-3.11.5.tgz
|
||||
cd Python-3.11.5/
|
||||
wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
|
||||
tar xvf Python-3.11.7.tgz
|
||||
cd Python-3.11.7/
|
||||
./configure --enable-optimizations --enable-shared
|
||||
sudo make altinstall
|
||||
```
|
||||
|
||||
@@ -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.
|
||||
|
||||
## 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
|
||||
|
||||
### 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
|
||||
|
||||
|
||||
@@ -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
|
||||
```
|
||||
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
|
||||
|
||||
```conf
|
||||
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.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user