mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-07 15:46:20 +01:00
Compare commits
257 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e16252842a | ||
|
|
950ae34093 | ||
|
|
0ba94c53aa | ||
|
|
96cc55d174 | ||
|
|
a9062c4389 | ||
|
|
c602cf0b00 | ||
|
|
3de988369f | ||
|
|
b28b51916c | ||
|
|
0db0978d5f | ||
|
|
0531da1128 | ||
|
|
547d047f59 | ||
|
|
5cd92e29d3 | ||
|
|
bb44194cfc | ||
|
|
aa1cb96c8a | ||
|
|
40ae092306 | ||
|
|
b2e70c3702 | ||
|
|
eebeb26001 | ||
|
|
003a67224e | ||
|
|
d3a3810456 | ||
|
|
f55008559e | ||
|
|
dbc19c76c5 | ||
|
|
ced7972962 | ||
|
|
ad508bd880 | ||
|
|
5c128f2c78 | ||
|
|
1caaca86cf | ||
|
|
33ad1413d5 | ||
|
|
cbb5c80b94 | ||
|
|
d2edd288f9 | ||
|
|
21e80f6961 | ||
|
|
a747951d19 | ||
|
|
4cc7135ace | ||
|
|
6a990c11e6 | ||
|
|
3f47cecbfc | ||
|
|
77c126ea2f | ||
|
|
8b7e57494c | ||
|
|
20fcf5efa4 | ||
|
|
8ff3d854ba | ||
|
|
49ff355d50 | ||
|
|
c15b955d5e | ||
|
|
65e1545a66 | ||
|
|
c558a980e1 | ||
|
|
bd8ef84862 | ||
|
|
6f670da1db | ||
|
|
c558f3785f | ||
|
|
04cdd4c64f | ||
|
|
42e96d2f14 | ||
|
|
00fcebd8e3 | ||
|
|
995c84481c | ||
|
|
4dd42da993 | ||
|
|
8295cc51a3 | ||
|
|
f7e1d7c47e | ||
|
|
234191218a | ||
|
|
de12b49527 | ||
|
|
021b7b2edb | ||
|
|
20b959f273 | ||
|
|
e16bb2a737 | ||
|
|
0a6a6e0bf9 | ||
|
|
f0fe3929d4 | ||
|
|
9a62c729eb | ||
|
|
eaedcd5bb7 | ||
|
|
d742257c74 | ||
|
|
ad92d7a916 | ||
|
|
af22222bdf | ||
|
|
01f49bd125 | ||
|
|
af5930b9d0 | ||
|
|
95ba19a827 | ||
|
|
c75647301f | ||
|
|
adedf7534f | ||
|
|
d0684862fe | ||
|
|
2440e5d2b2 | ||
|
|
5f51ad4a6a | ||
|
|
0bd3acc230 | ||
|
|
11a32c90a8 | ||
|
|
6f0b853a60 | ||
|
|
583a6d4c7f | ||
|
|
155494afea | ||
|
|
b0aa58b910 | ||
|
|
1adce85422 | ||
|
|
cd47eadcdc | ||
|
|
247058a30f | ||
|
|
e0fa615e90 | ||
|
|
61ec67183c | ||
|
|
4369813478 | ||
|
|
8bb3d35252 | ||
|
|
398a980fb5 | ||
|
|
e14a295ce6 | ||
|
|
e0cd5c6fb9 | ||
|
|
c37ece49d5 | ||
|
|
8adab8bae0 | ||
|
|
a9c87bc25a | ||
|
|
a4901802c0 | ||
|
|
079dcc5d28 | ||
|
|
10c5a8906d | ||
|
|
e6306ea7aa | ||
|
|
20067c1133 | ||
|
|
dba3c651dc | ||
|
|
0b4d2b819b | ||
|
|
23a3dd1ab9 | ||
|
|
81e5bc5337 | ||
|
|
7eebf4d953 | ||
|
|
9e45d2eac7 | ||
|
|
e3017f1ec7 | ||
|
|
a8ef844fe7 | ||
|
|
12709b1b56 | ||
|
|
51ae604efd | ||
|
|
63071ec359 | ||
|
|
0032e4a01f | ||
|
|
25ab78a41e | ||
|
|
3aa0e323d2 | ||
|
|
cadbb7e61c | ||
|
|
115263eb5a | ||
|
|
18fec5f614 | ||
|
|
02ab064ec3 | ||
|
|
ba25f99cb4 | ||
|
|
28fd1b07ea | ||
|
|
5de19c43df | ||
|
|
9ce1939040 | ||
|
|
322131cd4f | ||
|
|
55e6e92da5 | ||
|
|
e5d29629a5 | ||
|
|
6a0ddc9a83 | ||
|
|
03be66d11f | ||
|
|
26e187e4c8 | ||
|
|
3480c4e0e8 | ||
|
|
1544f097e0 | ||
|
|
2477c31656 | ||
|
|
0dc631d69e | ||
|
|
2a9981cdb9 | ||
|
|
3d92008069 | ||
|
|
59e47c24c2 | ||
|
|
6d942555ff | ||
|
|
7e312bb95f | ||
|
|
c92fee78e2 | ||
|
|
004c48b8ad | ||
|
|
658a8cd6ce | ||
|
|
c1dc130766 | ||
|
|
35f5573b63 | ||
|
|
4d66b7d456 | ||
|
|
77e5747a23 | ||
|
|
a9ebecdec6 | ||
|
|
21f0a96422 | ||
|
|
9e47d19337 | ||
|
|
2c5972d0ab | ||
|
|
6118c0ddec | ||
|
|
ce25deeca1 | ||
|
|
60084de3db | ||
|
|
e16c68e255 | ||
|
|
bf14e9c7c3 | ||
|
|
98e91fe207 | ||
|
|
ee41d62c13 | ||
|
|
346b4014a9 | ||
|
|
9b56a441ed | ||
|
|
068bf1ae7a | ||
|
|
5be686e3ca | ||
|
|
a215b4411c | ||
|
|
e15cfa0fb1 | ||
|
|
46d51699f4 | ||
|
|
ff30a136d5 | ||
|
|
6dcf3304d5 | ||
|
|
beddeea338 | ||
|
|
69723937f7 | ||
|
|
c541f56ee2 | ||
|
|
7e887e5e34 | ||
|
|
072327c79f | ||
|
|
28af3ff11e | ||
|
|
e3b151f2fb | ||
|
|
f87d7dbdf8 | ||
|
|
a04e6ae3d0 | ||
|
|
15042f5e77 | ||
|
|
6e25361d5e | ||
|
|
9e639a0eeb | ||
|
|
257fbdef36 | ||
|
|
df003c8ec5 | ||
|
|
ba22685eb8 | ||
|
|
773288072a | ||
|
|
63afb13d25 | ||
|
|
5dd286bbe7 | ||
|
|
8aaa8172ca | ||
|
|
b68b401146 | ||
|
|
f7821b647f | ||
|
|
a6526d6f78 | ||
|
|
7898594909 | ||
|
|
cfd12ee3cc | ||
|
|
2c9177b19f | ||
|
|
abff26fb6e | ||
|
|
e8c3b5225c | ||
|
|
98fd1dcc4c | ||
|
|
7024552c4e | ||
|
|
a0719e4b86 | ||
|
|
906c589f14 | ||
|
|
cfe46e4ca5 | ||
|
|
4675193416 | ||
|
|
a84fa1ca69 | ||
|
|
8f6cb0b9bb | ||
|
|
1c8634f1c8 | ||
|
|
2a21599d45 | ||
|
|
ffb526ab0c | ||
|
|
b9d128259e | ||
|
|
13d866bd0d | ||
|
|
e379c01655 | ||
|
|
afa3d2e7cc | ||
|
|
e5ed33aeec | ||
|
|
b12471e775 | ||
|
|
ea1887b9ec | ||
|
|
d2f8c2a42f | ||
|
|
5e70dab11f | ||
|
|
f728c786b3 | ||
|
|
7056912d54 | ||
|
|
7efed950ca | ||
|
|
886acf2005 | ||
|
|
b2dec3bff2 | ||
|
|
f0a402e141 | ||
|
|
2e2afd7923 | ||
|
|
e9ea09bc56 | ||
|
|
186fa1be03 | ||
|
|
37d1d84fc3 | ||
|
|
ee24706e43 | ||
|
|
07e85727ea | ||
|
|
4912f0f8f0 | ||
|
|
424246df26 | ||
|
|
563e2210ef | ||
|
|
02a1078005 | ||
|
|
30107de44e | ||
|
|
200e8f2ff1 | ||
|
|
77a08cd218 | ||
|
|
e5a09027e5 | ||
|
|
24376262f0 | ||
|
|
efe0c6963b | ||
|
|
a4644028ae | ||
|
|
3a77b4a429 | ||
|
|
52b6c5d341 | ||
|
|
fa375a551c | ||
|
|
00a93e6fe9 | ||
|
|
656e69d4b2 | ||
|
|
3b55d370d0 | ||
|
|
5c126ffe82 | ||
|
|
99be753836 | ||
|
|
2e78aa5f26 | ||
|
|
567d97f38a | ||
|
|
d6821b3fd6 | ||
|
|
90375246fd | ||
|
|
a2f217ace5 | ||
|
|
25cf2fdcd5 | ||
|
|
4305ae7995 | ||
|
|
4aff4006e3 | ||
|
|
55c188f2d0 | ||
|
|
f36f824a4b | ||
|
|
6fbf33bcdd | ||
|
|
ed3c2c8529 | ||
|
|
05d7fb1f63 | ||
|
|
3b19db2564 | ||
|
|
98aa44c070 | ||
|
|
8d46ee65af | ||
|
|
49780b871d | ||
|
|
2b7d24fc28 | ||
|
|
b8f86a618f | ||
|
|
9921011742 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -73,3 +73,4 @@ celerybeat-schedule
|
|||||||
.flake8
|
.flake8
|
||||||
.pylintrc
|
.pylintrc
|
||||||
Makefile
|
Makefile
|
||||||
|
alliance_auth.sqlite3
|
||||||
|
|||||||
@@ -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.10-bullseye
|
image: python:3.11-bullseye
|
||||||
variables:
|
variables:
|
||||||
PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
|
PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
|
||||||
cache:
|
cache:
|
||||||
@@ -99,18 +99,17 @@ test-3.11-core:
|
|||||||
coverage_format: cobertura
|
coverage_format: cobertura
|
||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
|
|
||||||
test-pvpy-core:
|
test-3.12-core:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
image: pypy:3.9-bullseye
|
image: python:3.12-rc-bullseye
|
||||||
script:
|
script:
|
||||||
- tox -e pypy-all
|
- tox -e py312-core
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
reports:
|
reports:
|
||||||
coverage_report:
|
coverage_report:
|
||||||
coverage_format: cobertura
|
coverage_format: cobertura
|
||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
test-3.8-all:
|
test-3.8-all:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
@@ -161,22 +160,21 @@ test-3.11-all:
|
|||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
|
coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
|
||||||
|
|
||||||
test-pvpy-all:
|
test-3.12-all:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
image: pypy:3.9-bullseye
|
image: python:3.12-rc-bullseye
|
||||||
script:
|
script:
|
||||||
- tox -e pypy-all
|
- tox -e py312-all
|
||||||
artifacts:
|
artifacts:
|
||||||
when: always
|
when: always
|
||||||
reports:
|
reports:
|
||||||
coverage_report:
|
coverage_report:
|
||||||
coverage_format: cobertura
|
coverage_format: cobertura
|
||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
build-test:
|
build-test:
|
||||||
stage: test
|
stage: test
|
||||||
image: python:3.10-bullseye
|
image: python:3.11-bullseye
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- python -m pip install --upgrade pip
|
- python -m pip install --upgrade pip
|
||||||
@@ -195,13 +193,13 @@ build-test:
|
|||||||
|
|
||||||
test-docs:
|
test-docs:
|
||||||
<<: *only-default
|
<<: *only-default
|
||||||
image: python:3.10-bullseye
|
image: python:3.11-bullseye
|
||||||
script:
|
script:
|
||||||
- tox -e docs
|
- tox -e docs
|
||||||
|
|
||||||
deploy_production:
|
deploy_production:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
image: python:3.10-bullseye
|
image: python:3.11-bullseye
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- python -m pip install --upgrade pip
|
- python -m pip install --upgrade pip
|
||||||
@@ -217,10 +215,10 @@ deploy_production:
|
|||||||
|
|
||||||
build-image:
|
build-image:
|
||||||
before_script: []
|
before_script: []
|
||||||
image: docker:20.10.10
|
image: docker:24.0
|
||||||
stage: docker
|
stage: docker
|
||||||
services:
|
services:
|
||||||
- docker:20.10.10-dind
|
- docker:24.0-dind
|
||||||
script: |
|
script: |
|
||||||
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
||||||
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_COMMIT_SHORT_SHA
|
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_COMMIT_SHORT_SHA
|
||||||
@@ -230,12 +228,10 @@ build-image:
|
|||||||
LATEST_TAG=$CI_REGISTRY_IMAGE/auth:latest
|
LATEST_TAG=$CI_REGISTRY_IMAGE/auth:latest
|
||||||
|
|
||||||
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
docker build . -t $IMAGE_TAG -f docker/Dockerfile --build-arg AUTH_VERSION=$(echo $CI_COMMIT_TAG | cut -c 2-)
|
docker run --privileged --rm tonistiigi/binfmt --uninstall qemu-*
|
||||||
docker tag $IMAGE_TAG $CURRENT_TAG
|
docker run --privileged --rm tonistiigi/binfmt --install all
|
||||||
docker tag $IMAGE_TAG $MINOR_TAG
|
docker buildx create --use --name new-builder
|
||||||
docker tag $IMAGE_TAG $MAJOR_TAG
|
docker buildx build . --tag $IMAGE_TAG --tag $CURRENT_TAG --tag $MINOR_TAG --tag $MAJOR_TAG --tag $LATEST_TAG --file docker/Dockerfile --platform linux/amd64,linux/arm64 --push --build-arg AUTH_VERSION=$(echo $CI_COMMIT_TAG | cut -c 2-)
|
||||||
docker tag $IMAGE_TAG $LATEST_TAG
|
|
||||||
docker image push --all-tags $CI_REGISTRY_IMAGE/auth
|
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_TAG
|
- if: $CI_COMMIT_TAG
|
||||||
when: delayed
|
when: delayed
|
||||||
@@ -243,17 +239,19 @@ build-image:
|
|||||||
|
|
||||||
build-image-dev:
|
build-image-dev:
|
||||||
before_script: []
|
before_script: []
|
||||||
image: docker:20.10.10
|
image: docker:24.0
|
||||||
stage: docker
|
stage: docker
|
||||||
services:
|
services:
|
||||||
- docker:20.10.10-dind
|
- docker:24.0-dind
|
||||||
script: |
|
script: |
|
||||||
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
||||||
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_COMMIT_BRANCH-$CI_COMMIT_SHORT_SHA
|
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_COMMIT_BRANCH-$CI_COMMIT_SHORT_SHA
|
||||||
|
|
||||||
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
docker build . -t $IMAGE_TAG -f docker/Dockerfile --build-arg AUTH_PACKAGE=git+https://gitlab.com/allianceauth/allianceauth@$CI_COMMIT_BRANCH
|
docker run --privileged --rm tonistiigi/binfmt --uninstall qemu-*
|
||||||
docker push $IMAGE_TAG
|
docker run --privileged --rm tonistiigi/binfmt --install all
|
||||||
|
docker buildx create --use --name new-builder
|
||||||
|
docker buildx build . --tag $IMAGE_TAG --file docker/Dockerfile --platform linux/amd64,linux/arm64 --push --build-arg AUTH_PACKAGE=git+https://gitlab.com/allianceauth/allianceauth@$CI_COMMIT_BRANCH
|
||||||
rules:
|
rules:
|
||||||
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == ""'
|
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == ""'
|
||||||
when: manual
|
when: manual
|
||||||
@@ -262,17 +260,19 @@ build-image-dev:
|
|||||||
|
|
||||||
build-image-mr:
|
build-image-mr:
|
||||||
before_script: []
|
before_script: []
|
||||||
image: docker:20.10.10
|
image: docker:24.0
|
||||||
stage: docker
|
stage: docker
|
||||||
services:
|
services:
|
||||||
- docker:20.10.10-dind
|
- docker:24.0-dind
|
||||||
script: |
|
script: |
|
||||||
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
CURRENT_DATE=$(echo $CI_COMMIT_TIMESTAMP | head -c 10 | tr -d -)
|
||||||
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME-$CI_COMMIT_SHORT_SHA
|
IMAGE_TAG=$CI_REGISTRY_IMAGE/auth:$CURRENT_DATE-$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME-$CI_COMMIT_SHORT_SHA
|
||||||
|
|
||||||
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
docker build . -t $IMAGE_TAG -f docker/Dockerfile --build-arg AUTH_PACKAGE=git+$CI_MERGE_REQUEST_SOURCE_PROJECT_URL@$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
|
docker run --privileged --rm tonistiigi/binfmt --uninstall qemu-*
|
||||||
docker push $IMAGE_TAG
|
docker run --privileged --rm tonistiigi/binfmt --install all
|
||||||
|
docker buildx create --use --name new-builder
|
||||||
|
docker buildx build . --tag $IMAGE_TAG --file docker/Dockerfile --platform linux/amd64,linux/arm64 --push --build-arg AUTH_PACKAGE=git+$CI_MERGE_REQUEST_SOURCE_PROJECT_URL@$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
|
||||||
rules:
|
rules:
|
||||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||||
when: manual
|
when: manual
|
||||||
|
|||||||
@@ -66,14 +66,20 @@ repos:
|
|||||||
swagger\.json
|
swagger\.json
|
||||||
)
|
)
|
||||||
|
|
||||||
- repo: https://github.com/adamchainz/django-upgrade
|
|
||||||
rev: 1.14.0
|
|
||||||
hooks:
|
|
||||||
- id: django-upgrade
|
|
||||||
args: [ --target-version=4.0 ]
|
|
||||||
|
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v3.10.1
|
rev: v3.10.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [ --py38-plus ]
|
args: [ --py38-plus ]
|
||||||
|
|
||||||
|
- repo: https://github.com/adamchainz/django-upgrade
|
||||||
|
rev: 1.14.0
|
||||||
|
hooks:
|
||||||
|
- id: django-upgrade
|
||||||
|
args: [--target-version=4.2]
|
||||||
|
|
||||||
|
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||||
|
rev: v2.3.0
|
||||||
|
hooks:
|
||||||
|
- id: setup-cfg-fmt
|
||||||
|
args: [ --include-version-classifiers ]
|
||||||
|
|||||||
@@ -7,11 +7,14 @@ version: 2
|
|||||||
|
|
||||||
# Set the version of Python and other tools you might need
|
# Set the version of Python and other tools you might need
|
||||||
build:
|
build:
|
||||||
os: ubuntu-20.04
|
os: ubuntu-22.04
|
||||||
apt_packages:
|
apt_packages:
|
||||||
- redis
|
- redis
|
||||||
tools:
|
tools:
|
||||||
python: "3.8"
|
python: "3.11"
|
||||||
|
jobs:
|
||||||
|
post_system_dependencies:
|
||||||
|
- redis-server --daemonize yes
|
||||||
|
|
||||||
# Build documentation in the docs/ directory with Sphinx
|
# Build documentation in the docs/ directory with Sphinx
|
||||||
sphinx:
|
sphinx:
|
||||||
@@ -20,7 +23,10 @@ sphinx:
|
|||||||
# Optionally build your docs in additional formats such as PDF and ePub
|
# Optionally build your docs in additional formats such as PDF and ePub
|
||||||
formats: all
|
formats: all
|
||||||
|
|
||||||
# Optionally set the version of Python and requirements required to build your docs
|
# Python requirements required to build your docs
|
||||||
python:
|
python:
|
||||||
install:
|
install:
|
||||||
- requirements: docs/requirements.txt
|
- method: pip
|
||||||
|
path: .
|
||||||
|
extra_requirements:
|
||||||
|
- docs
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[main]
|
[main]
|
||||||
host = https://www.transifex.com
|
host = https://app.transifex.com
|
||||||
lang_map = zh-Hans: zh_Hans
|
lang_map = zh-Hans: zh_Hans
|
||||||
|
|
||||||
[o:alliance-auth:p:alliance-auth:r:django-po]
|
[o:alliance-auth:p:alliance-auth:r:django-po]
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
[main]
|
|
||||||
host = https://www.transifex.com
|
|
||||||
lang_map = zh-Hans:zh_Hans
|
|
||||||
|
|
||||||
[alliance-auth.django-po]
|
|
||||||
file_filter = allianceauth/locale/<lang>/LC_MESSAGES/django.po
|
|
||||||
minimum_perc = 0
|
|
||||||
source_file = allianceauth/locale/en/LC_MESSAGES/django.po
|
|
||||||
source_lang = en
|
|
||||||
type = PO
|
|
||||||
10
.tx/transifex.yml
Normal file
10
.tx/transifex.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
filters:
|
||||||
|
- filter_type: file
|
||||||
|
file_format: PO
|
||||||
|
source_file: allianceauth/locale/en/LC_MESSAGES/django.po
|
||||||
|
source_language: en
|
||||||
|
translation_files_expression: allianceauth/locale/<lang>/LC_MESSAGES/django.po
|
||||||
|
|
||||||
|
settings:
|
||||||
|
language_mapping:
|
||||||
|
zh-Hans: zh_Hans
|
||||||
@@ -17,7 +17,7 @@ An auth system for EVE Online to help in-game organizations manage online servic
|
|||||||
- [Documentation](http://allianceauth.rtfd.io)
|
- [Documentation](http://allianceauth.rtfd.io)
|
||||||
- [Support](#support)
|
- [Support](#support)
|
||||||
- [Release Notes](https://gitlab.com/allianceauth/allianceauth/-/releases)
|
- [Release Notes](https://gitlab.com/allianceauth/allianceauth/-/releases)
|
||||||
- [Developer Team](#developer-team)
|
- [Developer Team](#development-team)
|
||||||
- [Contributing](#contributing)
|
- [Contributing](#contributing)
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|||||||
@@ -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__ = '3.7.0'
|
__version__ = '4.0.0a5'
|
||||||
__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__}'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import AnalyticsIdentifier, AnalyticsPath, AnalyticsTokens
|
from .models import AnalyticsIdentifier, AnalyticsTokens
|
||||||
|
|
||||||
|
|
||||||
@admin.register(AnalyticsIdentifier)
|
@admin.register(AnalyticsIdentifier)
|
||||||
@@ -13,9 +13,3 @@ class AnalyticsIdentifierAdmin(admin.ModelAdmin):
|
|||||||
class AnalyticsTokensAdmin(admin.ModelAdmin):
|
class AnalyticsTokensAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['name', ]
|
search_fields = ['name', ]
|
||||||
list_display = ('name', 'type',)
|
list_display = ('name', 'type',)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(AnalyticsPath)
|
|
||||||
class AnalyticsPathAdmin(admin.ModelAdmin):
|
|
||||||
search_fields = ['ignore_path', ]
|
|
||||||
list_display = ('ignore_path',)
|
|
||||||
|
|||||||
@@ -4,6 +4,3 @@ from django.apps import AppConfig
|
|||||||
class AnalyticsConfig(AppConfig):
|
class AnalyticsConfig(AppConfig):
|
||||||
name = 'allianceauth.analytics'
|
name = 'allianceauth.analytics'
|
||||||
label = 'analytics'
|
label = 'analytics'
|
||||||
|
|
||||||
def ready(self):
|
|
||||||
import allianceauth.analytics.signals
|
|
||||||
|
|||||||
@@ -3,11 +3,10 @@
|
|||||||
"model": "analytics.AnalyticsTokens",
|
"model": "analytics.AnalyticsTokens",
|
||||||
"pk": 1,
|
"pk": 1,
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "AA Team Public Google Analytics (Universal)",
|
"name": "AA Team Public Google Analytics (V4)",
|
||||||
"type": "GA-V4",
|
"type": "GA-V4",
|
||||||
"token": "UA-186249766-2",
|
"token": "G-6LYSMYK8DE",
|
||||||
"send_page_views": "False",
|
"secret": "KLlpjLZ-SRGozS5f5wb_kw",
|
||||||
"send_celery_tasks": "False",
|
|
||||||
"send_stats": "False"
|
"send_stats": "False"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
from bs4 import BeautifulSoup
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.utils.deprecation import MiddlewareMixin
|
|
||||||
from .models import AnalyticsTokens, AnalyticsIdentifier
|
|
||||||
from .tasks import send_ga_tracking_web_view
|
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
class AnalyticsMiddleware(MiddlewareMixin):
|
|
||||||
def process_response(self, request, response):
|
|
||||||
"""Django Middleware: Process Page Views and creates Analytics Celery Tasks"""
|
|
||||||
if getattr(settings, "ANALYTICS_DISABLED", False):
|
|
||||||
return response
|
|
||||||
analyticstokens = AnalyticsTokens.objects.all()
|
|
||||||
client_id = AnalyticsIdentifier.objects.get(id=1).identifier.hex
|
|
||||||
try:
|
|
||||||
title = BeautifulSoup(
|
|
||||||
response.content, "html.parser").html.head.title.text
|
|
||||||
except AttributeError:
|
|
||||||
title = ''
|
|
||||||
for token in analyticstokens:
|
|
||||||
# Check if Page View Sending is Disabled
|
|
||||||
if token.send_page_views is False:
|
|
||||||
continue
|
|
||||||
# Check Exclusions
|
|
||||||
ignore = False
|
|
||||||
for ignore_path in token.ignore_paths.values():
|
|
||||||
ignore_path_regex = re.compile(ignore_path["ignore_path"])
|
|
||||||
if re.search(ignore_path_regex, request.path) is not None:
|
|
||||||
ignore = True
|
|
||||||
|
|
||||||
if ignore is True:
|
|
||||||
continue
|
|
||||||
|
|
||||||
tracking_id = token.token
|
|
||||||
locale = request.LANGUAGE_CODE
|
|
||||||
path = request.path
|
|
||||||
try:
|
|
||||||
useragent = request.headers["User-Agent"]
|
|
||||||
except KeyError:
|
|
||||||
useragent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
|
|
||||||
|
|
||||||
send_ga_tracking_web_view.s(tracking_id=tracking_id,
|
|
||||||
client_id=client_id,
|
|
||||||
page=path,
|
|
||||||
title=title,
|
|
||||||
locale=locale,
|
|
||||||
useragent=useragent).\
|
|
||||||
apply_async(priority=9)
|
|
||||||
return response
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.0.6 on 2022-08-30 05:47
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('analytics', '0006_more_ignore_paths'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='analyticstokens',
|
||||||
|
name='secret',
|
||||||
|
field=models.CharField(blank=True, max_length=254),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# Generated by Django 3.1.4 on 2020-12-30 08:53
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
|
|
||||||
|
def add_aa_team_token(apps, schema_editor):
|
||||||
|
# We can't import the Person model directly as it may be a newer
|
||||||
|
# version than this migration expects. We use the historical version.
|
||||||
|
Tokens = apps.get_model('analytics', 'AnalyticsTokens')
|
||||||
|
AnalyticsPath = apps.get_model('analytics', 'AnalyticsPath')
|
||||||
|
token = Tokens()
|
||||||
|
try:
|
||||||
|
ua_token = Tokens.objects.get(token="UA-186249766-2")
|
||||||
|
original_send_page_views = ua_token.send_page_views
|
||||||
|
original_send_celery_tasks = ua_token.send_celery_tasks
|
||||||
|
original_send_stats = ua_token.send_stats
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
original_send_page_views = True
|
||||||
|
original_send_celery_tasks = True
|
||||||
|
original_send_stats = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
user_notifications_count = AnalyticsPath.objects.get(ignore_path=r"^\/user_notifications_count\/.*",)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
user_notifications_count = AnalyticsPath.objects.create(ignore_path=r"^\/user_notifications_count\/.*")
|
||||||
|
|
||||||
|
try:
|
||||||
|
admin = AnalyticsPath.objects.get(ignore_path=r"^\/admin\/.*")
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
admin = AnalyticsPath.objects.create(ignore_path=r"^\/admin\/.*")
|
||||||
|
|
||||||
|
try:
|
||||||
|
account_activate = AnalyticsPath.objects.get(ignore_path=r"^\/account\/activate\/.*")
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
account_activate = AnalyticsPath.objects.create(ignore_path=r"^\/account\/activate\/.*")
|
||||||
|
|
||||||
|
token.type = 'GA-V4'
|
||||||
|
token.token = 'G-6LYSMYK8DE'
|
||||||
|
token.secret = 'KLlpjLZ-SRGozS5f5wb_kw'
|
||||||
|
token.send_page_views = original_send_page_views
|
||||||
|
token.send_celery_tasks = original_send_celery_tasks
|
||||||
|
token.send_stats = original_send_stats
|
||||||
|
token.name = 'AA Team Public Google Analytics (V4)'
|
||||||
|
token.save()
|
||||||
|
token.ignore_paths.add(admin, user_notifications_count, account_activate)
|
||||||
|
token.save()
|
||||||
|
|
||||||
|
|
||||||
|
def remove_aa_team_token(apps, schema_editor):
|
||||||
|
# Have to define some code to remove this identifier
|
||||||
|
# In case of migration rollback?
|
||||||
|
Tokens = apps.get_model('analytics', 'AnalyticsTokens')
|
||||||
|
token = Tokens.objects.filter(token="G-6LYSMYK8DE").delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('analytics', '0007_analyticstokens_secret'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [migrations.RunPython(
|
||||||
|
add_aa_team_token, remove_aa_team_token)]
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 4.0.10 on 2023-05-08 05:24
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('analytics', '0008_add_AA_GA-4_Team_Token '),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='analyticstokens',
|
||||||
|
name='ignore_paths',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='analyticstokens',
|
||||||
|
name='send_celery_tasks',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='analyticstokens',
|
||||||
|
name='send_page_views',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='AnalyticsPath',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -7,7 +7,8 @@ from uuid import uuid4
|
|||||||
|
|
||||||
class AnalyticsIdentifier(models.Model):
|
class AnalyticsIdentifier(models.Model):
|
||||||
|
|
||||||
identifier = models.UUIDField(default=uuid4,
|
identifier = models.UUIDField(
|
||||||
|
default=uuid4,
|
||||||
editable=False)
|
editable=False)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
@@ -19,10 +20,6 @@ class AnalyticsIdentifier(models.Model):
|
|||||||
return super().save(*args, **kwargs)
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AnalyticsPath(models.Model):
|
|
||||||
ignore_path = models.CharField(max_length=254, default="/example/", help_text="Regex Expression, If matched no Analytics Page View is sent")
|
|
||||||
|
|
||||||
|
|
||||||
class AnalyticsTokens(models.Model):
|
class AnalyticsTokens(models.Model):
|
||||||
|
|
||||||
class Analytics_Type(models.TextChoices):
|
class Analytics_Type(models.TextChoices):
|
||||||
@@ -32,7 +29,5 @@ class AnalyticsTokens(models.Model):
|
|||||||
name = models.CharField(max_length=254)
|
name = models.CharField(max_length=254)
|
||||||
type = models.CharField(max_length=254, choices=Analytics_Type.choices)
|
type = models.CharField(max_length=254, choices=Analytics_Type.choices)
|
||||||
token = models.CharField(max_length=254, blank=False)
|
token = models.CharField(max_length=254, blank=False)
|
||||||
send_page_views = models.BooleanField(default=False)
|
secret = models.CharField(max_length=254, blank=True)
|
||||||
send_celery_tasks = models.BooleanField(default=False)
|
|
||||||
send_stats = models.BooleanField(default=False)
|
send_stats = models.BooleanField(default=False)
|
||||||
ignore_paths = models.ManyToManyField(AnalyticsPath, blank=True)
|
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
import logging
|
|
||||||
from celery.signals import task_failure, task_success
|
|
||||||
from django.conf import settings
|
|
||||||
from allianceauth.analytics.tasks import analytics_event
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
@task_failure.connect
|
|
||||||
def process_failure_signal(
|
|
||||||
exception, traceback,
|
|
||||||
sender, task_id, signal,
|
|
||||||
args, kwargs, einfo, **kw):
|
|
||||||
logger.debug("Celery task_failure signal %s" % sender.__class__.__name__)
|
|
||||||
if getattr(settings, "ANALYTICS_DISABLED", False):
|
|
||||||
return
|
|
||||||
|
|
||||||
category = sender.__module__
|
|
||||||
|
|
||||||
if 'allianceauth.analytics' not in category:
|
|
||||||
if category.endswith(".tasks"):
|
|
||||||
category = category[:-6]
|
|
||||||
|
|
||||||
action = sender.__name__
|
|
||||||
|
|
||||||
label = f"{exception.__class__.__name__}"
|
|
||||||
|
|
||||||
analytics_event(category=category,
|
|
||||||
action=action,
|
|
||||||
label=label)
|
|
||||||
|
|
||||||
|
|
||||||
@task_success.connect
|
|
||||||
def celery_success_signal(sender, result=None, **kw):
|
|
||||||
logger.debug("Celery task_success signal %s" % sender.__class__.__name__)
|
|
||||||
if getattr(settings, "ANALYTICS_DISABLED", False):
|
|
||||||
return
|
|
||||||
|
|
||||||
category = sender.__module__
|
|
||||||
|
|
||||||
if 'allianceauth.analytics' not in category:
|
|
||||||
if category.endswith(".tasks"):
|
|
||||||
category = category[:-6]
|
|
||||||
|
|
||||||
action = sender.__name__
|
|
||||||
label = "Success"
|
|
||||||
|
|
||||||
value = 0
|
|
||||||
if isinstance(result, int):
|
|
||||||
value = result
|
|
||||||
|
|
||||||
analytics_event(category=category,
|
|
||||||
action=action,
|
|
||||||
label=label,
|
|
||||||
value=value)
|
|
||||||
@@ -3,7 +3,6 @@ import logging
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from allianceauth import __version__
|
|
||||||
from .models import AnalyticsTokens, AnalyticsIdentifier
|
from .models import AnalyticsTokens, AnalyticsIdentifier
|
||||||
from .utils import (
|
from .utils import (
|
||||||
install_stat_addons,
|
install_stat_addons,
|
||||||
@@ -12,14 +11,14 @@ from .utils import (
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
BASE_URL = "https://www.google-analytics.com/"
|
BASE_URL = "https://www.google-analytics.com"
|
||||||
|
|
||||||
DEBUG_URL = f"{BASE_URL}debug/collect"
|
DEBUG_URL = f"{BASE_URL}/debug/mp/collect"
|
||||||
COLLECTION_URL = f"{BASE_URL}collect"
|
COLLECTION_URL = f"{BASE_URL}/mp/collect"
|
||||||
|
|
||||||
if getattr(settings, "ANALYTICS_ENABLE_DEBUG", False) and settings.DEBUG:
|
if getattr(settings, "ANALYTICS_ENABLE_DEBUG", False) and settings.DEBUG:
|
||||||
# Force sending of analytics data during in a debug/test environemt
|
# Force sending of analytics data during in a debug/test environment
|
||||||
# Usefull for developers working on this feature.
|
# Useful for developers working on this feature.
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"You have 'ANALYTICS_ENABLE_DEBUG' Enabled! "
|
"You have 'ANALYTICS_ENABLE_DEBUG' Enabled! "
|
||||||
"This debug instance will send analytics data!")
|
"This debug instance will send analytics data!")
|
||||||
@@ -31,40 +30,38 @@ if settings.DEBUG is True:
|
|||||||
ANALYTICS_URL = DEBUG_URL
|
ANALYTICS_URL = DEBUG_URL
|
||||||
|
|
||||||
|
|
||||||
def analytics_event(category: str,
|
def analytics_event(namespace: str,
|
||||||
action: str,
|
task: str,
|
||||||
label: str,
|
label: str = "",
|
||||||
value: int = 0,
|
result: str = "",
|
||||||
|
value: int = 1,
|
||||||
event_type: str = 'Celery'):
|
event_type: str = 'Celery'):
|
||||||
"""
|
"""
|
||||||
Send a Google Analytics Event for each token stored
|
Send a Google Analytics Event for each token stored
|
||||||
Includes check for if its enabled/disabled
|
Includes check for if its enabled/disabled
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
`category` (str): Celery Namespace
|
`namespace` (str): Celery Namespace
|
||||||
`action` (str): Task Name
|
`task` (str): Task Name
|
||||||
`label` (str): Optional, Task Success/Exception
|
`label` (str): Optional, additional task label
|
||||||
`value` (int): Optional, If bulk, Query size, can be a binary True/False
|
`result` (str): Optional, Task Success/Exception
|
||||||
|
`value` (int): Optional, If bulk, Query size, can be a Boolean
|
||||||
`event_type` (str): Optional, Celery or Stats only, Default to Celery
|
`event_type` (str): Optional, Celery or Stats only, Default to Celery
|
||||||
"""
|
"""
|
||||||
analyticstokens = AnalyticsTokens.objects.all()
|
for token in AnalyticsTokens.objects.filter(type='GA-V4'):
|
||||||
client_id = AnalyticsIdentifier.objects.get(id=1).identifier.hex
|
if event_type == 'Stats':
|
||||||
for token in analyticstokens:
|
|
||||||
if event_type == 'Celery':
|
|
||||||
allowed = token.send_celery_tasks
|
|
||||||
elif event_type == 'Stats':
|
|
||||||
allowed = token.send_stats
|
allowed = token.send_stats
|
||||||
else:
|
else:
|
||||||
allowed = False
|
allowed = False
|
||||||
|
|
||||||
if allowed is True:
|
if allowed is True:
|
||||||
tracking_id = token.token
|
|
||||||
send_ga_tracking_celery_event.s(
|
send_ga_tracking_celery_event.s(
|
||||||
tracking_id=tracking_id,
|
measurement_id=token.token,
|
||||||
client_id=client_id,
|
secret=token.secret,
|
||||||
category=category,
|
namespace=namespace,
|
||||||
action=action,
|
task=task,
|
||||||
label=label,
|
label=label,
|
||||||
|
result=result,
|
||||||
value=value).apply_async(priority=9)
|
value=value).apply_async(priority=9)
|
||||||
|
|
||||||
|
|
||||||
@@ -72,136 +69,104 @@ def analytics_event(category: str,
|
|||||||
def analytics_daily_stats():
|
def analytics_daily_stats():
|
||||||
"""Celery Task: Do not call directly
|
"""Celery Task: Do not call directly
|
||||||
|
|
||||||
Gathers a series of daily statistics and sends analytics events containing them
|
Gathers a series of daily statistics
|
||||||
|
Sends analytics events containing them
|
||||||
"""
|
"""
|
||||||
users = install_stat_users()
|
users = install_stat_users()
|
||||||
tokens = install_stat_tokens()
|
tokens = install_stat_tokens()
|
||||||
addons = install_stat_addons()
|
addons = install_stat_addons()
|
||||||
logger.debug("Running Daily Analytics Upload")
|
logger.debug("Running Daily Analytics Upload")
|
||||||
|
|
||||||
analytics_event(category='allianceauth.analytics',
|
analytics_event(namespace='allianceauth.analytics',
|
||||||
action='send_install_stats',
|
task='send_install_stats',
|
||||||
label='existence',
|
label='existence',
|
||||||
value=1,
|
value=1,
|
||||||
event_type='Stats')
|
event_type='Stats')
|
||||||
analytics_event(category='allianceauth.analytics',
|
analytics_event(namespace='allianceauth.analytics',
|
||||||
action='send_install_stats',
|
task='send_install_stats',
|
||||||
label='users',
|
label='users',
|
||||||
value=users,
|
value=users,
|
||||||
event_type='Stats')
|
event_type='Stats')
|
||||||
analytics_event(category='allianceauth.analytics',
|
analytics_event(namespace='allianceauth.analytics',
|
||||||
action='send_install_stats',
|
task='send_install_stats',
|
||||||
label='tokens',
|
label='tokens',
|
||||||
value=tokens,
|
value=tokens,
|
||||||
event_type='Stats')
|
event_type='Stats')
|
||||||
analytics_event(category='allianceauth.analytics',
|
analytics_event(namespace='allianceauth.analytics',
|
||||||
action='send_install_stats',
|
task='send_install_stats',
|
||||||
label='addons',
|
label='addons',
|
||||||
value=addons,
|
value=addons,
|
||||||
event_type='Stats')
|
event_type='Stats')
|
||||||
|
|
||||||
for appconfig in apps.get_app_configs():
|
for appconfig in apps.get_app_configs():
|
||||||
analytics_event(category='allianceauth.analytics',
|
analytics_event(namespace='allianceauth.analytics',
|
||||||
action='send_extension_stats',
|
task='send_extension_stats',
|
||||||
label=appconfig.label,
|
label=appconfig.label,
|
||||||
value=1,
|
value=1,
|
||||||
event_type='Stats')
|
event_type='Stats')
|
||||||
|
|
||||||
|
|
||||||
@shared_task()
|
|
||||||
def send_ga_tracking_web_view(
|
|
||||||
tracking_id: str,
|
|
||||||
client_id: str,
|
|
||||||
page: str,
|
|
||||||
title: str,
|
|
||||||
locale: str,
|
|
||||||
useragent: str) -> requests.Response:
|
|
||||||
|
|
||||||
"""Celery Task: Do not call directly
|
|
||||||
|
|
||||||
Sends Page View events to GA, Called only via analytics.middleware
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
`tracking_id` (str): Unique Server Identifier
|
|
||||||
`client_id` (str): GA Token
|
|
||||||
`page` (str): Page Path
|
|
||||||
`title` (str): Page Title
|
|
||||||
`locale` (str): Browser Language
|
|
||||||
`useragent` (str): Browser UserAgent
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
requests.Reponse Object
|
|
||||||
"""
|
|
||||||
headers = {"User-Agent": useragent}
|
|
||||||
|
|
||||||
payload = {
|
|
||||||
'v': '1',
|
|
||||||
'tid': tracking_id,
|
|
||||||
'cid': client_id,
|
|
||||||
't': 'pageview',
|
|
||||||
'dp': page,
|
|
||||||
'dt': title,
|
|
||||||
'ul': locale,
|
|
||||||
'ua': useragent,
|
|
||||||
'aip': 1,
|
|
||||||
'an': "allianceauth",
|
|
||||||
'av': __version__
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.post(
|
|
||||||
ANALYTICS_URL, data=payload,
|
|
||||||
timeout=5, headers=headers)
|
|
||||||
logger.debug(f"Analytics Page View HTTP{response.status_code}")
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
@shared_task()
|
@shared_task()
|
||||||
def send_ga_tracking_celery_event(
|
def send_ga_tracking_celery_event(
|
||||||
tracking_id: str,
|
measurement_id: str,
|
||||||
client_id: str,
|
secret: str,
|
||||||
category: str,
|
namespace: str,
|
||||||
action: str,
|
task: str,
|
||||||
label: str,
|
label: str = "",
|
||||||
value: int) -> requests.Response:
|
result: str = "",
|
||||||
|
value: int = 1):
|
||||||
"""Celery Task: Do not call directly
|
"""Celery Task: Do not call directly
|
||||||
|
|
||||||
Sends Page View events to GA, Called only via analytics.middleware
|
Sends an events to GA
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
`tracking_id` (str): Unique Server Identifier
|
`measurement_id` (str): GA Token
|
||||||
`client_id` (str): GA Token
|
`secret` (str): GA Authentication Secret
|
||||||
`category` (str): Celery Namespace
|
`namespace` (str): Celery Namespace
|
||||||
`action` (str): Task Name
|
`task` (str): Task Name
|
||||||
`label` (str): Optional, Task Success/Exception
|
`label` (str): Optional, additional task label
|
||||||
|
`result` (str): Optional, Task Success/Exception
|
||||||
`value` (int): Optional, If bulk, Query size, can be a binary True/False
|
`value` (int): Optional, If bulk, Query size, can be a binary True/False
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
requests.Reponse Object
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
headers = {
|
parameters = {
|
||||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"}
|
'measurement_id': measurement_id,
|
||||||
|
'api_secret': secret
|
||||||
payload = {
|
|
||||||
'v': '1',
|
|
||||||
'tid': tracking_id,
|
|
||||||
'cid': client_id,
|
|
||||||
't': 'event',
|
|
||||||
'ec': category,
|
|
||||||
'ea': action,
|
|
||||||
'el': label,
|
|
||||||
'ev': value,
|
|
||||||
'aip': 1,
|
|
||||||
'an': "allianceauth",
|
|
||||||
'av': __version__
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
'client_id': AnalyticsIdentifier.objects.get(id=1).identifier.hex,
|
||||||
|
"user_properties": {
|
||||||
|
"allianceauth_version": {
|
||||||
|
"value": "allianceauth_version"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'non_personalized_ads': True,
|
||||||
|
"events": [{
|
||||||
|
"name": "celery_event",
|
||||||
|
"params": {
|
||||||
|
"namespace": namespace,
|
||||||
|
"task": task,
|
||||||
|
'result': result,
|
||||||
|
'label': label,
|
||||||
|
"value": value
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
try:
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
ANALYTICS_URL, data=payload,
|
ANALYTICS_URL,
|
||||||
timeout=5, headers=headers)
|
params=parameters,
|
||||||
logger.debug(f"Analytics Celery/Stats Event HTTP{response.status_code}")
|
json=payload,
|
||||||
return response
|
timeout=10)
|
||||||
|
response.raise_for_status()
|
||||||
|
logger.debug(
|
||||||
|
f"Analytics Celery/Stats Event HTTP{response.status_code}")
|
||||||
|
return response.status_code
|
||||||
|
except requests.exceptions.HTTPError as e:
|
||||||
|
logger.debug(e)
|
||||||
|
return response.status_code
|
||||||
|
except requests.exceptions.ConnectionError as e:
|
||||||
|
logger.debug(e)
|
||||||
|
return "Failed"
|
||||||
|
|||||||
@@ -1,109 +0,0 @@
|
|||||||
from unittest.mock import patch
|
|
||||||
from urllib.parse import parse_qs
|
|
||||||
|
|
||||||
import requests_mock
|
|
||||||
|
|
||||||
from django.test import override_settings
|
|
||||||
|
|
||||||
from allianceauth.analytics.tasks import ANALYTICS_URL
|
|
||||||
from allianceauth.eveonline.tasks import update_character
|
|
||||||
from allianceauth.tests.auth_utils import AuthUtils
|
|
||||||
from allianceauth.utils.testing import NoSocketsTestCase
|
|
||||||
|
|
||||||
|
|
||||||
@override_settings(CELERY_ALWAYS_EAGER=True)
|
|
||||||
@requests_mock.mock()
|
|
||||||
class TestAnalyticsForViews(NoSocketsTestCase):
|
|
||||||
@override_settings(ANALYTICS_DISABLED=False)
|
|
||||||
def test_should_run_analytics(self, requests_mocker):
|
|
||||||
# given
|
|
||||||
requests_mocker.post(ANALYTICS_URL)
|
|
||||||
user = AuthUtils.create_user("Bruce Wayne")
|
|
||||||
self.client.force_login(user)
|
|
||||||
# when
|
|
||||||
response = self.client.get("/dashboard/")
|
|
||||||
# then
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertTrue(requests_mocker.called)
|
|
||||||
|
|
||||||
@override_settings(ANALYTICS_DISABLED=True)
|
|
||||||
def test_should_not_run_analytics(self, requests_mocker):
|
|
||||||
# given
|
|
||||||
requests_mocker.post(ANALYTICS_URL)
|
|
||||||
user = AuthUtils.create_user("Bruce Wayne")
|
|
||||||
self.client.force_login(user)
|
|
||||||
# when
|
|
||||||
response = self.client.get("/dashboard/")
|
|
||||||
# then
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertFalse(requests_mocker.called)
|
|
||||||
|
|
||||||
|
|
||||||
@override_settings(CELERY_ALWAYS_EAGER=True)
|
|
||||||
@requests_mock.mock()
|
|
||||||
class TestAnalyticsForTasks(NoSocketsTestCase):
|
|
||||||
@override_settings(ANALYTICS_DISABLED=False)
|
|
||||||
@patch("allianceauth.eveonline.models.EveCharacter.objects.update_character")
|
|
||||||
def test_should_run_analytics_for_successful_task(
|
|
||||||
self, requests_mocker, mock_update_character
|
|
||||||
):
|
|
||||||
# given
|
|
||||||
requests_mocker.post(ANALYTICS_URL)
|
|
||||||
user = AuthUtils.create_user("Bruce Wayne")
|
|
||||||
character = AuthUtils.add_main_character_2(user, "Bruce Wayne", 1001)
|
|
||||||
# when
|
|
||||||
update_character.delay(character.character_id)
|
|
||||||
# then
|
|
||||||
self.assertTrue(mock_update_character.called)
|
|
||||||
self.assertTrue(requests_mocker.called)
|
|
||||||
payload = parse_qs(requests_mocker.last_request.text)
|
|
||||||
self.assertListEqual(payload["el"], ["Success"])
|
|
||||||
|
|
||||||
@override_settings(ANALYTICS_DISABLED=True)
|
|
||||||
@patch("allianceauth.eveonline.models.EveCharacter.objects.update_character")
|
|
||||||
def test_should_not_run_analytics_for_successful_task(
|
|
||||||
self, requests_mocker, mock_update_character
|
|
||||||
):
|
|
||||||
# given
|
|
||||||
requests_mocker.post(ANALYTICS_URL)
|
|
||||||
user = AuthUtils.create_user("Bruce Wayne")
|
|
||||||
character = AuthUtils.add_main_character_2(user, "Bruce Wayne", 1001)
|
|
||||||
# when
|
|
||||||
update_character.delay(character.character_id)
|
|
||||||
# then
|
|
||||||
self.assertTrue(mock_update_character.called)
|
|
||||||
self.assertFalse(requests_mocker.called)
|
|
||||||
|
|
||||||
@override_settings(ANALYTICS_DISABLED=False)
|
|
||||||
@patch("allianceauth.eveonline.models.EveCharacter.objects.update_character")
|
|
||||||
def test_should_run_analytics_for_failed_task(
|
|
||||||
self, requests_mocker, mock_update_character
|
|
||||||
):
|
|
||||||
# given
|
|
||||||
requests_mocker.post(ANALYTICS_URL)
|
|
||||||
mock_update_character.side_effect = RuntimeError
|
|
||||||
user = AuthUtils.create_user("Bruce Wayne")
|
|
||||||
character = AuthUtils.add_main_character_2(user, "Bruce Wayne", 1001)
|
|
||||||
# when
|
|
||||||
update_character.delay(character.character_id)
|
|
||||||
# then
|
|
||||||
self.assertTrue(mock_update_character.called)
|
|
||||||
self.assertTrue(requests_mocker.called)
|
|
||||||
payload = parse_qs(requests_mocker.last_request.text)
|
|
||||||
self.assertNotEqual(payload["el"], ["Success"])
|
|
||||||
|
|
||||||
@override_settings(ANALYTICS_DISABLED=True)
|
|
||||||
@patch("allianceauth.eveonline.models.EveCharacter.objects.update_character")
|
|
||||||
def test_should_not_run_analytics_for_failed_task(
|
|
||||||
self, requests_mocker, mock_update_character
|
|
||||||
):
|
|
||||||
# given
|
|
||||||
requests_mocker.post(ANALYTICS_URL)
|
|
||||||
mock_update_character.side_effect = RuntimeError
|
|
||||||
user = AuthUtils.create_user("Bruce Wayne")
|
|
||||||
character = AuthUtils.add_main_character_2(user, "Bruce Wayne", 1001)
|
|
||||||
# when
|
|
||||||
update_character.delay(character.character_id)
|
|
||||||
# then
|
|
||||||
self.assertTrue(mock_update_character.called)
|
|
||||||
self.assertFalse(requests_mocker.called)
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
from allianceauth.analytics.middleware import AnalyticsMiddleware
|
|
||||||
from unittest.mock import Mock
|
|
||||||
from django.http import HttpResponse
|
|
||||||
|
|
||||||
from django.test.testcases import TestCase
|
|
||||||
|
|
||||||
|
|
||||||
class TestAnalyticsMiddleware(TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.middleware = AnalyticsMiddleware(HttpResponse)
|
|
||||||
self.request = Mock()
|
|
||||||
self.request.headers = {
|
|
||||||
"User-Agent": "AUTOMATED TEST"
|
|
||||||
}
|
|
||||||
self.request.path = '/testURL/'
|
|
||||||
self.request.session = {}
|
|
||||||
self.request.LANGUAGE_CODE = 'en'
|
|
||||||
self.response = Mock()
|
|
||||||
self.response.content = 'hello world'
|
|
||||||
|
|
||||||
def test_middleware(self):
|
|
||||||
response = self.middleware.process_response(self.request, self.response)
|
|
||||||
self.assertEqual(self.response, response)
|
|
||||||
@@ -23,4 +23,5 @@ class TestAnalyticsIdentifier(TestCase):
|
|||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(ValidationError):
|
||||||
AnalyticsIdentifier.objects.create(identifier=uuid_2)
|
AnalyticsIdentifier.objects.create(identifier=uuid_2)
|
||||||
self.assertEqual(AnalyticsIdentifier.objects.count(), 1)
|
self.assertEqual(AnalyticsIdentifier.objects.count(), 1)
|
||||||
self.assertEqual(AnalyticsIdentifier.objects.get(pk=1).identifier, UUID(uuid_1))
|
self.assertEqual(AnalyticsIdentifier.objects.get(
|
||||||
|
pk=1).identifier, UUID(uuid_1))
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ from django.test.utils import override_settings
|
|||||||
|
|
||||||
from allianceauth.analytics.tasks import (
|
from allianceauth.analytics.tasks import (
|
||||||
analytics_event,
|
analytics_event,
|
||||||
send_ga_tracking_celery_event,
|
send_ga_tracking_celery_event)
|
||||||
send_ga_tracking_web_view)
|
|
||||||
from allianceauth.utils.testing import NoSocketsTestCase
|
from allianceauth.utils.testing import NoSocketsTestCase
|
||||||
|
|
||||||
|
|
||||||
GOOGLE_ANALYTICS_DEBUG_URL = 'https://www.google-analytics.com/debug/collect'
|
GOOGLE_ANALYTICS_DEBUG_URL = 'https://www.google-analytics.com/debug/mp/collect'
|
||||||
|
|
||||||
|
|
||||||
@override_settings(CELERY_ALWAYS_EAGER=True, CELERY_EAGER_PROPAGATES_EXCEPTIONS=True)
|
@override_settings(CELERY_ALWAYS_EAGER=True, CELERY_EAGER_PROPAGATES_EXCEPTIONS=True)
|
||||||
@@ -18,195 +17,53 @@ class TestAnalyticsTasks(NoSocketsTestCase):
|
|||||||
def test_analytics_event(self, requests_mocker):
|
def test_analytics_event(self, requests_mocker):
|
||||||
requests_mocker.register_uri('POST', GOOGLE_ANALYTICS_DEBUG_URL)
|
requests_mocker.register_uri('POST', GOOGLE_ANALYTICS_DEBUG_URL)
|
||||||
analytics_event(
|
analytics_event(
|
||||||
category='allianceauth.analytics',
|
namespace='allianceauth.analytics',
|
||||||
action='send_tests',
|
task='send_tests',
|
||||||
label='test',
|
label='test',
|
||||||
value=1,
|
value=1,
|
||||||
|
result="Success",
|
||||||
event_type='Stats')
|
event_type='Stats')
|
||||||
|
|
||||||
def test_send_ga_tracking_web_view_sent(self, requests_mocker):
|
|
||||||
"""This test sends if the event SENDS to google.
|
|
||||||
Not if it was successful.
|
|
||||||
"""
|
|
||||||
# given
|
|
||||||
requests_mocker.register_uri('POST', GOOGLE_ANALYTICS_DEBUG_URL)
|
|
||||||
tracking_id = 'UA-186249766-2'
|
|
||||||
client_id = 'ab33e241fbf042b6aa77c7655a768af7'
|
|
||||||
page = '/index/'
|
|
||||||
title = 'Hello World'
|
|
||||||
locale = 'en'
|
|
||||||
useragent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
|
|
||||||
# when
|
|
||||||
response = send_ga_tracking_web_view(
|
|
||||||
tracking_id,
|
|
||||||
client_id,
|
|
||||||
page,
|
|
||||||
title,
|
|
||||||
locale,
|
|
||||||
useragent)
|
|
||||||
# then
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
def test_send_ga_tracking_web_view_success(self, requests_mocker):
|
|
||||||
# given
|
|
||||||
requests_mocker.register_uri(
|
|
||||||
'POST',
|
|
||||||
GOOGLE_ANALYTICS_DEBUG_URL,
|
|
||||||
json={"hitParsingResult":[{'valid': True}]}
|
|
||||||
)
|
|
||||||
tracking_id = 'UA-186249766-2'
|
|
||||||
client_id = 'ab33e241fbf042b6aa77c7655a768af7'
|
|
||||||
page = '/index/'
|
|
||||||
title = 'Hello World'
|
|
||||||
locale = 'en'
|
|
||||||
useragent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
|
|
||||||
# when
|
|
||||||
json_response = send_ga_tracking_web_view(
|
|
||||||
tracking_id,
|
|
||||||
client_id,
|
|
||||||
page,
|
|
||||||
title,
|
|
||||||
locale,
|
|
||||||
useragent).json()
|
|
||||||
# then
|
|
||||||
self.assertTrue(json_response["hitParsingResult"][0]["valid"])
|
|
||||||
|
|
||||||
def test_send_ga_tracking_web_view_invalid_token(self, requests_mocker):
|
|
||||||
# given
|
|
||||||
requests_mocker.register_uri(
|
|
||||||
'POST',
|
|
||||||
GOOGLE_ANALYTICS_DEBUG_URL,
|
|
||||||
json={
|
|
||||||
"hitParsingResult":[
|
|
||||||
{
|
|
||||||
'valid': False,
|
|
||||||
'parserMessage': [
|
|
||||||
{
|
|
||||||
'messageType': 'INFO',
|
|
||||||
'description': 'IP Address from this hit was anonymized to 1.132.110.0.',
|
|
||||||
'messageCode': 'VALUE_MODIFIED'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'messageType': 'ERROR',
|
|
||||||
'description': "The value provided for parameter 'tid' is invalid. Please see http://goo.gl/a8d4RP#tid for details.",
|
|
||||||
'messageCode': 'VALUE_INVALID', 'parameter': 'tid'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'hit': '/debug/collect?v=1&tid=UA-IntentionallyBadTrackingID-2&cid=ab33e241fbf042b6aa77c7655a768af7&t=pageview&dp=/index/&dt=Hello World&ul=en&ua=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36&aip=1&an=allianceauth&av=2.9.0a2'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
tracking_id = 'UA-IntentionallyBadTrackingID-2'
|
|
||||||
client_id = 'ab33e241fbf042b6aa77c7655a768af7'
|
|
||||||
page = '/index/'
|
|
||||||
title = 'Hello World'
|
|
||||||
locale = 'en'
|
|
||||||
useragent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
|
|
||||||
# when
|
|
||||||
json_response = send_ga_tracking_web_view(
|
|
||||||
tracking_id,
|
|
||||||
client_id,
|
|
||||||
page,
|
|
||||||
title,
|
|
||||||
locale,
|
|
||||||
useragent).json()
|
|
||||||
# then
|
|
||||||
self.assertFalse(json_response["hitParsingResult"][0]["valid"])
|
|
||||||
self.assertEqual(
|
|
||||||
json_response["hitParsingResult"][0]["parserMessage"][1]["description"],
|
|
||||||
"The value provided for parameter 'tid' is invalid. Please see http://goo.gl/a8d4RP#tid for details."
|
|
||||||
)
|
|
||||||
|
|
||||||
# [{'valid': False, 'parserMessage': [{'messageType': 'INFO', 'description': 'IP Address from this hit was anonymized to 1.132.110.0.', 'messageCode': 'VALUE_MODIFIED'}, {'messageType': 'ERROR', 'description': "The value provided for parameter 'tid' is invalid. Please see http://goo.gl/a8d4RP#tid for details.", 'messageCode': 'VALUE_INVALID', 'parameter': 'tid'}], 'hit': '/debug/collect?v=1&tid=UA-IntentionallyBadTrackingID-2&cid=ab33e241fbf042b6aa77c7655a768af7&t=pageview&dp=/index/&dt=Hello World&ul=en&ua=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36&aip=1&an=allianceauth&av=2.9.0a2'}]
|
|
||||||
|
|
||||||
def test_send_ga_tracking_celery_event_sent(self, requests_mocker):
|
def test_send_ga_tracking_celery_event_sent(self, requests_mocker):
|
||||||
# given
|
# given
|
||||||
requests_mocker.register_uri('POST', GOOGLE_ANALYTICS_DEBUG_URL)
|
requests_mocker.register_uri('POST', GOOGLE_ANALYTICS_DEBUG_URL)
|
||||||
tracking_id = 'UA-186249766-2'
|
token = 'G-6LYSMYK8DE'
|
||||||
client_id = 'ab33e241fbf042b6aa77c7655a768af7'
|
secret = 'KLlpjLZ-SRGozS5f5wb_kw',
|
||||||
category = 'test'
|
category = 'test'
|
||||||
action = 'test'
|
action = 'test'
|
||||||
label = 'test'
|
label = 'test'
|
||||||
value = '1'
|
value = '1'
|
||||||
# when
|
# when
|
||||||
response = send_ga_tracking_celery_event(
|
task = send_ga_tracking_celery_event(
|
||||||
tracking_id,
|
token,
|
||||||
client_id,
|
secret,
|
||||||
category,
|
category,
|
||||||
action,
|
action,
|
||||||
label,
|
label,
|
||||||
value)
|
value)
|
||||||
# then
|
# then
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(task, 200)
|
||||||
|
|
||||||
def test_send_ga_tracking_celery_event_success(self, requests_mocker):
|
def test_send_ga_tracking_celery_event_success(self, requests_mocker):
|
||||||
# given
|
# given
|
||||||
requests_mocker.register_uri(
|
requests_mocker.register_uri(
|
||||||
'POST',
|
'POST',
|
||||||
GOOGLE_ANALYTICS_DEBUG_URL,
|
GOOGLE_ANALYTICS_DEBUG_URL,
|
||||||
json={"hitParsingResult":[{'valid': True}]}
|
json={"validationMessages": []}
|
||||||
)
|
)
|
||||||
tracking_id = 'UA-186249766-2'
|
token = 'G-6LYSMYK8DE'
|
||||||
client_id = 'ab33e241fbf042b6aa77c7655a768af7'
|
secret = 'KLlpjLZ-SRGozS5f5wb_kw',
|
||||||
category = 'test'
|
category = 'test'
|
||||||
action = 'test'
|
action = 'test'
|
||||||
label = 'test'
|
label = 'test'
|
||||||
value = '1'
|
value = '1'
|
||||||
# when
|
# when
|
||||||
json_response = send_ga_tracking_celery_event(
|
task = send_ga_tracking_celery_event(
|
||||||
tracking_id,
|
token,
|
||||||
client_id,
|
secret,
|
||||||
category,
|
category,
|
||||||
action,
|
action,
|
||||||
label,
|
label,
|
||||||
value).json()
|
value)
|
||||||
# then
|
# then
|
||||||
self.assertTrue(json_response["hitParsingResult"][0]["valid"])
|
self.assertTrue(task, 200)
|
||||||
|
|
||||||
def test_send_ga_tracking_celery_event_invalid_token(self, requests_mocker):
|
|
||||||
# given
|
|
||||||
requests_mocker.register_uri(
|
|
||||||
'POST',
|
|
||||||
GOOGLE_ANALYTICS_DEBUG_URL,
|
|
||||||
json={
|
|
||||||
"hitParsingResult":[
|
|
||||||
{
|
|
||||||
'valid': False,
|
|
||||||
'parserMessage': [
|
|
||||||
{
|
|
||||||
'messageType': 'INFO',
|
|
||||||
'description': 'IP Address from this hit was anonymized to 1.132.110.0.',
|
|
||||||
'messageCode': 'VALUE_MODIFIED'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'messageType': 'ERROR',
|
|
||||||
'description': "The value provided for parameter 'tid' is invalid. Please see http://goo.gl/a8d4RP#tid for details.",
|
|
||||||
'messageCode': 'VALUE_INVALID', 'parameter': 'tid'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'hit': '/debug/collect?v=1&tid=UA-IntentionallyBadTrackingID-2&cid=ab33e241fbf042b6aa77c7655a768af7&t=pageview&dp=/index/&dt=Hello World&ul=en&ua=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36&aip=1&an=allianceauth&av=2.9.0a2'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
tracking_id = 'UA-IntentionallyBadTrackingID-2'
|
|
||||||
client_id = 'ab33e241fbf042b6aa77c7655a768af7'
|
|
||||||
category = 'test'
|
|
||||||
action = 'test'
|
|
||||||
label = 'test'
|
|
||||||
value = '1'
|
|
||||||
# when
|
|
||||||
json_response = send_ga_tracking_celery_event(
|
|
||||||
tracking_id,
|
|
||||||
client_id,
|
|
||||||
category,
|
|
||||||
action,
|
|
||||||
label,
|
|
||||||
value).json()
|
|
||||||
# then
|
|
||||||
self.assertFalse(json_response["hitParsingResult"][0]["valid"])
|
|
||||||
self.assertEqual(
|
|
||||||
json_response["hitParsingResult"][0]["parserMessage"][1]["description"],
|
|
||||||
"The value provided for parameter 'tid' is invalid. Please see http://goo.gl/a8d4RP#tid for details."
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,5 +1,30 @@
|
|||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.core.checks import Warning, Error, register
|
||||||
|
|
||||||
|
|
||||||
class AllianceAuthConfig(AppConfig):
|
class AllianceAuthConfig(AppConfig):
|
||||||
name = 'allianceauth'
|
name = 'allianceauth'
|
||||||
|
|
||||||
|
|
||||||
|
@register()
|
||||||
|
def check_settings(app_configs, **kwargs):
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
if hasattr(settings, "SITE_URL"):
|
||||||
|
if settings.SITE_URL[-1] == "/":
|
||||||
|
errors.append(Warning(
|
||||||
|
"'SITE_URL' Has a trailing slash. This may lead to incorrect links being generated by Auth."))
|
||||||
|
else:
|
||||||
|
errors.append(Error(
|
||||||
|
"No 'SITE_URL' found is settings. This may lead to incorrect links being generated by Auth or Errors in 3rd party modules."))
|
||||||
|
if hasattr(settings, "CSRF_TRUSTED_ORIGINS"):
|
||||||
|
if hasattr(settings, "SITE_URL"):
|
||||||
|
if settings.SITE_URL not in settings.CSRF_TRUSTED_ORIGINS:
|
||||||
|
errors.append(Warning(
|
||||||
|
"'SITE_URL' not found in 'CSRF_TRUSTED_ORIGINS'. Auth may not load pages correctly until this is rectified."))
|
||||||
|
else:
|
||||||
|
errors.append(Error(
|
||||||
|
"No 'CSRF_TRUSTED_ORIGINS' found is settings, Auth may not load pages correctly until this is rectified"))
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ class UserAdmin(BaseUserAdmin):
|
|||||||
Behavior of groups and characters columns can be configured via settings
|
Behavior of groups and characters columns can be configured via settings
|
||||||
"""
|
"""
|
||||||
|
|
||||||
inlines = BaseUserAdmin.inlines + [UserProfileInline]
|
inlines = [UserProfileInline]
|
||||||
ordering = ('username', )
|
ordering = ('username', )
|
||||||
list_select_related = ('profile__state', 'profile__main_character')
|
list_select_related = ('profile__state', 'profile__main_character')
|
||||||
show_full_result_count = True
|
show_full_result_count = True
|
||||||
|
|||||||
45
allianceauth/authentication/auth_hooks.py
Normal file
45
allianceauth/authentication/auth_hooks.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
from allianceauth.hooks import DashboardItemHook
|
||||||
|
from allianceauth import hooks
|
||||||
|
from .views import dashboard_characters, dashboard_groups, dashboard_admin
|
||||||
|
|
||||||
|
|
||||||
|
class UserCharactersHook(DashboardItemHook):
|
||||||
|
def __init__(self):
|
||||||
|
DashboardItemHook.__init__(
|
||||||
|
self,
|
||||||
|
dashboard_characters,
|
||||||
|
5
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class UserGroupsHook(DashboardItemHook):
|
||||||
|
def __init__(self):
|
||||||
|
DashboardItemHook.__init__(
|
||||||
|
self,
|
||||||
|
dashboard_groups,
|
||||||
|
5
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AdminHook(DashboardItemHook):
|
||||||
|
def __init__(self):
|
||||||
|
DashboardItemHook.__init__(
|
||||||
|
self,
|
||||||
|
dashboard_admin,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@hooks.register('dashboard_hook')
|
||||||
|
def register_character_hook():
|
||||||
|
return UserCharactersHook()
|
||||||
|
|
||||||
|
|
||||||
|
@hooks.register('dashboard_hook')
|
||||||
|
def register_groups_hook():
|
||||||
|
return UserGroupsHook()
|
||||||
|
|
||||||
|
|
||||||
|
@hooks.register('dashboard_hook')
|
||||||
|
def register_admin_hook():
|
||||||
|
return AdminHook()
|
||||||
@@ -2,7 +2,6 @@ import logging
|
|||||||
|
|
||||||
from django.contrib.auth.backends import ModelBackend
|
from django.contrib.auth.backends import ModelBackend
|
||||||
from django.contrib.auth.models import User, Permission
|
from django.contrib.auth.models import User, Permission
|
||||||
from django.contrib import messages
|
|
||||||
|
|
||||||
from .models import UserProfile, CharacterOwnership, OwnershipRecord
|
from .models import UserProfile, CharacterOwnership, OwnershipRecord
|
||||||
|
|
||||||
@@ -41,9 +40,7 @@ class StateBackend(ModelBackend):
|
|||||||
if ownership.user.profile.main_character:
|
if ownership.user.profile.main_character:
|
||||||
if ownership.user.profile.main_character.character_id == token.character_id:
|
if ownership.user.profile.main_character.character_id == token.character_id:
|
||||||
return ownership.user
|
return ownership.user
|
||||||
else: ## this is an alt, enforce main only.
|
else: # this is an alt, enforce main only.
|
||||||
if request:
|
|
||||||
messages.error("Unable to authenticate with this Character, Please log in with the main character associated with this account.")
|
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
logger.debug(f'{token.character_name} has changed ownership. Creating new user account.')
|
logger.debug(f'{token.character_name} has changed ownership. Creating new user account.')
|
||||||
@@ -66,9 +63,7 @@ class StateBackend(ModelBackend):
|
|||||||
user = records[0].user
|
user = records[0].user
|
||||||
if user.profile.main_character:
|
if user.profile.main_character:
|
||||||
if user.profile.main_character.character_id != token.character_id:
|
if user.profile.main_character.character_id != token.character_id:
|
||||||
## this is an alt, enforce main only due to trust issues in SSO.
|
# this is an alt, enforce main only due to trust issues in SSO.
|
||||||
if request:
|
|
||||||
messages.error("Unable to authenticate with this Character, Please log in with the main character associated with this account. Then add this character from the dashboard.")
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
token.user = user
|
token.user = user
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
from django.urls import include
|
||||||
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import Callable, Iterable, Optional
|
from typing import Callable, Iterable, Optional
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class UserSettingsMiddleware(MiddlewareMixin):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
|
|
||||||
|
# AA v3 NIGHT_MODE
|
||||||
# Set our Night mode flag from the DB
|
# Set our Night mode flag from the DB
|
||||||
# Null = hasnt been set by the user ever, dont act.
|
# Null = hasnt been set by the user ever, dont act.
|
||||||
#
|
#
|
||||||
@@ -42,4 +43,13 @@ class UserSettingsMiddleware(MiddlewareMixin):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
|
|
||||||
|
# AA v4 Themes
|
||||||
|
# Null = has not been set by the user ever, dont act
|
||||||
|
# DEFAULT_THEME or DEFAULT_THEME_DARK will be used in get_theme()
|
||||||
|
try:
|
||||||
|
if request.user.profile.theme is not None:
|
||||||
|
request.session["THEME"] = request.user.profile.theme
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.0.10 on 2023-10-07 07:59
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('authentication', '0021_alter_userprofile_language'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userprofile',
|
||||||
|
name='theme',
|
||||||
|
field=models.CharField(blank=True, help_text='Bootstrap 5 Themes from https://bootswatch.com/ or Community Apps', max_length=200, null=True, verbose_name='Theme'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -101,6 +101,13 @@ class UserProfile(models.Model):
|
|||||||
_("Night Mode"),
|
_("Night Mode"),
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True)
|
null=True)
|
||||||
|
theme = models.CharField(
|
||||||
|
_("Theme"),
|
||||||
|
max_length=200,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
help_text="Bootstrap 5 Themes from https://bootswatch.com/ or Community Apps"
|
||||||
|
)
|
||||||
|
|
||||||
def assign_state(self, state=None, commit=True):
|
def assign_state(self, state=None, commit=True):
|
||||||
if not state:
|
if not state:
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
<div class="col-12 col-xl-8 align-self-stretch p-2 ps-0 pe-0 ps-xl-0 pe-xl-2">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<h4 class="ms-auto me-auto">
|
||||||
|
{% translate "Characters" %}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div style="height: 300px; overflow-y:auto;">
|
||||||
|
<div class="d-flex">
|
||||||
|
<a href="{% url 'authentication:add_character' %}" class="btn btn-primary flex-fill m-1" title="{% translate 'Add Character' %}">
|
||||||
|
<span class="d-md-inline m-2">{% translate 'Add Character' %}</span>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'authentication:change_main_character' %}" class="btn btn-primary flex-fill m-1" title="{% translate 'Change Main' %}">
|
||||||
|
<span class="d-md-inline m-2">{% translate 'Change Main' %}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center"></th>
|
||||||
|
<th class="text-center">{% translate "Name" %}</th>
|
||||||
|
<th class="text-center">{% translate "Corp" %}</th>
|
||||||
|
<th class="text-center">{% translate "Alliance" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for char in characters %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">
|
||||||
|
<img class="ra-avatar rounded-circle" src="{{ char.portrait_url_32 }}" alt="{{ char.character_name }}">
|
||||||
|
</td>
|
||||||
|
<td class="text-center">{{ char.character_name }}</td>
|
||||||
|
<td class="text-center">{{ char.corporation_name }}</td>
|
||||||
|
<td class="text-center">{{ char.alliance_name|default_if_none:"" }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
<div class="col-12 col-xl-4 align-self-stretch py-2 ps-xl-2">
|
||||||
|
<div class="card h-100">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4 class="card-title text-center">{% translate "Membership" %}</h4>
|
||||||
|
<div class="card-body">
|
||||||
|
<div style="height: 300px; overflow-y:auto;">
|
||||||
|
<h5 class="text-center">{% translate "State:" %} {{ request.user.profile.state }}</h5>
|
||||||
|
<table class="table">
|
||||||
|
{% for group in groups %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ group.name }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,190 +1,15 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Dashboard" %}{% endblock %}
|
{% block page_title %}{% translate "Dashboard" %}{% endblock %}
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Dashboard" %}
|
||||||
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 class="page-header text-center">{% translate "Dashboard" %}</h1>
|
<div class="d-flex justify-content-around align-self-center flex-wrap">
|
||||||
{% if user.is_staff %}
|
{% for dash in views %}
|
||||||
{% include 'allianceauth/admin-status/include.html' %}
|
{{ dash | safe }}
|
||||||
{% endif %}
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<div class="row vertical-flexbox-row2">
|
|
||||||
<div class="col-sm-6 text-center">
|
|
||||||
<div class="panel panel-primary" style="height:100%">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title">
|
|
||||||
{% blocktranslate with state=request.user.profile.state %}
|
|
||||||
Main Character (State: {{ state }})
|
|
||||||
{% endblocktranslate %}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
{% if request.user.profile.main_character %}
|
|
||||||
{% with request.user.profile.main_character as main %}
|
|
||||||
<div class="hidden-xs">
|
|
||||||
<div class="col-lg-4 col-sm-2">
|
|
||||||
<table class="table">
|
|
||||||
<tr>
|
|
||||||
<td class="text-center">
|
|
||||||
<img class="ra-avatar" src="{{ main.portrait_url_128 }}" alt="{{ main.character_name }}">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="text-center">{{ main.character_name }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-4 col-sm-2">
|
|
||||||
<table class="table">
|
|
||||||
<tr>
|
|
||||||
<td class="text-center">
|
|
||||||
<img class="ra-avatar" src="{{ main.corporation_logo_url_128 }}" alt="{{ main.corporation_name }}">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="text-center">{{ main.corporation_name }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-4 col-sm-2">
|
|
||||||
{% if main.alliance_id %}
|
|
||||||
<table class="table">
|
|
||||||
<tr>
|
|
||||||
<td class="text-center">
|
|
||||||
<img class="ra-avatar" src="{{ main.alliance_logo_url_128 }}" alt="{{ main.alliance_name }}">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="text-center">{{ main.alliance_name }}</td>
|
|
||||||
<tr>
|
|
||||||
</table>
|
|
||||||
{% elif main.faction_id %}
|
|
||||||
<table class="table">
|
|
||||||
<tr>
|
|
||||||
<td class="text-center">
|
|
||||||
<img class="ra-avatar" src="{{ main.faction_logo_url_128 }}" alt="{{ main.faction_name }}">
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="text-center">{{ main.faction_name }}</td>
|
|
||||||
<tr>
|
|
||||||
</table>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="table visible-xs-block">
|
|
||||||
<p>
|
|
||||||
<img class="ra-avatar" src="{{ main.portrait_url_64 }}" alt="{{ main.corporation_name }}">
|
|
||||||
<img class="ra-avatar" src="{{ main.corporation_logo_url_64 }}" alt="{{ main.corporation_name }}">
|
|
||||||
{% if main.alliance_id %}
|
|
||||||
<img class="ra-avatar" src="{{ main.alliance_logo_url_64 }}" alt="{{ main.alliance_name }}">
|
|
||||||
{% endif %}
|
|
||||||
{% if main.faction_id %}
|
|
||||||
<img class="ra-avatar" src="{{ main.faction_logo_url_64 }}" alt="{{ main.faction_name }}">
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>{{ main.character_name }}</strong><br>
|
|
||||||
{{ main.corporation_name }}<br>
|
|
||||||
{% if main.alliance_id %}
|
|
||||||
{{ main.alliance_name }}<br>
|
|
||||||
{% endif %}
|
|
||||||
{% if main.faction_id %}
|
|
||||||
{{ main.faction_name }}
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{% endwith %}
|
|
||||||
{% else %}
|
|
||||||
<div class="alert alert-danger" role="alert">
|
|
||||||
{% translate "No main character set." %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="clearfix"></div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<p>
|
|
||||||
<a href="{% url 'authentication:add_character' %}" class="btn btn-block btn-info"
|
|
||||||
title="Add Character">{% translate 'Add Character' %}</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<p>
|
|
||||||
<a href="{% url 'authentication:change_main_character' %}" class="btn btn-block btn-info"
|
|
||||||
title="Change Main Character">{% translate "Change Main" %}</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6 text-center">
|
|
||||||
<div class="panel panel-success" style="height:100%">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title">{% translate "Group Memberships" %}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<div style="height: 240px;overflow-y:auto;">
|
|
||||||
<table class="table table-aa">
|
|
||||||
{% for group in groups %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ group.name }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="clearfix"></div>
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title text-center" style="text-align: center">
|
|
||||||
{% translate 'Characters' %}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<table class="table table-aa hidden-xs">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="text-center"></th>
|
|
||||||
<th class="text-center">{% translate 'Name' %}</th>
|
|
||||||
<th class="text-center">{% translate 'Corp' %}</th>
|
|
||||||
<th class="text-center">{% translate 'Alliance' %}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for char in characters %}
|
|
||||||
<tr>
|
|
||||||
<td class="text-center">
|
|
||||||
<img class="ra-avatar img-circle" src="{{ char.portrait_url_32 }}" alt="{{ char.character_name }}">
|
|
||||||
</td>
|
|
||||||
<td class="text-center">{{ char.character_name }}</td>
|
|
||||||
<td class="text-center">{{ char.corporation_name }}</td>
|
|
||||||
<td class="text-center">{{ char.alliance_name|default:"" }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table class="table table-aa visible-xs-block" style="width: 100%">
|
|
||||||
<tbody>
|
|
||||||
{% for char in characters %}
|
|
||||||
<tr>
|
|
||||||
<td class="text-center" style="vertical-align: middle">
|
|
||||||
<img class="ra-avatar img-circle" src="{{ char.portrait_url_32 }}" alt="{{ char.character_name }}">
|
|
||||||
</td>
|
|
||||||
<td class="text-center" style="vertical-align: middle; width: 100%">
|
|
||||||
<strong>{{ char.character_name }}</strong><br>
|
|
||||||
{{ char.corporation_name }}<br>
|
|
||||||
{{ char.alliance_name|default:"" }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,62 +1,85 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Dashboard" %}{% endblock %}
|
{% block page_title %}
|
||||||
|
{% translate "Token Management" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Token Management" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 class="page-header text-center">{% translate "Token Management" %}</h1>
|
<div>
|
||||||
<div class="col-sm-12">
|
<p class="mb-3">
|
||||||
<table class="table table-aa" id="table_tokens" style="width:100%">
|
{% translate "This page is a best attempt, but backups or database logs can still contain your tokens. Always revoke tokens on https://community.eveonline.com/support/third-party-applications/ where possible."|urlize %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table class="table" id="table_tokens" style="width: 100%;">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% translate "Scopes" %}</th>
|
<th>{% translate "Scopes" %}</th>
|
||||||
<th class="text-right">{% translate "Actions" %}</th>
|
<th class="text-end">{% translate "Actions" %}</th>
|
||||||
<th>{% translate "Character" %}</th>
|
<th>{% translate "Character" %}</th>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for t in tokens %}
|
{% for t in tokens %}
|
||||||
<tr>
|
<tr>
|
||||||
<td styl="white-space:initial;">{% for s in t.scopes.all %}<span class="label label-default">{{s.name}}</span> {% endfor %}</td>
|
<td style="white-space:initial;">
|
||||||
<td nowrap class="text-right"><a href="{% url 'authentication:token_delete' t.id %}" class="btn btn-danger"><i class="fas fa-trash"></i></a> <a href="{% url 'authentication:token_refresh' t.id %}" class="btn btn-success"><i class="fas fa-sync-alt"></i></a></td>
|
{% for s in t.scopes.all %}
|
||||||
|
<span class="badge bg-secondary">{{ s.name }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td nowrap class="text-end">
|
||||||
|
<a href="{% url 'authentication:token_delete' t.id %}" class="btn btn-danger"><i class="fa-solid fa-trash-can"></i></a>
|
||||||
|
<a href="{% url 'authentication:token_refresh' t.id %}" class="btn btn-success"><i class="fa-solid fa-rotate"></i></a>
|
||||||
|
</td>
|
||||||
|
|
||||||
<td>{{ t.character_name }}</td>
|
<td>{{ t.character_name }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% translate "This page is a best attempt, but backups or database logs can still contain your tokens. Always revoke tokens on https://community.eveonline.com/support/third-party-applications/ where possible."|urlize %}
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block extra_javascript %}
|
{% block extra_javascript %}
|
||||||
{% include 'bundles/datatables-js.html' %}
|
{% include "bundles/datatables-js-bs5.html" %}
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block extra_css %}
|
<script>
|
||||||
{% include 'bundles/datatables-css.html' %}
|
$(document).ready(() => {
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block extra_script %}
|
|
||||||
$(document).ready(function(){
|
|
||||||
let grp = 2;
|
let grp = 2;
|
||||||
var table = $('#table_tokens').DataTable({
|
|
||||||
"columnDefs": [{ orderable: false, targets: [0,1] },{ "visible": false, "targets": grp }],
|
const table = $('#table_tokens').DataTable({
|
||||||
"order": [[grp, 'asc']],
|
'columnDefs': [{orderable: false, targets: [0, 1]}, {
|
||||||
"drawCallback": function (settings) {
|
'visible': false,
|
||||||
|
'targets': grp
|
||||||
|
}],
|
||||||
|
'order': [[grp, 'asc']],
|
||||||
|
'drawCallback': function (settings) {
|
||||||
var api = this.api();
|
var api = this.api();
|
||||||
var rows = api.rows({page: 'current'}).nodes();
|
var rows = api.rows({page: 'current'}).nodes();
|
||||||
var last = null;
|
var last = null;
|
||||||
api.column(grp, {page: 'current'})
|
api.column(grp, {page: 'current'})
|
||||||
.data()
|
.data()
|
||||||
.each(function (group, i) {
|
.each((group, i) => {
|
||||||
if (last !== group) {
|
if (last !== group) {
|
||||||
$(rows).eq(i).before('<tr class="info"><td colspan="3">' + group + '</td></tr>');
|
$(rows).eq(i).before(`<tr class="h5 table-primary"><td colspan="3">${group}</td></tr>`);
|
||||||
|
|
||||||
last = group;
|
last = group;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
"stateSave": true,
|
'stateSave': true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
{% endblock %}
|
</script>
|
||||||
|
{% endblock extra_javascript %}
|
||||||
|
|
||||||
|
{% block extra_css %}
|
||||||
|
{% include "bundles/datatables-css-bs5.html" %}
|
||||||
|
{% endblock extra_css %}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="author" content="">
|
<meta name="author" content="">
|
||||||
|
<!-- TODO Bundle all the site specific stuff up into its own template for easy override -->
|
||||||
<meta property="og:title" content="{{ SITE_NAME }}">
|
<meta property="og:title" content="{{ SITE_NAME }}">
|
||||||
<meta property="og:image" content="{{ SITE_URL }}{% static 'allianceauth/icons/apple-touch-icon.png' %}">
|
<meta property="og:image" content="{{ SITE_URL }}{% static 'allianceauth/icons/apple-touch-icon.png' %}">
|
||||||
<meta property="og:description" content="Alliance Auth - An auth system for EVE Online to help in-game organizations manage online service access.">
|
<meta property="og:description" content="Alliance Auth - An auth system for EVE Online to help in-game organizations manage online service access.">
|
||||||
@@ -15,8 +16,9 @@
|
|||||||
|
|
||||||
<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.html' %}
|
{% include 'bundles/bootstrap-css-bs5.html' %}
|
||||||
{% include 'bundles/fontawesome.html' %}
|
{% include 'bundles/fontawesome.html' %}
|
||||||
|
|
||||||
{% block extra_include %}
|
{% block extra_include %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -29,25 +31,23 @@
|
|||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-transparent {
|
.card-login {
|
||||||
background: rgba(48, 48, 48, 0.7);
|
background: rgba(48 48 48 / 0.7);
|
||||||
color: #ffffff;
|
color: rgb(255 255 255);
|
||||||
padding-bottom: 21px;
|
padding-bottom: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-body {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#lang-select {
|
#lang-select {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
{% block extra_style %}
|
{% block extra_style %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container" style="margin-top:150px;">
|
<div class="container" style="margin-top:150px;">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<form action="{% url 'set_language' %}" method="post">
|
<form action="{% url 'set_language' %}" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<select onchange="this.form.submit()" class="form-control" id="lang-select" name="language">
|
<select onchange="this.form.submit()" class="form-control" id="lang-select" name="language">
|
||||||
{% get_language_info_list for LANGUAGES as languages %}
|
{% get_language_info_list for LANGUAGES as languages %}
|
||||||
|
|
||||||
{% for language in languages %}
|
{% for language in languages %}
|
||||||
<option lang="{{ language.code }}" value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
|
<option lang="{{ language.code }}" value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
|
||||||
{{ language.name_local|capfirst }} ({{ language.code }})
|
{{ language.name_local|capfirst }} ({{ language.code }})
|
||||||
|
|||||||
@@ -3,16 +3,17 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-md-4 col-md-offset-4">
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-4">
|
||||||
{% 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>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="panel panel-default panel-transparent">
|
<div class="card card-login border-secondary p-3">
|
||||||
<div class="panel-body">
|
<div class="card-body">
|
||||||
<div class="col-md-12">
|
<div class="text-center">
|
||||||
{% block middle_box_content %}
|
{% block middle_box_content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
@@ -20,22 +21,23 @@
|
|||||||
|
|
||||||
{% include 'public/lang_select.html' %}
|
{% include 'public/lang_select.html' %}
|
||||||
|
|
||||||
<p class="text-center" style="margin-top: 2rem;">
|
<p class="text-center mt-3">
|
||||||
{% translate "For information on SSO, ESI and security read the CCP Dev Blog" %}<br>
|
{% translate "For information on SSO, ESI and security read the CCP Dev Blog" %}<br>
|
||||||
<a href="https://www.eveonline.com/article/introducing-esi" target="_blank" rel="noopener noreferrer">
|
<a class="text-reset" href="https://www.eveonline.com/news/view/introducing-esi" target="_blank" rel="noopener noreferrer">
|
||||||
{% translate "Introducing ESI - A New API For Eve Online" %}
|
{% translate "Introducing ESI - A New API For EVE Online" %}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<a href="https://community.eveonline.com/support/third-party-applications/" target="_blank" rel="noopener noreferrer">
|
<a class="text-reset" href="https://community.eveonline.com/support/third-party-applications/" target="_blank" rel="noopener noreferrer">
|
||||||
{% translate "Manage ESI Applications" %}
|
{% translate "Manage ESI Applications" %}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_include %}
|
{% block extra_include %}
|
||||||
{% include 'bundles/bootstrap-js.html' %}
|
{% include 'bundles/bootstrap-js-bs5.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
{% block page_title %}{% translate "Registration" %}{% endblock %}
|
{% block page_title %}{% translate "Registration" %}{% endblock %}
|
||||||
|
|
||||||
{% block extra_include %}
|
{% block extra_include %}
|
||||||
{% include 'bundles/bootstrap-css.html' %}
|
{% include 'bundles/bootstrap-css-bs5.html' %}
|
||||||
{% include 'bundles/fontawesome.html' %}
|
{% include 'bundles/fontawesome.html' %}
|
||||||
{% include 'bundles/bootstrap-js.html' %}
|
{% include 'bundles/bootstrap-js-bs5.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
{% extends 'public/middle_box.html' %}
|
{% extends 'public/middle_box.html' %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block middle_box_content %}
|
{% block middle_box_content %}
|
||||||
<div class="alert alert-danger">{% translate 'Invalid or expired activation link.' %}</div>
|
<div class="alert alert-danger">{% translate 'Invalid or expired activation link.' %}</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from allianceauth.hooks import get_hooks
|
||||||
|
|
||||||
from django_registration.backends.activation.views import (
|
from django_registration.backends.activation.views import (
|
||||||
REGISTRATION_SALT, ActivationView as BaseActivationView,
|
REGISTRATION_SALT, ActivationView as BaseActivationView,
|
||||||
@@ -42,23 +43,51 @@ def index(request):
|
|||||||
return redirect('authentication:dashboard')
|
return redirect('authentication:dashboard')
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
def dashboard_groups(request):
|
||||||
def dashboard(request):
|
|
||||||
groups = request.user.groups.all()
|
groups = request.user.groups.all()
|
||||||
if _has_auto_groups:
|
if _has_auto_groups:
|
||||||
groups = groups\
|
groups = groups\
|
||||||
.filter(managedalliancegroup__isnull=True)\
|
.filter(managedalliancegroup__isnull=True)\
|
||||||
.filter(managedcorpgroup__isnull=True)
|
.filter(managedcorpgroup__isnull=True)
|
||||||
groups = groups.order_by('name')
|
groups = groups.order_by('name')
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'groups': groups,
|
||||||
|
}
|
||||||
|
return render_to_string('authentication/dashboard.groups.html', context=context, request=request)
|
||||||
|
|
||||||
|
|
||||||
|
def dashboard_characters(request):
|
||||||
characters = EveCharacter.objects\
|
characters = EveCharacter.objects\
|
||||||
.filter(character_ownership__user=request.user)\
|
.filter(character_ownership__user=request.user)\
|
||||||
.select_related()\
|
.select_related()\
|
||||||
.order_by('character_name')
|
.order_by('character_name')
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'groups': groups,
|
|
||||||
'characters': characters
|
'characters': characters
|
||||||
}
|
}
|
||||||
|
return render_to_string('authentication/dashboard.characters.html', context=context, request=request)
|
||||||
|
|
||||||
|
|
||||||
|
def dashboard_admin(request):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
return render_to_string('allianceauth/admin-status/include.html', request=request)
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def dashboard(request):
|
||||||
|
_dash_items = list()
|
||||||
|
hooks = get_hooks('dashboard_hook')
|
||||||
|
items = [fn() for fn in hooks]
|
||||||
|
items.sort(key=lambda i: i.order)
|
||||||
|
for item in items:
|
||||||
|
_dash_items.append(item.render(request))
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'views': _dash_items,
|
||||||
|
}
|
||||||
return render(request, 'authentication/dashboard.html', context)
|
return render(request, 'authentication/dashboard.html', context)
|
||||||
|
|
||||||
|
|
||||||
@@ -171,7 +200,13 @@ def sso_login(request, token):
|
|||||||
request.session['registration_uid'] = user.pk
|
request.session['registration_uid'] = user.pk
|
||||||
# Go to Step 2
|
# Go to Step 2
|
||||||
return redirect('registration_register')
|
return redirect('registration_register')
|
||||||
messages.error(request, _('Unable to authenticate as the selected character.'))
|
# Logging in with an alt is not allowed due to security concerns.
|
||||||
|
token.delete()
|
||||||
|
messages.error(
|
||||||
|
request,
|
||||||
|
_('Unable to authenticate as the selected character. '
|
||||||
|
'Please log in with the main character associated with this account.')
|
||||||
|
)
|
||||||
return redirect(settings.LOGIN_URL)
|
return redirect(settings.LOGIN_URL)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,13 +12,14 @@ class StartProject(BaseStartProject):
|
|||||||
parser.add_argument('--python', help='The path to the python executable.')
|
parser.add_argument('--python', help='The path to the python executable.')
|
||||||
parser.add_argument('--celery', help='The path to the celery executable.')
|
parser.add_argument('--celery', help='The path to the celery executable.')
|
||||||
parser.add_argument('--gunicorn', help='The path to the gunicorn executable.')
|
parser.add_argument('--gunicorn', help='The path to the gunicorn executable.')
|
||||||
|
parser.add_argument('--memmon', help='The path to the memmon executable.')
|
||||||
|
|
||||||
|
|
||||||
def create_project(parser, options, args):
|
def create_project(parser, options, args):
|
||||||
# Validate args
|
# Validate args
|
||||||
if len(args) < 2:
|
if len(args) < 2:
|
||||||
parser.error("Please specify a name for your Alliance Auth installation.")
|
parser.error("Please specify a name for your Alliance Auth installation.")
|
||||||
elif len(args) > 3:
|
elif len(args) > 4:
|
||||||
parser.error("Too many arguments.")
|
parser.error("Too many arguments.")
|
||||||
|
|
||||||
# First find the path to Alliance Auth
|
# First find the path to Alliance Auth
|
||||||
@@ -32,6 +33,7 @@ def create_project(parser, options, args):
|
|||||||
'python': shutil.which('python'),
|
'python': shutil.which('python'),
|
||||||
'gunicorn': shutil.which('gunicorn'),
|
'gunicorn': shutil.which('gunicorn'),
|
||||||
'celery': shutil.which('celery'),
|
'celery': shutil.which('celery'),
|
||||||
|
'memmon': shutil.which('memmon'),
|
||||||
'extensions': ['py', 'conf', 'json'],
|
'extensions': ['py', 'conf', 'json'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
from allianceauth.menu.hooks import MenuItemHook
|
||||||
|
from allianceauth.services.hooks import UrlHook
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from allianceauth import hooks
|
from allianceauth import hooks
|
||||||
from allianceauth.corputils import urls
|
from allianceauth.corputils import urls
|
||||||
@@ -9,7 +10,7 @@ class CorpStats(MenuItemHook):
|
|||||||
MenuItemHook.__init__(
|
MenuItemHook.__init__(
|
||||||
self,
|
self,
|
||||||
_('Corporation Stats'),
|
_('Corporation Stats'),
|
||||||
'fas fa-share-alt fa-fw',
|
'fa-solid fa-share-nodes',
|
||||||
'corputils:view',
|
'corputils:view',
|
||||||
navactive=['corputils:']
|
navactive=['corputils:']
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,37 +1,63 @@
|
|||||||
{% extends 'allianceauth/base.html' %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block page_title %}{% translate "Corporation Member Data" %}{% endblock %}
|
|
||||||
{% block content %}
|
{% block page_title %}
|
||||||
<div class="col-lg-12">
|
{% translate "Corporation Member Data" %}
|
||||||
<h1 class="page-header text-center">{% translate "Corporation Member Data" %}</h1>
|
{% endblock page_title %}
|
||||||
<div class="col-lg-10 col-lg-offset-1 container">
|
|
||||||
<nav class="navbar navbar-default">
|
{% block header_nav_brand %}
|
||||||
<div class="container-fluid">
|
{% translate "Corporation Member Data" %}
|
||||||
<ul class="nav navbar-nav">
|
{% endblock header_nav_brand %}
|
||||||
<li class="dropdown">
|
|
||||||
<a href="#" id="dLabel" class="dropdown-toggle" role="button" data-toggle="dropdown" aria-haspopup="false" aria-expanded="false">{% translate "Corporations" %}<span class="caret"></span></a>
|
{% block header_nav_collapse_left %}
|
||||||
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false">
|
||||||
|
{% translate "Corporations" %}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<ul class="dropdown-menu">
|
||||||
{% for corpstat in available %}
|
{% for corpstat in available %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'corputils:view_corp' corpstat.corp.corporation_id %}">{{ corpstat.corp.corporation_name }}</a>
|
<a class="dropdown-item" href="{% url 'corputils:view_corp' corpstat.corp.corporation_id %}">
|
||||||
|
{{ corpstat.corp.corporation_name }}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
{% if perms.corputils.add_corpstats %}
|
{% if perms.corputils.add_corpstats %}
|
||||||
|
{% if available.count >= 1 %}
|
||||||
|
<li> </li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'corputils:add' %}">{% translate "Add" %}</a>
|
<a class="dropdown-item" href="{% url 'corputils:add' %}">
|
||||||
|
{% translate "Add corporation" %}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block header_nav_collapse_right %}
|
||||||
|
<li class="nav-item">
|
||||||
<form class="navbar-form navbar-right" role="search" action="{% url 'corputils:search' %}" method="GET">
|
<form class="navbar-form navbar-right" role="search" action="{% url 'corputils:search' %}" method="GET">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control" name="search_string" placeholder="{% if search_string %}{{ search_string }}{% else %}{% translate "Search all corporations..." %}{% endif %}">
|
<input
|
||||||
|
type="text"
|
||||||
|
class="form-control"
|
||||||
|
name="search_string"
|
||||||
|
placeholder="{% if search_string %}{{ search_string }}{% else %}{% translate 'Search all corporations...' %}{% endif %}"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</li>
|
||||||
</nav>
|
|
||||||
{% block member_data %}{% endblock %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
{% block member_data %}
|
||||||
|
{% endblock member_data %}
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
|
|||||||
@@ -1,93 +1,143 @@
|
|||||||
{% extends 'corputils/base.html' %}
|
{% extends 'corputils/base.html' %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load humanize %}
|
{% load humanize %}
|
||||||
|
|
||||||
{% block member_data %}
|
{% block member_data %}
|
||||||
{% if corpstats %}
|
{% if corpstats %}
|
||||||
<div class="row">
|
<div>
|
||||||
<div class="col-lg-12 text-center">
|
<table class="table text-center">
|
||||||
<table class="table">
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center col-lg-6{% if corpstats.corp.alliance %}{% else %}col-lg-offset-3{% endif %}">
|
<td>
|
||||||
<img class="ra-avatar" src="{{ corpstats.corp.logo_url_64 }}" alt="{{ corpstats.corp.corporation_name }}">
|
<img class="ra-avatar" src="{{ corpstats.corp.logo_url_64 }}" alt="{{ corpstats.corp.corporation_name }}">
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
{% if corpstats.corp.alliance %}
|
{% if corpstats.corp.alliance %}
|
||||||
<td class="text-center col-lg-6">
|
<td>
|
||||||
<img class="ra-avatar" src="{{ corpstats.corp.alliance.logo_url_64 }}" alt="{{ corpstats.corp.alliance.alliance_name }}">
|
<img class="ra-avatar" src="{{ corpstats.corp.alliance.logo_url_64 }}" alt="{{ corpstats.corp.alliance.alliance_name }}">
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center"><h4>{{ corpstats.corp.corporation_name }}</h4></td>
|
<td><p class="h4">{{ corpstats.corp.corporation_name }}</p></td>
|
||||||
|
|
||||||
{% if corpstats.corp.alliance %}
|
{% if corpstats.corp.alliance %}
|
||||||
<td class="text-center"><h4>{{ corpstats.corp.alliance.alliance_name }}</h4></td>
|
<td><p class="h4">{{ corpstats.corp.alliance.alliance_name }}</p></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="card card-default mt-4">
|
||||||
<div class="col-lg-12">
|
<div class="card-header clearfix" role="tablist">
|
||||||
<div class="panel panel-default">
|
<ul class="nav nav-pills text-right float-start">
|
||||||
<div class="panel-heading">
|
<li class="nav-item" role="presentation">
|
||||||
<ul class="nav nav-pills pull-left">
|
<a
|
||||||
<li class="active"><a href="#mains" data-toggle="pill">{% translate 'Mains' %} ({{ total_mains }})</a></li>
|
class="nav-link active"
|
||||||
<li><a href="#members" data-toggle="pill">{% translate 'Members' %} ({{ corpstats.member_count }})</a></li>
|
id="mains"
|
||||||
<li><a href="#unregistered" data-toggle="pill">{% translate 'Unregistered' %} ({{ unregistered.count }})</a></li>
|
data-bs-toggle="tab"
|
||||||
|
href="#tab-mains"
|
||||||
|
role="tab"
|
||||||
|
aria-controls="tab-mains"
|
||||||
|
aria-selected="true"
|
||||||
|
>
|
||||||
|
{% translate 'Mains' %} ({{ total_mains }})
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<a
|
||||||
|
class="nav-link"
|
||||||
|
id="members"
|
||||||
|
data-bs-toggle="tab"
|
||||||
|
href="#tab-members"
|
||||||
|
role="tab"
|
||||||
|
aria-controls="tab-members"
|
||||||
|
aria-selected="false"
|
||||||
|
>
|
||||||
|
{% translate 'Members' %} ({{ corpstats.member_count }})
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-item">
|
||||||
|
<a
|
||||||
|
class="nav-link"
|
||||||
|
id="unregistered"
|
||||||
|
data-bs-toggle="tab"
|
||||||
|
href="#tab-unregistered"
|
||||||
|
role="tab"
|
||||||
|
aria-controls="tab-unregistered"
|
||||||
|
aria-selected="false"
|
||||||
|
>
|
||||||
|
{% translate 'Unregistered' %} ({{ unregistered.count }})
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="pull-right hidden-xs">
|
|
||||||
{% translate "Last update:" %} {{ corpstats.last_update|naturaltime }}
|
<div class="float-end d-none d-sm-block">
|
||||||
<a class="btn btn-success" type="button" href="{% url 'corputils:update' corpstats.corp.corporation_id %}" title="Update Now">
|
{% translate "Last update:" %} {{ corpstats.last_update|naturaltime }}
|
||||||
<span class="glyphicon glyphicon-refresh"></span>
|
|
||||||
|
<a
|
||||||
|
class="btn btn-success btn-sm ms-2"
|
||||||
|
type="button"
|
||||||
|
href="{% url 'corputils:update' corpstats.corp.corporation_id %}"
|
||||||
|
title="{% translate 'Update Now' %}"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-rotate"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
|
||||||
|
<div class="card-body">
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane fade in active" id="mains">
|
<div class="tab-pane fade show active" id="tab-mains" role="tabpanel" aria-labelledby="tab-mains">
|
||||||
{% if mains %}
|
{% if mains %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover" id="table-mains">
|
<table class="table table-hover" id="table-mains">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="height:1em;"><!-- Must have text or height to prevent clipping --></th>
|
<th>{% translate "Main character" %}</th>
|
||||||
<th></th>
|
<th>{% translate "Registered characters" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for id, main in mains.items %}
|
{% for id, main in mains.items %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center" style="vertical-align:middle">
|
<td class="text-center" style="vertical-align: middle;">
|
||||||
<div class="thumbnail" style="border: 0 none; box-shadow: none; background: transparent;">
|
<div class="thumbnail" style="border: 0 none; box-shadow: none; background: transparent;">
|
||||||
<img src="{{ main.main.portrait_url_64 }}" class="img-circle" alt="{{ main.main }}">
|
<img src="{{ main.main.portrait_url_64 }}" class="img-circle" alt="{{ main.main }}">
|
||||||
<div class="caption text-center">
|
<div class="caption">
|
||||||
{{ main.main }}
|
{{ main.main }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
{% for alt in main.alts %}
|
{% for alt in main.alts|dictsort:"character_name" %}
|
||||||
{% if forloop.first %}
|
{% if forloop.first %}
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th class="text-center">{% translate "Character" %}</th>
|
<th>{% translate "Character" %}</th>
|
||||||
<th class="text-center">{% translate "Corporation" %}</th>
|
<th>{% translate "Corporation" %}</th>
|
||||||
<th class="text-center">{% translate "Alliance" %}</th>
|
<th>{% translate "Alliance" %}</th>
|
||||||
<th class="text-center"></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center" style="width:5%">
|
<td style="width: 5%;">
|
||||||
<div class="thumbnail" style="border: 0 none; box-shadow: none; background: transparent;">
|
<div class="thumbnail" style="border: 0 none; box-shadow: none; background: transparent;">
|
||||||
<img src="{{ alt.portrait_url_32 }}" class="img-circle" alt="{{ alt.character_name }}">
|
<img src="{{ alt.portrait_url_32 }}" class="img-circle" alt="{{ alt.character_name }}">
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center" style="width:30%">{{ alt.character_name }}</td>
|
<td style="width: 30%;">{{ alt.character_name }}</td>
|
||||||
<td class="text-center" style="width:30%">{{ alt.corporation_name }}</td>
|
<td style="width: 30%;">{{ alt.corporation_name }}</td>
|
||||||
<td class="text-center" style="width:30%">{{ alt.alliance_name }}</td>
|
<td style="width: 30%;">{{ alt.alliance_name|default_if_none:"" }}</td>
|
||||||
<td class="text-center" style="width:5%">
|
<td style="width: 5%;">
|
||||||
<a href="https://zkillboard.com/character/{{ alt.character_id }}/" class="label label-danger" target="_blank">
|
<a href="https://zkillboard.com/character/{{ alt.character_id }}/" class="badge bg-danger" target="_blank">
|
||||||
{% translate "Killboard" %}
|
{% translate "Killboard" %}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
@@ -102,43 +152,46 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane fade" id="members">
|
|
||||||
|
<div class="tab-pane fade" id="tab-members" role="tabpanel" aria-labelledby="tab-members">
|
||||||
{% if members %}
|
{% if members %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover" id="table-members">
|
<table class="table table-hover" id="table-members">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th class="text-center">{% translate "Character" %}</th>
|
<th>{% translate "Character" %}</th>
|
||||||
<th class="text-center"></th>
|
<th></th>
|
||||||
<th class="text-center">{% translate "Main Character" %}</th>
|
<th>{% translate "Main Character" %}</th>
|
||||||
<th class="text-center">{% translate "Main Corporation" %}</th>
|
<th>{% translate "Main Corporation" %}</th>
|
||||||
<th class="text-center">{% translate "Main Alliance" %}</th>
|
<th>{% translate "Main Alliance" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for member in members %}
|
{% for member in members %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><img src="{{ member.portrait_url }}" class="img-circle" alt="{{ member }}"></td>
|
<td><img src="{{ member.portrait_url }}" class="img-circle" alt="{{ member }}"></td>
|
||||||
<td class="text-center">{{ member }}</td>
|
<td>{{ member }}</td>
|
||||||
<td class="text-center">
|
<td>
|
||||||
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="label label-danger" target="_blank">{% translate "Killboard" %}</a>
|
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="badge bg-danger" target="_blank">{% translate "Killboard" %}</a>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">{{ member.character_ownership.user.profile.main_character.character_name }}</td>
|
<td>{{ member.character_ownership.user.profile.main_character.character_name }}</td>
|
||||||
<td class="text-center">{{ member.character_ownership.user.profile.main_character.corporation_name }}</td>
|
<td>{{ member.character_ownership.user.profile.main_character.corporation_name }}</td>
|
||||||
<td class="text-center">{{ member.character_ownership.user.profile.main_character.alliance_name }}</td>
|
<td>{{ member.character_ownership.user.profile.main_character.alliance_name|default_if_none:"" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% for member in unregistered %}
|
{% for member in unregistered %}
|
||||||
<tr class="danger">
|
<tr class="table-danger">
|
||||||
<td><img src="{{ member.portrait_url }}" class="img-circle" alt="{{ member.character_name }}"></td>
|
<td><img src="{{ member.portrait_url }}" class="img-circle" alt="{{ member.character_name }}"></td>
|
||||||
<td class="text-center">{{ member.character_name }}</td>
|
<td>{{ member.character_name }}</td>
|
||||||
<td class="text-center">
|
<td>
|
||||||
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="label label-danger" target="_blank">{% translate "Killboard" %}</a>
|
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="badge bg-danger" target="_blank">{% translate "Killboard" %}</a>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center"></td>
|
<td></td>
|
||||||
<td class="text-center"></td>
|
<td></td>
|
||||||
<td class="text-center"></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -146,24 +199,26 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane fade" id="unregistered">
|
|
||||||
|
<div class="tab-pane fade" id="tab-unregistered" role="tabpanel" aria-labelledby="tab-unregistered">
|
||||||
{% if unregistered %}
|
{% if unregistered %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover" id="table-unregistered">
|
<table class="table table-hover" id="table-unregistered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th class="text-center">{% translate "Character" %}</th>
|
<th>{% translate "Character" %}</th>
|
||||||
<th class="text-center"></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for member in unregistered %}
|
{% for member in unregistered %}
|
||||||
<tr class="danger">
|
<tr class="table-danger">
|
||||||
<td><img src="{{ member.portrait_url }}" class="img-circle" alt="{{ member.character_name }}"></td>
|
<td><img src="{{ member.portrait_url }}" class="img-circle" alt="{{ member.character_name }}"></td>
|
||||||
<td class="text-center">{{ member.character_name }}</td>
|
<td>{{ member.character_name }}</td>
|
||||||
<td class="text-center">
|
<td>
|
||||||
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="label label-danger" target="_blank">
|
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="badge bg-danger" target="_blank">
|
||||||
{% translate "Killboard" %}
|
{% translate "Killboard" %}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
@@ -177,18 +232,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_javascript %}
|
{% block extra_javascript %}
|
||||||
{% include 'bundles/datatables-js.html' %}
|
{% include 'bundles/datatables-js-bs5.html' %}
|
||||||
{% endblock %}
|
|
||||||
{% block extra_css %}
|
<script>
|
||||||
{% include 'bundles/datatables-css.html' %}
|
$(document).ready(() => {
|
||||||
{% endblock %}
|
|
||||||
{% block extra_script %}
|
|
||||||
$(document).ready(function(){
|
|
||||||
$('#table-mains').DataTable({
|
$('#table-mains').DataTable({
|
||||||
"columnDefs": [
|
"columnDefs": [
|
||||||
{ "sortable": false, "targets": [1] },
|
{ "sortable": false, "targets": [1] },
|
||||||
@@ -196,6 +247,7 @@
|
|||||||
"stateSave": true,
|
"stateSave": true,
|
||||||
"stateDuration": 0
|
"stateDuration": 0
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#table-members').DataTable({
|
$('#table-members').DataTable({
|
||||||
"columnDefs": [
|
"columnDefs": [
|
||||||
{ "searchable": false, "targets": [0, 2] },
|
{ "searchable": false, "targets": [0, 2] },
|
||||||
@@ -205,6 +257,7 @@
|
|||||||
"stateSave": true,
|
"stateSave": true,
|
||||||
"stateDuration": 0
|
"stateDuration": 0
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#table-unregistered').DataTable({
|
$('#table-unregistered').DataTable({
|
||||||
"columnDefs": [
|
"columnDefs": [
|
||||||
{ "searchable": false, "targets": [0, 2] },
|
{ "searchable": false, "targets": [0, 2] },
|
||||||
@@ -214,6 +267,10 @@
|
|||||||
"stateSave": true,
|
"stateSave": true,
|
||||||
"stateDuration": 0
|
"stateDuration": 0
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_css %}
|
||||||
|
{% include 'bundles/datatables-css-bs5.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,33 +1,36 @@
|
|||||||
{% extends "corputils/base.html" %}
|
{% extends "corputils/base.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block member_data %}
|
{% block member_data %}
|
||||||
<div class="panel panel-default">
|
<div class="card card-default">
|
||||||
<div class="panel-heading clearfix">
|
<div class="card-header clearfix">
|
||||||
<div class="panel-title pull-left">{% translate "Search Results" %}</div>
|
<div class="card-title">{% translate "Search Results" %}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
|
||||||
|
<div class="card-body mt-2">
|
||||||
<table class="table table-hover" id="table-search">
|
<table class="table table-hover" id="table-search">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center"></th>
|
<th></th>
|
||||||
<th class="text-center">{% translate "Character" %}</th>
|
<th>{% translate "Character" %}</th>
|
||||||
<th class="text-center">{% translate "Corporation" %}</th>
|
<th>{% translate "Corporation" %}</th>
|
||||||
<th class="text-center">{% translate "zKillboard" %}</th>
|
<th>{% translate "zKillboard" %}</th>
|
||||||
<th class="text-center">{% translate "Main Character" %}</th>
|
<th>{% translate "Main Character" %}</th>
|
||||||
<th class="text-center">{% translate "Main Corporation" %}</th>
|
<th>{% translate "Main Corporation" %}</th>
|
||||||
<th class="text-center">{% translate "Main Alliance" %}</th>
|
<th>{% translate "Main Alliance" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for result in results %}
|
{% for result in results %}
|
||||||
<tr {% if not result.1.registered %}class="danger"{% endif %}>
|
<tr {% if not result.1.registered %}class="danger"{% endif %}>
|
||||||
<td class="text-center"><img src="{{ result.1.portrait_url }}" class="img-circle" alt="{{ result.1.character_name }}"></td>
|
<td><img src="{{ result.1.portrait_url }}" class="img-circle" alt="{{ result.1.character_name }}"></td>
|
||||||
<td class="text-center">{{ result.1.character_name }}</td>
|
<td>{{ result.1.character_name }}</td>
|
||||||
<td class="text-center">{{ result.0.corp.corporation_name }}</td>
|
<td >{{ result.0.corp.corporation_name }}</td>
|
||||||
<td class="text-center"><a href="https://zkillboard.com/character/{{ result.1.character_id }}/" class="label label-danger" target="_blank">{% translate "Killboard" %}</a></td>
|
<td><a href="https://zkillboard.com/character/{{ result.1.character_id }}/" class="badge bg-danger" target="_blank">{% translate "Killboard" %}</a></td>
|
||||||
<td class="text-center">{{ result.1.main_character.character_name }}</td>
|
<td>{{ result.1.main_character.character_name }}</td>
|
||||||
<td class="text-center">{{ result.1.main_character.corporation_name }}</td>
|
<td>{{ result.1.main_character.corporation_name }}</td>
|
||||||
<td class="text-center">{{ result.1.main_character.alliance_name }}</td>
|
<td>{{ result.1.main_character.alliance_name }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -35,17 +38,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_javascript %}
|
{% block extra_javascript %}
|
||||||
{% include 'bundles/datatables-js.html' %}
|
{% include 'bundles/datatables-js-bs5.html' %}
|
||||||
{% endblock %}
|
|
||||||
{% block extra_css %}
|
<script>
|
||||||
{% include 'bundles/datatables-css.html' %}
|
$(document).ready(() => {
|
||||||
{% endblock %}
|
|
||||||
{% block extra_script %}
|
|
||||||
$(document).ready(function(){
|
|
||||||
$('#table-search').DataTable({
|
$('#table-search').DataTable({
|
||||||
"stateSave": true,
|
"stateSave": true,
|
||||||
"stateDuration": 0
|
"stateDuration": 0
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_css %}
|
||||||
|
{% include 'bundles/datatables-css-bs5.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class AutogroupsConfigTestCase(TestCase):
|
|||||||
group_qs = Group.objects.filter(pk=group.pk)
|
group_qs = Group.objects.filter(pk=group.pk)
|
||||||
|
|
||||||
self.assertIn(group, self.member.groups.all())
|
self.assertIn(group, self.member.groups.all())
|
||||||
self.assertQuerysetEqual(self.member.groups.all(), map(repr, pre_groups | group_qs), ordered=False)
|
self.assertQuerySetEqual(self.member.groups.all(), pre_groups | group_qs, ordered=False)
|
||||||
|
|
||||||
def test_update_alliance_group_membership_no_main_character(self):
|
def test_update_alliance_group_membership_no_main_character(self):
|
||||||
obj = AutogroupsConfig.objects.create()
|
obj = AutogroupsConfig.objects.create()
|
||||||
@@ -172,7 +172,7 @@ class AutogroupsConfigTestCase(TestCase):
|
|||||||
group_qs = Group.objects.filter(pk=group.pk)
|
group_qs = Group.objects.filter(pk=group.pk)
|
||||||
|
|
||||||
self.assertIn(group, self.member.groups.all())
|
self.assertIn(group, self.member.groups.all())
|
||||||
self.assertQuerysetEqual(self.member.groups.all(), map(repr, pre_groups | group_qs), ordered=False)
|
self.assertQuerySetEqual(self.member.groups.all(), pre_groups | group_qs, ordered=False)
|
||||||
|
|
||||||
def test_update_corp_group_membership_no_state(self):
|
def test_update_corp_group_membership_no_state(self):
|
||||||
obj = AutogroupsConfig.objects.create(corp_groups=True)
|
obj = AutogroupsConfig.objects.create(corp_groups=True)
|
||||||
|
|||||||
@@ -8,21 +8,19 @@ Needs to be called with a context containing three objects:
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
{% extends 'allianceauth/base.html' %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
{% load evelinks %}
|
{% load evelinks %}
|
||||||
|
|
||||||
{% block page_title %}Evelinks examples{% endblock %}
|
{% block page_title %}Evelinks Examples{% endblock page_title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
{% include "framework/header/page-header.html" with title="Evelinks templatetags examples" %}
|
||||||
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<h1 class="page-header text-center">Evelinks templatetags examples</h1>
|
|
||||||
<div class="col-lg-12 container">
|
<div class="col-lg-12 container">
|
||||||
|
|
||||||
<h2>profile URLs</h2>
|
<h2>profile URLs</h2>
|
||||||
|
|
||||||
<div class="rows">
|
<div class="rows">
|
||||||
|
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<h3>evewho</h3>
|
<h3>evewho</h3>
|
||||||
<p><a href="{{ my_character|evewho_character_url }}">character from character object</a></p>
|
<p><a href="{{ my_character|evewho_character_url }}">character from character object</a></p>
|
||||||
@@ -53,12 +51,10 @@ Needs to be called with a context containing three objects:
|
|||||||
<p><a href="{{ 30002813|zkillboard_solar_system_url }}">solar sytem from ID</a></p>
|
<p><a href="{{ 30002813|zkillboard_solar_system_url }}">solar sytem from ID</a></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2>image URLs</h2>
|
<h2>image URLs</h2>
|
||||||
|
|
||||||
<div class="rows">
|
<div class="rows">
|
||||||
|
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<p>character from ID: <img src="{{ my_character.character_id|character_portrait_url:128 }}"></p>
|
<p>character from ID: <img src="{{ my_character.character_id|character_portrait_url:128 }}"></p>
|
||||||
<p>character from character object: <img src="{{ my_character|character_portrait_url:128 }}"></p>
|
<p>character from character object: <img src="{{ my_character|character_portrait_url:128 }}"></p>
|
||||||
@@ -75,10 +71,7 @@ Needs to be called with a context containing three objects:
|
|||||||
<p>alliance from character object: <img src="{{ my_character|alliance_logo_url:128 }}"></p>
|
<p>alliance from character object: <img src="{{ my_character|alliance_logo_url:128 }}"></p>
|
||||||
<p>alliance from alliance object: <img src="{{ my_alliance|alliance_logo_url:128 }}"></p>
|
<p>alliance from alliance object: <img src="{{ my_alliance|alliance_logo_url:128 }}"></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
|
from allianceauth.menu.hooks import MenuItemHook
|
||||||
from . import urls
|
from . import urls
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from allianceauth import hooks
|
from allianceauth import hooks
|
||||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
from allianceauth.services.hooks import UrlHook
|
||||||
|
|
||||||
|
|
||||||
@hooks.register('menu_item_hook')
|
@hooks.register('menu_item_hook')
|
||||||
def register_menu():
|
def register_menu():
|
||||||
return MenuItemHook(_('Fleet Activity Tracking'), 'fas fa-users fa-fw', 'fatlink:view',
|
return MenuItemHook(_('Fleet Activity Tracking'), 'fa-solid fa-users', 'fatlink:view',
|
||||||
navactive=['fatlink:'])
|
navactive=['fatlink:'])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
class FatlinkForm(forms.Form):
|
class FatlinkForm(forms.Form):
|
||||||
fleet = forms.CharField(label=_("Fleet Name"), max_length=50)
|
fleet = forms.CharField(label=_("Fleet Name"), max_length=50)
|
||||||
duration = forms.IntegerField(label=_("Duration of fat-link"), required=True, initial=30, min_value=1, max_value=2147483647, help_text=_('minutes'))
|
duration = forms.IntegerField(label=_("Duration of fat-link"), required=True, initial=30, min_value=1, max_value=2147483647, help_text=_('Duration of the fat-link in minutes'))
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
from django.utils.timezone import utc
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
@@ -15,6 +14,6 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='fatlink',
|
model_name='fatlink',
|
||||||
name='fatdatetime',
|
name='fatdatetime',
|
||||||
field=models.DateTimeField(default=datetime.datetime(2016, 9, 5, 22, 20, 2, 999041, tzinfo=utc)),
|
field=models.DateTimeField(default=datetime.datetime(2016, 9, 5, 22, 20, 2, 999041, tzinfo=datetime.timezone.utc)),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
"""
|
||||||
|
Migration to AA Framework API method
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import allianceauth.framework.api.user
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("fleetactivitytracking", "0006_auto_20180803_0430"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="fatlink",
|
||||||
|
name="creator",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
on_delete=models.SET(allianceauth.framework.api.user.get_sentinel_user),
|
||||||
|
to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -3,10 +3,7 @@ from django.db import models
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from allianceauth.eveonline.models import EveCharacter
|
from allianceauth.eveonline.models import EveCharacter
|
||||||
|
from allianceauth.framework.api.user import get_sentinel_user
|
||||||
|
|
||||||
def get_sentinel_user():
|
|
||||||
return User.objects.get_or_create(username='deleted')[0]
|
|
||||||
|
|
||||||
|
|
||||||
class Fatlink(models.Model):
|
class Fatlink(models.Model):
|
||||||
|
|||||||
@@ -1,22 +1,43 @@
|
|||||||
{% extends 'allianceauth/base.html' %}
|
{% extends 'allianceauth/base-bs5.html' %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block page_title %}{% translate "Fleet Participation" %}{% endblock %}
|
|
||||||
|
{% block page_title %}
|
||||||
|
{% translate "Fleet Participation" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Fleet Activity Tracking" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
<h1 class="page-header text-center">{% translate "Character not found!" %}</h1>
|
{% translate "Character not found!" as page_header %}
|
||||||
<div class="col-lg-12 container" id="example">
|
{% include "framework/header/page-header.html" with title=page_header %}
|
||||||
|
|
||||||
|
<div class="col-lg-12 container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="panel panel-default">
|
<div class="card card-default">
|
||||||
<div class="panel-heading">{{ character_name }}</div>
|
<div class="card-header">
|
||||||
<div class="panel-body">
|
<div class="card-title mb-0">
|
||||||
|
{{ character_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
<div class="col-lg-2 col-sm-2">
|
<div class="col-lg-2 col-sm-2">
|
||||||
<img class="ra-avatar img-responsive" src="{{ character_portrait_url }}" alt="{{ character_name }}">
|
<img class="ra-avatar img-responsive" src="{{ character_portrait_url }}" alt="{{ character_name }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-lg-10 col-sm-2">
|
<div class="col-lg-10 col-sm-2">
|
||||||
<div class="alert alert-danger" role="alert">{% translate "Character not registered!" %}</div>
|
<div class="alert alert-danger" role="alert">
|
||||||
{% translate "This character is not associated with an auth account." %} <a href=" {% url 'authentication:add_character' %}">{% translate "Add it here" %}</a> {% translate "before attempting to click fleet attendance links." %}
|
{% translate "Character not registered!" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% translate "This character is not associated with an auth account." %}
|
||||||
|
<a href="{% url 'authentication:add_character' %}">{% translate "Add it here" %}</a>
|
||||||
|
{% translate "before attempting to click fleet attendance links." %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
|
{% load django_bootstrap5 %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block page_title %}
|
||||||
|
{% translate "Create Fatlink" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Fleet Activity Tracking" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
{% translate "Create Fatlink" as page_header %}
|
||||||
|
{% include "framework/header/page-header.html" with title=page_header %}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{% if badrequest %}
|
||||||
|
<div class="alert alert-danger" role="alert">{% translate "Bad request!" %}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for message in errormessages %}
|
||||||
|
<div class="alert alert-danger" role="alert">{{ message }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<div class="card card-primary border-0">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title mb-0">
|
||||||
|
{% translate "Fatlink details" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form role="form" action="" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% bootstrap_form form %}
|
||||||
|
|
||||||
|
<div class="form-group mt-3 clearfix">
|
||||||
|
{% translate "Create fatlink" as button_text %}
|
||||||
|
{% bootstrap_button button_class="btn btn-primary" content=button_text name="submit_fat" id="submit_fat" %}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
|
||||||
{% load bootstrap %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block page_title %}{% translate "Create Fatlink" %}{% endblock page_title %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<h1 class="page-header text-center">{% translate "Create Fleet Operation" %}</h1>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
{% if badrequest %}
|
|
||||||
<div class="alert alert-danger" role="alert">{% translate "Bad request!" %}</div>
|
|
||||||
{% endif %}
|
|
||||||
{% for message in errormessages %}
|
|
||||||
<div class="alert alert-danger" role="alert">{{ message }}</div>
|
|
||||||
{% endfor %}
|
|
||||||
<div class="col-md-4 col-md-offset-4">
|
|
||||||
<div class="row">
|
|
||||||
<form class="form-signin" role="form" action="" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ form|bootstrap }}
|
|
||||||
<br>
|
|
||||||
<button class="btn btn-lg btn-primary btn-block" type="submit" name="submit_fat">{% translate "Create fatlink" %}</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock content %}
|
|
||||||
@@ -1,21 +1,35 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block page_title %}{% translate "Fatlink view" %}{% endblock page_title %}
|
|
||||||
|
{% block page_title %}
|
||||||
|
{% translate "Fatlink view" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Fleet Activity Tracking" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
<h1 class="page-header text-center">{% translate "Edit fatlink" %} "{{ fatlink }}"
|
<h1 class="page-header text-center mb-3">
|
||||||
<div class="text-right">
|
{% translate "Edit fatlink" %} "{{ fatlink }}"
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div class="text-end mb-3">
|
||||||
<form>
|
<form>
|
||||||
<button type="submit" onclick="return confirm('Are you sure?')" class="btn btn-danger" name="deletefat" value="True">
|
<button type="submit" onclick="return confirm('{% translate "Are you sure?" %}')" class="btn btn-danger" name="deletefat" value="True">
|
||||||
{% translate "Delete fat" %}
|
{% translate "Delete fat" %}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
|
||||||
<div class="panel panel-default">
|
<div class="card card-default">
|
||||||
<div class="panel-heading">{% translate "Registered characters" %}</div>
|
<div class="card-header">
|
||||||
<div class="panel-body">
|
<div class="card-title mb-0">{% translate "Registered characters" %}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
<table class="table table-responsive table-hover">
|
<table class="table table-responsive table-hover">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center">{% translate "User" %}</th>
|
<th class="text-center">{% translate "User" %}</th>
|
||||||
@@ -25,21 +39,23 @@
|
|||||||
<th class="text-center">{% translate "Eve Time" %}</th>
|
<th class="text-center">{% translate "Eve Time" %}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for fat in registered_fats %}
|
{% for fat in registered_fats %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">{{ fat.user }}</td>
|
<td class="text-center">{{ fat.user }}</td>
|
||||||
<td class="text-center">{{ fat.character.character_name }}</td>
|
<td class="text-center">{{ fat.character.character_name }}</td>
|
||||||
|
<td class="text-center">
|
||||||
{% if fat.station != "No Station" %}
|
{% if fat.station != "No Station" %}
|
||||||
<td class="text-center">{% blocktranslate %}Docked in {% endblocktranslate %}{{ fat.system }}</td>
|
{% translate "Docked in" %}
|
||||||
{% else %}
|
|
||||||
<td class="text-center">{{ fat.system }}</td>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{{ fat.system }}
|
||||||
|
</td>
|
||||||
<td class="text-center">{{ fat.shiptype }}</td>
|
<td class="text-center">{{ fat.shiptype }}</td>
|
||||||
<td class="text-center">{{ fat.fatlink.fatdatetime }}</td>
|
<td class="text-center">{{ fat.fatlink.fatdatetime }}</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<form>
|
<form>
|
||||||
<button type="submit" class="btn btn-warning" name="removechar" value="{{ fat.character.character_id }}">
|
<button type="submit" class="btn btn-warning" name="removechar" value="{{ fat.character.character_id }}">
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
<i class="fa-solid fa-trash-can fa-fw"></i>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -1,30 +1,50 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Personal fatlink statistics" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
|
{% translate "Personal fatlink statistics" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Fleet Activity Tracking" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
<h1 class="page-header text-center">{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
|
<h1 class="page-header text-center mb-3">
|
||||||
|
{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
|
||||||
|
</h1>
|
||||||
|
|
||||||
{% if char_id %}
|
{% if char_id %}
|
||||||
<div class="text-right">
|
<div class="text-end mb-3">
|
||||||
<a href="{% url 'fatlink:user_statistics_month' char_id previous_month|date:'Y' previous_month|date:'m' %}" class="btn btn-info">{% translate "Previous month" %}</a>
|
<a href="{% url 'fatlink:user_statistics_month' char_id previous_month|date:'Y' previous_month|date:'m' %}" class="btn btn-info">
|
||||||
<a href="{% url 'fatlink:user_statistics_month' char_id next_month|date:'Y' next_month|date:'m' %}" class="btn btn-info">{% translate "Next month" %}</a>
|
{% translate "Previous month" %}
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'fatlink:user_statistics_month' char_id next_month|date:'Y' next_month|date:'m' %}" class="btn btn-info">
|
||||||
|
{% translate "Next month" %}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h1>
|
|
||||||
<h2>
|
<div class="card card-default mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title mb-0">
|
||||||
{% blocktranslate count links=n_fats trimmed %}
|
{% blocktranslate count links=n_fats trimmed %}
|
||||||
{{ user }} has collected one link this month.
|
{{ user }} has collected one link this month.
|
||||||
{% plural %}
|
{% plural %}
|
||||||
{{ user }} has collected {{ links }} links this month.
|
{{ user }} has collected {{ links }} links this month.
|
||||||
{% endblocktranslate %}
|
{% endblocktranslate %}
|
||||||
</h2>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
<table class="table table-responsive">
|
<table class="table table-responsive">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-2 text-center">{% translate "Ship" %}</th>
|
<th class="col-md-2 text-center">{% translate "Ship" %}</th>
|
||||||
<th class="col-md-2 text-center">{% translate "Times used" %}</th>
|
<th class="col-md-2 text-center">{% translate "Times used" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for ship, n_fats in shipStats %}
|
{% for ship, n_fats in shipStats %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">{{ ship }}</td>
|
<td class="text-center">{{ ship }}</td>
|
||||||
@@ -32,15 +52,22 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if created_fats %}
|
{% if created_fats %}
|
||||||
<h2>
|
<div class="card card-default">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title mb-0">
|
||||||
{% blocktranslate count links=n_created_fats trimmed %}
|
{% blocktranslate count links=n_created_fats trimmed %}
|
||||||
{{ user }} has created one link this month.
|
{{ user }} has created one link this month.
|
||||||
{% plural %}
|
{% plural %}
|
||||||
{{ user }} has created {{ links }} links this month.
|
{{ user }} has created {{ links }} links this month.
|
||||||
{% endblocktranslate %}
|
{% endblocktranslate %}
|
||||||
</h2>
|
</div>
|
||||||
{% if created_fats %}
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center">{% translate "Fleet" %}</th>
|
<th class="text-center">{% translate "Fleet" %}</th>
|
||||||
@@ -49,23 +76,29 @@
|
|||||||
<th class="text-center">{% translate "Duration" %}</th>
|
<th class="text-center">{% translate "Duration" %}</th>
|
||||||
<th class="text-center">{% translate "Edit" %}</th>
|
<th class="text-center">{% translate "Edit" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for link in created_fats %}
|
{% for link in created_fats %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center"><a href="{% url 'fatlink:click' link.hash %}" class="label label-primary">{{ link.fleet }}</a></td>
|
<td class="text-center">
|
||||||
|
<a href="{% url 'fatlink:click' link.hash %}" class="badge bg-primary">
|
||||||
|
{{ link.fleet }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td class="text-center">{{ link.creator.username }}</td>
|
<td class="text-center">{{ link.creator.username }}</td>
|
||||||
<td class="text-center">{{ link.fatdatetime }}</td>
|
<td class="text-center">{{ link.fatdatetime }}</td>
|
||||||
<td class="text-center">{{ link.duration }}</td>
|
<td class="text-center">{{ link.duration }}</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a href="{% url 'fatlink:modify' link.hash %}">
|
<a href="{% url 'fatlink:modify' link.hash %}">
|
||||||
<button type="button" class="btn btn-info"><span
|
<button type="button" class="btn btn-info">
|
||||||
class="glyphicon glyphicon-edit"></span></button>
|
<i class="fa-solid fa-pen-to-square fa-fw"></i>
|
||||||
|
</button>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
{% endif %}
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -1,30 +1,40 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Personal fatlink statistics" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
|
{% translate "Personal fatlink statistics" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Fleet Activity Tracking" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
<h1 class="page-header text-center">{% blocktranslate %}Participation data statistics for {{ year }}{% endblocktranslate %}
|
<h1 class="page-header text-center mb-3">
|
||||||
<div class="text-right">
|
{% blocktranslate %}Participation data statistics for {{ year }}{% endblocktranslate %}
|
||||||
<a href="{% url 'fatlink:personal_statistics_year' previous_year %}" class="btn btn-info">{% translate "Previous year" %}</a>
|
</h1>
|
||||||
|
|
||||||
|
<div class="text-end mb-3">
|
||||||
|
<a href="{% url "fatlink:personal_statistics_year" previous_year %}" class="btn btn-info"><i class="fa-solid fa-chevron-left"></i> {% translate "Previous year" %}</a>
|
||||||
|
|
||||||
{% if next_year %}
|
{% if next_year %}
|
||||||
<a href="{% url 'fatlink:personal_statistics_year' next_year %}" class="btn btn-info">{% translate "Next year" %}</a>
|
<a href="{% url "fatlink:personal_statistics_year" next_year %}" class="btn btn-info">{% translate "Next year" %} <i class="fa-solid fa-chevron-right"></i></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
|
||||||
<div class="col-lg-2 col-lg-offset-5">
|
<div class="col-lg-2 offset-lg-5">
|
||||||
<table class="table table-responsive">
|
<table class="table table-responsive">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-2 text-center">{% translate "Month" %}</th>
|
<th scope="col" class="col-md-2 text-center">{% translate "Month" %}</th>
|
||||||
<th class="col-md-2 text-center">{% translate "Fats" %}</th>
|
<th scope="col" class="col-md-2 text-center">{% translate "Fats" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for monthnr, month, n_fats in monthlystats %}
|
{% for monthnr, month, n_fats in monthlystats %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a href="{% url 'fatlink:personal_statistics_month' year monthnr %}">
|
<a href="{% url 'fatlink:personal_statistics_month' year monthnr %}">{{ month }}</a>
|
||||||
{{ month }}
|
|
||||||
</a>
|
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">{{ n_fats }}</td>
|
<td class="text-center">{{ n_fats }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,27 +1,40 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Fatlink Corp Statistics" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
|
{% translate "Fatlink Corp Statistics" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Fleet Activity Tracking" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
<h1 class="page-header text-center">{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
|
<h1 class="page-header text-center mb-3">
|
||||||
<div class="text-right">
|
{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
|
||||||
<a href="{% url 'fatlink:statistics_corp_month' corpid previous_month|date:"Y" previous_month|date:"m" %}" class="btn btn-info">{% translate "Previous month" %}</a>
|
</h1>
|
||||||
|
|
||||||
|
<div class="text-end mb-3">
|
||||||
|
<a href="{% url "fatlink:statistics_corp_month" corpid previous_month|date:"Y" previous_month|date:"m" %}" class="btn btn-info">{% translate "Previous month" %}</a>
|
||||||
|
|
||||||
{% if next_month %}
|
{% if next_month %}
|
||||||
<a href="{% url 'fatlink:statistics_corp_month' corpid next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% translate "Next month" %}</a>
|
<a href="{% url "fatlink:statistics_corp_month" corpid next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% translate "Next month" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
|
||||||
{% if fatStats %}
|
{% if fatStats %}
|
||||||
<table class="table table-responsive">
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-1"></th>
|
<th scope="col" class="col-md-1"></th>
|
||||||
<th class="col-md-2 text-center">{% translate "Main Character" %}</th>
|
<th scope="col" class="col-md-2 text-center">{% translate "Main Character" %}</th>
|
||||||
<th class="col-md-2 text-center">{% translate "Characters" %}</th>
|
<th scope="col" class="col-md-2 text-center">{% translate "Characters" %}</th>
|
||||||
<th class="col-md-2 text-center">{% translate "Fats" %}</th>
|
<th scope="col" class="col-md-2 text-center">{% translate "Fats" %}</th>
|
||||||
<th class="col-md-2 text-center">{% translate "Average fats" %}
|
<th scope="col" class="col-md-2 text-center">
|
||||||
<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="Fats ÷ Characters"></i>
|
{% translate "Average fats" %}
|
||||||
|
<i class="fa-solid fa-question" rel="tooltip" title="Fats / Characters"></i>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for memberStat in fatStats %}
|
{% for memberStat in fatStats %}
|
||||||
@@ -36,11 +49,15 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
{% block extra_script %}
|
|
||||||
$(document).ready(function () {
|
{% block extra_javascript %}
|
||||||
|
<script>
|
||||||
|
$(document).ready(() => {
|
||||||
$("[rel=tooltip]").tooltip();
|
$("[rel=tooltip]").tooltip();
|
||||||
});
|
});
|
||||||
{% endblock extra_script %}
|
</script>
|
||||||
|
{% endblock extra_javascript %}
|
||||||
|
|||||||
@@ -1,28 +1,41 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Fatlink statistics" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
|
{% translate "Fatlink Statistics" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Fleet Activity Tracking" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
<h1 class="page-header text-center">{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
|
<h1 class="page-header text-center mb-3">
|
||||||
<div class="text-right">
|
{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
|
||||||
<a href="{% url 'fatlink:statistics_month' previous_month|date:"Y" previous_month|date:"m" %}" class="btn btn-info">{% translate "Previous month" %}</a>
|
</h1>
|
||||||
|
|
||||||
|
<div class="text-end mb-3">
|
||||||
|
<a href="{% url "fatlink:statistics_month" previous_month|date:"Y" previous_month|date:"m" %}" class="btn btn-info">{% translate "Previous month" %}</a>
|
||||||
|
|
||||||
{% if next_month %}
|
{% if next_month %}
|
||||||
<a href="{% url 'fatlink:statistics_month' next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% translate "Next month" %}</a>
|
<a href="{% url 'fatlink:statistics_month' next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% translate "Next month" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
|
||||||
{% if fatStats %}
|
{% if fatStats %}
|
||||||
<table class="table table-responsive">
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-1"></th>
|
<th scope="col" class="col-md-1"></th>
|
||||||
<th class="col-md-2 text-center">{% translate "Ticker" %}</th>
|
<th scope="col" class="col-md-2 text-center">{% translate "Ticker" %}</th>
|
||||||
<th class="col-md-5 text-center">{% translate "Corp" %}</th>
|
<th scope="col" class="col-md-5 text-center">{% translate "Corp" %}</th>
|
||||||
<th class="col-md-2 text-center">{% translate "Members" %}</th>
|
<th scope="col" class="col-md-2 text-center">{% translate "Members" %}</th>
|
||||||
<th class="col-md-2 text-center">{% translate "Fats" %}</th>
|
<th scope="col" class="col-md-2 text-center">{% translate "Fats" %}</th>
|
||||||
<th class="col-md-2 text-center">{% translate "Average fats" %}
|
<th scope="col" class="col-md-2 text-center">
|
||||||
<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="Fats ÷ Characters"></i>
|
{% translate "Average fats" %}
|
||||||
|
<i class="fa-solid fa-question" rel="tooltip" title="Fats / Characters"></i>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for corpStat in fatStats %}
|
{% for corpStat in fatStats %}
|
||||||
@@ -30,7 +43,9 @@
|
|||||||
<td>
|
<td>
|
||||||
<img src="{{ corpStat.corp.logo_url_32 }}" class="ra-avatar img-responsive" alt="{{ corpStat.corp.corporation_name }}">
|
<img src="{{ corpStat.corp.logo_url_32 }}" class="ra-avatar img-responsive" alt="{{ corpStat.corp.corporation_name }}">
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center"><a href="{% url 'fatlink:statistics_corp' corpStat.corp.corporation_id %}">[{{ corpStat.corp.corporation_ticker }}]</a></td>
|
<td class="text-center">
|
||||||
|
<a href="{% url 'fatlink:statistics_corp' corpStat.corp.corporation_id %}">[{{ corpStat.corp.corporation_ticker }}]</a>
|
||||||
|
</td>
|
||||||
<td class="text-center">{{ corpStat.corp.corporation_name }}</td>
|
<td class="text-center">{{ corpStat.corp.corporation_name }}</td>
|
||||||
<td class="text-center">{{ corpStat.corp.member_count }}</td>
|
<td class="text-center">{{ corpStat.corp.member_count }}</td>
|
||||||
<td class="text-center">{{ corpStat.n_fats }}</td>
|
<td class="text-center">{{ corpStat.n_fats }}</td>
|
||||||
@@ -38,11 +53,15 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
{% block extra_script %}
|
|
||||||
$(document).ready(function () {
|
{% block extra_javascript %}
|
||||||
|
<script>
|
||||||
|
$(document).ready(() => {
|
||||||
$("[rel=tooltip]").tooltip();
|
$("[rel=tooltip]").tooltip();
|
||||||
});
|
});
|
||||||
{% endblock extra_script %}
|
</script>
|
||||||
|
{% endblock extra_javascript %}
|
||||||
|
|||||||
@@ -1,39 +1,55 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Fatlink view" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
|
{% translate "Fatlink view" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Fleet Activity Tracking" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
<h1 class="page-header text-center">{% translate "Participation data" %}</h1>
|
{% translate "Participation data" as page_header %}
|
||||||
<table class="table">
|
{% include "framework/header/page-header.html" with title=page_header %}
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-11">
|
<th class="col-md-10">
|
||||||
<h4><b>{% translate "Most recent clicked fatlinks" %}</b>
|
<h4>
|
||||||
|
<b>{% translate "Most recent clicked fatlinks" %}</b>
|
||||||
</h4>
|
</h4>
|
||||||
</th>
|
</th>
|
||||||
<th class="col-md-1">
|
<th class="col-md-2 align-self-end">
|
||||||
<a href="{% url 'fatlink:personal_statistics' %}" class="btn btn-info">
|
<a href="{% url 'fatlink:personal_statistics' %}" class="btn btn-info">
|
||||||
|
<i class="fa-solid fa-circle-info fa-fw"></i>
|
||||||
{% translate "Personal statistics" %}
|
{% translate "Personal statistics" %}
|
||||||
</a>
|
</a>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if fats %}
|
{% if fats %}
|
||||||
<table class="table table-responsive">
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center">{% translate "Fleet" %}</th>
|
<th scope="col" class="text-center">{% translate "Fleet" %}</th>
|
||||||
<th class="text-center">{% translate "Character" %}</th>
|
<th scope="col" class="text-center">{% translate "Character" %}</th>
|
||||||
<th class="text-center">{% translate "System" %}</th>
|
<th scope="col" class="text-center">{% translate "System" %}</th>
|
||||||
<th class="text-center">{% translate "Ship" %}</th>
|
<th scope="col" class="text-center">{% translate "Ship" %}</th>
|
||||||
<th class="text-center">{% translate "Eve Time" %}</th>
|
<th scope="col" class="text-center">{% translate "Eve Time" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for fat in fats %}
|
{% for fat in fats %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">{{ fat.fatlink.fleet }}</td>
|
<td class="text-center">{{ fat.fatlink.fleet }}</td>
|
||||||
<td class="text-center">{{ fat.character.character_name }}</td>
|
<td class="text-center">{{ fat.character.character_name }}</td>
|
||||||
{% if fat.station != "No Station" %}
|
{% if fat.station != "No Station" %}
|
||||||
<td class="text-center">{% blocktranslate %}Docked in {% endblocktranslate %}{{ fat.system }}</td>
|
<td class="text-center">{% translate "Docked in" %} {{ fat.system }}</td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td class="text-center">{{ fat.system }}</td>
|
<td class="text-center">{{ fat.system }}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -42,57 +58,66 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="alert alert-warning text-center">{% translate "No fleet activity on record." %}</div>
|
<div class="alert alert-warning text-center">{% translate "No fleet activity on record." %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if perms.auth.fleetactivitytracking %}
|
{% if perms.auth.fleetactivitytracking %}
|
||||||
<table class="table">
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-10">
|
<th class="col-md-8">
|
||||||
<h4><b>{% translate "Most recent fatlinks" %}</b>
|
<h4>
|
||||||
|
<b>{% translate "Most recent fatlinks" %}</b>
|
||||||
</h4>
|
</h4>
|
||||||
</th>
|
</th>
|
||||||
<th class="col-md-1">
|
<th class="col-md-2 align-self-end">
|
||||||
<a href="{% url 'fatlink:statistics' %}" class="btn btn-info">
|
<a href="{% url 'fatlink:statistics' %}" class="btn btn-info"><i class="fa-solid fa-eye fa-fw"></i> {% translate "View statistics" %}</a>
|
||||||
{% translate "View statistics" %}
|
|
||||||
</a>
|
|
||||||
</th>
|
</th>
|
||||||
<th class="col-md-1">
|
<th class="col-md-2 align-self-end">
|
||||||
<a href="{% url 'fatlink:create' %}" class="btn btn-success">
|
<a href="{% url 'fatlink:create' %}" class="btn btn-success"><i class="fa-solid fa-plus fa-fw"></i> {% translate "Create fatlink" %}</a>
|
||||||
{% translate "Create fatlink" %}
|
|
||||||
</a>
|
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if fatlinks %}
|
{% if fatlinks %}
|
||||||
<table class="table">
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center">{% translate "Name" %}</th>
|
<th scope="col" class="text-center">{% translate "Name" %}</th>
|
||||||
<th class="text-center">{% translate "Creator" %}</th>
|
<th scope="col" class="text-center">{% translate "Creator" %}</th>
|
||||||
<th class="text-center">{% translate "Fleet" %}</th>
|
<th scope="col" class="text-center">{% translate "Fleet" %}</th>
|
||||||
<th class="text-center">{% translate "Eve Time" %}</th>
|
<th scope="col" class="text-center">{% translate "Eve Time" %}</th>
|
||||||
<th class="text-center">{% translate "Duration" %}</th>
|
<th scope="col" class="text-center">{% translate "Duration" %}</th>
|
||||||
<th class="text-center">{% translate "Edit" %}</th>
|
<th scope="col" class="text-center">{% translate "Edit" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for link in fatlinks %}
|
{% for link in fatlinks %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center"><a href="{% url 'fatlink:click' link.hash %}" class="label label-primary">{{ link.fleet }}</a></td>
|
<td class="text-center">
|
||||||
|
<a href="{% url 'fatlink:click' link.hash %}" class="badge bg-primary">{{ link.fleet }}</a>
|
||||||
|
</td>
|
||||||
<td class="text-center">{{ link.creator.username }}</td>
|
<td class="text-center">{{ link.creator.username }}</td>
|
||||||
<td class="text-center">{{ link.fleet }}</td>
|
<td class="text-center">{{ link.fleet }}</td>
|
||||||
<td class="text-center">{{ link.fatdatetime }}</td>
|
<td class="text-center">{{ link.fatdatetime }}</td>
|
||||||
<td class="text-center">{{ link.duration }}</td>
|
<td class="text-center">
|
||||||
|
{{ link.duration }}
|
||||||
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a href="{% url 'fatlink:modify' link.hash %}" class="btn btn-info">
|
<a href="{% url 'fatlink:modify' link.hash %}" class="btn btn-info">
|
||||||
<span class="glyphicon glyphicon-edit"></span>
|
<i class="fa-solid fa-pen-to-square fa-fw"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="alert alert-warning text-center">{% translate "No created fatlinks on record." %}</div>
|
<div class="alert alert-warning text-center">
|
||||||
|
{% translate "No created fatlinks on record." %}
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -352,11 +352,11 @@ def create_fatlink_view(request):
|
|||||||
for errorname, message in e.message_dict.items():
|
for errorname, message in e.message_dict.items():
|
||||||
messages.append(message[0].decode())
|
messages.append(message[0].decode())
|
||||||
context = {'form': form, 'errormessages': messages}
|
context = {'form': form, 'errormessages': messages}
|
||||||
return render(request, 'fleetactivitytracking/fatlinkformatter.html', context=context)
|
return render(request, 'fleetactivitytracking/fatlinkcreate.html', context=context)
|
||||||
else:
|
else:
|
||||||
form = FatlinkForm()
|
form = FatlinkForm()
|
||||||
context = {'form': form, 'badrequest': True}
|
context = {'form': form, 'badrequest': True}
|
||||||
return render(request, 'fleetactivitytracking/fatlinkformatter.html', context=context)
|
return render(request, 'fleetactivitytracking/fatlinkcreate.html', context=context)
|
||||||
return redirect('fatlink:view')
|
return redirect('fatlink:view')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -365,7 +365,7 @@ def create_fatlink_view(request):
|
|||||||
|
|
||||||
context = {'form': form}
|
context = {'form': form}
|
||||||
|
|
||||||
return render(request, 'fleetactivitytracking/fatlinkformatter.html', context=context)
|
return render(request, 'fleetactivitytracking/fatlinkcreate.html', context=context)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
3
allianceauth/framework/__init__.py
Normal file
3
allianceauth/framework/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Alliance Auth Framework
|
||||||
|
"""
|
||||||
64
allianceauth/framework/api/user.py
Normal file
64
allianceauth/framework/api/user.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
"""
|
||||||
|
Alliance Auth User API
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from allianceauth.eveonline.models import EveCharacter
|
||||||
|
|
||||||
|
|
||||||
|
def get_sentinel_user() -> User:
|
||||||
|
"""
|
||||||
|
Get the sentinel user or create one
|
||||||
|
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
return User.objects.get_or_create(username="deleted")[0]
|
||||||
|
|
||||||
|
def get_main_character_from_user(user: User) -> Optional[EveCharacter]:
|
||||||
|
"""
|
||||||
|
Get the main character from a user
|
||||||
|
|
||||||
|
:param user:
|
||||||
|
:type user:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
if user is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
main_character = user.profile.main_character
|
||||||
|
except AttributeError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return main_character
|
||||||
|
|
||||||
|
|
||||||
|
def get_main_character_name_from_user(user: User) -> str:
|
||||||
|
"""
|
||||||
|
Get the main character name from a user
|
||||||
|
|
||||||
|
:param user:
|
||||||
|
:type user:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
if user is None:
|
||||||
|
sentinel_user = get_sentinel_user()
|
||||||
|
|
||||||
|
return sentinel_user.username
|
||||||
|
|
||||||
|
main_character = get_main_character_from_user(user=user)
|
||||||
|
|
||||||
|
try:
|
||||||
|
username = main_character.character_name
|
||||||
|
except AttributeError:
|
||||||
|
return str(user)
|
||||||
|
|
||||||
|
return username
|
||||||
14
allianceauth/framework/apps.py
Normal file
14
allianceauth/framework/apps.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
"""
|
||||||
|
Framework App Config
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class FrameworkConfig(AppConfig):
|
||||||
|
"""
|
||||||
|
Framework App Config
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = "allianceauth.framework"
|
||||||
|
label = "framework"
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/**
|
||||||
|
* Alliance Auth CSS Framework
|
||||||
|
*
|
||||||
|
* This provides some CSS classes together with a couple of Bootstrap fixes
|
||||||
|
* to be used throughout Alliance Auth and its Community Apps
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Bootstrap fixes
|
||||||
|
------------------------------------------------------------------------------------- */
|
||||||
|
@media all {
|
||||||
|
.table {
|
||||||
|
--bs-table-bg: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cursor classes
|
||||||
|
------------------------------------------------------------------------------------- */
|
||||||
|
@media all {
|
||||||
|
.cursor-auto {
|
||||||
|
cursor: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-default {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-wait {
|
||||||
|
cursor: wait;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-text {
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-move {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-help {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-not-allowed {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-inherit {
|
||||||
|
cursor: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-zoom-in {
|
||||||
|
cursor: zoom-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-zoom-out {
|
||||||
|
cursor: zoom-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callouts
|
||||||
|
*
|
||||||
|
* Not quite alerts, but custom and helpful notes for folks.
|
||||||
|
* Requires a base and modifier class.
|
||||||
|
------------------------------------------------------------------------------------- */
|
||||||
|
@media all {
|
||||||
|
/* Common styles for all types */
|
||||||
|
.aa-callout {
|
||||||
|
border: 1px solid var(--bs-border-color);
|
||||||
|
border-left-width: 0.25rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
margin-top: 1.25rem;
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Last item bottom margin should be 0 */
|
||||||
|
.aa-callout :last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Variations */
|
||||||
|
.aa-callout.aa-callout-danger {
|
||||||
|
border-left-color: var(--bs-danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-callout.aa-callout-info {
|
||||||
|
border-left-color: var(--bs-info);
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-callout.aa-callout-success {
|
||||||
|
border-left-color: var(--bs-success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.aa-callout.aa-callout-warning {
|
||||||
|
border-left-color: var(--bs-warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{#Usage:#}
|
||||||
|
{# {% include "framework/header/page-header.html" with title="Foobar" subtitle="Barfoo" %}#}
|
||||||
|
|
||||||
|
{% if title %}
|
||||||
|
<h1 class="page-header text-center mb-3">
|
||||||
|
{{ title }}
|
||||||
|
|
||||||
|
{% if subtitle %}
|
||||||
|
<br>
|
||||||
|
<small>{{ subtitle }}</small>
|
||||||
|
{% endif %}
|
||||||
|
</h1>
|
||||||
|
{% endif %}
|
||||||
3
allianceauth/framework/tests/__init__.py
Normal file
3
allianceauth/framework/tests/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Initializing our tests
|
||||||
|
"""
|
||||||
179
allianceauth/framework/tests/test_api_user.py
Normal file
179
allianceauth/framework/tests/test_api_user.py
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
"""
|
||||||
|
Test sentinel user
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
# Django
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Alliance Auth
|
||||||
|
from allianceauth.framework.api.user import (
|
||||||
|
get_sentinel_user,
|
||||||
|
get_main_character_from_user,
|
||||||
|
get_main_character_name_from_user
|
||||||
|
)
|
||||||
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
|
||||||
|
|
||||||
|
class TestSentinelUser(TestCase):
|
||||||
|
"""
|
||||||
|
Tests for the sentinel user
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_should_create_user_when_it_does_not_exist(self) -> None:
|
||||||
|
"""
|
||||||
|
Test should create a sentinel user when it doesn't exist
|
||||||
|
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
# when
|
||||||
|
user = get_sentinel_user()
|
||||||
|
|
||||||
|
# then
|
||||||
|
self.assertEqual(first=user.username, second="deleted")
|
||||||
|
|
||||||
|
def test_should_return_user_when_it_does(self) -> None:
|
||||||
|
"""
|
||||||
|
Test should return sentinel user when it exists
|
||||||
|
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
# given
|
||||||
|
User.objects.create_user(username="deleted")
|
||||||
|
|
||||||
|
# when
|
||||||
|
user = get_sentinel_user()
|
||||||
|
|
||||||
|
# then
|
||||||
|
self.assertEqual(first=user.username, second="deleted")
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetMainForUser(TestCase):
|
||||||
|
"""
|
||||||
|
Tests for get_main_character_from_user
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls) -> None:
|
||||||
|
"""
|
||||||
|
Set up groups and users
|
||||||
|
"""
|
||||||
|
|
||||||
|
super().setUpClass()
|
||||||
|
|
||||||
|
cls.character_name = "William T. Riker"
|
||||||
|
cls.character_name_2 = "Christopher Pike"
|
||||||
|
|
||||||
|
cls.username = re.sub(pattern=r"[^\w\d@\.\+-]", repl="_", string=cls.character_name)
|
||||||
|
cls.username_2 = re.sub(
|
||||||
|
pattern=r"[^\w\d@\.\+-]", repl="_", string=cls.character_name_2
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.user = AuthUtils.create_user(username=cls.username)
|
||||||
|
cls.user_without_main = AuthUtils.create_user(
|
||||||
|
username=cls.username_2, disconnect_signals=True
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.character = AuthUtils.add_main_character_2(
|
||||||
|
user=cls.user, name=cls.character_name, character_id=1001
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_main_character_from_user_should_return_character_name(self):
|
||||||
|
"""
|
||||||
|
Test should return the main character name for a regular user
|
||||||
|
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
character = get_main_character_from_user(user=self.user)
|
||||||
|
|
||||||
|
self.assertEqual(first=character, second=self.character)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_main_character_from_user_should_return_none_for_no_main_character(self):
|
||||||
|
"""
|
||||||
|
Test should return None for User without a main character
|
||||||
|
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
character = get_main_character_from_user(user=self.user_without_main)
|
||||||
|
|
||||||
|
self.assertIsNone(obj=character)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_main_character_from_user_should_none(self):
|
||||||
|
"""
|
||||||
|
Test should return None when user is None
|
||||||
|
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
user = None
|
||||||
|
|
||||||
|
character = get_main_character_from_user(user=user)
|
||||||
|
|
||||||
|
self.assertIsNone(obj=character)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_main_character_name_from_user_should_return_character_name(self):
|
||||||
|
"""
|
||||||
|
Test should return the main character name for a regular user
|
||||||
|
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
character_name = get_main_character_name_from_user(user=self.user)
|
||||||
|
|
||||||
|
self.assertEqual(first=character_name, second=self.character_name)
|
||||||
|
|
||||||
|
def test_get_main_character_name_from_user_should_return_user_name(self):
|
||||||
|
"""
|
||||||
|
Test should return just the username for a user without a main character
|
||||||
|
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
character_name = get_main_character_name_from_user(user=self.user_without_main)
|
||||||
|
|
||||||
|
self.assertEqual(first=character_name, second=self.username_2)
|
||||||
|
|
||||||
|
def test_get_main_character_name_from_user_should_return_sentinel_user(self):
|
||||||
|
"""
|
||||||
|
Test should return "deleted" as username (Sentinel User)
|
||||||
|
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
user = get_sentinel_user()
|
||||||
|
|
||||||
|
character_name = get_main_character_name_from_user(user=user)
|
||||||
|
|
||||||
|
self.assertEqual(first=character_name, second="deleted")
|
||||||
|
|
||||||
|
def test_get_main_character_name_from_user_should_return_sentinel_user_for_none(self):
|
||||||
|
"""
|
||||||
|
Test should return "deleted" (Sentinel User) if user is None
|
||||||
|
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
user = None
|
||||||
|
|
||||||
|
character_name = get_main_character_name_from_user(user=user)
|
||||||
|
|
||||||
|
self.assertEqual(first=character_name, second="deleted")
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from allianceauth.menu.hooks import MenuItemHook
|
||||||
|
|
||||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
from allianceauth.services.hooks import UrlHook
|
||||||
from allianceauth import hooks
|
from allianceauth import hooks
|
||||||
|
|
||||||
from . import urls
|
from . import urls
|
||||||
@@ -15,7 +16,7 @@ class GroupManagementMenuItem(MenuItemHook):
|
|||||||
MenuItemHook.__init__(
|
MenuItemHook.__init__(
|
||||||
self,
|
self,
|
||||||
text=_("Group Management"),
|
text=_("Group Management"),
|
||||||
classes="fas fa-users-cog fa-fw",
|
classes="fa-solid fa-users-gear",
|
||||||
url_name="groupmanagement:management",
|
url_name="groupmanagement:management",
|
||||||
order=50,
|
order=50,
|
||||||
navactive=[
|
navactive=[
|
||||||
@@ -33,11 +34,43 @@ class GroupManagementMenuItem(MenuItemHook):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
<li class="d-flex m-2 p-2 pt-0 pb-0 mt-0 mb-0">
|
||||||
|
<i class="fa-solid fa-users fa-fw align-self-center me-2"></i>
|
||||||
|
<a class="nav-link flex-fill align-self-center {% navactive request 'groupmanagement:groups' %}" href="{% url 'groupmanagement:groups' %}">
|
||||||
|
{% translate "Groups" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class GroupsMenuItem(MenuItemHook):
|
||||||
|
def __init__(self):
|
||||||
|
MenuItemHook.__init__(
|
||||||
|
self,
|
||||||
|
text=_("Groups"),
|
||||||
|
classes="fa-solid fa-user",
|
||||||
|
url_name="groupmanagement:groups",
|
||||||
|
order=25,
|
||||||
|
navactive=[
|
||||||
|
"groupmanagement:groups", # group list view
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def render(self, request):
|
||||||
|
return MenuItemHook.render(self, request)
|
||||||
|
|
||||||
|
|
||||||
@hooks.register("menu_item_hook")
|
@hooks.register("menu_item_hook")
|
||||||
def register_menu():
|
def register_manager_menu():
|
||||||
return GroupManagementMenuItem()
|
return GroupManagementMenuItem()
|
||||||
|
|
||||||
|
|
||||||
|
@hooks.register("menu_item_hook")
|
||||||
|
def register_groups_menu():
|
||||||
|
return GroupsMenuItem()
|
||||||
|
|
||||||
|
|
||||||
@hooks.register("url_hook")
|
@hooks.register("url_hook")
|
||||||
def register_urls():
|
def register_urls():
|
||||||
return UrlHook(urls, "group", r"^groups/")
|
return UrlHook(urls, "group", r"^groups/")
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
import functools
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||||
|
from django.contrib.auth.models import Group, User
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.db.models.functions import Lower
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
@@ -8,6 +12,39 @@ from .models import ReservedGroupName
|
|||||||
|
|
||||||
|
|
||||||
class GroupAdminForm(forms.ModelForm):
|
class GroupAdminForm(forms.ModelForm):
|
||||||
|
users = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=User.objects.order_by(Lower('username')),
|
||||||
|
required=False,
|
||||||
|
widget=FilteredSelectMultiple(verbose_name=_("Users"), is_stacked=False),
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
if self.instance and self.instance.pk:
|
||||||
|
self.fields["users"].initial = self.instance.user_set.all()
|
||||||
|
|
||||||
|
def save(self, commit=True):
|
||||||
|
group: Group = super().save(commit=False)
|
||||||
|
|
||||||
|
if commit:
|
||||||
|
group.save()
|
||||||
|
|
||||||
|
users = self.cleaned_data["users"]
|
||||||
|
if group.pk:
|
||||||
|
self._save_m2m_and_users(group, users)
|
||||||
|
else:
|
||||||
|
self.save_m2m = functools.partial(
|
||||||
|
self._save_m2m_and_users, group=group, users=users
|
||||||
|
)
|
||||||
|
|
||||||
|
return group
|
||||||
|
|
||||||
|
def _save_m2m_and_users(self, group, users):
|
||||||
|
"""Save m2m relations incl. users."""
|
||||||
|
group.user_set.set(users)
|
||||||
|
self._save_m2m()
|
||||||
|
|
||||||
def clean_name(self):
|
def clean_name(self):
|
||||||
my_name = self.cleaned_data['name']
|
my_name = self.cleaned_data['name']
|
||||||
if ReservedGroupName.objects.filter(name__iexact=my_name).exists():
|
if ReservedGroupName.objects.filter(name__iexact=my_name).exists():
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
from typing import Set
|
from typing import Set
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group, User
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@@ -14,7 +13,7 @@ from allianceauth.notifications import notify
|
|||||||
class GroupRequest(models.Model):
|
class GroupRequest(models.Model):
|
||||||
"""Request from a user for joining or leaving a group."""
|
"""Request from a user for joining or leaving a group."""
|
||||||
|
|
||||||
leave_request = models.BooleanField(default=0)
|
leave_request = models.BooleanField(default=False)
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||||
|
|
||||||
@@ -49,7 +48,7 @@ class RequestLog(models.Model):
|
|||||||
request_type = models.BooleanField(null=True)
|
request_type = models.BooleanField(null=True)
|
||||||
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||||
request_info = models.CharField(max_length=254)
|
request_info = models.CharField(max_length=254)
|
||||||
action = models.BooleanField(default=0)
|
action = models.BooleanField(default=False)
|
||||||
request_actor = models.ForeignKey(User, on_delete=models.CASCADE)
|
request_actor = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
date = models.DateTimeField(auto_now_add=True)
|
date = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block page_title %}{{ group }} {% translate "Audit Log" %}{% endblock page_title %}
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load navactive %}
|
||||||
|
|
||||||
|
{% block page_title %}
|
||||||
|
{{ group }} {% translate "Audit Log" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Audit Log" %} - {{ group.name }}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
|
{% block header_nav_collapse_left %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% navactive request 'groupmanagement:management' %}" href="{% url 'groupmanagement:management' %}">{% translate "Back" %}</a>
|
||||||
|
</li>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
|
||||||
<br>
|
|
||||||
{% include 'groupmanagement/menu.html' %}
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
{{ group }} - {% translate "Audit Log" %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-body">
|
|
||||||
<p>
|
|
||||||
<a class="btn btn-default" href="{% url 'groupmanagement:membership' %}" role="button">
|
|
||||||
{% translate "Back" %}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{% if entries %}
|
{% if entries %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped" id="log-entries">
|
<table class="table table-striped" id="log-entries">
|
||||||
@@ -67,39 +66,31 @@
|
|||||||
{% translate "No entries found for this group." %}
|
{% translate "No entries found for this group." %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_javascript %}
|
{% block extra_javascript %}
|
||||||
{% include 'bundles/datatables-js.html' %}
|
{% include 'bundles/datatables-js-bs5.html' %}
|
||||||
{% include 'bundles/moment-js.html' with locale=True %}
|
{% include 'bundles/moment-js.html' with locale=True %}
|
||||||
{% include 'bundles/filterdropdown-js.html' %}
|
{# {% include 'bundles/filterdropdown-js.html' %}#}
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block extra_css %}
|
<script>
|
||||||
{% include 'bundles/datatables-css.html' %}
|
$.fn.dataTable.moment = (format, locale) => {
|
||||||
{% endblock %}
|
const types = $.fn.dataTable.ext.type;
|
||||||
|
|
||||||
{% block extra_script %}
|
|
||||||
$.fn.dataTable.moment = function(format, locale) {
|
|
||||||
let types = $.fn.dataTable.ext.type;
|
|
||||||
|
|
||||||
// Add type detection
|
// Add type detection
|
||||||
types.detect.unshift(function(d) {
|
types.detect.unshift((d) => {
|
||||||
return moment(d, format, locale, true).isValid() ?
|
return moment(d, format, locale, true).isValid() ?
|
||||||
'moment-'+format :
|
'moment-'+format :
|
||||||
null;
|
null;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add sorting method - use an integer for the sorting
|
// Add sorting method - use an integer for the sorting
|
||||||
types.order[ 'moment-'+format+'-pre' ] = function(d) {
|
types.order[ 'moment-'+format+'-pre' ] = (d) => {
|
||||||
return moment(d, format, locale, true).unix();
|
return moment(d, format, locale, true).unix();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(() => {
|
||||||
$.fn.dataTable.moment('YYYY-MMM-D, HH:mm');
|
$.fn.dataTable.moment('YYYY-MMM-D, HH:mm');
|
||||||
|
|
||||||
$('#log-entries').DataTable({
|
$('#log-entries').DataTable({
|
||||||
@@ -132,4 +123,9 @@
|
|||||||
"stateDuration": 0
|
"stateDuration": 0
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_css %}
|
||||||
|
{% include 'bundles/datatables-css-bs5.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,29 +1,28 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load evelinks %}
|
{% load evelinks %}
|
||||||
|
{% load navactive %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Group Members" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
|
{% translate "Group Members" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Group Members" %} - {{ group.name }}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
|
{% block header_nav_collapse_left %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% navactive request 'groupmanagement:management' %}" href="{% url 'groupmanagement:management' %}">{% translate "Back" %}</a>
|
||||||
|
</li>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
|
||||||
<br>
|
|
||||||
{% include 'groupmanagement/menu.html' %}
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
{{ group.name }} - {% translate 'Members' %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-body">
|
|
||||||
<p>
|
|
||||||
<a class="btn btn-default" href="{% url 'groupmanagement:membership' %}" role="button">
|
|
||||||
{% translate "Back" %}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{% if group.user_set %}
|
{% if group.user_set %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-aa" id="tab_group_members">
|
<table class="table" id="tab_group_members">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% translate "Character" %}</th>
|
<th>{% translate "Character" %}</th>
|
||||||
@@ -36,7 +35,8 @@
|
|||||||
{% for member in members %}
|
{% for member in members %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<img src="{{ member.main_char|character_portrait_url:32 }}" class="img-circle" style="margin-right: 1rem;" alt="{{ member.main_char.character_name }}">
|
<img src="{{ member.main_char|character_portrait_url:32 }}" class="rounded-circle" style="margin-right: 1rem;" alt="{{ member.main_char.character_name }}">
|
||||||
|
|
||||||
{% if member.main_char %}
|
{% if member.main_char %}
|
||||||
<a href="{{ member.main_char|evewho_character_url }}" target="_blank">
|
<a href="{{ member.main_char|evewho_character_url }}" target="_blank">
|
||||||
{{ member.main_char.character_name }}
|
{{ member.main_char.character_name }}
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if member.is_leader %}
|
{% if member.is_leader %}
|
||||||
<i class="fas fa-star" title="{% translate "Group leader" %}" style="margin-left: 1rem;"></i>
|
<sup><i class="fa-solid fa-star" title="{% translate "Group leader" %}"></i></sup>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@@ -61,9 +61,9 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="text-right">
|
<td class="text-end">
|
||||||
<a href="{% url 'groupmanagement:membership_remove' group.id member.user.id %}" class="btn btn-danger" title="{% translate "Remove from group" %}">
|
<a href="{% url 'groupmanagement:membership_remove' group.id member.user.id %}" class="btn btn-danger" title="{% translate "Remove from group" %}">
|
||||||
<i class="glyphicon glyphicon-remove"></i>
|
<i class="fa-solid fa-xmark"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p class="text-muted">
|
<p class="text-muted">
|
||||||
<i class="fas fa-star"></i>: {% translate "Group leader" %}
|
<i class="fa-solid fa-star"></i>: {% translate "Group leader" %}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -80,22 +80,14 @@
|
|||||||
{% translate "No group members to list." %}
|
{% translate "No group members to list." %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block extra_javascript %}
|
{% block extra_javascript %}
|
||||||
{% include 'bundles/datatables-js.html' %}
|
{% include 'bundles/datatables-js-bs5.html' %}
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block extra_css %}
|
<script>
|
||||||
{% include 'bundles/datatables-css.html' %}
|
$(document).ready(() => {
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block extra_script %}
|
|
||||||
$(document).ready(function(){
|
|
||||||
$('#tab_group_members').DataTable({
|
$('#tab_group_members').DataTable({
|
||||||
order: [[0, "asc"]],
|
order: [[0, "asc"]],
|
||||||
columnDefs: [
|
columnDefs: [
|
||||||
@@ -108,4 +100,9 @@
|
|||||||
"stateDuration": 0
|
"stateDuration": 0
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_css %}
|
||||||
|
{% include 'bundles/datatables-css-bs5.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load navactive %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Groups Membership" %}{% endblock page_title %}
|
{% block page_title %}{% translate "Groups Membership" %}{% endblock page_title %}
|
||||||
|
{% block header_nav_brand %}{% translate "Groups Membership" %}{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block extra_css %}{% endblock extra_css %}
|
{% block extra_css %}{% endblock extra_css %}
|
||||||
|
|
||||||
|
{% block header_nav_collapse_left %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% navactive request 'groupmanagement:management' %}" href="{% url 'groupmanagement:management' %}">{% translate "Join/Leave Requests" %}</a>
|
||||||
|
</li>
|
||||||
|
{% endblock header_nav_collapse_left %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
|
||||||
<br>
|
|
||||||
{% include 'groupmanagement/menu.html' %}
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
{% translate "Groups" %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-body">
|
|
||||||
{% if groups %}
|
{% if groups %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-aa">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% translate "Name" %}</th>
|
<th>{% translate "Name" %}</th>
|
||||||
<th>{% translate "Description" %}</th>
|
<th>{% translate "Description" %}</th>
|
||||||
<th>{% translate "Status" %}</th>
|
<th>{% translate "Status" %}</th>
|
||||||
<th style="white-space: nowrap;">{% translate "Member Count" %}</th>
|
<th style="white-space: nowrap;" class="text-center">{% translate "Member Count" %}</th>
|
||||||
<th style="min-width: 170px;"></th>
|
<th style="min-width: 170px;"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody class="align-middle">
|
||||||
{% for group in groups %}
|
{% for group in groups %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
@@ -39,29 +39,30 @@
|
|||||||
|
|
||||||
<td>
|
<td>
|
||||||
{% if group.authgroup.hidden %}
|
{% if group.authgroup.hidden %}
|
||||||
<span class="label label-info">{% translate "Hidden" %}</span>
|
<span class="badge bg-info">{% translate "Hidden" %}</span>
|
||||||
{% elif group.authgroup.open %}
|
{% endif %}
|
||||||
<span class="label label-success">{% translate "Open" %}</span>
|
{% if group.authgroup.open %}
|
||||||
|
<span class="badge bg-success">{% translate "Open" %}</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="label label-default">{% translate "Requestable" %}</span>
|
<span class="badge bg-secondary">{% translate "Requestable" %}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="text-right">
|
<td class="text-center">
|
||||||
{{ group.num_members }}
|
{{ group.num_members }}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="text-right">
|
<td class="text-end">
|
||||||
<a href="{% url 'groupmanagement:membership' group.id %}" class="btn btn-primary" title="{% translate "View Members" %}">
|
<a href="{% url 'groupmanagement:membership' group.id %}" class="btn btn-primary" title="{% translate "View Members" %}">
|
||||||
<i class="glyphicon glyphicon-eye-open"></i>
|
<i class="fa-regular fa-eye"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{% url "groupmanagement:audit_log" group.id %}" class="btn btn-info" title="{% translate "Audit Members" %}">
|
<a href="{% url "groupmanagement:audit_log" group.id %}" class="btn btn-info" title="{% translate "Audit Members" %}">
|
||||||
<i class="glyphicon glyphicon-list-alt"></i>
|
<i class="fa-regular fa-rectangle-list"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a id="clipboard-copy" data-clipboard-text="{{ SITE_URL }}{% url 'groupmanagement:request_add' group.id %}" class="btn btn-warning" title="{% translate "Copy Direct Join Link" %}">
|
<a id="clipboard-copy" data-clipboard-text="{{ request.scheme }}://{{request.get_host}}{% url 'groupmanagement:request_add' group.id %}" class="btn btn-warning" title="{% translate "Copy Direct Join Link" %}">
|
||||||
<i class="glyphicon glyphicon-copy"></i>
|
<i class="fa-regular fa-clipboard"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -74,15 +75,12 @@
|
|||||||
{% translate "No groups to list." %}
|
{% translate "No groups to list." %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block extra_javascript %}
|
{% block extra_javascript %}
|
||||||
{% include 'bundles/clipboard-js.html' %}
|
{% include "bundles/clipboard-js.html" %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
new ClipboardJS('#clipboard-copy');
|
new ClipboardJS('#clipboard-copy');
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock extra_javascript %}
|
||||||
|
|||||||
@@ -1,29 +1,55 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Available Groups" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
{% block extra_css %}{% endblock extra_css %}
|
{% translate "Available Groups" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "Available Groups" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
|
{% if manager_perms %}
|
||||||
|
{% block header_nav_collapse_left %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'groupmanagement:management' %}">{% translate "Group Management" %}
|
||||||
|
{% if req_count %}
|
||||||
|
<span class="badge bg-secondary">{{ req_count }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endblock %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
|
||||||
<h1 class="page-header text-center">{% translate "Available Groups" %}</h1>
|
|
||||||
{% if groups %}
|
{% if groups %}
|
||||||
<table class="table table-aa">
|
<table class="table" id="groupsTable" >
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% translate "Name" %}</th>
|
<th>{% translate "Name" %}</th>
|
||||||
<th>{% translate "Description" %}</th>
|
<th>{% translate "Description" %}</th>
|
||||||
|
<th>{% translate "Leaders" %}<span class="m-1 fw-lighter badge bg-primary">{% translate "User" %}</span><span class="m-1 fw-lighter badge bg-secondary ">{% translate "Group" %}</span></th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody class>
|
||||||
{% for g in groups %}
|
{% for g in groups %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ g.group.name }}</td>
|
<td>{{ g.group.name }}</td>
|
||||||
<td>{{ g.group.authgroup.description|linebreaks|urlize }}</td>
|
<td>{{ g.group.authgroup.description|linebreaks|urlize }}</td>
|
||||||
<td class="text-right">
|
<td style="max-width: 30%;">
|
||||||
{% if g.group in user.groups.all %}
|
{% if g.group.authgroup.group_leaders.all.count %}
|
||||||
|
{% for leader in g.group.authgroup.group_leaders.all %}{% if leader.profile.main_character %}<span class="m-1 badge bg-primary">{{leader.profile.main_character}}</span>{% endif %}{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if g.group.authgroup.group_leaders.all.count %}
|
||||||
|
{% for group in g.group.authgroup.group_leader_groups.all %}<span class="badge bg-secondary">{{group.name}}</span>{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="text-end">
|
||||||
|
{% if g.group in user_groups %}
|
||||||
{% if not g.request %}
|
{% if not g.request %}
|
||||||
<a href="{% url 'groupmanagement:request_leave' g.group.id %}" class="btn btn-danger">
|
<a href="{% url 'groupmanagement:request_leave' g.group.id %}" class="btn btn-danger">
|
||||||
{% translate "Leave" %}
|
{% translate "Leave" %}
|
||||||
@@ -58,5 +84,18 @@
|
|||||||
{% translate "No groups available." %}
|
{% translate "No groups available." %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
|
{% block extra_javascript %}
|
||||||
|
{% include 'bundles/datatables-js-bs5.html' %}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(() => {
|
||||||
|
$('#groupsTable').DataTable();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_css %}
|
||||||
|
{% include 'bundles/datatables-css-bs5.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,55 +1,55 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load evelinks %}
|
{% load evelinks %}
|
||||||
|
{% load navactive %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Groups Management" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
|
{% translate "Groups Management" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
{% block extra_css %}
|
{% block header_nav_brand %}
|
||||||
<style>
|
{% translate "Groups Management" %}
|
||||||
.nav-tabs > li.active > a {
|
{% endblock header_nav_brand %}
|
||||||
background-color: rgb(236, 240, 241) !important;
|
|
||||||
color: rgb(44, 62, 80);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock extra_css %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block header_nav_collapse_left %}
|
||||||
<div class="col-lg-12">
|
|
||||||
<br>
|
|
||||||
{% include 'groupmanagement/menu.html' %}
|
|
||||||
|
|
||||||
<ul class="nav nav-tabs">
|
|
||||||
<li class="active">
|
<li class="active">
|
||||||
<a data-toggle="tab" href="#add">
|
<a class="nav-link active" id="add-tab" data-bs-toggle="tab" data-bs-target="#add" type="button" role="tab" aria-controls="add" aria-selected="true">
|
||||||
{% translate "Join Requests" %}
|
{% translate "Join Requests" %}
|
||||||
|
|
||||||
{% if acceptrequests %}
|
{% if acceptrequests %}
|
||||||
<span class="badge">{{ acceptrequests|length }}</span>
|
<span class="badge bg-secondary">{{ acceptrequests|length }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% if not auto_leave %}
|
{% if not show_leave_tab %}
|
||||||
<li>
|
<li>
|
||||||
<a data-toggle="tab" href="#leave">
|
<a class="nav-link" id="leave-tab" data-bs-toggle="tab" data-bs-target="#leave" type="button" role="tab" aria-controls="leave" aria-selected="false">
|
||||||
{% translate "Leave Requests" %}
|
{% translate "Leave Requests" %}
|
||||||
|
|
||||||
{% if leaverequests %}
|
{% if leaverequests %}
|
||||||
<span class="badge">{{ leaverequests|length }}</span>
|
<span class="badge bg-secondary">{{ leaverequests|length }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="panel panel-default panel-tabs-aa">
|
<li class="nav-item ">
|
||||||
<div class="panel-body">
|
<a class="nav-link {% navactive request 'groupmanagement:membership groupmanagement:audit_log' %}" href="{% url 'groupmanagement:membership' %}">
|
||||||
|
{% translate "Group Membership" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endblock header_nav_collapse_left %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
|
|
||||||
<div id="add" class="tab-pane active">
|
<div id="add" class="tab-pane active">
|
||||||
{% if acceptrequests %}
|
{% if acceptrequests %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-aa">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% translate "Character" %}</th>
|
<th>{% translate "Character" %}</th>
|
||||||
@@ -59,11 +59,12 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody class="align-middle">
|
||||||
{% for acceptrequest in acceptrequests %}
|
{% for acceptrequest in acceptrequests %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<img src="{{ acceptrequest.main_char|character_portrait_url:32 }}" class="img-circle" style="margin-right: 1rem;" alt="{{ acceptrequest.main_char.character_name }}">
|
<img src="{{ acceptrequest.main_char|character_portrait_url:32 }}" class="rounded-circle" style="margin-right: 1rem;" alt="{{ acceptrequest.main_char.character_name }}">
|
||||||
|
|
||||||
{% if acceptrequest.main_char %}
|
{% if acceptrequest.main_char %}
|
||||||
<a href="{{ acceptrequest.main_char|evewho_character_url }}" target="_blank">
|
<a href="{{ acceptrequest.main_char|evewho_character_url }}" target="_blank">
|
||||||
{{ acceptrequest.main_char.character_name }}
|
{{ acceptrequest.main_char.character_name }}
|
||||||
@@ -72,25 +73,25 @@
|
|||||||
{{ acceptrequest.user.username }}
|
{{ acceptrequest.user.username }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
{% if acceptrequest.main_char %}
|
{% if acceptrequest.main_char %}
|
||||||
<a href="{{ acceptrequest.main_char|dotlan_corporation_url }}" target="_blank">
|
<a href="{{ acceptrequest.main_char|dotlan_corporation_url }}" target="_blank">
|
||||||
{{ acceptrequest.main_char.corporation_name }}
|
{{ acceptrequest.main_char.corporation_name }}
|
||||||
</a><br>
|
</a>
|
||||||
|
<br>
|
||||||
{{ acceptrequest.main_char.alliance_name|default_if_none:"" }}
|
{{ acceptrequest.main_char.alliance_name|default_if_none:"" }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% translate "(unknown)" %}
|
{% translate "(unknown)" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>{{ acceptrequest.group.name }}</td>
|
<td>{{ acceptrequest.group.name }}</td>
|
||||||
<td class="text-right">
|
|
||||||
|
<td class="text-end">
|
||||||
<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 %}
|
||||||
@@ -98,15 +99,17 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="alert alert-warning text-center">{% translate "No group add requests." %}</div>
|
<div class="aa-callout aa-callout-warning text-center">
|
||||||
|
{% translate "No group add requests." %}
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if not auto_leave %}
|
{% if not show_leave_tab %}
|
||||||
<div id="leave" class="tab-pane">
|
<div id="leave" class="tab-pane">
|
||||||
{% if leaverequests %}
|
{% if leaverequests %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-aa">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% translate "Character" %}</th>
|
<th>{% translate "Character" %}</th>
|
||||||
@@ -116,11 +119,12 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody class="align-middle">
|
||||||
{% for leaverequest in leaverequests %}
|
{% for leaverequest in leaverequests %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<img src="{{ leaverequest.main_char|character_portrait_url:32 }}" class="img-circle" style="margin-right: 1rem;" alt="{{ leaverequest.main_char.character_name }}">
|
<img src="{{ leaverequest.main_char|character_portrait_url:32 }}" class="rounded-circle" style="margin-right: 1rem;" alt="{{ leaverequest.main_char.character_name }}">
|
||||||
|
|
||||||
{% if leaverequest.main_char %}
|
{% if leaverequest.main_char %}
|
||||||
<a href="{{ leaverequest.main_char|evewho_character_url }}" target="_blank">
|
<a href="{{ leaverequest.main_char|evewho_character_url }}" target="_blank">
|
||||||
{{ leaverequest.main_char.character_name }}
|
{{ leaverequest.main_char.character_name }}
|
||||||
@@ -129,18 +133,22 @@
|
|||||||
{{ leaverequest.user.username }}
|
{{ leaverequest.user.username }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
{% if leaverequest.main_char %}
|
{% if leaverequest.main_char %}
|
||||||
<a href="{{ leaverequest.main_char|dotlan_corporation_url }}" target="_blank">
|
<a href="{{ leaverequest.main_char|dotlan_corporation_url }}" target="_blank">
|
||||||
{{ leaverequest.main_char.corporation_name }}
|
{{ leaverequest.main_char.corporation_name }}
|
||||||
</a><br>
|
</a>
|
||||||
|
<br>
|
||||||
{{ leaverequest.main_char.alliance_name|default_if_none:"" }}
|
{{ leaverequest.main_char.alliance_name|default_if_none:"" }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% translate "(unknown)" %}
|
{% translate "(unknown)" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>{{ leaverequest.group.name }}</td>
|
<td>{{ leaverequest.group.name }}</td>
|
||||||
<td class="text-right">
|
|
||||||
|
<td class="text-end">
|
||||||
<a href="{% url 'groupmanagement:leave_accept_request' leaverequest.id %}" class="btn btn-success">
|
<a href="{% url 'groupmanagement:leave_accept_request' leaverequest.id %}" class="btn btn-success">
|
||||||
{% translate "Accept" %}
|
{% translate "Accept" %}
|
||||||
</a>
|
</a>
|
||||||
@@ -155,12 +163,9 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="alert alert-warning text-center">{% translate "No group leave requests." %}</div>
|
<div class="aa-callout aa-callout-warning text-center">{% translate "No group leave requests." %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -1,27 +1,10 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load navactive %}
|
{% load navactive %}
|
||||||
|
|
||||||
<nav class="navbar navbar-default">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
|
|
||||||
<span class="sr-only">{% translate "Toggle navigation" %}</span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
|
||||||
<a class="navbar-brand" href="{% url 'groupmanagement:management' %}">{% translate "Group Management" %}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
<li class="nav-item ">
|
||||||
<ul class="nav navbar-nav">
|
<a class="nav-link {% navactive request 'groupmanagement:management' %}" href="{% url 'groupmanagement:management' %}">{% translate "Group Requests" %}</a>
|
||||||
<li class="{% navactive request 'groupmanagement:management' %}">
|
|
||||||
<a href="{% url 'groupmanagement:management' %}">{% translate "Group Requests" %}</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li class="{% navactive request 'groupmanagement:membership groupmanagement:audit_log' %}">
|
<li class="nav-item ">
|
||||||
<a href="{% url 'groupmanagement:membership' %}">{% translate "Group Membership" %}</a>
|
<a class="nav-link {% navactive request 'groupmanagement:membership groupmanagement:audit_log' %}" href="{% url 'groupmanagement:membership' %}">{% translate "Group Membership" %}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|||||||
@@ -6,22 +6,22 @@ from django.conf import settings
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.admin.sites import AdminSite
|
from django.contrib.admin.sites import AdminSite
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.test import TestCase, RequestFactory, Client, override_settings
|
from django.test import Client, RequestFactory, TestCase, override_settings
|
||||||
|
|
||||||
from allianceauth.authentication.models import CharacterOwnership, State
|
from allianceauth.authentication.models import CharacterOwnership, State
|
||||||
from allianceauth.eveonline.models import (
|
from allianceauth.eveonline.models import (
|
||||||
EveCharacter, EveCorporationInfo, EveAllianceInfo
|
EveAllianceInfo, EveCharacter, EveCorporationInfo,
|
||||||
)
|
)
|
||||||
from allianceauth.tests.auth_utils import AuthUtils
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
|
||||||
from . import get_admin_change_view_url
|
from ..admin import Group, GroupAdmin, HasLeaderFilter
|
||||||
from ..admin import HasLeaderFilter, GroupAdmin, Group
|
|
||||||
from ..models import ReservedGroupName
|
from ..models import ReservedGroupName
|
||||||
|
from . import get_admin_change_view_url
|
||||||
|
|
||||||
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
||||||
_has_auto_groups = True
|
_has_auto_groups = True
|
||||||
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
|
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
|
||||||
|
|
||||||
from ..admin import IsAutoGroupFilter
|
from ..admin import IsAutoGroupFilter
|
||||||
else:
|
else:
|
||||||
_has_auto_groups = False
|
_has_auto_groups = False
|
||||||
@@ -621,21 +621,16 @@ class TestGroupAdmin2(TestCase):
|
|||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
f"/admin/groupmanagement/group/{group.pk}/change/",
|
f"/admin/groupmanagement/group/{group.pk}/change/",
|
||||||
data={
|
data={
|
||||||
"name": f"{group.name}",
|
"name": group.name,
|
||||||
"authgroup-TOTAL_FORMS": "1",
|
"users": [user_member.pk, user_guest.pk],
|
||||||
"authgroup-INITIAL_FORMS": "1",
|
"authgroup-TOTAL_FORMS": 1,
|
||||||
"authgroup-MIN_NUM_FORMS": "0",
|
"authgroup-INITIAL_FORMS": 1,
|
||||||
"authgroup-MAX_NUM_FORMS": "1",
|
"authgroup-MIN_NUM_FORMS": 0,
|
||||||
"authgroup-0-description": "",
|
"authgroup-MAX_NUM_FORMS": 1,
|
||||||
"authgroup-0-states": f"{member_state.pk}",
|
"authgroup-0-states": member_state.pk,
|
||||||
"authgroup-0-internal": "on",
|
"authgroup-0-internal": "on",
|
||||||
"authgroup-0-hidden": "on",
|
"authgroup-0-hidden": "on",
|
||||||
"authgroup-0-group": f"{group.pk}",
|
"authgroup-0-group": group.pk,
|
||||||
"authgroup-__prefix__-description": "",
|
|
||||||
"authgroup-__prefix__-internal": "on",
|
|
||||||
"authgroup-__prefix__-hidden": "on",
|
|
||||||
"authgroup-__prefix__-group": f"{group.pk}",
|
|
||||||
"_save": "Save"
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# then
|
# then
|
||||||
@@ -644,6 +639,85 @@ class TestGroupAdmin2(TestCase):
|
|||||||
self.assertIn(group, user_member.groups.all())
|
self.assertIn(group, user_member.groups.all())
|
||||||
self.assertNotIn(group, user_guest.groups.all())
|
self.assertNotIn(group, user_guest.groups.all())
|
||||||
|
|
||||||
|
def test_should_add_user_to_existing_group(self):
|
||||||
|
# given
|
||||||
|
user_bruce = AuthUtils.create_user("Bruce Wayne")
|
||||||
|
user_lex = AuthUtils.create_user("Lex Luthor")
|
||||||
|
group = Group.objects.create(name="dummy")
|
||||||
|
user_bruce.groups.add(group)
|
||||||
|
self.client.force_login(self.superuser)
|
||||||
|
# when
|
||||||
|
response = self.client.post(
|
||||||
|
f"/admin/groupmanagement/group/{group.pk}/change/",
|
||||||
|
data={
|
||||||
|
"name": group.name,
|
||||||
|
"users": [user_bruce.pk, user_lex.pk],
|
||||||
|
"authgroup-TOTAL_FORMS": 1,
|
||||||
|
"authgroup-INITIAL_FORMS": 1,
|
||||||
|
"authgroup-MIN_NUM_FORMS": 0,
|
||||||
|
"authgroup-MAX_NUM_FORMS": 1,
|
||||||
|
"authgroup-0-internal": "on",
|
||||||
|
"authgroup-0-hidden": "on",
|
||||||
|
"authgroup-0-group": group.pk,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# then
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
self.assertEqual(response.url, "/admin/groupmanagement/group/")
|
||||||
|
self.assertIn(group, user_bruce.groups.all())
|
||||||
|
self.assertIn(group, user_lex.groups.all())
|
||||||
|
|
||||||
|
def test_should_remove_user_from_existing_group(self):
|
||||||
|
# given
|
||||||
|
user_bruce = AuthUtils.create_user("Bruce Wayne")
|
||||||
|
user_lex = AuthUtils.create_user("Lex Luthor")
|
||||||
|
group = Group.objects.create(name="dummy")
|
||||||
|
user_bruce.groups.add(group)
|
||||||
|
user_lex.groups.add(group)
|
||||||
|
self.client.force_login(self.superuser)
|
||||||
|
# when
|
||||||
|
response = self.client.post(
|
||||||
|
f"/admin/groupmanagement/group/{group.pk}/change/",
|
||||||
|
data={
|
||||||
|
"name": group.name,
|
||||||
|
"users": user_bruce.pk,
|
||||||
|
"authgroup-TOTAL_FORMS": 1,
|
||||||
|
"authgroup-INITIAL_FORMS": 1,
|
||||||
|
"authgroup-MIN_NUM_FORMS": 0,
|
||||||
|
"authgroup-MAX_NUM_FORMS": 1,
|
||||||
|
"authgroup-0-internal": "on",
|
||||||
|
"authgroup-0-hidden": "on",
|
||||||
|
"authgroup-0-group": group.pk,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# then
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
self.assertEqual(response.url, "/admin/groupmanagement/group/")
|
||||||
|
self.assertIn(group, user_bruce.groups.all())
|
||||||
|
self.assertNotIn(group, user_lex.groups.all())
|
||||||
|
|
||||||
|
def test_should_include_user_when_creating_group(self):
|
||||||
|
# given
|
||||||
|
user_bruce = AuthUtils.create_user("Bruce Wayne")
|
||||||
|
self.client.force_login(self.superuser)
|
||||||
|
# when
|
||||||
|
response = self.client.post(
|
||||||
|
"/admin/groupmanagement/group/add/",
|
||||||
|
data={
|
||||||
|
"name": "new group",
|
||||||
|
"users": user_bruce.pk,
|
||||||
|
"authgroup-TOTAL_FORMS": 1,
|
||||||
|
"authgroup-INITIAL_FORMS": 0,
|
||||||
|
"authgroup-MIN_NUM_FORMS": 0,
|
||||||
|
"authgroup-MAX_NUM_FORMS": 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# then
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
self.assertEqual(response.url, "/admin/groupmanagement/group/")
|
||||||
|
group = Group.objects.get(name="new group")
|
||||||
|
self.assertIn(group, user_bruce.groups.all())
|
||||||
|
|
||||||
|
|
||||||
class TestReservedGroupNameAdmin(TestCase):
|
class TestReservedGroupNameAdmin(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from django.test import RequestFactory, TestCase, override_settings
|
from django.test import RequestFactory, TestCase, override_settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from allianceauth.groupmanagement.models import Group, GroupRequest
|
||||||
from allianceauth.tests.auth_utils import AuthUtils
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
|
||||||
from .. import views
|
from .. import views
|
||||||
@@ -16,6 +17,7 @@ class TestViews(TestCase):
|
|||||||
self.factory = RequestFactory()
|
self.factory = RequestFactory()
|
||||||
self.user = AuthUtils.create_user('Peter Parker')
|
self.user = AuthUtils.create_user('Peter Parker')
|
||||||
self.user_with_manage_permission = AuthUtils.create_user('Bruce Wayne')
|
self.user_with_manage_permission = AuthUtils.create_user('Bruce Wayne')
|
||||||
|
self.group = Group.objects.create(name="Example group")
|
||||||
|
|
||||||
# set permissions
|
# set permissions
|
||||||
AuthUtils.add_permission_to_user_by_name(
|
AuthUtils.add_permission_to_user_by_name(
|
||||||
@@ -64,7 +66,7 @@ class TestViews(TestCase):
|
|||||||
content = response_content_to_str(response)
|
content = response_content_to_str(response)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertIn('<a data-toggle="tab" href="#leave">', content)
|
self.assertIn('id="leave-tab" data-bs-toggle="tab" data-bs-target="#leave"', content)
|
||||||
self.assertIn('<div id="leave" class="tab-pane">', content)
|
self.assertIn('<div id="leave" class="tab-pane">', content)
|
||||||
|
|
||||||
@override_settings(GROUPMANAGEMENT_AUTO_LEAVE=True)
|
@override_settings(GROUPMANAGEMENT_AUTO_LEAVE=True)
|
||||||
@@ -81,5 +83,21 @@ class TestViews(TestCase):
|
|||||||
content = response_content_to_str(response)
|
content = response_content_to_str(response)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertNotIn('<a data-toggle="tab" href="#leave">', content)
|
self.assertNotIn('id="leave-tab" data-bs-toggle="tab" data-bs-target="#leave"', content)
|
||||||
self.assertNotIn('<div id="leave" class="tab-pane">', content)
|
self.assertNotIn('<div id="leave" class="tab-pane">', content)
|
||||||
|
|
||||||
|
@override_settings(GROUPMANAGEMENT_AUTO_LEAVE=True)
|
||||||
|
def test_should_not_hide_leave_requests_tab_when_there_are_open_requests(self):
|
||||||
|
# given
|
||||||
|
request = self.factory.get(reverse('groupmanagement:management'))
|
||||||
|
request.user = self.user_with_manage_permission
|
||||||
|
GroupRequest.objects.create(user=self.user, group=self.group, leave_request=True)
|
||||||
|
|
||||||
|
# when
|
||||||
|
response = views.group_management(request)
|
||||||
|
|
||||||
|
# then
|
||||||
|
content = response_content_to_str(response)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertIn('<a class="nav-link" id="leave-tab" data-bs-toggle="tab" data-bs-target="#leave"', content)
|
||||||
|
self.assertIn('<div id="leave" class="tab-pane">', content)
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ import logging
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.shortcuts import render, redirect, get_object_or_404
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from allianceauth.notifications import notify
|
from allianceauth.notifications import notify
|
||||||
@@ -16,7 +15,6 @@ from allianceauth.notifications import notify
|
|||||||
from .managers import GroupManager
|
from .managers import GroupManager
|
||||||
from .models import GroupRequest, RequestLog
|
from .models import GroupRequest, RequestLog
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -45,10 +43,15 @@ def group_management(request):
|
|||||||
logger.debug("Providing user {} with {} acceptrequests and {} leaverequests.".format(
|
logger.debug("Providing user {} with {} acceptrequests and {} leaverequests.".format(
|
||||||
request.user, len(acceptrequests), len(leaverequests)))
|
request.user, len(acceptrequests), len(leaverequests)))
|
||||||
|
|
||||||
|
show_leave_tab = (
|
||||||
|
getattr(settings, 'GROUPMANAGEMENT_AUTO_LEAVE', False)
|
||||||
|
and not GroupRequest.objects.filter(leave_request=True).exists()
|
||||||
|
)
|
||||||
|
|
||||||
render_items = {
|
render_items = {
|
||||||
'acceptrequests': acceptrequests,
|
'acceptrequests': acceptrequests,
|
||||||
'leaverequests': leaverequests,
|
'leaverequests': leaverequests,
|
||||||
'auto_leave': getattr(settings, 'GROUPMANAGEMENT_AUTO_LEAVE', False),
|
'show_leave_tab': show_leave_tab,
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(request, 'groupmanagement/index.html', context=render_items)
|
return render(request, 'groupmanagement/index.html', context=render_items)
|
||||||
@@ -87,7 +90,7 @@ def group_membership_audit(request, group_id):
|
|||||||
|
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
raise Http404("Group does not exist")
|
raise Http404("Group does not exist")
|
||||||
render_items = {'group': group.name}
|
render_items = {'group': group}
|
||||||
entries = RequestLog.objects.filter(group=group).order_by('-date')
|
entries = RequestLog.objects.filter(group=group).order_by('-date')
|
||||||
render_items['entries'] = entries
|
render_items['entries'] = entries
|
||||||
|
|
||||||
@@ -311,8 +314,10 @@ def groups_view(request):
|
|||||||
groups_qs = GroupManager.get_joinable_groups_for_user(
|
groups_qs = GroupManager.get_joinable_groups_for_user(
|
||||||
request.user, include_hidden=False
|
request.user, include_hidden=False
|
||||||
)
|
)
|
||||||
groups_qs = groups_qs.order_by('name')
|
groups_qs = groups_qs.order_by('name').select_related("authgroup").prefetch_related('authgroup__group_leaders', 'authgroup__group_leaders__profile__main_character', 'authgroup__group_leader_groups')
|
||||||
groups = []
|
groups = []
|
||||||
|
|
||||||
|
## TODO see about making this faster
|
||||||
for group in groups_qs:
|
for group in groups_qs:
|
||||||
group_request = GroupRequest.objects\
|
group_request = GroupRequest.objects\
|
||||||
.filter(user=request.user)\
|
.filter(user=request.user)\
|
||||||
@@ -322,7 +327,14 @@ def groups_view(request):
|
|||||||
'request': group_request[0] if group_request else None
|
'request': group_request[0] if group_request else None
|
||||||
})
|
})
|
||||||
|
|
||||||
context = {'groups': groups}
|
count = 0
|
||||||
|
perms = GroupManager.can_manage_groups(request.user)
|
||||||
|
if perms:
|
||||||
|
count = GroupManager.pending_requests_count_for_user(request.user)
|
||||||
|
|
||||||
|
user_groups_list = list(request.user.groups.all())
|
||||||
|
context = {'groups': groups, "manager_perms": perms, "req_count":count, "user_groups": user_groups_list}
|
||||||
|
|
||||||
return render(request, 'groupmanagement/groups.html', context=context)
|
return render(request, 'groupmanagement/groups.html', context=context)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ def get_app_modules():
|
|||||||
|
|
||||||
|
|
||||||
def get_app_submodules(module_name):
|
def get_app_submodules(module_name):
|
||||||
"""
|
"""pyt
|
||||||
Get a specific sub module of the app
|
Get a specific sub module of the app
|
||||||
:param module_name: module name to get
|
:param module_name: module name to get
|
||||||
:return: name, module tuple
|
:return: name, module tuple
|
||||||
@@ -122,3 +122,17 @@ def get_hooks(name):
|
|||||||
"""
|
"""
|
||||||
register_all_hooks()
|
register_all_hooks()
|
||||||
return _hooks.get(name, [])
|
return _hooks.get(name, [])
|
||||||
|
|
||||||
|
|
||||||
|
class DashboardItemHook:
|
||||||
|
def __init__(self, view_function, order:int=10):
|
||||||
|
self.view_function = view_function
|
||||||
|
self.order = order
|
||||||
|
|
||||||
|
def render(self, request):
|
||||||
|
try:
|
||||||
|
logger.debug(f"Rendering {self.view_function} to dashboard")
|
||||||
|
return self.view_function(request)
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"Rendering {self.view_function} failed!")
|
||||||
|
return ""
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from allianceauth import hooks
|
from allianceauth import hooks
|
||||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
from allianceauth.menu.hooks import MenuItemHook
|
||||||
|
from allianceauth.services.hooks import UrlHook
|
||||||
|
|
||||||
from . import urls
|
from . import urls
|
||||||
from .models import Application
|
from .models import Application
|
||||||
@@ -12,7 +13,7 @@ class ApplicationsMenu(MenuItemHook):
|
|||||||
MenuItemHook.__init__(
|
MenuItemHook.__init__(
|
||||||
self,
|
self,
|
||||||
_('Applications'),
|
_('Applications'),
|
||||||
'far fa-file fa-fw',
|
'fa-regular fa-file',
|
||||||
'hrapplications:index',
|
'hrapplications:index',
|
||||||
navactive=['hrapplications:'])
|
navactive=['hrapplications:'])
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,27 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Choose a Corp" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
|
{% translate "Choose a Corp" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "HR Application Management" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
<h1 class="page-header text-center">{% translate "Choose a Corp" %}</h1>
|
{% translate "Choose a Corp" as page_header %}
|
||||||
|
{% include "framework/header/page-header.html" with title=page_header %}
|
||||||
|
|
||||||
{% if choices %}
|
{% if choices %}
|
||||||
<div class="panel panel-primary">
|
<div class="card card-primary">
|
||||||
<div class="panel-heading">{% translate "Available Corps" %}</div>
|
<div class="card-header">
|
||||||
|
<div class="card-title mb-0">{% translate "Available Corps" %}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
<table class="table table-responsive">
|
<table class="table table-responsive">
|
||||||
{% for choice in choices %}
|
{% for choice in choices %}
|
||||||
<tr>
|
<tr>
|
||||||
@@ -18,6 +32,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="alert alert-danger">{% translate "No corps are accepting applications at this time." %}</div>
|
<div class="alert alert-danger">{% translate "No corps are accepting applications at this time." %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -1,35 +1,66 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
{% load django_bootstrap5 %}
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "Apply To" %} {{ corp.corporation_name }}{% endblock page_title %}
|
{% block page_title %}
|
||||||
|
{% translate "Apply To" %} {{ corp.corporation_name }}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "HR Application Management" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
<h1 class="page-header text-center">{% translate "Apply To" %} {{ corp.corporation_name }}</h1>
|
<h1 class="page-header text-center mb-3">
|
||||||
<div class="container-fluid">
|
{% translate "Apply To" %} {{ corp.corporation_name }}
|
||||||
<div class="col-md-4 col-md-offset-4">
|
</h1>
|
||||||
<div class="row">
|
|
||||||
<form class="form-signin">
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title mb-0">
|
||||||
|
{% translate "Application form" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
{% for question in questions %}
|
{% for question in questions %}
|
||||||
<div class="form-group">
|
<div class="card mb-3 form-group border-0">
|
||||||
<label class="control-label" for="id_{{ question.pk }}">{{ question.title }}</label>
|
<div class="card-header">
|
||||||
<div class=" ">
|
<div class="card-title mb-0">{{ question.title }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
{% if question.help_text %}
|
{% if question.help_text %}
|
||||||
<div class="text-center">{{ question.help_text }}</div>
|
<p class="text-muted">
|
||||||
|
{{ question.help_text }}
|
||||||
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for choice in question.choices.all %}
|
{% for choice in question.choices.all %}
|
||||||
<input type={% if question.multi_select == False %}"radio"{% else %}"checkbox"{% endif %} name="{{ question.pk }}" id="id_{{ question.pk }}_choice_{{ forloop.counter }}" value="{{ choice.choice_text }}">
|
<input type="{% if question.multi_select == False %}radio{% else %}checkbox{% endif %}" name="{{ question.pk }}" id="id_{{ question.pk }}_choice_{{ forloop.counter }}" value="{{ choice.choice_text }}">
|
||||||
<label for="id_{{ question.pk }}_choice_{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
|
<label for="id_{{ question.pk }}_choice_{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<textarea class="form-control" cols="30" id="id_{{ question.pk }}" name="{{ question.pk }}" rows="4"></textarea>
|
<textarea class="form-control" cols="30" id="id_{{ question.pk }}" name="{{ question.pk }}" rows="10"></textarea>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<button class="btn btn-lg btn-primary btn-block" type="submit" formmethod="post">{% translate "Submit" %}</button>
|
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
{% translate "Submit" as button_text %}
|
||||||
|
{% bootstrap_button button_class="btn btn-primary" content=button_text name="submitApplicationForm" id="submitApplicationForm" %}
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,14 +1,22 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
{% load bootstrap %}
|
|
||||||
|
{% load django_bootstrap5 %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "HR Application Management" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
{% block extra_css %}{% endblock extra_css %}
|
{% translate "HR Application Management" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "HR Application Management" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
<h1 class="page-header text-center">{% translate "Personal Applications" %}
|
{% translate "Personal Applications" as page_header %}
|
||||||
<div class="text-right">
|
{% include "framework/header/page-header.html" with title=page_header %}
|
||||||
|
|
||||||
|
<div class="text-end mb-3">
|
||||||
{% if create %}
|
{% if create %}
|
||||||
<a href="{% url 'hrapplications:create_view' %}">
|
<a href="{% url 'hrapplications:create_view' %}">
|
||||||
<button type="button" class="btn btn-success">{% translate "Create Application" %}</button>
|
<button type="button" class="btn btn-success">{% translate "Create Application" %}</button>
|
||||||
@@ -17,9 +25,10 @@
|
|||||||
<button type="button" class="btn btn-success" disabled>{% translate "Create Application" %}</button>
|
<button type="button" class="btn btn-success" disabled>{% translate "Create Application" %}</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
|
||||||
{% if personal_apps %}
|
{% if personal_apps %}
|
||||||
<div class="panel panel-default">
|
<div class="card card-default mb-3">
|
||||||
|
<div class="card-body">
|
||||||
<table class="table table-condensed">
|
<table class="table table-condensed">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center">{% translate "Username" %}</th>
|
<th class="text-center">{% translate "Username" %}</th>
|
||||||
@@ -27,27 +36,28 @@
|
|||||||
<th class="text-center">{% translate "Status" %}</th>
|
<th class="text-center">{% translate "Status" %}</th>
|
||||||
<th class="text-center">{% translate "Actions" %}</th>
|
<th class="text-center">{% translate "Actions" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for personal_app in personal_apps %}
|
{% for personal_app in personal_apps %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">{{ personal_app.user.username }}</td>
|
<td class="text-center">{{ personal_app.user.username }}</td>
|
||||||
<td class="text-center">{{ personal_app.form.corp.corporation_name }}</td>
|
<td class="text-center">{{ personal_app.form.corp.corporation_name }}</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
{% if personal_app.approved == None %}
|
{% if personal_app.approved == None %}
|
||||||
<div class="label label-warning">{% translate "Pending" %}</div>
|
<div class="badge bg-warning">{% translate "Pending" %}</div>
|
||||||
{% elif personal_app.approved == True %}
|
{% elif personal_app.approved == True %}
|
||||||
<div class="label label-success">{% translate "Approved" %}</div>
|
<div class="badge bg-success">{% translate "Approved" %}</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="label label-danger">{% translate "Rejected" %}</div>
|
<div class="badge bg-danger">{% translate "Rejected" %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a href="{% url 'hrapplications:personal_view' personal_app.id %}" class="btn btn-primary">
|
<a href="{% url 'hrapplications:personal_view' personal_app.id %}" class="btn btn-primary">
|
||||||
<span class="glyphicon glyphicon-eye-open"></span>
|
<i class="fa-solid fa-eye"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{% if personal_app.approved == None %}
|
{% if personal_app.approved == None %}
|
||||||
<a href="{% url 'hrapplications:personal_removal' personal_app.id %}" class="btn btn-danger">
|
<a href="{% url 'hrapplications:personal_removal' personal_app.id %}" class="btn btn-danger">
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
<i class="fa-solid fa-trash-can"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
@@ -55,23 +65,54 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if perms.auth.human_resources %}
|
{% if perms.auth.human_resources %}
|
||||||
<h1 class="page-header text-center">{% translate "Application Management" %}
|
{% translate "Application Management" as page_header %}
|
||||||
<div class="text-right">
|
{% include "framework/header/page-header.html" with title=page_header %}
|
||||||
|
|
||||||
|
<div class="text-end mb-3">
|
||||||
<!-- Button trigger modal -->
|
<!-- Button trigger modal -->
|
||||||
<button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#myModal">
|
<button type="button" class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#modal-hr-search">
|
||||||
{% translate "Search Applications" %}
|
{% translate "Search Applications" %}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
|
||||||
<ul class="nav nav-tabs">
|
<div class="card card-default">
|
||||||
<li class="active"><a data-toggle="tab" href="#pending">{% translate "Pending" %}</a></li>
|
<div class="card-body clearfix">
|
||||||
<li><a data-toggle="tab" href="#reviewed">{% translate "Reviewed" %}</a></li>
|
<ul class="nav nav-tabs" id="application-list" role="tablist">
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<a
|
||||||
|
class="nav-link active"
|
||||||
|
id="pending"
|
||||||
|
data-bs-toggle="tab"
|
||||||
|
href="#tab-pending"
|
||||||
|
role="tab"
|
||||||
|
aria-controls="tab-pending"
|
||||||
|
aria-selected="true"
|
||||||
|
>
|
||||||
|
{% translate "Pending" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<a
|
||||||
|
class="nav-link"
|
||||||
|
id="reviewed"
|
||||||
|
data-bs-toggle="tab"
|
||||||
|
href="#tab-reviewed"
|
||||||
|
role="tab"
|
||||||
|
aria-controls="tab-reviewed"
|
||||||
|
aria-selected="false"
|
||||||
|
>
|
||||||
|
{% translate "Reviewed" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content">
|
|
||||||
<div id="pending" class="tab-pane fade in active panel panel-default">
|
<div class="tab-content" id="application-list-content">
|
||||||
<div class="panel-body">
|
<div id="tab-pending" class="tab-pane fade show active" role="tabpanel" aria-labelledby="tab-pending">
|
||||||
{% if applications %}
|
{% if applications %}
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -82,6 +123,7 @@
|
|||||||
<th class="text-center">{% translate "Status" %}</th>
|
<th class="text-center">{% translate "Status" %}</th>
|
||||||
<th class="text-center">{% translate "Actions" %}</th>
|
<th class="text-center">{% translate "Actions" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for app in applications %}
|
{% for app in applications %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">{{ app.created }}</td>
|
<td class="text-center">{{ app.created }}</td>
|
||||||
@@ -91,19 +133,19 @@
|
|||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
{% if app.approved == None %}
|
{% if app.approved == None %}
|
||||||
{% if app.reviewer_str %}
|
{% if app.reviewer_str %}
|
||||||
<div class="label label-info">{% translate "Reviewer:" %} {{ app.reviewer_str }}</div>
|
<div class="badge bg-info">{% translate "Reviewer:" %} {{ app.reviewer_str }}</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="label label-warning">{% translate "Pending" %}</div>
|
<div class="badge bg-warning">{% translate "Pending" %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif app.approved == True %}
|
{% elif app.approved == True %}
|
||||||
<div class="label label-success">{% translate "Approved" %}</div>
|
<div class="badge bg-success">{% translate "Approved" %}</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="label label-danger">{% translate "Rejected" %}</div>
|
<div class="badge bg-danger">{% translate "Rejected" %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a href="{% url 'hrapplications:view' app.id %}" class="btn btn-primary">
|
<a href="{% url 'hrapplications:view' app.id %}" class="btn btn-primary">
|
||||||
<span class="glyphicon glyphicon-eye-open"></span>
|
<i class="fa-solid fa-eye"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -113,9 +155,8 @@
|
|||||||
<div class="alert alert-warning text-center">{% translate "No pending applications." %}</div>
|
<div class="alert alert-warning text-center">{% translate "No pending applications." %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div id="reviewed" class="tab-pane fade panel panel-default">
|
<div id="tab-reviewed" class="tab-pane fade" role="tabpanel" aria-labelledby="tab-reviewed">
|
||||||
<div class="panel-body">
|
|
||||||
{% if finished_applications %}
|
{% if finished_applications %}
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -126,6 +167,7 @@
|
|||||||
<th class="text-center">{% translate "Status" %}</th>
|
<th class="text-center">{% translate "Status" %}</th>
|
||||||
<th class="text-center">{% translate "Actions" %}</th>
|
<th class="text-center">{% translate "Actions" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for app in finished_applications %}
|
{% for app in finished_applications %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">{{ app.created }}</td>
|
<td class="text-center">{{ app.created }}</td>
|
||||||
@@ -135,23 +177,24 @@
|
|||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
{% if app.approved == None %}
|
{% if app.approved == None %}
|
||||||
{% if app.reviewer_str %}
|
{% if app.reviewer_str %}
|
||||||
<div class="label label-info">{% translate "Reviewer:" %} {{ app.reviewer_str }}</div>
|
<div class="badge bg-info">{% translate "Reviewer:" %} {{ app.reviewer_str }}</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="label label-warning">{% translate "Pending" %}</div>
|
<div class="badge bg-warning">{% translate "Pending" %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif app.approved == True %}
|
{% elif app.approved == True %}
|
||||||
<div class="label label-success">{% translate "Approved" %}</div>
|
<div class="badge bg-success">{% translate "Approved" %}</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="label label-danger">{% translate "Rejected" %}</div>
|
<div class="badge bg-danger">{% translate "Rejected" %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a href="{% url 'hrapplications:view' app.id %}" class="btn btn-primary">
|
<a href="{% url 'hrapplications:view' app.id %}" class="btn btn-primary">
|
||||||
<span class="glyphicon glyphicon-eye-open"></span>
|
<i class="fa-solid fa-eye"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{% if perms.hrapplications.delete_application %}
|
{% if perms.hrapplications.delete_application %}
|
||||||
<a href="{% url 'hrapplications:remove' app.id %}" class="btn btn-danger">
|
<a href="{% url 'hrapplications:remove' app.id %}" class="btn btn-danger">
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
<i class="fa-solid fa-trash-can"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
@@ -164,30 +207,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if perms.auth.human_resources %}
|
{% include "hrapplications/partials/modals/search.html" %}
|
||||||
<!-- Modal -->
|
|
||||||
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">{% translate "Close" %}</span></button>
|
|
||||||
<h4 class="modal-title" id="myModalLabel">{% translate "Application Search" %}</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form class="form-signin" role="form" action="{% url 'hrapplications:search' %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ search_form|bootstrap }}
|
|
||||||
<br>
|
|
||||||
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Search" %}</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
{% load django_bootstrap5 %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% if perms.auth.human_resources %}
|
||||||
|
<!-- Modal -->
|
||||||
|
<div class="modal fade" id="modal-hr-search" tabindex="-1" aria-labelledby="modalHrSearch" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<div class="modal-title fs-5" id="modalHrSearchLabel">
|
||||||
|
{% translate "Application Search" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Close' %}"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<form class="form-signin" role="form" action="{% url 'hrapplications:search' %}" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
{% bootstrap_form search_form %}
|
||||||
|
|
||||||
|
<div class="form-group mt-3 clearfix">
|
||||||
|
{% translate "Search" as button_text %}
|
||||||
|
{% bootstrap_button button_class="btn btn-primary" content=button_text name="search" id="search" %}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
@@ -1,49 +1,58 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
|
|
||||||
{% load bootstrap %}
|
{% load bootstrap %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "HR Application Management" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
{% block extra_css %}{% endblock extra_css %}
|
{% translate "HR Application Management" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "HR Application Management" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
{% if perms.auth.human_resources %}
|
{% if perms.auth.human_resources %}
|
||||||
<h1 class="page-header text-center">{% translate "Application Search Results" %}
|
{% translate "Application Search Results" as page_header %}
|
||||||
<div class="text-right">
|
{% include "framework/header/page-header.html" with title=page_header %}
|
||||||
|
|
||||||
|
<div class="text-end mb-3">
|
||||||
<!-- Button trigger modal -->
|
<!-- Button trigger modal -->
|
||||||
<button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#myModal">
|
<button type="button" class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#modal-hr-search">
|
||||||
{% translate "Search Applications" %}
|
{% translate "Search Applications" %}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</h1>
|
|
||||||
<div class="container-fluid">
|
<div>
|
||||||
<table class="table table-bordered">
|
<table class="table">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center">{% translate "Application ID" %}</th>
|
<th>{% translate "Application ID" %}</th>
|
||||||
<th class="text-center">{% translate "Username" %}</th>
|
<th>{% translate "Username" %}</th>
|
||||||
<th class="text-center">{% translate "Main Character" %}</th>
|
<th>{% translate "Main Character" %}</th>
|
||||||
<th class="text-center">{% translate "Corporation" %}</th>
|
<th>{% translate "Corporation" %}</th>
|
||||||
<th class="text-center">{% translate "Status" %}</th>
|
<th class="text-center">{% translate "Status" %}</th>
|
||||||
<th class="text-center">{% translate "Actions" %}</th>
|
<th class="text-end">{% translate "Actions" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for app in applications %}
|
{% for app in applications %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">{{ app.id }}</td>
|
<td>{{ app.id }}</td>
|
||||||
<td class="text-center">{{ app.user }}</td>
|
<td>{{ app.user }}</td>
|
||||||
<td class="text-center">{{ app.main_character }}</td>
|
<td >{{ app.main_character }}</td>
|
||||||
<td class="text-center">{{ app.form.corp }}</td>
|
<td>{{ app.form.corp }}</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
{% if app.approved == None %}
|
{% if app.approved == None %}
|
||||||
<div class="label label-warning">{% translate "Pending" %}</div>
|
<div class="badge bg-warning">{% translate "Pending" %}</div>
|
||||||
{% elif app.approved == True %}
|
{% elif app.approved == True %}
|
||||||
<div class="label label-success">{% translate "Approved" %}</div>
|
<div class="badge bg-success">{% translate "Approved" %}</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="label label-danger">{% translate "Rejected" %}</div>
|
<div class="badge bg-danger">{% translate "Rejected" %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-end">
|
||||||
<a href="{% url 'hrapplications:view' app.id %}" class="btn btn-primary">
|
<a href="{% url 'hrapplications:view' app.id %}" class="btn btn-primary">
|
||||||
<span class="glyphicon glyphicon-eye-open"></span>
|
<i class="fa-solid fa-eye"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -53,27 +62,5 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if perms.auth.human_resources %}
|
{% include "hrapplications/partials/modals/search.html" %}
|
||||||
<!-- Modal -->
|
|
||||||
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">{% translate "Close" %}</span></button>
|
|
||||||
<h4 class="modal-title" id="myModalLabel">{% translate "Application Search" %}</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form class="form-signin" role="form" action="{% url 'hrapplications:search' %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ search_form|bootstrap }}
|
|
||||||
<br>
|
|
||||||
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Search" %}</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base-bs5.html" %}
|
||||||
{% load bootstrap %}
|
|
||||||
|
{% load django_bootstrap5 %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}{% translate "View Application" %}{% endblock page_title %}
|
{% block page_title %}
|
||||||
{% block extra_css %}{% endblock extra_css %}
|
{% translate "View Application" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block header_nav_brand %}
|
||||||
|
{% translate "HR Application Management" %}
|
||||||
|
{% endblock header_nav_brand %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div>
|
||||||
<h1 class="page-header text-center">{% translate "View Application" %}</h1>
|
{% translate "View Application" as page_header %}
|
||||||
<div class="container-fluid">
|
{% include "framework/header/page-header.html" with title=page_header %}
|
||||||
<div class="col-md-6 col-md-offset-3">
|
|
||||||
<div class="row">
|
<div>
|
||||||
{% if app.approved %}
|
{% if app.approved %}
|
||||||
<div class="alert alert-success text-center">{% translate "Approved" %}</div>
|
<div class="alert alert-success text-center">{% translate "Approved" %}</div>
|
||||||
{% elif app.approved == False %}
|
{% elif app.approved == False %}
|
||||||
@@ -18,13 +24,18 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<div class="alert alert-warning text-center">{% translate "Pending" %}</div>
|
<div class="alert alert-warning text-center">{% translate "Pending" %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if app.reviewer_str %}
|
{% if app.reviewer_str %}
|
||||||
<div class="alert alert-info text-center">{% translate "Reviewer:" %} {{ app.reviewer_str }}</div>
|
<div class="alert alert-info text-center">{% translate "Reviewer:" %} {{ app.reviewer_str }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div class="panel panel-info">
|
<div class="card mb-3">
|
||||||
<div class="panel-heading">{% translate "Applicant" %}</div>
|
<div class="card-header bg-info">
|
||||||
|
<div class="card-title mb-0">{% translate "Applicant" %}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center">{% translate "User" %}</th>
|
<th class="text-center">{% translate "User" %}</th>
|
||||||
@@ -36,49 +47,61 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-info">
|
</div>
|
||||||
<div class="panel-heading">{% translate "Characters" %}</div>
|
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header bg-info">
|
||||||
|
<div class="card-title mb-0">{% translate "Characters" %}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center"></th>
|
<th></th>
|
||||||
<th class="text-center">{% translate "Name" %}</th>
|
<th>{% translate "Name" %}</th>
|
||||||
<th class="text-center">{% translate "Corp" %}</th>
|
<th>{% translate "Corporation" %}</th>
|
||||||
<th class="text-center">{% translate "Alliance" %}</th>
|
<th>{% translate "Alliance" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for char in app.characters %}
|
{% for char in app.characters %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">
|
<td>
|
||||||
<img class="ra-avatar img-responsive img-circle" src="{{ char.portrait_url_32 }}" alt="{{ char.character_name }}">
|
<img class="ra-avatar img-responsive rounded-circle" src="{{ char.portrait_url_32 }}" alt="{{ char.character_name }}">
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">{{ char.character_name }}</td>
|
<td>{{ char.character_name }}</td>
|
||||||
<td class="text-center">{{ char.corporation_name }}</td>
|
<td>{{ char.corporation_name }}</td>
|
||||||
<td class="text-center">{{ char.alliance_name }}</td>
|
<td>{{ char.alliance_name }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
{% for response in responses %}
|
{% for response in responses %}
|
||||||
<div class="panel panel-default">
|
<div class="card mb-3">
|
||||||
<div class="panel-heading">{{ response.question.title }}</div>
|
<div class="card-header">
|
||||||
<div class="alert">{{ response.answer|linebreaksbr }}</div>
|
<div class="card-title mb-0">{{ response.question.title }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">{{ response.answer|linebreaksbr }}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
|
||||||
{% if buttons %}
|
{% if buttons %}
|
||||||
{% if perms.auth.human_resources %}
|
{% if perms.auth.human_resources %}
|
||||||
<div class="row">
|
<div class="card mb-3">
|
||||||
<div class="panel panel-primary">
|
<div class="card-header">
|
||||||
<div class="panel-heading">{% translate "Actions" %}</div>
|
<div class="card-title mb-0">{% translate "Actions" %}</div>
|
||||||
<div class="panel-body text-center">
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body text-center">
|
||||||
{% if app.approved == None %}
|
{% if app.approved == None %}
|
||||||
{% if app.reviewer == user %}
|
{% if app.reviewer == user %}
|
||||||
{% if perms.hrapplications.approve_application %}
|
{% if perms.hrapplications.approve_application %}
|
||||||
<a href="{% url 'hrapplications:approve' app.id %}" class="btn btn-success">{% translate "Approve" %}</a>
|
<a href="{% url 'hrapplications:approve' app.id %}" class="btn btn-success">{% translate "Approve" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.hrapplications.reject_application %}
|
{% if perms.hrapplications.reject_application %}
|
||||||
<a href="{% url 'hrapplications:reject' app.id %}" class="btn btn-danger">{% translate "Reject" %}</a>
|
<a href="{% url 'hrapplications:reject' app.id %}" class="btn btn-warning">{% translate "Reject" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.hrapplications.delete_application %}
|
{% if perms.hrapplications.delete_application %}
|
||||||
<a href="{% url 'hrapplications:remove' app.id %}" class="btn btn-danger">{% translate "Delete" %}</a>
|
<a href="{% url 'hrapplications:remove' app.id %}" class="btn btn-danger">{% translate "Delete" %}</a>
|
||||||
@@ -87,63 +110,70 @@
|
|||||||
<a href="{% url 'hrapplications:mark_in_progress' app.id %}" class="btn btn-warning">{% translate "Mark in Progress" %}</a>
|
<a href="{% url 'hrapplications:mark_in_progress' app.id %}" class="btn btn-warning">{% translate "Mark in Progress" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if perms.hrapplications.add_applicationcomment %}
|
{% if perms.hrapplications.add_applicationcomment %}
|
||||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal">{% translate "Comment" %}</button>
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modal-hr-comment">{% translate "Comment" %}</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
|
<div class="card-group" id="accordion" role="tablist" aria-multiselectable="true">
|
||||||
<div class="panel panel-default">
|
<div class="card card-default">
|
||||||
<div class="panel-heading" role="tab" id="headingThree">
|
<div class="card-header">
|
||||||
<h4 class="panel-title">
|
<div class="card-title mb-0">
|
||||||
<a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
|
||||||
{% translate 'Comments' %} ({{ comments.count }})
|
{% translate 'Comments' %} ({{ comments.count }})
|
||||||
</a>
|
|
||||||
</h4>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="collapseThree" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingThree">
|
</div>
|
||||||
<div class="panel-body">
|
|
||||||
|
<div class="card-body">
|
||||||
|
{% if comments %}
|
||||||
{% for comment in comments %}
|
{% for comment in comments %}
|
||||||
<div class="panel panel-default">
|
<div class="card card-default">
|
||||||
<div class="panel-heading" role="tab" id="">
|
<div class="card-header" role="tab" id="">
|
||||||
<div class="panel-title">
|
<div class="card-title mb-0 clearfix">
|
||||||
<div class="pull-right">{{ comment.created }}</div>
|
<div class="float-md-end">{{ comment.created }}</div>
|
||||||
<div class="pull-left">{% if comment.user.profile.main_character %}{{ comment.user.profile.main_character }}{% else %}{{ comment.user }}{% endif %}</div>
|
<div class="float-md-start">{% if comment.user.profile.main_character %}{{ comment.user.profile.main_character }}{% else %}{{ comment.user }}{% endif %}</div>
|
||||||
<div class="clearfix"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">{{ comment.text|linebreaks }}</div>
|
<div class="card-body">{{ comment.text|linebreaks }}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-info">
|
||||||
|
{% translate "No comments" %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% if perms.hrapplications.add_applicationcomment %}
|
{% if perms.hrapplications.add_applicationcomment %}
|
||||||
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
<div class="modal fade" id="modal-hr-comment" tabindex="-1" aria-labelledby="modalHrComment" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal">
|
<div class="modal-title fs-5" id="modalHrCommentLabel">
|
||||||
<span aria-hidden="true">×</span><span class="sr-only">{% translate "Close" %}</span>
|
{% translate "Add Comment" %}
|
||||||
</button>
|
|
||||||
<h4 class="modal-title" id="myModalLabel">{% translate "Add Comment" %}</h4>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Close' %}"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form class="form-signin" role="form" action="" method="POST">
|
<form class="form-signin" role="form" action="" method="POST">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ comment_form|bootstrap }}
|
|
||||||
<br>
|
{% bootstrap_form comment_form %}
|
||||||
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Add Comment" %}</button>
|
|
||||||
|
<div class="form-group mt-3 clearfix">
|
||||||
|
{% translate "Add comment" as button_text %}
|
||||||
|
{% bootstrap_button button_class="btn btn-primary" content=button_text name="addComment" id="addComment" %}
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Binary file not shown.
@@ -4,9 +4,9 @@
|
|||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# Erik Kalkoken <erik.kalkoken@gmail.com>, 2020
|
# Erik Kalkoken <erik.kalkoken@gmail.com>, 2023
|
||||||
# Joel Falknau <ozirascal@gmail.com>, 2021
|
# Joel Falknau <ozirascal@gmail.com>, 2023
|
||||||
# Peter Pfeufer, 2022
|
# Peter Pfeufer, 2023
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -14,8 +14,8 @@ 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: 2022-10-09 18:20+1000\n"
|
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
|
||||||
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
|
"PO-Revision-Date: 2023-10-08 09:23+0000\n"
|
||||||
"Last-Translator: Peter Pfeufer, 2022\n"
|
"Last-Translator: Peter Pfeufer, 2023\n"
|
||||||
"Language-Team: German (https://app.transifex.com/alliance-auth/teams/107430/de/)\n"
|
"Language-Team: German (https://app.transifex.com/alliance-auth/teams/107430/de/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@@ -34,7 +34,8 @@ msgstr "Google Analytics V4"
|
|||||||
#: allianceauth/authentication/decorators.py:37
|
#: allianceauth/authentication/decorators.py:37
|
||||||
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 ""
|
||||||
"Für diese Aktion wird ein Hauptcharacter benötigt. Bitte füge einen hinzu."
|
"Zur Ausführung dieser Aktion ist ein Hauptcharakter erforderlich. Füge unten"
|
||||||
|
" einen hinzu."
|
||||||
|
|
||||||
#: allianceauth/authentication/forms.py:12
|
#: allianceauth/authentication/forms.py:12
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
@@ -131,7 +132,7 @@ msgstr "Hauptcharakter ändern"
|
|||||||
|
|
||||||
#: allianceauth/authentication/templates/authentication/dashboard.html:125
|
#: allianceauth/authentication/templates/authentication/dashboard.html:125
|
||||||
msgid "Group Memberships"
|
msgid "Group Memberships"
|
||||||
msgstr "Gruppen"
|
msgstr "Gruppenmitgliedschaften"
|
||||||
|
|
||||||
#: allianceauth/authentication/templates/authentication/dashboard.html:145
|
#: allianceauth/authentication/templates/authentication/dashboard.html:145
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:21
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:21
|
||||||
@@ -206,7 +207,7 @@ msgstr ""
|
|||||||
#: allianceauth/authentication/views.py:83
|
#: allianceauth/authentication/views.py:83
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Changed main character to %(char)s"
|
msgid "Changed main character to %(char)s"
|
||||||
msgstr "Haupcharakter geändert zu %(char)s"
|
msgstr "Haupcharakter zu %(char)s geändert"
|
||||||
|
|
||||||
#: allianceauth/authentication/views.py:92
|
#: allianceauth/authentication/views.py:92
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -233,13 +234,12 @@ 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 ""
|
||||||
"Bestätigungsmail gesendet. Bitte folge dem Link in der E-Mail zur "
|
"Bestätigungs-E-Mail gesendet. Bitte folge dem Link, um Deine E-Mail-Adresse "
|
||||||
"Bestätigung."
|
"zu bestätigen."
|
||||||
|
|
||||||
#: allianceauth/authentication/views.py:257
|
#: allianceauth/authentication/views.py:257
|
||||||
msgid "Confirmed your email address. Please login to continue."
|
msgid "Confirmed your email address. Please login to continue."
|
||||||
msgstr ""
|
msgstr "Deine E-Mail Adresse wurde bestätigt. Bitte einloggen zum Fortfahren."
|
||||||
"Deine E-Mail Adresse wurde bestätigt. Bitte log Dich ein um fortzufahren."
|
|
||||||
|
|
||||||
#: allianceauth/authentication/views.py:262
|
#: allianceauth/authentication/views.py:262
|
||||||
msgid "Registration of new accounts is not allowed at this time."
|
msgid "Registration of new accounts is not allowed at this time."
|
||||||
@@ -274,7 +274,7 @@ msgstr "Hauptcharaktere"
|
|||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:22
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:22
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:14
|
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:14
|
||||||
msgid "Members"
|
msgid "Members"
|
||||||
msgstr "Mitgliederzahl"
|
msgstr "Mitglieder"
|
||||||
|
|
||||||
#: allianceauth/corputils/templates/corputils/corpstats.html:35
|
#: allianceauth/corputils/templates/corputils/corpstats.html:35
|
||||||
msgid "Unregistered"
|
msgid "Unregistered"
|
||||||
@@ -282,7 +282,7 @@ msgstr "Nicht registriert"
|
|||||||
|
|
||||||
#: allianceauth/corputils/templates/corputils/corpstats.html:38
|
#: allianceauth/corputils/templates/corputils/corpstats.html:38
|
||||||
msgid "Last update:"
|
msgid "Last update:"
|
||||||
msgstr "Letzes Update:"
|
msgstr "Letzte Aktualisierung:"
|
||||||
|
|
||||||
#: allianceauth/corputils/templates/corputils/corpstats.html:74
|
#: allianceauth/corputils/templates/corputils/corpstats.html:74
|
||||||
#: allianceauth/corputils/templates/corputils/corpstats.html:112
|
#: allianceauth/corputils/templates/corputils/corpstats.html:112
|
||||||
@@ -382,11 +382,11 @@ msgstr "Charakter nicht registriert!"
|
|||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
|
||||||
msgid "This character is not associated with an auth account."
|
msgid "This character is not associated with an auth account."
|
||||||
msgstr "Dieser Charakter ist mit keinen Auth Konto verbunden."
|
msgstr "Dieser Charakter ist keinem Auth Konto zugeordnet."
|
||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
|
||||||
msgid "Add it here"
|
msgid "Add it here"
|
||||||
msgstr "Füge es hier hinzu"
|
msgstr "Füge ihn hier hinzu"
|
||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
|
||||||
msgid "before attempting to click fleet attendance links."
|
msgid "before attempting to click fleet attendance links."
|
||||||
@@ -394,7 +394,7 @@ msgstr "bevor Du versuchst auf FAT-Links zu klicken."
|
|||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:5
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:5
|
||||||
msgid "Create Fatlink"
|
msgid "Create Fatlink"
|
||||||
msgstr "Erstelle FAT-Link"
|
msgstr "FAT-Link erstellen"
|
||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:9
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:9
|
||||||
#: allianceauth/optimer/templates/optimer/add.html:13
|
#: allianceauth/optimer/templates/optimer/add.html:13
|
||||||
@@ -409,20 +409,20 @@ msgstr "Fehlerhafte Anfrage!"
|
|||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:24
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:24
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:63
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:63
|
||||||
msgid "Create fatlink"
|
msgid "Create fatlink"
|
||||||
msgstr "Erstelle FAT-Link"
|
msgstr "FAT-Link erstellen"
|
||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:3
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:3
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:4
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:4
|
||||||
msgid "Fatlink view"
|
msgid "Fatlink view"
|
||||||
msgstr "FAT-Link sehen"
|
msgstr "FAT-Link ansehen"
|
||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:7
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:7
|
||||||
msgid "Edit fatlink"
|
msgid "Edit fatlink"
|
||||||
msgstr "Editiere FAT-Link"
|
msgstr "FAT-Link bearbeiten"
|
||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:11
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:11
|
||||||
msgid "Delete fat"
|
msgid "Delete fat"
|
||||||
msgstr "Lösche FAT"
|
msgstr "FAT löschen"
|
||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:17
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:17
|
||||||
msgid "Registered characters"
|
msgid "Registered characters"
|
||||||
@@ -497,7 +497,7 @@ msgstr[1] "%(user)s hat diesen Monat %(links)s FAT-Links eingesammelt."
|
|||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:26
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:26
|
||||||
msgid "Times used"
|
msgid "Times used"
|
||||||
msgstr "male genutzt"
|
msgstr "Wie oft genutzt"
|
||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:37
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:37
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -570,7 +570,7 @@ msgstr "FAT-Link Statistik"
|
|||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:20
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:20
|
||||||
msgid "Ticker"
|
msgid "Ticker"
|
||||||
msgstr "Ticker: "
|
msgstr "Ticker"
|
||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:8
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:8
|
||||||
msgid "Participation data"
|
msgid "Participation data"
|
||||||
@@ -594,7 +594,7 @@ msgstr "Letzter FAT-Link"
|
|||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:58
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:58
|
||||||
msgid "View statistics"
|
msgid "View statistics"
|
||||||
msgstr "Statistik"
|
msgstr "Statistiken ansehen"
|
||||||
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:95
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:95
|
||||||
msgid "No created fatlinks on record."
|
msgid "No created fatlinks on record."
|
||||||
@@ -713,8 +713,8 @@ msgid ""
|
|||||||
"States listed here will have the ability to join this group provided they "
|
"States listed here will have the ability to join this group provided they "
|
||||||
"have the proper permissions.<br>"
|
"have the proper permissions.<br>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Hier gelistete Ränge können dieser Gruppe beitreten, vorausgesetzt sie haben"
|
"Die hier aufgeführten Status können dieser Gruppe beitreten, sofern sie über"
|
||||||
" die entsprechenden Berechtigungen.<br>"
|
" die entsprechenden Berechtigungen verfügen.<br>"
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:171
|
#: allianceauth/groupmanagement/models.py:171
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -814,7 +814,7 @@ msgstr "Gruppenmitglieder"
|
|||||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:113
|
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:113
|
||||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:21
|
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:21
|
||||||
msgid "Organization"
|
msgid "Organization"
|
||||||
msgstr "Organization"
|
msgstr "Organisation"
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:49
|
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:49
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:75
|
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:75
|
||||||
@@ -933,18 +933,18 @@ msgstr "Gruppenverwaltung"
|
|||||||
|
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:24
|
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:24
|
||||||
msgid "Join Requests"
|
msgid "Join Requests"
|
||||||
msgstr "Beitrittsgesuche"
|
msgstr "Beitrittsanfragen"
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:35
|
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:35
|
||||||
msgid "Leave Requests"
|
msgid "Leave Requests"
|
||||||
msgstr "Austrittsgesuche"
|
msgstr "Austrittsanfragen"
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:57
|
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:57
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:114
|
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:114
|
||||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:18
|
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:18
|
||||||
#: allianceauth/services/modules/openfire/forms.py:6
|
#: allianceauth/services/modules/openfire/forms.py:6
|
||||||
msgid "Group"
|
msgid "Group"
|
||||||
msgstr "Gruppen"
|
msgstr "Gruppe"
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:88
|
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:88
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:145
|
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:145
|
||||||
@@ -968,7 +968,7 @@ msgstr "Keine Gruppenaustrittsanfragen"
|
|||||||
#: allianceauth/groupmanagement/templates/groupmanagement/menu.html:8
|
#: allianceauth/groupmanagement/templates/groupmanagement/menu.html:8
|
||||||
#: allianceauth/templates/allianceauth/top-menu.html:8
|
#: allianceauth/templates/allianceauth/top-menu.html:8
|
||||||
msgid "Toggle navigation"
|
msgid "Toggle navigation"
|
||||||
msgstr "Toggle Navigation"
|
msgstr "Navigation umschalten"
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/menu.html:19
|
#: allianceauth/groupmanagement/templates/groupmanagement/menu.html:19
|
||||||
msgid "Group Requests"
|
msgid "Group Requests"
|
||||||
@@ -994,7 +994,7 @@ msgstr "Gruppe existiert nicht"
|
|||||||
#: allianceauth/groupmanagement/views.py:195
|
#: allianceauth/groupmanagement/views.py:195
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Accepted application from %(mainchar)s to %(group)s."
|
msgid "Accepted application from %(mainchar)s to %(group)s."
|
||||||
msgstr "Beitrittsgesuch von %(mainchar)s zur Gruppe %(group)s zugestimmt."
|
msgstr "Beitrittsanfrage von %(mainchar)s zur Gruppe %(group)s akzeptiert."
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:201
|
#: allianceauth/groupmanagement/views.py:201
|
||||||
#: allianceauth/groupmanagement/views.py:232
|
#: allianceauth/groupmanagement/views.py:232
|
||||||
@@ -1003,18 +1003,18 @@ msgid ""
|
|||||||
"An unhandled error occurred while processing the application from "
|
"An unhandled error occurred while processing the application from "
|
||||||
"%(mainchar)s to %(group)s."
|
"%(mainchar)s to %(group)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Bei der Bearbeitung des Beitrittsgesuchs von %(mainchar)s zur Gruppe "
|
"Bei der Bearbeitung des Beitrittsanfrage von %(mainchar)s zur Gruppe "
|
||||||
"%(group)s ist ein unbehandelter Fehler aufgetreten."
|
"%(group)s ist ein unbehandelter Fehler aufgetreten."
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:226
|
#: allianceauth/groupmanagement/views.py:226
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Rejected application from %(mainchar)s to %(group)s."
|
msgid "Rejected application from %(mainchar)s to %(group)s."
|
||||||
msgstr "Beitrittsgesuch von %(mainchar)s zur Gruppe %(group)s abgelehnt."
|
msgstr "Beitrittsanfrage von %(mainchar)s zur Gruppe %(group)s abgelehnt."
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:261
|
#: allianceauth/groupmanagement/views.py:261
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Accepted application from %(mainchar)s to leave %(group)s."
|
msgid "Accepted application from %(mainchar)s to leave %(group)s."
|
||||||
msgstr "Austrittsgesuch von %(mainchar)s für Gruppe %(group)s akzeptiert."
|
msgstr "Austrittsanfrage von %(mainchar)s für Gruppe %(group)s akzeptiert."
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:266
|
#: allianceauth/groupmanagement/views.py:266
|
||||||
#: allianceauth/groupmanagement/views.py:298
|
#: allianceauth/groupmanagement/views.py:298
|
||||||
@@ -1023,13 +1023,13 @@ msgid ""
|
|||||||
"An unhandled error occurred while processing the application from "
|
"An unhandled error occurred while processing the application from "
|
||||||
"%(mainchar)s to leave %(group)s."
|
"%(mainchar)s to leave %(group)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Bei der Bearbeitung des Austrittsgesuchs von %(mainchar)s für Gruppe "
|
"Bei der Bearbeitung des Austrittsanfrage von %(mainchar)s für Gruppe "
|
||||||
"%(group)s ist ein unbehandelter Fehler aufgetreten."
|
"%(group)s ist ein unbehandelter Fehler aufgetreten."
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:292
|
#: allianceauth/groupmanagement/views.py:292
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Rejected application from %(mainchar)s to leave %(group)s."
|
msgid "Rejected application from %(mainchar)s to leave %(group)s."
|
||||||
msgstr "Austrittsgesuch von %(mainchar)s für Gruppe %(group)s abgelehnt."
|
msgstr "Austrittsanfrage von %(mainchar)s für Gruppe %(group)s abgelehnt."
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:336
|
#: allianceauth/groupmanagement/views.py:336
|
||||||
#: allianceauth/groupmanagement/views.py:346
|
#: allianceauth/groupmanagement/views.py:346
|
||||||
@@ -1042,7 +1042,7 @@ msgstr "Du bist bereits Mitglied dieser Gruppe."
|
|||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:358
|
#: allianceauth/groupmanagement/views.py:358
|
||||||
msgid "You already have a pending application for that group."
|
msgid "You already have a pending application for that group."
|
||||||
msgstr "Du hast Dich bereits für diese Gruppe beworben."
|
msgstr "Du hast bereits für diese Gruppe angefragt."
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:367
|
#: allianceauth/groupmanagement/views.py:367
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -1059,12 +1059,12 @@ msgstr "Du bist kein Mitglied dieser Gruppe"
|
|||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:393
|
#: allianceauth/groupmanagement/views.py:393
|
||||||
msgid "You already have a pending leave request for that group."
|
msgid "You already have a pending leave request for that group."
|
||||||
msgstr "Du hast bereits ein ausstehendes Austrittsgesuch für diese Gruppe."
|
msgstr "Du hast bereits eine ausstehendes Austrittsanfrage für diese Gruppe."
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:409
|
#: allianceauth/groupmanagement/views.py:409
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Applied to leave group %(group)s."
|
msgid "Applied to leave group %(group)s."
|
||||||
msgstr "Austrittsgesuch für Gruppe %(group)s gesendet."
|
msgstr "Austrittsanfrage für Gruppe %(group)s gesendet."
|
||||||
|
|
||||||
#: allianceauth/hrapplications/auth_hooks.py:14
|
#: allianceauth/hrapplications/auth_hooks.py:14
|
||||||
msgid "Applications"
|
msgid "Applications"
|
||||||
@@ -1086,11 +1086,11 @@ msgstr "Wähle eine Corporation"
|
|||||||
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:10
|
#: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:10
|
||||||
msgid "Available Corps"
|
msgid "Available Corps"
|
||||||
msgstr "Zur Auswahl stehende Corporations"
|
msgstr "Verfügbare Corporationen"
|
||||||
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:22
|
#: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:22
|
||||||
msgid "No corps are accepting applications at this time."
|
msgid "No corps are accepting applications at this time."
|
||||||
msgstr "Zur Zeit nimmt keine Corp Bewerbungen entgegen."
|
msgstr "Zur Zeit nimmt keine Corp Bewerbungen an."
|
||||||
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/create.html:4
|
#: allianceauth/hrapplications/templates/hrapplications/create.html:4
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/create.html:7
|
#: allianceauth/hrapplications/templates/hrapplications/create.html:7
|
||||||
@@ -1186,7 +1186,7 @@ msgstr "Keine angesehenen Bewerbungen"
|
|||||||
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:62
|
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:62
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/view.html:134
|
#: allianceauth/hrapplications/templates/hrapplications/view.html:134
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Geschlossen"
|
msgstr "Schließen"
|
||||||
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:177
|
#: allianceauth/hrapplications/templates/hrapplications/management.html:177
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:63
|
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:63
|
||||||
@@ -1200,7 +1200,7 @@ msgstr "Suche"
|
|||||||
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:11
|
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:11
|
||||||
msgid "Application Search Results"
|
msgid "Application Search Results"
|
||||||
msgstr "Bewerbungen Suchergebnisse"
|
msgstr "Ergebnisse der Bewerbungssuche"
|
||||||
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:22
|
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:22
|
||||||
msgid "Application ID"
|
msgid "Application ID"
|
||||||
@@ -1342,12 +1342,12 @@ msgstr "Operationsart"
|
|||||||
#: allianceauth/optimer/form.py:17
|
#: allianceauth/optimer/form.py:17
|
||||||
#: allianceauth/srp/templates/srp/management.html:38
|
#: allianceauth/srp/templates/srp/management.html:38
|
||||||
msgid "Fleet Commander"
|
msgid "Fleet Commander"
|
||||||
msgstr "Flottenkommandeur"
|
msgstr "Flottenkommandant"
|
||||||
|
|
||||||
#: allianceauth/optimer/form.py:22 allianceauth/srp/form.py:14
|
#: allianceauth/optimer/form.py:22 allianceauth/srp/form.py:14
|
||||||
#: allianceauth/srp/templates/srp/data.html:91
|
#: allianceauth/srp/templates/srp/data.html:91
|
||||||
msgid "Additional Info"
|
msgid "Additional Info"
|
||||||
msgstr "Zusätzliche Info"
|
msgstr "Zusätzliche Informationen"
|
||||||
|
|
||||||
#: allianceauth/optimer/form.py:23
|
#: allianceauth/optimer/form.py:23
|
||||||
msgid "(Optional) Describe the operation with a couple of short words."
|
msgid "(Optional) Describe the operation with a couple of short words."
|
||||||
@@ -1360,7 +1360,7 @@ msgstr "Operation erstellen"
|
|||||||
|
|
||||||
#: allianceauth/optimer/templates/optimer/fleetoptable.html:12
|
#: allianceauth/optimer/templates/optimer/fleetoptable.html:12
|
||||||
msgid "Form Up System"
|
msgid "Form Up System"
|
||||||
msgstr "Form Up System"
|
msgstr "Startsystem"
|
||||||
|
|
||||||
#: allianceauth/optimer/templates/optimer/fleetoptable.html:14
|
#: allianceauth/optimer/templates/optimer/fleetoptable.html:14
|
||||||
#: allianceauth/timerboard/templates/timerboard/view.html:36
|
#: allianceauth/timerboard/templates/timerboard/view.html:36
|
||||||
@@ -1384,20 +1384,20 @@ msgstr "Flottenoperationen Zeiten"
|
|||||||
#: allianceauth/optimer/templates/optimer/management.html:20
|
#: allianceauth/optimer/templates/optimer/management.html:20
|
||||||
#: allianceauth/timerboard/templates/timerboard/view.html:22
|
#: allianceauth/timerboard/templates/timerboard/view.html:22
|
||||||
msgid "Current Eve Time:"
|
msgid "Current Eve Time:"
|
||||||
msgstr "Momentane Eve Zeit"
|
msgstr "Aktuelle Eve Zeit"
|
||||||
|
|
||||||
#: allianceauth/optimer/templates/optimer/management.html:26
|
#: allianceauth/optimer/templates/optimer/management.html:26
|
||||||
msgid "Next Fleet Operations"
|
msgid "Next Fleet Operations"
|
||||||
msgstr "Anstehende Flottenoperationen"
|
msgstr "Anstehende Flotten"
|
||||||
|
|
||||||
#: allianceauth/optimer/templates/optimer/management.html:30
|
#: allianceauth/optimer/templates/optimer/management.html:30
|
||||||
#: allianceauth/timerboard/templates/timerboard/view.html:362
|
#: allianceauth/timerboard/templates/timerboard/view.html:362
|
||||||
msgid "No upcoming timers."
|
msgid "No upcoming timers."
|
||||||
msgstr "Keine kommenden Timer."
|
msgstr "Keine bevorstehenden Timer."
|
||||||
|
|
||||||
#: allianceauth/optimer/templates/optimer/management.html:33
|
#: allianceauth/optimer/templates/optimer/management.html:33
|
||||||
msgid "Past Fleet Operations"
|
msgid "Past Fleet Operations"
|
||||||
msgstr "Vergangene Flottenoperationen"
|
msgstr "Vergangene Flotten"
|
||||||
|
|
||||||
#: allianceauth/optimer/templates/optimer/management.html:37
|
#: allianceauth/optimer/templates/optimer/management.html:37
|
||||||
#: allianceauth/timerboard/templates/timerboard/view.html:535
|
#: allianceauth/timerboard/templates/timerboard/view.html:535
|
||||||
@@ -1408,7 +1408,7 @@ msgstr "Keine vergangenen Timer."
|
|||||||
#: allianceauth/optimer/templates/optimer/update.html:15
|
#: allianceauth/optimer/templates/optimer/update.html:15
|
||||||
#: allianceauth/optimer/templates/optimer/update.html:27
|
#: allianceauth/optimer/templates/optimer/update.html:27
|
||||||
msgid "Update Fleet Operation"
|
msgid "Update Fleet Operation"
|
||||||
msgstr "Aktualisiere Flottenoperationen"
|
msgstr "Aktualisiere Flottenoperation"
|
||||||
|
|
||||||
#: allianceauth/optimer/templates/optimer/update.html:21
|
#: allianceauth/optimer/templates/optimer/update.html:21
|
||||||
msgid "Fleet Operation Does Not Exist"
|
msgid "Fleet Operation Does Not Exist"
|
||||||
@@ -1432,7 +1432,7 @@ msgstr "Änderungen für Operation timer %(opname)s gespeichert."
|
|||||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:4
|
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:4
|
||||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:8
|
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:8
|
||||||
msgid "Permissions Audit"
|
msgid "Permissions Audit"
|
||||||
msgstr "Berechtigungsübersicht"
|
msgstr "Berechtigungsprüfung"
|
||||||
|
|
||||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:20
|
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:20
|
||||||
msgid "User / Character"
|
msgid "User / Character"
|
||||||
@@ -1494,11 +1494,11 @@ msgstr "Dienste"
|
|||||||
|
|
||||||
#: allianceauth/services/forms.py:6
|
#: allianceauth/services/forms.py:6
|
||||||
msgid "Name of Fleet:"
|
msgid "Name of Fleet:"
|
||||||
msgstr "SRP Flotte erstellen:"
|
msgstr "Name der Flotte:"
|
||||||
|
|
||||||
#: allianceauth/services/forms.py:7
|
#: allianceauth/services/forms.py:7
|
||||||
msgid "Fleet Commander:"
|
msgid "Fleet Commander:"
|
||||||
msgstr "Flottenkommandeur:"
|
msgstr "Flottenkommandant:"
|
||||||
|
|
||||||
#: allianceauth/services/forms.py:8
|
#: allianceauth/services/forms.py:8
|
||||||
msgid "Fleet Comms:"
|
msgid "Fleet Comms:"
|
||||||
@@ -1514,11 +1514,11 @@ msgstr "Schiffspriorität:"
|
|||||||
|
|
||||||
#: allianceauth/services/forms.py:11
|
#: allianceauth/services/forms.py:11
|
||||||
msgid "Formup Location:"
|
msgid "Formup Location:"
|
||||||
msgstr "Formup Location:"
|
msgstr "Startsystem:"
|
||||||
|
|
||||||
#: allianceauth/services/forms.py:12
|
#: allianceauth/services/forms.py:12
|
||||||
msgid "Formup Time:"
|
msgid "Formup Time:"
|
||||||
msgstr "Formup Zeit:"
|
msgstr "Startzeit:"
|
||||||
|
|
||||||
#: allianceauth/services/forms.py:13
|
#: allianceauth/services/forms.py:13
|
||||||
msgid "Expected Duration:"
|
msgid "Expected Duration:"
|
||||||
@@ -1530,7 +1530,7 @@ msgstr "Grund:"
|
|||||||
|
|
||||||
#: allianceauth/services/forms.py:15
|
#: allianceauth/services/forms.py:15
|
||||||
msgid "Reimbursable?*"
|
msgid "Reimbursable?*"
|
||||||
msgstr "Erstattungsfähig?"
|
msgstr "Erstattungsfähig?*"
|
||||||
|
|
||||||
#: allianceauth/services/forms.py:15 allianceauth/services/forms.py:16
|
#: allianceauth/services/forms.py:15 allianceauth/services/forms.py:16
|
||||||
msgid "Yes"
|
msgid "Yes"
|
||||||
@@ -1542,7 +1542,7 @@ msgstr "Nein"
|
|||||||
|
|
||||||
#: allianceauth/services/forms.py:16
|
#: allianceauth/services/forms.py:16
|
||||||
msgid "Important?*"
|
msgid "Important?*"
|
||||||
msgstr "Wichtig?"
|
msgstr "Wichtig?*"
|
||||||
|
|
||||||
#: allianceauth/services/forms.py:21 allianceauth/services/forms.py:31
|
#: allianceauth/services/forms.py:21 allianceauth/services/forms.py:31
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
@@ -1550,7 +1550,7 @@ msgstr "Passwort"
|
|||||||
|
|
||||||
#: allianceauth/services/forms.py:26 allianceauth/services/forms.py:36
|
#: allianceauth/services/forms.py:26 allianceauth/services/forms.py:36
|
||||||
msgid "Password must be at least 8 characters long."
|
msgid "Password must be at least 8 characters long."
|
||||||
msgstr "Passwort muss mindestens 8 Zeichen lang sein"
|
msgstr "Das Passwort muss mindestens 8 Zeichen lang sein"
|
||||||
|
|
||||||
#: allianceauth/services/modules/discord/models.py:187
|
#: allianceauth/services/modules/discord/models.py:187
|
||||||
msgid "Discord Account Disabled"
|
msgid "Discord Account Disabled"
|
||||||
@@ -1591,7 +1591,7 @@ msgstr "Discord Konto deaktiviert."
|
|||||||
#: allianceauth/services/modules/discord/views.py:36
|
#: allianceauth/services/modules/discord/views.py:36
|
||||||
#: allianceauth/services/modules/discord/views.py:59
|
#: allianceauth/services/modules/discord/views.py:59
|
||||||
msgid "An error occurred while processing your Discord account."
|
msgid "An error occurred while processing your Discord account."
|
||||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines Discord Kontos."
|
msgstr "Es gab einen Fehler während der Verarbeitung Deines Discord Kontos."
|
||||||
|
|
||||||
#: allianceauth/services/modules/discord/views.py:102
|
#: allianceauth/services/modules/discord/views.py:102
|
||||||
msgid "Your Discord account has been successfully activated."
|
msgid "Your Discord account has been successfully activated."
|
||||||
@@ -1607,7 +1607,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: allianceauth/services/modules/discourse/views.py:29
|
#: allianceauth/services/modules/discourse/views.py:29
|
||||||
msgid "You are not authorized to access Discourse."
|
msgid "You are not authorized to access Discourse."
|
||||||
msgstr "Du bist nicht autorisiert auf Discorse zuzugreifen."
|
msgstr "Du bist nicht autorisiert auf Discourse zuzugreifen."
|
||||||
|
|
||||||
#: allianceauth/services/modules/discourse/views.py:34
|
#: allianceauth/services/modules/discourse/views.py:34
|
||||||
msgid "You must have a main character set to access Discourse."
|
msgid "You must have a main character set to access Discourse."
|
||||||
@@ -1619,14 +1619,14 @@ msgid ""
|
|||||||
"No SSO payload or signature. Please contact support if this problem "
|
"No SSO payload or signature. Please contact support if this problem "
|
||||||
"persists."
|
"persists."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Keine SSO-Nutzdaten oder Signaturen. Bitte wenden Sie sich an den Support, "
|
"Keine SSO-Nutzdaten oder Signaturen. Bitte wende Dich an den Support, wenn "
|
||||||
"wenn das Problem weiterhin besteht."
|
"das Problem weiterhin besteht."
|
||||||
|
|
||||||
#: allianceauth/services/modules/discourse/views.py:54
|
#: allianceauth/services/modules/discourse/views.py:54
|
||||||
#: allianceauth/services/modules/discourse/views.py:62
|
#: allianceauth/services/modules/discourse/views.py:62
|
||||||
msgid "Invalid payload. Please contact support if this problem persists."
|
msgid "Invalid payload. Please contact support if this problem persists."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Ungültige Nutzdaten. Bitte wenden Sie sich an den Support, wenn das Problem "
|
"Ungültige Nutzdaten. Bitte wenden Dich an den Support, wenn das Problem "
|
||||||
"weiterhin besteht."
|
"weiterhin besteht."
|
||||||
|
|
||||||
#: allianceauth/services/modules/ips4/views.py:31
|
#: allianceauth/services/modules/ips4/views.py:31
|
||||||
@@ -1638,7 +1638,7 @@ msgstr "IP4Suite Konto aktiviert."
|
|||||||
#: allianceauth/services/modules/ips4/views.py:81
|
#: allianceauth/services/modules/ips4/views.py:81
|
||||||
#: allianceauth/services/modules/ips4/views.py:101
|
#: allianceauth/services/modules/ips4/views.py:101
|
||||||
msgid "An error occurred while processing your IPSuite4 account."
|
msgid "An error occurred while processing your IPSuite4 account."
|
||||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines IPSuite4 Kontos."
|
msgstr "Es gab einen Fehler während der Verarbeitung Deines IPSuite4 Kontos."
|
||||||
|
|
||||||
#: allianceauth/services/modules/ips4/views.py:52
|
#: allianceauth/services/modules/ips4/views.py:52
|
||||||
msgid "Reset IPSuite4 password."
|
msgid "Reset IPSuite4 password."
|
||||||
@@ -1660,7 +1660,7 @@ msgstr "Jabber"
|
|||||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:5
|
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:5
|
||||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:10
|
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:10
|
||||||
msgid "Jabber Broadcast"
|
msgid "Jabber Broadcast"
|
||||||
msgstr "Jabber Übertragung"
|
msgstr "Jabber Ankündigung"
|
||||||
|
|
||||||
#: allianceauth/services/modules/openfire/auth_hooks.py:94
|
#: allianceauth/services/modules/openfire/auth_hooks.py:94
|
||||||
msgid "Fleet Broadcast Formatter"
|
msgid "Fleet Broadcast Formatter"
|
||||||
@@ -1672,11 +1672,11 @@ msgstr "Nachricht"
|
|||||||
|
|
||||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:16
|
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:16
|
||||||
msgid "Broadcast Sent!!"
|
msgid "Broadcast Sent!!"
|
||||||
msgstr "Übertragung gesendet!!"
|
msgstr "Ankündigung gesendet!!"
|
||||||
|
|
||||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:22
|
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:22
|
||||||
msgid "Broadcast"
|
msgid "Broadcast"
|
||||||
msgstr "Übertragungen"
|
msgstr "Ankündigung"
|
||||||
|
|
||||||
#: allianceauth/services/modules/openfire/views.py:35
|
#: allianceauth/services/modules/openfire/views.py:35
|
||||||
msgid "Activated jabber account."
|
msgid "Activated jabber account."
|
||||||
@@ -1687,7 +1687,7 @@ msgstr "Jabber Konto aktiviert."
|
|||||||
#: allianceauth/services/modules/openfire/views.py:76
|
#: allianceauth/services/modules/openfire/views.py:76
|
||||||
#: allianceauth/services/modules/openfire/views.py:147
|
#: allianceauth/services/modules/openfire/views.py:147
|
||||||
msgid "An error occurred while processing your jabber account."
|
msgid "An error occurred while processing your jabber account."
|
||||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines Jabber Kontos."
|
msgstr "Es gab einen Fehler während der Verarbeitung Deines Jabber Kontos."
|
||||||
|
|
||||||
#: allianceauth/services/modules/openfire/views.py:69
|
#: allianceauth/services/modules/openfire/views.py:69
|
||||||
msgid "Reset jabber password."
|
msgid "Reset jabber password."
|
||||||
@@ -1696,7 +1696,7 @@ msgstr "Jabber Passwort zurücksetzen."
|
|||||||
#: allianceauth/services/modules/openfire/views.py:115
|
#: allianceauth/services/modules/openfire/views.py:115
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Sent jabber broadcast to %s"
|
msgid "Sent jabber broadcast to %s"
|
||||||
msgstr "Sende Jabber Durchsage an %s"
|
msgstr "Sende Jabber Ankündigung an %s"
|
||||||
|
|
||||||
#: allianceauth/services/modules/openfire/views.py:144
|
#: allianceauth/services/modules/openfire/views.py:144
|
||||||
msgid "Set jabber password."
|
msgid "Set jabber password."
|
||||||
@@ -1711,7 +1711,7 @@ msgstr "Forum Konto aktiviert."
|
|||||||
#: allianceauth/services/modules/phpbb3/views.py:78
|
#: allianceauth/services/modules/phpbb3/views.py:78
|
||||||
#: allianceauth/services/modules/phpbb3/views.py:101
|
#: allianceauth/services/modules/phpbb3/views.py:101
|
||||||
msgid "An error occurred while processing your forum account."
|
msgid "An error occurred while processing your forum account."
|
||||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines Forum Kontos."
|
msgstr "Es gab einen Fehler während der Verarbeitung Deines Forum Kontos."
|
||||||
|
|
||||||
#: allianceauth/services/modules/phpbb3/views.py:53
|
#: allianceauth/services/modules/phpbb3/views.py:53
|
||||||
msgid "Deactivated forum account."
|
msgid "Deactivated forum account."
|
||||||
@@ -1734,7 +1734,7 @@ msgstr "SMF Konto aktiviert."
|
|||||||
#: allianceauth/services/modules/smf/views.py:102
|
#: allianceauth/services/modules/smf/views.py:102
|
||||||
#: allianceauth/services/modules/smf/views.py:124
|
#: allianceauth/services/modules/smf/views.py:124
|
||||||
msgid "An error occurred while processing your SMF account."
|
msgid "An error occurred while processing your SMF account."
|
||||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines SMF Kontos."
|
msgstr "Es gab einen Fehler während der Verarbeitung Deines SMF Kontos."
|
||||||
|
|
||||||
#: allianceauth/services/modules/smf/views.py:78
|
#: allianceauth/services/modules/smf/views.py:78
|
||||||
msgid "Deactivated SMF account."
|
msgid "Deactivated SMF account."
|
||||||
@@ -1751,7 +1751,7 @@ msgstr "Setze SMF Passwort."
|
|||||||
#: allianceauth/services/modules/teamspeak3/forms.py:14
|
#: allianceauth/services/modules/teamspeak3/forms.py:14
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Unable to locate user %s on server"
|
msgid "Unable to locate user %s on server"
|
||||||
msgstr "Kann den Benutzer %s auf dem Server nicht finden"
|
msgstr "Der Benutzer %s konnte auf dem Server nicht gefunden werden"
|
||||||
|
|
||||||
#: allianceauth/services/modules/teamspeak3/templates/admin/teamspeak3/authts/change_list.html:8
|
#: allianceauth/services/modules/teamspeak3/templates/admin/teamspeak3/authts/change_list.html:8
|
||||||
msgid "Update TS3 groups"
|
msgid "Update TS3 groups"
|
||||||
@@ -1783,7 +1783,8 @@ msgstr "TeamSpeak3 Konto aktiviert."
|
|||||||
#: allianceauth/services/modules/teamspeak3/views.py:74
|
#: allianceauth/services/modules/teamspeak3/views.py:74
|
||||||
#: allianceauth/services/modules/teamspeak3/views.py:100
|
#: allianceauth/services/modules/teamspeak3/views.py:100
|
||||||
msgid "An error occurred while processing your TeamSpeak3 account."
|
msgid "An error occurred while processing your TeamSpeak3 account."
|
||||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines TeamSpeak3 Kontos."
|
msgstr ""
|
||||||
|
"Es gab einen Fehler während der Verarbeitung Deines TeamSpeak3 Kontos."
|
||||||
|
|
||||||
#: allianceauth/services/modules/teamspeak3/views.py:71
|
#: allianceauth/services/modules/teamspeak3/views.py:71
|
||||||
msgid "Deactivated TeamSpeak3 account."
|
msgid "Deactivated TeamSpeak3 account."
|
||||||
@@ -1802,7 +1803,7 @@ msgstr "XenForo Konto aktiviert."
|
|||||||
#: allianceauth/services/modules/xenforo/views.py:73
|
#: allianceauth/services/modules/xenforo/views.py:73
|
||||||
#: allianceauth/services/modules/xenforo/views.py:94
|
#: allianceauth/services/modules/xenforo/views.py:94
|
||||||
msgid "An error occurred while processing your XenForo account."
|
msgid "An error occurred while processing your XenForo account."
|
||||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines XenForo Kontos."
|
msgstr "Es gab einen Fehler während der Verarbeitung Deines XenForo Kontos."
|
||||||
|
|
||||||
#: allianceauth/services/modules/xenforo/views.py:50
|
#: allianceauth/services/modules/xenforo/views.py:50
|
||||||
msgid "Deactivated XenForo account."
|
msgid "Deactivated XenForo account."
|
||||||
@@ -1832,7 +1833,7 @@ msgstr "Formatieren"
|
|||||||
#: allianceauth/services/templates/services/service_confirm_delete.html:12
|
#: allianceauth/services/templates/services/service_confirm_delete.html:12
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Delete %(service_name)s Account?"
|
msgid "Delete %(service_name)s Account?"
|
||||||
msgstr "Konto %(service_name)s löschen?"
|
msgstr " %(service_name)s Konto löschen?"
|
||||||
|
|
||||||
#: allianceauth/services/templates/services/service_confirm_delete.html:20
|
#: allianceauth/services/templates/services/service_confirm_delete.html:20
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -1856,7 +1857,7 @@ msgstr "%(service_name)s Passwort ändern"
|
|||||||
#: allianceauth/services/templates/services/service_password.html:9
|
#: allianceauth/services/templates/services/service_password.html:9
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Set %(service_name)s Password"
|
msgid "Set %(service_name)s Password"
|
||||||
msgstr "%(service_name)s Passwort"
|
msgstr "%(service_name)s Passwort setzen"
|
||||||
|
|
||||||
#: allianceauth/services/templates/services/service_password.html:17
|
#: allianceauth/services/templates/services/service_password.html:17
|
||||||
msgid "Set Password"
|
msgid "Set Password"
|
||||||
@@ -1927,7 +1928,7 @@ msgstr "SRP Flotten Daten"
|
|||||||
|
|
||||||
#: allianceauth/srp/templates/srp/data.html:50
|
#: allianceauth/srp/templates/srp/data.html:50
|
||||||
msgid "SRP Fleet Data"
|
msgid "SRP Fleet Data"
|
||||||
msgstr "SRP-Flotte Daten"
|
msgstr "SRP Flotte Daten"
|
||||||
|
|
||||||
#: allianceauth/srp/templates/srp/data.html:55
|
#: allianceauth/srp/templates/srp/data.html:55
|
||||||
msgid "Mark Incomplete"
|
msgid "Mark Incomplete"
|
||||||
@@ -2005,7 +2006,7 @@ msgstr "Füge SRP Flotte hinzu"
|
|||||||
|
|
||||||
#: allianceauth/srp/templates/srp/management.html:39
|
#: allianceauth/srp/templates/srp/management.html:39
|
||||||
msgid "Fleet AAR"
|
msgid "Fleet AAR"
|
||||||
msgstr "Flotten AAR"
|
msgstr "Flottenbericht"
|
||||||
|
|
||||||
#: allianceauth/srp/templates/srp/management.html:40
|
#: allianceauth/srp/templates/srp/management.html:40
|
||||||
msgid "Fleet SRP Code"
|
msgid "Fleet SRP Code"
|
||||||
@@ -2033,7 +2034,7 @@ msgstr "Deaktiviert"
|
|||||||
|
|
||||||
#: allianceauth/srp/templates/srp/management.html:83
|
#: allianceauth/srp/templates/srp/management.html:83
|
||||||
msgid "Completed"
|
msgid "Completed"
|
||||||
msgstr "Fertig"
|
msgstr "Abgeschlossen"
|
||||||
|
|
||||||
#: allianceauth/srp/templates/srp/management.html:101
|
#: allianceauth/srp/templates/srp/management.html:101
|
||||||
msgid "Are you sure you want to delete this SRP code and its contents?"
|
msgid "Are you sure you want to delete this SRP code and its contents?"
|
||||||
@@ -2086,7 +2087,7 @@ msgstr "SRP Link für %(fleetname)s aktiviert."
|
|||||||
#: allianceauth/srp/views.py:140
|
#: allianceauth/srp/views.py:140
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Marked SRP fleet %(fleetname)s as completed."
|
msgid "Marked SRP fleet %(fleetname)s as completed."
|
||||||
msgstr "SRP Flotte %(fleetname)s als vollständig markiert."
|
msgstr "SRP Flotte %(fleetname)s als abgeschlossen markiert."
|
||||||
|
|
||||||
#: allianceauth/srp/views.py:153
|
#: allianceauth/srp/views.py:153
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -2204,7 +2205,7 @@ msgstr "Testversion verfügbar"
|
|||||||
|
|
||||||
#: allianceauth/templates/allianceauth/admin-status/overview.html:78
|
#: allianceauth/templates/allianceauth/admin-status/overview.html:78
|
||||||
msgid "Task Queue"
|
msgid "Task Queue"
|
||||||
msgstr "Warteschlange"
|
msgstr "Task-Warteschlange"
|
||||||
|
|
||||||
#: allianceauth/templates/allianceauth/admin-status/overview.html:81
|
#: allianceauth/templates/allianceauth/admin-status/overview.html:81
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -2249,7 +2250,7 @@ msgstr "Ausloggen"
|
|||||||
|
|
||||||
#: allianceauth/timerboard/form.py:53
|
#: allianceauth/timerboard/form.py:53
|
||||||
msgid "Other"
|
msgid "Other"
|
||||||
msgstr "anderes"
|
msgstr "Anderes"
|
||||||
|
|
||||||
#: allianceauth/timerboard/form.py:54
|
#: allianceauth/timerboard/form.py:54
|
||||||
#: allianceauth/timerboard/templates/timerboard/view.html:62
|
#: allianceauth/timerboard/templates/timerboard/view.html:62
|
||||||
@@ -2353,7 +2354,7 @@ msgstr "Timer löschen"
|
|||||||
#: allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html:19
|
#: allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html:19
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Are you sure you want to delete timer \"%(object)s\"?"
|
msgid "Are you sure you want to delete timer \"%(object)s\"?"
|
||||||
msgstr "Bist Du sicher das Du Timer \"%(object)s\" löschen möchtest?"
|
msgstr "Bist Du sicher das Du Timer „%(object)s“ löschen möchtest?"
|
||||||
|
|
||||||
#: allianceauth/timerboard/templates/timerboard/timer_create_form.html:5
|
#: allianceauth/timerboard/templates/timerboard/timer_create_form.html:5
|
||||||
#: allianceauth/timerboard/templates/timerboard/timer_create_form.html:13
|
#: allianceauth/timerboard/templates/timerboard/timer_create_form.html:13
|
||||||
|
|||||||
@@ -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: 2022-10-09 18:20+1000\n"
|
"POT-Creation-Date: 2023-11-08 23:55+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,7 +26,7 @@ msgstr ""
|
|||||||
msgid "Google Analytics V4"
|
msgid "Google Analytics V4"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/decorators.py:37
|
#: allianceauth/authentication/decorators.py:49
|
||||||
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 ""
|
||||||
|
|
||||||
@@ -39,63 +39,68 @@ msgstr ""
|
|||||||
msgid "You are not allowed to add or remove these restricted groups: %s"
|
msgid "You are not allowed to add or remove these restricted groups: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:80
|
#: allianceauth/authentication/models.py:71
|
||||||
msgid "English"
|
msgid "English"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:81
|
#: allianceauth/authentication/models.py:72
|
||||||
msgid "German"
|
msgid "German"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:82
|
#: allianceauth/authentication/models.py:73
|
||||||
msgid "Spanish"
|
msgid "Spanish"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:83
|
#: allianceauth/authentication/models.py:74
|
||||||
msgid "Chinese Simplified"
|
msgid "Chinese Simplified"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:84
|
#: allianceauth/authentication/models.py:75
|
||||||
msgid "Russian"
|
msgid "Russian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:85
|
#: allianceauth/authentication/models.py:76
|
||||||
msgid "Korean"
|
msgid "Korean"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:86
|
#: allianceauth/authentication/models.py:77
|
||||||
msgid "French"
|
msgid "French"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:87
|
#: allianceauth/authentication/models.py:78
|
||||||
msgid "Japanese"
|
msgid "Japanese"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:88
|
#: allianceauth/authentication/models.py:79
|
||||||
msgid "Italian"
|
msgid "Italian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:91
|
#: allianceauth/authentication/models.py:80
|
||||||
msgid "Language"
|
msgid "Ukrainian"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:96
|
#: allianceauth/authentication/models.py:96
|
||||||
|
msgid "Language"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: allianceauth/authentication/models.py:101
|
||||||
#: allianceauth/templates/allianceauth/night-toggle.html:6
|
#: allianceauth/templates/allianceauth/night-toggle.html:6
|
||||||
msgid "Night Mode"
|
msgid "Night Mode"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:110
|
#: allianceauth/authentication/models.py:115
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "State changed to: %s"
|
msgid "State changed to: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/models.py:111
|
#: allianceauth/authentication/models.py:116
|
||||||
#, python-format
|
#, python-format
|
||||||
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.html:4
|
#: allianceauth/authentication/templates/authentication/dashboard.html:4
|
||||||
#: allianceauth/authentication/templates/authentication/dashboard.html:7
|
#: allianceauth/authentication/templates/authentication/dashboard.html:7
|
||||||
|
#: allianceauth/authentication/templates/authentication/tokens.html:4
|
||||||
#: allianceauth/templates/allianceauth/side-menu.html:10
|
#: allianceauth/templates/allianceauth/side-menu.html:10
|
||||||
msgid "Dashboard"
|
msgid "Dashboard"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -151,8 +156,49 @@ msgstr ""
|
|||||||
msgid "Alliance"
|
msgid "Alliance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: allianceauth/authentication/templates/authentication/tokens.html:7
|
||||||
|
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
|
||||||
|
msgid "Token Management"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: allianceauth/authentication/templates/authentication/tokens.html:12
|
||||||
|
msgid "Scopes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: allianceauth/authentication/templates/authentication/tokens.html:13
|
||||||
|
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
|
||||||
|
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
|
||||||
|
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
|
||||||
|
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
|
||||||
|
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
|
||||||
|
#: allianceauth/srp/templates/srp/data.html:101
|
||||||
|
#: allianceauth/srp/templates/srp/management.html:44
|
||||||
|
msgid "Actions"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: allianceauth/authentication/templates/authentication/tokens.html:14
|
||||||
|
#: allianceauth/corputils/templates/corputils/corpstats.html:74
|
||||||
|
#: allianceauth/corputils/templates/corputils/corpstats.html:112
|
||||||
|
#: allianceauth/corputils/templates/corputils/corpstats.html:156
|
||||||
|
#: allianceauth/corputils/templates/corputils/search.html:13
|
||||||
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
|
||||||
|
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
|
||||||
|
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
|
||||||
|
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
|
||||||
|
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
|
||||||
|
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
|
||||||
|
msgid "Character"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: allianceauth/authentication/templates/authentication/tokens.html:28
|
||||||
|
msgid ""
|
||||||
|
"This page is a best attempt, but backups or database logs can still contain "
|
||||||
|
"your tokens. Always revoke tokens on https://community.eveonline.com/support/"
|
||||||
|
"third-party-applications/ where possible."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/templates/public/login.html:6
|
#: allianceauth/authentication/templates/public/login.html:6
|
||||||
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:58
|
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:69
|
||||||
msgid "Login"
|
msgid "Login"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -184,47 +230,47 @@ msgstr ""
|
|||||||
msgid "Invalid or expired activation link."
|
msgid "Invalid or expired activation link."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/views.py:77
|
#: allianceauth/authentication/views.py:118
|
||||||
#, 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:83
|
#: allianceauth/authentication/views.py:124
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Changed main character to %(char)s"
|
msgid "Changed main character to %(char)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/views.py:92
|
#: allianceauth/authentication/views.py:133
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Added %(name)s to your account."
|
msgid "Added %(name)s to your account."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/views.py:94
|
#: allianceauth/authentication/views.py:135
|
||||||
#, 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:133
|
#: allianceauth/authentication/views.py:174
|
||||||
msgid "Unable to authenticate as the selected character."
|
msgid "Unable to authenticate as the selected character."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/views.py:197
|
#: allianceauth/authentication/views.py:238
|
||||||
msgid "Registration token has expired."
|
msgid "Registration token has expired."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/views.py:252
|
#: allianceauth/authentication/views.py:296
|
||||||
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:257
|
#: allianceauth/authentication/views.py:301
|
||||||
msgid "Confirmed your email address. Please login to continue."
|
msgid "Confirmed your email address. Please login to continue."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/authentication/views.py:262
|
#: allianceauth/authentication/views.py:306
|
||||||
msgid "Registration of new accounts is not allowed at this time."
|
msgid "Registration of new accounts is not allowed at this time."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -267,19 +313,6 @@ msgstr ""
|
|||||||
msgid "Last update:"
|
msgid "Last update:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/corputils/templates/corputils/corpstats.html:74
|
|
||||||
#: allianceauth/corputils/templates/corputils/corpstats.html:112
|
|
||||||
#: allianceauth/corputils/templates/corputils/corpstats.html:156
|
|
||||||
#: allianceauth/corputils/templates/corputils/search.html:13
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
|
|
||||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
|
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
|
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
|
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
|
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
|
|
||||||
msgid "Character"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: allianceauth/corputils/templates/corputils/corpstats.html:75
|
#: allianceauth/corputils/templates/corputils/corpstats.html:75
|
||||||
#: allianceauth/corputils/templates/corputils/search.html:14
|
#: allianceauth/corputils/templates/corputils/search.html:14
|
||||||
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
|
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
|
||||||
@@ -611,36 +644,41 @@ msgstr ""
|
|||||||
msgid "Group Management"
|
msgid "Group Management"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/forms.py:15
|
#: allianceauth/groupmanagement/forms.py:18
|
||||||
|
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
|
||||||
|
msgid "Users"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: allianceauth/groupmanagement/forms.py:52
|
||||||
msgid "This name has been reserved and can not be used for groups."
|
msgid "This name has been reserved and can not be used for groups."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/forms.py:25
|
#: allianceauth/groupmanagement/forms.py:62
|
||||||
msgid "(auto)"
|
msgid "(auto)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/forms.py:34
|
#: allianceauth/groupmanagement/forms.py:71
|
||||||
msgid "There already exists a group with that name."
|
msgid "There already exists a group with that name."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:105
|
#: allianceauth/groupmanagement/models.py:104
|
||||||
msgid ""
|
msgid ""
|
||||||
"Internal group, users cannot see, join or request to join this group."
|
"Internal group, users cannot see, join or request to join this group."
|
||||||
"<br>Used for groups such as Members, Corp_*, Alliance_* etc.<br><b>Overrides "
|
"<br>Used for groups such as Members, Corp_*, Alliance_* etc.<br><b>Overrides "
|
||||||
"Hidden and Open options when selected.</b>"
|
"Hidden and Open options when selected.</b>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:113
|
#: allianceauth/groupmanagement/models.py:112
|
||||||
msgid "Group is hidden from users but can still join with the correct link."
|
msgid "Group is hidden from users but can still join with the correct link."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:119
|
#: allianceauth/groupmanagement/models.py:118
|
||||||
msgid ""
|
msgid ""
|
||||||
"Group is open and users will be automatically added upon request.<br>If the "
|
"Group is open and users will be automatically added upon request.<br>If the "
|
||||||
"group is not open users will need their request manually approved."
|
"group is not open users will need their request manually approved."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:126
|
#: allianceauth/groupmanagement/models.py:125
|
||||||
msgid ""
|
msgid ""
|
||||||
"Group is public. Any registered user is able to join this group, with "
|
"Group is public. Any registered user is able to join this group, with "
|
||||||
"visibility based on the other options set for this group.<br>Auth will not "
|
"visibility based on the other options set for this group.<br>Auth will not "
|
||||||
@@ -648,65 +686,65 @@ msgid ""
|
|||||||
"authenticated."
|
"authenticated."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:135
|
#: allianceauth/groupmanagement/models.py:134
|
||||||
msgid ""
|
msgid ""
|
||||||
"Group is restricted. This means that adding or removing users for this group "
|
"Group is restricted. This means that adding or removing users for this group "
|
||||||
"requires a superuser admin."
|
"requires a superuser admin."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:144
|
#: allianceauth/groupmanagement/models.py:143
|
||||||
msgid ""
|
msgid ""
|
||||||
"Group leaders can process requests for this group. Use the <code>auth."
|
"Group leaders can process requests for this group. Use the <code>auth."
|
||||||
"group_management</code> permission to allow a user to manage all groups.<br>"
|
"group_management</code> permission to allow a user to manage all groups.<br>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:154
|
#: allianceauth/groupmanagement/models.py:153
|
||||||
msgid ""
|
msgid ""
|
||||||
"Members of leader groups can process requests for this group. Use the "
|
"Members of leader groups can process requests for this group. Use the "
|
||||||
"<code>auth.group_management</code> permission to allow a user to manage all "
|
"<code>auth.group_management</code> permission to allow a user to manage all "
|
||||||
"groups.<br>"
|
"groups.<br>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:163
|
#: allianceauth/groupmanagement/models.py:162
|
||||||
msgid ""
|
msgid ""
|
||||||
"States listed here will have the ability to join this group provided they "
|
"States listed here will have the ability to join this group provided they "
|
||||||
"have the proper permissions.<br>"
|
"have the proper permissions.<br>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:171
|
#: allianceauth/groupmanagement/models.py:170
|
||||||
msgid ""
|
msgid ""
|
||||||
"Short description <i>(max. 512 characters)</i> of the group shown to users."
|
"Short description <i>(max. 512 characters)</i> of the group shown to users."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:178
|
#: allianceauth/groupmanagement/models.py:177
|
||||||
msgid "Can request non-public groups"
|
msgid "Can request non-public groups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:209
|
#: allianceauth/groupmanagement/models.py:208
|
||||||
msgid "name"
|
msgid "name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:212
|
#: allianceauth/groupmanagement/models.py:211
|
||||||
msgid "Name that can not be used for groups."
|
msgid "Name that can not be used for groups."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:215
|
#: allianceauth/groupmanagement/models.py:214
|
||||||
msgid "reason"
|
msgid "reason"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:215
|
#: allianceauth/groupmanagement/models.py:214
|
||||||
msgid "Reason why this name is reserved."
|
msgid "Reason why this name is reserved."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:218
|
#: allianceauth/groupmanagement/models.py:217
|
||||||
msgid "created by"
|
msgid "created by"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:223
|
#: allianceauth/groupmanagement/models.py:222
|
||||||
msgid "created at"
|
msgid "created at"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/models.py:223
|
#: allianceauth/groupmanagement/models.py:222
|
||||||
msgid "Date when this entry was created"
|
msgid "Date when this entry was created"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -933,86 +971,86 @@ msgstr ""
|
|||||||
msgid "Group Membership"
|
msgid "Group Membership"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:163
|
#: allianceauth/groupmanagement/views.py:166
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Removed user %(user)s from group %(group)s."
|
msgid "Removed user %(user)s from group %(group)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:165
|
#: allianceauth/groupmanagement/views.py:168
|
||||||
msgid "User does not exist in that group"
|
msgid "User does not exist in that group"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:168
|
#: allianceauth/groupmanagement/views.py:171
|
||||||
msgid "Group does not exist"
|
msgid "Group does not exist"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:195
|
#: allianceauth/groupmanagement/views.py:198
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Accepted application from %(mainchar)s to %(group)s."
|
msgid "Accepted application from %(mainchar)s to %(group)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:201
|
#: allianceauth/groupmanagement/views.py:204
|
||||||
#: allianceauth/groupmanagement/views.py:232
|
#: allianceauth/groupmanagement/views.py:235
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"An unhandled error occurred while processing the application from "
|
"An unhandled error occurred while processing the application from "
|
||||||
"%(mainchar)s to %(group)s."
|
"%(mainchar)s to %(group)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:226
|
#: allianceauth/groupmanagement/views.py:229
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Rejected application from %(mainchar)s to %(group)s."
|
msgid "Rejected application from %(mainchar)s to %(group)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:261
|
#: allianceauth/groupmanagement/views.py:264
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Accepted application from %(mainchar)s to leave %(group)s."
|
msgid "Accepted application from %(mainchar)s to leave %(group)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:266
|
#: allianceauth/groupmanagement/views.py:269
|
||||||
#: allianceauth/groupmanagement/views.py:298
|
#: allianceauth/groupmanagement/views.py:301
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"An unhandled error occurred while processing the application from "
|
"An unhandled error occurred while processing the application from "
|
||||||
"%(mainchar)s to leave %(group)s."
|
"%(mainchar)s to leave %(group)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:292
|
#: allianceauth/groupmanagement/views.py:295
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Rejected application from %(mainchar)s to leave %(group)s."
|
msgid "Rejected application from %(mainchar)s to leave %(group)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:336
|
#: allianceauth/groupmanagement/views.py:339
|
||||||
#: allianceauth/groupmanagement/views.py:346
|
#: allianceauth/groupmanagement/views.py:349
|
||||||
msgid "You cannot join that group"
|
msgid "You cannot join that group"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:341
|
#: allianceauth/groupmanagement/views.py:344
|
||||||
msgid "You are already a member of that group."
|
msgid "You are already a member of that group."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:358
|
#: allianceauth/groupmanagement/views.py:361
|
||||||
msgid "You already have a pending application for that group."
|
msgid "You already have a pending application for that group."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:367
|
#: allianceauth/groupmanagement/views.py:370
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Applied to group %(group)s."
|
msgid "Applied to group %(group)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:377
|
#: allianceauth/groupmanagement/views.py:380
|
||||||
msgid "You cannot leave that group"
|
msgid "You cannot leave that group"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:381
|
#: allianceauth/groupmanagement/views.py:384
|
||||||
msgid "You are not a member of that group"
|
msgid "You are not a member of that group"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:393
|
#: allianceauth/groupmanagement/views.py:396
|
||||||
msgid "You already have a pending leave request for that group."
|
msgid "You already have a pending leave request for that group."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/groupmanagement/views.py:409
|
#: allianceauth/groupmanagement/views.py:412
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Applied to leave group %(group)s."
|
msgid "Applied to leave group %(group)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1074,16 +1112,6 @@ msgstr ""
|
|||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
|
|
||||||
#: allianceauth/srp/templates/srp/data.html:101
|
|
||||||
#: allianceauth/srp/templates/srp/management.html:44
|
|
||||||
msgid "Actions"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:38
|
#: allianceauth/hrapplications/templates/hrapplications/management.html:38
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
|
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
|
||||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:143
|
#: allianceauth/hrapplications/templates/hrapplications/management.html:143
|
||||||
@@ -1422,10 +1450,6 @@ msgstr ""
|
|||||||
msgid "Code Name"
|
msgid "Code Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
|
|
||||||
msgid "Users"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41
|
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41
|
||||||
msgid "States"
|
msgid "States"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -2146,11 +2170,11 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
|
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
|
||||||
#, python-format
|
msgid "running"
|
||||||
msgid ""
|
msgstr ""
|
||||||
"\n"
|
|
||||||
" %(queue_length)s queued tasks\n"
|
#: allianceauth/templates/allianceauth/admin-status/overview.html:96
|
||||||
" "
|
msgid "queued"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
|
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
|
||||||
@@ -2166,11 +2190,11 @@ msgid "AA Support Discord"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10
|
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10
|
||||||
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14
|
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:16
|
||||||
msgid "User Menu"
|
msgid "User Menu"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56
|
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:67
|
||||||
msgid "Logout"
|
msgid "Logout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2226,22 +2250,30 @@ msgid "Objective"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/timerboard/form.py:64
|
#: allianceauth/timerboard/form.py:64
|
||||||
msgid "Days Remaining"
|
msgid "Absolute Timer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/timerboard/form.py:65
|
#: allianceauth/timerboard/form.py:65
|
||||||
msgid "Hours Remaining"
|
msgid "Date and Time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: allianceauth/timerboard/form.py:66
|
||||||
|
msgid "Days Remaining"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/timerboard/form.py:67
|
#: allianceauth/timerboard/form.py:67
|
||||||
msgid "Minutes Remaining"
|
msgid "Hours Remaining"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/timerboard/form.py:69
|
#: allianceauth/timerboard/form.py:69
|
||||||
|
msgid "Minutes Remaining"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: allianceauth/timerboard/form.py:71
|
||||||
msgid "Important"
|
msgid "Important"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: allianceauth/timerboard/form.py:70
|
#: allianceauth/timerboard/form.py:72
|
||||||
msgid "Corp-Restricted"
|
msgid "Corp-Restricted"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -4,11 +4,11 @@
|
|||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# frank1210 <francolopez_16@hotmail.com>, 2021
|
|
||||||
# Joel Falknau <ozirascal@gmail.com>, 2021
|
|
||||||
# Young Anexo, 2023
|
|
||||||
# Fegpawn Kaundur, 2023
|
# Fegpawn Kaundur, 2023
|
||||||
|
# frank1210 <francolopez_16@hotmail.com>, 2023
|
||||||
# trenus, 2023
|
# trenus, 2023
|
||||||
|
# Joel Falknau <ozirascal@gmail.com>, 2023
|
||||||
|
# Young Anexo, 2023
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -16,8 +16,8 @@ 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: 2022-10-09 18:20+1000\n"
|
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
|
||||||
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
|
"PO-Revision-Date: 2023-10-08 09:23+0000\n"
|
||||||
"Last-Translator: trenus, 2023\n"
|
"Last-Translator: Young Anexo, 2023\n"
|
||||||
"Language-Team: Spanish (https://app.transifex.com/alliance-auth/teams/107430/es/)\n"
|
"Language-Team: Spanish (https://app.transifex.com/alliance-auth/teams/107430/es/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
|||||||
Binary file not shown.
@@ -4,14 +4,14 @@
|
|||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# François LACROIX-DURANT <umbre@fallenstarscreations.com>, 2020
|
# Keven D. <theenarki@gmail.com>, 2023
|
||||||
# Philippe Querin-Laporte <philippe.querin@hotmail.com>, 2020
|
# rockclodbuster, 2023
|
||||||
# Keven D. <theenarki@gmail.com>, 2020
|
# Geoffrey Fabbro, 2023
|
||||||
# Idea ., 2021
|
|
||||||
# Mickael PATTE, 2021
|
|
||||||
# Geoffrey Fabbro, 2021
|
|
||||||
# Mohssine Daghghar, 2023
|
# Mohssine Daghghar, 2023
|
||||||
# Ludovick Fortin, 2023
|
# François LACROIX-DURANT <umbre@fallenstarscreations.com>, 2023
|
||||||
|
# Mickael PATTE, 2023
|
||||||
|
# Philippe Querin-Laporte <philippe.querin@hotmail.com>, 2023
|
||||||
|
# Idea ., 2023
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -19,8 +19,8 @@ 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: 2022-10-09 18:20+1000\n"
|
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
|
||||||
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
|
"PO-Revision-Date: 2023-10-08 09:23+0000\n"
|
||||||
"Last-Translator: Ludovick Fortin, 2023\n"
|
"Last-Translator: Idea ., 2023\n"
|
||||||
"Language-Team: French (France) (https://app.transifex.com/alliance-auth/teams/107430/fr_FR/)\n"
|
"Language-Team: French (France) (https://app.transifex.com/alliance-auth/teams/107430/fr_FR/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user