mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-23 19:22:27 +02:00
Compare commits
17 Commits
156e7c891e
...
86abc4f169
Author | SHA1 | Date | |
---|---|---|---|
|
86abc4f169 | ||
|
fbafcac5b1 | ||
|
a5971314f5 | ||
|
a03c766840 | ||
|
ad47ff2c54 | ||
|
3efdb8f12b | ||
|
823fc82d19 | ||
|
a93e510895 | ||
|
d99f5858d8 | ||
|
4578ecf21d | ||
|
b737504d52 | ||
|
c6b6443901 | ||
|
f51523dc07 | ||
|
bd4dd60c98 | ||
|
a4ea48e14e | ||
|
646d3f5408 | ||
|
0f057ffa84 |
@ -1,15 +1,16 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import AnalyticsIdentifier, AnalyticsTokens
|
from .models import AnalyticsIdentifier, AnalyticsTokens
|
||||||
|
from solo.admin import SingletonModelAdmin
|
||||||
|
|
||||||
|
|
||||||
@admin.register(AnalyticsIdentifier)
|
@admin.register(AnalyticsIdentifier)
|
||||||
class AnalyticsIdentifierAdmin(admin.ModelAdmin):
|
class AnalyticsIdentifierAdmin(SingletonModelAdmin):
|
||||||
search_fields = ['identifier', ]
|
search_fields = ['identifier', ]
|
||||||
list_display = ('identifier',)
|
list_display = ['identifier', ]
|
||||||
|
|
||||||
|
|
||||||
@admin.register(AnalyticsTokens)
|
@admin.register(AnalyticsTokens)
|
||||||
class AnalyticsTokensAdmin(admin.ModelAdmin):
|
class AnalyticsTokensAdmin(admin.ModelAdmin):
|
||||||
search_fields = ['name', ]
|
search_fields = ['name', ]
|
||||||
list_display = ('name', 'type',)
|
list_display = ['name', 'type', ]
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 4.2.16 on 2024-12-11 02:17
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('analytics', '0009_remove_analyticstokens_ignore_paths_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='analyticsidentifier',
|
||||||
|
options={'verbose_name': 'Analytics Identifier'},
|
||||||
|
),
|
||||||
|
]
|
@ -1,23 +1,19 @@
|
|||||||
|
from typing import Literal
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from solo.models import SingletonModel
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
|
|
||||||
class AnalyticsIdentifier(models.Model):
|
class AnalyticsIdentifier(SingletonModel):
|
||||||
|
|
||||||
identifier = models.UUIDField(
|
identifier = models.UUIDField(default=uuid4, editable=False)
|
||||||
default=uuid4,
|
|
||||||
editable=False)
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def __str__(self) -> Literal['Analytics Identifier']:
|
||||||
if not self.pk and AnalyticsIdentifier.objects.exists():
|
return "Analytics Identifier"
|
||||||
# Force a single object
|
|
||||||
raise ValidationError('There is can be only one \
|
class Meta:
|
||||||
AnalyticsIdentifier instance')
|
verbose_name = "Analytics Identifier"
|
||||||
self.pk = self.id = 1 # If this happens to be deleted and recreated, force it to be 1
|
|
||||||
return super().save(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class AnalyticsTokens(models.Model):
|
class AnalyticsTokens(models.Model):
|
||||||
|
@ -5,6 +5,7 @@ from django.apps import apps
|
|||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from .models import AnalyticsTokens, AnalyticsIdentifier
|
from .models import AnalyticsTokens, AnalyticsIdentifier
|
||||||
from .utils import (
|
from .utils import (
|
||||||
|
existence_baremetal_or_docker,
|
||||||
install_stat_addons,
|
install_stat_addons,
|
||||||
install_stat_tokens,
|
install_stat_tokens,
|
||||||
install_stat_users)
|
install_stat_users)
|
||||||
@ -67,8 +68,8 @@ def analytics_event(namespace: str,
|
|||||||
value=value).apply_async(priority=9)
|
value=value).apply_async(priority=9)
|
||||||
|
|
||||||
|
|
||||||
@shared_task()
|
@shared_task
|
||||||
def analytics_daily_stats():
|
def analytics_daily_stats() -> None:
|
||||||
"""Celery Task: Do not call directly
|
"""Celery Task: Do not call directly
|
||||||
|
|
||||||
Gathers a series of daily statistics
|
Gathers a series of daily statistics
|
||||||
@ -77,6 +78,7 @@ def analytics_daily_stats():
|
|||||||
users = install_stat_users()
|
users = install_stat_users()
|
||||||
tokens = install_stat_tokens()
|
tokens = install_stat_tokens()
|
||||||
addons = install_stat_addons()
|
addons = install_stat_addons()
|
||||||
|
existence_type = existence_baremetal_or_docker()
|
||||||
logger.debug("Running Daily Analytics Upload")
|
logger.debug("Running Daily Analytics Upload")
|
||||||
|
|
||||||
analytics_event(namespace='allianceauth.analytics',
|
analytics_event(namespace='allianceauth.analytics',
|
||||||
@ -84,6 +86,11 @@ def analytics_daily_stats():
|
|||||||
label='existence',
|
label='existence',
|
||||||
value=1,
|
value=1,
|
||||||
event_type='Stats')
|
event_type='Stats')
|
||||||
|
analytics_event(namespace='allianceauth.analytics',
|
||||||
|
task='send_install_stats',
|
||||||
|
label=existence_type,
|
||||||
|
value=1,
|
||||||
|
event_type='Stats')
|
||||||
analytics_event(namespace='allianceauth.analytics',
|
analytics_event(namespace='allianceauth.analytics',
|
||||||
task='send_install_stats',
|
task='send_install_stats',
|
||||||
label='users',
|
label='users',
|
||||||
@ -99,7 +106,6 @@ def analytics_daily_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():
|
||||||
if appconfig.label in [
|
if appconfig.label in [
|
||||||
"django_celery_beat",
|
"django_celery_beat",
|
||||||
@ -135,7 +141,7 @@ def analytics_daily_stats():
|
|||||||
event_type='Stats')
|
event_type='Stats')
|
||||||
|
|
||||||
|
|
||||||
@shared_task()
|
@shared_task
|
||||||
def send_ga_tracking_celery_event(
|
def send_ga_tracking_celery_event(
|
||||||
measurement_id: str,
|
measurement_id: str,
|
||||||
secret: str,
|
secret: str,
|
||||||
@ -165,7 +171,7 @@ def send_ga_tracking_celery_event(
|
|||||||
}
|
}
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
'client_id': AnalyticsIdentifier.objects.get(id=1).identifier.hex,
|
'client_id': AnalyticsIdentifier.get_solo().identifier.hex,
|
||||||
"user_properties": {
|
"user_properties": {
|
||||||
"allianceauth_version": {
|
"allianceauth_version": {
|
||||||
"value": __version__
|
"value": __version__
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
from allianceauth.analytics.models import AnalyticsIdentifier
|
from allianceauth.analytics.models import AnalyticsIdentifier
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
|
|
||||||
from django.test.testcases import TestCase
|
from django.test.testcases import TestCase
|
||||||
|
|
||||||
from uuid import UUID, uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
|
|
||||||
# Identifiers
|
# Identifiers
|
||||||
@ -14,14 +13,4 @@ uuid_2 = "7aa6bd70701f44729af5e3095ff4b55c"
|
|||||||
class TestAnalyticsIdentifier(TestCase):
|
class TestAnalyticsIdentifier(TestCase):
|
||||||
|
|
||||||
def test_identifier_random(self):
|
def test_identifier_random(self):
|
||||||
self.assertNotEqual(AnalyticsIdentifier.objects.get(), uuid4)
|
self.assertNotEqual(AnalyticsIdentifier.get_solo(), uuid4)
|
||||||
|
|
||||||
def test_identifier_singular(self):
|
|
||||||
AnalyticsIdentifier.objects.all().delete()
|
|
||||||
AnalyticsIdentifier.objects.create(identifier=uuid_1)
|
|
||||||
# Yeah i have multiple asserts here, they all do the same thing
|
|
||||||
with self.assertRaises(ValidationError):
|
|
||||||
AnalyticsIdentifier.objects.create(identifier=uuid_2)
|
|
||||||
self.assertEqual(AnalyticsIdentifier.objects.count(), 1)
|
|
||||||
self.assertEqual(AnalyticsIdentifier.objects.get(
|
|
||||||
pk=1).identifier, UUID(uuid_1))
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import os
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from allianceauth.authentication.models import User
|
from allianceauth.authentication.models import User
|
||||||
from esi.models import Token
|
from esi.models import Token
|
||||||
@ -34,3 +35,16 @@ def install_stat_addons() -> int:
|
|||||||
The Number of Installed Apps"""
|
The Number of Installed Apps"""
|
||||||
addons = len(list(apps.get_app_configs()))
|
addons = len(list(apps.get_app_configs()))
|
||||||
return addons
|
return addons
|
||||||
|
|
||||||
|
|
||||||
|
def existence_baremetal_or_docker() -> str:
|
||||||
|
"""Checks the Installation Type of an install
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
existence_baremetal or existence_docker"""
|
||||||
|
docker_tag = os.getenv('AA_DOCKER_TAG')
|
||||||
|
if docker_tag:
|
||||||
|
return "existence_docker"
|
||||||
|
return "existence_baremetal"
|
||||||
|
@ -44,8 +44,10 @@ INSTALLED_APPS = [
|
|||||||
'allianceauth.theme.materia',
|
'allianceauth.theme.materia',
|
||||||
"allianceauth.custom_css",
|
"allianceauth.custom_css",
|
||||||
'allianceauth.crontab',
|
'allianceauth.crontab',
|
||||||
|
'sri',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SRI_ALGORITHM = "sha512"
|
||||||
SECRET_KEY = "wow I'm a really bad default secret key"
|
SECRET_KEY = "wow I'm a really bad default secret key"
|
||||||
|
|
||||||
# Celery configuration
|
# Celery configuration
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{% load static %}
|
{% load sri %}
|
||||||
|
|
||||||
<link href="{% static 'allianceauth/css/auth-base.css' %}" rel="stylesheet">
|
{% sri_static 'allianceauth/css/auth-base.css' %}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{% load static %}
|
{% load sri %}
|
||||||
|
|
||||||
<link href="{% static 'allianceauth/framework/css/auth-framework.css' %}" rel="stylesheet">
|
{% sri_static 'allianceauth/framework/css/auth-framework.css' %}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
{% load sri %}
|
||||||
|
|
||||||
<!-- Bootstrap CSS -->
|
<!-- Bootstrap CSS -->
|
||||||
{% if NIGHT_MODE %}
|
{% if NIGHT_MODE %}
|
||||||
{% if debug %}
|
{% if debug %}
|
||||||
@ -6,7 +8,7 @@
|
|||||||
<link rel="stylesheet/less" href="{% static 'allianceauth/css/themes/darkly/darkly.less' %}">
|
<link rel="stylesheet/less" href="{% static 'allianceauth/css/themes/darkly/darkly.less' %}">
|
||||||
<script src='https://cdnjs.cloudflare.com/ajax/libs/less.js/4.1.3/less.min.js' integrity='sha512-6gUGqd/zBCrEKbJqPI7iINc61jlOfH5A+SluY15IkNO1o4qP1DEYjQBewTB4l0U4ihXZdupg8Mb77VxqE+37dg==' crossorigin='anonymous' referrerpolicy="no-referrer"></script>
|
<script src='https://cdnjs.cloudflare.com/ajax/libs/less.js/4.1.3/less.min.js' integrity='sha512-6gUGqd/zBCrEKbJqPI7iINc61jlOfH5A+SluY15IkNO1o4qP1DEYjQBewTB4l0U4ihXZdupg8Mb77VxqE+37dg==' crossorigin='anonymous' referrerpolicy="no-referrer"></script>
|
||||||
{% else %}
|
{% else %}
|
||||||
<link rel="stylesheet" href="{% static 'allianceauth/css/themes/darkly/darkly.min.css' %}">
|
{% sri_static 'allianceauth/css/themes/darkly/darkly.min.css' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if debug %}
|
{% if debug %}
|
||||||
@ -14,7 +16,7 @@
|
|||||||
<link rel="stylesheet/less" href="{% static 'allianceauth/css/themes/flatly/flatly.less' %}">
|
<link rel="stylesheet/less" href="{% static 'allianceauth/css/themes/flatly/flatly.less' %}">
|
||||||
<script src='https://cdnjs.cloudflare.com/ajax/libs/less.js/4.1.3/less.min.js' integrity='sha512-6gUGqd/zBCrEKbJqPI7iINc61jlOfH5A+SluY15IkNO1o4qP1DEYjQBewTB4l0U4ihXZdupg8Mb77VxqE+37dg==' crossorigin='anonymous' referrerpolicy="no-referrer"></script>
|
<script src='https://cdnjs.cloudflare.com/ajax/libs/less.js/4.1.3/less.min.js' integrity='sha512-6gUGqd/zBCrEKbJqPI7iINc61jlOfH5A+SluY15IkNO1o4qP1DEYjQBewTB4l0U4ihXZdupg8Mb77VxqE+37dg==' crossorigin='anonymous' referrerpolicy="no-referrer"></script>
|
||||||
{% else %}
|
{% else %}
|
||||||
<link rel="stylesheet" href="{% static 'allianceauth/css/themes/flatly/flatly.min.css' %}">
|
{% sri_static 'allianceauth/css/themes/flatly/flatly.min.css' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<!-- End Bootstrap CSS -->
|
<!-- End Bootstrap CSS -->
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{% load static %}
|
{% load sri %}
|
||||||
|
|
||||||
<link href="{% static 'allianceauth/css/checkbox.css' %}" rel="stylesheet">
|
{% sri_static 'allianceauth/css/checkbox.css' %}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{% load static %}
|
{% load sri %}
|
||||||
|
|
||||||
<script src="{% static 'allianceauth/js/eve-time.js' %}"></script>
|
{% sri_static 'allianceauth/js/eve-time.js' %}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{% load static %}
|
{% load sri %}
|
||||||
|
|
||||||
<script src="{% static 'allianceauth/js/filterDropDown/filterDropDown.min.js' %}"></script>
|
{% sri_static 'allianceauth/js/filterDropDown/filterDropDown.min.js' %}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{% load static %}
|
|
||||||
<!-- Start jQuery UI CSS from Alliance Auth -->
|
<!-- Start jQuery UI CSS from Alliance Auth -->
|
||||||
<!-- CDNs all contain theme.css, which is not supposed to be in the base CSS, Which is why this is uniquely bundled in not using a CDN -->
|
<!-- CDNs all contain theme.css, which is not supposed to be in the base CSS, which is why this is uniquely bundled in not using a CDN -->
|
||||||
<link rel="stylesheet" href="{% static 'allianceauth/js/jquery-ui/1.13.2/css/jquery-ui.min.css' %}" integrity="VEqAhOZvZrx/WaxlpMoLvZDSLeLNYhkL5LU2R4/ihPJb/+qkGoMrA15SqEGtI+PCLgKwCDiby7tgdvdiAZkJGg==" crossorigin="anonymous" referrerpolicy="no-referrer">
|
{% load sri %}
|
||||||
|
|
||||||
|
{% sri_static 'allianceauth/js/jquery-ui/1.13.2/css/jquery-ui.min.css' %}
|
||||||
<!-- End jQuery UI CSS from aa-gdpr -->
|
<!-- End jQuery UI CSS from aa-gdpr -->
|
||||||
|
@ -1,7 +1,19 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
<!-- Start Moment.js from cdnjs -->
|
<!-- Start Moment.js from cdnjs -->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js" integrity="sha512-+H4iLjY3JsKiF2V6N366in5IQHj2uEsGV7Pp/GRcm0fn76aPAk5V8xB6n8fQhhSonTqTXs/klFz4D0GIn6Br9g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js" integrity="sha512-+H4iLjY3JsKiF2V6N366in5IQHj2uEsGV7Pp/GRcm0fn76aPAk5V8xB6n8fQhhSonTqTXs/klFz4D0GIn6Br9g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
|
||||||
{% if locale and LANGUAGE_CODE != 'en' %}
|
{% if locale and LANGUAGE_CODE != 'en' %}
|
||||||
<!-- Moment.JS Not EN-en -->
|
<!-- Moment.JS Not EN-en -->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/locale/{{ LANGUAGE_CODE }}.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
|
{% get_language_info for LANGUAGE_CODE as lang %}
|
||||||
|
|
||||||
|
{% if lang.code == 'zh-hans' %}
|
||||||
|
<!-- Moment.JS Localisation ({{ lang.code }}) -->
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/locale/zh-cn.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
{% else %}
|
||||||
|
<!-- Moment.JS Localisation ({{ lang.code }}) -->
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/locale/{{ lang.code }}.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<!-- End Moment JS from cdnjs -->
|
<!-- End Moment JS from cdnjs -->
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{% load static %}
|
{% load sri %}
|
||||||
|
|
||||||
<script src="{% static 'allianceauth/js/refresh-notification-icon.js' %}"></script>
|
{% sri_static 'allianceauth/js/refresh-notification-icon.js' %}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{% load static %}
|
{% load sri %}
|
||||||
|
|
||||||
<script src="{% static 'allianceauth/js/refresh_notifications.js' %}"></script>
|
{% sri_static 'allianceauth/js/refresh_notifications.js' %}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{% load static %}
|
{% load sri %}
|
||||||
|
|
||||||
<script src="{% static 'allianceauth/js/timerboard.js' %}"></script>
|
{% sri_static 'allianceauth/js/timerboard.js' %}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{% load static %}
|
{% load sri %}
|
||||||
|
|
||||||
<script src="{% static 'allianceauth/js/timers.js' %}"></script>
|
{% sri_static 'allianceauth/js/timers.js' %}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
# Generated by Django 4.2.17 on 2025-01-06 17:16
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("timerboard", "0006_alter_timer_objective_alter_timer_structure_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="timer",
|
||||||
|
name="structure",
|
||||||
|
field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("POCO", "POCO"),
|
||||||
|
("Orbital Skyhook", "Orbital Skyhook"),
|
||||||
|
("I-HUB", "Sovereignty Hub"),
|
||||||
|
("TCU", "TCU"),
|
||||||
|
("POS[S]", "POS [S]"),
|
||||||
|
("POS[M]", "POS [M]"),
|
||||||
|
("POS[L]", "POS [L]"),
|
||||||
|
("Astrahus", "Astrahus"),
|
||||||
|
("Fortizar", "Fortizar"),
|
||||||
|
("Keepstar", "Keepstar"),
|
||||||
|
("Raitaru", "Raitaru"),
|
||||||
|
("Azbel", "Azbel"),
|
||||||
|
("Sotiyo", "Sotiyo"),
|
||||||
|
("Athanor", "Athanor"),
|
||||||
|
("Tatara", "Tatara"),
|
||||||
|
("Pharolux Cyno Beacon", "Cyno Beacon"),
|
||||||
|
("Tenebrex Cyno Jammer", "Cyno Jammer"),
|
||||||
|
("Ansiblex Jump Gate", "Ansiblex Jump Gate"),
|
||||||
|
("Mercenary Den", "Mercenary Den"),
|
||||||
|
("Moon Mining Cycle", "Moon Mining Cycle"),
|
||||||
|
("Metenox Moon Drill", "Metenox Moon Drill"),
|
||||||
|
("Other", "Other"),
|
||||||
|
],
|
||||||
|
default="Other",
|
||||||
|
max_length=254,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -1,6 +1,6 @@
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from allianceauth.eveonline.models import EveCharacter
|
from allianceauth.eveonline.models import EveCharacter
|
||||||
from allianceauth.eveonline.models import EveCorporationInfo
|
from allianceauth.eveonline.models import EveCorporationInfo
|
||||||
@ -23,7 +23,7 @@ class Timer(models.Model):
|
|||||||
|
|
||||||
POCO = "POCO", _("POCO")
|
POCO = "POCO", _("POCO")
|
||||||
ORBITALSKYHOOK = "Orbital Skyhook", _("Orbital Skyhook")
|
ORBITALSKYHOOK = "Orbital Skyhook", _("Orbital Skyhook")
|
||||||
IHUB = "I-HUB", _("I-HUB")
|
IHUB = "I-HUB", _("Sovereignty Hub")
|
||||||
TCU = "TCU", _("TCU") # Pending Remval
|
TCU = "TCU", _("TCU") # Pending Remval
|
||||||
POSS = "POS[S]", _("POS [S]")
|
POSS = "POS[S]", _("POS [S]")
|
||||||
POSM = "POS[M]", _("POS [M]")
|
POSM = "POS[M]", _("POS [M]")
|
||||||
@ -36,9 +36,10 @@ class Timer(models.Model):
|
|||||||
SOTIYO = "Sotiyo", _("Sotiyo")
|
SOTIYO = "Sotiyo", _("Sotiyo")
|
||||||
ATHANOR = "Athanor", _("Athanor")
|
ATHANOR = "Athanor", _("Athanor")
|
||||||
TATARA = "Tatara", _("Tatara")
|
TATARA = "Tatara", _("Tatara")
|
||||||
PHAROLUX = "Pharolux Cyno Beacon", _("Pharolux Cyno Beacon")
|
PHAROLUX = "Pharolux Cyno Beacon", _("Cyno Beacon")
|
||||||
TENEBREX = "Tenebrex Cyno Jammer", _("Tenebrex Cyno Jammer")
|
TENEBREX = "Tenebrex Cyno Jammer", _("Cyno Jammer")
|
||||||
ANSIBLEX = "Ansiblex Jump Gate", _("Ansiblex Jump Gate")
|
ANSIBLEX = "Ansiblex Jump Gate", _("Ansiblex Jump Gate")
|
||||||
|
MERCDEN = "Mercenary Den", _("Mercenary Den")
|
||||||
MOONPOP = "Moon Mining Cycle", _("Moon Mining Cycle")
|
MOONPOP = "Moon Mining Cycle", _("Moon Mining Cycle")
|
||||||
METENOX = "Metenox Moon Drill", _("Metenox Moon Drill")
|
METENOX = "Metenox Moon Drill", _("Metenox Moon Drill")
|
||||||
OTHER = "Other", _("Other")
|
OTHER = "Other", _("Other")
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
{% for timer in timers %}
|
{% for timer in timers %}
|
||||||
<tr class="{% if timer.important == True %}bg-danger bg-opacity-25{% else %}bg-info bg-opacity-25{% endif %}">
|
<tr class="{% if timer.important == True %}bg-danger bg-opacity-25{% else %}bg-info bg-opacity-25{% endif %}">
|
||||||
|
|
||||||
<td style="width: 150px;" class="text-center">
|
<td style="width: 150px;" class="text-center">
|
||||||
{{ timer.details }}
|
{{ timer.details }}
|
||||||
|
|
||||||
@ -30,13 +29,21 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
|
{% comment %} Objective: Hostile (BG: Danger) {% endcomment %}
|
||||||
{% if timer.objective == "Hostile" %}
|
{% if timer.objective == "Hostile" %}
|
||||||
<div class="badge bg-danger">{% translate "Hostile" %}</div>
|
<div class="badge bg-danger">
|
||||||
|
|
||||||
|
{% comment %} Objective: Friendly (BG: Primare) {% endcomment %}
|
||||||
{% elif timer.objective == "Friendly" %}
|
{% elif timer.objective == "Friendly" %}
|
||||||
<div class="badge bg-primary">{% translate "Friendly" %}</div>
|
<div class="badge bg-primary">
|
||||||
|
|
||||||
|
{% comment %} Objective: Neutral (BG: Secondary) {% endcomment %}
|
||||||
{% elif timer.objective == "Neutral" %}
|
{% elif timer.objective == "Neutral" %}
|
||||||
<div class="badge bg-secondary">{% translate "Neutral" %}</div>
|
<div class="badge bg-secondary">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{{ timer.get_objective_display }}
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
@ -44,49 +51,9 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
{% if timer.structure == "POCO" %}
|
<div class="badge bg-{{ timer.bg_modifier }}">
|
||||||
<div class="badge bg-info">{% translate "POCO" %}</div>
|
{{ timer.get_structure_display }}
|
||||||
{% elif timer.structure == "Orbital Skyhook" %}
|
</div>
|
||||||
<div class="badge bg-warning">{% translate "Orbital Skyhook" %}</div>
|
|
||||||
{% elif timer.structure == "I-HUB" %}
|
|
||||||
<div class="badge bg-warning">{% translate "I-HUB" %}</div>
|
|
||||||
{% elif timer.structure == "TCU" %} {% comment %} Pending Removal {% endcomment %}
|
|
||||||
<div class="badge bg-secondary">{% translate "TCU" %}</div>
|
|
||||||
{% elif timer.structure == "POS[S]" %}
|
|
||||||
<div class="badge bg-info">{% translate "POS [S]" %}</div>
|
|
||||||
{% elif timer.structure == "POS[M]" %}
|
|
||||||
<div class="badge bg-info">{% translate "POS [M]" %}</div>
|
|
||||||
{% elif timer.structure == "POS[L]" %}
|
|
||||||
<div class="badge bg-info">{% translate "POS [L]" %}</div>
|
|
||||||
{% elif timer.structure == "Citadel[M]" or timer.structure == "Astrahus" %}
|
|
||||||
<div class="badge bg-danger">{% translate "Astrahus" %}</div>
|
|
||||||
{% elif timer.structure == "Citadel[L]" or timer.structure == "Fortizar" %}
|
|
||||||
<div class="badge bg-danger">{% translate "Fortizar" %}</div>
|
|
||||||
{% elif timer.structure == "Citadel[XL]" or timer.structure == "Keepstar" %}
|
|
||||||
<div class="badge bg-danger">{% translate "Keepstar" %}</div>
|
|
||||||
{% elif timer.structure == "Engineering Complex[M]" or timer.structure == "Raitaru" %}
|
|
||||||
<div class="badge bg-warning">{% translate "Raitaru" %}</div>
|
|
||||||
{% elif timer.structure == "Engineering Complex[L]" or timer.structure == "Azbel" %}
|
|
||||||
<div class="badge bg-warning">{% translate "Azbel" %}</div>
|
|
||||||
{% elif timer.structure == "Engineering Complex[XL]" or timer.structure == "Sotiyo" %}
|
|
||||||
<div class="badge bg-danger">{% translate "Sotiyo" %}</div>
|
|
||||||
{% elif timer.structure == "Refinery[M]" or timer.structure == "Athanor" %}
|
|
||||||
<div class="badge bg-warning">{% translate "Athanor" %}</div>
|
|
||||||
{% elif timer.structure == "Refinery[L]" or timer.structure == "Tatara" %}
|
|
||||||
<div class="badge bg-warning">{% translate "Tatara" %}</div>
|
|
||||||
{% elif timer.structure == "Cyno Beacon" or timer.structure == "Pharolux Cyno Beacon" %}
|
|
||||||
<div class="badge bg-warning">{% translate "Cyno Beacon" %}</div>
|
|
||||||
{% elif timer.structure == "Cyno Jammer" or timer.structure == "Tenebrex Cyno Jammer" %}
|
|
||||||
<div class="badge bg-warning">{% translate "Cyno Jammer" %}</div>
|
|
||||||
{% elif timer.structure == "Jump Gate" or timer.structure == "Ansiblex Jump Gate" %}
|
|
||||||
<div class="badge bg-warning">{% translate "Ansiblex Jump Gate" %}</div>
|
|
||||||
{% elif timer.structure == "Moon Mining Cycle" %}
|
|
||||||
<div class="badge bg-success">{% translate "Moon Mining Cycle" %}</div>
|
|
||||||
{% elif timer.structure == "Metenox Moon Drill" %}
|
|
||||||
<div class="badge bg-warning">{% translate "Metenox Moon Drill" %}</div>
|
|
||||||
{% elif timer.structure == "Other" %}
|
|
||||||
<div class="badge bg-secondary">{% translate "Other" %}</div>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
|
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import datetime
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.mixins import (
|
from django.contrib.auth.mixins import (
|
||||||
LoginRequiredMixin, PermissionRequiredMixin,
|
LoginRequiredMixin,
|
||||||
|
PermissionRequiredMixin,
|
||||||
)
|
)
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
@ -20,8 +20,8 @@ from allianceauth.timerboard.models import Timer
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
TIMER_VIEW_PERMISSION = 'auth.timer_view'
|
TIMER_VIEW_PERMISSION = "auth.timer_view"
|
||||||
TIMER_MANAGE_PERMISSION = 'auth.timer_management'
|
TIMER_MANAGE_PERMISSION = "auth.timer_management"
|
||||||
|
|
||||||
|
|
||||||
class BaseTimerView(LoginRequiredMixin, PermissionRequiredMixin, View):
|
class BaseTimerView(LoginRequiredMixin, PermissionRequiredMixin, View):
|
||||||
@ -29,22 +29,112 @@ class BaseTimerView(LoginRequiredMixin, PermissionRequiredMixin, View):
|
|||||||
|
|
||||||
|
|
||||||
class TimerView(BaseTimerView):
|
class TimerView(BaseTimerView):
|
||||||
template_name = 'timerboard/view.html'
|
template_name = "timerboard/view.html"
|
||||||
permission_required = TIMER_VIEW_PERMISSION
|
permission_required = TIMER_VIEW_PERMISSION
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
|
"""
|
||||||
|
Renders the timer view
|
||||||
|
|
||||||
|
:param request:
|
||||||
|
:type request:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_bg_modifier(structure):
|
||||||
|
"""
|
||||||
|
Returns the bootstrap bg modifier for the given structure
|
||||||
|
|
||||||
|
:param structure:
|
||||||
|
:type structure:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
|
||||||
|
if structure in bg_info:
|
||||||
|
return "info"
|
||||||
|
elif structure in bg_warning:
|
||||||
|
return "warning"
|
||||||
|
elif structure in bg_danger:
|
||||||
|
return "danger"
|
||||||
|
elif structure in bg_secondary:
|
||||||
|
return "secondary"
|
||||||
|
|
||||||
|
return "primary"
|
||||||
|
|
||||||
logger.debug(f"timer_view called by user {request.user}")
|
logger.debug(f"timer_view called by user {request.user}")
|
||||||
char = request.user.profile.main_character
|
char = request.user.profile.main_character
|
||||||
|
|
||||||
if char:
|
if char:
|
||||||
corp = char.corporation
|
corp = char.corporation
|
||||||
else:
|
else:
|
||||||
corp = None
|
corp = None
|
||||||
base_query = Timer.objects.select_related('eve_character')
|
|
||||||
|
base_query = Timer.objects.select_related("eve_character")
|
||||||
|
|
||||||
|
timers = []
|
||||||
|
corp_timers = []
|
||||||
|
future_timers = []
|
||||||
|
past_timers = []
|
||||||
|
|
||||||
|
bg_info = [
|
||||||
|
Timer.Structure.POCO.value, # POCO
|
||||||
|
Timer.Structure.POSS.value, # POS[S]
|
||||||
|
Timer.Structure.POSM.value, # POS[M]
|
||||||
|
Timer.Structure.POSL.value, # POS[L]
|
||||||
|
]
|
||||||
|
bg_warning = [
|
||||||
|
Timer.Structure.ANSIBLEX.value, # Ansiblex Jump Gate
|
||||||
|
Timer.Structure.ATHANOR.value, # Athanor
|
||||||
|
Timer.Structure.AZBEL.value, # Azbel
|
||||||
|
Timer.Structure.MERCDEN.value, # Mercenary Den
|
||||||
|
Timer.Structure.METENOX.value, # Metenox Moon Drill
|
||||||
|
Timer.Structure.ORBITALSKYHOOK.value, # Orbital Skyhook
|
||||||
|
Timer.Structure.PHAROLUX.value, # Pharolux Cyno Beacon
|
||||||
|
Timer.Structure.RAITARU.value, # Raitaru
|
||||||
|
"Station", # Legacy structure, remove in future update
|
||||||
|
Timer.Structure.TATARA.value, # Tatara
|
||||||
|
Timer.Structure.TENEBREX.value, # Tenebrex Cyno Jammer
|
||||||
|
]
|
||||||
|
bg_danger = [
|
||||||
|
Timer.Structure.ASTRAHUS.value, # Astrahus
|
||||||
|
Timer.Structure.FORTIZAR.value, # Fortizar
|
||||||
|
Timer.Structure.IHUB.value, # I-HUB
|
||||||
|
Timer.Structure.KEEPSTAR.value, # Keepstar
|
||||||
|
Timer.Structure.SOTIYO.value, # Sotiyo
|
||||||
|
Timer.Structure.TCU.value, # TCU (Legacy structure, remove in future update)
|
||||||
|
]
|
||||||
|
bg_secondary = [
|
||||||
|
Timer.Structure.MOONPOP.value, # Moon Mining Cycle
|
||||||
|
Timer.Structure.OTHER.value, # Other
|
||||||
|
]
|
||||||
|
|
||||||
|
# Timers
|
||||||
|
for timer in base_query.filter(corp_timer=False):
|
||||||
|
timer.bg_modifier = get_bg_modifier(timer.structure)
|
||||||
|
timers.append(timer)
|
||||||
|
|
||||||
|
# Corp Timers
|
||||||
|
for timer in base_query.filter(corp_timer=True, eve_corp=corp):
|
||||||
|
timer.bg_modifier = get_bg_modifier(timer.structure)
|
||||||
|
corp_timers.append(timer)
|
||||||
|
|
||||||
|
# Future Timers
|
||||||
|
for timer in base_query.filter(corp_timer=False, eve_time__gte=timezone.now()):
|
||||||
|
timer.bg_modifier = get_bg_modifier(timer.structure)
|
||||||
|
future_timers.append(timer)
|
||||||
|
|
||||||
|
# Past Timers
|
||||||
|
for timer in base_query.filter(corp_timer=False, eve_time__lt=timezone.now()):
|
||||||
|
timer.bg_modifier = get_bg_modifier(timer.structure)
|
||||||
|
past_timers.append(timer)
|
||||||
|
|
||||||
render_items = {
|
render_items = {
|
||||||
'timers': base_query.filter(corp_timer=False),
|
"timers": timers,
|
||||||
'corp_timers': base_query.filter(corp_timer=True, eve_corp=corp),
|
"corp_timers": corp_timers,
|
||||||
'future_timers': base_query.filter(corp_timer=False, eve_time__gte=timezone.now()),
|
"future_timers": future_timers,
|
||||||
'past_timers': base_query.filter(corp_timer=False, eve_time__lt=timezone.now()),
|
"past_timers": past_timers,
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(request, self.template_name, context=render_items)
|
return render(request, self.template_name, context=render_items)
|
||||||
@ -52,7 +142,7 @@ class TimerView(BaseTimerView):
|
|||||||
|
|
||||||
class TimerManagementView(BaseTimerView):
|
class TimerManagementView(BaseTimerView):
|
||||||
permission_required = TIMER_MANAGE_PERMISSION
|
permission_required = TIMER_MANAGE_PERMISSION
|
||||||
index_redirect = 'timerboard:view'
|
index_redirect = "timerboard:view"
|
||||||
success_url = reverse_lazy(index_redirect)
|
success_url = reverse_lazy(index_redirect)
|
||||||
model = Timer
|
model = Timer
|
||||||
|
|
||||||
@ -66,12 +156,12 @@ class AddUpdateMixin:
|
|||||||
Inject the request user into the kwargs passed to the form
|
Inject the request user into the kwargs passed to the form
|
||||||
"""
|
"""
|
||||||
kwargs = super().get_form_kwargs()
|
kwargs = super().get_form_kwargs()
|
||||||
kwargs.update({'user': self.request.user})
|
kwargs.update({"user": self.request.user})
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class AddTimerView(TimerManagementView, AddUpdateMixin, CreateView):
|
class AddTimerView(TimerManagementView, AddUpdateMixin, CreateView):
|
||||||
template_name_suffix = '_create_form'
|
template_name_suffix = "_create_form"
|
||||||
form_class = TimerForm
|
form_class = TimerForm
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
@ -82,17 +172,18 @@ class AddTimerView(TimerManagementView, AddUpdateMixin, CreateView):
|
|||||||
)
|
)
|
||||||
messages.success(
|
messages.success(
|
||||||
self.request,
|
self.request,
|
||||||
_('Added new timer in %(system)s at %(time)s.') % {"system": timer.system, "time": timer.eve_time}
|
_("Added new timer in %(system)s at %(time)s.")
|
||||||
|
% {"system": timer.system, "time": timer.eve_time},
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
class EditTimerView(TimerManagementView, AddUpdateMixin, UpdateView):
|
class EditTimerView(TimerManagementView, AddUpdateMixin, UpdateView):
|
||||||
template_name_suffix = '_update_form'
|
template_name_suffix = "_update_form"
|
||||||
form_class = TimerForm
|
form_class = TimerForm
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
messages.success(self.request, _('Saved changes to the timer.'))
|
messages.success(self.request, _("Saved changes to the timer."))
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
@ -107,21 +198,20 @@ def dashboard_timers(request):
|
|||||||
except (EveCorporationInfo.DoesNotExist, AttributeError):
|
except (EveCorporationInfo.DoesNotExist, AttributeError):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
timers = Timer.objects.select_related(
|
timers = Timer.objects.select_related("eve_character").filter(
|
||||||
'eve_character'
|
|
||||||
).filter(
|
|
||||||
(Q(corp_timer=True) & Q(eve_corp=corp)) | Q(corp_timer=False),
|
(Q(corp_timer=True) & Q(eve_corp=corp)) | Q(corp_timer=False),
|
||||||
eve_time__gte=timezone.now()
|
eve_time__gte=timezone.now(),
|
||||||
)[:5]
|
)[:5]
|
||||||
|
|
||||||
if timers.count():
|
if timers.count():
|
||||||
context = {
|
context = {
|
||||||
'timers': timers,
|
"timers": timers,
|
||||||
}
|
}
|
||||||
|
|
||||||
return render_to_string(
|
return render_to_string(
|
||||||
template_name='timerboard/dashboard.timers.html',
|
template_name="timerboard/dashboard.timers.html",
|
||||||
context=context, request=request
|
context=context,
|
||||||
|
request=request,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
@ -27,6 +27,7 @@ Analytics comes preloaded with our Google Analytics token, and the three types o
|
|||||||
Our Daily Stats contain the following:
|
Our Daily Stats contain the following:
|
||||||
|
|
||||||
- A phone-in task to identify a server's existence
|
- A phone-in task to identify a server's existence
|
||||||
|
- A phone-in task to identify if a server is Bare-Metal or Dockerized
|
||||||
- A task to send the Number of User models
|
- A task to send the Number of User models
|
||||||
- A task to send the Number of Token Models
|
- A task to send the Number of Token Models
|
||||||
- A task to send the Number of Installed Apps
|
- A task to send the Number of Installed Apps
|
||||||
|
@ -52,6 +52,7 @@ dependencies = [
|
|||||||
"django-registration<3.4,>=3.3",
|
"django-registration<3.4,>=3.3",
|
||||||
"django-solo",
|
"django-solo",
|
||||||
"django-sortedm2m",
|
"django-sortedm2m",
|
||||||
|
"django-sri",
|
||||||
"dnspython",
|
"dnspython",
|
||||||
"mysqlclient>=2.1",
|
"mysqlclient>=2.1",
|
||||||
"openfire-restapi",
|
"openfire-restapi",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user