Compare commits

...

97 Commits

Author SHA1 Message Date
Joel Falknau
bd17b95cac Version Bump 4.3.0 2024-09-09 14:05:58 +10:00
Joel Falknau
4ed1c5b7c4 bring test celery in line with project 2024-09-09 13:59:43 +10:00
Ariel Rin
271fd8e8c4 Merge branch 'docs-user-creation-fix' into 'master'
[Docs] Add shell option to adduser command for Ubuntu install docs

See merge request allianceauth/allianceauth!1622
2024-09-09 03:58:47 +00:00
colcrunch
9b4321281a [Docs] Add shell option to adduser command for Ubuntu install docs 2024-09-09 03:58:47 +00:00
Ariel Rin
052c35c8e5 Merge branch 'metenox' into 'master'
Timerboard Improvements

Closes #1384

See merge request allianceauth/allianceauth!1645
2024-09-09 03:57:21 +00:00
Ariel Rin
0fcb517b0b Timerboard Improvements 2024-09-09 03:57:21 +00:00
Ariel Rin
dcfddf0add Merge branch 'docs2' into 'master'
Documentation

See merge request allianceauth/allianceauth!1646
2024-09-09 03:43:30 +00:00
Joel Falknau
4a4258d0e6 use docker command inside docker 2024-09-09 13:32:18 +10:00
Joel Falknau
dd15a221aa split repo from install 2024-09-09 13:32:06 +10:00
Joel Falknau
737e02293a expand mumble service install docs 2024-09-09 12:59:49 +10:00
Joel Falknau
c34efebacf define charsets for db backed apps 2024-09-03 12:27:50 +10:00
Joel Falknau
4602097399 remove DB step from mumble install, sqlite has been reccommended for a while 2024-09-03 12:27:02 +10:00
Joel Falknau
7051e06564 update features from readme 2024-09-03 12:26:43 +10:00
Joel Falknau
9767ce79d8 cleanup some local.py references 2024-09-03 12:26:31 +10:00
Joel Falknau
0c090f1486 Ubuntu 2004 should not be reccommended for new isntalls 2024-09-03 12:25:01 +10:00
Joel Falknau
618ee81f9b remove unneeded analytics docs for removed features 2024-09-03 12:24:37 +10:00
Joel Falknau
98efb9f887 split maintenance tasks into bare metal / docker 2024-09-03 12:24:17 +10:00
Ariel Rin
cbe6c821cc Merge branch 'custom-css' into 'master'
[ADD] Custom CSS Module

See merge request allianceauth/allianceauth!1643
2024-08-21 05:01:38 +00:00
Ariel Rin
de9d2b39a6 Merge branch 'theme-html-tags' into 'master'
[ADD] Theme html tags

See merge request allianceauth/allianceauth!1642
2024-08-21 04:59:18 +00:00
Peter Pfeufer
0d5f22288b Merge branch 'switch-to-django-solo' into custom-css 2024-08-20 14:41:52 +02:00
Peter Pfeufer
e0d76dc268 [CHANGE] Switch to Django Solo 2024-08-20 14:41:43 +02:00
Peter Pfeufer
ecc9e68330 [CHANGE] Consolidate migrations 2024-08-14 13:25:49 +02:00
Peter Pfeufer
710149ec21 [FIX] Check if the CustomCSS object exists 2024-08-14 13:22:23 +02:00
Peter Pfeufer
3c2c137dad [CHANGE] improve try block in template tag 2024-08-14 13:05:32 +02:00
Peter Pfeufer
a8271c4189 [CHANGE] Remove custom CSS file when it will be empty 2024-08-14 12:58:01 +02:00
Peter Pfeufer
3315ae7778 [ADD] Module to base settings file 2024-08-14 12:47:38 +02:00
Peter Pfeufer
d2f048f8fe [ADD Example template for admin overrides
For when we might want to add syntax highlight ti it, which is a completely different can of worms though.
2024-08-14 12:45:57 +02:00
Peter Pfeufer
0fe2855faa [ADD] Custom CSS to base file
Check if the CSS file exists and add it to the HTML output
2024-08-14 12:44:51 +02:00
Peter Pfeufer
79a1fa3d7c [ADD] CSS compression on save 2024-08-14 12:42:52 +02:00
Peter Pfeufer
96fe88d5c7 [REMOVE] highlight.js and leave it as an example in the widget code 2024-08-14 11:53:02 +02:00
Peter Pfeufer
59391ad3c5 [ADD] Custom CSS module (First steps) 2024-08-11 22:34:16 +02:00
Peter Pfeufer
94e9c08422 [ADD] Theme html tags 2024-08-08 10:22:14 +02:00
Joel Falknau
acff3695bc Version Bump 4.2.2 2024-08-06 12:43:06 +10:00
Ariel Rin
43ec8514aa Merge branch 'improve-redis-installation-on-ubuntu' into 'master'
[MISC] Improve Redis installation instructions for Ubuntu

See merge request allianceauth/allianceauth!1641
2024-08-05 01:26:07 +00:00
Peter Pfeufer
4c629b193f [CHANGE] Redis hint link 2024-08-05 03:21:14 +02:00
Peter Pfeufer
c651da4011 [MISC] Improve Redis installation instructions for Ubuntu 2024-08-05 03:12:24 +02:00
Ariel Rin
da382cffd1 Merge branch 'fix-mumble-url' into 'master'
[FIX] Mumble URL in service card

See merge request allianceauth/allianceauth!1637
2024-08-05 01:04:24 +00:00
Ariel Rin
4ecfc3afd8 Merge branch 'docs-docker-headlines' into 'master'
[CHANGE] Clarify that these instructions are for Docker

See merge request allianceauth/allianceauth!1638
2024-08-05 01:02:57 +00:00
Ariel Rin
4eb7dbbe62 Merge branch 'add-margin' into 'master'
[ADD] A bit margin to the notifications

See merge request allianceauth/allianceauth!1639
2024-08-05 01:02:52 +00:00
Ariel Rin
c96ba65296 Merge branch 'avoid-KeyError-in-checks' into 'master'
[FIX] Avoid `KeyError` in `celery_settings` checks

See merge request allianceauth/allianceauth!1640
2024-08-05 01:02:40 +00:00
Peter Pfeufer
ff2f60f7f3 [FIX] Avoid KeyError in celery_settings checks 2024-08-04 18:29:43 +02:00
Peter Pfeufer
3000545c98 [ADD] A bit margin to the notifications 2024-07-26 23:09:15 +02:00
Peter Pfeufer
f3ad092ef2 [CHANGNE] Clarify that these instructions are for Docker
This should also fix the menu item title, hopefully …
2024-07-19 19:13:48 +02:00
Peter Pfeufer
a012e7df2f [FIX] Mumble URL in service card 2024-07-19 17:33:32 +02:00
Ariel Rin
1fa77412c0 Merge branch 'fix/missing-celery-setting' into 'master'
fix missing setting in celery

See merge request allianceauth/allianceauth!1636
2024-07-15 13:39:28 +00:00
Matteo Ghia
e56caeb22b fix missing setting in celery 2024-07-15 14:53:45 +02:00
Joel Falknau
ceb07ebc67 Version Bump 4.2.1 2024-07-15 22:20:32 +10:00
Ariel Rin
237075d45c Merge branch 'checklib' into 'master'
More Detail on the SQL charset check

See merge request allianceauth/allianceauth!1635
2024-07-15 12:18:47 +00:00
Ariel Rin
7099b1946d More Detail on the SQL charset check 2024-07-15 12:18:47 +00:00
Joel Falknau
e416ab8ff2 Version Bump 4.2.0 2024-07-15 21:25:00 +10:00
Joel Falknau
2802ed03a5 Add Celery to classifiers 2024-07-15 21:22:58 +10:00
Ariel Rin
4af73c76fe Merge branch 'analytics' into 'master'
Analytics

See merge request allianceauth/allianceauth!1632
2024-07-15 11:00:27 +00:00
Ariel Rin
b6149979aa Analytics 2024-07-15 11:00:26 +00:00
Ariel Rin
cb20288427 Merge branch 'checklib' into 'master'
More Checks for System Packages and Configs

See merge request allianceauth/allianceauth!1633
2024-07-15 11:00:06 +00:00
Ariel Rin
db6f4c91dc More Checks for System Packages and Configs 2024-07-15 11:00:06 +00:00
Ariel Rin
57ac7a5277 Merge branch 'center-error-messages' into 'master'
[CHANGE] Center HTTPError messages

See merge request allianceauth/allianceauth!1634
2024-07-15 03:32:34 +00:00
Peter Pfeufer
136438f9c2 [CHANGE] Center HTTPError messages 2024-07-13 00:31:44 +02:00
Ariel Rin
e2be8b3440 Merge branch 'composelint' into 'master'
Optimize Dockerfile

See merge request allianceauth/allianceauth!1630
2024-06-17 08:42:39 +00:00
Ariel Rin
04f3473ef3 Optimize Dockerfile 2024-06-17 08:42:39 +00:00
Ariel Rin
255cb0da8d Merge branch 'bootstrap-class-fixes' into 'master'
[CHANGE] Remove unnecessary bootstrap classes from the dashboard

See merge request allianceauth/allianceauth!1631
2024-06-17 08:42:34 +00:00
Peter Pfeufer
069352fb0f [FIX] Switch to bottom margin instead of top/bottom padding
This is the much more commonly used approach.
2024-06-01 12:01:44 +02:00
Peter Pfeufer
66e8ddb684 [CHANGE] Remove unnecessary bootstrap classes from the dashboard 2024-05-31 21:59:24 +02:00
Ariel Rin
179c26975c Version Bump 4.1.0 2024-05-27 14:31:41 +10:00
Ariel Rin
e17f6e799b correct capitalization 2024-05-27 14:31:21 +10:00
Ariel Rin
7cd8294104 Merge branch 'widget-title-to-framework' into 'master'
[ADD] Widget title partial to AA framework

See merge request allianceauth/allianceauth!1629
2024-05-27 04:25:56 +00:00
Peter Pfeufer
ede5540335 [ADD] Widget title partial to AA framework 2024-05-26 16:52:15 +02:00
Ariel Rin
747279b773 Merge branch 'yet-another-padding-fix' into 'master'
Some more widget fixes

See merge request allianceauth/allianceauth!1628
2024-05-26 09:08:00 +00:00
Peter Pfeufer
44f8b1c477 [FIX] Don't try to underline these links
Fixing this while I'm at it …
2024-05-26 10:06:07 +02:00
Peter Pfeufer
7c6ebd9bf6 [FIX] Yet another padding in the dashboard widgets 2024-05-26 09:52:03 +02:00
Ariel Rin
430469b708 Merge branch 'widget-padding-fix' into 'master'
[FIX] Dashboard widget padding

See merge request allianceauth/allianceauth!1627
2024-05-26 06:51:20 +00:00
Peter Pfeufer
efbb3cee31 [FIX] Dashboard widget padding 2024-05-26 08:23:57 +02:00
Ariel Rin
21094ed4dd lint 2024-05-26 13:30:21 +10:00
Ariel Rin
5f326efc7e Merge branch 'v4docs' into 'master'
Expand Tuning Doccs

See merge request allianceauth/allianceauth!1624
2024-05-26 03:22:08 +00:00
Ariel Rin
b6e34ace35 Expand Tuning Doccs 2024-05-26 03:22:08 +00:00
Ariel Rin
fe4a8965e3 Merge branch 'master' into 'master'
Improve Error Troubleshooting with Log Documentation

See merge request allianceauth/allianceauth!1619
2024-05-26 02:58:23 +00:00
Ariel Rin
23371c233d Merge branch 'bmtuk-master-patch-12042' into 'master'
Timerboard - Fix Timer deletion

See merge request allianceauth/allianceauth!1625
2024-05-26 02:56:35 +00:00
Ariel Rin
7a3bbf0d7f Merge branch 'staff-menu-item' into 'master'
Allow staff access to admin button in user menu

See merge request allianceauth/allianceauth!1626
2024-05-26 02:56:05 +00:00
Aaron Kable
89a1bec9c1 Allow staff access to admin button in user menu 2024-05-26 02:56:04 +00:00
Ben Thomas
1c1e70619a Fix ability to delete timers 2024-05-21 23:42:19 +00:00
entropylaw
634e7357be Update troubleshooting.md. Fixed Typo. 2024-04-13 21:21:13 -05:00
entropylaw
08dc88da1a Update troubleshooting.md 2024-04-13 20:59:19 -05:00
entropylaw
3d206e445c Update troubleshooting.md 2024-04-13 20:55:10 -05:00
entropylaw
64686cdad1 Update troubleshooting.md 2024-04-13 20:49:46 -05:00
AnomicDev
d7fe09bdf1 Update troubleshooting.md 2024-04-14 01:19:51 +00:00
AnomicDev
6da50da92f Update troubleshooting.md 2024-04-14 01:10:38 +00:00
AnomicDev
51e4dd986f Update troubleshooting.md 2024-04-14 01:09:56 +00:00
AnomicDev
bee6522182 Update troubleshooting.md 2024-04-14 01:07:08 +00:00
AnomicDev
1711a9dd33 Update troubleshooting.md 2024-04-14 01:05:25 +00:00
AnomicDev
3914626379 Update troubleshooting.md 2024-04-14 01:04:59 +00:00
AnomicDev
df276cb32d Update troubleshooting.md 2024-04-14 00:59:19 +00:00
AnomicDev
daad7d8b10 Update troubleshooting.md 2024-04-14 00:58:44 +00:00
AnomicDev
3bf5bc0fe3 Update troubleshooting.md 2024-04-14 00:58:09 +00:00
AnomicDev
96abae553a Update troubleshooting.md 2024-04-14 00:57:12 +00:00
AnomicDev
f9cbfb1562 Update troubleshooting.md 2024-04-14 00:55:59 +00:00
AnomicDev
8eaa94e179 Update troubleshooting.md 2024-04-14 00:55:24 +00:00
AnomicDev
4f876b648b Update troubleshooting.md 2024-04-14 00:53:16 +00:00
AnomicDev
cd738137c0 Update troubleshooting.md 2024-04-14 00:52:07 +00:00
89 changed files with 2681 additions and 1156 deletions

View File

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

View File

@@ -74,10 +74,15 @@ repos:
\.mo|
swagger\.json
)
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.41.0
hooks:
- id: markdownlint
args:
- --disable=MD013
# Infrastructure
- repo: https://github.com/tox-dev/pyproject-fmt
rev: 2.0.3
rev: 2.1.3
hooks:
- id: pyproject-fmt
name: pyproject.toml formatter
@@ -87,7 +92,7 @@ repos:
additional_dependencies:
- tox==4.15.0 # https://github.com/tox-dev/tox/releases/latest
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.17
rev: v0.18
hooks:
- id: validate-pyproject
name: Validate pyproject.toml

View File

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

View File

@@ -101,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()

View File

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

View File

@@ -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 %}

View File

@@ -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' %}">

View File

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

187
allianceauth/checks.py Normal file
View File

@@ -0,0 +1,187 @@
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://allianceauth.readthedocs.io/en/latest/installation/allianceauth.html#redis-and-other-tools", id="allianceauth.checks.A001"))
elif redis_version.major == 7 and redis_version.minor == 0:
errors.append(Warning(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint="https://allianceauth.readthedocs.io/en/latest/installation/allianceauth.html#redis-and-other-tools", id="allianceauth.checks.A002"))
elif redis_version.major == 6 and redis_version.minor == 2:
errors.append(Warning(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint="https://allianceauth.readthedocs.io/en/latest/installation/allianceauth.html#redis-and-other-tools", id="allianceauth.checks.A018"))
elif redis_version.major in [6, 5]:
errors.append(Error(f"Redis {redis_version.public} EOL", hint="https://allianceauth.readthedocs.io/en/latest/installation/allianceauth.html#redis-and-other-tools", id="allianceauth.checks.A003"))
return errors
@register()
def system_package_mysql(app_configs, **kwargs) -> List[CheckMessage]:
errors: List[CheckMessage] = []
for connection in db.connections.all():
if connection.vendor == "mysql":
try:
mysql_version = Pep440Version(".".join(str(i) for i in connection.mysql_version))
except InvalidVersion:
errors.append(Warning("Unable to confirm MySQL Version"))
return errors
# MySQL 8
if mysql_version.major == 8 and mysql_version.minor == 4 and timezone.now() > timezone.datetime(year=2032, month=4, day=30, tzinfo=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":
try:
if connection.settings_dict["OPTIONS"]["charset"] != "utf8mb4":
errors.append(Error(f"SQL Charset is not set to utf8mb4 DB:{connection.alias}", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
except KeyError:
errors.append(Error(f"SQL Charset is not set to utf8mb4 DB:{connection.alias}", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
# This hasn't actually been set on AA yet
# try:
# if connection.settings_dict["OPTIONS"]["collation"] != "utf8mb4_unicode_ci":
# errors.append(Error(f"SQL Collation is not set to utf8mb4_unicode_ci DB:{connection.alias}", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
# except KeyError:
# errors.append(Error(f"SQL Collation is not set to utf8mb4_unicode_ci DB:{connection.alias}", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
# if connection.vendor == "sqlite":
return errors
@register()
def celery_settings(app_configs, **kwargs) -> List[CheckMessage]:
errors: List[CheckMessage] = []
try:
if current_app.conf.broker_transport_options != {'priority_steps': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 'queue_order_strategy': 'priority'}:
errors.append(Error("Celery Priorities are not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc", id="allianceauth.checks.B003"))
except KeyError:
errors.append(Error("Celery Priorities are not set", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc", id="allianceauth.checks.B003"))
try:
if current_app.conf.broker_connection_retry_on_startup != True:
errors.append(Error("Celery broker_connection_retry_on_startup not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280", id="allianceauth.checks.B004"))
except KeyError:
errors.append(Error("Celery broker_connection_retry_on_startup not set", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280", id="allianceauth.checks.B004"))
return errors
# IDEAS
# Any other celery things weve manually changed over the years
# I'd be happy to add Community App checks, old versions the owners dont want to support etc.
# Check Default Collation on DB
# Check Charset Collation on all tables

View File

@@ -0,0 +1,3 @@
"""
Initializes the custom_css module.
"""

View File

@@ -0,0 +1,25 @@
"""
Admin classes for custom_css app
"""
# Django
from django.contrib import admin
# Django Solos
from solo.admin import SingletonModelAdmin
# Alliance Auth Custom CSS
from allianceauth.custom_css.models import CustomCSS
from allianceauth.custom_css.forms import CustomCSSAdminForm
@admin.register(CustomCSS)
class CustomCSSAdmin(SingletonModelAdmin):
"""
Custom CSS Admin
"""
form = CustomCSSAdminForm
# Leave this here for when we decide to add syntax highlighting to the CSS editor
# change_form_template = 'custom_css/admin/change_form.html'

View File

@@ -0,0 +1,13 @@
"""
Django app configuration for custom_css
"""
# Django
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class CustomCSSConfig(AppConfig):
name = "allianceauth.custom_css"
label = "custom_css"
verbose_name = _("Custom CSS")

View File

@@ -0,0 +1,29 @@
"""
Forms for custom_css app
"""
# Alliance Auth Custom CSS
from allianceauth.custom_css.models import CustomCSS
from allianceauth.custom_css.widgets import CssEditorWidget
# Django
from django import forms
class CustomCSSAdminForm(forms.ModelForm):
"""
Form for editing custom CSS
"""
class Meta:
model = CustomCSS
fields = ("css",)
widgets = {
"css": CssEditorWidget(
attrs={
"style": "width: 90%; height: 100%;",
"data-editor": "code-highlight",
"data-language": "css",
}
)
}

View File

@@ -0,0 +1,42 @@
# Generated by Django 4.2.15 on 2024-08-14 11:25
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="CustomCSS",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"css",
models.TextField(
blank=True,
help_text="This CSS will be added to the site after the default CSS.",
null=True,
verbose_name="Your custom CSS",
),
),
("timestamp", models.DateTimeField(auto_now=True)),
],
options={
"verbose_name": "Custom CSS",
"verbose_name_plural": "Custom CSS",
"default_permissions": (),
},
),
]

View File

@@ -0,0 +1,143 @@
"""
Models for the custom_css app
"""
import os
import re
# Django Solo
from solo.models import SingletonModel
# Django
from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _
class CustomCSS(SingletonModel):
"""
Model for storing custom CSS for the site
"""
css = models.TextField(
blank=True,
null=True,
verbose_name=_("Your custom CSS"),
help_text=_("This CSS will be added to the site after the default CSS."),
)
timestamp = models.DateTimeField(auto_now=True)
class Meta:
"""
Meta for CustomCSS
"""
default_permissions = ()
verbose_name = _("Custom CSS")
verbose_name_plural = _("Custom CSS")
def __str__(self) -> str:
"""
String representation of CustomCSS
:return:
:rtype:
"""
return str(_("Custom CSS"))
def save(self, *args, **kwargs):
"""
Save method for CustomCSS
:param args:
:type args:
:param kwargs:
:type kwargs:
:return:
:rtype:
"""
self.pk = 1
if self.css and len(self.css.replace(" ", "")) > 0:
# Write the custom CSS to a file
custom_css_file = open(
f"{settings.STATIC_ROOT}allianceauth/custom-styles.css", "w+"
)
custom_css_file.write(self.compress_css())
custom_css_file.close()
else:
# Remove the custom CSS file
try:
os.remove(f"{settings.STATIC_ROOT}allianceauth/custom-styles.css")
except FileNotFoundError:
pass
super().save(*args, **kwargs)
def compress_css(self) -> str:
"""
Compress CSS
:return:
:rtype:
"""
css = self.css
new_css = ""
# Remove comments
css = re.sub(pattern=r"\s*/\*\s*\*/", repl="$$HACK1$$", string=css)
css = re.sub(pattern=r"/\*[\s\S]*?\*/", repl="", string=css)
css = css.replace("$$HACK1$$", "/**/")
# url() doesn't need quotes
css = re.sub(pattern=r'url\((["\'])([^)]*)\1\)', repl=r"url(\2)", string=css)
# Spaces may be safely collapsed as generated content will collapse them anyway.
css = re.sub(pattern=r"\s+", repl=" ", string=css)
# Shorten collapsable colors: #aabbcc to #abc
css = re.sub(
pattern=r"#([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3(\s|;)",
repl=r"#\1\2\3\4",
string=css,
)
# Fragment values can loose zeros
css = re.sub(
pattern=r":\s*0(\.\d+([cm]m|e[mx]|in|p[ctx]))\s*;", repl=r":\1;", string=css
)
for rule in re.findall(pattern=r"([^{]+){([^}]*)}", string=css):
# We don't need spaces around operators
selectors = [
re.sub(
pattern=r"(?<=[\[\(>+=])\s+|\s+(?=[=~^$*|>+\]\)])",
repl=r"",
string=selector.strip(),
)
for selector in rule[0].split(",")
]
# Order is important, but we still want to discard repetitions
properties = {}
porder = []
for prop in re.findall(pattern="(.*?):(.*?)(;|$)", string=rule[1]):
key = prop[0].strip().lower()
if key not in porder:
porder.append(key)
properties[key] = prop[1].strip()
# output rule if it contains any declarations
if properties:
new_css += "{}{{{}}}".format(
",".join(selectors),
"".join([f"{key}:{properties[key]};" for key in porder])[:-1],
)
return new_css

View File

@@ -0,0 +1,48 @@
{% extends "admin/change_form.html" %}
{% block field_sets %}
{% for fieldset in adminform %}
<fieldset class="module aligned {{ fieldset.classes }}">
{% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
{% if fieldset.description %}
<div class="description">{{ fieldset.description|safe }}</div>
{% endif %}
{% for line in fieldset %}
<div class="form-row{% if line.fields|length == 1 and line.errors %} errors{% endif %}{% if not line.has_visible_field %} hidden{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}">
{% if line.fields|length == 1 %}{{ line.errors }}{% else %}<div class="flex-container form-multiline">{% endif %}
{% for field in line %}
<div>
{% if not line.fields|length == 1 and not field.is_readonly %}{{ field.errors }}{% endif %}
<div class="flex-container{% if not line.fields|length == 1 %} fieldBox{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% if not field.is_readonly and field.errors %} errors{% endif %}{% if field.field.is_hidden %} hidden{% endif %}{% elif field.is_checkbox %} checkbox-row{% endif %}">
{% if field.is_checkbox %}
{{ field.field }}{{ field.label_tag }}
{% else %}
{{ field.label_tag }}
{% if field.is_readonly %}
<div class="readonly">{{ field.contents }}</div>
{% else %}
{{ field.field }}
{% endif %}
{% endif %}
</div>
{% if field.field.help_text %}
<div class="help"{% if field.field.id_for_label %} id="{{ field.field.id_for_label }}_helptext"{% endif %}>
<div>{{ field.field.help_text|safe }}</div>
</div>
{% endif %}
</div>
{% endfor %}
{% if not line.fields|length == 1 %}</div>{% endif %}
</div>
{% endfor %}
</fieldset>
{% endfor %}
{% endblock %}
{% block after_field_sets %}{% endblock %}

View File

@@ -0,0 +1,3 @@
{% load custom_css %}
{% custom_css_static 'allianceauth/custom-styles.css' %}

View File

@@ -0,0 +1,3 @@
"""
Init file for custom_css templatetags
"""

View File

@@ -0,0 +1,48 @@
"""
Custom template tags for custom_css app
"""
# Alliance Auth Custom CSS
from allianceauth.custom_css.models import CustomCSS
# Django
from django.conf import settings
from django.template.defaulttags import register
from django.templatetags.static import static
from django.utils.safestring import mark_safe
from pathlib import Path
@register.simple_tag
def custom_css_static(path: str) -> str:
"""
Versioned static URL
This is to make sure to break the browser cache on CSS updates.
Example: /static/allianceauth/custom-styles.css?v=1234567890
:param path:
:type path:
:return:
:rtype:
"""
try:
Path(f"{settings.STATIC_ROOT}{path}").resolve(strict=True)
except FileNotFoundError:
return ""
else:
try:
custom_css = CustomCSS.objects.get(pk=1)
except CustomCSS.DoesNotExist:
return ""
else:
custom_css_changed = custom_css.timestamp.timestamp()
custom_css_version = (
str(custom_css_changed).replace(" ", "").replace(":", "").replace("-", "")
) # remove spaces, colons, and dashes
static_url = static(path)
versioned_url = static_url + "?v=" + custom_css_version
return mark_safe(f'<link rel="stylesheet" href="{versioned_url}">')

View File

@@ -0,0 +1,38 @@
"""
Form widgets for custom_css app
"""
# Django
from django import forms
# Alliance Auth
from allianceauth.custom_css.models import CustomCSS
class CssEditorWidget(forms.Textarea):
"""
Widget for editing CSS
"""
def __init__(self, attrs=None):
default_attrs = {"class": "custom-css-editor"}
if attrs:
default_attrs.update(attrs)
super().__init__(default_attrs)
# For when we want to add some sort of syntax highlight to it, which is not that
# easy to do on a textarea field though.
# `highlight.js` is just used as an example here, and doesn't work on a textarea field.
# class Media:
# css = {
# "all": (
# "/static/custom_css/libs/highlight.js/11.10.0/styles/github.min.css",
# )
# }
# js = (
# "/static/custom_css/libs/highlight.js/11.10.0/highlight.min.js",
# "/static/custom_css/libs/highlight.js/11.10.0/languages/css.min.js",
# "/static/custom_css/javascript/custom-css.min.js",
# )

View File

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

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-05-12 19:15+1000\n"
"POT-Creation-Date: 2024-09-09 13:05+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"
@@ -88,27 +88,31 @@ msgstr ""
msgid "Ukrainian"
msgstr ""
#: allianceauth/authentication/models.py:96
#: allianceauth/authentication/models.py:81
msgid "Polish"
msgstr ""
#: allianceauth/authentication/models.py:97
#: allianceauth/menu/templates/menu/menu-user.html:42
msgid "Language"
msgstr ""
#: allianceauth/authentication/models.py:101
#: allianceauth/authentication/models.py:102
#: allianceauth/templates/allianceauth/night-toggle.html:6
msgid "Night Mode"
msgstr ""
#: allianceauth/authentication/models.py:105
#: allianceauth/authentication/models.py:106
#: allianceauth/menu/templates/menu/menu-user.html:46
msgid "Theme"
msgstr ""
#: allianceauth/authentication/models.py:122
#: allianceauth/authentication/models.py:123
#, python-format
msgid "State changed to: %s"
msgstr ""
#: allianceauth/authentication/models.py:123
#: allianceauth/authentication/models.py:124
#, python-format
msgid "Your user's state is now: %(state)s"
msgstr ""
@@ -120,27 +124,27 @@ msgstr ""
msgid "Dashboard"
msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:7
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:5
#: 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:11
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:12
#: 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:14
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:15
#: 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:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:89
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:23
#: allianceauth/groupmanagement/templates/groupmanagement/groups.html:31
@@ -149,12 +153,12 @@ msgstr ""
msgid "Name"
msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:25
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:23
#: 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:24
#: allianceauth/corputils/templates/corputils/corpstats.html:125
#: allianceauth/hrapplications/templates/hrapplications/view.html:63
msgid "Alliance"
@@ -164,7 +168,7 @@ msgstr ""
msgid "Membership"
msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard_groups.html:8
#: allianceauth/authentication/templates/authentication/dashboard_groups.html:10
msgid "State:"
msgstr ""
@@ -395,6 +399,19 @@ msgstr ""
msgid "Failed to gather corporation statistics with selected token."
msgstr ""
#: allianceauth/custom_css/apps.py:13 allianceauth/custom_css/models.py:36
#: allianceauth/custom_css/models.py:37 allianceauth/custom_css/models.py:47
msgid "Custom CSS"
msgstr ""
#: allianceauth/custom_css/models.py:25
msgid "Your custom CSS"
msgstr ""
#: allianceauth/custom_css/models.py:26
msgid "This CSS will be added to the site after the default CSS."
msgstr ""
#: allianceauth/fleetactivitytracking/auth_hooks.py:10
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:10
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkcreate.html:11
@@ -487,8 +504,8 @@ msgstr ""
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:37
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:42
#: allianceauth/optimer/form.py:13 allianceauth/timerboard/form.py:59
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:16
#: allianceauth/optimer/form.py:13 allianceauth/timerboard/form.py:37
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:17
#: allianceauth/timerboard/templates/timerboard/timertable.html:9
msgid "System"
msgstr ""
@@ -807,7 +824,7 @@ msgstr ""
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
#: allianceauth/optimer/templates/optimer/dashboard.ops.html:15
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:15
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:16
msgid "Type"
msgstr ""
@@ -899,7 +916,7 @@ msgid "Hidden"
msgstr ""
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:45
#: allianceauth/templates/allianceauth/admin-status/overview.html:19
#: allianceauth/templates/allianceauth/admin-status/overview.html:16
msgid "Open"
msgstr ""
@@ -1375,16 +1392,16 @@ msgstr ""
msgid "Super User"
msgstr ""
#: allianceauth/menu/templates/menu/menu-user.html:68
#: allianceauth/menu/templates/menu/menu-user.html:70
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
msgid "Admin"
msgstr ""
#: allianceauth/menu/templates/menu/menu-user.html:80
#: allianceauth/menu/templates/menu/menu-user.html:82
msgid "Sign Out"
msgstr ""
#: allianceauth/menu/templates/menu/menu-user.html:84
#: allianceauth/menu/templates/menu/menu-user.html:86
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
msgid "Sign In"
@@ -1534,7 +1551,7 @@ msgid "Form Up System"
msgstr ""
#: allianceauth/optimer/templates/optimer/dashboard.ops.html:17
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:17
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:18
msgid "EVE Time"
msgstr ""
@@ -1729,17 +1746,17 @@ msgid ""
msgstr ""
#: allianceauth/services/modules/discord/templates/services/discord/discord_service_ctrl.html:26
#: allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html:20
#: allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html:22
msgid "Activate"
msgstr ""
#: allianceauth/services/modules/discord/templates/services/discord/discord_service_ctrl.html:32
#: allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html:32
#: allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html:34
msgid "Reset Password"
msgstr ""
#: allianceauth/services/modules/discord/templates/services/discord/discord_service_ctrl.html:38
#: allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html:38
#: allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html:40
msgid "Deactivate"
msgstr ""
@@ -1819,12 +1836,12 @@ msgstr ""
msgid "Deactivated IPSuite4 account."
msgstr ""
#: allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html:26
#: allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html:28
#: allianceauth/services/templates/services/service_password.html:26
msgid "Set Password"
msgstr ""
#: allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html:44
#: allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html:46
msgid "Connect"
msgstr ""
@@ -2386,56 +2403,56 @@ msgstr ""
msgid "Your Server received an ESI error response code of "
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:11
#: allianceauth/templates/allianceauth/admin-status/overview.html:8
msgid "Alliance Auth Notifications"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:21
#: allianceauth/templates/allianceauth/admin-status/overview.html:18
msgid "Closed"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:27
#: allianceauth/templates/allianceauth/admin-status/overview.html:24
msgid "No notifications at this time"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:36
#: allianceauth/templates/allianceauth/admin-status/overview.html:33
msgid "Powered by GitLab"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:42
#: allianceauth/templates/allianceauth/admin-status/overview.html:39
msgid "Support Discord"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:59
#: allianceauth/templates/allianceauth/admin-status/overview.html:63
#: allianceauth/templates/allianceauth/admin-status/overview.html:53
#: allianceauth/templates/allianceauth/admin-status/overview.html:57
msgid "Software Version"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:66
#: allianceauth/templates/allianceauth/admin-status/overview.html:60
msgid "Current"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:73
#: allianceauth/templates/allianceauth/admin-status/overview.html:67
msgid "Latest Stable"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:78
#: allianceauth/templates/allianceauth/admin-status/overview.html:72
msgid "Update available"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:86
#: allianceauth/templates/allianceauth/admin-status/overview.html:80
msgid "Latest Pre-Release"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:91
#: allianceauth/templates/allianceauth/admin-status/overview.html:85
msgid "Pre-Release available"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:102
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
msgid "Task Queue"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:107
#: allianceauth/templates/allianceauth/admin-status/overview.html:100
#, python-format
msgid ""
"\n"
@@ -2444,11 +2461,11 @@ msgid ""
" "
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:123
#: allianceauth/templates/allianceauth/admin-status/overview.html:116
msgid "running"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:124
#: allianceauth/templates/allianceauth/admin-status/overview.html:117
msgid "queued"
msgstr ""
@@ -2477,105 +2494,203 @@ msgstr ""
msgid "Select Theme"
msgstr ""
#: allianceauth/timerboard/form.py:53
#: allianceauth/timerboard/templates/timerboard/timertable.html:172
msgid "Other"
msgstr ""
#: allianceauth/timerboard/form.py:54
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:38
#: allianceauth/timerboard/templates/timerboard/timertable.html:44
msgid "Friendly"
msgstr ""
#: allianceauth/timerboard/form.py:55
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:33
#: allianceauth/timerboard/templates/timerboard/timertable.html:38
msgid "Hostile"
msgstr ""
#: allianceauth/timerboard/form.py:56
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:43
#: allianceauth/timerboard/templates/timerboard/timertable.html:50
msgid "Neutral"
msgstr ""
#: allianceauth/timerboard/form.py:58
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:13
#: allianceauth/timerboard/form.py:36
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:14
#: allianceauth/timerboard/templates/timerboard/timertable.html:7
msgid "Details"
msgstr ""
#: allianceauth/timerboard/form.py:60
#: allianceauth/timerboard/form.py:38
msgid "Planet/Moon"
msgstr ""
#: allianceauth/timerboard/form.py:61
#: allianceauth/timerboard/form.py:39
msgid "Structure Type"
msgstr ""
#: allianceauth/timerboard/form.py:62
#: allianceauth/timerboard/form.py:40
msgid "Timer Type"
msgstr ""
#: allianceauth/timerboard/form.py:63
#: allianceauth/timerboard/form.py:41
#: allianceauth/timerboard/templates/timerboard/timertable.html:8
msgid "Objective"
msgstr ""
#: allianceauth/timerboard/form.py:64
#: allianceauth/timerboard/form.py:42
msgid "Absolute Timer"
msgstr ""
#: allianceauth/timerboard/form.py:65
#: allianceauth/timerboard/form.py:43
msgid "Date and Time"
msgstr ""
#: allianceauth/timerboard/form.py:66
#: allianceauth/timerboard/form.py:44
msgid "Days Remaining"
msgstr ""
#: allianceauth/timerboard/form.py:67
#: allianceauth/timerboard/form.py:45
msgid "Hours Remaining"
msgstr ""
#: allianceauth/timerboard/form.py:69
#: allianceauth/timerboard/form.py:47
msgid "Minutes Remaining"
msgstr ""
#: allianceauth/timerboard/form.py:71
#: allianceauth/timerboard/form.py:48
msgid "Important"
msgstr ""
#: allianceauth/timerboard/form.py:72
#: allianceauth/timerboard/form.py:49
msgid "Corp-Restricted"
msgstr ""
#: allianceauth/timerboard/models.py:13
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:39
#: allianceauth/timerboard/templates/timerboard/timertable.html:36
msgid "Friendly"
msgstr ""
#: allianceauth/timerboard/models.py:14
msgid "Not Specified"
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:34
#: allianceauth/timerboard/templates/timerboard/timertable.html:34
msgid "Hostile"
msgstr ""
#: allianceauth/timerboard/models.py:15
msgid "Shield"
msgstr ""
#: allianceauth/timerboard/models.py:16
msgid "Armor"
msgstr ""
#: allianceauth/timerboard/models.py:17
msgid "Hull"
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:44
#: allianceauth/timerboard/templates/timerboard/timertable.html:38
msgid "Neutral"
msgstr ""
#: allianceauth/timerboard/models.py:18
msgid "Final"
#: allianceauth/timerboard/templates/timerboard/timertable.html:48
msgid "POCO"
msgstr ""
#: allianceauth/timerboard/models.py:19
msgid "Anchoring"
#: allianceauth/timerboard/templates/timerboard/timertable.html:50
msgid "Orbital Skyhook"
msgstr ""
#: allianceauth/timerboard/models.py:20
#: allianceauth/timerboard/templates/timerboard/timertable.html:52
msgid "I-HUB"
msgstr ""
#: allianceauth/timerboard/models.py:21
#: allianceauth/timerboard/templates/timerboard/timertable.html:54
msgid "TCU"
msgstr ""
#: allianceauth/timerboard/models.py:22
#: allianceauth/timerboard/templates/timerboard/timertable.html:56
msgid "POS [S]"
msgstr ""
#: allianceauth/timerboard/models.py:23
#: allianceauth/timerboard/templates/timerboard/timertable.html:58
msgid "POS [M]"
msgstr ""
#: allianceauth/timerboard/models.py:24
#: allianceauth/timerboard/templates/timerboard/timertable.html:60
msgid "POS [L]"
msgstr ""
#: allianceauth/timerboard/models.py:25
#: allianceauth/timerboard/templates/timerboard/timertable.html:62
msgid "Astrahus"
msgstr ""
#: allianceauth/timerboard/models.py:26
#: allianceauth/timerboard/templates/timerboard/timertable.html:64
msgid "Fortizar"
msgstr ""
#: allianceauth/timerboard/models.py:27
#: allianceauth/timerboard/templates/timerboard/timertable.html:66
msgid "Keepstar"
msgstr ""
#: allianceauth/timerboard/models.py:28
#: allianceauth/timerboard/templates/timerboard/timertable.html:68
msgid "Raitaru"
msgstr ""
#: allianceauth/timerboard/models.py:29
#: allianceauth/timerboard/templates/timerboard/timertable.html:70
msgid "Azbel"
msgstr ""
#: allianceauth/timerboard/models.py:30
#: allianceauth/timerboard/templates/timerboard/timertable.html:72
msgid "Sotiyo"
msgstr ""
#: allianceauth/timerboard/models.py:31
#: allianceauth/timerboard/templates/timerboard/timertable.html:74
msgid "Athanor"
msgstr ""
#: allianceauth/timerboard/models.py:32
#: allianceauth/timerboard/templates/timerboard/timertable.html:76
msgid "Tatara"
msgstr ""
#: allianceauth/timerboard/models.py:33
msgid "Pharolux Cyno Beacon"
msgstr ""
#: allianceauth/timerboard/models.py:34
msgid "Tenebrex Cyno Jammer"
msgstr ""
#: allianceauth/timerboard/models.py:35
#: allianceauth/timerboard/templates/timerboard/timertable.html:82
msgid "Ansiblex Jump Gate"
msgstr ""
#: allianceauth/timerboard/models.py:36
#: allianceauth/timerboard/templates/timerboard/timertable.html:84
msgid "Moon Mining Cycle"
msgstr ""
#: allianceauth/timerboard/models.py:37
#: allianceauth/timerboard/templates/timerboard/timertable.html:86
msgid "Metenox Moon Drill"
msgstr ""
#: allianceauth/timerboard/models.py:38
#: allianceauth/timerboard/templates/timerboard/timertable.html:88
msgid "Other"
msgstr ""
#: allianceauth/timerboard/models.py:45
msgid "Not Specified"
msgstr ""
#: allianceauth/timerboard/models.py:46
msgid "Shield"
msgstr ""
#: allianceauth/timerboard/models.py:47
msgid "Armor"
msgstr ""
#: allianceauth/timerboard/models.py:48
msgid "Hull"
msgstr ""
#: allianceauth/timerboard/models.py:49
msgid "Final"
msgstr ""
#: allianceauth/timerboard/models.py:50
msgid "Anchoring"
msgstr ""
#: allianceauth/timerboard/models.py:51
msgid "Unanchoring"
msgstr ""
@@ -2584,7 +2699,7 @@ msgstr ""
msgid "Upcoming Timers"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:14
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:15
msgid "Timer"
msgstr ""
@@ -2628,78 +2743,14 @@ msgstr ""
msgid "Structure"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:64
msgid "POCO"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:70
msgid "I-HUB"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:76
msgid "TCU"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:82
msgid "POS [S]"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:88
msgid "POS [M]"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:94
msgid "POS [L]"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:100
msgid "Astrahus"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:106
msgid "Fortizar"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:112
msgid "Keepstar"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:118
msgid "Raitaru"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:124
msgid "Azbel"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:130
msgid "Sotiyo"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:136
msgid "Athanor"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:142
msgid "Tatara"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:148
#: allianceauth/timerboard/templates/timerboard/timertable.html:78
msgid "Cyno Beacon"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:154
#: allianceauth/timerboard/templates/timerboard/timertable.html:80
msgid "Cyno Jammer"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:160
msgid "Ansiblex Jump Gate"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/timertable.html:166
msgid "Moon Mining Cycle"
msgstr ""
#: allianceauth/timerboard/templates/timerboard/view.html:9
msgid "Structure Timer Management"
msgstr ""

View File

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

View File

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

View File

@@ -22,6 +22,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'django.contrib.humanize',
'django_celery_beat',
'solo',
'bootstrapform',
'django_bootstrap5', # https://github.com/zostera/django-bootstrap5
'sortedm2m',
@@ -39,6 +40,7 @@ INSTALLED_APPS = [
'allianceauth.theme.darkly',
'allianceauth.theme.flatly',
'allianceauth.theme.materia',
"allianceauth.custom_css",
]
SECRET_KEY = "wow I'm a really bad default secret key"

View File

@@ -7,7 +7,9 @@
{% endblock %}
{% block url %}
<a href="{{ service_url }}">{{ service_url }}</a>
{% if username != '' %}
<a href="mumble://{{ connect_url }}">{{ service_url }}</a>
{% endif %}
{% endblock %}
{% block user %}

View File

@@ -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, {

View File

@@ -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 me-2">{% translate "Open" %}</span>
{% else %}
<span class="badge bg-danger me-2">{% translate "Closed" %}</span>
{% endif %}
<a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a>
</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,15 +46,14 @@
</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 h-100 w-100 cursor-default">
@@ -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 }}

View File

@@ -35,6 +35,8 @@
</style>
{% block extra_css %}{% endblock extra_css %}
{% include 'custom_css/bundles/custom-css.html' %}
</head>
<body>

View File

@@ -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 %}

View File

@@ -27,6 +27,7 @@ class BootstrapThemeHook(ThemeHook):
self,
"Bootstrap",
"Powerful, extensible, and feature-packed frontend toolkit.",
html_tags={"data-theme": "bootstrap"},
css=CSS_STATICS,
js=JS_STATICS,
header_padding="3.5em"
@@ -44,9 +45,9 @@ class BootstrapDarkThemeHook(ThemeHook):
self,
"Bootstrap Dark",
"Powerful, extensible, and feature-packed frontend toolkit.",
html_tags={"data-theme": "bootstrap-dark"},
css=CSS_STATICS,
js=JS_STATICS,
html_tags="data-bs-theme=dark",
header_padding="3.5em"
)

View File

@@ -13,6 +13,7 @@ class DarklyThemeHook(ThemeHook):
self,
"Darkly",
"Flatly in night mode!",
html_tags={"data-theme": "darkly"},
css=[{
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.3/darkly/bootstrap.min.css",
"integrity": "sha512-HDszXqSUU0om4Yj5dZOUNmtwXGWDa5ppESlX98yzbBS+z+3HQ8a/7kcdI1dv+jKq+1V5b01eYurE7+yFjw6Rdg=="

View File

@@ -13,6 +13,7 @@ class FlatlyThemeHook(ThemeHook):
self,
"Flatly",
"Flat and modern!",
html_tags={"data-theme": "flatly"},
css=[{
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.3/flatly/bootstrap.min.css",
"integrity": "sha512-qoT4KwnRpAQ9uczPsw7GunsNmhRnYwSlE2KRCUPRQHSkDuLulCtDXuC2P/P6oqr3M5hoGagUG9pgHDPkD2zCDA=="

View File

@@ -1,10 +1,10 @@
from typing import List, Optional
from typing import List, Optional, Union
class ThemeHook:
"""
Theme hook for injecting a Bootstrap 5 Theme and associated JS into alliance auth.
these can be local or CDN delivered
Theme hook for injecting a Bootstrap 5 Theme and associated JS into alliance auth.
These can be local or CDN delivered.
"""
def __init__(self,
@@ -14,7 +14,7 @@ class ThemeHook:
js: List[dict],
css_template: Optional[str] = None,
js_template: Optional[str] = None,
html_tags: Optional[str] = "",
html_tags: Optional[Union[dict, str]] = None,
header_padding: Optional[str] = "4em"):
"""
:param name: Theme python name
@@ -29,6 +29,10 @@ class ThemeHook:
:type css_template: Optional[str], optional
:param js_template: _description_, defaults to None
:type js_template: Optional[str], optional
:param html_tags: Attributes added to the `<html>` tag, defaults to None
:type html_tags: Optional[dict|str], optional
:param header_padding: Top padding, defaults to "4em"
:type header_padding: Optional[str], optional
"""
self.name = name
self.description = description
@@ -41,7 +45,11 @@ class ThemeHook:
self.css_template = css_template
self.js_template = js_template
self.html_tags = html_tags
self.html_tags = (
" ".join([f"{key}={value}" for key, value in html_tags.items()])
if isinstance(html_tags, dict)
else html_tags
)
self.header_padding = header_padding
def get_name(self):
return f"{self.__class__.__module__}.{self.__class__.__name__}"

View File

@@ -13,6 +13,7 @@ class MateriaThemeHook(ThemeHook):
self,
"Materia",
"Material is the metaphor",
html_tags={"data-theme": "materia"},
css=[{
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.3/materia/bootstrap.min.css",
"integrity": "sha512-2S9Do+uTmZmmJpdmAcOKdUrK/YslcvAuRfIF2ws8+BW9AvZXMRZM+o8Wq+PZrfISD6ZlIaeCWWZAdeprXIoYuQ=="

View File

@@ -1,11 +1,12 @@
import logging
import datetime
import logging
from django import forms
from django.utils import timezone
from django.core.validators import MaxValueValidator, MinValueValidator
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from .models import Timer, TimerType
from .models import Timer
logger = logging.getLogger(__name__)
@@ -32,54 +33,28 @@ class TimerForm(forms.ModelForm):
kwargs.update({'initial': initial})
super().__init__(*args, **kwargs)
structure_choices = [('POCO', 'POCO'),
('I-HUB', 'I-HUB'),
('TCU', 'TCU'),
('POS[S]', 'POS[S]'),
('POS[M]', 'POS[M]'),
('POS[L]', 'POS[L]'),
('Astrahus', 'Astrahus'),
('Fortizar', 'Fortizar'),
('Keepstar', 'Keepstar'),
('Raitaru', 'Raitaru'),
('Azbel', 'Azbel'),
('Sotiyo', 'Sotiyo'),
('Athanor', 'Athanor'),
('Tatara', 'Tatara'),
('Pharolux Cyno Beacon', 'Pharolux Cyno Beacon'),
('Tenebrex Cyno Jammer', 'Tenebrex Cyno Jammer'),
('Ansiblex Jump Gate', 'Ansiblex Jump Gate'),
('Moon Mining Cycle', 'Moon Mining Cycle'),
(_('Other'), _('Other'))]
objective_choices = [('Friendly', _('Friendly')),
('Hostile', _('Hostile')),
('Neutral', _('Neutral'))]
details = forms.CharField(max_length=254, required=True, label=_('Details'))
system = forms.CharField(max_length=254, required=True, label=_("System"))
planet_moon = forms.CharField(max_length=254, label=_("Planet/Moon"), required=False, initial="")
structure = forms.ChoiceField(choices=structure_choices, required=True, label=_("Structure Type"))
timer_type = forms.ChoiceField(choices=TimerType.choices, label=_("Timer Type"))
objective = forms.ChoiceField(choices=objective_choices, required=True, label=_("Objective"))
structure = forms.ChoiceField(choices=Timer.Structure.choices, required=True, label=_("Structure Type"))
timer_type = forms.ChoiceField(choices=Timer.TimerType.choices, label=_("Timer Type"))
objective = forms.ChoiceField(choices=Timer.Objective.choices, required=True, label=_("Objective"))
absolute_checkbox = forms.BooleanField(label=_("Absolute Timer"), required=False, initial=False)
absolute_time = forms.CharField(required=False,label=_("Date and Time"))
days_left = forms.IntegerField(required=False, label=_("Days Remaining"), validators=[MinValueValidator(0)])
hours_left = forms.IntegerField(required=False, label=_("Hours Remaining"),
validators=[MinValueValidator(0), MaxValueValidator(23)])
minutes_left = forms.IntegerField(required=False, label=_("Minutes Remaining"),
validators=[MinValueValidator(0), MaxValueValidator(59)])
minutes_left = forms.IntegerField(required=False, label=_("Minutes Remaining"), validators=[MinValueValidator(0), MaxValueValidator(59)])
important = forms.BooleanField(label=_("Important"), required=False)
corp_timer = forms.BooleanField(label=_("Corp-Restricted"), required=False)
def save(self, commit=True):
timer = super().save(commit=False)
# Get character
character = self.user.profile.main_character
corporation = character.corporation
logger.debug("Determined timer save request on behalf "
"of character {} corporation {}".format(character, corporation))
logger.debug(f"Determined timer save request on behalf of character {character} corporation {corporation}")
days_left = self.cleaned_data['days_left']
hours_left = self.cleaned_data['hours_left']

View File

@@ -0,0 +1,28 @@
# Generated by Django 4.2 on 2024-09-09 03:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('timerboard', '0005_alter_timer_planet_moon'),
]
operations = [
migrations.AlterField(
model_name='timer',
name='objective',
field=models.CharField(choices=[('Friendly', 'Friendly'), ('Hostile', 'Hostile'), ('Neutral', 'Neutral')], default='Neutral', max_length=254),
),
migrations.AlterField(
model_name='timer',
name='structure',
field=models.CharField(choices=[('POCO', 'POCO'), ('Orbital Skyhook', 'Orbital Skyhook'), ('I-HUB', 'I-HUB'), ('TCU', 'TCU'), ('POS[S]', 'POS [S]'), ('POS[M]', 'POS [M]'), ('POS[L]', 'POS [L]'), ('Astrahus', 'Astrahus'), ('Fortizar', 'Fortizar'), ('Keepstar', 'Keepstar'), ('Raitaru', 'Raitaru'), ('Azbel', 'Azbel'), ('Sotiyo', 'Sotiyo'), ('Athanor', 'Athanor'), ('Tatara', 'Tatara'), ('Pharolux Cyno Beacon', 'Pharolux Cyno Beacon'), ('Tenebrex Cyno Jammer', 'Tenebrex Cyno Jammer'), ('Ansiblex Jump Gate', 'Ansiblex Jump Gate'), ('Moon Mining Cycle', 'Moon Mining Cycle'), ('Metenox Moon Drill', 'Metenox Moon Drill'), ('Other', 'Other')], default='Other', max_length=254),
),
migrations.AlterField(
model_name='timer',
name='timer_type',
field=models.CharField(choices=[('UNSPECIFIED', 'Not Specified'), ('SHIELD', 'Shield'), ('ARMOR', 'Armor'), ('HULL', 'Hull'), ('FINAL', 'Final'), ('ANCHORING', 'Anchoring'), ('UNANCHORING', 'Unanchoring'), ('ABANDONED', 'Abandoned')], default='UNSPECIFIED', max_length=254),
),
]

View File

@@ -6,34 +6,63 @@ from allianceauth.eveonline.models import EveCharacter
from allianceauth.eveonline.models import EveCorporationInfo
class TimerType(models.TextChoices):
"""
Choices for Timer Type
"""
UNSPECIFIED = "UNSPECIFIED", _("Not Specified")
SHIELD = "SHIELD", _("Shield")
ARMOR = "ARMOR", _("Armor")
HULL = "HULL", _("Hull")
FINAL = "FINAL", _("Final")
ANCHORING = "ANCHORING", _("Anchoring")
UNANCHORING = "UNANCHORING", _("Unanchoring")
class Timer(models.Model):
class Meta:
ordering = ['eve_time']
class Objective(models.TextChoices):
"""
Choices for Objective Type
"""
FRIENDLY = "Friendly", _("Friendly")
HOSTILE = "Hostile", _("Hostile")
NEUTRAL = "Neutral", _("Neutral")
class Structure(models.TextChoices):
"""
Choices for Structure Type
"""
POCO = "POCO", _("POCO")
ORBITALSKYHOOK = "Orbital Skyhook", _("Orbital Skyhook")
IHUB = "I-HUB", _("I-HUB")
TCU = "TCU", _("TCU") # Pending Remval
POSS = "POS[S]", _("POS [S]")
POSM = "POS[M]", _("POS [M]")
POSL = "POS[L]", _("POS [L]")
ASTRAHUS = "Astrahus", _("Astrahus")
FORTIZAR = "Fortizar", _("Fortizar")
KEEPSTAR = "Keepstar", _("Keepstar")
RAITARU = "Raitaru", _("Raitaru")
AZBEL = "Azbel", _("Azbel")
SOTIYO = "Sotiyo", _("Sotiyo")
ATHANOR = "Athanor", _("Athanor")
TATARA = "Tatara", _("Tatara")
PHAROLUX = "Pharolux Cyno Beacon", _("Pharolux Cyno Beacon")
TENEBREX = "Tenebrex Cyno Jammer", _("Tenebrex Cyno Jammer")
ANSIBLEX = "Ansiblex Jump Gate", _("Ansiblex Jump Gate")
MOONPOP = "Moon Mining Cycle", _("Moon Mining Cycle")
METENOX = "Metenox Moon Drill", _("Metenox Moon Drill")
OTHER = "Other", _("Other")
class TimerType(models.TextChoices):
"""
Choices for Timer Type
"""
UNSPECIFIED = "UNSPECIFIED", _("Not Specified")
SHIELD = "SHIELD", _("Shield")
ARMOR = "ARMOR", _("Armor")
HULL = "HULL", _("Hull")
FINAL = "FINAL", _("Final")
ANCHORING = "ANCHORING", _("Anchoring")
UNANCHORING = "UNANCHORING", _("Unanchoring")
ABANDONED = "ABANDONED", _("Abandoned")
details = models.CharField(max_length=254, default="")
system = models.CharField(max_length=254, default="")
planet_moon = models.CharField(max_length=254, blank=True, default="")
structure = models.CharField(max_length=254, default="")
timer_type = models.CharField(
max_length=254,
choices=TimerType.choices,
default=TimerType.UNSPECIFIED,
)
objective = models.CharField(max_length=254, default="")
structure = models.CharField(max_length=254,choices=Structure.choices,default=Structure.OTHER)
timer_type = models.CharField(max_length=254,choices=TimerType.choices,default=TimerType.UNSPECIFIED)
objective = models.CharField(max_length=254, choices=Objective.choices, default=Objective.NEUTRAL)
eve_time = models.DateTimeField()
important = models.BooleanField(default=False)
eve_character = models.ForeignKey(EveCharacter, null=True, on_delete=models.SET_NULL)
@@ -41,5 +70,8 @@ class Timer(models.Model):
corp_timer = models.BooleanField(default=False)
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
def __str__(self):
def __str__(self) -> str:
return str(self.system) + ' ' + str(self.details)
class Meta:
ordering = ['eve_time']

View File

@@ -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>
<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-secondary">
{% 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>

View File

@@ -18,174 +18,85 @@
</tr>
{% for timer in timers %}
{% if timer.important == True %}
<tr class="bg-danger bg-opacity-25">
{% else %}
<tr class="bg-info bg-opacity-25">
{% endif %}
<tr class="{% if timer.important == True %}bg-danger bg-opacity-25{% else %}bg-info bg-opacity-25{% endif %}">
<td style="width: 150px;" class="text-center">
{{ timer.details }}
{% if timer.timer_type != 'UNSPECIFIED' %}
<br>({{ timer.get_timer_type_display }})
<br />
({{ timer.get_timer_type_display }})
{% endif %}
</td>
<td class="text-center">
{% 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>
<div class="badge bg-danger">{% translate "Hostile" %}</div>
{% elif timer.objective == "Friendly" %}
<div class="badge bg-primary">{% translate "Friendly" %}</div>
{% elif timer.objective == "Neutral" %}
<div class="badge bg-secondary">{% translate "Neutral" %}</div>
{% endif %}
</td>
<td class="text-center">
<a href="{{ timer.system|dotlan_solar_system_url }}">
{{ timer.system }} {{ timer.planet_moon }}
</a>
<a href="{{ timer.system|dotlan_solar_system_url }}">{{ timer.system }} {{ timer.planet_moon }}</a>
</td>
<td class="text-center">
{% if timer.structure == "POCO" %}
<div class="badge bg-info">
{% translate "POCO" %}
</div>
{% endif %}
{% if timer.structure == "I-HUB" %}
<div class="badge bg-warning">
{% translate "I-HUB" %}
</div>
{% endif %}
{% if timer.structure == "TCU" %}
<div class="badge bg-danger">
{% translate "TCU" %}
</div>
{% endif %}
{% if timer.structure == "POS[S]" %}
<div class="badge bg-info">
{% translate "POS [S]" %}
</div>
{% endif %}
{% if timer.structure == "POS[M]" %}
<div class="badge bg-info">
{% translate "POS [M]" %}
</div>
{% endif %}
{% if timer.structure == "POS[L]" %}
<div class="badge bg-info">
{% translate "POS [L]" %}
</div>
{% endif %}
{% if timer.structure == "Citadel[M]" or timer.structure == "Astrahus" %}
<div class="badge bg-danger">
{% translate "Astrahus" %}
</div>
{% endif %}
{% if timer.structure == "Citadel[L]" or timer.structure == "Fortizar" %}
<div class="badge bg-danger">
{% translate "Fortizar" %}
</div>
{% endif %}
{% if timer.structure == "Citadel[XL]" or timer.structure == "Keepstar" %}
<div class="badge bg-danger">
{% translate "Keepstar" %}
</div>
{% endif %}
{% if timer.structure == "Engineering Complex[M]" or timer.structure == "Raitaru" %}
<div class="badge bg-warning">
{% translate "Raitaru" %}
</div>
{% endif %}
{% if timer.structure == "Engineering Complex[L]" or timer.structure == "Azbel" %}
<div class="badge bg-warning">
{% translate "Azbel" %}
</div>
{% endif %}
{% if timer.structure == "Engineering Complex[XL]" or timer.structure == "Sotiyo" %}
<div class="badge bg-warning">
{% translate "Sotiyo" %}
</div>
{% endif %}
{% if timer.structure == "Refinery[M]" or timer.structure == "Athanor" %}
<div class="badge bg-warning">
{% translate "Athanor" %}
</div>
{% endif %}
{% if timer.structure == "Refinery[L]" or timer.structure == "Tatara"%}
<div class="badge bg-warning">
{% translate "Tatara" %}
</div>
{% endif %}
{% if timer.structure == "Cyno Beacon" or timer.structure == "Pharolux Cyno Beacon" %}
<div class="badge bg-warning">
{% translate "Cyno Beacon" %}
</div>
{% endif %}
{% if timer.structure == "Cyno Jammer" or timer.structure == "Tenebrex Cyno Jammer" %}
<div class="badge bg-warning">
{% translate "Cyno Jammer" %}
</div>
{% endif %}
{% if timer.structure == "Jump Gate" or timer.structure == "Ansiblex Jump Gate" %}
<div class="badge bg-warning">
{% translate "Ansiblex Jump Gate" %}
</div>
{% endif %}
{% if timer.structure == "Moon Mining Cycle" %}
<div class="badge bg-success">
{% translate "Moon Mining Cycle" %}
</div>
{% endif %}
{% if timer.structure == "Other" %}
<div class="badge bg-default">
{% translate "Other" %}
</div>
<div class="badge bg-info">{% translate "POCO" %}</div>
{% elif timer.structure == "Orbital Skyhook" %}
<div class="badge bg-warning">{% translate "Orbital Skyhook" %}</div>
{% elif timer.structure == "I-HUB" %}
<div class="badge bg-warning">{% translate "I-HUB" %}</div>
{% elif timer.structure == "TCU" %} {% comment %} Pending Removal {% endcomment %}
<div class="badge bg-secondary">{% translate "TCU" %}</div>
{% elif timer.structure == "POS[S]" %}
<div class="badge bg-info">{% translate "POS [S]" %}</div>
{% elif timer.structure == "POS[M]" %}
<div class="badge bg-info">{% translate "POS [M]" %}</div>
{% elif timer.structure == "POS[L]" %}
<div class="badge bg-info">{% translate "POS [L]" %}</div>
{% elif timer.structure == "Citadel[M]" or timer.structure == "Astrahus" %}
<div class="badge bg-danger">{% translate "Astrahus" %}</div>
{% elif timer.structure == "Citadel[L]" or timer.structure == "Fortizar" %}
<div class="badge bg-danger">{% translate "Fortizar" %}</div>
{% elif timer.structure == "Citadel[XL]" or timer.structure == "Keepstar" %}
<div class="badge bg-danger">{% translate "Keepstar" %}</div>
{% elif timer.structure == "Engineering Complex[M]" or timer.structure == "Raitaru" %}
<div class="badge bg-warning">{% translate "Raitaru" %}</div>
{% elif timer.structure == "Engineering Complex[L]" or timer.structure == "Azbel" %}
<div class="badge bg-warning">{% translate "Azbel" %}</div>
{% elif timer.structure == "Engineering Complex[XL]" or timer.structure == "Sotiyo" %}
<div class="badge bg-danger">{% translate "Sotiyo" %}</div>
{% elif timer.structure == "Refinery[M]" or timer.structure == "Athanor" %}
<div class="badge bg-warning">{% translate "Athanor" %}</div>
{% elif timer.structure == "Refinery[L]" or timer.structure == "Tatara" %}
<div class="badge bg-warning">{% translate "Tatara" %}</div>
{% elif timer.structure == "Cyno Beacon" or timer.structure == "Pharolux Cyno Beacon" %}
<div class="badge bg-warning">{% translate "Cyno Beacon" %}</div>
{% elif timer.structure == "Cyno Jammer" or timer.structure == "Tenebrex Cyno Jammer" %}
<div class="badge bg-warning">{% translate "Cyno Jammer" %}</div>
{% elif timer.structure == "Jump Gate" or timer.structure == "Ansiblex Jump Gate" %}
<div class="badge bg-warning">{% translate "Ansiblex Jump Gate" %}</div>
{% elif timer.structure == "Moon Mining Cycle" %}
<div class="badge bg-success">{% translate "Moon Mining Cycle" %}</div>
{% elif timer.structure == "Metenox Moon Drill" %}
<div class="badge bg-warning">{% translate "Metenox Moon Drill" %}</div>
{% elif timer.structure == "Other" %}
<div class="badge bg-secondary">{% translate "Other" %}</div>
{% endif %}
</td>
<td class="text-center" nowrap>
{{ timer.eve_time | date:"Y-m-d H:i" }}
</td>
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
<td class="text-center" nowrap>
<div id="localtime{{ timer.id }}"></div>
<div id="countdown{{ timer.id }}"></div>
</td>
<td class="text-center">
{{ timer.eve_character.character_name }}
</td>
<td class="text-center">{{ timer.eve_character.character_name }}</td>
{% if perms.auth.timer_management %}
<td class="text-center">

View File

@@ -167,8 +167,8 @@ class TimerboardViewsTestCase(WebTest):
form['details'] = 'details'
form['system'] = 'jita'
form['planet_moon'] = '4-4'
form['structure'] = TimerForm.structure_choices[0][0]
form['objective'] = TimerForm.objective_choices[0][0]
form['structure'] = Timer.Structure.choices[0][0]
form['objective'] = Timer.Objective.choices[0][0]
form['days_left'] = 1
form['hours_left'] = 2
form['minutes_left'] = 3
@@ -206,8 +206,8 @@ class TimerboardViewsTestCase(WebTest):
form['details'] = 'detailsUNIQUE'
form['system'] = 'jita'
form['planet_moon'] = '4-4'
form['structure'] = TimerForm.structure_choices[0][0]
form['objective'] = TimerForm.objective_choices[0][0]
form['structure'] = Timer.Structure.choices[0][0]
form['objective'] = Timer.Objective.choices[0][0]
form['days_left'] = 1
form['hours_left'] = 2
form['minutes_left'] = 3

View File

@@ -97,7 +97,7 @@ class EditTimerView(TimerManagementView, AddUpdateMixin, UpdateView):
class RemoveTimerView(TimerManagementView, DeleteView):
form_class = TimerForm
pass
def dashboard_timers(request):

View File

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

View File

@@ -1,5 +1,5 @@
FROM python:3.11-slim
ARG AUTH_VERSION=v4.0.2
ARG AUTH_VERSION=v4.3.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

View File

@@ -9,6 +9,10 @@ from django.conf import settings # noqa
app = Celery('myauth')
# Automatically try to establish the connection to the AMQP broker on
# Celery startup if it is unavailable.
app.conf.broker_connection_retry_on_startup = True
# Using a string here means the worker don't have to serialize
# the configuration object to child processes.
app.config_from_object('django.conf:settings')

View File

@@ -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;
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -337,7 +337,7 @@ To deactivate, click on the debug icon to switch to the debug view. Then uncheck
### AA debug config
In VSC, click on Debug / Add Configuration and choose "Django". Should Django not appear as an option, make sure to first open a Django file (e.g., the local.py settings) to help VSC detect that you are using Django.
In VSC, click on Debug / Add Configuration and choose "Django". Should Django not appear as an option, make sure to first open a Django file (e.g., the `local.py` settings) to help VSC detect that you are using Django.
The result should look something like this:

View File

@@ -4,9 +4,33 @@ Auto Groups allows you to automatically place users of certain states into corp
## Installation
This is an optional app that needs to be installed.
- Add `'allianceauth.eveonline.autogroups',` to `INSTALLED_APPS` in your `local.py`
To install this app add `'allianceauth.eveonline.autogroups',` to your `INSTALLED_APPS` list and run migrations. All other settings are controlled via the admin panel under the `Eve_Autogroups` section.
Perform Django Maintenance and restart our Web Service and Workers.
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate
python manage.py collectstatic --noinput
supervisorctl restart myauth:
```
:::
:::{group-tab} Containerized
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
auth collectstatic
```
:::
::::
All other settings are controlled via the admin panel under the `Eve_Autogroups` section.
## Configuring a group

View File

@@ -8,7 +8,31 @@ This module is used to check the registration status of Corp members and to dete
Corp Stats requires access to the `esi-corporations.read_corporation_membership.v1` SSO scope. Update your application on the [EVE Developers site](https://developers.eveonline.com) to ensure it is available.
Add `'allianceauth.corputils',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
- Add `'allianceauth.corputils',` to `INSTALLED_APPS` in your `local.py`
Perform Django Maintenance and restart our Web Service and Workers.
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate
python manage.py collectstatic --noinput
supervisorctl restart myauth:
```
:::
:::{group-tab} Containerized
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
auth collectstatic
```
:::
::::
## Creating a Corp Stats

View File

@@ -8,7 +8,31 @@ The Fleet Activity Tracking (FAT) app allows you to track fleet participation.
Fleet Activity Tracking requires access to the `esi-location.read_location.v1`, `esi-location.read_ship_type.v1`, and `esi-universe.read_structures.v1` SSO scopes. Update your application on the [EVE Developers site](https://developers.eveonline.com) to ensure these are available.
Add `'allianceauth.fleetactivitytracking',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
Add `'allianceauth.fleetactivitytracking',` to `INSTALLED_APPS` in your `local.py`
Perform Django Maintenance and restart our Web Service and Workers.
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate
python manage.py collectstatic --noinput
supervisorctl restart myauth:
```
:::
:::{group-tab} Containerized
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
auth collectstatic
```
:::
::::
## Permissions

View File

@@ -10,7 +10,31 @@ This app allows you to manage applications for multiple corporations in your all
## Installation
Add `'allianceauth.hrapplications',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
- Add `'allianceauth.hrapplications',` to `INSTALLED_APPS` in your `local.py`
Perform Django Maintenance and restart our Web Service and Workers.
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate
python manage.py collectstatic --noinput
supervisorctl restart myauth:
```
:::
:::{group-tab} Containerized
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
auth collectstatic
```
:::
::::
## Management

View File

@@ -6,7 +6,31 @@ Fleet Operations is an app for organizing and communicating fleet schedules.
## Installation
Add `'allianceauth.optimer',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
- Add `'allianceauth.optimer',` to `INSTALLED_APPS` in your `local.py`
Perform Django Maintenance and restart our Web Service and Workers.
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate
python manage.py collectstatic --noinput
supervisorctl restart myauth:
```
:::
:::{group-tab} Containerized
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
auth collectstatic
```
:::
::::
## Permissions

View File

@@ -2,9 +2,33 @@
Access to most of Alliance Auth's features is controlled by Django's permissions system. To help you secure your services, Alliance Auth provides a permission auditing tool.
This is an optional app that needs to be installed.
## Installation
To install it add `'allianceauth.permissions_tool',` to your `INSTALLED_APPS` list in your auth project's settings file.
- Add `'allianceauth.permissions_tool',` to `INSTALLED_APPS` in your `local.py`
Perform Django Maintenance and restart our Web Service and Workers.
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate
python manage.py collectstatic --noinput
supervisorctl restart myauth:
```
:::
:::{group-tab} Containerized
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
auth collectstatic
```
:::
::::
## Usage

View File

@@ -6,7 +6,31 @@ Ship Replacement helps you to organize ship replacement programs (SRP) for your
## Installation
Add `'allianceauth.srp',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
- Add `'allianceauth.srp',` to `INSTALLED_APPS` in your `local.py`
Perform Django Maintenance and restart our Web Service and Workers.
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate
python manage.py collectstatic --noinput
supervisorctl restart myauth:
```
:::
:::{group-tab} Containerized
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
auth collectstatic
```
:::
::::
## Permissions

View File

@@ -6,7 +6,31 @@ Structure Timers helps you keep track of both offensive and defensive structure
## Installation
Add `'allianceauth.timerboard',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
- Add `'allianceauth.timerboard',` to `INSTALLED_APPS` in your `local.py`
Perform Django Maintenance and restart our Web Service and Workers.
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate
python manage.py collectstatic --noinput
supervisorctl restart myauth:
```
:::
:::{group-tab} Containerized
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
auth collectstatic
```
:::
::::
## Permissions

View File

@@ -33,23 +33,6 @@ Our Daily Stats contain the following:
- A task to send a List of Installed Apps
- Each Task contains the UUID and Alliance Auth Version
Our Celery Events contain the following:
- Unique Identifier (The UUID)
- Celery Namespace of the task e.g., allianceauth.eveonline
- Celery Task
- Task Success or Exception
- A context number for bulk tasks or sometimes a binary True/False
Our Page Views contain the following:
- Unique Identifier (The UUID)
- Page Path
- Page Title
- The locale of the users browser
- The User-Agent of the user's browser
- The Alliance Auth Version
## Why
This data allows Alliance Auth development to gather accurate statistics on our installation base, as well as how those installations are used.

View File

@@ -4,9 +4,9 @@
It has the following key features:
- Automatically grants or revokes users access to external services (e.g. Discord, Mumble) and web apps (e.g. SRP requests) based on the user's current membership to [in-game organizations](/features/core/states) and [groups](/features/core/groups)
- Automatically grants or revokes user access to external services (e.g. Discord, Mumble) and web apps (e.g. SRP requests) based on the user's current membership to [in-game organizations](/features/core/states) and [groups](/features/core/groups)
- Provides a central website where users can directly access web apps (e.g., SRP requests) and manage their access to external services and groups.
- Provides a central web site where users can directly access web apps (e.g. SRP requests, Fleet Schedule) and manage their access to external services and groups.
- Includes a set of connectors (called ["services"](/features/services/index)) for integrating access management with many popular external services like Discord, Mumble, Teamspeak 3, SMF and others
@@ -14,4 +14,4 @@ It has the following key features:
- It can be easily extended with additional services and apps. Many are provided by the [community](/features/community/index).
- Chinese, English, German and Spanish localization
- English :flag_gb:, Chinese :flag_cn:, German :flag_de:, Spanish :flag_es:, Korean :flag_kr:, Russian :flag_ru:, Italian :flag_it:, French :flag_fr:, Japanese :flag_jp: and Ukrainian :flag_ua: Localization

View File

@@ -6,13 +6,13 @@ Discord is a web-based instant messaging client with voice. Kind of like TeamSpe
Discord is very popular amongst ad-hoc small groups and larger organizations seeking a modern technology. Alternative voice communications should be investigated for larger than small-medium groups for more advanced features.
## Setup
## Setup Auth
### Prepare Your Settings File
Make the following changes in your auth project's settings file (`local.py`):
- Add `'allianceauth.services.modules.discord',` to `INSTALLED_APPS`
- Add `'allianceauth.services.modules.discord',` to `INSTALLED_APPS` in your `local.py`
- Append the following to the bottom of the settings file:
```python
@@ -37,6 +37,34 @@ CELERYBEAT_SCHEDULE['discord.update_all_usernames'] = {
You will have to add most of the values for these settings, e.g., your Discord server ID (aka guild ID), later in the setup process.
:::
### Preparing Auth
Before continuing, it is essential to perform Django Maintenance and restart our Web Service and Workers.
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate
python manage.py collectstatic --noinput
supervisorctl restart myauth:
```
:::
:::{group-tab} Containerized
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
auth collectstatic
```
:::
::::
## Setup Discord
### Creating a Server
Navigate to the [Discord site](https://discord.com/) and register an account, or log in if you have one already.
@@ -50,6 +78,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.
@@ -66,10 +95,6 @@ Update your auth project's settings file with these pieces of information from t
- From the OAuth2 > General panel, `DISCORD_APP_SECRET` is the Client Secret
- From the Bot panel, `DISCORD_BOT_TOKEN` is the Token
### Preparing Auth
Before continuing, it is essential to run migrations and restart Gunicorn and Celery.
### Adding a Bot to the Server
Once created, navigate to the "Services" page of your Alliance Auth install as the superuser account. At the top there is a big green button labeled "Link Discord Server". Click it, then from the drop-down select the server you created, and then Authorize.
@@ -112,6 +137,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 +158,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 +183,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 +195,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

View File

@@ -1,11 +1,13 @@
# Discourse
## Prepare Your Settings
## Setup Auth
### Prepare Your Settings File
In your auth project's settings file, do the following:
- Add `'allianceauth.services.modules.discourse',` to your `INSTALLED_APPS` list
- Append the following to your local.py settings file:
- Add `'allianceauth.services.modules.discourse',` to `INSTALLED_APPS` in your `local.py`
- Append the following to your `local.py` settings file:
```python
# Discourse Configuration
@@ -15,6 +17,32 @@ DISCOURSE_API_KEY = ''
DISCOURSE_SSO_SECRET = ''
```
### Preparing Auth
Before continuing, it is essential to perform Django Maintenance and restart our Web Service and Workers.
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate
python manage.py collectstatic --noinput
supervisorctl restart myauth:
```
:::
:::{group-tab} Containerized
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
auth collectstatic
```
:::
::::
## Install Docker
```shell

View File

@@ -1,4 +1,4 @@
# Mumble
# Mumble (Docker)
An alternate install guide for Mumble using Docker, better suited to an Alliance Auth Docker install
@@ -8,7 +8,7 @@ Mumble is a free voice chat server. While not as flashy as TeamSpeak, it has all
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
- Add `'allianceauth.services.modules.mumble',` to `INSTALLED_APPS` in your `local.py`
- Append the following to your auth project's settings file:
```python

View File

@@ -14,25 +14,38 @@ This guide is currently for Ubuntu only.
### Installing Mumble Server
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
The mumble server package can be retrieved from a repository, which we need to add:
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204, 2404
```shell
sudo apt-add-repository ppa:mumble/release
```
```shell
sudo apt-get update
```
:::
:::{group-tab} CentOS 7, Stream 8, Stream 9
sudo yum install epel-release
sudo yum update
:::
::::
Now three packages need to be installed:
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204, 2404
```shell
sudo apt-get install python-software-properties mumble-server libqt5sql5-mysql
sudo apt-get install software-properties-common mumble-server libqt5sql5-mysql
```
:::
:::{group-tab} CentOS 7, Stream 8, Stream 9
sudo yum install mumble-server
:::
::::
@@ -58,17 +71,7 @@ pip install -r requirements.txt
## Configuring Mumble Server
The mumble server needs its own database. Open an SQL shell with `mysql -u root -p` and execute the SQL commands to create it:
```sql
CREATE DATABASE alliance_mumble CHARACTER SET utf8mb4;
```
```sql
GRANT ALL PRIVILEGES ON alliance_mumble . * TO 'allianceserver'@'localhost';
```
Mumble ships with a configuration file that needs customization. By default, its located at `/etc/mumble-server.ini`. Open it with your favorite text editor:
Mumble ships with a configuration file that needs customization. By default, it's located at `/etc/mumble-server.ini`. Open it with your favorite text editor:
```shell
sudo nano /etc/mumble-server.ini
@@ -79,15 +82,6 @@ We need to enable the ICE authenticator. Edit the following:
- `icesecretwrite=MY_CLEVER_PASSWORD`, obviously choosing a secure password
- ensure the line containing `Ice="tcp -h 127.0.0.1 -p 6502"` is uncommented
We also want to enable Mumble to use the previously created MySQL / MariaDB database, edit the following:
- uncomment the database line, and change it to `database=alliance_mumble`
- `dbDriver=QMYSQL`
- `dbUsername=allianceserver` or whatever you called the Alliance Auth MySQL user
- `dbPassword=` that users password
- `dbPort=3306`
- `dbPrefix=murmur_`
To name your root channel, uncomment and set `registerName=` to whatever cool name you want
Save and close the file.
@@ -98,7 +92,7 @@ To get Mumble superuser account credentials, run the following:
sudo dpkg-reconfigure mumble-server
```
Set the password to something youll remember and write it down. This is your superuser password and later needed to manage ACLs.
Set the password to something you'll remember and write it down. This is your superuser password and later needed to manage ACLs.
Now restart the server to see the changes reflected.
@@ -106,7 +100,7 @@ Now restart the server to see the changes reflected.
sudo service mumble-server restart
```
Thats it! Your server is ready to be connected to at example.com:64738
That's it! Your server is ready to be connected to at example.com:64738
## Configuring Mumble Authenticator

View File

@@ -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.
:::

View File

@@ -1,4 +1,4 @@
# Openfire
# Openfire (Docker)
An alternate install guide for Openfire using Docker, better suited to an Alliance Auth Docker install
@@ -8,7 +8,7 @@ Openfire is a Jabber (XMPP) server.
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
- Add `'allianceauth.services.modules.openfire',` to `INSTALLED_APPS` in your `local.py`
- Append the following to your auth project's settings file:
```python

View File

@@ -4,7 +4,7 @@ Openfire is a Jabber (XMPP) server.
## Prepare Your Settings
- Add `'allianceauth.services.modules.openfire',` to your `INSTALLED_APPS` list
- Add `'allianceauth.services.modules.openfire',` to `INSTALLED_APPS` in your `local.py`
- Append the following to your auth project's settings file:
```python
@@ -108,7 +108,7 @@ exit;
The remainder of the setup occurs through Openfires web interface. Navigate to <http://example.com:9090>, or if youre behind CloudFlare, go straight to your servers IP:9090.
Select your language. I sure hope its English if youre reading this guide.
Select your language.
Under Server Settings, set the Domain to `example.com` replacing it with your actual domain. Dont touch the rest.

View File

@@ -12,7 +12,7 @@ phpBB3 requires PHP installed in your web server. Apache has `mod_php`, NGINX re
In your auth project's settings file, do the following:
- Add `'allianceauth.services.modules.phpbb3',` to your `INSTALLED_APPS` list
- Add `'allianceauth.services.modules.phpbb3',` to `INSTALLED_APPS` in your `local.py`
- Append the following to the bottom of the settings file:
```python
@@ -25,6 +25,7 @@ DATABASES['phpbb3'] = {
'PASSWORD': 'password',
'HOST': '127.0.0.1',
'PORT': '3306',
'OPTIONS': {'charset': 'utf8mb4'},
}
```

View File

@@ -12,7 +12,7 @@ SMF requires PHP installed in your web server. Apache has `mod_php`, NGINX requi
In your auth project's settings file, do the following:
- Add `'allianceauth.services.modules.smf',` to your `INSTALLED_APPS` list
- Add `'allianceauth.services.modules.smf',` to `INSTALLED_APPS` in your `local.py`
- Append the following to the bottom of the settings file:
```python
@@ -25,6 +25,7 @@ DATABASES['smf'] = {
'PASSWORD': 'password',
'HOST': '127.0.0.1',
'PORT': '3306',
'OPTIONS': {'charset': 'utf8mb4'},
}
```

View File

@@ -1,4 +1,4 @@
# TeamSpeak 3
# TeamSpeak 3 (Docker)
## Overview
@@ -14,7 +14,7 @@ Sticking with TS3? Alright, I tried.
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
- Add `'allianceauth.services.modules.teamspeak',` to `INSTALLED_APPS` in your `local.py`
- Append the following to your auth project's settings file:
```python
@@ -32,7 +32,7 @@ CELERYBEAT_SCHEDULE['run_ts3_group_update'] = {
}
```
Add the following lines to your `.env` file
- Add the following lines to your `.env` file
```env
# Temspeak
@@ -152,7 +152,7 @@ If you have SSH access to the server hosting it, you need to locate the teamspea
### `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.
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`

View File

@@ -14,7 +14,7 @@ Sticking with TS3? Alright, I tried.
In your auth project's settings file, do the following:
- Add `'allianceauth.services.modules.teamspeak3',` to your `INSTALLED_APPS` list
- Add `'allianceauth.services.modules.teamspeak3',` to `INSTALLED_APPS` in your `local.py`
- Append the following to the bottom of the settings file:
```python
@@ -170,7 +170,7 @@ If you have SSH access to the server hosting it, you need to locate the teamspea
### `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.
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`

View File

@@ -4,12 +4,14 @@
[XenForo](https://xenforo.com/) is a popular, paid forum. This guide will assume that you already have XenForo installed with a valid license (please keep in mind that XenForo is not free nor open-source, therefore, you need to purchase a license first). If you come across any problems related with the installation of XenForo please contact their support service.
## Prepare Your Settings
## Setup Auth
### Prepare Your Settings
In your auth project's settings file, do the following:
- Add `'allianceauth.services.modules.xenforo',` to your `INSTALLED_APPS` list
- Append the following to your local.py settings file:
- Add `'allianceauth.services.modules.xenforo',` to `INSTALLED_APPS` in your `local.py`
- Append the following to your `local.py` settings file:
```python
# XenForo Configuration
@@ -18,6 +20,32 @@ XENFORO_DEFAULT_GROUP = 0
XENFORO_APIKEY = 'yourapikey'
```
### Preparing Auth
Before continuing, it is essential to perform Django Maintenance and restart our Web Service and Workers.
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate
python manage.py collectstatic --noinput
supervisorctl restart myauth:
```
:::
:::{group-tab} Containerized
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
auth collectstatic
```
:::
::::
## XenAPI
By default, XenForo does not support any kind of API, however, there is a third-party package called [XenAPI](https://github.com/Contex/XenAPI) which provides a simple REST interface by which we can access XenForo's functions to create and edit users.

View File

@@ -14,7 +14,7 @@ Alliance Auth can be installed on any in-support *nix operating system.
Our install documentation targets the following operating systems.
- Ubuntu 20.04
- Ubuntu 20.04 - Not Recommended for new installs
- Ubuntu 22.04
- Centos 7
- CentOS Stream 8
@@ -27,7 +27,7 @@ To install on your favorite flavour of Linux, identify and install equivalent pa
It is recommended to ensure your OS is fully up-to-date before proceeding. We may also add Package Repositories here, used later in the documentation.
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
```shell
sudo apt-get update
@@ -70,7 +70,7 @@ Install Python 3.11 and related tools on your system.
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
```shell
sudo add-apt-repository ppa:deadsnakes/ppa
@@ -128,7 +128,7 @@ sudo make altinstall
It's recommended to use a database service instead of SQLite. Many options are available, but this guide will use MariaDB 10.11
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
Follow the instructions at <https://mariadb.org/download/?t=repo-config&d=20.04+%22focal%22&v=10.11&r_m=osuosl> to add the MariaDB repository to your host.
```shell
@@ -164,7 +164,7 @@ sudo dnf install mariadb mariadb-server mariadb-devel
:::::{important}
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
If you don't plan on running the database on the same server as auth you still need to install the `libmysqlclient-dev` package
:::
:::{group-tab} CentOS 7
@@ -181,13 +181,17 @@ If you don't plan on running the database on the same server as auth you still n
### Redis and Other Tools
A few extra utilities are also required for installation of packages.
A few extra utilities are also required for the installation of packages.
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
```shell
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt-get update
sudo apt-get install unzip git redis-server curl libssl-dev libbz2-dev libffi-dev build-essential pkg-config
```
@@ -275,13 +279,13 @@ mysql_secure_installation
### User Account
For security and permissions, its highly recommended you create a separate user to install auth under. Do not log in as this account.
For security and permissions, it's highly recommended you create a separate user to install auth under. Do not log in as this account.
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
```shell
sudo adduser --disabled-login allianceserver
sudo adduser --disabled-login allianceserver --shell /bin/bash
```
:::
@@ -493,7 +497,7 @@ exit
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
```shell
sudo apt-get install supervisor
@@ -550,7 +554,7 @@ sudo systemctl start supervisord.service
Once installed, it needs a configuration file to know which processes to watch. Your Alliance Auth project comes with a ready-to-use template which will ensure the Celery workers, Celery task scheduler and Gunicorn are all running.
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
```shell
ln -s /home/allianceserver/myauth/supervisor.conf /etc/supervisor/conf.d/myauth.conf

View File

@@ -10,22 +10,29 @@ If you're using a small VPS to host services with very limited memory, consider
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
```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
@@ -44,7 +50,7 @@ CentOS 7, Stream 8, Stream 9
Apache needs to be able to read the folder containing your auth project's static files.
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
```shell
chown -R www-data:www-data /var/www/myauth/static
@@ -81,7 +87,7 @@ Apache serves sites through defined virtual hosts. These are located in `/etc/ap
A virtual host for auth needs only proxy requests to your WSGI server (Gunicorn if you followed the installation guide) and serve static files. Examples can be found below. Create your config in its own file e.g. `myauth.conf`
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
To proxy and modify headers a few mods need to be enabled.
```shell

View File

@@ -42,7 +42,7 @@ You will need to have [Gunicorn](gunicorn.md) or some other WSGI server setup fo
## Install
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
```shell
sudo apt-get install nginx

View File

@@ -25,7 +25,7 @@ sudo dnf install python39 python39-devel
:::
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
:::{group-tab} Ubuntu 2004, 2204, 2404
```shell
sudo add-apt-repository ppa:deadsnakes/ppa

View File

@@ -4,10 +4,25 @@
Your auth project is just a regular Django project - you can add in [other Django apps](https://djangopackages.org/) as desired. Most come with dedicated setup guides, but here is the general procedure:
1. add `'appname',` to your `INSTALLED_APPS` setting in `local.py`
2. run `python manage.py migrate`
3. run `python manage.py collectstatic --noinput`
4. restart AA with `supervisorctl restart myauth:`
::::{tabs}
:::{group-tab} Bare Metal
1. Add `'appname',` to `INSTALLED_APPS` setting in `local.py`
1. Run Migrations `python manage.py migrate`
1. Collect Static Files `python manage.py collectstatic --noinput`
1. Restart our Web Service and Workers `supervisorctl restart myauth:`
:::
:::{group-tab} Containerized
1. Add `'appname',` to `INSTALLED_APPS` setting in `local.py`
1. Restart our Web Service and Workers `docker compose --env-file=.env up -d`
1. Enter a Docker Container `docker compose exec allianceauth_gunicorn bash`
1. Run Migrations `auth migrate`
1. Collect Static Files `auth collectstatic`
:::
::::
## Removing Apps
@@ -25,20 +40,38 @@ First, we want to remove the app related tables from the database.
Let's first try the automatic approach by running the following command:
::::{tabs}
:::{group-tab} Bare Metal
```shell
python manage.py migrate appname zero
```
:::
:::{group-tab} Containerized
```shell
docker compose exec allianceauth_gunicorn bash
auth migrate appname zero
```
:::
::::
If that works, you'll get a confirmation message.
If that did not work, and you got error messages, you will need to remove the tables manually. This is pretty common btw, because many apps use sophisticated table setups, which cannot be removed automatically by Django.
If that did not work, and you got error messages, you will need to remove the tables manually.
> This is pretty common, because many apps use sophisticated table setups, which cannot be removed automatically by Django.
#### Manual table removal
::::{tabs}
:::{group-tab} Bare Metal
First, tell Django that these migrations are no longer in effect (note the additional `--fake`):
```shell
python manage.py migrate appname zero --fake
python manage.py appname zero --fake
```
Then, open the mysql tool and connect to your Alliance Auth database:
@@ -75,6 +108,53 @@ SET FOREIGN_KEY_CHECKS=1;
exit;
```
:::
:::{group-tab} Containerized
First, tell Django that these migrations are no longer in effect (note the additional `--fake`):
```shell
auth migrate appname zero --fake
```
Here we need to swap containers, if you are still inside allianceauth_gunicorn, exit with `exit`
```shell
docker compose exec auth_mysql bash
sudo mysql -u root
use alliance_auth;
```
Next, disable foreign key check. This makes it much easier to drop tables in any order.
```shell
SET FOREIGN_KEY_CHECKS=0;
```
Then get a list of all tables. All tables belonging to the app in question will start with `appname_`.
```shell
show tables;
```
Now, drop the tables from the app one by one like so:
```shell
drop table appname_model_1;
drop table appname_model_2;
...
```
And finally, but very importantly, re-enable foreign key checks again and then exit:
```shell
SET FOREIGN_KEY_CHECKS=1;
exit;
```
:::
::::
### Step 2 - Remove the app from Alliance Auth
Once the tables have been removed, you can remove the app from Alliance Auth. This is done by removing the applabel from the `INSTALLED_APPS` list in your local settings file.

View File

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

View File

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

View 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.

View File

@@ -18,6 +18,7 @@ authors = [
requires-python = ">=3.8"
classifiers = [
"Environment :: Web Environment",
"Framework :: Celery",
"Framework :: Django",
"Framework :: Django :: 4.2",
"Intended Audience :: Developers",
@@ -49,6 +50,7 @@ dependencies = [
"django-esi>=5",
"django-redis>=5.2",
"django-registration<3.4,>=3.3",
"django-solo",
"django-sortedm2m",
"dnspython",
"mysqlclient>=2.1",

View File

@@ -1,4 +1,5 @@
import os
from celery import Celery
# set the default Django settings module for the 'celery' program.
@@ -12,6 +13,10 @@ app = Celery('devauth')
# the configuration object to child processes.
app.config_from_object('django.conf:settings')
# Automatically try to establish the connection to the AMQP broker on
# Celery startup if it is unavailable.
app.conf.broker_connection_retry_on_startup = True
# setup priorities ( 0 Highest, 9 Lowest )
app.conf.broker_transport_options = {
'priority_steps': list(range(10)), # setup que to have 10 steps

View File

@@ -1,5 +1,5 @@
[tox]
isolated_build = True
isolated_build = true
skipsdist = true
usedevelop = true
envlist = py{38,39,310,311,312}-{all,core}, docs