Compare commits

..

32 Commits

Author SHA1 Message Date
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
31 changed files with 466 additions and 28 deletions

View File

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

View File

@@ -42,13 +42,13 @@ def system_package_redis(app_configs, **kwargs) -> List[CheckMessage]:
return errors return errors
if redis_version.major == 7 and redis_version.minor == 2 and timezone.now() > timezone.datetime(year=2025, month=8, day=31, tzinfo=timezone.utc): if redis_version.major == 7 and redis_version.minor == 2 and timezone.now() > timezone.datetime(year=2025, month=8, day=31, tzinfo=timezone.utc):
errors.append(Error(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint="https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", id="allianceauth.checks.A001")) 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: elif redis_version.major == 7 and redis_version.minor == 0:
errors.append(Warning(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint="https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", id="allianceauth.checks.A002")) 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: elif redis_version.major == 6 and redis_version.minor == 2:
errors.append(Warning(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint="https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", id="allianceauth.checks.A018")) 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]: elif redis_version.major in [6, 5]:
errors.append(Error(f"Redis {redis_version.public} EOL", hint="https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", id="allianceauth.checks.A003")) 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 return errors
@@ -140,11 +140,19 @@ def sql_settings(app_configs, **kwargs) -> List[CheckMessage]:
errors: List[CheckMessage] = [] errors: List[CheckMessage] = []
for connection in db.connections.all(): for connection in db.connections.all():
if connection.vendor == "mysql": if connection.vendor == "mysql":
if connection.settings_dict["OPTIONS"]["charset"] != "utf8mb4": try:
errors.append(Error("SQL Charset is not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001")) 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 # This hasn't actually been set on AA yet
# if connection.settings_dict["OPTIONS"]["charset"] != "utf8mb4_unicode_ci": # try:
# errors.append(Error("SQL Collation is not set correctly", hint="", id="allianceauth.checks.B002")) # 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": # if connection.vendor == "sqlite":
return errors return errors
@@ -153,11 +161,19 @@ def sql_settings(app_configs, **kwargs) -> List[CheckMessage]:
@register() @register()
def celery_settings(app_configs, **kwargs) -> List[CheckMessage]: def celery_settings(app_configs, **kwargs) -> List[CheckMessage]:
errors: List[CheckMessage] = [] errors: List[CheckMessage] = []
if current_app.conf.broker_transport_options != {'priority_steps': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 'queue_order_strategy': 'priority'}:
errors.append(Error("Celery Priorities are not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc", id="allianceauth.checks.B003"))
if current_app.conf.broker_connection_retry_on_startup != True: try:
errors.append(Error("Celery broker_connection_retry_on_startup not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280", id="allianceauth.checks.B004")) if current_app.conf.broker_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 return errors

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

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

View File

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

View File

@@ -13,9 +13,9 @@
{% for notif in notifications %} {% for notif in notifications %}
<li class="list-group-item"> <li class="list-group-item">
{% if notif.state == 'opened' %} {% if notif.state == 'opened' %}
<span class="badge bg-success">{% translate "Open" %}</span> <span class="badge bg-success me-2">{% translate "Open" %}</span>
{% else %} {% else %}
<span class="badge bg-danger">{% translate "Closed" %}</span> <span class="badge bg-danger me-2">{% translate "Closed" %}</span>
{% endif %} {% endif %}
<a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a> <a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a>
</li> </li>

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,10 +1,10 @@
from typing import List, Optional from typing import List, Optional, Union
class ThemeHook: class ThemeHook:
""" """
Theme hook for injecting a Bootstrap 5 Theme and associated JS into alliance auth. Theme hook for injecting a Bootstrap 5 Theme and associated JS into alliance auth.
these can be local or CDN delivered These can be local or CDN delivered.
""" """
def __init__(self, def __init__(self,
@@ -14,7 +14,7 @@ class ThemeHook:
js: List[dict], js: List[dict],
css_template: Optional[str] = None, css_template: Optional[str] = None,
js_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"): header_padding: Optional[str] = "4em"):
""" """
:param name: Theme python name :param name: Theme python name
@@ -29,6 +29,10 @@ class ThemeHook:
:type css_template: Optional[str], optional :type css_template: Optional[str], optional
:param js_template: _description_, defaults to None :param js_template: _description_, defaults to None
:type js_template: Optional[str], optional :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.name = name
self.description = description self.description = description
@@ -41,7 +45,11 @@ class ThemeHook:
self.css_template = css_template self.css_template = css_template
self.js_template = js_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 self.header_padding = header_padding
def get_name(self): def get_name(self):
return f"{self.__class__.__module__}.{self.__class__.__name__}" return f"{self.__class__.__module__}.{self.__class__.__name__}"

View File

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

View File

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

View File

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

View File

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

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 An alternate install guide for Mumble using Docker, better suited to an Alliance Auth Docker install

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 An alternate install guide for Openfire using Docker, better suited to an Alliance Auth Docker install

View File

@@ -1,4 +1,4 @@
# TeamSpeak 3 # TeamSpeak 3 (Docker)
## Overview ## Overview

View File

@@ -181,13 +181,17 @@ If you don't plan on running the database on the same server as auth you still n
### Redis and Other Tools ### Redis and Other Tools
A few extra utilities are also required for installation of packages. A few extra utilities are also required for the installation of packages.
::::{tabs} ::::{tabs}
:::{group-tab} Ubuntu 2004, 2204 :::{group-tab} Ubuntu 2004, 2204
```shell ```shell
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt-get update
sudo apt-get install unzip git redis-server curl libssl-dev libbz2-dev libffi-dev build-essential pkg-config sudo apt-get install unzip git redis-server curl libssl-dev libbz2-dev libffi-dev build-essential pkg-config
``` ```

View File

@@ -50,6 +50,7 @@ dependencies = [
"django-esi>=5", "django-esi>=5",
"django-redis>=5.2", "django-redis>=5.2",
"django-registration<3.4,>=3.3", "django-registration<3.4,>=3.3",
"django-solo",
"django-sortedm2m", "django-sortedm2m",
"dnspython", "dnspython",
"mysqlclient>=2.1", "mysqlclient>=2.1",