mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-21 18:22:27 +02:00
Compare commits
22 Commits
8f7253bed7
...
4385d2af8b
Author | SHA1 | Date | |
---|---|---|---|
|
4385d2af8b | ||
|
9dad53f763 | ||
|
2d57064a7a | ||
|
833d12cf66 | ||
|
7b56caa4cb | ||
|
5752644122 | ||
|
cadc0cb534 | ||
|
dcdab5ae1f | ||
|
d64e896288 | ||
|
500d8ede32 | ||
|
f4c5c7f6db | ||
|
43e1be4032 | ||
|
702def2a4d | ||
|
a34baf4154 | ||
|
4de0774f15 | ||
|
83d2dfc7d9 | ||
|
c93afd2d68 | ||
|
b7bacd11af | ||
|
f26835fae0 | ||
|
4edb7cb678 | ||
|
2ce9ba997f | ||
|
0dd47e72bc |
@ -1,24 +1,24 @@
|
|||||||
{% load theme_tags %}
|
{% load theme_tags %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en" {% theme_html_tags %}>
|
||||||
<head>
|
<head>
|
||||||
|
<!-- Required meta tags -->
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="description" content="">
|
<!-- End Required meta tags -->
|
||||||
<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: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 tags -->
|
||||||
|
{% include 'allianceauth/opengraph.html' %}
|
||||||
{% include 'allianceauth/icons.html' %}
|
{% include 'allianceauth/icons.html' %}
|
||||||
|
<!-- Meta tags -->
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
{% theme_css %}
|
{% theme_css %}
|
||||||
|
|
||||||
{% include 'bundles/fontawesome.html' %}
|
{% include 'bundles/fontawesome.html' %}
|
||||||
|
{% include 'bundles/auth-framework-css.html' %}
|
||||||
|
|
||||||
{% block extra_include %}
|
{% block extra_include %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
<th class="text-center">{% translate "Character" %}</th>
|
<th class="text-center">{% translate "Character" %}</th>
|
||||||
<th class="text-center">{% translate "System" %}</th>
|
<th class="text-center">{% translate "System" %}</th>
|
||||||
<th class="text-center">{% translate "Ship" %}</th>
|
<th class="text-center">{% translate "Ship" %}</th>
|
||||||
<th class="text-center">{% translate "Eve Time" %}</th>
|
<th class="text-center">{% translate "EVE time" %}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th class="text-center">{% translate "Fleet" %}</th>
|
<th class="text-center">{% translate "Fleet" %}</th>
|
||||||
<th class="text-center">{% translate "Creator" %}</th>
|
<th class="text-center">{% translate "Creator" %}</th>
|
||||||
<th class="text-center">{% translate "Eve Time" %}</th>
|
<th class="text-center">{% translate "EVE time" %}</th>
|
||||||
<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>
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
<th scope="col" class="text-center">{% translate "Character" %}</th>
|
<th scope="col" class="text-center">{% translate "Character" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "System" %}</th>
|
<th scope="col" class="text-center">{% translate "System" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Ship" %}</th>
|
<th scope="col" class="text-center">{% translate "Ship" %}</th>
|
||||||
<th scope="col" 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 %}
|
||||||
@ -89,7 +89,7 @@
|
|||||||
<th scope="col" class="text-center">{% translate "Name" %}</th>
|
<th scope="col" class="text-center">{% translate "Name" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Creator" %}</th>
|
<th scope="col" class="text-center">{% translate "Creator" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Fleet" %}</th>
|
<th scope="col" class="text-center">{% translate "Fleet" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Eve Time" %}</th>
|
<th scope="col" class="text-center">{% translate "EVE time" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Duration" %}</th>
|
<th scope="col" class="text-center">{% translate "Duration" %}</th>
|
||||||
<th scope="col" class="text-center">{% translate "Edit" %}</th>
|
<th scope="col" class="text-center">{% translate "Edit" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -2,12 +2,14 @@
|
|||||||
{# {% include "framework/header/page-header.html" with title="Foobar" subtitle="Barfoo" %}#}
|
{# {% include "framework/header/page-header.html" with title="Foobar" subtitle="Barfoo" %}#}
|
||||||
|
|
||||||
{% if title %}
|
{% if title %}
|
||||||
<h1 class="page-header text-center mb-3">
|
<header class="aa-page-header mb-3">
|
||||||
{{ title }}
|
<h1 class="page-header text-center">
|
||||||
|
{{ title }}
|
||||||
|
|
||||||
{% if subtitle %}
|
{% if subtitle %}
|
||||||
<br>
|
<br>
|
||||||
<small class="text-muted">{{ subtitle }}</small>
|
<small class="text-muted">{{ subtitle }}</small>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
|
</header>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<th class="text-center">{% translate "Operation" %}</th>
|
<th class="text-center">{% translate "Operation" %}</th>
|
||||||
<th class="text-center">{% translate "Type" %}</th>
|
<th class="text-center">{% translate "Type" %}</th>
|
||||||
<th class="text-center">{% translate "Form Up System" %}</th>
|
<th class="text-center">{% translate "Form Up System" %}</th>
|
||||||
<th class="text-center">{% translate "EVE Time" %}</th>
|
<th class="text-center">{% translate "EVE time" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="text-center mb-3">
|
<div class="text-center mb-3">
|
||||||
<div class="badge bg-primary text-start">
|
<div class="badge bg-primary text-start">
|
||||||
<b>{% translate "Current Eve Time:" %}</b>
|
<b>{% translate "Current EVE time:" %}</b>
|
||||||
<span id="current-time"></span>
|
<span id="current-time"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -127,8 +127,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current Eve time as a string
|
* Get the current EVE time as a string
|
||||||
* @returns {string} Eve time string
|
* @returns {string} EVE time string
|
||||||
*/
|
*/
|
||||||
const updateClock = () => {
|
const updateClock = () => {
|
||||||
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
||||||
|
@ -26,7 +26,7 @@ app.conf.task_default_priority = 5 # anything called with the task.delay() will
|
|||||||
app.conf.worker_prefetch_multiplier = 1 # only prefetch single tasks at a time on the workers so that prio tasks happen
|
app.conf.worker_prefetch_multiplier = 1 # only prefetch single tasks at a time on the workers so that prio tasks happen
|
||||||
|
|
||||||
app.conf.ONCE = {
|
app.conf.ONCE = {
|
||||||
'backend': 'allianceauth.services.tasks.DjangoBackend',
|
'backend': 'allianceauth.services.celery_once.backends.DjangoBackend',
|
||||||
'settings': {}
|
'settings': {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,49 +1,48 @@
|
|||||||
[program:beat]
|
[program:beat]
|
||||||
command={{ celery }} -A {{ project_name }} beat
|
command = {{ celery }} -A {{ project_name }} beat
|
||||||
directory={{ project_directory }}
|
directory = {{ project_directory }}
|
||||||
user=allianceserver
|
user = allianceserver
|
||||||
stdout_logfile={{ project_directory }}/log/beat.log
|
stdout_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
stderr_logfile={{ project_directory }}/log/beat.log
|
stderr_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
autostart=true
|
autostart = true
|
||||||
autorestart=true
|
autorestart = true
|
||||||
startsecs=10
|
startsecs = 10
|
||||||
priority=998
|
priority = 998
|
||||||
|
|
||||||
[program:worker]
|
[program:worker]
|
||||||
command={{ celery }} -A {{ project_name }} worker --pool=threads --concurrency=5 -n %(program_name)s_%(process_num)02d
|
command = {{ celery }} -A {{ project_name }} worker --pool=threads --concurrency=5 -n %(program_name)s_%(process_num)02d
|
||||||
directory={{ project_directory }}
|
directory = {{ project_directory }}
|
||||||
user=allianceserver
|
user = allianceserver
|
||||||
numprocs=1
|
numprocs = 1
|
||||||
process_name=%(program_name)s_%(process_num)02d
|
process_name = %(program_name)s_%(process_num)02d
|
||||||
stdout_logfile={{ project_directory }}/log/worker.log
|
stdout_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
stderr_logfile={{ project_directory }}/log/worker.log
|
stderr_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
autostart=true
|
autostart = true
|
||||||
autorestart=true
|
autorestart = true
|
||||||
startsecs=10
|
startsecs = 10
|
||||||
stopwaitsecs = 600
|
stopwaitsecs = 600
|
||||||
killasgroup=true
|
killasgroup = true
|
||||||
priority=998
|
priority = 998
|
||||||
|
|
||||||
{% if gunicorn %}
|
{% if gunicorn %}
|
||||||
[program:gunicorn]
|
[program:gunicorn]
|
||||||
user = allianceserver
|
user = allianceserver
|
||||||
directory={{ project_directory }}
|
directory = {{ project_directory }}
|
||||||
command={{ gunicorn }} {{ project_name }}.wsgi --workers=3 --timeout 120
|
command = {{ gunicorn }} {{ project_name }}.wsgi --workers=3 --timeout 120
|
||||||
stdout_logfile={{ project_directory }}/log/gunicorn.log
|
stdout_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
stderr_logfile={{ project_directory }}/log/gunicorn.log
|
stderr_logfile = {{ project_directory }}/log/%(program_name)s.log
|
||||||
autostart=true
|
autostart = true
|
||||||
autorestart=true
|
autorestart = true
|
||||||
stopsignal=INT
|
stopsignal = INT
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
[eventlistener:memmon]
|
[eventlistener:memmon]
|
||||||
command={{ memmon }} -p worker_00=256MB -p gunicorn=256MB
|
command = {{ memmon }} -p worker_00=256MB -p gunicorn=256MB
|
||||||
directory={{ project_directory }}
|
directory = {{ project_directory }}
|
||||||
events=TICK_60
|
events = TICK_60
|
||||||
stdout_logfile={{ project_directory }}/log/memmon.log
|
stdout_logfile = {{ project_directory }}/log/memmon.log
|
||||||
stderr_logfile={{ project_directory }}/log/memmon.log
|
stderr_logfile = {{ project_directory }}/log/memmon.log
|
||||||
|
|
||||||
[group:{{ project_name }}]
|
[group:{{ project_name }}]
|
||||||
programs=beat,worker{% if gunicorn %},gunicorn{% endif %}
|
programs = beat,worker{% if gunicorn %},gunicorn{% endif %}
|
||||||
priority=999
|
priority = 999
|
||||||
|
0
allianceauth/services/celery_once/__init__.py
Normal file
0
allianceauth/services/celery_once/__init__.py
Normal file
19
allianceauth/services/celery_once/backends.py
Normal file
19
allianceauth/services/celery_once/backends.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from celery_once import AlreadyQueued
|
||||||
|
from django.core.cache import cache
|
||||||
|
|
||||||
|
|
||||||
|
class DjangoBackend:
|
||||||
|
"""Locking backend for celery once."""
|
||||||
|
|
||||||
|
def __init__(self, settings):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def raise_or_lock(key, timeout):
|
||||||
|
acquired = cache.add(key=key, value="lock", timeout=timeout)
|
||||||
|
if not acquired:
|
||||||
|
raise AlreadyQueued(int(cache.ttl(key)))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def clear_lock(key):
|
||||||
|
return cache.delete(key)
|
8
allianceauth/services/celery_once/tasks.py
Normal file
8
allianceauth/services/celery_once/tasks.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from celery_once import QueueOnce as BaseTask
|
||||||
|
|
||||||
|
|
||||||
|
class QueueOnce(BaseTask):
|
||||||
|
"""QueueOnce class with custom defaults."""
|
||||||
|
|
||||||
|
once = BaseTask.once
|
||||||
|
once["graceful"] = True
|
47
allianceauth/services/celery_once/tests.py
Normal file
47
allianceauth/services/celery_once/tests.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
from celery_once import AlreadyQueued
|
||||||
|
from django.core.cache import cache
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from allianceauth.services.celery_once.backends import DjangoBackend
|
||||||
|
|
||||||
|
|
||||||
|
class TestDjangoBackend(TestCase):
|
||||||
|
TEST_KEY = "my-django-backend-test-key"
|
||||||
|
TIMEOUT = 1800
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
cache.delete(self.TEST_KEY)
|
||||||
|
self.backend = DjangoBackend(dict())
|
||||||
|
|
||||||
|
def test_can_get_lock(self):
|
||||||
|
"""
|
||||||
|
when lock can be acquired
|
||||||
|
then set it with timeout
|
||||||
|
"""
|
||||||
|
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
||||||
|
self.assertIsNotNone(cache.get(self.TEST_KEY))
|
||||||
|
self.assertAlmostEqual(cache.ttl(self.TEST_KEY), self.TIMEOUT, delta=2)
|
||||||
|
|
||||||
|
def test_when_cant_get_lock_raise_exception(self):
|
||||||
|
"""
|
||||||
|
when lock can bot be acquired
|
||||||
|
then raise AlreadyQueued exception with countdown
|
||||||
|
"""
|
||||||
|
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
||||||
|
except Exception as ex:
|
||||||
|
self.assertIsInstance(ex, AlreadyQueued)
|
||||||
|
self.assertAlmostEqual(ex.countdown, self.TIMEOUT, delta=2)
|
||||||
|
|
||||||
|
def test_can_clear_lock(self):
|
||||||
|
"""
|
||||||
|
when a lock exists
|
||||||
|
then can get a new lock after clearing it
|
||||||
|
"""
|
||||||
|
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
||||||
|
|
||||||
|
self.backend.clear_lock(self.TEST_KEY)
|
||||||
|
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
||||||
|
self.assertIsNotNone(cache.get(self.TEST_KEY))
|
@ -48,9 +48,9 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.user.is_superuser %}
|
{% if perms.mumble.view_connection_history %}
|
||||||
<a class="btn btn-primary" type="button" id="btnMumbleConnectionHistory" href="{% url 'mumble:connection_history' %}" title="{% translate 'Mumble Connection History' %}">
|
<a class="btn btn-primary" type="button" id="btnMumbleConnectionHistory" href="{% url 'mumble:connection_history' %}" title="{% translate 'Mumble Connection History' %}">
|
||||||
<i class="fa-solid fa-clock-rotate-left"></i> History
|
<i class="fa-solid fa-clock-rotate-left"></i> History
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -3,33 +3,11 @@ import logging
|
|||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from .hooks import ServicesHook
|
from .hooks import ServicesHook
|
||||||
from celery_once import QueueOnce as BaseTask, AlreadyQueued
|
from .celery_once.tasks import QueueOnce # noqa: F401 - for backwards compatibility
|
||||||
from django.core.cache import cache
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class QueueOnce(BaseTask):
|
|
||||||
once = BaseTask.once
|
|
||||||
once['graceful'] = True
|
|
||||||
|
|
||||||
|
|
||||||
class DjangoBackend:
|
|
||||||
def __init__(self, settings):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def raise_or_lock(key, timeout):
|
|
||||||
acquired = cache.add(key=key, value="lock", timeout=timeout)
|
|
||||||
if not acquired:
|
|
||||||
raise AlreadyQueued(int(cache.ttl(key)))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def clear_lock(key):
|
|
||||||
return cache.delete(key)
|
|
||||||
|
|
||||||
|
|
||||||
@shared_task(bind=True)
|
@shared_task(bind=True)
|
||||||
def validate_services(self, pk):
|
def validate_services(self, pk):
|
||||||
user = User.objects.get(pk=pk)
|
user = User.objects.get(pk=pk)
|
||||||
@ -38,7 +16,7 @@ def validate_services(self, pk):
|
|||||||
for svc in ServicesHook.get_services():
|
for svc in ServicesHook.get_services():
|
||||||
try:
|
try:
|
||||||
svc.validate_user(user)
|
svc.validate_user(user)
|
||||||
except:
|
except Exception:
|
||||||
logger.exception(f'Exception running validate_user for services module {svc} on user {user}')
|
logger.exception(f'Exception running validate_user for services module {svc} on user {user}')
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from celery_once import AlreadyQueued
|
|
||||||
|
|
||||||
from django.core.cache import cache
|
|
||||||
from django.test import override_settings, TestCase
|
from django.test import override_settings, TestCase
|
||||||
|
|
||||||
from allianceauth.tests.auth_utils import AuthUtils
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
from allianceauth.services.tasks import validate_services, update_groups_for_user
|
from allianceauth.services.tasks import validate_services, update_groups_for_user
|
||||||
|
|
||||||
from ..tasks import DjangoBackend
|
|
||||||
|
|
||||||
|
|
||||||
@override_settings(CELERY_ALWAYS_EAGER=True, CELERY_EAGER_PROPAGATES_EXCEPTIONS=True)
|
@override_settings(CELERY_ALWAYS_EAGER=True, CELERY_EAGER_PROPAGATES_EXCEPTIONS=True)
|
||||||
class ServicesTasksTestCase(TestCase):
|
class ServicesTasksTestCase(TestCase):
|
||||||
@ -46,46 +41,3 @@ class ServicesTasksTestCase(TestCase):
|
|||||||
self.assertTrue(svc.update_groups.called)
|
self.assertTrue(svc.update_groups.called)
|
||||||
args, _ = svc.update_groups.call_args
|
args, _ = svc.update_groups.call_args
|
||||||
self.assertEqual(self.member, args[0]) # Assert correct user
|
self.assertEqual(self.member, args[0]) # Assert correct user
|
||||||
|
|
||||||
|
|
||||||
class TestDjangoBackend(TestCase):
|
|
||||||
|
|
||||||
TEST_KEY = "my-django-backend-test-key"
|
|
||||||
TIMEOUT = 1800
|
|
||||||
|
|
||||||
def setUp(self) -> None:
|
|
||||||
cache.delete(self.TEST_KEY)
|
|
||||||
self.backend = DjangoBackend(dict())
|
|
||||||
|
|
||||||
def test_can_get_lock(self):
|
|
||||||
"""
|
|
||||||
when lock can be acquired
|
|
||||||
then set it with timetout
|
|
||||||
"""
|
|
||||||
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
|
||||||
self.assertIsNotNone(cache.get(self.TEST_KEY))
|
|
||||||
self.assertAlmostEqual(cache.ttl(self.TEST_KEY), self.TIMEOUT, delta=2)
|
|
||||||
|
|
||||||
def test_when_cant_get_lock_raise_exception(self):
|
|
||||||
"""
|
|
||||||
when lock can bot be acquired
|
|
||||||
then raise AlreadyQueued exception with countdown
|
|
||||||
"""
|
|
||||||
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
|
||||||
except Exception as ex:
|
|
||||||
self.assertIsInstance(ex, AlreadyQueued)
|
|
||||||
self.assertAlmostEqual(ex.countdown, self.TIMEOUT, delta=2)
|
|
||||||
|
|
||||||
def test_can_clear_lock(self):
|
|
||||||
"""
|
|
||||||
when a lock exists
|
|
||||||
then can get a new lock after clearing it
|
|
||||||
"""
|
|
||||||
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
|
||||||
|
|
||||||
self.backend.clear_lock(self.TEST_KEY)
|
|
||||||
self.backend.raise_or_lock(self.TEST_KEY, self.TIMEOUT)
|
|
||||||
self.assertIsNotNone(cache.get(self.TEST_KEY))
|
|
||||||
|
@ -172,7 +172,7 @@ ul.list-group.list-group-horizontal > li.list-group-item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eve time in navbar
|
/* EVE time in navbar
|
||||||
------------------------------------------------------------------------------------- */
|
------------------------------------------------------------------------------------- */
|
||||||
@media all {
|
@media all {
|
||||||
.nav-item-eve-time .eve-time-wrapper {
|
.nav-item-eve-time .eve-time-wrapper {
|
||||||
|
@ -14,7 +14,7 @@ $(document).ready(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the Eve time clock in the top menu bar
|
* Start the EVE time clock in the top menu bar
|
||||||
*/
|
*/
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
renderClock($('.eve-time-wrapper .eve-time-clock'));
|
renderClock($('.eve-time-wrapper .eve-time-clock'));
|
||||||
|
@ -28,7 +28,7 @@ const getDurationString = (duration) => { // eslint-disable-line no-unused-vars
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the current eve time as a formatted string
|
* returns the current EVE time as a formatted string
|
||||||
*
|
*
|
||||||
* condition:
|
* condition:
|
||||||
* only if moment.js is loaded before,
|
* only if moment.js is loaded before,
|
||||||
|
@ -12,11 +12,10 @@
|
|||||||
<!-- End Required meta tags -->
|
<!-- End Required meta tags -->
|
||||||
|
|
||||||
<!-- Meta tags -->
|
<!-- Meta tags -->
|
||||||
<!-- TODO Bundle all the site specific stuff up into its own template for easy override -->
|
{% include 'allianceauth/opengraph.html' %}
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="author" content="">
|
|
||||||
{% include 'allianceauth/icons.html' %}
|
{% include 'allianceauth/icons.html' %}
|
||||||
<!-- Meta tags -->
|
<!-- Meta tags -->
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
{% theme_css %}
|
{% theme_css %}
|
||||||
@ -30,7 +29,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nav-padding {
|
.nav-padding {
|
||||||
padding-top: {% header_padding_size %} !important;
|
margin-top: {% header_padding_size %} !important;
|
||||||
|
max-height: calc(100vh - {% header_padding_size %}) !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
8
allianceauth/templates/allianceauth/opengraph.html
Normal file
8
allianceauth/templates/allianceauth/opengraph.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{% load static %}
|
||||||
|
|
||||||
|
<meta property="og:title" content="{{ SITE_NAME }}">
|
||||||
|
<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:type" content="website">
|
||||||
|
<meta property="og:site_name" content="{{ request.META.HTTP_HOST }}">
|
||||||
|
<meta property="og:url" content="{{ request.path }}">
|
@ -20,7 +20,7 @@
|
|||||||
<div class="collapse navbar-collapse auth-menus-collapse">
|
<div class="collapse navbar-collapse auth-menus-collapse">
|
||||||
<ul class="nav navbar-nav navbar-right navbar-pills">
|
<ul class="nav navbar-nav navbar-right navbar-pills">
|
||||||
<li class="nav-item-eve-time">
|
<li class="nav-item-eve-time">
|
||||||
<div class="eve-time-wrapper">{% translate "Eve Time" %}: <span class="eve-time-clock"></span></div>
|
<div class="eve-time-wrapper">{% translate "EVE time" %}: <span class="eve-time-clock"></span></div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
<img src="{% static 'allianceauth/images/auth-logo.svg' %}" width="{{ logo_width|default:"128px" }}" height="{% if logo_height %}{{ logo_ }}{% else %}{{ logo_width|default:"128px" }}{% endif %}" alt="{{ SITE_NAME }}">
|
<img src="{% static 'allianceauth/images/auth-logo.svg' %}" width="{{ logo_width|default:"128px" }}" height="{% if logo_height %}{{ logo_height }}{% else %}{{ logo_width|default:"128px" }}{% endif %}" alt="{{ SITE_NAME }}">
|
||||||
|
@ -66,7 +66,7 @@ class TimerForm(forms.ModelForm):
|
|||||||
future_time = datetime.timedelta(days=days_left, hours=hours_left, minutes=minutes_left)
|
future_time = datetime.timedelta(days=days_left, hours=hours_left, minutes=minutes_left)
|
||||||
current_time = timezone.now()
|
current_time = timezone.now()
|
||||||
eve_time = current_time + future_time
|
eve_time = current_time + future_time
|
||||||
logger.debug(f"Determined timer eve time is {eve_time} - current time {current_time}, adding {future_time}")
|
logger.debug(f"Determined timer EVE time is {eve_time} - current time {current_time}, adding {future_time}")
|
||||||
elif absolute_time:
|
elif absolute_time:
|
||||||
# Use absolute time
|
# Use absolute time
|
||||||
eve_time = absolute_time
|
eve_time = absolute_time
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<th class="text-center">{% translate "Timer" %}</th>
|
<th class="text-center">{% translate "Timer" %}</th>
|
||||||
<th class="text-center">{% translate "Type" %}</th>
|
<th class="text-center">{% translate "Type" %}</th>
|
||||||
<th class="text-center">{% translate "System" %}</th>
|
<th class="text-center">{% translate "System" %}</th>
|
||||||
<th class="text-center">{% translate "EVE Time" %}</th>
|
<th class="text-center">{% translate "EVE time" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<th class="text-center">{% translate "Objective" %}</th>
|
<th class="text-center">{% translate "Objective" %}</th>
|
||||||
<th class="text-center">{% translate "System" %}</th>
|
<th class="text-center">{% translate "System" %}</th>
|
||||||
<th class="text-center">{% translate "Structure" %}</th>
|
<th class="text-center">{% translate "Structure" %}</th>
|
||||||
<th class="text-center">{% translate "Eve Time" %}</th>
|
<th class="text-center">{% translate "EVE time" %}</th>
|
||||||
<th class="text-center">{% translate "Local Time" %}</th>
|
<th class="text-center">{% translate "Local Time" %}</th>
|
||||||
<th class="text-center">{% translate "Creator" %}</th>
|
<th class="text-center">{% translate "Creator" %}</th>
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<div class="allianceauth-timerboard">
|
<div class="allianceauth-timerboard">
|
||||||
<div class="col-lg-12 text-center mb-3">
|
<div class="col-lg-12 text-center mb-3">
|
||||||
<div class="badge bg-primary text-start">
|
<div class="badge bg-primary text-start">
|
||||||
<span>{% translate "Current Eve Time:" %}</span>
|
<span>{% translate "Current EVE time:" %}</span>
|
||||||
<span id="current-time"></span>
|
<span id="current-time"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -81,7 +81,7 @@ Example implementation for a celery chain:
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
from allianceauth.services.hooks import get_extension_logger
|
from allianceauth.services.hooks import get_extension_logger
|
||||||
from celery import shared_task, chain
|
from celery import shared_task, group
|
||||||
|
|
||||||
logger = get_extension_logger(__name__)
|
logger = get_extension_logger(__name__)
|
||||||
|
|
||||||
@ -98,18 +98,23 @@ def long_runner():
|
|||||||
task_signature = example.si()
|
task_signature = example.si()
|
||||||
my_tasks.append(task_signature)
|
my_tasks.append(task_signature)
|
||||||
|
|
||||||
chain(my_tasks).delay()
|
group(my_tasks).delay()
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example, we first add 10 example tasks that need to run one after the other to a list. This can be done by creating a so-called signature for a task. Those signatures are a kind of wrapper for tasks and can be used in various ways to compose work flow for tasks.
|
In this example, we first add 10 example tasks that need to run one after the other to a list. This can be done by creating a so-called signature for a task. Those signatures are a kind of wrapper for tasks and can be used in various ways to compose work flow for tasks.
|
||||||
|
|
||||||
The list of task signatures is then converted to a chain and started asynchronously.
|
The list of task signatures is then converted to a chain and started asynchronously.
|
||||||
|
|
||||||
|
:::{note}
|
||||||
|
In this example we import group to execute all tasks independently.
|
||||||
|
If you wish to run them in order (and stop if a tasks fail) you can use `celery.chain` instead of `celery.group`
|
||||||
|
|
||||||
|
For more information on signature and work flows see the official documentation on [Canvas](https://docs.celeryproject.org/en/latest/userguide/canvas.html).
|
||||||
|
:::
|
||||||
|
|
||||||
:::{hint}
|
:::{hint}
|
||||||
In our example we use ``si()``, which is a shortcut for "immutable signatures" and prevents us from having to deal with result sharing between tasks.
|
In our example we use ``si()``, which is a shortcut for "immutable signatures" and prevents us from having to deal with result sharing between tasks.
|
||||||
|
|
||||||
For more information on signature and work flows see the official documentation on `Canvas <https://docs.celeryproject.org/en/latest/userguide/canvas.html>`_.
|
|
||||||
|
|
||||||
In this context, please note that Alliance Auth currently only supports chaining because all other variants require a so-called results back, which Alliance Auth does not have.
|
In this context, please note that Alliance Auth currently only supports chaining because all other variants require a so-called results back, which Alliance Auth does not have.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ app.conf.task_default_priority = 5 # anything called with the task.delay() will
|
|||||||
app.conf.worker_prefetch_multiplier = 1 # only prefetch single tasks at a time on the workers so that prio tasks happen
|
app.conf.worker_prefetch_multiplier = 1 # only prefetch single tasks at a time on the workers so that prio tasks happen
|
||||||
|
|
||||||
app.conf.ONCE = {
|
app.conf.ONCE = {
|
||||||
'backend': 'allianceauth.services.tasks.DjangoBackend',
|
'backend': 'allianceauth.services.celery_once.backends.DjangoBackend',
|
||||||
'settings': {}
|
'settings': {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user