diff --git a/allianceauth/analytics/admin.py b/allianceauth/analytics/admin.py index 383bbbe2..497f2d7c 100644 --- a/allianceauth/analytics/admin.py +++ b/allianceauth/analytics/admin.py @@ -1,15 +1,16 @@ from django.contrib import admin from .models import AnalyticsIdentifier, AnalyticsTokens +from solo.admin import SingletonModelAdmin @admin.register(AnalyticsIdentifier) -class AnalyticsIdentifierAdmin(admin.ModelAdmin): +class AnalyticsIdentifierAdmin(SingletonModelAdmin): search_fields = ['identifier', ] - list_display = ('identifier',) + list_display = ['identifier', ] @admin.register(AnalyticsTokens) class AnalyticsTokensAdmin(admin.ModelAdmin): search_fields = ['name', ] - list_display = ('name', 'type',) + list_display = ['name', 'type', ] diff --git a/allianceauth/analytics/migrations/0010_alter_analyticsidentifier_options.py b/allianceauth/analytics/migrations/0010_alter_analyticsidentifier_options.py new file mode 100644 index 00000000..7c1993e9 --- /dev/null +++ b/allianceauth/analytics/migrations/0010_alter_analyticsidentifier_options.py @@ -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'}, + ), + ] diff --git a/allianceauth/analytics/models.py b/allianceauth/analytics/models.py index ddee495a..16ea0221 100644 --- a/allianceauth/analytics/models.py +++ b/allianceauth/analytics/models.py @@ -1,23 +1,19 @@ +from typing import Literal from django.db import models -from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ - +from solo.models import SingletonModel from uuid import uuid4 -class AnalyticsIdentifier(models.Model): +class AnalyticsIdentifier(SingletonModel): - identifier = models.UUIDField( - default=uuid4, - editable=False) + identifier = models.UUIDField(default=uuid4, editable=False) - def save(self, *args, **kwargs): - if not self.pk and AnalyticsIdentifier.objects.exists(): - # Force a single object - raise ValidationError('There is can be only one \ - AnalyticsIdentifier instance') - self.pk = self.id = 1 # If this happens to be deleted and recreated, force it to be 1 - return super().save(*args, **kwargs) + def __str__(self) -> Literal['Analytics Identifier']: + return "Analytics Identifier" + + class Meta: + verbose_name = "Analytics Identifier" class AnalyticsTokens(models.Model): diff --git a/allianceauth/analytics/tasks.py b/allianceauth/analytics/tasks.py index cc9ef160..d0a76c30 100644 --- a/allianceauth/analytics/tasks.py +++ b/allianceauth/analytics/tasks.py @@ -5,6 +5,7 @@ from django.apps import apps from celery import shared_task from .models import AnalyticsTokens, AnalyticsIdentifier from .utils import ( + existence_baremetal_or_docker, install_stat_addons, install_stat_tokens, install_stat_users) @@ -67,8 +68,8 @@ def analytics_event(namespace: str, value=value).apply_async(priority=9) -@shared_task() -def analytics_daily_stats(): +@shared_task +def analytics_daily_stats() -> None: """Celery Task: Do not call directly Gathers a series of daily statistics @@ -77,6 +78,7 @@ def analytics_daily_stats(): users = install_stat_users() tokens = install_stat_tokens() addons = install_stat_addons() + existence_type = existence_baremetal_or_docker() logger.debug("Running Daily Analytics Upload") analytics_event(namespace='allianceauth.analytics', @@ -84,6 +86,11 @@ def analytics_daily_stats(): label='existence', value=1, 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', task='send_install_stats', label='users', @@ -99,7 +106,6 @@ def analytics_daily_stats(): label='addons', value=addons, event_type='Stats') - for appconfig in apps.get_app_configs(): if appconfig.label in [ "django_celery_beat", @@ -135,7 +141,7 @@ def analytics_daily_stats(): event_type='Stats') -@shared_task() +@shared_task def send_ga_tracking_celery_event( measurement_id: str, secret: str, @@ -165,7 +171,7 @@ def send_ga_tracking_celery_event( } payload = { - 'client_id': AnalyticsIdentifier.objects.get(id=1).identifier.hex, + 'client_id': AnalyticsIdentifier.get_solo().identifier.hex, "user_properties": { "allianceauth_version": { "value": __version__ diff --git a/allianceauth/analytics/tests/test_models.py b/allianceauth/analytics/tests/test_models.py index 452c4eaa..979f2720 100644 --- a/allianceauth/analytics/tests/test_models.py +++ b/allianceauth/analytics/tests/test_models.py @@ -1,9 +1,8 @@ from allianceauth.analytics.models import AnalyticsIdentifier -from django.core.exceptions import ValidationError from django.test.testcases import TestCase -from uuid import UUID, uuid4 +from uuid import uuid4 # Identifiers @@ -14,14 +13,4 @@ uuid_2 = "7aa6bd70701f44729af5e3095ff4b55c" class TestAnalyticsIdentifier(TestCase): def test_identifier_random(self): - self.assertNotEqual(AnalyticsIdentifier.objects.get(), 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)) + self.assertNotEqual(AnalyticsIdentifier.get_solo(), uuid4) diff --git a/allianceauth/analytics/utils.py b/allianceauth/analytics/utils.py index e8c57927..fa50084f 100644 --- a/allianceauth/analytics/utils.py +++ b/allianceauth/analytics/utils.py @@ -1,3 +1,4 @@ +import os from django.apps import apps from allianceauth.authentication.models import User from esi.models import Token @@ -34,3 +35,16 @@ def install_stat_addons() -> int: The Number of Installed Apps""" addons = len(list(apps.get_app_configs())) 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" diff --git a/allianceauth/project_template/project_name/settings/base.py b/allianceauth/project_template/project_name/settings/base.py index 19bdbe77..56e7c493 100644 --- a/allianceauth/project_template/project_name/settings/base.py +++ b/allianceauth/project_template/project_name/settings/base.py @@ -44,8 +44,10 @@ INSTALLED_APPS = [ 'allianceauth.theme.materia', "allianceauth.custom_css", 'allianceauth.crontab', + 'sri', ] +SRI_ALGORITHM = "sha512" SECRET_KEY = "wow I'm a really bad default secret key" # Celery configuration diff --git a/allianceauth/templates/bundles/auth-base-css.html b/allianceauth/templates/bundles/auth-base-css.html index 0ee2e7ce..ce7b4373 100644 --- a/allianceauth/templates/bundles/auth-base-css.html +++ b/allianceauth/templates/bundles/auth-base-css.html @@ -1,3 +1,3 @@ -{% load static %} +{% load sri %} - +{% sri_static 'allianceauth/css/auth-base.css' %} diff --git a/allianceauth/templates/bundles/auth-framework-css.html b/allianceauth/templates/bundles/auth-framework-css.html index 9f1c038a..1722377a 100644 --- a/allianceauth/templates/bundles/auth-framework-css.html +++ b/allianceauth/templates/bundles/auth-framework-css.html @@ -1,3 +1,3 @@ -{% load static %} +{% load sri %} - +{% sri_static 'allianceauth/framework/css/auth-framework.css' %} diff --git a/allianceauth/templates/bundles/bootstrap-css.html b/allianceauth/templates/bundles/bootstrap-css.html index bed760ba..88147119 100644 --- a/allianceauth/templates/bundles/bootstrap-css.html +++ b/allianceauth/templates/bundles/bootstrap-css.html @@ -1,4 +1,6 @@ {% load static %} +{% load sri %} + {% if NIGHT_MODE %} {% if debug %} @@ -6,7 +8,7 @@ {% else %} - + {% sri_static 'allianceauth/css/themes/darkly/darkly.min.css' %} {% endif %} {% else %} {% if debug %} @@ -14,7 +16,7 @@ {% else %} - + {% sri_static 'allianceauth/css/themes/flatly/flatly.min.css' %} {% endif %} {% endif %} diff --git a/allianceauth/templates/bundles/checkbox-css.html b/allianceauth/templates/bundles/checkbox-css.html index f400d36c..1f2cc08e 100644 --- a/allianceauth/templates/bundles/checkbox-css.html +++ b/allianceauth/templates/bundles/checkbox-css.html @@ -1,3 +1,3 @@ -{% load static %} +{% load sri %} - +{% sri_static 'allianceauth/css/checkbox.css' %} diff --git a/allianceauth/templates/bundles/evetime-js.html b/allianceauth/templates/bundles/evetime-js.html index 63b712c3..6611516e 100644 --- a/allianceauth/templates/bundles/evetime-js.html +++ b/allianceauth/templates/bundles/evetime-js.html @@ -1,3 +1,3 @@ -{% load static %} +{% load sri %} - +{% sri_static 'allianceauth/js/eve-time.js' %} diff --git a/allianceauth/templates/bundles/filterdropdown-js.html b/allianceauth/templates/bundles/filterdropdown-js.html index 677fa536..41a0e3bd 100644 --- a/allianceauth/templates/bundles/filterdropdown-js.html +++ b/allianceauth/templates/bundles/filterdropdown-js.html @@ -1,3 +1,3 @@ -{% load static %} +{% load sri %} - +{% sri_static 'allianceauth/js/filterDropDown/filterDropDown.min.js' %} diff --git a/allianceauth/templates/bundles/jquery-ui-css.html b/allianceauth/templates/bundles/jquery-ui-css.html index 3bf4d1a3..9177c19e 100644 --- a/allianceauth/templates/bundles/jquery-ui-css.html +++ b/allianceauth/templates/bundles/jquery-ui-css.html @@ -1,5 +1,6 @@ -{% load static %} - - + +{% load sri %} + +{% sri_static 'allianceauth/js/jquery-ui/1.13.2/css/jquery-ui.min.css' %} diff --git a/allianceauth/templates/bundles/moment-js.html b/allianceauth/templates/bundles/moment-js.html index a094b4be..802411b9 100644 --- a/allianceauth/templates/bundles/moment-js.html +++ b/allianceauth/templates/bundles/moment-js.html @@ -1,7 +1,19 @@ +{% load i18n %} + + {% if locale and LANGUAGE_CODE != 'en' %} - + {% get_current_language as LANGUAGE_CODE %} + {% get_language_info for LANGUAGE_CODE as lang %} + + {% if lang.code == 'zh-hans' %} + + + {% else %} + + + {% endif %} {% endif %} diff --git a/allianceauth/templates/bundles/refresh-notification-icon-js.html b/allianceauth/templates/bundles/refresh-notification-icon-js.html index 88f3d16f..69cc53b8 100644 --- a/allianceauth/templates/bundles/refresh-notification-icon-js.html +++ b/allianceauth/templates/bundles/refresh-notification-icon-js.html @@ -1,3 +1,3 @@ -{% load static %} +{% load sri %} - +{% sri_static 'allianceauth/js/refresh-notification-icon.js' %} diff --git a/allianceauth/templates/bundles/refresh-notifications-js.html b/allianceauth/templates/bundles/refresh-notifications-js.html index 27622b3e..50b5e8f4 100644 --- a/allianceauth/templates/bundles/refresh-notifications-js.html +++ b/allianceauth/templates/bundles/refresh-notifications-js.html @@ -1,3 +1,3 @@ -{% load static %} +{% load sri %} - +{% sri_static 'allianceauth/js/refresh_notifications.js' %} diff --git a/allianceauth/templates/bundles/timerboard-js.html b/allianceauth/templates/bundles/timerboard-js.html index 8cf6f353..8bad97d9 100644 --- a/allianceauth/templates/bundles/timerboard-js.html +++ b/allianceauth/templates/bundles/timerboard-js.html @@ -1,3 +1,3 @@ -{% load static %} +{% load sri %} - +{% sri_static 'allianceauth/js/timerboard.js' %} diff --git a/allianceauth/templates/bundles/timers-js.html b/allianceauth/templates/bundles/timers-js.html index b9690202..a570a10d 100644 --- a/allianceauth/templates/bundles/timers-js.html +++ b/allianceauth/templates/bundles/timers-js.html @@ -1,3 +1,3 @@ -{% load static %} +{% load sri %} - +{% sri_static 'allianceauth/js/timers.js' %} diff --git a/allianceauth/timerboard/migrations/0007_alter_timer_structure.py b/allianceauth/timerboard/migrations/0007_alter_timer_structure.py new file mode 100644 index 00000000..26513513 --- /dev/null +++ b/allianceauth/timerboard/migrations/0007_alter_timer_structure.py @@ -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, + ), + ), + ] diff --git a/allianceauth/timerboard/models.py b/allianceauth/timerboard/models.py index d4127c9b..bf6f9b08 100644 --- a/allianceauth/timerboard/models.py +++ b/allianceauth/timerboard/models.py @@ -1,6 +1,6 @@ from django.contrib.auth.models import User 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 EveCorporationInfo @@ -23,7 +23,7 @@ class Timer(models.Model): POCO = "POCO", _("POCO") ORBITALSKYHOOK = "Orbital Skyhook", _("Orbital Skyhook") - IHUB = "I-HUB", _("I-HUB") + IHUB = "I-HUB", _("Sovereignty Hub") TCU = "TCU", _("TCU") # Pending Remval POSS = "POS[S]", _("POS [S]") POSM = "POS[M]", _("POS [M]") @@ -36,9 +36,10 @@ class Timer(models.Model): SOTIYO = "Sotiyo", _("Sotiyo") ATHANOR = "Athanor", _("Athanor") TATARA = "Tatara", _("Tatara") - PHAROLUX = "Pharolux Cyno Beacon", _("Pharolux Cyno Beacon") - TENEBREX = "Tenebrex Cyno Jammer", _("Tenebrex Cyno Jammer") + PHAROLUX = "Pharolux Cyno Beacon", _("Cyno Beacon") + TENEBREX = "Tenebrex Cyno Jammer", _("Cyno Jammer") ANSIBLEX = "Ansiblex Jump Gate", _("Ansiblex Jump Gate") + MERCDEN = "Mercenary Den", _("Mercenary Den") MOONPOP = "Moon Mining Cycle", _("Moon Mining Cycle") METENOX = "Metenox Moon Drill", _("Metenox Moon Drill") OTHER = "Other", _("Other") diff --git a/allianceauth/timerboard/templates/timerboard/timertable.html b/allianceauth/timerboard/templates/timerboard/timertable.html index c1d5c818..014b01e8 100644 --- a/allianceauth/timerboard/templates/timerboard/timertable.html +++ b/allianceauth/timerboard/templates/timerboard/timertable.html @@ -19,7 +19,6 @@ {% for timer in timers %} - {{ timer.details }} @@ -30,13 +29,21 @@ + {% comment %} Objective: Hostile (BG: Danger) {% endcomment %} {% if timer.objective == "Hostile" %} -
{% translate "Hostile" %}
+
+ + {% comment %} Objective: Friendly (BG: Primare) {% endcomment %} {% elif timer.objective == "Friendly" %} -
{% translate "Friendly" %}
+
+ + {% comment %} Objective: Neutral (BG: Secondary) {% endcomment %} {% elif timer.objective == "Neutral" %} -
{% translate "Neutral" %}
+
{% endif %} + + {{ timer.get_objective_display }} +
@@ -44,49 +51,9 @@ - {% if timer.structure == "POCO" %} -
{% translate "POCO" %}
- {% elif timer.structure == "Orbital Skyhook" %} -
{% translate "Orbital Skyhook" %}
- {% elif timer.structure == "I-HUB" %} -
{% translate "I-HUB" %}
- {% elif timer.structure == "TCU" %} {% comment %} Pending Removal {% endcomment %} -
{% translate "TCU" %}
- {% elif timer.structure == "POS[S]" %} -
{% translate "POS [S]" %}
- {% elif timer.structure == "POS[M]" %} -
{% translate "POS [M]" %}
- {% elif timer.structure == "POS[L]" %} -
{% translate "POS [L]" %}
- {% elif timer.structure == "Citadel[M]" or timer.structure == "Astrahus" %} -
{% translate "Astrahus" %}
- {% elif timer.structure == "Citadel[L]" or timer.structure == "Fortizar" %} -
{% translate "Fortizar" %}
- {% elif timer.structure == "Citadel[XL]" or timer.structure == "Keepstar" %} -
{% translate "Keepstar" %}
- {% elif timer.structure == "Engineering Complex[M]" or timer.structure == "Raitaru" %} -
{% translate "Raitaru" %}
- {% elif timer.structure == "Engineering Complex[L]" or timer.structure == "Azbel" %} -
{% translate "Azbel" %}
- {% elif timer.structure == "Engineering Complex[XL]" or timer.structure == "Sotiyo" %} -
{% translate "Sotiyo" %}
- {% elif timer.structure == "Refinery[M]" or timer.structure == "Athanor" %} -
{% translate "Athanor" %}
- {% elif timer.structure == "Refinery[L]" or timer.structure == "Tatara" %} -
{% translate "Tatara" %}
- {% elif timer.structure == "Cyno Beacon" or timer.structure == "Pharolux Cyno Beacon" %} -
{% translate "Cyno Beacon" %}
- {% elif timer.structure == "Cyno Jammer" or timer.structure == "Tenebrex Cyno Jammer" %} -
{% translate "Cyno Jammer" %}
- {% elif timer.structure == "Jump Gate" or timer.structure == "Ansiblex Jump Gate" %} -
{% translate "Ansiblex Jump Gate" %}
- {% elif timer.structure == "Moon Mining Cycle" %} -
{% translate "Moon Mining Cycle" %}
- {% elif timer.structure == "Metenox Moon Drill" %} -
{% translate "Metenox Moon Drill" %}
- {% elif timer.structure == "Other" %} -
{% translate "Other" %}
- {% endif %} +
+ {{ timer.get_structure_display }} +
{{ timer.eve_time | date:"Y-m-d H:i" }} diff --git a/allianceauth/timerboard/views.py b/allianceauth/timerboard/views.py index 93c877c8..0c7c76d1 100644 --- a/allianceauth/timerboard/views.py +++ b/allianceauth/timerboard/views.py @@ -1,12 +1,12 @@ -import datetime import logging from django.contrib import messages from django.contrib.auth.mixins import ( - LoginRequiredMixin, PermissionRequiredMixin, + LoginRequiredMixin, + PermissionRequiredMixin, ) 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.urls import reverse_lazy from django.utils import timezone @@ -20,8 +20,8 @@ from allianceauth.timerboard.models import Timer logger = logging.getLogger(__name__) -TIMER_VIEW_PERMISSION = 'auth.timer_view' -TIMER_MANAGE_PERMISSION = 'auth.timer_management' +TIMER_VIEW_PERMISSION = "auth.timer_view" +TIMER_MANAGE_PERMISSION = "auth.timer_management" class BaseTimerView(LoginRequiredMixin, PermissionRequiredMixin, View): @@ -29,22 +29,112 @@ class BaseTimerView(LoginRequiredMixin, PermissionRequiredMixin, View): class TimerView(BaseTimerView): - template_name = 'timerboard/view.html' + template_name = "timerboard/view.html" permission_required = TIMER_VIEW_PERMISSION 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}") char = request.user.profile.main_character + if char: corp = char.corporation else: 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 = { - 'timers': base_query.filter(corp_timer=False), - 'corp_timers': base_query.filter(corp_timer=True, eve_corp=corp), - 'future_timers': base_query.filter(corp_timer=False, eve_time__gte=timezone.now()), - 'past_timers': base_query.filter(corp_timer=False, eve_time__lt=timezone.now()), + "timers": timers, + "corp_timers": corp_timers, + "future_timers": future_timers, + "past_timers": past_timers, } return render(request, self.template_name, context=render_items) @@ -52,7 +142,7 @@ class TimerView(BaseTimerView): class TimerManagementView(BaseTimerView): permission_required = TIMER_MANAGE_PERMISSION - index_redirect = 'timerboard:view' + index_redirect = "timerboard:view" success_url = reverse_lazy(index_redirect) model = Timer @@ -66,12 +156,12 @@ class AddUpdateMixin: Inject the request user into the kwargs passed to the form """ kwargs = super().get_form_kwargs() - kwargs.update({'user': self.request.user}) + kwargs.update({"user": self.request.user}) return kwargs class AddTimerView(TimerManagementView, AddUpdateMixin, CreateView): - template_name_suffix = '_create_form' + template_name_suffix = "_create_form" form_class = TimerForm def form_valid(self, form): @@ -82,17 +172,18 @@ class AddTimerView(TimerManagementView, AddUpdateMixin, CreateView): ) messages.success( 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 class EditTimerView(TimerManagementView, AddUpdateMixin, UpdateView): - template_name_suffix = '_update_form' + template_name_suffix = "_update_form" form_class = TimerForm 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) @@ -107,21 +198,20 @@ def dashboard_timers(request): except (EveCorporationInfo.DoesNotExist, AttributeError): return "" - timers = Timer.objects.select_related( - 'eve_character' - ).filter( + timers = Timer.objects.select_related("eve_character").filter( (Q(corp_timer=True) & Q(eve_corp=corp)) | Q(corp_timer=False), - eve_time__gte=timezone.now() + eve_time__gte=timezone.now(), )[:5] if timers.count(): context = { - 'timers': timers, + "timers": timers, } return render_to_string( - template_name='timerboard/dashboard.timers.html', - context=context, request=request + template_name="timerboard/dashboard.timers.html", + context=context, + request=request, ) else: return "" diff --git a/docs/features/core/analytics.md b/docs/features/core/analytics.md index d610edb6..d04c47a3 100644 --- a/docs/features/core/analytics.md +++ b/docs/features/core/analytics.md @@ -27,6 +27,7 @@ Analytics comes preloaded with our Google Analytics token, and the three types o Our Daily Stats contain the following: - 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 Token Models - A task to send the Number of Installed Apps diff --git a/pyproject.toml b/pyproject.toml index 35edbe64..3ed04b9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,7 @@ dependencies = [ "django-registration<3.4,>=3.3", "django-solo", "django-sortedm2m", + "django-sri", "dnspython", "mysqlclient>=2.1", "openfire-restapi",