From 2c59cc4cc3dd1c3ae5a0ca3b0e9f8f9d89d2da8d Mon Sep 17 00:00:00 2001 From: Peter Pfeufer Date: Sat, 30 Oct 2021 04:34:49 +0000 Subject: [PATCH] Add types and description to optimers --- allianceauth/optimer/admin.py | 3 +- allianceauth/optimer/form.py | 25 ++++++++- allianceauth/optimer/form_widgets.py | 45 ++++++++++++++++ .../0005_add_type_and_description.py | 50 ++++++++++++++++++ allianceauth/optimer/models.py | 21 +++++++- .../templates/optimer/fleetoptable.html | 51 +++++++++++-------- .../optimer/templates/optimer/management.html | 4 +- allianceauth/optimer/views.py | 43 +++++++++++++--- 8 files changed, 211 insertions(+), 31 deletions(-) create mode 100644 allianceauth/optimer/form_widgets.py create mode 100644 allianceauth/optimer/migrations/0005_add_type_and_description.py diff --git a/allianceauth/optimer/admin.py b/allianceauth/optimer/admin.py index 72b8767a..c097170c 100644 --- a/allianceauth/optimer/admin.py +++ b/allianceauth/optimer/admin.py @@ -1,5 +1,6 @@ from django.contrib import admin -from allianceauth.optimer.models import OpTimer +from allianceauth.optimer.models import OpTimer, OpTimerType +admin.site.register(OpTimerType) admin.site.register(OpTimer) diff --git a/allianceauth/optimer/form.py b/allianceauth/optimer/form.py index 620616d3..8fb97c91 100644 --- a/allianceauth/optimer/form.py +++ b/allianceauth/optimer/form.py @@ -1,11 +1,34 @@ from django import forms from django.utils.translation import ugettext_lazy as _ +from allianceauth.optimer.form_widgets import DataListWidget + class OpForm(forms.Form): + """ + Create/Edit Fleet Operation Form + """ + doctrine = forms.CharField(max_length=254, required=True, label=_('Doctrine')) system = forms.CharField(max_length=254, required=True, label=_("System")) start = forms.DateTimeField(required=True, label=_("Start Time")) - duration = forms.CharField(max_length=254, required=True, label=_("Duration")) operation_name = forms.CharField(max_length=254, required=True, label=_("Operation Name")) + type = forms.CharField(required=False, label=_("Operation Type")) fc = forms.CharField(max_length=254, required=True, label=_("Fleet Commander")) + duration = forms.CharField(max_length=254, required=True, label=_("Duration")) + description = forms.CharField( + widget=forms.Textarea(attrs={"rows": 10, "cols": 20, "input_type": "textarea"}), + required=False, + label=_("Additional Info"), + help_text=_("(Optional) Describe the operation with a couple of short words."), + ) + + def __init__(self, *args, **kwargs): + _data_list = kwargs.pop('data_list', None) + + super().__init__(*args, **kwargs) + + # Add the DataListWidget to our type field + self.fields['type'].widget = DataListWidget( + data_list=_data_list, name='data-list' + ) diff --git a/allianceauth/optimer/form_widgets.py b/allianceauth/optimer/form_widgets.py new file mode 100644 index 00000000..3cd313b8 --- /dev/null +++ b/allianceauth/optimer/form_widgets.py @@ -0,0 +1,45 @@ +""" +Form Widgets +""" + +from django import forms + + +class DataListWidget(forms.TextInput): + """ + DataListWidget + + Draws an HTML5 datalist form field + """ + + def __init__(self, data_list, name, *args, **kwargs): + super().__init__(*args, **kwargs) + + self._name = name + self._list = data_list + self.attrs.update({"list": "list__%s" % self._name}) + + def render(self, name, value, attrs=None, renderer=None): + """ + Render the DataList + :param name: + :type name: + :param value: + :type value: + :param attrs: + :type attrs: + :param renderer: + :type renderer: + :return: + :rtype: + """ + + text_html = super().render(name, value, attrs=attrs) + data_list = '' % self._name + + for item in self._list: + data_list += '" + + return text_html + data_list diff --git a/allianceauth/optimer/migrations/0005_add_type_and_description.py b/allianceauth/optimer/migrations/0005_add_type_and_description.py new file mode 100644 index 00000000..c8fee43d --- /dev/null +++ b/allianceauth/optimer/migrations/0005_add_type_and_description.py @@ -0,0 +1,50 @@ +# Generated by Django 3.2.8 on 2021-10-26 16:20 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ("optimer", "0004_on_delete"), + ] + + operations = [ + migrations.CreateModel( + name="OpTimerType", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("type", models.CharField(default="", max_length=254)), + ], + options={ + "ordering": ["type"], + "default_permissions": (), + }, + ), + migrations.AlterModelOptions( + name="optimer", + options={"default_permissions": (), "ordering": ["start"]}, + ), + migrations.AddField( + model_name="optimer", + name="description", + field=models.TextField(blank=True, default=""), + ), + migrations.AddField( + model_name="optimer", + name="type", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="optimer.optimertype", + ), + ), + ] diff --git a/allianceauth/optimer/models.py b/allianceauth/optimer/models.py index 08a17e3e..0479dca6 100644 --- a/allianceauth/optimer/models.py +++ b/allianceauth/optimer/models.py @@ -6,9 +6,25 @@ from django.utils import timezone from allianceauth.eveonline.models import EveCharacter +class OpTimerType(models.Model): + """ + Optimer Type + """ + + type = models.CharField(max_length=254, default="") + + def __str__(self): + return self.type + + class Meta: + ordering = ['type'] + default_permissions = () + + class OpTimer(models.Model): class Meta: ordering = ['start'] + default_permissions = () doctrine = models.CharField(max_length=254, default="") system = models.CharField(max_length=254, default="") @@ -17,7 +33,10 @@ class OpTimer(models.Model): operation_name = models.CharField(max_length=254, default="") fc = models.CharField(max_length=254, default="") post_time = models.DateTimeField(default=timezone.now) - eve_character = models.ForeignKey(EveCharacter, null=True, on_delete=models.SET_NULL) + eve_character = models.ForeignKey(EveCharacter, null=True, + on_delete=models.SET_NULL) + description = models.TextField(blank=True, default="") + type = models.ForeignKey(OpTimerType, null=True, on_delete=models.SET_NULL) def __str__(self): return self.operation_name diff --git a/allianceauth/optimer/templates/optimer/fleetoptable.html b/allianceauth/optimer/templates/optimer/fleetoptable.html index f95099dc..cb5d89e7 100644 --- a/allianceauth/optimer/templates/optimer/fleetoptable.html +++ b/allianceauth/optimer/templates/optimer/fleetoptable.html @@ -6,37 +6,48 @@ - - - - - - - + + + + + + + + {% if perms.auth.optimer_management %} - - +{# #} + {% endif %} {% for ops in timers %} - - - + + + - - - - + + + + {% if perms.auth.optimer_management %} - - #} + {% endif %} diff --git a/allianceauth/optimer/templates/optimer/management.html b/allianceauth/optimer/templates/optimer/management.html index d93b2588..1cb85f0e 100644 --- a/allianceauth/optimer/templates/optimer/management.html +++ b/allianceauth/optimer/templates/optimer/management.html @@ -24,14 +24,14 @@
-

{% translate "Next Timers" %}

+

{% translate "Next Fleet Operations" %}

{% if future_timers %} {% include "optimer/fleetoptable.html" with timers=future_timers %} {% else %}
{% translate "No upcoming timers." %}
{% endif %} -

{% translate "Past Timers" %}

+

{% translate "Past Fleet Operations" %}

{% if past_timers %} {% include "optimer/fleetoptable.html" with timers=past_timers %} {% else %} diff --git a/allianceauth/optimer/views.py b/allianceauth/optimer/views.py index 787c2e19..ae492d03 100644 --- a/allianceauth/optimer/views.py +++ b/allianceauth/optimer/views.py @@ -9,7 +9,7 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from .form import OpForm -from .models import OpTimer +from .models import OpTimer, OpTimerType logger = logging.getLogger(__name__) @@ -18,7 +18,7 @@ logger = logging.getLogger(__name__) @permission_required('auth.optimer_view') def optimer_view(request): logger.debug("optimer_view called by user %s" % request.user) - base_query = OpTimer.objects.select_related('eve_character') + base_query = OpTimer.objects.select_related('eve_character', 'type') render_items = {'optimer': base_query.all(), 'future_timers': base_query.filter( start__gte=timezone.now()), @@ -33,9 +33,21 @@ def optimer_view(request): def add_optimer_view(request): logger.debug("add_optimer_view called by user %s" % request.user) if request.method == 'POST': - form = OpForm(request.POST) + form = OpForm(request.POST, data_list=OpTimerType.objects.all()) logger.debug("Request type POST contains form valid: %s" % form.is_valid()) if form.is_valid(): + optimer_type = None + + if form.cleaned_data['type'] != '': + try: + optimer_type = OpTimerType.objects.get( + type__iexact=form.cleaned_data['type'] + ) + except OpTimerType.DoesNotExist: + optimer_type = OpTimerType.objects.create( + type=form.cleaned_data['type'] + ) + # Get Current Time post_time = timezone.now() # Get character @@ -50,13 +62,15 @@ def add_optimer_view(request): op.fc = form.cleaned_data['fc'] op.create_time = post_time op.eve_character = character + op.type = optimer_type + op.description = form.cleaned_data['description'] op.save() logger.info(f"User {request.user} created op timer with name {op.operation_name}") messages.success(request, _('Created operation timer for %(opname)s.') % {"opname": op.operation_name}) return redirect("optimer:view") else: logger.debug("Returning new opForm") - form = OpForm() + form = OpForm(data_list=OpTimerType.objects.all()) render_items = {'form': form} @@ -80,10 +94,23 @@ def edit_optimer(request, optimer_id): logger.debug(f"edit_optimer called by user {request.user} for optimer id {optimer_id}") op = get_object_or_404(OpTimer, id=optimer_id) if request.method == 'POST': - form = OpForm(request.POST) + form = OpForm(request.POST, data_list=OpTimerType.objects.all()) logger.debug("Received POST request containing update optimer form, is valid: %s" % form.is_valid()) if form.is_valid(): character = request.user.profile.main_character + + optimer_type = None + + if form.cleaned_data['type'] != '': + try: + optimer_type = OpTimerType.objects.get( + type__iexact=form.cleaned_data['type'] + ) + except OpTimerType.DoesNotExist: + optimer_type = OpTimerType.objects.create( + type=form.cleaned_data['type'] + ) + op.doctrine = form.cleaned_data['doctrine'] op.system = form.cleaned_data['system'] op.start = form.cleaned_data['start'] @@ -91,6 +118,8 @@ def edit_optimer(request, optimer_id): op.operation_name = form.cleaned_data['operation_name'] op.fc = form.cleaned_data['fc'] op.eve_character = character + op.type = optimer_type + op.description = form.cleaned_data['description'] logger.info(f"User {request.user} updating optimer id {optimer_id} ") op.save() messages.success(request, _('Saved changes to operation timer for %(opname)s.') % {"opname": op.operation_name}) @@ -103,6 +132,8 @@ def edit_optimer(request, optimer_id): 'duration': op.duration, 'operation_name': op.operation_name, 'fc': op.fc, + 'description': op.description, + 'type': op.type } - form = OpForm(initial=data) + form = OpForm(initial=data, data_list=OpTimerType.objects.all()) return render(request, 'optimer/update.html', context={'form': form})
{% translate "Operation Name" %}{% translate "Doctrine" %}{% translate "Form Up System" %}{% translate "Start Time" %}{% translate "Local Time" %}{% translate "Duration" %}{% translate "FC" %}{% translate "Operation Name" %}{% translate "Description" %}{% translate "Doctrine" %}{% translate "Form Up System" %}{% translate "Start Time" %}{% translate "Local Time" %}{% translate "Duration" %}{% translate "FC" %}{% translate "Creator" %}{% translate "Action" %}{% translate "Creator" %}{% translate "Action" %}
{{ ops.operation_name }}{{ ops.doctrine }} + + {{ ops.operation_name }} + {% if ops.type %} +
({{ ops.type }}) + {% endif %} +
{{ ops.description }}{{ ops.doctrine }} {{ ops.system }} {{ ops.start | date:"Y-m-d H:i" }}
{{ ops.duration }}{{ ops.fc }}{{ ops.start | date:"Y-m-d H:i" }}
{{ ops.duration }}{{ ops.fc }}{{ ops.eve_character }} +{# {{ ops.eve_character }} - - + + + + + +