Compare commits

...

129 Commits

Author SHA1 Message Date
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
Ariel Rin
0ff4374efa Version Bump 4.0.2 2024-05-12 19:51:02 +10:00
Ariel Rin
18d0e58a48 Merge branch 'master' of gitlab.com:allianceauth/allianceauth 2024-05-12 19:50:10 +10:00
Ariel Rin
84f44338dc Merge branch 'mute-subtitle' into 'master'
[CHANGE] Mute subtitle text

See merge request allianceauth/allianceauth!1623
2024-05-12 09:48:47 +00:00
Ariel Rin
2ba0412890 Add Polish to language selections 2024-05-12 19:44:30 +10:00
Peter Pfeufer
2326522b29 [CHANGE] Docs updated with the missing subtitle attribute 2024-05-12 11:40:47 +02:00
Peter Pfeufer
a7cb6ee434 [CHANGE] Mute subtitle text 2024-05-12 11:35:42 +02:00
Ariel Rin
2aeef63565 Merge branch 'translations_7f31a07ccd4e4a66b1dd7b6bc2dbddb5' into 'master'
Updates for project Alliance Auth

See merge request allianceauth/allianceauth!1609
2024-05-12 09:23:26 +00:00
Ariel Rin
3c9e7335ef Updates for project Alliance Auth 2024-05-12 09:23:26 +00:00
Ariel Rin
49067de325 apply precommit here 2024-05-12 19:21:58 +10:00
Ariel Rin
471e7e29ae Update Source EN 2024-05-12 19:15:56 +10:00
Ariel Rin
3ec5775406 remove unneeded legacy transifex config 2024-05-12 19:15:29 +10:00
Ariel Rin
e804d2b60d update (and sort) precommit 2024-05-12 19:15:14 +10:00
Ariel Rin
742438a95d Merge branch 'timerboard-bg-fix' into 'master'
Make table bg a little less oppressive in timerboard

See merge request allianceauth/allianceauth!1617
2024-04-27 05:09:37 +00:00
Ariel Rin
5c60086baa Merge branch 'add-missing-padding' into 'master'
[ADD] missing padding

See merge request allianceauth/allianceauth!1620
2024-04-27 05:05:22 +00:00
Ariel Rin
e49041bb14 Merge branch 'Haffi-master-patch-21354' into 'master'
updates package registry reference

Closes #1403

See merge request allianceauth/allianceauth!1621
2024-04-25 09:48:10 +00:00
Haffi
f3cbe91883 updates package registry reference 2024-04-25 08:42:18 +00:00
Peter Pfeufer
ea439a2176 [FIX] Indentation 2024-04-15 17:16:01 +02:00
Peter Pfeufer
56e1e76f11 [ADD] Missing theme padding on public pages 2024-04-15 17:15:35 +02: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
Aaron Kable
5605eb129d Make table bg a little less opressive in timerboard 2024-04-10 16:27:09 +08:00
Ariel Rin
87ef0f21a3 Merge branch 'add-missing-colon' into 'master'
[ADD] Missing colon

See merge request allianceauth/allianceauth!1616
2024-04-10 01:12:30 +00:00
Ariel Rin
a1c7ce827e Merge branch 'topnav-revival' into 'master'
V4 Theme - Re-add the Top Nav for unauthenticated users

See merge request allianceauth/allianceauth!1615
2024-04-10 01:09:03 +00:00
Aaron Kable
97466bcdfb V4 Theme - Re-add the Top Nav for unauthenticated users 2024-04-10 01:09:02 +00:00
Peter Pfeufer
ff3096b106 [ADD] Missing colon 2024-04-07 15:58:35 +02:00
Ariel Rin
98f0d77f3f Merge branch 'pre-commit-updates' into 'master'
[MISC] pre-commit config updates

See merge request allianceauth/allianceauth!1614
2024-03-29 02:24:49 +00:00
Peter Pfeufer
92548ba402 [ADD] pyproject.toml validation 2024-03-28 20:40:45 +01:00
Peter Pfeufer
c46741d311 [MISC] Update repo versions 2024-03-28 20:34:31 +01:00
Peter Pfeufer
7c7c1abf7c [CHANGE] Project file linter
We don't use setup.cfg anymore, so we should lint the pyproject.toml file now.
2024-03-28 20:33:16 +01:00
Ariel Rin
fc303b1b0a Merge branch 'fix-phpbb3-mysql-user' into 'master'
[FIX] DB user for phpBB

See merge request allianceauth/allianceauth!1613
2024-03-26 10:19:07 +00:00
Peter Pfeufer
4e220a9679 [FIX] DB user for phpBB 2024-03-24 17:08:34 +01:00
Ariel Rin
b17b1f7504 Version Bump 4.0.1 2024-03-21 19:34:02 +10:00
Ariel Rin
7081fc0e76 Merge branch 'docs' into 'master'
Documentation

See merge request allianceauth/allianceauth!1610
2024-03-21 09:17:43 +00:00
Ariel Rin
68e4574f19 Merge branch 'analytics' into 'master'
Pass Version to analytics user properties

See merge request allianceauth/allianceauth!1612
2024-03-21 09:12:53 +00:00
Ariel Rin
e6e0a70012 Pass Version to analytics user properties 2024-03-21 09:12:53 +00:00
Ariel Rin
13e38da942 Merge branch 'timers-row-background' into 'master'
[CHANGE] Restore the "old" color coding in table rows

See merge request allianceauth/allianceauth!1611
2024-03-21 09:12:25 +00:00
Peter Pfeufer
468c1de26b [CHANGE] restore the "old" color coding in table rows 2024-03-20 19:22:03 +01:00
Ariel Rin
22ef5ac0e5 raw file contents incase someone wgets 2024-03-16 15:44:39 +10:00
Ariel Rin
ef2dc08958 Version Bump 4.0.0 2024-03-16 14:17:29 +10:00
Ariel Rin
6b84ffa16c update pre-commit 2024-03-16 14:16:50 +10:00
Ariel Rin
d7a1096413 Merge branch 'translations_7f31a07ccd4e4a66b1dd7b6bc2dbddb5' into 'master'
Updates for project Alliance Auth

See merge request allianceauth/allianceauth!1595
2024-03-16 04:08:52 +00:00
Ariel Rin
93b94a8bc2 Updates for project Alliance Auth 2024-03-16 04:08:52 +00:00
Ariel Rin
9a95716105 Merge branch 'nav-active-passthrough' into 'master'
[Enhancement] Keep menu folders open when a sub item is active

See merge request allianceauth/allianceauth!1608
2024-03-16 04:00:06 +00:00
Aaron Kable
dbfcf5d87a [Enhancement] Keep menu folders open when a sub item is active 2024-03-16 04:00:06 +00:00
Ariel Rin
105d7d53b3 Merge branch 'no-perm-folders' into 'master'
[FIX] Hide empty folders in menu

See merge request allianceauth/allianceauth!1607
2024-03-16 03:59:54 +00:00
Aaron Kable
01cefe1457 [FIX] Hide empty folders in menu 2024-03-16 03:59:54 +00:00
Ariel Rin
7fe3db8017 drop pypy testing 2024-03-13 21:44:48 +10:00
Ariel Rin
e0945fac80 Version Bump 4.0.0rc1 2024-03-13 19:12:11 +10:00
Ariel Rin
40fa190820 Merge branch 'v4docs' into 'v4.x'
Expand Docker Docs for v4

See merge request allianceauth/allianceauth!1577
2024-03-13 09:06:10 +00:00
Ariel Rin
670580f8f3 Merge branch 'sw-version-button-same-height' into 'v4.x'
[FIX] Make SW Version buttons the same height

See merge request allianceauth/allianceauth!1606
2024-03-12 13:23:32 +00:00
Peter Pfeufer
323a0bcf16 [FIX] Make SW Version buttons the same height 2024-03-12 12:42:34 +01:00
Ariel Rin
6e995edd80 Merge branch 'sha-fixes' into 'v4.x'
[FIX] Bootstrap SHA hashes

See merge request allianceauth/allianceauth!1605
2024-03-12 11:30:16 +00:00
Peter Pfeufer
8d86e45b7a [FIX] Bootstrap SHA hashes 2024-03-12 12:29:21 +01:00
Ariel Rin
2aa6df4461 Merge branch 'bootswatch' into 'v4.x'
Bump and unify on bootstrap 5.3.3

See merge request allianceauth/allianceauth!1603
2024-03-12 03:36:19 +00:00
Ariel Rin
cf6f989502 Bump and unify on bootstrap 5.3.3 2024-03-12 03:36:19 +00:00
Ariel Rin
3e1d8ae334 Merge branch 'widgets' into 'v4.x'
When providing a single time, clarify EVE Time

See merge request allianceauth/allianceauth!1604
2024-03-12 03:34:33 +00:00
Ariel Rin
bcfe9484b5 When providing a single time, clarify EVE Time 2024-03-12 03:34:33 +00:00
Ariel Rin
5e4d1b9cfd Merge branch 'timerboard-perms' into 'v4.x'
Add Dashboard Widget View Perms

See merge request allianceauth/allianceauth!1602
2024-03-10 09:36:51 +00:00
Aaron Kable
3b463e7305 Fix timer query, Corp is not nullable 2024-03-08 17:37:11 +08:00
Aaron Kable
eedf5082fa remove the locked hieght from the ops/tiemrs dashboard widgets 2024-03-08 17:15:03 +08:00
Aaron Kable
2ea5b15175 Add perms to ops dashboard view 2024-03-08 17:14:36 +08:00
Aaron Kable
7a9808aad3 Add permision check to timerboard dashboard view 2024-03-08 15:54:39 +08:00
Ariel Rin
a1d712694c Merge branch 'theme-fixes' into 'v4.x'
[V4] Add reject button back to group management.

See merge request allianceauth/allianceauth!1601
2024-03-07 10:35:39 +00:00
Ariel Rin
ca11c726a3 Merge branch 'login-screen-theming' into 'v4.x'
[ADD] Theme CSS to login base template

See merge request allianceauth/allianceauth!1600
2024-03-07 10:34:53 +00:00
Ariel Rin
6e0f7a35bd Merge branch 'login-box-fix' into 'v4.x'
[CHANGE] Give the login box a bit more space

See merge request allianceauth/allianceauth!1599
2024-03-07 10:34:16 +00:00
Aaron Kable
7375b001ca Add reject button back in 2024-03-04 17:18:19 +08:00
Peter Pfeufer
0287086633 [ADD] Theme CSS to login base template 2024-02-25 20:53:52 +01:00
Peter Pfeufer
9eb2becbb5 [CHANGE] Give the login box a bit more space 2024-02-25 20:37:32 +01:00
Ariel Rin
12f1444fe7 add update command 2024-02-24 20:41:10 +10:00
Ariel Rin
d6372bd093 add notes to building custom image 2024-02-24 16:05:50 +10:00
Ariel Rin
f4d8ead54e remove justified text 2024-02-23 23:25:20 +10:00
Ariel Rin
7427e13505 move into docker and add to toctree 2024-02-23 23:21:09 +10:00
Ariel Rin
445683c3d5 Merge branch 'v4.x' of gitlab.com:allianceauth/allianceauth into v4docs 2024-02-23 22:26:38 +10:00
Ariel Rin
677c46c48a very basic migration guide to our v4 docker stack 2024-02-23 22:23:12 +10:00
Ariel Rin
87b9e3f87a use latest python minor 2024-02-23 20:37:41 +10:00
Ariel Rin
da2a5aff2f missing ` 2024-02-23 20:37:18 +10:00
Ariel Rin
65d77743dc fix toctree after myst conversion 2024-02-23 20:37:06 +10:00
Ariel Rin
9f4bf13cc9 Expand documentation on building a custom image, provide example 2024-01-05 15:42:39 +10:00
Ariel Rin
51b86f88b9 generate some basic docker install guides for services 2023-12-26 20:41:53 +10:00
Ariel Rin
8184461b48 use docker compose instead of dash, add hint 2023-12-26 19:35:11 +10:00
Ariel Rin
ca0cdd6e15 remove old docs images 2023-12-26 19:34:25 +10:00
Ariel Rin
036a17ad3b note the container name changes after refactor 2023-12-26 19:34:09 +10:00
Ariel Rin
2418023ddd remove venv 2023-12-26 19:28:34 +10:00
102 changed files with 20876 additions and 7278 deletions

View File

@@ -25,7 +25,7 @@ before_script:
pre-commit-check: pre-commit-check:
<<: *only-default <<: *only-default
stage: pre-commit stage: pre-commit
image: python:3.11-bullseye image: python:3.11-bookworm
# variables: # variables:
# PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit # PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
# cache: # cache:
@@ -53,7 +53,7 @@ secret_detection:
test-3.8-core: test-3.8-core:
<<: *only-default <<: *only-default
image: python:3.8-bullseye image: python:3.8-bookworm
script: script:
- tox -e py38-core - tox -e py38-core
artifacts: artifacts:
@@ -65,7 +65,7 @@ test-3.8-core:
test-3.9-core: test-3.9-core:
<<: *only-default <<: *only-default
image: python:3.9-bullseye image: python:3.9-bookworm
script: script:
- tox -e py39-core - tox -e py39-core
artifacts: artifacts:
@@ -77,7 +77,7 @@ test-3.9-core:
test-3.10-core: test-3.10-core:
<<: *only-default <<: *only-default
image: python:3.10-bullseye image: python:3.10-bookworm
script: script:
- tox -e py310-core - tox -e py310-core
artifacts: artifacts:
@@ -89,7 +89,7 @@ test-3.10-core:
test-3.11-core: test-3.11-core:
<<: *only-default <<: *only-default
image: python:3.11-bullseye image: python:3.11-bookworm
script: script:
- tox -e py311-core - tox -e py311-core
artifacts: artifacts:
@@ -101,7 +101,7 @@ test-3.11-core:
test-3.12-core: test-3.12-core:
<<: *only-default <<: *only-default
image: python:3.12-rc-bullseye image: python:3.12-bookworm
script: script:
- tox -e py312-core - tox -e py312-core
artifacts: artifacts:
@@ -113,7 +113,7 @@ test-3.12-core:
test-3.8-all: test-3.8-all:
<<: *only-default <<: *only-default
image: python:3.8-bullseye image: python:3.8-bookworm
script: script:
- tox -e py38-all - tox -e py38-all
artifacts: artifacts:
@@ -125,7 +125,7 @@ test-3.8-all:
test-3.9-all: test-3.9-all:
<<: *only-default <<: *only-default
image: python:3.9-bullseye image: python:3.9-bookworm
script: script:
- tox -e py39-all - tox -e py39-all
artifacts: artifacts:
@@ -137,7 +137,7 @@ test-3.9-all:
test-3.10-all: test-3.10-all:
<<: *only-default <<: *only-default
image: python:3.10-bullseye image: python:3.10-bookworm
script: script:
- tox -e py310-all - tox -e py310-all
artifacts: artifacts:
@@ -149,7 +149,7 @@ test-3.10-all:
test-3.11-all: test-3.11-all:
<<: *only-default <<: *only-default
image: python:3.11-bullseye image: python:3.11-bookworm
script: script:
- tox -e py311-all - tox -e py311-all
artifacts: artifacts:
@@ -162,7 +162,7 @@ test-3.11-all:
test-3.12-all: test-3.12-all:
<<: *only-default <<: *only-default
image: python:3.12-rc-bullseye image: python:3.12-bookworm
script: script:
- tox -e py312-all - tox -e py312-all
artifacts: artifacts:
@@ -174,7 +174,7 @@ test-3.12-all:
build-test: build-test:
stage: test stage: test
image: python:3.11-bullseye image: python:3.11-bookworm
before_script: before_script:
- python -m pip install --upgrade pip - python -m pip install --upgrade pip
@@ -193,13 +193,13 @@ build-test:
test-docs: test-docs:
<<: *only-default <<: *only-default
image: python:3.11-bullseye image: python:3.11-bookworm
script: script:
- tox -e docs - tox -e docs
deploy_production: deploy_production:
stage: deploy stage: deploy
image: python:3.11-bullseye image: python:3.11-bookworm
before_script: before_script:
- python -m pip install --upgrade pip - python -m pip install --upgrade pip

View File

@@ -4,8 +4,21 @@
# pre-commit autoupdate # pre-commit autoupdate
repos: repos:
# Code Upgrades
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.2
hooks:
- id: pyupgrade
args: [--py38-plus]
- repo: https://github.com/adamchainz/django-upgrade
rev: 1.17.0
hooks:
- id: django-upgrade
args: [--target-version=4.2]
# Formatting
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0 rev: v4.6.0
hooks: hooks:
# Identify invalid files # Identify invalid files
- id: check-ast - id: check-ast
@@ -13,27 +26,24 @@ repos:
- id: check-json - id: check-json
- id: check-toml - id: check-toml
- id: check-xml - id: check-xml
# git checks # git checks
- id: check-merge-conflict - id: check-merge-conflict
- id: check-added-large-files - id: check-added-large-files
args: [ --maxkb=1000 ] args: [--maxkb=1000]
- id: detect-private-key - id: detect-private-key
- id: check-case-conflict - id: check-case-conflict
# Python checks # Python checks
# - id: check-docstring-first # - id: check-docstring-first
- id: debug-statements - id: debug-statements
# - id: requirements-txt-fixer # - id: requirements-txt-fixer
- id: fix-encoding-pragma - id: fix-encoding-pragma
args: [ --remove ] args: [--remove]
- id: fix-byte-order-marker - id: fix-byte-order-marker
# General quality checks # General quality checks
- id: mixed-line-ending - id: mixed-line-ending
args: [ --fix=lf ] args: [--fix=lf]
- id: trailing-whitespace - id: trailing-whitespace
args: [ --markdown-linebreak-ext=md ] args: [--markdown-linebreak-ext=md]
exclude: | exclude: |
(?x)( (?x)(
\.min\.css| \.min\.css|
@@ -52,9 +62,8 @@ repos:
\.mo| \.mo|
swagger\.json swagger\.json
) )
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python - repo: https://github.com/editorconfig-checker/editorconfig-checker.python
rev: 2.7.2 rev: 2.7.3
hooks: hooks:
- id: editorconfig-checker - id: editorconfig-checker
exclude: | exclude: |
@@ -65,21 +74,26 @@ repos:
\.mo| \.mo|
swagger\.json swagger\.json
) )
- repo: https://github.com/igorshubovych/markdownlint-cli
- repo: https://github.com/asottile/pyupgrade rev: v0.41.0
rev: v3.10.1
hooks: hooks:
- id: pyupgrade - id: markdownlint
args: [ --py38-plus ] args:
- --disable=MD013
- repo: https://github.com/adamchainz/django-upgrade # Infrastructure
rev: 1.14.0 - repo: https://github.com/tox-dev/pyproject-fmt
rev: 2.1.3
hooks: hooks:
- id: django-upgrade - id: pyproject-fmt
args: [--target-version=4.2] name: pyproject.toml formatter
description: "Format the pyproject.toml file."
- repo: https://github.com/asottile/setup-cfg-fmt args:
rev: v2.3.0 - --indent=4
additional_dependencies:
- tox==4.15.0 # https://github.com/tox-dev/tox/releases/latest
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.18
hooks: hooks:
- id: setup-cfg-fmt - id: validate-pyproject
args: [ --include-version-classifiers ] name: Validate pyproject.toml
description: "Validate the pyproject.toml file."

View File

@@ -1,10 +0,0 @@
[main]
host = https://app.transifex.com
lang_map = zh-Hans: zh_Hans
[o:alliance-auth:p:alliance-auth:r:django-po]
file_filter = allianceauth/locale/<lang>/LC_MESSAGES/django.po
source_file = allianceauth/locale/en/LC_MESSAGES/django.po
source_lang = en
type = PO
minimum_perc = 0

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.0.0b2' __version__ = '4.2.0'
__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

@@ -9,6 +9,8 @@ from .utils import (
install_stat_tokens, install_stat_tokens,
install_stat_users) install_stat_users)
from allianceauth import __version__
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
BASE_URL = "https://www.google-analytics.com" BASE_URL = "https://www.google-analytics.com"
@@ -99,11 +101,38 @@ def analytics_daily_stats():
event_type='Stats') event_type='Stats')
for appconfig in apps.get_app_configs(): for appconfig in apps.get_app_configs():
analytics_event(namespace='allianceauth.analytics', if appconfig.label in [
task='send_extension_stats', "django_celery_beat",
label=appconfig.label, "bootstrapform",
value=1, "messages",
event_type='Stats') "sessions",
"auth",
"staticfiles",
"users",
"addons",
"admin",
"humanize",
"contenttypes",
"sortedm2m",
"django_bootstrap5",
"tokens",
"authentication",
"services",
"framework",
"notifications"
"eveonline",
"navhelper",
"analytics",
"menu",
"theme"
]:
pass
else:
analytics_event(namespace='allianceauth.analytics',
task='send_extension_stats',
label=appconfig.label,
value=1,
event_type='Stats')
@shared_task() @shared_task()
@@ -139,7 +168,7 @@ def send_ga_tracking_celery_event(
'client_id': AnalyticsIdentifier.objects.get(id=1).identifier.hex, 'client_id': AnalyticsIdentifier.objects.get(id=1).identifier.hex,
"user_properties": { "user_properties": {
"allianceauth_version": { "allianceauth_version": {
"value": "allianceauth_version" "value": __version__
} }
}, },
'non_personalized_ads': True, 'non_personalized_ads': True,

View File

@@ -5,26 +5,5 @@ from django.core.checks import Warning, Error, register
class AllianceAuthConfig(AppConfig): class AllianceAuthConfig(AppConfig):
name = 'allianceauth' name = 'allianceauth'
def ready(self) -> None:
@register() import allianceauth.checks # noqa
def check_settings(app_configs, **kwargs):
from django.conf import settings
errors = []
if hasattr(settings, "SITE_URL"):
if settings.SITE_URL[-1] == "/":
errors.append(Warning(
"'SITE_URL' Has a trailing slash. This may lead to incorrect links being generated by Auth."))
else:
errors.append(Error(
"No 'SITE_URL' found is settings. This may lead to incorrect links being generated by Auth or Errors in 3rd party modules."))
if hasattr(settings, "CSRF_TRUSTED_ORIGINS"):
if hasattr(settings, "SITE_URL"):
if settings.SITE_URL not in settings.CSRF_TRUSTED_ORIGINS:
errors.append(Warning(
"'SITE_URL' not found in 'CSRF_TRUSTED_ORIGINS'. Auth may not load pages correctly until this is rectified."))
else:
errors.append(Error(
"No 'CSRF_TRUSTED_ORIGINS' found is settings, Auth may not load pages correctly until this is rectified"))
return errors

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.2.13 on 2024-05-12 09:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authentication', '0022_userprofile_theme'),
]
operations = [
migrations.AlterField(
model_name='userprofile',
name='language',
field=models.CharField(blank=True, choices=[('en', 'English'), ('de', 'German'), ('es', 'Spanish'), ('zh-hans', 'Chinese Simplified'), ('ru', 'Russian'), ('ko', 'Korean'), ('fr', 'French'), ('ja', 'Japanese'), ('it', 'Italian'), ('uk', 'Ukrainian'), ('pl', 'Polish')], default='', max_length=10, verbose_name='Language'),
),
]

View File

@@ -78,6 +78,7 @@ class UserProfile(models.Model):
JAPANESE = 'ja', _('Japanese') JAPANESE = 'ja', _('Japanese')
ITALIAN = 'it', _('Italian') ITALIAN = 'it', _('Italian')
UKRAINIAN = 'uk', _('Ukrainian') UKRAINIAN = 'uk', _('Ukrainian')
POLISH = 'pl', _("Polish")
user = models.OneToOneField( user = models.OneToOneField(
User, User,

View File

@@ -7,7 +7,7 @@
{% translate "Dashboard" %} {% translate "Dashboard" %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="d-flex justify-content-around align-self-center flex-wrap"> <div class="row">
{% for dash in views %} {% for dash in views %}
{{ dash | safe }} {{ dash | safe }}
{% endfor %} {% endfor %}

View File

@@ -1,13 +1,11 @@
{% load i18n %} {% load i18n %}
<div id="aa-dashboard-panel-characters" class="col-12 col-xl-8 align-self-stretch p-2 ps-0 pe-0 ps-xl-0 pe-xl-2"> <div id="aa-dashboard-panel-characters" class="col-12 col-xl-8 mb-3">
<div class="card"> <div class="card h-100">
<div class="card-body"> <div class="card-body">
<div class="d-flex align-items-center"> {% translate "Characters" as widget_title %}
<h4 class="ms-auto me-auto"> {% include "framework/dashboard/widget-title.html" with title=widget_title %}
{% translate "Characters" %}
</h4> <div>
</div>
<div class="card-body">
<div style="height: 300px; overflow-y:auto;"> <div style="height: 300px; overflow-y:auto;">
<div class="d-flex"> <div class="d-flex">
<a href="{% url 'authentication:add_character' %}" class="btn btn-primary flex-fill m-1" title="{% translate 'Add Character' %}"> <a href="{% url 'authentication:add_character' %}" class="btn btn-primary flex-fill m-1" title="{% translate 'Add Character' %}">

View File

@@ -1,9 +1,11 @@
{% load i18n %} {% load i18n %}
<div id="aa-dashboard-panel-membership" class="col-12 col-xl-4 align-self-stretch py-2 ps-xl-2"> <div id="aa-dashboard-panel-membership" class="col-12 col-xl-4 mb-3">
<div class="card h-100"> <div class="card h-100">
<div class="card-body"> <div class="card-body">
<h4 class="card-title text-center">{% translate "Membership" %}</h4> {% translate "Membership" as widget_title %}
<div class="card-body"> {% include "framework/dashboard/widget-title.html" with title=widget_title %}
<div>
<div style="height: 300px; overflow-y:auto;"> <div style="height: 300px; overflow-y:auto;">
<h5 class="text-center">{% translate "State:" %} {{ request.user.profile.state }}</h5> <h5 class="text-center">{% translate "State:" %} {{ request.user.profile.state }}</h5>
<table class="table"> <table class="table">

View File

@@ -1,3 +1,4 @@
{% load theme_tags %}
{% load static %} {% load static %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
@@ -16,7 +17,7 @@
<title>{% block title %}{% block page_title %}{% endblock page_title %} - {{ SITE_NAME }}{% endblock title %}</title> <title>{% block title %}{% block page_title %}{% endblock page_title %} - {{ SITE_NAME }}{% endblock title %}</title>
{% include 'bundles/bootstrap-css-bs5.html' %} {% theme_css %}
{% include 'bundles/fontawesome.html' %} {% include 'bundles/fontawesome.html' %}
{% block extra_include %} {% block extra_include %}

View File

@@ -4,7 +4,7 @@
{% block content %} {% block content %}
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-4"> <div class="col-md-6">
{% if messages %} {% if messages %}
{% for message in messages %} {% for message in messages %}
<div class="alert alert-{{ message.level_tag}}">{{ message }}</div> <div class="alert alert-{{ message.level_tag}}">{{ message }}</div>

View File

@@ -13,7 +13,7 @@
{% block content %} {% block content %}
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-4"> <div class="col-md-6">
<div class="card card-login border-secondary p-3"> <div class="card card-login border-secondary p-3">
<div class="card-body"> <div class="card-body">
<form method="POST"> <form method="POST">

171
allianceauth/checks.py Normal file
View File

@@ -0,0 +1,171 @@
from typing import List
from django import db
from django.core.checks import CheckMessage, Error, register, Warning
from allianceauth.utils.cache import get_redis_client
from django.utils import timezone
from packaging.version import InvalidVersion, Version as Pep440Version
from celery import current_app
from django.conf import settings
from sqlite3.dbapi2 import sqlite_version_info
"""
A = System Packages
B = Configuration
"""
@register()
def django_settings(app_configs, **kwargs) -> List[CheckMessage]:
errors: List[CheckMessage] = []
if hasattr(settings, "SITE_URL"):
if settings.SITE_URL[-1] == "/":
errors.append(Warning("'SITE_URL' Has a trailing slash. This may lead to incorrect links being generated by Auth.", hint="", id="allianceauth.checks.B005"))
else:
errors.append(Error("No 'SITE_URL' found is settings. This may lead to incorrect links being generated by Auth or Errors in 3rd party modules.", hint="", id="allianceauth.checks.B006"))
if hasattr(settings, "CSRF_TRUSTED_ORIGINS") and hasattr(settings, "SITE_URL"):
if settings.SITE_URL not in settings.CSRF_TRUSTED_ORIGINS:
errors.append(Warning("'SITE_URL' not found in 'CSRF_TRUSTED_ORIGINS'. Auth may not load pages correctly until this is rectified.", hint="", id="allianceauth.checks.B007"))
else:
errors.append(Error("No 'CSRF_TRUSTED_ORIGINS' found is settings, Auth may not load pages correctly until this is rectified", hint="", id="allianceauth.checks.B008"))
return errors
@register()
def system_package_redis(app_configs, **kwargs) -> List[CheckMessage]:
errors: List[CheckMessage] = []
try:
redis_version = Pep440Version(get_redis_client().info()['redis_version'])
except InvalidVersion:
errors.append(Warning("Unable to confirm Redis Version"))
return errors
if redis_version.major == 7 and redis_version.minor == 2 and timezone.now() > timezone.datetime(year=2025, month=8, day=31, tzinfo=timezone.utc):
errors.append(Error(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint="https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", id="allianceauth.checks.A001"))
elif redis_version.major == 7 and redis_version.minor == 0:
errors.append(Warning(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint="https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", id="allianceauth.checks.A002"))
elif redis_version.major == 6 and redis_version.minor == 2:
errors.append(Warning(f"Redis {redis_version.public} in Security Support only, Updating Suggested", hint="https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", id="allianceauth.checks.A018"))
elif redis_version.major in [6, 5]:
errors.append(Error(f"Redis {redis_version.public} EOL", hint="https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-linux/", id="allianceauth.checks.A003"))
return errors
@register()
def system_package_mysql(app_configs, **kwargs) -> List[CheckMessage]:
errors: List[CheckMessage] = []
for connection in db.connections.all():
if connection.vendor == "mysql":
try:
mysql_version = Pep440Version(".".join(str(i) for i in connection.mysql_version))
except InvalidVersion:
errors.append(Warning("Unable to confirm MySQL Version"))
return errors
# MySQL 8
if mysql_version.major == 8 and mysql_version.minor == 4 and timezone.now() > timezone.datetime(year=2032, month=4, day=30, tzinfo=timezone.utc):
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A004"))
elif mysql_version.major == 8 and mysql_version.minor == 3:
errors.append(Warning(f"MySQL {mysql_version.public} Non LTS", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A005"))
elif mysql_version.major == 8 and mysql_version.minor == 2:
errors.append(Warning(f"MySQL {mysql_version.public} Non LTS", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A006"))
elif mysql_version.major == 8 and mysql_version.minor == 1:
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A007"))
elif mysql_version.major == 8 and mysql_version.minor == 0 and timezone.now() > timezone.datetime(year=2026, month=4, day=30, tzinfo=timezone.utc):
errors.append(Error(f"MySQL {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A008"))
elif mysql_version.major < 8: # This will also catch Mariadb 5.x
errors.append(Error(f"MySQL or MariaDB {mysql_version.public} EOL", hint="https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/", id="allianceauth.checks.A009"))
return errors
@register()
def system_package_mariadb(app_configs, **kwargs) -> List[CheckMessage]:
errors: List[CheckMessage] = []
for connection in db.connections.all():
if connection.vendor == "mysql": # Still to find a way to determine MySQL vs MariaDB
try:
mariadb_version = Pep440Version(".".join(str(i) for i in connection.mysql_version))
except InvalidVersion:
errors.append(Warning("Unable to confirm MariaDB Version"))
return errors
# MariaDB 11
if mariadb_version.major == 11 and mariadb_version.minor == 4 and timezone.now() > timezone.datetime(year=2029, month=5, day=19, tzinfo=timezone.utc):
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A010"))
elif mariadb_version.major == 11 and mariadb_version.minor == 2:
errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A018"))
if timezone.now() > timezone.datetime(year=2024, month=11, day=21, tzinfo=timezone.utc):
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A011"))
elif mariadb_version.major == 11 and mariadb_version.minor == 1:
errors.append(Warning(f"MariaDB {mariadb_version.public} Non LTS", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A019"))
if timezone.now() > timezone.datetime(year=2024, month=8, day=21, tzinfo=timezone.utc):
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A012"))
elif mariadb_version.major == 11 and mariadb_version.minor in [0, 3]: # Demote versions down here once EOL
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config.", id="allianceauth.checks.A013"))
# MariaDB 10
elif mariadb_version.major == 10 and mariadb_version.minor == 11 and timezone.now() > timezone.datetime(year=2028, month=2, day=10, tzinfo=timezone.utc):
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config.", id="allianceauth.checks.A014"))
elif mariadb_version.major == 10 and mariadb_version.minor == 6 and timezone.now() > timezone.datetime(year=2026, month=7, day=6, tzinfo=timezone.utc):
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A0015"))
elif mariadb_version.major == 10 and mariadb_version.minor == 5 and timezone.now() > timezone.datetime(year=2025, month=6, day=24, tzinfo=timezone.utc):
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A016"))
elif mariadb_version.major == 10 and mariadb_version.minor in [0, 1, 2, 3, 4, 7, 9, 10]: # Demote versions down here once EOL
errors.append(Error(f"MariaDB {mariadb_version.public} EOL", hint="https://mariadb.org/download/?t=repo-config", id="allianceauth.checks.A017"))
return errors
@register()
def system_package_sqlite(app_configs, **kwargs) -> List[CheckMessage]:
errors: List[CheckMessage] = []
for connection in db.connections.all():
if connection.vendor == "sqlite":
try:
sqlite_version = Pep440Version(".".join(str(i) for i in sqlite_version_info))
except InvalidVersion:
errors.append(Warning("Unable to confirm SQLite Version"))
return errors
if sqlite_version.major == 3 and sqlite_version.minor < 27:
errors.append(Error(f"SQLite {sqlite_version.public} Unsupported by Django", hint="https://pkgs.org/download/sqlite3", id="allianceauth.checks.A020"))
return errors
@register()
def sql_settings(app_configs, **kwargs) -> List[CheckMessage]:
errors: List[CheckMessage] = []
for connection in db.connections.all():
if connection.vendor == "mysql":
if connection.settings_dict["OPTIONS"]["charset"] != "utf8mb4":
errors.append(Error("SQL Charset is not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/89be2456fb2d741b86417e889da9b6129525bec8", id="allianceauth.checks.B001"))
# This hasn't actually been set on AA yet
# if connection.settings_dict["OPTIONS"]["charset"] != "utf8mb4_unicode_ci":
# errors.append(Error("SQL Collation is not set correctly", hint="", id="allianceauth.checks.B002"))
# if connection.vendor == "sqlite":
return errors
@register()
def celery_settings(app_configs, **kwargs) -> List[CheckMessage]:
errors: List[CheckMessage] = []
if current_app.conf.broker_transport_options != {'priority_steps': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 'queue_order_strategy': 'priority'}:
errors.append(Error("Celery Priorities are not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/8861ec0a61790eca0261f1adc1cc04ca5f243cbc", id="allianceauth.checks.B003"))
if current_app.conf.broker_connection_retry_on_startup != True:
errors.append(Error("Celery broker_connection_retry_on_startup not set correctly", hint="https://gitlab.com/allianceauth/allianceauth/-/commit/380c41400b535447839e5552df2410af35a75280", id="allianceauth.checks.B004"))
return errors
# IDEAS
# Any other celery things weve manually changed over the years
# I'd be happy to add Community App checks, old versions the owners dont want to support etc.
# Check Default Collation on DB
# Check Charset Collation on all tables

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

@@ -7,7 +7,7 @@
{% if subtitle %} {% if subtitle %}
<br> <br>
<small>{{ subtitle }}</small> <small class="text-muted">{{ subtitle }}</small>
{% endif %} {% endif %}
</h1> </h1>
{% endif %} {% endif %}

View File

@@ -92,6 +92,9 @@
<a href="{% url 'groupmanagement:accept_request' acceptrequest.id %}" class="btn btn-success"> <a href="{% url 'groupmanagement:accept_request' acceptrequest.id %}" class="btn btn-success">
{% translate "Accept" %} {% translate "Accept" %}
</a> </a>
<a href="{% url 'groupmanagement:reject_request' acceptrequest.id %}" class="btn btn-danger">
{% translate "Reject" %}
</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-02-17 20:02+1000\n" "POT-Creation-Date: 2024-05-12 19:15+1000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -26,6 +26,15 @@ msgstr ""
msgid "Google Analytics V4" msgid "Google Analytics V4"
msgstr "" msgstr ""
#: allianceauth/authentication/constants.py:6
msgid ""
"This software has exceeded the error limit for ESI. If you are a user, "
"please contact the maintainer of this software. If you are a developer/"
"maintainer, please make a greater effort in the future to receive valid "
"responses. For tips on how, come have a chat with us in ##3rd-party-dev-and-"
"esi on the EVE Online Discord. https://www.eveonline.com/discord"
msgstr ""
#: allianceauth/authentication/decorators.py:52 #: allianceauth/authentication/decorators.py:52
msgid "A main character is required to perform that action. Add one below." msgid "A main character is required to perform that action. Add one below."
msgstr "" msgstr ""
@@ -104,27 +113,34 @@ msgstr ""
msgid "Your user's state is now: %(state)s" msgid "Your user's state is now: %(state)s"
msgstr "" msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:7 #: allianceauth/authentication/templates/authentication/dashboard.html:5
#: allianceauth/authentication/templates/authentication/dashboard.html:7
#: allianceauth/menu/templates/menu/sortable-side-menu.html:14
#: allianceauth/templates/allianceauth/side-menu.html:10
msgid "Dashboard"
msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard_characters.html:7
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:33 #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:33
#: allianceauth/hrapplications/templates/hrapplications/view.html:54 #: allianceauth/hrapplications/templates/hrapplications/view.html:54
msgid "Characters" msgid "Characters"
msgstr "" msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:13 #: allianceauth/authentication/templates/authentication/dashboard_characters.html:13
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:14 #: allianceauth/authentication/templates/authentication/dashboard_characters.html:14
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:4 #: allianceauth/templates/allianceauth/top-menu-rh-default.html:4
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:6 #: allianceauth/templates/allianceauth/top-menu-rh-default.html:6
msgid "Add Character" msgid "Add Character"
msgstr "" msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:16 #: allianceauth/authentication/templates/authentication/dashboard_characters.html:16
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:17 #: allianceauth/authentication/templates/authentication/dashboard_characters.html:17
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:10 #: allianceauth/templates/allianceauth/top-menu-rh-default.html:10
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:12 #: allianceauth/templates/allianceauth/top-menu-rh-default.html:12
msgid "Change Main" msgid "Change Main"
msgstr "" msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:24 #: allianceauth/authentication/templates/authentication/dashboard_characters.html:24
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:89 #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:89
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:23 #: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:23
#: allianceauth/groupmanagement/templates/groupmanagement/groups.html:31 #: allianceauth/groupmanagement/templates/groupmanagement/groups.html:31
@@ -133,32 +149,25 @@ msgstr ""
msgid "Name" msgid "Name"
msgstr "" msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:25 #: allianceauth/authentication/templates/authentication/dashboard_characters.html:25
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:33 #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:33
msgid "Corp" msgid "Corp"
msgstr "" msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.characters.html:26 #: allianceauth/authentication/templates/authentication/dashboard_characters.html:26
#: allianceauth/corputils/templates/corputils/corpstats.html:125 #: allianceauth/corputils/templates/corputils/corpstats.html:125
#: allianceauth/hrapplications/templates/hrapplications/view.html:63 #: allianceauth/hrapplications/templates/hrapplications/view.html:63
msgid "Alliance" msgid "Alliance"
msgstr "" msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.groups.html:5 #: allianceauth/authentication/templates/authentication/dashboard_groups.html:5
msgid "Membership" msgid "Membership"
msgstr "" msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.groups.html:8 #: allianceauth/authentication/templates/authentication/dashboard_groups.html:8
msgid "State:" msgid "State:"
msgstr "" msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.html:5
#: allianceauth/authentication/templates/authentication/dashboard.html:7
#: allianceauth/menu/templates/menu/sortable-side-menu.html:14
#: allianceauth/templates/allianceauth/side-menu.html:10
msgid "Dashboard"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:6 #: allianceauth/authentication/templates/authentication/tokens.html:6
#: allianceauth/authentication/templates/authentication/tokens.html:10 #: allianceauth/authentication/templates/authentication/tokens.html:10
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62 #: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
@@ -197,7 +206,7 @@ msgstr ""
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:29 #: allianceauth/groupmanagement/templates/groupmanagement/audit.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:28 #: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:28
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:115 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:118
msgid "Character" msgid "Character"
msgstr "" msgstr ""
@@ -234,49 +243,49 @@ msgstr ""
msgid "Invalid or expired activation link." msgid "Invalid or expired activation link."
msgstr "" msgstr ""
#: allianceauth/authentication/views.py:147 #: allianceauth/authentication/views.py:158
#, python-format #, python-format
msgid "" msgid ""
"Cannot change main character to %(char)s: character owned by a different " "Cannot change main character to %(char)s: character owned by a different "
"account." "account."
msgstr "" msgstr ""
#: allianceauth/authentication/views.py:153 #: allianceauth/authentication/views.py:165
#, python-format #, python-format
msgid "Changed main character to %(char)s" msgid "Changed main character to %s"
msgstr "" msgstr ""
#: allianceauth/authentication/views.py:162 #: allianceauth/authentication/views.py:179
#, python-format #, python-format
msgid "Added %(name)s to your account." msgid "Added %(name)s to your account."
msgstr "" msgstr ""
#: allianceauth/authentication/views.py:164 #: allianceauth/authentication/views.py:181
#, python-format #, python-format
msgid "Failed to add %(name)s to your account: they already have an account." msgid "Failed to add %(name)s to your account: they already have an account."
msgstr "" msgstr ""
#: allianceauth/authentication/views.py:207 #: allianceauth/authentication/views.py:226
msgid "" msgid ""
"Unable to authenticate as the selected character. Please log in with the " "Unable to authenticate as the selected character. Please log in with the "
"main character associated with this account." "main character associated with this account."
msgstr "" msgstr ""
#: allianceauth/authentication/views.py:273 #: allianceauth/authentication/views.py:293
msgid "Registration token has expired." msgid "Registration token has expired."
msgstr "" msgstr ""
#: allianceauth/authentication/views.py:331 #: allianceauth/authentication/views.py:354
msgid "" msgid ""
"Sent confirmation email. Please follow the link to confirm your email " "Sent confirmation email. Please follow the link to confirm your email "
"address." "address."
msgstr "" msgstr ""
#: allianceauth/authentication/views.py:336 #: allianceauth/authentication/views.py:360
msgid "Confirmed your email address. Please login to continue." msgid "Confirmed your email address. Please login to continue."
msgstr "" msgstr ""
#: allianceauth/authentication/views.py:341 #: allianceauth/authentication/views.py:366
msgid "Registration of new accounts is not allowed at this time." msgid "Registration of new accounts is not allowed at this time."
msgstr "" msgstr ""
@@ -495,7 +504,6 @@ msgstr ""
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:44 #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:44
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:92 #: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:92
#: allianceauth/templates/allianceauth/top-menu.html:23 #: allianceauth/templates/allianceauth/top-menu.html:23
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:17
#: allianceauth/timerboard/templates/timerboard/timertable.html:11 #: allianceauth/timerboard/templates/timerboard/timertable.html:11
msgid "Eve Time" msgid "Eve Time"
msgstr "" msgstr ""
@@ -833,7 +841,7 @@ msgstr ""
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29 #: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:56 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:56
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:116 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:119
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:32 #: allianceauth/permissions_tool/templates/permissions_tool/audit.html:32
msgid "Organization" msgid "Organization"
msgstr "" msgstr ""
@@ -845,7 +853,7 @@ msgstr ""
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:60 #: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:60
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:85 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:85
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:145 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:148
#: allianceauth/permissions_tool/templates/permissions_tool/audit_row.html:18 #: allianceauth/permissions_tool/templates/permissions_tool/audit_row.html:18
msgid "(unknown)" msgid "(unknown)"
msgstr "" msgstr ""
@@ -926,7 +934,7 @@ msgstr ""
#: allianceauth/groupmanagement/templates/groupmanagement/groups.html:36 #: allianceauth/groupmanagement/templates/groupmanagement/groups.html:36
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:57 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:57
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:117 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:120
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:29 #: allianceauth/permissions_tool/templates/permissions_tool/audit.html:29
#: allianceauth/services/modules/openfire/forms.py:6 #: allianceauth/services/modules/openfire/forms.py:6
msgid "Group" msgid "Group"
@@ -980,20 +988,21 @@ msgid "Group Membership"
msgstr "" msgstr ""
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:93 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:93
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:153 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:156
msgid "Accept" msgid "Accept"
msgstr "" msgstr ""
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:103 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:96
msgid "No group add requests." #: allianceauth/groupmanagement/templates/groupmanagement/index.html:160
msgstr ""
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:157
#: allianceauth/hrapplications/templates/hrapplications/view.html:104 #: allianceauth/hrapplications/templates/hrapplications/view.html:104
msgid "Reject" msgid "Reject"
msgstr "" msgstr ""
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:166 #: allianceauth/groupmanagement/templates/groupmanagement/index.html:106
msgid "No group add requests."
msgstr ""
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:169
msgid "No group leave requests." msgid "No group leave requests."
msgstr "" msgstr ""
@@ -1376,6 +1385,8 @@ msgid "Sign Out"
msgstr "" msgstr ""
#: allianceauth/menu/templates/menu/menu-user.html:84 #: allianceauth/menu/templates/menu/menu-user.html:84
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:17
#: allianceauth/templates/allianceauth/top-menu-rh-default.html:18
msgid "Sign In" msgid "Sign In"
msgstr "" msgstr ""
@@ -1458,7 +1469,6 @@ msgid "Doctrine"
msgstr "" msgstr ""
#: allianceauth/optimer/form.py:14 #: allianceauth/optimer/form.py:14
#: allianceauth/optimer/templates/optimer/dashboard.ops.html:17
#: allianceauth/optimer/templates/optimer/fleetoptable.html:13 #: allianceauth/optimer/templates/optimer/fleetoptable.html:13
msgid "Start Time" msgid "Start Time"
msgstr "" msgstr ""
@@ -1523,6 +1533,11 @@ msgstr ""
msgid "Form Up System" msgid "Form Up System"
msgstr "" msgstr ""
#: allianceauth/optimer/templates/optimer/dashboard.ops.html:17
#: allianceauth/timerboard/templates/timerboard/dashboard.timers.html:17
msgid "EVE Time"
msgstr ""
#: allianceauth/optimer/templates/optimer/fleetoptable.html:14 #: allianceauth/optimer/templates/optimer/fleetoptable.html:14
#: allianceauth/timerboard/templates/timerboard/timertable.html:12 #: allianceauth/timerboard/templates/timerboard/timertable.html:12
msgid "Local Time" msgid "Local Time"
@@ -1568,17 +1583,17 @@ msgstr ""
msgid "Update fleet operation" msgid "Update fleet operation"
msgstr "" msgstr ""
#: allianceauth/optimer/views.py:89 #: allianceauth/optimer/views.py:91
#, python-format #, python-format
msgid "Created operation timer for %(opname)s." msgid "Created operation timer for %(opname)s."
msgstr "" msgstr ""
#: allianceauth/optimer/views.py:118 #: allianceauth/optimer/views.py:120
#, python-format #, python-format
msgid "Removed operation timer for %(opname)s." msgid "Removed operation timer for %(opname)s."
msgstr "" msgstr ""
#: allianceauth/optimer/views.py:169 #: allianceauth/optimer/views.py:171
#, python-format #, python-format
msgid "Saved changes to operation timer for %(opname)s." msgid "Saved changes to operation timer for %(opname)s."
msgstr "" msgstr ""
@@ -2367,6 +2382,10 @@ msgstr ""
msgid "Saved changes to SRP fleet %(fleetname)s" msgid "Saved changes to SRP fleet %(fleetname)s"
msgstr "" msgstr ""
#: allianceauth/templates/allianceauth/admin-status/esi_check.html:4
msgid "Your Server received an ESI error response code of "
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:11 #: allianceauth/templates/allianceauth/admin-status/overview.html:11
msgid "Alliance Auth Notifications" msgid "Alliance Auth Notifications"
msgstr "" msgstr ""
@@ -2693,12 +2712,12 @@ msgstr ""
msgid "Past Timers" msgid "Past Timers"
msgstr "" msgstr ""
#: allianceauth/timerboard/views.py:78 #: allianceauth/timerboard/views.py:85
#, python-format #, python-format
msgid "Added new timer in %(system)s at %(time)s." msgid "Added new timer in %(system)s at %(time)s."
msgstr "" msgstr ""
#: allianceauth/timerboard/views.py:87 #: allianceauth/timerboard/views.py:95
msgid "Saved changes to the timer." msgid "Saved changes to the timer."
msgstr "" msgstr ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,7 @@
{% endif %}> {% endif %}>
</i> </i>
<a <a
class="nav-link flex-fill align-self-center me-auto" class="nav-link flex-fill align-self-center me-auto {% if item.navactive %}{% navactive request item.navactive|join:' ' %}{% endif %}"
{% if item.is_folder %} {% if item.is_folder %}
type="button" type="button"
data-bs-toggle="collapse" data-bs-toggle="collapse"

View File

@@ -60,15 +60,17 @@
<li> <li>
<a class="dropdown-item" href="https://discord.gg/fjnHAmk" title="Alliance Auth Discord"><i class="fa-brands fa-discord fa-fw"></i> Alliance Auth Discord</a> <a class="dropdown-item" href="https://discord.gg/fjnHAmk" title="Alliance Auth Discord"><i class="fa-brands fa-discord fa-fw"></i> Alliance Auth Discord</a>
</li> </li>
<li>
<a class="dropdown-item" href="https://gitlab.com/allianceauth/allianceauth" title="Alliance Auth Git"><i class="fa-brands fa-gitlab fa-fw"></i> Alliance Auth Git</a>
</li>
<li> <li>
<a class="dropdown-item" href="{% url 'admin:index' %}"> <a class="dropdown-item" href="https://gitlab.com/allianceauth/allianceauth" title="Alliance Auth Git"><i class="fa-brands fa-gitlab fa-fw"></i> Alliance Auth Git</a>
<i class="fa-solid fa-gear fa-fw"></i> {% translate "Admin" %}
</a>
</li> </li>
{% endif %} {% endif %}
{% if user.is_staff %}
<li>
<a class="dropdown-item" href="{% url 'admin:index' %}">
<i class="fa-solid fa-gear fa-fw"></i> {% translate "Admin" %}
</a>
</li>
{% endif %}
<li><hr class="dropdown-divider"></li> <li><hr class="dropdown-divider"></li>
{% if user.is_authenticated %} {% if user.is_authenticated %}
<li> <li>

View File

@@ -10,7 +10,7 @@
<ul id="sidebar-menu" class="navbar-nav flex-column mb-auto overflow-auto pt-2"> <ul id="sidebar-menu" class="navbar-nav flex-column mb-auto overflow-auto pt-2">
<li class="d-flex flex-wrap m-2 p-2 pt-0 pb-0 mt-0 mb-0 me-0 pe-0"> <li class="d-flex flex-wrap m-2 p-2 pt-0 pb-0 mt-0 mb-0 me-0 pe-0">
<i class="nav-link fas fa-tachometer-alt fa-fw align-self-center me-3 {% navactive request 'authentication:dashboard' %}"></i> <i class="nav-link fas fa-tachometer-alt fa-fw align-self-center me-3 {% navactive request 'authentication:dashboard' %}"></i>
<a class="nav-link flex-fill align-self-center" href="{% url 'authentication:dashboard' %}"> <a class="nav-link flex-fill align-self-center {% navactive request 'authentication:dashboard' %}" href="{% url 'authentication:dashboard' %}">
{% translate "Dashboard" %} {% translate "Dashboard" %}
</a> </a>
</li> </li>

View File

@@ -98,6 +98,10 @@ def render_menu(request: HttpRequest) -> List[RenderedMenuItem]:
if item.is_app_item: if item.is_app_item:
rendered_item = _render_app_item(request, hook_items, item, bs5_template) rendered_item = _render_app_item(request, hook_items, item, bs5_template)
if rendered_item.html == "":
# If there is no content dont render it.
# This item has probably been hidden by permissions
continue
elif item.is_link_item: elif item.is_link_item:
rendered_item = _render_link_item(request, item, bs5_template) rendered_item = _render_link_item(request, item, bs5_template)
elif item.is_folder: elif item.is_folder:

View File

@@ -19,6 +19,11 @@ def create_user(permissions=None, **kwargs) -> User:
return user return user
def create_menu_item_hook_class(**kwargs) -> MenuItemHook:
num = next(counter_menu_item_hook)
return type(f"GeneratedMenuItem{num}", (MenuItemHook,), {})
def create_menu_item_hook(**kwargs) -> MenuItemHook: def create_menu_item_hook(**kwargs) -> MenuItemHook:
num = next(counter_menu_item_hook) num = next(counter_menu_item_hook)
new_class = type(f"GeneratedMenuItem{num}", (MenuItemHook,), {}) new_class = type(f"GeneratedMenuItem{num}", (MenuItemHook,), {})

View File

@@ -14,6 +14,7 @@ from allianceauth.menu.tests.factories import (
create_folder_menu_item, create_folder_menu_item,
create_link_menu_item, create_link_menu_item,
create_menu_item_from_hook, create_menu_item_from_hook,
create_menu_item_hook_class,
create_menu_item_hook_function, create_menu_item_hook_function,
create_rendered_menu_item, create_rendered_menu_item,
) )
@@ -177,6 +178,44 @@ class TestRenderDefaultMenu(TestCase):
self.assertEqual(menu[0].menu_item.text, "Alpha") self.assertEqual(menu[0].menu_item.text, "Alpha")
self.assertEqual(menu[1].menu_item.text, "Bravo") self.assertEqual(menu[1].menu_item.text, "Bravo")
def test_should_remove_empty_folders_with_items_hidden(self, mock_get_hooks):
# given
class TestHook(create_menu_item_hook_class()):
text = "Dummy App No Data"
classes = "fa-solid fa-users-gear"
url_name = "groupmanagement:management"
def render(Self, request):
# simulate no perms
return ""
params = {
"text": "Alpha",
"classes": "fa-solid fa-users-gear",
"url_name": "groupmanagement:management",
}
alpha = TestHook(**params)
hooks = [lambda: alpha]
mock_get_hooks.return_value = hooks
folder = create_folder_menu_item(text="Folder", order=2)
create_menu_item_from_hook(hooks[0], parent=folder)
create_link_menu_item(text="Bravo", order=3) # this is all that should show
request = self.factory.get("/")
# when
result = render_menu(request)
# then
menu = list(result)
self.assertEqual(len(menu), 1)
self.assertEqual(menu[0].menu_item.text, "Bravo")
def test_should_not_include_hidden_items(self, mock_get_hooks): def test_should_not_include_hidden_items(self, mock_get_hooks):
# given # given
mock_get_hooks.return_value = [] mock_get_hooks.return_value = []
@@ -196,7 +235,6 @@ class TestRenderDefaultMenu(TestCase):
self.assertEqual(menu[1].menu_item.text, "Charlie") self.assertEqual(menu[1].menu_item.text, "Charlie")
def test_should_not_render_hidden_folders(self, mock_get_hooks): def test_should_not_render_hidden_folders(self, mock_get_hooks):
# given
# given # given
menu = [ menu = [
create_menu_item_hook_function(text="Charlie", count=42), create_menu_item_hook_function(text="Charlie", count=42),

View File

@@ -1,41 +1,40 @@
{% load i18n %} {% load i18n %}
{% load evelinks %} {% load evelinks %}
<div class="col-12 align-self-stretch py-2"> <div class="col-12 mb-3">
<div class="card h-100"> <div class="card h-100">
<div class="card-body"> <div class="card-body">
<h4 class="card-title text-center">{% translate "Upcoming Fleets" %}</h4> {% translate "Upcoming Fleets" as widget_title %}
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
<div class="card-body"> <div>
<div style="height: 300px; overflow-y:auto;"> <table class="table">
<table class="table"> <thead>
<thead> <tr>
<th class="text-center">{% translate "Operation" %}</th>
<th class="text-center">{% translate "Type" %}</th>
<th class="text-center">{% translate "Form Up System" %}</th>
<th class="text-center">{% translate "EVE Time" %}</th>
</tr>
</thead>
<tbody>
{% for ops in timers %}
<tr> <tr>
<th class="text-center">{% translate "Operation" %}</th> <td class="text-center">
<th class="text-center">{% translate "Type" %}</th> {{ ops.operation_name }}
<th class="text-center">{% translate "Form Up System" %}</th> </td>
<th class="text-center">{% translate "Start Time" %}</th> <td class="text-center">
{{ ops.type }}
</td>
<td class="text-center">
<a href="{{ ops.system|dotlan_solar_system_url }}">{{ ops.system }}</a>
</td>
<td class="text-center" nowrap>{{ ops.start | date:"Y-m-d H:i" }}</td>
</tr> </tr>
</thead> {% endfor %}
</tbody>
<tbody> </table>
{% for ops in timers %}
<tr>
<td class="text-center">
{{ ops.operation_name }}
</td>
<td class="text-center">
{{ ops.type }}
</td>
<td class="text-center">
<a href="{{ ops.system|dotlan_solar_system_url }}">{{ ops.system }}</a>
</td>
<td class="text-center" nowrap>{{ ops.start | date:"Y-m-d H:i" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -14,9 +14,11 @@ from .models import OpTimer, OpTimerType
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
OPS_VIEW_PERMISSION = 'auth.optimer_view'
OPS_MANAGE_PERMISSION = 'auth.optimer_management'
@login_required @login_required
@permission_required('auth.optimer_view') @permission_required(OPS_VIEW_PERMISSION)
def optimer_view(request): def optimer_view(request):
""" """
View for the optimer management page View for the optimer management page
@@ -39,7 +41,7 @@ def optimer_view(request):
@login_required @login_required
@permission_required('auth.optimer_management') @permission_required(OPS_MANAGE_PERMISSION)
def add_optimer_view(request): def add_optimer_view(request):
""" """
View for the add optimer page View for the add optimer page
@@ -98,7 +100,7 @@ def add_optimer_view(request):
@login_required @login_required
@permission_required('auth.optimer_management') @permission_required(OPS_MANAGE_PERMISSION)
def remove_optimer(request, optimer_id): def remove_optimer(request, optimer_id):
""" """
Remove optimer Remove optimer
@@ -121,7 +123,7 @@ def remove_optimer(request, optimer_id):
@login_required @login_required
@permission_required('auth.optimer_management') @permission_required(OPS_MANAGE_PERMISSION)
def edit_optimer(request, optimer_id): def edit_optimer(request, optimer_id):
""" """
Edit optimer Edit optimer
@@ -192,14 +194,22 @@ def dashboard_ops(request):
:return: :return:
:rtype: :rtype:
""" """
if request.user.has_perm(OPS_VIEW_PERMISSION):
base_query = OpTimer.objects.select_related('eve_character', 'type')
timers = base_query.filter(
start__gte=timezone.now()
)[:5]
base_query = OpTimer.objects.select_related('eve_character', 'type') if timers.count():
timers = base_query.filter(start__gte=timezone.now())[:5] context = {
'timers': timers,
if timers.count(): }
context = { return render_to_string(
'timers': timers, 'optimer/dashboard.ops.html',
} context=context,
return render_to_string('optimer/dashboard.ops.html', context=context, request=request) request=request
)
else:
return ""
else: else:
return "" return ""

View File

@@ -102,6 +102,7 @@ LANGUAGES = (
("ja", "Japanese"), ("ja", "Japanese"),
("it", "Italian"), ("it", "Italian"),
("uk", "Ukrainian"), ("uk", "Ukrainian"),
("pl", "Polish"),
) )
TEMPLATES = [ TEMPLATES = [

View File

@@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
<div id="esi-alert" class="col-12 align-self-stretch py-2 collapse"> <div id="esi-alert" class="col-12 collapse">
<div class="alert alert-warning"> <div class="alert alert-warning">
<p class="text-center ">{% translate 'Your Server received an ESI error response code of ' %}<b id="esi-code">?</b></p> <p class="text-center ">{% translate 'Your Server received an ESI error response code of ' %}<b id="esi-code">?</b></p>
<hr> <hr>
@@ -23,7 +23,7 @@
console.log("ESI Check: ", JSON.stringify(responseJson, null, 2)); console.log("ESI Check: ", JSON.stringify(responseJson, null, 2));
const status = responseJson.status; const status = responseJson.status;
if (status != 200) { if (status !== 200) {
elemCode.textContent = status elemCode.textContent = status
elemMessage.textContent = responseJson.data.error; elemMessage.textContent = responseJson.data.error;
new bootstrap.Collapse(elemCard, { new bootstrap.Collapse(elemCard, {

View File

@@ -2,48 +2,43 @@
{% load humanize %} {% load humanize %}
{% if notifications %} {% if notifications %}
<div id="aa-dashboard-panel-admin-notifications" class="col-12 align-self-stretch pb-2"> <div id="aa-dashboard-panel-admin-notifications" class="col-12 mb-3">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<div class="d-flex align-items-center"> {% translate "Alliance Auth Notifications" as widget_title %}
<div class="w-100 align-self-stretch"> {% include "framework/dashboard/widget-title.html" with title=widget_title %}
<h4 class="ms-auto me-auto text-center">
{% translate "Alliance Auth Notifications" %}
</h4>
<div class="card-body"> <div>
<ul class="list-group"> <ul class="list-group">
{% for notif in notifications %} {% for notif in notifications %}
<li class="list-group-item"> <li class="list-group-item">
{% if notif.state == 'opened' %} {% if notif.state == 'opened' %}
<span class="badge bg-success">{% translate "Open" %}</span> <span class="badge bg-success">{% translate "Open" %}</span>
{% else %} {% else %}
<span class="badge bg-danger">{% translate "Closed" %}</span> <span class="badge bg-danger">{% translate "Closed" %}</span>
{% endif %} {% endif %}
<a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a> <a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a>
</li> </li>
{% empty %} {% empty %}
<div class="alert alert-primary" role="alert"> <div class="alert alert-primary" role="alert">
{% translate "No notifications at this time" %} {% translate "No notifications at this time" %}
</div>
{% endfor %}
</ul>
<div class="text-end">
<a href="https://gitlab.com/allianceauth/allianceauth/issues" target="_blank" class="me-1">
<span class="badge" style="background-color: rgb(230 83 40);">
<i class="fab fa-gitlab" aria-hidden="true"></i>
{% translate 'Powered by GitLab' %}
</span>
</a>
<a href="https://discord.com/invite/fjnHAmk" target="_blank">
<span class="badge" style="background-color: rgb(110 133 211);">
<i class="fab fa-discord" aria-hidden="true"></i>
{% translate 'Support Discord' %}
</span>
</a>
</div> </div>
</div> {% endfor %}
</ul>
<div class="text-end pt-3">
<a href="https://gitlab.com/allianceauth/allianceauth/issues" target="_blank" class="me-1 text-decoration-none">
<span class="badge" style="background-color: rgb(230 83 40);">
<i class="fab fa-gitlab" aria-hidden="true"></i>
{% translate 'Powered by GitLab' %}
</span>
</a>
<a href="https://discord.com/invite/fjnHAmk" target="_blank" class="text-decoration-none">
<span class="badge" style="background-color: rgb(110 133 211);">
<i class="fab fa-discord" aria-hidden="true"></i>
{% translate 'Support Discord' %}
</span>
</a>
</div> </div>
</div> </div>
</div> </div>
@@ -51,25 +46,24 @@
</div> </div>
{% endif %} {% endif %}
<div class="col-12 align-self-stretch pb-2"> <div class="col-12 mb-3">
<div class="card"> <div class="card">
<div class="card-body d-flex flex-row flex-wrap"> <div class="card-body row">
<div id="aa-dashboard-panel-software-version" class="col-xl-6 col-lg-12 col-md-12 col-sm-12"> <div id="aa-dashboard-panel-software-version" class="col-xl-6 col-lg-12 col-md-12 col-sm-12">
<h4 class="ms-auto me-auto text-center"> {% translate "Software Version" as widget_title %}
{% translate "Software Version" %} {% include "framework/dashboard/widget-title.html" with title=widget_title %}
</h4>
<div class="card-body"> <div>
<ul class="list-group list-group-horizontal w-100" role="group" aria-label="{% translate 'Software Version' %}"> <ul class="list-group list-group-horizontal w-100" role="group" aria-label="{% translate 'Software Version' %}">
<li class="list-group-item w-100"> <li class="list-group-item w-100">
<div class="btn w-100 cursor-default"> <div class="btn h-100 w-100 cursor-default">
<h5 class="list-group-item-heading">{% translate "Current" %}</h5> <h5 class="list-group-item-heading">{% translate "Current" %}</h5>
<p class="list-group-item-text">{{ current_version }}</p> <p class="list-group-item-text">{{ current_version }}</p>
</div> </div>
</li> </li>
<li class="list-group-item bg-{% if latest_patch %}success{% elif latest_minor %}warning{% else %}danger{% endif %} w-100"> <li class="list-group-item bg-{% if latest_patch %}success{% elif latest_minor %}warning{% else %}danger{% endif %} w-100">
<a class="btn w-100" href="https://gitlab.com/allianceauth/allianceauth/-/releases/v{{ latest_patch_version }}"> <a class="btn h-100 w-100" href="https://gitlab.com/allianceauth/allianceauth/-/releases/v{{ latest_patch_version }}">
<h5 class="list-group-item-heading">{% translate "Latest Stable" %}</h5> <h5 class="list-group-item-heading">{% translate "Latest Stable" %}</h5>
<p class="list-group-item-text"> <p class="list-group-item-text">
@@ -82,7 +76,7 @@
{% if latest_beta %} {% if latest_beta %}
<li class="list-group-item bg-info w-100"> <li class="list-group-item bg-info w-100">
<a class="btn w-100" href="https://gitlab.com/allianceauth/allianceauth/-/releases/v{{ latest_beta_version }}"> <a class="btn h-100 w-100" href="https://gitlab.com/allianceauth/allianceauth/-/releases/v{{ latest_beta_version }}">
<h5 class="list-group-item-heading">{% translate "Latest Pre-Release" %}</h5> <h5 class="list-group-item-heading">{% translate "Latest Pre-Release" %}</h5>
<p class="list-group-item-text"> <p class="list-group-item-text">
@@ -98,11 +92,10 @@
</div> </div>
<div id="aa-dashboard-panel-task-queue" class="col-xl-6 col-lg-12 col-md-12 col-sm-12"> <div id="aa-dashboard-panel-task-queue" class="col-xl-6 col-lg-12 col-md-12 col-sm-12">
<h4 class="ms-auto me-auto text-center"> {% translate "Task Queue" as widget_title %}
{% translate "Task Queue" %} {% include "framework/dashboard/widget-title.html" with title=widget_title %}
</h4>
<div class="card-body"> <div>
<p> <p>
{% blocktranslate with total=tasks_total|intcomma latest=earliest_task|timesince|default:"?" %} {% blocktranslate with total=tasks_total|intcomma latest=earliest_task|timesince|default:"?" %}
Status of {{ total }} processed tasks • last {{ latest }} Status of {{ total }} processed tasks • last {{ latest }}

View File

@@ -29,56 +29,53 @@
transform: rotate(180deg); transform: rotate(180deg);
} }
{% if user.is_authenticated %} .nav-padding {
.nav-padding { padding-top: {% header_padding_size %} !important;
padding-top: {% header_padding_size %} !important; }
}
{% endif %}
</style> </style>
{% block extra_css %}{% endblock extra_css %} {% block extra_css %}{% endblock extra_css %}
</head> </head>
<body> <body>
{% if user.is_authenticated %} <!-- Top Menu, Blocks don't work in "include" tagged views -->
<!-- Top Menu, Blocks don't work in "include" tagged views --> <nav class="navbar navbar-expand-lg navbar-dark fixed-top bg-primary">
<nav class="navbar navbar-expand-lg navbar-dark fixed-top bg-primary"> <div class="container-fluid justify-content-start">
<div class="container-fluid justify-content-start"> <a class="navbar-brand" data-bs-toggle="collapse" data-bs-target="#sidebar" role="button">
{% if user.is_authenticated %} <i class="fa-solid fa-bars ms-2 me-2"></i>
<a class="navbar-brand" data-bs-toggle="collapse" data-bs-target="#sidebar" role="button"> </a>
<i class="fa-solid fa-bars ms-2 me-2"></i>
</a>
{% endif %}
<div class="navbar-brand"> <div class="navbar-brand">
{% block header_nav_brand %}{{ SITE_NAME }}{% endblock %} {% block header_nav_brand %}{{ SITE_NAME }}{% endblock %}
</div>
<div class="collapse navbar-collapse ms-2 px-2" id="navbarexpand">
<ul id="nav-left" class="nav navbar-nav me-auto">
{% block header_nav_collapse_left %}
{% endblock %}
</ul>
<ul id="nav-right" class="nav navbar-nav">
{% block header_nav_collapse_right %}
{% endblock %}
</ul>
<ul id="nav-right-character-control" class="nav navbar-nav">
{% block header_nav_user_character_control %} <!-- Default to add char and swap main -->
{% include 'allianceauth/top-menu-rh-default.html' %}
{% endblock %}
{% include 'menu/menu-notification-block.html' %}
</ul>
</div>
<a class="navbar-toggler navbar-brand border-0 collapsed" data-bs-toggle="collapse" data-bs-target="#navbarexpand" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation" style="margin-left: auto;">
<i class="fa-solid fa-chevron-up"></i>
</a>
</div> </div>
</nav>
{% endif %} <div class="collapse navbar-collapse ms-2 px-2" id="navbarexpand">
<ul id="nav-left" class="nav navbar-nav me-auto">
{% block header_nav_collapse_left %}
{% endblock %}
</ul>
<ul id="nav-right" class="nav navbar-nav">
{% block header_nav_collapse_right %}
{% endblock %}
</ul>
<ul id="nav-right-character-control" class="nav navbar-nav">
{% block header_nav_user_character_control %} <!-- Default to add char and swap main -->
{% include 'allianceauth/top-menu-rh-default.html' %}
{% endblock %}
{% if user.is_authenticated %}
{% include 'menu/menu-notification-block.html' %}
{% endif %}
</ul>
</div>
<a class="navbar-toggler navbar-brand border-0 collapsed" data-bs-toggle="collapse" data-bs-target="#navbarexpand" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation" style="margin-left: auto;">
<i class="fa-solid fa-chevron-up"></i>
</a>
</div>
</nav>
<!-- End Top Menu --> <!-- End Top Menu -->
<!-- Body --> <!-- Body -->
@@ -98,23 +95,27 @@
<script> <script>
(() => { (() => {
// TODO Extend this to the groups in the sidebar too.
// TODO Move to own JS file // TODO Move to own JS file
const sidebar = document.getElementById('sidebar'); const sidebar = document.getElementById('sidebar');
sidebar.addEventListener("shown.bs.collapse", () => { sidebar.addEventListener('shown.bs.collapse', () => {
localStorage.removeItem("sidebar_" + sidebar.id); localStorage.removeItem('sidebar_' + sidebar.id);
}); });
sidebar.addEventListener("hidden.bs.collapse", () => { sidebar.addEventListener('hidden.bs.collapse', () => {
localStorage.setItem("sidebar_" + sidebar.id, true); localStorage.setItem('sidebar_' + sidebar.id, 'closed');
}); });
if (localStorage.getItem("sidebar_" + sidebar.id) === "true") { if (localStorage.getItem('sidebar_' + sidebar.id) === 'closed') {
sidebar.classList.remove("show") sidebar.classList.remove('show')
} else { } else {
sidebar.classList.add("show") sidebar.classList.add("show")
} }
const activeChildMenuItem = document.querySelector('#sidebar-menu li ul li a.active');
if (activeChildMenuItem) {
activeChildMenuItem.parentElement.parentElement.classList.add('show');
}
})(); })();
</script> </script>

View File

@@ -1,31 +1,37 @@
{% extends "allianceauth/base-bs5.html" %} {% extends "allianceauth/base-bs5.html" %}
{% load theme_tags %}
{% block page_title %} {% block page_title %}
{{ error_title }} {{ error_title }}
{% endblock page_title %} {% endblock page_title %}
{% block content %} {% block content %}
<div> <div class="d-flex flex-column" style="height: calc(100vh - {% header_padding_size %}); margin-top: -1rem; margin-bottom: -1rem;">
{% include "framework/header/page-header.html" with title=error_title %} <div class="d-flex flex-grow-1 justify-content-center align-items-center">
<div>
{% include "framework/header/page-header.html" with title=error_title %}
<div class="text-center"> <div class="text-center">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="150" width="150"
height="150" height="150"
fill="currentColor" fill="currentColor"
class="bi bi-exclamation-triangle" class="bi bi-exclamation-triangle"
viewBox="0 0 16 16" viewBox="0 0 16 16"
> >
<path <path
d="M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.146.146 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.163.163 0 0 1-.054.06.116.116 0 0 1-.066.017H1.146a.115.115 0 0 1-.066-.017.163.163 0 0 1-.054-.06.176.176 0 0 1 .002-.183L7.884 2.073a.147.147 0 0 1 .054-.057zm1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566z" d="M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.146.146 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.163.163 0 0 1-.054.06.116.116 0 0 1-.066.017H1.146a.115.115 0 0 1-.066-.017.163.163 0 0 1-.054-.06.176.176 0 0 1 .002-.183L7.884 2.073a.147.147 0 0 1 .054-.057zm1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566z"
/> />
<path <path
d="M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995z" d="M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995z"
/> />
</svg> </svg>
</div>
<p class="text-center">{{ error_message }}</p>
</div>
</div> </div>
<p class="text-center">{{ error_message }}</p>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
{% if user.is_authenticated %}
<li class="nav-item"> <li class="nav-item">
<a href="{% url 'authentication:add_character' %}" class="nav-link" title="{% translate 'Add Character' %}"> <a href="{% url 'authentication:add_character' %}" class="nav-link" title="{% translate 'Add Character' %}">
<i class="fa-solid fa-plus"></i> <i class="fa-solid fa-plus"></i>
@@ -12,3 +12,10 @@
<span class="d-lg-none d-md-inline m-2">{% translate "Change Main" %}</span> <span class="d-lg-none d-md-inline m-2">{% translate "Change Main" %}</span>
</a> </a>
</li> </li>
{% else %}
<li class="nav-item">
<a href="{% url 'authentication:login' %}" class="nav-link" title="{% translate 'Sign In' %}">
<i class="fa-solid fa-right-to-bracket fa-fw "></i> {% translate "Sign In" %}
</a>
</li>
{% endif %}

View File

@@ -4,7 +4,7 @@ from django.apps import AppConfig
class BootstrapThemeConfig(AppConfig): class BootstrapThemeConfig(AppConfig):
name = "allianceauth.theme.bootstrap" name = "allianceauth.theme.bootstrap"
label = "bootstrap" label = "bootstrap"
version = "5.3.0" version = "5.3.3"
verbose_name = f"Bootstrap v{version}" verbose_name = f"Bootstrap v{version}"
def ready(self): def ready(self):

View File

@@ -3,16 +3,16 @@ from allianceauth.theme.hooks import ThemeHook
CSS_STATICS = [{ CSS_STATICS = [{
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css", "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css",
"integrity": "sha512-b2QcS5SsA8tZodcDtGRELiGv5SaKSk1vDHDaQRda0htPYWZ6046lr3kJ5bAAQdpV2mmA/4v0wQF9MyU6/pDIAg==" "integrity": "sha512-jnSuA4Ss2PkkikSOLtYs8BlYIeeIK1h99ty4YfvRPAlzr377vr3CXDb7sb7eEEBYjDtcYj+AjBH3FLv5uSJuXg=="
}] }]
JS_STATICS = [{ JS_STATICS = [{
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js", "url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ==" "integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
}, { }, {
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.min.js", "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js",
"integrity": "sha512-WW8/jxkELe2CAiE4LvQfwm1rajOS8PHasCCx+knHG0gBHt8EXxS6T6tJRTGuDQVnluuAvMxWF4j8SNFDKceLFg==" "integrity": "sha512-ykZ1QQr0Jy/4ZkvKuqWn4iF3lqPZyij9iRv6sGqLRdTPkY69YX6+7wvVGmsdBbiIfN/8OdsI7HABjvEok6ZopQ=="
}] }]

View File

@@ -4,7 +4,7 @@ from django.apps import AppConfig
class DarklyThemeConfig(AppConfig): class DarklyThemeConfig(AppConfig):
name = "allianceauth.theme.darkly" name = "allianceauth.theme.darkly"
label = "darkly" label = "darkly"
version = "5.3.0" version = "5.3.3"
verbose_name = f"Bootswatch Darkly v{version}" verbose_name = f"Bootswatch Darkly v{version}"
def ready(self): def ready(self):

View File

@@ -14,15 +14,15 @@ class DarklyThemeHook(ThemeHook):
"Darkly", "Darkly",
"Flatly in night mode!", "Flatly in night mode!",
css=[{ css=[{
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.2.3/darkly/bootstrap.min.css", "url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.3/darkly/bootstrap.min.css",
"integrity": "sha512-YRcmztDXzJQCCBk2YUiEAY+r74gu/c9UULMPTeLsAp/Tw5eXiGkYMPC4tc4Kp1jx/V9xjEOCVpBe4r6Lx6n5dA==" "integrity": "sha512-HDszXqSUU0om4Yj5dZOUNmtwXGWDa5ppESlX98yzbBS+z+3HQ8a/7kcdI1dv+jKq+1V5b01eYurE7+yFjw6Rdg=="
}], }],
js=[{ js=[{
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js", "url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ==" "integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
}, { }, {
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/js/bootstrap.min.js", "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js",
"integrity": "sha512-1/RvZTcCDEUjY/CypiMz+iqqtaoQfAITmNSJY17Myp4Ms5mdxPS5UV7iOfdZoxcGhzFbOm6sntTKJppjvuhg4g==" "integrity": "sha512-ykZ1QQr0Jy/4ZkvKuqWn4iF3lqPZyij9iRv6sGqLRdTPkY69YX6+7wvVGmsdBbiIfN/8OdsI7HABjvEok6ZopQ=="
}], }],
header_padding="4.5em" header_padding="4.5em"
) )

View File

@@ -4,7 +4,7 @@ from django.apps import AppConfig
class FlatlyThemeConfig(AppConfig): class FlatlyThemeConfig(AppConfig):
name = "allianceauth.theme.flatly" name = "allianceauth.theme.flatly"
label = "flatly" label = "flatly"
version = "5.3.0" version = "5.3.3"
verbose_name = f"Bootswatch Flatly v{version}" verbose_name = f"Bootswatch Flatly v{version}"
def ready(self): def ready(self):

View File

@@ -14,15 +14,15 @@ class FlatlyThemeHook(ThemeHook):
"Flatly", "Flatly",
"Flat and modern!", "Flat and modern!",
css=[{ css=[{
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.2/flatly/bootstrap.min.css", "url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.3/flatly/bootstrap.min.css",
"integrity": "sha512-rx+BMEjKes84XHg1erhvtq7Mqxm/lm6w4WMoCtDAaTMtUzT5iK5hNTu8mc2+yPNSldAX5hheN/ZhtNQjjYy5nA==" "integrity": "sha512-qoT4KwnRpAQ9uczPsw7GunsNmhRnYwSlE2KRCUPRQHSkDuLulCtDXuC2P/P6oqr3M5hoGagUG9pgHDPkD2zCDA=="
}], }],
js=[{ js=[{
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js", "url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ==" "integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
}, { }, {
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.min.js", "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js",
"integrity": "sha512-WW8/jxkELe2CAiE4LvQfwm1rajOS8PHasCCx+knHG0gBHt8EXxS6T6tJRTGuDQVnluuAvMxWF4j8SNFDKceLFg==" "integrity": "sha512-ykZ1QQr0Jy/4ZkvKuqWn4iF3lqPZyij9iRv6sGqLRdTPkY69YX6+7wvVGmsdBbiIfN/8OdsI7HABjvEok6ZopQ=="
}], }],
header_padding="4.5em" header_padding="4.5em"
) )

View File

@@ -4,7 +4,7 @@ from django.apps import AppConfig
class MateriaThemeConfig(AppConfig): class MateriaThemeConfig(AppConfig):
name = "allianceauth.theme.materia" name = "allianceauth.theme.materia"
label = "materia" label = "materia"
version = "5.3.0" version = "5.3.3"
verbose_name = f"Bootswatch Materia v{version}" verbose_name = f"Bootswatch Materia v{version}"
def ready(self): def ready(self):

View File

@@ -14,15 +14,15 @@ class MateriaThemeHook(ThemeHook):
"Materia", "Materia",
"Material is the metaphor", "Material is the metaphor",
css=[{ css=[{
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.2/materia/bootstrap.min.css", "url": "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.3/materia/bootstrap.min.css",
"integrity": "sha512-4+PCWoNUxEeasuW2ipP8Avsr7X/oS61Kz2CLdwS6ZfHt7jLuzAAcIfPlWLg4aGaDNo0GSmTOmM9biaqnmo6P7g==" "integrity": "sha512-2S9Do+uTmZmmJpdmAcOKdUrK/YslcvAuRfIF2ws8+BW9AvZXMRZM+o8Wq+PZrfISD6ZlIaeCWWZAdeprXIoYuQ=="
}], }],
js=[{ js=[{
"url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js", "url": "https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.8/umd/popper.min.js",
"integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ==" "integrity": "sha512-TPh2Oxlg1zp+kz3nFA0C5vVC6leG/6mm1z9+mA81MI5eaUVqasPLO8Cuk4gMF4gUfP5etR73rgU/8PNMsSesoQ=="
}, { }, {
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.min.js", "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js",
"integrity": "sha512-WW8/jxkELe2CAiE4LvQfwm1rajOS8PHasCCx+knHG0gBHt8EXxS6T6tJRTGuDQVnluuAvMxWF4j8SNFDKceLFg==" "integrity": "sha512-ykZ1QQr0Jy/4ZkvKuqWn4iF3lqPZyij9iRv6sGqLRdTPkY69YX6+7wvVGmsdBbiIfN/8OdsI7HABjvEok6ZopQ=="
}], }],
header_padding="5.25em" header_padding="5.25em"
) )

View File

@@ -1,59 +1,59 @@
{% load i18n %} {% load i18n %}
{% load evelinks %} {% load evelinks %}
<div class="col-12 align-self-stretch py-2"> <div class="col-12 mb-3">
<div class="card h-100"> <div class="card h-100">
<div class="card-body"> <div class="card-body">
<h4 class="card-title text-center">{% translate "Upcoming Timers" %}</h4> {% translate "Upcoming Timers" as widget_title %}
<div class="card-body"> {% include "framework/dashboard/widget-title.html" with title=widget_title %}
<div style="height: 300px; overflow-y:auto;">
<table class="table">
<thead>
<tr>
<th class="text-center">{% translate "Details" %}</th>
<th class="text-center">{% translate "Timer" %}</th>
<th class="text-center">{% translate "Type" %}</th>
<th class="text-center">{% translate "System" %}</th>
<th class="text-center">{% translate "Eve Time" %}</th>
</tr>
</thead>
<tbody> <div>
{% for timer in timers %} <table class="table">
<tr> <thead>
<td class="text-center"> <tr>
{{ timer.details }} <th class="text-center">{% translate "Details" %}</th>
</td> <th class="text-center">{% translate "Timer" %}</th>
<td class="text-center"> <th class="text-center">{% translate "Type" %}</th>
{{ timer.get_timer_type_display }} <th class="text-center">{% translate "System" %}</th>
</td> <th class="text-center">{% translate "EVE Time" %}</th>
<td class="text-center" nowrap> </tr>
{% if timer.objective == "Hostile" %} </thead>
<div class="badge bg-danger">
{% translate "Hostile" %} <tbody>
</div> {% for timer in timers %}
{% endif %} <tr>
{% if timer.objective == "Friendly" %} <td class="text-center">
<div class="badge bg-primary"> {{ timer.details }}
{% translate "Friendly" %} </td>
</div> <td class="text-center">
{% endif %} {{ timer.get_timer_type_display }}
{% if timer.objective == "Neutral" %} </td>
<div class="badge bg-default"> <td class="text-center" nowrap>
{% translate "Neutral" %} {% if timer.objective == "Hostile" %}
</div> <div class="badge bg-danger">
{% endif %} {% translate "Hostile" %}
</td> </div>
<td class="text-center"><a href="{{ timer.system|dotlan_solar_system_url }}"> {% endif %}
{{ timer.system }} {{ timer.planet_moon }} {% if timer.objective == "Friendly" %}
</a> <div class="badge bg-primary">
</td> {% translate "Friendly" %}
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td> </div>
</tr> {% endif %}
{% endfor %} {% if timer.objective == "Neutral" %}
</tbody> <div class="badge bg-default">
</table> {% translate "Neutral" %}
</div> </div>
{% endif %}
</td>
<td class="text-center"><a href="{{ timer.system|dotlan_solar_system_url }}">
{{ timer.system }} {{ timer.planet_moon }}
</a>
</td>
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -19,9 +19,9 @@
{% for timer in timers %} {% for timer in timers %}
{% if timer.important == True %} {% if timer.important == True %}
<tr class="danger"> <tr class="bg-danger bg-opacity-25">
{% else %} {% else %}
<tr class="info"> <tr class="bg-info bg-opacity-25">
{% endif %} {% endif %}
<td style="width: 150px;" class="text-center"> <td style="width: 150px;" class="text-center">

View File

@@ -20,6 +20,9 @@ from allianceauth.timerboard.models import Timer
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
TIMER_VIEW_PERMISSION = 'auth.timer_view'
TIMER_MANAGE_PERMISSION = 'auth.timer_management'
class BaseTimerView(LoginRequiredMixin, PermissionRequiredMixin, View): class BaseTimerView(LoginRequiredMixin, PermissionRequiredMixin, View):
pass pass
@@ -27,7 +30,7 @@ class BaseTimerView(LoginRequiredMixin, PermissionRequiredMixin, View):
class TimerView(BaseTimerView): class TimerView(BaseTimerView):
template_name = 'timerboard/view.html' template_name = 'timerboard/view.html'
permission_required = 'auth.timer_view' permission_required = TIMER_VIEW_PERMISSION
def get(self, request): def get(self, request):
logger.debug(f"timer_view called by user {request.user}") logger.debug(f"timer_view called by user {request.user}")
@@ -48,7 +51,7 @@ class TimerView(BaseTimerView):
class TimerManagementView(BaseTimerView): class TimerManagementView(BaseTimerView):
permission_required = 'auth.timer_management' permission_required = TIMER_MANAGE_PERMISSION
index_redirect = 'timerboard:view' index_redirect = 'timerboard:view'
success_url = reverse_lazy(index_redirect) success_url = reverse_lazy(index_redirect)
model = Timer model = Timer
@@ -74,8 +77,13 @@ class AddTimerView(TimerManagementView, AddUpdateMixin, CreateView):
def form_valid(self, form): def form_valid(self, form):
result = super().form_valid(form) result = super().form_valid(form)
timer = self.object timer = self.object
logger.info(f"Created new timer in {timer.system} at {timer.eve_time} by user {self.request.user}") logger.info(
messages.success(self.request, _('Added new timer in %(system)s at %(time)s.') % {"system": timer.system, "time": timer.eve_time}) f"Created new timer in {timer.system} at {timer.eve_time} by user {self.request.user}"
)
messages.success(
self.request,
_('Added new timer in %(system)s at %(time)s.') % {"system": timer.system, "time": timer.eve_time}
)
return result return result
@@ -89,22 +97,33 @@ class EditTimerView(TimerManagementView, AddUpdateMixin, UpdateView):
class RemoveTimerView(TimerManagementView, DeleteView): class RemoveTimerView(TimerManagementView, DeleteView):
form_class = TimerForm pass
def dashboard_timers(request): def dashboard_timers(request):
try: if request.user.has_perm(TIMER_VIEW_PERMISSION):
corp = request.user.profile.main_character.corporation try:
except (EveCorporationInfo.DoesNotExist, AttributeError): corp = request.user.profile.main_character.corporation
return "" except (EveCorporationInfo.DoesNotExist, AttributeError):
return ""
timers = Timer.objects.select_related('eve_character').filter((Q(eve_corp__isnull=True) | Q(eve_corp=corp)) ,eve_time__gte=timezone.now())[:5] timers = Timer.objects.select_related(
'eve_character'
).filter(
(Q(corp_timer=True) & Q(eve_corp=corp)) | Q(corp_timer=False),
eve_time__gte=timezone.now()
)[:5]
if timers.count(): if timers.count():
context = { context = {
'timers': timers, 'timers': timers,
} }
return render_to_string(template_name='timerboard/dashboard.timers.html', context=context, request=request) return render_to_string(
template_name='timerboard/dashboard.timers.html',
context=context, request=request
)
else:
return ""
else: else:
return "" return ""

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.0.0b2 AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v4.2.0
# 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.0.0b2 ARG AUTH_VERSION=v4.2.0
ARG AUTH_PACKAGE=allianceauth==${AUTH_VERSION} ARG AUTH_PACKAGE=allianceauth==${AUTH_VERSION}
ENV AUTH_USER=allianceauth ENV AUTH_USER=allianceauth
ENV AUTH_GROUP=allianceauth ENV AUTH_GROUP=allianceauth
@@ -9,21 +9,21 @@ ENV AUTH_HOME=/home/allianceauth
# Setup user and directory permissions # Setup user and directory permissions
SHELL ["/bin/bash", "-c"] SHELL ["/bin/bash", "-c"]
RUN groupadd -g 61000 ${AUTH_GROUP} RUN groupadd -g 61000 ${AUTH_GROUP} && \
RUN useradd -g 61000 -l -M -s /bin/false -u 61000 ${AUTH_USER} useradd -g 61000 -l -m -s /bin/false -u 61000 ${AUTH_USER}
RUN mkdir -p ${STATIC_BASE} \
&& chown ${AUTH_USERGROUP} ${STATIC_BASE} \
&& mkdir -p ${AUTH_HOME} \
&& chown ${AUTH_USERGROUP} ${AUTH_HOME}
# Install build dependencies RUN mkdir -p ${STATIC_BASE}/myauth/static \
RUN apt-get update && apt-get upgrade -y && apt-get install -y \ && chown ${AUTH_USERGROUP} ${STATIC_BASE}/myauth/static
libmariadb-dev gcc git pkg-config
# Install python dependencies # Install Build Dependencies
RUN pip install --upgrade pip RUN apt-get update \
RUN pip install wheel gunicorn && apt-get upgrade -y \
RUN pip install ${AUTH_PACKAGE} && apt-get install -y --no-install-recommends libmariadb-dev gcc git pkg-config \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install AA and Dependencies
RUN pip install --no-cache-dir ${AUTH_PACKAGE} gunicorn
# Switch to non-root user # Switch to non-root user
USER ${AUTH_USER} USER ${AUTH_USER}
@@ -33,7 +33,6 @@ WORKDIR ${AUTH_HOME}
RUN allianceauth start myauth RUN allianceauth start myauth
COPY /allianceauth/project_template/project_name/settings/local.py ${AUTH_HOME}/myauth/myauth/settings/local.py COPY /allianceauth/project_template/project_name/settings/local.py ${AUTH_HOME}/myauth/myauth/settings/local.py
RUN allianceauth update myauth RUN allianceauth update myauth
RUN mkdir -p ${STATIC_BASE}/myauth/static
RUN echo 'alias auth="python $AUTH_HOME/myauth/manage.py"' >> ~/.bashrc && \ RUN echo 'alias auth="python $AUTH_HOME/myauth/manage.py"' >> ~/.bashrc && \
source ~/.bashrc source ~/.bashrc

View File

@@ -1,20 +1,28 @@
server { events {}
listen 80; http {
location = /favicon.ico { access_log off; log_not_found off; } include mime.types;
location /static { default_type application/octet-stream;
alias /var/www/myauth/static;
autoindex off;
}
location /robots.txt { sendfile on;
alias /var/www/myauth/static/robots.txt;
}
location / { server {
proxy_pass http://allianceauth_gunicorn:8000; listen 80;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location = /favicon.ico { access_log off; log_not_found off; }
proxy_set_header Host $host; location /static {
proxy_set_header X-Real-IP $remote_addr; alias /var/www/myauth/static;
proxy_redirect off; autoindex off;
}
location /robots.txt {
alias /var/www/myauth/static/robots.txt;
}
location / {
proxy_pass http://allianceauth_gunicorn:8000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
}
} }
} }

View File

@@ -1,6 +1,8 @@
ARG AA_DOCKER_TAG ARG AA_DOCKER_TAG
FROM $AA_DOCKER_TAG FROM $AA_DOCKER_TAG
RUN cd /home/allianceauth WORKDIR ${AUTH_HOME}
COPY /conf/requirements.txt requirements.txt COPY /conf/requirements.txt requirements.txt
RUN pip install -r requirements.txt RUN --mount=type=cache,target=~/.cache \
pip install -r requirements.txt

View File

@@ -62,10 +62,10 @@ services:
max-file: "5" max-file: "5"
nginx: nginx:
image: nginx:1.25 image: nginx:stable
restart: always restart: always
volumes: volumes:
- ./conf/nginx.conf:/etc/nginx/conf.d/default.conf - ./conf/nginx.conf:/etc/nginx/nginx.conf
- static-volume:/var/www/myauth/static - static-volume:/var/www/myauth/static
depends_on: depends_on:
- allianceauth_gunicorn - allianceauth_gunicorn

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -24,8 +24,13 @@
color: aliceblue; color: aliceblue;
} }
.method dt, .class dt, .data dt, .attribute dt, .function dt, .method dt,
.descclassname, .descname { .class dt,
.data dt,
.attribute dt,
.function dt,
.descclassname,
.descname {
background-color: #525252 !important; background-color: #525252 !important;
color: white !important; color: white !important;
} }
@@ -51,11 +56,13 @@
background-color: #2b2b2b !important; background-color: #2b2b2b !important;
} }
.xref, .py-meth { .xref,
.py-meth {
color: #7ec3e6 !important; color: #7ec3e6 !important;
} }
.admonition, .note { .admonition,
.note {
background-color: #2d2d2d !important; background-color: #2d2d2d !important;
} }
@@ -64,19 +71,27 @@
border-bottom: 1px solid #fcfcfc; border-bottom: 1px solid #fcfcfc;
} }
.wy-table thead, .rst-content table.docutils thead, .rst-content table.field-list thead { .wy-table thead,
.rst-content table.docutils thead,
.rst-content table.field-list thead {
background-color: #b9b9b9; background-color: #b9b9b9;
} }
.wy-table thead th, .rst-content table.docutils thead th, .rst-content table.field-list thead th { .wy-table thead th,
.rst-content table.docutils thead th,
.rst-content table.field-list thead th {
border: solid 2px #e1e4e5; border: solid 2px #e1e4e5;
} }
.wy-table thead p, .rst-content table.docutils thead p, .rst-content table.field-list thead p { .wy-table thead p,
.rst-content table.docutils thead p,
.rst-content table.field-list thead p {
margin: 0; margin: 0;
} }
.wy-table-odd td, .wy-table-striped tr:nth-child(2n-1) td, .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td { .wy-table-odd td,
.wy-table-striped tr:nth-child(2n-1) td,
.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
background-color: #343131; background-color: #343131;
} }
@@ -91,10 +106,6 @@
/* Name.Variable */ /* Name.Variable */
body {
text-align: justify;
}
.rst-content .section .admonition ul { .rst-content .section .admonition ul {
margin-bottom: 0; margin-bottom: 0;
} }

View File

@@ -36,7 +36,7 @@ from allianceauth.framework.api.evecharacter import get_user_from_evecharacter
user = get_user_from_evecharacter(character=my_evecharacter) user = get_user_from_evecharacter(character=my_evecharacter)
``` ```
Now, `user` is a `User` object, or the sentinel username (see [get_sentinel_user](#get-sentinel-user)) Now, `user` is a `User` object, or the sentinel username (see [get_sentinel_user](#get_sentinel_user))
if the `EveCharacter` has no user. if the `EveCharacter` has no user.
## User API ## User API
@@ -88,7 +88,7 @@ main_character = get_main_character_name_from_user(user=my_user)
Now, `main_character` is a `string` containing the user's main character name. Now, `main_character` is a `string` containing the user's main character name.
If the user has no main character, the username will be returned. If the user is `None`, If the user has no main character, the username will be returned. If the user is `None`,
the sentinel username (see [get_sentinel_user](#get-sentinel-user)) will be returned. the sentinel username (see [get_sentinel_user](#get_sentinel_user)) will be returned.
### get_sentinel_user ### get_sentinel_user

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. These bundles include DataTables CSS and JS, jQuery Datepicker CSS and JS, jQueryUI CSS and JS, and more.
A full list of bundles we provide can be found here: https://gitlab.com/allianceauth/allianceauth/-/tree/master/allianceauth/templates/bundles A full list of bundles we provide can be found here: <https://gitlab.com/allianceauth/allianceauth/-/tree/master/allianceauth/templates/bundles>
To use a bundle, you can use the following code in your template (Example for jQueryUI): To use a bundle, you can use the following code in your template (Example for jQueryUI):
@@ -28,6 +28,27 @@ To ensure a unified style language throughout Alliance Auth and Community Apps,
we also provide a couple of template partials. This collection is bound to grow over we also provide a couple of template partials. This collection is bound to grow over
time, so best have an eye on this page. time, so best have an eye on this page.
### Dashboard Widget Title
To ensure the dashboard widgets have a unified style, we provide a template partial for the widget title.
To use it, you can use the following code in your dashboard widget template:
```django
<div id="my-app-dashboard-widget" class="col-12 mb-3">
<div class="card">
<div class="card-body">
{% translate "My Widget Title" as widget_title %}
{% include "framework/dashboard/widget-title.html" with title=widget_title %}
<div>
<p>My widget content</p>
</div>
</div>
</div>
</div>
```
### Page Header ### Page Header
On some pages you want to have a page header. To make this easier, we provide a template partial for this. On some pages you want to have a page header. To make this easier, we provide a template partial for this.
@@ -38,7 +59,8 @@ To use it, you can use the following code in your template:
{% block content %} {% block content %}
<div> <div>
{% translate "My Page Header" as page_header %} {% translate "My Page Header" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %} {% translate "My Page Header Subtitle" as optional_subtitle %}
{% include "framework/header/page-header.html" with title=page_header subtitle=optional_subtitle %}
<p>My page content</p> <p>My page content</p>
</div> </div>

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. All of your apps defined urlpatterns will then be included in the `URLconf` when the core application starts.
#### self.service_ctrl_template
This is provided as a courtesy and defines the default template to be used with [render_service_ctrl](#render_service_ctrl). You are free to redefine or not use this variable at all.
#### title #### title
This is a property which provides a user-friendly display of your service's name. It will usually do a reasonably good job unless your service name has punctuation or odd capitalization. If this is the case, you should override this method and return a string. This is a property which provides a user-friendly display of your service's name. It will usually do a reasonably good job unless your service name has punctuation or odd capitalization. If this is the case, you should override this method and return a string.
@@ -134,7 +130,7 @@ This is a property which provides a user-friendly display of your service's name
#### self.service_ctrl_template #### self.service_ctrl_template
This is provided as a courtesy and defines the default template to be used with [render_service_ctrl](#render-service-ctrl). You are free to redefine or not use this variable at all. This is provided as a courtesy and defines the default template to be used with [render_service_ctrl](#render_service_ctrl). You are free to redefine or not use this variable at all.
#### delete_user #### delete_user

View File

@@ -18,6 +18,8 @@ The `MenuItemHook` class specifies some parameters/instance variables required f
:undoc-members: :undoc-members:
``` ```
## Parameters
### text ### text
The text shown as menu item, e.g., usually the name of the app. The text shown as menu item, e.g., usually the name of the app.

View File

@@ -12,6 +12,8 @@ def register_urls():
return UrlHook(app_name.urls, 'app_name', r^'app_name/') return UrlHook(app_name.urls, 'app_name', r^'app_name/')
``` ```
### Parameters
#### urls #### urls
The urls module to include. See [the Django docs](https://docs.djangoproject.com/en/dev/topics/http/urls/#example) for designing urlpatterns. The urls module to include. See [the Django docs](https://docs.djangoproject.com/en/dev/topics/http/urls/#example) for designing urlpatterns.

View File

@@ -50,6 +50,7 @@ Update your auth project's settings file, inputting the server ID as `DISCORD_GU
:::{note} :::{note}
If you already have a Discord server, skip the creation step, but be sure to retrieve the server ID If you already have a Discord server, skip the creation step, but be sure to retrieve the server ID
::: :::
### Registering an Application ### Registering an Application
Navigate to the [Discord Developers site.](https://discord.com/developers/applications/me) Press the plus sign to create a new application. Navigate to the [Discord Developers site.](https://discord.com/developers/applications/me) Press the plus sign to create a new application.
@@ -112,6 +113,7 @@ Role names on Discord are case-sensitive, while reserved group names on Auth are
.. seealso:: .. seealso::
For more information see :ref:`ref-reserved-group-names`. For more information see :ref:`ref-reserved-group-names`.
``` ```
## Tasks ## Tasks
The Discord service contains a number of tasks that can be run to manually perform updates to all users. The Discord service contains a number of tasks that can be run to manually perform updates to all users.
@@ -132,6 +134,7 @@ Name Description
`update_all` Update groups, nicknames, usernames of all users `update_all` Update groups, nicknames, usernames of all users
======================== ==================================================== ======================== ====================================================
``` ```
:::{note} :::{note}
Depending on how many users you have, running these tasks can take considerable time to finish. You can calculate roughly 1 sec per user for all tasks, except update_all, which needs roughly 3 secs per user. Depending on how many users you have, running these tasks can take considerable time to finish. You can calculate roughly 1 sec per user for all tasks, except update_all, which needs roughly 3 secs per user.
::: :::
@@ -156,6 +159,7 @@ Name Description
`DISCORD_TASKS_MAX_RETRIES` max retries of tasks after an error occurred `3` `DISCORD_TASKS_MAX_RETRIES` max retries of tasks after an error occurred `3`
=================================== ============================================================================================= ======= =================================== ============================================================================================= =======
``` ```
## Permissions ## Permissions
To use this service, users will require some of the following. To use this service, users will require some of the following.
@@ -167,6 +171,7 @@ To use this service, users will require some of the following.
| discord.access_discord | None | Can Access the Discord Service | | discord.access_discord | None | Can Access the Discord Service |
+---------------------------------------+------------------+--------------------------------------------------------------------------+ +---------------------------------------+------------------+--------------------------------------------------------------------------+
``` ```
## Troubleshooting ## Troubleshooting
### "Unknown Error" on Discord site when activating service ### "Unknown Error" on Discord site when activating service

View File

@@ -10,10 +10,13 @@
discord discord
discourse discourse
mumble mumble
mumble-docker
openfire openfire
openfire-docker
phpbb3 phpbb3
smf smf
teamspeak3 teamspeak3
teamspeak3-docker
xenforo xenforo
::: :::

View File

@@ -0,0 +1,207 @@
# Mumble
An alternate install guide for Mumble using Docker, better suited to an Alliance Auth Docker install
Mumble is a free voice chat server. While not as flashy as TeamSpeak, it has all the functionality and is easier to customize. And is better. I may be slightly biased.
## Configuring Auth
In your auth project's settings file (`aa-docker/conf/local.py`), do the following:
- Add `'allianceauth.services.modules.mumble',` to your `INSTALLED_APPS` list
- Append the following to your auth project's settings file:
```python
# Mumble Configuration
MUMBLE_URL = "mumble.example.com"
```
Add the following lines to your `.env` file
```env
# Mumble
MUMBLE_SUPERUSER_PASSWORD = superuser_password
MUMBLE_ICESECRETWRITE = icesecretwrite
MUMBLE_SERVERPASSWORD = serverpassword
```
Finally, restart your stack and run migrations
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
```
## Docker Installations
### Installing Mumble and Authenticator
Inside your `aa-docker` directory, clone the authenticator to a sub directory as follows
```shell
git clone https://gitlab.com/allianceauth/mumble-authenticator.git
```
Add the following to your `docker-compose.yml` under the `services:` section
```docker
mumble-server:
image: mumblevoip/mumble-server:latest
restart: always
environment:
- MUMBLE_SUPERUSER_PASSWORD=${MUMBLE_SUPERUSER_PASSWORD}
- MUMBLE_CONFIG_ice="tcp -h 127.0.0.1 -p 6502"
- MUMBLE_CONFIG_icesecretwrite=${MUMBLE_ICESECRETWRITE}
- MUMBLE_CONFIG_serverpassword=${MUMBLE_SERVERPASSWORD}
- MUMBLE_CONFIG_opusthreshold=0
- MUMBLE_CONFIG_suggestPushToTalk=true
- MUMBLE_CONFIG_suggestVersion=1.4.0
ports:
- 64738:64738
- 64738:64738/udp
logging:
driver: "json-file"
options:
max-size: "10Mb"
max-file: "5"
mumble-authenticator:
build:
context: .
dockerfile: ./mumble-authenticator/Dockerfile
restart: always
volumes:
- ./mumble-authenticator/authenticator.py:/authenticator.py
- ./mumble-authenticator/authenticator.ini.docker:/authenticator.ini
environment:
- MUMBLE_SUPERUSER_PASSWORD=${MUMBLE_SUPERUSER_PASSWORD}
- MUMBLE_CONFIG_ice="tcp -h 127.0.0.1 -p 6502"
- MUMBLE_CONFIG_icesecretwrite=${MUMBLE_ICESECRETWRITE}
- MUMBLE_CONFIG_serverpassword=${MUMBLE_SERVERPASSWORD}
depends_on:
- mumble-server
- auth_mysql
logging:
driver: "json-file"
options:
max-size: "10Mb"
max-file: "5"
```
## Permissions
To use this service, users will require some of the following.
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+
| mumble.access_mumble | None | Can Access the Mumble Service |
+---------------------------------------+------------------+--------------------------------------------------------------------------+
```
## ACL configuration
On a freshly installed mumble server only your superuser has the right to configure ACLs and create channels. The credentials for logging in with your superuser are:
- user: `SuperUser`
- password: *what you defined when configuring your mumble server*
## Optimizing a Mumble Server
The needs and available resources will vary between Alliance Auth installations. Consider yours when applying these settings.
### Bandwidth
<https://wiki.mumble.info/wiki/Murmur.ini#bandwidth>
This is likely the most important setting for scaling a Mumble install, The default maximum Bandwidth is 72000bps Per User. Reducing this value will cause your clients to automatically scale back their bandwidth transmitted, while causing a reduction in voice quality. A value thats still high may cause robotic voices or users with bad connections to drop due entirely due to network load.
Please tune this value to your individual needs, the below scale may provide a rough starting point.
72000 - Superior voice quality - Less than 50 users.
54000 - No noticeable reduction in quality - 50+ Users or many channels with active audio.
36000 - Mild reduction in quality - 100+ Users
30000 - Noticeable reduction in quality but not function - 250+ Users
### Forcing Opus
<https://wiki.mumble.info/wiki/Murmur.ini#opusthreshold>
A Mumble server by default, will fall back to the older CELT codec as soon as a single user connects with an old client. This will significantly reduce your audio quality and likely place higher load on your server. We *highly* reccommend setting this to Zero, to force OPUS to be used at all times. Be aware any users with Mumble clients prior to 1.2.4 (From 2013...) Will not hear any audio.
Our default config sets this as follows
```docker
mumble-authenticator:
environment:
`MUMBLE_CONFIG_opusthreshold=0`
```
### AutoBan and Rate Limiting
<https://wiki.mumble.info/wiki/Murmur.ini#autobanAttempts.2C_autobanTimeframe_and_autobanTime>
The AutoBan feature has some sensible settings by default, You may wish to tune these if your users keep locking themselves out by opening two clients by mistake, or if you are receiving unwanted attention
<https://wiki.mumble.info/wiki/Murmur.ini#messagelimit_and_messageburst>
This too, is set to a sensible configuration by default. Take note on upgrading older installs, as this may actually be set too restrictively and will rate-limit your admins accidentally, take note of the configuration in <https://github.com/mumble-voip/mumble/blob/master/scripts/murmur.ini#L156>
```docker
mumble-authenticator:
environment:
MUMBLE_CONFIG_messagelimit=
MUMBLE_CONFIG_messageburst=
MUMBLE_CONFIG_autobanAttempts=10
MUMBLE_CONFIG_autobanTimeframe=120
MUMBLE_CONFIG_autobanTime=30
MUMBLE_CONFIG_autobanSuccessfulConnections=false
```
### "Suggest" Options
There is no way to force your users to update their clients or use Push to Talk, but these options will throw an error into their Mumble Client.
<https://wiki.mumble.info/wiki/Murmur.ini#Miscellany>
We suggest using Mumble 1.4.0+ for your server and Clients, you can tune this to the latest Patch version.
If Push to Talk is to your tastes, configure the suggestion as follows
```docker
mumble-authenticator:
environment:
MUMBLE_CONFIG_suggestVersion=s1.4.287
MUMBLE_CONFIG_suggestPushToTalk=true
```
## General notes
### Server password
With the default Mumble configuration your mumble server is public. Meaning that everyone who has the address can at least connect to it and might also be able join all channels that don't have any permissions set (Depending on your ACL configured for the root channel).
We have changed this behaviour by setting a Server Password by default, to change this password modify `MUMBLE_SERVERPASSWORD` in `.env`.
Restart the container to apply the change.
```shell
docker compose restart mumble-server
```
It is not reccommended to share/use this password, instead use the Mumble Authenticator whenever possible.
As only registered member can join your mumble server. If you still want to allow guests to join you have 2 options.
- Allow the "Guest" state to activate the Mumble service in your Auth instance
- Use [Mumble temporary links](https://github.com/pvyParts/allianceauth-mumble-temp)
### Enabling Avatars in Overlay (V1.0.0+)
Ensure you have an up to date Mumble-Authenticator, this feature was added in V1.0.0
Edit `authenticator.ini` and change (or add for older installs) This code block.
```ini
;If enabled, textures are automatically set as player's EvE avatar for use on overlay.
avatar_enable = True
;Get EvE avatar images from this location. {charid} will be filled in.
ccp_avatar_url = https://images.evetech.net/characters/{charid}/portrait?size=32
```

View File

@@ -9,7 +9,8 @@ Note that this guide assumes that you have installed Auth with the official :doc
:::{warning} :::{warning}
This guide is currently for Ubuntu only. This guide is currently for Ubuntu only.
::: :::
## Installations
## Bare Metal Installations
### Installing Mumble Server ### Installing Mumble Server
@@ -35,7 +36,6 @@ sudo apt-get install python-software-properties mumble-server libqt5sql5-mysql
::: :::
:::: ::::
### Installing Mumble Authenticator ### Installing Mumble Authenticator
Next, we need to download the latest authenticator release from the [authenticator repository](https://gitlab.com/allianceauth/mumble-authenticator). Next, we need to download the latest authenticator release from the [authenticator repository](https://gitlab.com/allianceauth/mumble-authenticator).
@@ -236,7 +236,7 @@ Please tune this value to your individual needs, the below scale may provide a r
### Forcing Opus ### Forcing Opus
<https://wiki.mumble.info/wiki/Murmur.ini#opusthreshold> <https://wiki.mumble.info/wiki/Murmur.ini#opusthreshold>
A Mumble server, by default, will fall back to the older CELT codec as soon as a single user connects with an old client. This will significantly reduce your audio quality and likely place a higher load on your server. We _highly_ reccommend setting this to Zero, to force OPUS to be used at all times. Be aware any users with Mumble clients prior to 1.2.4 (From 2013...) Will not hear any audio. A Mumble server, by default, will fall back to the older CELT codec as soon as a single user connects with an old client. This will significantly reduce your audio quality and likely place a higher load on your server. We *highly* recommend setting this to Zero, to force OPUS to be used at all times. Be aware any users with Mumble clients prior to 1.2.4 (From 2013...) Will not hear any audio.
`opusthreshold=0` `opusthreshold=0`
@@ -255,7 +255,7 @@ There is no way to force your users to update their clients or use Push to Talk,
<https://wiki.mumble.info/wiki/Murmur.ini#Miscellany> <https://wiki.mumble.info/wiki/Murmur.ini#Miscellany>
We suggest using Mumble 1.4.0+ for your server and Clients, you can tune this to the latest Patch version. We suggest using Mumble 1.4.0+ for your server and Clients, you can tune this to the latest Patch version.
`suggestVersion=1.4.230` `suggestVersion=1.4.287`
If Push to Talk is to your tastes, configure the suggestion as follows If Push to Talk is to your tastes, configure the suggestion as follows
`suggestPushToTalk=true` `suggestPushToTalk=true`

View File

@@ -29,6 +29,7 @@ Currently, the following services support custom name formats:
| Xenforo | Username | ``{character_name}`` | | Xenforo | Username | ``{character_name}`` |
+-------------+-----------+-------------------------------------+ +-------------+-----------+-------------------------------------+
``` ```
:::{note} :::{note}
It's important to note here, before we get into what you can do with a name formatter, that before the generated name is passed off to the service to create an account it will be sanitized to remove characters (the letters and numbers etc.) that the service cannot support. This means that, despite what you configured, the service may display something different. It is up to you to test your formatter and understand how your format may be disrupted by a certain services sanitization function. It's important to note here, before we get into what you can do with a name formatter, that before the generated name is passed off to the service to create an account it will be sanitized to remove characters (the letters and numbers etc.) that the service cannot support. This means that, despite what you configured, the service may display something different. It is up to you to test your formatter and understand how your format may be disrupted by a certain services sanitization function.
::: :::

View File

@@ -0,0 +1,180 @@
# Openfire
An alternate install guide for Openfire using Docker, better suited to an Alliance Auth Docker install
Openfire is a Jabber (XMPP) server.
## Configuring Auth
In your auth project's settings file (`aa-docker/conf/local.py`), do the following:
- Add `'allianceauth.services.modules.openfire',` to your `INSTALLED_APPS` list
- Append the following to your auth project's settings file:
```python
# Jabber Configuration
JABBER_URL = SITE_URL
JABBER_PORT = os.environ.get('JABBER_PORT', 5223)
JABBER_SERVER = SITE_URL
OPENFIRE_ADDRESS = SITE_URL
OPENFIRE_SECRET_KEY = os.environ.get('OPENFIRE_SECRET_KEY', '')
BROADCAST_USER = ""
BROADCAST_USER_PASSWORD = os.environ.get('BROADCAST_USER_PASSWORD', '127.0.0.1')
BROADCAST_SERVICE_NAME = "broadcast"
```
Add the following lines to your `.env` file
```env
# Openfire
OPENFIRE_SECRET_KEY = superuser_password
BROADCAST_USER_PASSWORD = icesecretwrite
```
Finally, restart your stack and run migrations
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
```
## Docker Installation
Add the following to your `docker-compose.yml` under the `services:` section
```docker
openfire:
image: nasqueron/openfire:4.7.5
ports:
- "5222:5222/tcp"
- "5223:5223/tcp"
- "7777:7777/tcp"
volumes:
- openfire-data:/var/lib/openfire
depends_on:
- auth_mysql
logging:
driver: "json-file"
options:
max-size: "50Mb"
max-file: "5"
```
### Create Database
We have a Mariadb container already as part of the Alliance Auth stack, enter it and create a database for it.
```shell
docker exec -it auth_mysql
mysql -u root -p $AA_DB_ROOT_PASSWORD
```
```sql
create database alliance_jabber;
grant all privileges on alliance_jabber . * to 'aauth'@'localhost';
exit;
exit
```
### Configure Webserver
In Nginx Proxy Manager `http://yourdomain:81/`, go to `Proxy Hosts`, Click `Add Proxy Host`. You can refer to :doc:`/installation-containerized/docker`
Domain Name: `jabber.yourdomain`
Forward Hostname `openfire`
forward port `9090` for http, `9091` for https
### Web Configuration
The remainder of the setup occurs through Openfires web interface. Navigate to <http://jabber.yourdomain.com>
Select your language, our guide will assume English
Under Server Settings, set the Domain to `jabber.yourdomain.com` replacing it with your actual domain. Dont touch the rest.
Under Database Settings, select `Standard Database Connection`
On the next page, select `MySQL` from the dropdown list and change the following:
- `[server]`: `auth_mysql`
- `[database]`: `alliance_jabber`
- `[user]`: `aauth`
- `[password]`: Your database users password
If Openfire returns with a failed to connect error, re-check these settings. Note the lack of square brackets.
Under Profile Settings, leave `Default` selected.
Create an administrator account. The actual name is irrelevant, just dont lose this login information.
Finally, log in to the console with your admin account.
Edit your auth project's settings file (`aa-docker/conf/local.py`) and enter the values you just set:
- `JABBER_URL` is the pubic address of your jabber server
- `JABBER_PORT` is the port for clients to connect to (usually 5223)
- `JABBER_SERVER` is the name of the jabber server. If you didn't alter it during install it'll usually be your domain (eg `jabber.example.com`)
- `OPENFIRE_ADDRESS` is the web address of Openfire's web interface. Use http:// with port 9090 or https:// with port 9091 if you configure SSL in Openfire and Nginx Proxy Manager
### REST API Setup
Navigate to the `plugins` tab, and then `Available Plugins` on the left navigation bar. Youll need to fetch the list of available plugins by clicking the link.
Once loaded, press the green plus on the right for `REST API`.
Navigate the `Server` tab, `Sever Settings` subtab. At the bottom of the left navigation bar select `REST API`.
Select `Enabled`, and `Secret Key Auth`. Update your auth project's settings with this secret key as `OPENFIRE_SECRET_KEY`.
### Broadcast Plugin Setup
Navigate to the `Users/Groups` tab and select `Create New User` from the left navigation bar.
Pick a username (e.g. `broadcast`) and password for your ping user. Enter these in your auth project's settings file as `BROADCAST_USER` and `BROADCAST_USER_PASSWORD`. Note that `BROADCAST_USER` needs to be in the format `user@example.com` matching your jabber server name. Press `Create User` to save this user.
Broadcasting requires a plugin. Navigate to the `plugins` tab, press the green plus for the `Broadcast` plugin.
Navigate to the `Server` tab, `Server Manager` subtab, and select `System Properties`. Enter the following:
- Name: `plugin.broadcast.disableGroupPermissions`
- Value: `True`
- Do not encrypt this property value
- Name: `plugin.broadcast.allowedUsers`
- Value: `broadcast@example.com`, replacing the domain name with yours
- Do not encrypt this property value
If you have troubles getting broadcasts to work, you can try setting the optional (you will need to add it) `BROADCAST_IGNORE_INVALID_CERT` setting to `True`. This will allow invalid certificates to be used when connecting to the Openfire server to send a broadcast.
### Preparing Auth
Once all settings are entered, run migrations and restart Gunicorn and Celery.
### Group Chat
Channels are available which function like a chat room. Access can be controlled either by password or ACL (not unlike mumble).
Navigate to the `Group Chat` tab and select `Create New Room` from the left navigation bar.
- Room ID is a short, easy-to-type version of the rooms name users will connect to
- Room Name is the full name for the room
- Description is short text describing the rooms purpose
- Set a password if you want password authentication
- Every other setting is optional. Save changes.
Now select your new room. On the left navigation bar, select `Permissions`.
ACL is achieved by assigning groups to each of the three tiers: `Owners`, `Admins` and `Members`. `Outcast` is the blacklist. Youll usually only be assigning groups to the `Member` category.
## Permissions
To use this service, users will require some of the following.
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+
| openfire.access_openfire | None | Can Access the Openfire Service |
+---------------------------------------+------------------+--------------------------------------------------------------------------+
```

View File

@@ -21,7 +21,7 @@ PHPBB3_URL = ''
DATABASES['phpbb3'] = { DATABASES['phpbb3'] = {
'ENGINE': 'django.db.backends.mysql', 'ENGINE': 'django.db.backends.mysql',
'NAME': 'alliance_forum', 'NAME': 'alliance_forum',
'USER': 'allianceserver-phpbb3', 'USER': 'allianceserver',
'PASSWORD': 'password', 'PASSWORD': 'password',
'HOST': '127.0.0.1', 'HOST': '127.0.0.1',
'PORT': '3306', 'PORT': '3306',

View File

@@ -0,0 +1,179 @@
# TeamSpeak 3
## Overview
TeamSpeak3 is the most popular VOIP program for gamers.
But have you considered using Mumble? Not only is it free, but it has features and performance far superior to Teamspeak3.
## Setup
Sticking with TS3? Alright, I tried.
## Configuring Auth
In your auth project's settings file (`aa-docker/conf/local.py`), do the following:
- Add `'allianceauth.services.modules.teamspeak',` to your `INSTALLED_APPS` list
- Append the following to your auth project's settings file:
```python
# Teamspeak3 Configuration
TEAMSPEAK3_SERVER_IP = os.environ.get('TEAMSPEAK3_SERVER_IP', '127.0.0.1')
TEAMSPEAK3_SERVER_PORT = os.environ.get('TEAMSPEAK3_SERVER_PORT', 10011)
TEAMSPEAK3_SERVERQUERY_USER = os.environ.get('TEAMSPEAK3_SERVERQUERY_USER', "serverquery")
TEAMSPEAK3_SERVERQUERY_PASSWORD = os.environ.get('TEAMSPEAK3_SERVERQUERY_PASSWORD', "")
TEAMSPEAK3_VIRTUAL_SERVER = os.environ.get('TEAMSPEAK3_VIRTUAL_SERVER', 1)
TEAMSPEAK3_PUBLIC_URL = SITE_URL
CELERYBEAT_SCHEDULE['run_ts3_group_update'] = {
'task': 'allianceauth.services.modules.teamspeak3.tasks.run_ts3_group_update',"
'schedule': crontab(minute='*/30'),
}
```
Add the following lines to your `.env` file
```env
# Temspeak
TEAMSPEAK3_SERVERQUERY_USER = "serverquery"
TEAMSPEAK3_SERVERQUERY_PASSWORD = ""
```
## Docker Installation
Add the following to your `docker-compose.yml` under the `services:` section
```docker
teamspeak:
image: teamspeak:3.13
restart: always
environment:
TS3SERVER_LICENSE: accept
ports:
- 9987:9987/udp
- 30033:30033
volumes:
- teamspeak-data:/var/ts3server/
logging:
driver: "json-file"
options:
max-size: "10Mb"
max-file: "5"
```
### Update Settings
In (`aa-docker/conf/local.py`), update the following
- `TEAMSPEAK_VIRTUAL_SERVER` is the virtual server ID of the server to be managed - it will only ever not be 1 if your server is hosted by a professional company
- `TEAMSPEAK3_PUBLIC_URL` is the public address of your TeamSpeak server. Do not include any leading http:// or teamspeak://
In your `.env` file, update the following, obtained from the logs of the Teamspeak server initaliztion `docker compose logs teamspeak`
- `TEAMSPEAK3_SERVERQUERY_USER` is `loginname` from the above bash command (usually `serveradmin`)
- `TEAMSPEAK3_SERVERQUERY_PASSWORD` is `password` following the equals in `serveradmin_password=`
Once settings are entered, run migrations and restart your stack
```shell
docker compose --env-file=.env up -d
docker compose exec allianceauth_gunicorn bash
auth migrate
```
### Generate User Account
And now we can generate ourselves a user account. Navigate to the services in Alliance Auth for your user account and press the checkmark for TeamSpeak 3.
Click the URL provided to automatically connect to our server. It will prompt you to redeem the serveradmin token, enter the `token` from startup.
### Groups
Now we need to make groups. AllianceAuth handles groups in teamspeak differently: instead of creating groups it creates an association between groups in TeamSpeak and groups in AllianceAuth. Go ahead and make the groups you want to associate with auth groups, keeping in mind multiple TeamSpeak groups can be associated with a single auth group.
Navigate back to the AllianceAuth admin interface (example.com/admin) and under `Teamspeak3`, select `Auth / TS Groups`.
In the top-right corner click, first click on `Update TS3 Groups` to fetch the newly created server groups from TS3 (this may take a minute to complete). Then click on `Add Auth / TS Group` to link Auth groups with TS3 server groups.
The dropdown box provides all auth groups. Select one and assign TeamSpeak groups from the panels below. If these panels are empty, wait a minute for the database update to run, or see the [troubleshooting section](#ts-group-models-not-populating-on-admin-site) below.
## Troubleshooting
### `Insufficient client permissions (failed on Invalid permission: 0x26)`
Using the advanced permissions editor, ensure the `Guest` group has the permission `Use Privilege Keys to gain permissions` (under `Virtual Server` expand the `Administration` section)
To enable advanced permissions, on your client go to the `Tools` menu, `Application`, and under the `Misc` section, tick `Advanced permission system`
### TS group models not populating on admin site
The method which populates these runs every 30 minutes. To populate manually you start the process from the admin site or from the Django shell.
#### Admin Site
Navigate to the AllianceAuth admin interface and under `Teamspeak3`, select `Auth / TS Groups`.
Then, in the top-right corner click, click on `Update TS3 Groups` to start the process of fetching the server groups from TS3 (this may take a minute to complete).
#### Django Shell
Start a django shell with:
```shell
docker compose exec allianceauth_gunicorn bash
auth shell
```
And execute the update as follows:
```python
from allianceauth.services.modules.teamspeak3.tasks import Teamspeak3Tasks
Teamspeak3Tasks.run_ts3_group_update()
```
Ensure that command does not return an error.
### `2564 access to default group is forbidden`
This usually occurs because auth is trying to remove a user from the `Guest` group (group ID 8). The guest group is only assigned to a user when they have no other groups, unless you have changed the default teamspeak server config.
Teamspeak servers v3.0.13 and up are especially susceptible to this. Ensure the Channel Admin Group is not set to `Guest (8)`. Check by right clicking on the server name, `Edit virtual server`, and in the middle of the panel select the `Misc` tab.
### `TypeError: string indices must be integers, not str`
This error generally means teamspeak returned an error message that went unhandled. The full traceback is required for proper debugging, which the logs do not record. Please check the superuser notifications for this record and get in touch with a developer.
### `3331 flood ban`
This most commonly happens when your teamspeak server is externally hosted. You need to add the auth server IP to the teamspeak serverquery whitelist. This varies by provider.
If you have SSH access to the server hosting it, you need to locate the teamspeak server folder and add the auth server IP on a new line in `query_ip_allowlist.txt` (named `query_ip_whitelist.txt` on older teamspeak versions).
### `520 invalid loginname or password`
The serverquery account login specified in local.py is incorrect. Please verify `TEAMSPEAK3_SERVERQUERY_USER` and `TEAMSPEAK3_SERVERQUERY_PASSWORD`. The [installation section](#update-settings) describes where to get them.
### `2568 insufficient client permissions`
This usually occurs if you've created a separate serverquery user to use with auth. It has not been assigned sufficient permissions to complete all the tasks required of it. The full list of required permissions is not known, so assign liberally.
## Permissions
To use and configure this service, users will require some of the following.
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+
| teamspeak.access_teamspeak | None | Can Access the TeamSpeak Service |
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| teamspeak.add_authts | Can Add Model | None |
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| teamspeak.change_authts | Can Change Model | None |
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| teamspeak.delete_authts | Can Delete Model | None |
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| teamspeak.view_authts | Can View Model | None |
+---------------------------------------+------------------+--------------------------------------------------------------------------+
```

View File

@@ -8,13 +8,17 @@ You should have the following available on the system you are using to set this
* git * git
* curl * curl
:::{hint}
If at any point `docker compose` does not work, but `docker-compose` does, you have an older version of Docker (and Compose), please update before continuing. Be cautious of these two commands and any suggestions copy and pasted from the internet
:::
## Setup Guide ## Setup Guide
1. run `bash <(curl -s https://gitlab.com/allianceauth/allianceauth/-/raw/master/docker/scripts/download.sh)`. This will download all the files you need to install Alliance Auth and place them in a directory named `aa-docker`. Feel free to rename/move this folder. 1. run `bash <(curl -s https://gitlab.com/allianceauth/allianceauth/-/raw/master/docker/scripts/download.sh)`. This will download all the files you need to install Alliance Auth and place them in a directory named `aa-docker`. Feel free to rename/move this folder.
1. run `./scripts/prepare-env.sh` to set up your environment 1. run `./scripts/prepare-env.sh` to set up your environment
1. (optional) Change `PROTOCOL` to `http://` if not using SSL in `.env` 1. (optional) Change `PROTOCOL` to `http://` if not using SSL in `.env`
1. run `docker-compose --env-file=.env up -d` (NOTE: if this command hangs, follow the instructions [here](https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged)) 1. run `docker compose --env-file=.env up -d` (NOTE: if this command hangs, follow the instructions [here](https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged))
1. run `docker-compose exec allianceauth bash` to open up a terminal inside your auth container 1. run `docker compose exec allianceauth_gunicorn bash` to open up a terminal inside an auth container
1. run `auth migrate` 1. run `auth migrate`
1. run `auth collectstatic` 1. run `auth collectstatic`
1. run `auth createsuperuser` 1. run `auth createsuperuser`
@@ -24,7 +28,7 @@ You should have the following available on the system you are using to set this
1. click "Add Proxy Host", with the following settings for auth. The example uses `auth.localhost` for the domain, but you'll want to use whatever address you have auth configured on 1. click "Add Proxy Host", with the following settings for auth. The example uses `auth.localhost` for the domain, but you'll want to use whatever address you have auth configured on
![nginx-host](/_static/images/installation/docker/nginx-host.png) ![nginx-host](/_static/images/installation/docker/nginx-host.png)
1. click "Add Proxy Host", with the following settings for grafana. The example uses `grafana.localhost` for the domain 1. click "Add Proxy Host", with the following settings for grafana. The example uses `grafana.localhost` for the domain
![grafana-host](/_static/images/installation/docker/grafana-host.png)) ![grafana-host](/_static/images/installation/docker/grafana-host.png)
Congrats! You should now see auth running at <http://auth.yourdomain> and grafana at <http://grafana.yourdomain>! Congrats! You should now see auth running at <http://auth.yourdomain> and grafana at <http://grafana.yourdomain>!
@@ -46,7 +50,7 @@ That's it! You should now be able to access your auth install at <https://auth.y
There are a handful of ways to add packages: There are a handful of ways to add packages:
* Running `pip install` in the container * Running `pip install` in the containers
* Modifying the container's initial command to install packages * Modifying the container's initial command to install packages
* Building a custom Docker image (recommended, and less scary than it sounds!) * Building a custom Docker image (recommended, and less scary than it sounds!)
@@ -54,10 +58,26 @@ There are a handful of ways to add packages:
Using a custom docker image is the preferred approach, as it gives you the stability of packages only changing when you tell them to, along with packages not having to be downloaded every time your container restarts Using a custom docker image is the preferred approach, as it gives you the stability of packages only changing when you tell them to, along with packages not having to be downloaded every time your container restarts
1. Add each additional package that you want to install to a single line in `conf/requirements.txt`. It is recommended, but not required, that you include a version number as well. This will keep your packages from magically updating. You can lookup packages on <https://package.wiki>, and copy everything after `pip install` from the top of the page to use the most recent version. It should look something like `allianceauth-signal-pings==0.0.7`. Every entry in this file should be on a separate line 1. Add each additional package that you want to install to a single line in `conf/requirements.txt`. It is recommended, but not required, that you include a version number as well. This will keep your packages from magically updating. You can lookup packages on <https://pypi.org>, and copy from the title at the top of the page to use the most recent version. It should look something like `allianceauth-signal-pings==0.0.7`. Every entry in this file should be on a separate line
1. In `docker-compose.yml`, comment out the `image` line under `allianceauth` (line 36... ish) and uncomment the `build` section 1. Modify `docker-compose.yml`, as follows.
1. run `docker-compose --env-file=.env up -d`, your custom container will be built, and auth will have your new packages. Make sure to follow the package's instructions on config values that go in `local.py` * Comment out the `image` line under `allianceauth`
1. run `docker-compose exec allianceauth_gunicorn bash` to open up a terminal inside your auth container * Uncomment the `build` section
* e.g.
```docker
x-allianceauth-base: &allianceauth-base
# image: ${AA_DOCKER_TAG?err}
build:
context: .
dockerfile: custom.dockerfile
args:
AA_DOCKER_TAG: ${AA_DOCKER_TAG?err}
restart: always
...
```
1. run `docker compose --env-file=.env up -d`, your custom container will be built, and auth will have your new packages. Make sure to follow the package's instructions on config values that go in `local.py`
1. run `docker compose exec allianceauth_gunicorn bash` to open up a terminal inside your auth container
1. run `allianceauth update myauth` 1. run `allianceauth update myauth`
1. run `auth migrate` 1. run `auth migrate`
1. run `auth collectstatic` 1. run `auth collectstatic`
@@ -71,9 +91,9 @@ _NOTE: It is recommended that you put any secret values (API keys, database cred
Whether you're using a custom image or not, the version of auth is dictated by $AA_DOCKER_TAG in your `.env` file. Whether you're using a custom image or not, the version of auth is dictated by $AA_DOCKER_TAG in your `.env` file.
1. To update to a new version of auth, update the version number at the end (or replace the whole value with the tag in the release notes). 1. To update to a new version of auth, update the version number at the end (or replace the whole value with the tag in the release notes).
1. run `docker-compose pull` 1. run `docker compose pull`
1. run `docker-compose --env-file=.env up -d` 1. run `docker compose --env-file=.env up -d`
1. run `docker-compose exec allianceauth bash` to open up a terminal inside your auth container 1. run `docker compose exec allianceauth_gunicorn bash` to open up a terminal inside your auth container
1. run `allianceauth update myauth` 1. run `allianceauth update myauth`
1. run `auth migrate` 1. run `auth migrate`
1. run `auth collectstatic` 1. run `auth collectstatic`
@@ -83,5 +103,5 @@ _NOTE: If you specify a version of allianceauth in your `requirements.txt` in a
### Custom Packages ### Custom Packages
1. Update the versions in your `requirements.txt` file 1. Update the versions in your `requirements.txt` file
1. Run `docker-compose build` 1. Run `docker compose build`
1. Run `docker-compose --env-file=.env up -d` 1. Run `docker compose --env-file=.env up -d`

View File

@@ -10,5 +10,7 @@ There are additional installation steps for activating services and apps that co
:::{toctree} :::{toctree}
:maxdepth: 1 :maxdepth: 1
docker docker
v4_docker_migration
::: :::

View File

@@ -0,0 +1,118 @@
# Migrating your Docker Compose stack from AA V3.x to AA v4.x
Our Docker Compose stack has both changed significantly, and simplified itself drastically depending on your level of familiarity with Docker.
We have Removed our need to run Supervisor inside the container to run the various tasks needed, and split the stack into multiple containers responsible for each task, as well as modernized many elements.
## aa-docker/conf/*
We are bundling a few often customized files along side our AA install for easier modification by users, you will need to download these into aa-docker/conf
```shell
wget https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/conf/celery.py
wget https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/conf/urls.py
wget https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/conf/memory_check.sh
wget https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/conf/redis_healthcheck.sh
```
## Docker Compose
At this point you should take a copy of your docker-compose and take note of any additional volumes or configurations you have, and why.
Take a complete backup of your local.py, docker-compose and SQL database.
`docker compose down`
Replace your conf/nginx.conf with the contents of <https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/conf/nginx.conf>
Replace your docker-compose.yml with the contents of <https://gitlab.com/allianceauth/allianceauth/-/raw/v4.x/docker/docker-compose.yml>
V3.x installs likely used a dedicated database for Nginx Proxy Manager, you can either setup NPM again without a database, or uncomment the sections noted to maintain this configuration
```docker-compose
proxy:
...
# Uncomment this section to use a dedicated database for Nginx Proxy Manager
environment:
DB_MYSQL_HOST: "proxy-db"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
DB_MYSQL_PASSWORD: "${PROXY_MYSQL_PASS?err}"
DB_MYSQL_NAME: "npm"
...
# Uncomment this section to use a dedicated database for Nginx Proxy Manager
proxy-db:
image: 'jc21/mariadb-aria:latest'
restart: always
environment:
MYSQL_ROOT_PASSWORD: "${PROXY_MYSQL_PASS_ROOT?err}"
MYSQL_DATABASE: 'npm'
MYSQL_USER: 'npm'
MYSQL_PASSWORD: "${PROXY_MYSQL_PASS?err}"
ports:
- 3306
volumes:
- proxy-db:/var/lib/mysql
logging:
driver: "json-file"
options:
max-size: "1Mb"
max-file: "5"
```
## .env
You will need to add some entries to your .env file
```env
AA_DB_CHARSET=utf8mb4
GF_SECURITY_ADMIN_USERNAME=admin
```
and
`GF_SECURITY_ADMIN_PASSWORD`
The password field is intentionally not filled so that you create one. You can either use the grafana credentials you have been using, or create a suitably secure password now.
You will also need to update the `AA_DOCKER_TAG` to the version of V4.x you want to install. Either follow the pattern or check <https://gitlab.com/allianceauth/allianceauth/-/releases>
## (Optional) Build Custom Container
If you are using a docker container with a requirements.txt, You will need to reinstate some customizations.
Modify `docker-compose.yml`, as follows.
* Comment out the `image` line under `allianceauth`
* Uncomment the `build` section
* e.g.
```docker
x-allianceauth-base: &allianceauth-base
# image: ${AA_DOCKER_TAG?err}
build:
context: .
dockerfile: custom.dockerfile
args:
AA_DOCKER_TAG: ${AA_DOCKER_TAG?err}
restart: always
...
```
Now build your custom image
```shell
docker compose pull
docker compose build
```
## Bring docker back up, migrate, collect static
```shell
docker compose --env-file=.env up -d --remove-orphans
docker compose exec allianceauth_gunicorn bash
allianceauth update myauth
auth migrate
auth collectstatic --clear
```

View File

@@ -85,9 +85,9 @@ We need to build Python from source
```bash ```bash
cd ~ cd ~
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
tar xvf Python-3.11.5.tgz tar xvf Python-3.11.7.tgz
cd Python-3.11.5/ cd Python-3.11.7/
./configure --enable-optimizations --enable-shared ./configure --enable-optimizations --enable-shared
sudo make altinstall sudo make altinstall
``` ```
@@ -99,9 +99,9 @@ We need to build Python from source
```bash ```bash
cd ~ cd ~
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
tar xvf Python-3.11.5.tgz tar xvf Python-3.11.7.tgz
cd Python-3.11.5/ cd Python-3.11.7/
./configure --enable-optimizations --enable-shared ./configure --enable-optimizations --enable-shared
sudo make altinstall sudo make altinstall
``` ```
@@ -113,9 +113,9 @@ We need to build Python from source
```bash ```bash
cd ~ cd ~
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
tar xvf Python-3.11.5.tgz tar xvf Python-3.11.7.tgz
cd Python-3.11.5/ cd Python-3.11.7/
./configure --enable-optimizations --enable-shared ./configure --enable-optimizations --enable-shared
sudo make altinstall sudo make altinstall
``` ```

View File

@@ -11,21 +11,28 @@ If you're using a small VPS to host services with very limited memory, consider
::::{tabs} ::::{tabs}
:::{group-tab} Ubuntu 2004, 2204 :::{group-tab} Ubuntu 2004, 2204
```shell ```shell
apt-get install apache2 apt-get install apache2
``` ```
::: :::
:::{group-tab} CentOS 7 :::{group-tab} CentOS 7
```shell ```shell
yum install httpd yum install httpd
``` ```
::: :::
:::{group-tab} CentOS Stream 8 :::{group-tab} CentOS Stream 8
```shell ```shell
dnf install httpd dnf install httpd
``` ```
::: :::
:::{group-tab} CentOS Stream 9 :::{group-tab} CentOS Stream 9
```shell ```shell
systemctl enable httpd systemctl enable httpd
systemctl start httpd systemctl start httpd
@@ -36,7 +43,6 @@ systemctl start httpd
CentOS 7, Stream 8, Stream 9 CentOS 7, Stream 8, Stream 9
## Configuration ## Configuration
### Permissions ### Permissions

View File

@@ -15,7 +15,7 @@ To run AA with a newer Python 3 version than your system's default, you need to
To install other Python versions than those included with your distribution, you need to add a new installation repository. Then you can install the specific Python 3 to your system. To install other Python versions than those included with your distribution, you need to add a new installation repository. Then you can install the specific Python 3 to your system.
:::{note} :::{note}
Ubuntu 2204 ships with Python 3.10 already Ubuntu 2204 ships with Python 3.10 already
::: :::
Centos Stream 8/9: Centos Stream 8/9:
@@ -39,9 +39,9 @@ sudo apt-get install python3.11 python3.11-dev python3.11-venv
```bash ```bash
cd ~ cd ~
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
tar xvf Python-3.11.5.tgz tar xvf Python-3.11.7.tgz
cd Python-3.11.5/ cd Python-3.11.7/
./configure --enable-optimizations --enable-shared ./configure --enable-optimizations --enable-shared
sudo make altinstall sudo make altinstall
``` ```
@@ -52,9 +52,9 @@ sudo make altinstall
```bash ```bash
cd ~ cd ~
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
tar xvf Python-3.11.5.tgz tar xvf Python-3.11.7.tgz
cd Python-3.11.5/ cd Python-3.11.7/
./configure --enable-optimizations --enable-shared ./configure --enable-optimizations --enable-shared
sudo make altinstall sudo make altinstall
``` ```
@@ -65,9 +65,9 @@ sudo make altinstall
```bash ```bash
cd ~ cd ~
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz wget https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz
tar xvf Python-3.11.5.tgz tar xvf Python-3.11.7.tgz
cd Python-3.11.5/ cd Python-3.11.7/
./configure --enable-optimizations --enable-shared ./configure --enable-optimizations --enable-shared
sudo make altinstall sudo make altinstall
``` ```

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. To record DEBUG messages in the log file, alter a setting in your auth project's settings file: `LOGGING['handlers']['log_file']['level'] = 'DEBUG'`. After restarting gunicorn and celery, your log file will record all logging messages.
## Steps to Check Logs for Errors
### Locate the Logs
The logs are located within the `myauth/log/` directory of your Alliance Auth project.
### Access the Logs
Use a text editor or terminal commands (like `tail -f <filename>`) to open the relevant log files.
_(The `tail -f` command displays the last few lines of a file and then continues to monitor the file, printing any new lines that are added in real-time. Useful to watch while actively testing a troublesome feature while troubleshooting.)_
Consider the following:
`allianceauth.log` is the primary log for general troubleshooting. Tracks user actions, changes made, and potential errors.
`worker.log` is important for issues related to background tasks.(Such as services(Discord)).
`beat.log` if you suspect scheduler problems.
`gunicorn.log` for web-specific or Gunicorn worker errors.
### Search for Errors
Look for keywords like `ERROR`, `WARNING`, `EXCEPTION`, or `CRITICAL`. Examine timestamps to correlate errors with user actions or events. Read the error messages carefully for clues about the problem's nature.
Troubleshooting Tips:
**Filter Logs:** Use tools like `grep` to filter logs based on keywords or timeframes, making it easier to focus on relevant information.
**Example**: `tail -f worker.log | grep -i 'discord'`. This will isolate lines containing discord. Making it easier to see among the other logs.
**Debug Mode:** For in-depth troubleshooting, temporarily enable DEBUG logging in your `local.py` to get more detailed messages. Remember to set it back to `False` after debugging.
**Important Note: Before sharing logs publicly, sanitize any sensitive information such as usernames, passwords, or API keys.**
## Common Problems ## Common Problems
### I'm getting error 500 when trying to connect to the website on a new installation ### I'm getting error 500 when trying to connect to the website on a new installation
*Great.* Error 500 is the generic message given by your web server when *anything* breaks. The actual error message is hidden in one of your auth project's log files. Read them to identify it. _Great._ Error 500 is the generic message given by your web server when _anything_ breaks. The actual error message is hidden in one of your auth project's log files. Read them to identify it.
### Failed to configure log handler ### Failed to configure log handler

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.

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