From dbe0d3540019f8a3a48d6dc35fced86699eb7fed Mon Sep 17 00:00:00 2001 From: FreneticScribbler Date: Sat, 29 Aug 2020 21:52:09 +0100 Subject: [PATCH] Event checklist crew works Mostly - its not happy with timezones --- RIGS/forms.py | 42 ++++++++-- RIGS/migrations/0047_auto_20200829_2105.py | 31 ++++++++ RIGS/models.py | 18 ++++- RIGS/templates/event_checklist_detail.html | 10 +++ RIGS/templates/event_checklist_form.html | 79 ++++++++++++------- templates/index.html | 12 +-- .../templates/partials/version_changes.html | 16 ++-- .../version_changes_change.html | 0 versioning/versioning.py | 45 ++++++----- 9 files changed, 177 insertions(+), 76 deletions(-) create mode 100644 RIGS/migrations/0047_auto_20200829_2105.py rename versioning/templates/{ => partials}/version_changes_change.html (100%) diff --git a/RIGS/forms.py b/RIGS/forms.py index 41a4840b..8913e64e 100644 --- a/RIGS/forms.py +++ b/RIGS/forms.py @@ -10,6 +10,7 @@ from django.contrib.auth.forms import AuthenticationForm from captcha.fields import ReCaptchaField from reversion import revisions as reversion import simplejson +from datetime import datetime from RIGS import models @@ -172,17 +173,17 @@ class EventRiskAssessmentForm(forms.ModelForm): class EventChecklistForm(forms.ModelForm): + # Parsed from incoming form data by clean, then saved into models when the form is saved items = {} + # There's probably a thousand better ways to do this, but this one is mine def clean(self): vehicles = {key: val for key, val in self.data.items() if key.startswith('vehicle')} - drivers = {key: val for key, val in self.data.items() - if key.startswith('driver')} for key in vehicles: pk = int(key.split('_')[1]) driver_key = 'driver_' + str(pk) - if(drivers[driver_key] == ''): + if(self.data[driver_key] == ''): raise forms.ValidationError('Add a driver to vehicle ' + str(pk), code='vehicle_mismatch') else: try: @@ -191,10 +192,36 @@ class EventChecklistForm(forms.ModelForm): item = models.EventChecklistVehicle() item.vehicle = vehicles['vehicle_' + str(pk)] - item.driver = models.Profile.objects.get(pk=drivers['driver_' + str(pk)]) + item.driver = models.Profile.objects.get(pk=self.data[driver_key]) + item.full_clean('checklist') # item does not have a database pk yet as it isn't saved - self.items[pk] = item + self.items['v' + str(pk)] = item + + crewmembers = {key: val for key, val in self.data.items() + if key.startswith('crewmember')} + other_fields = ['start','role','end'] + for key in crewmembers: + pk = int(key.split('_')[1]) + + for field in other_fields: + value = self.data['{}_{}'.format(field,pk)] + if value == '': + raise forms.ValidationError('Add a {} to crewmember {}'.format(field, pk), code='{}_mismatch'.format(field)) + + try: + item = models.EventChecklistCrew.objects.get(pk=pk) + except models.EventChecklistCrew.DoesNotExist: + item = models.EventChecklistCrew() + + item.crewmember = models.Profile.objects.get(pk=self.data['crewmember_' + str(pk)]) + item.start = self.data['start_' + str(pk)] + item.role = self.data['role_' + str(pk)] + item.end = self.data['end_' + str(pk)] + item.full_clean('checklist') + + # item does not have a database pk yet as it isn't saved + self.items['c' + str(pk)] = item return super(EventChecklistForm, self).clean() @@ -203,15 +230,18 @@ class EventChecklistForm(forms.ModelForm): if (commit): # Remove all existing, to be recreated from the form checklist.vehicles.all().delete() - checklist.save() + checklist.crew.all().delete() for key in self.items: item = self.items[key] reversion.add_to_revision(item) # finish and save new database items item.checklist = checklist + item.full_clean() item.save() + checklist.save() + self.items.clear() return checklist diff --git a/RIGS/migrations/0047_auto_20200829_2105.py b/RIGS/migrations/0047_auto_20200829_2105.py new file mode 100644 index 00000000..6b5148cb --- /dev/null +++ b/RIGS/migrations/0047_auto_20200829_2105.py @@ -0,0 +1,31 @@ +# Generated by Django 3.1 on 2020-08-29 20:05 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('RIGS', '0046_auto_20200828_1246'), + ] + + operations = [ + migrations.AlterField( + model_name='eventchecklistvehicle', + name='driver', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='vehicles', to=settings.AUTH_USER_MODEL), + ), + migrations.CreateModel( + name='EventChecklistCrew', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('role', models.CharField(max_length=255, null=True)), + ('start', models.DateTimeField(blank=True, null=True)), + ('end', models.DateTimeField(blank=True, null=True)), + ('checklist', models.ForeignKey(blank=True, on_delete=django.db.models.deletion.CASCADE, related_name='crew', to='RIGS.eventchecklist')), + ('crewmember', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='crewed', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/RIGS/models.py b/RIGS/models.py index 7f896e8d..a583153c 100644 --- a/RIGS/models.py +++ b/RIGS/models.py @@ -635,7 +635,7 @@ class RiskAssessment(models.Model, RevisionMixin): return "%i - %s" % (self.pk, self.event) -@reversion.register(follow=['vehicles', ]) +@reversion.register(follow=['vehicles', 'crew']) class EventChecklist(models.Model, RevisionMixin): event = models.OneToOneField('Event', on_delete=models.CASCADE) @@ -680,9 +680,23 @@ class EventChecklist(models.Model, RevisionMixin): class EventChecklistVehicle(models.Model): checklist = models.ForeignKey('EventChecklist', related_name='vehicles', blank=True, on_delete=models.CASCADE) vehicle = models.CharField(max_length=255) - driver = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='drivers', on_delete=models.CASCADE) + driver = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='vehicles', on_delete=models.CASCADE) reversion_hide = True def __str__(self): return "{} driven by {}".format(self.vehicle, str(self.driver)) + + +@reversion.register +class EventChecklistCrew(models.Model): + checklist = models.ForeignKey('EventChecklist', related_name='crew', blank=True, on_delete=models.CASCADE) + crewmember = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='crewed', on_delete=models.CASCADE) + role = models.CharField(max_length=255) + start = models.DateTimeField() + end = models.DateTimeField() + + reversion_hide = True + + def __str__(self): + return "{} ({})".format(str(self.crewmember), self.role) diff --git a/RIGS/templates/event_checklist_detail.html b/RIGS/templates/event_checklist_detail.html index 8f708878..4f3d3d8c 100644 --- a/RIGS/templates/event_checklist_detail.html +++ b/RIGS/templates/event_checklist_detail.html @@ -61,6 +61,16 @@ +
+
Crew Record
+
+
    + {% for i in object.crew.all %} +
  • {{i}}
  • + {% endfor %} +
+
+
Power
diff --git a/RIGS/templates/event_checklist_form.html b/RIGS/templates/event_checklist_form.html index f7fc254b..e1b882e6 100644 --- a/RIGS/templates/event_checklist_form.html +++ b/RIGS/templates/event_checklist_form.html @@ -35,9 +35,11 @@ {% if object.medium_event %} $('#small-event').slideUp(); $('#medium-event').slideDown(); + $('#size-selector button[data-event-size=1]').addClass('active'); {% else %} $('#small-event').slideDown(); $('#medium-event').slideUp(); + $('#size-selector button[data-event-size=0]').addClass('active'); {% endif%} {% endif %} $('#size-selector button').on('click', function () { @@ -53,24 +55,29 @@ $('#medium-event').slideUp(); } }); - $('#vehicle-add').on('click', function (event) { + $('button[data-action=add]').on('click', function (event) { event.preventDefault(); - var newID = Number($('#vehiclest').attr('data-pk')); - $('#vehicles_new').clone().attr('style', "").attr('id', 'vehicles_' + newID).appendTo('#vehiclest'); - $('#vehicles_' + newID).find('select,input').attr('name', function(){ - return this.name.split('_')[0] + '_' + newID; - //Disabled prevents the hidden row being sent to the form - }).removeAttr('disabled'); - $('#vehicles_' + newID).find('button[data-action=delete]').attr('data-id', newID); - $('#vehicles_' + newID).find('select').addClass('selectpicker'); - $('#vehicles_' + newID).find('.selectpicker').selectpicker('refresh'); + var target = $($(this).attr('data-target')); + var newID = Number(target.attr('data-pk')); + var newRow = $($(this).attr('data-clone')) + .clone().attr('style', "") + .attr('id', function(i, val){ + return val.split("_")[0] + '_' + newID; + }) + .appendTo(target); + newRow.find('select,input').attr('name', function(i, val){ + return val.split("_")[0] + '_' + newID; + })//Disabled is to prevent the hidden row being sent to the form + .removeAttr('disabled'); + newRow.find('button[data-action=delete]').attr('data-id', newID); + newRow.find('select').addClass('selectpicker'); + newRow.find('.selectpicker').selectpicker('refresh'); $(".selectpicker").each(function(){initPicker($(this))}); - $('#vehiclest').attr('data-pk', newID - 1); + $(target).attr('data-pk', newID - 1); }); $('button[data-action=delete]').on('click', function(event) { event.preventDefault(); - console.log($(this).attr('data-id')); - $('#vehicles_' + $(this).attr('data-id')).remove(); + $($(this).attr('data-target') + '_' + $(this).attr('data-id')).remove(); }); }); @@ -124,11 +131,8 @@ - - - - +
@@ -184,23 +188,38 @@ Start Time Role End Time + - - {% for i in '012'|make_list %} - - - - - - - + + + + + + + + + + diff --git a/templates/index.html b/templates/index.html index 9242ca97..c82341db 100644 --- a/templates/index.html +++ b/templates/index.html @@ -9,9 +9,7 @@

Welcome back {{ user.get_full_name }}, there {%if rig_count == 1 %}is one rig coming up{%else%}are {{ rig_count|apnumber }} rigs coming up.{%endif%}

-
-

Rigboard

-
+

Rigboard

Rigboard Calendar @@ -19,9 +17,7 @@ New Event {% endif %}
-
-

Asset Database

-
+

Asset Database

Asset List {% if perms.assets.add_asset %} @@ -32,9 +28,7 @@ New Supplier {% endif %}
-
-

Quick Links

-
+

Quick Links

TEC Forum TEC Wiki diff --git a/versioning/templates/partials/version_changes.html b/versioning/templates/partials/version_changes.html index a3a5a081..674e8e02 100644 --- a/versioning/templates/partials/version_changes.html +++ b/versioning/templates/partials/version_changes.html @@ -1,18 +1,18 @@ {% if version.changes.anything_changed or version.changes.old == None %} {% for change in version.changes.field_changes %} - {{ change.field.verbose_name }} + {{ change.field.verbose_name }} {% endfor %} - {% for itemChange in version.changes.item_changes %} - +

{{ change.field.verbose_name|title }}:

+
{% include 'partials/version_changes_change.html' with change=itemchange %}
{% endfor %} - {% endspaceless %}'>item '{% if itemChange.new %}{{ itemChange.new.name }}{% else %}{{ itemChange.old.name }}{% endif %}'
+ {% endspaceless %}'>{{ itemchange.name }} {% endfor %} {% else %} nothing useful diff --git a/versioning/templates/version_changes_change.html b/versioning/templates/partials/version_changes_change.html similarity index 100% rename from versioning/templates/version_changes_change.html rename to versioning/templates/partials/version_changes_change.html diff --git a/versioning/versioning.py b/versioning/versioning.py index 2a4367fb..aeacb594 100644 --- a/versioning/versioning.py +++ b/versioning/versioning.py @@ -118,30 +118,34 @@ class ModelComparison(object): @cached_property def item_changes(self): # Recieves two event version objects and compares their items, returns an array of ItemCompare objects - item_type = ContentType.objects.get_for_model(models.EventItem) - item_dict = {} - if hasattr(self.version, 'parent'): - old_item_versions = self.version.parent.revision.version_set.filter(content_type=item_type) - new_item_versions = self.version.revision.version_set.filter(content_type=item_type) + item_type = ContentType.objects.get_for_model(self.version.object) + old_item_versions = self.version.parent.revision.version_set.exclude(content_type=item_type) + new_item_versions = self.version.revision.version_set.exclude(content_type=item_type) - comparisonParams = {'excluded_keys': ['id', 'event', 'order']} + comparisonParams = {'excluded_keys': ['id', 'event', 'order']} - # Build some dicts of what we have - # build a list of items, key is the item_pk - for version in old_item_versions: # put all the old versions in a list - if version.field_dict["event_id"] == int(self.new.pk): - compare = ModelComparison(old=version._object_version.object, **comparisonParams) - item_dict[version.object_id] = compare + # Build some dicts of what we have + item_dict = {} # build a list of items, key is the item_pk + # FIXME Removing the if checks makes things REALLY slow... + for version in old_item_versions: # put all the old versions in a list + #if version.field_dict["event_id"] == int(self.new.pk): + compare = ModelComparison(old=version._object_version.object, **comparisonParams) + item_dict[version.object_id] = compare - for version in new_item_versions: # go through the new versions - if version.field_dict["event_id"] == int(self.new.pk): - try: - compare = item_dict[version.object_id] # see if there's a matching old version - compare.new = version._object_version.object # then add the new version to the dictionary - except KeyError: # there's no matching old version, so add this item to the dictionary by itself - compare = ModelComparison(new=version._object_version.object, **comparisonParams) + for version in new_item_versions: # go through the new versions + #if version.field_dict["event_id"] == int(self.new.pk): + try: + compare = item_dict[version.object_id] # see if there's a matching old version + compare.new = version._object_version.object # then add the new version to the dictionary + except KeyError: # there's no matching old version, so add this item to the dictionary by itself + compare = ModelComparison(new=version._object_version.object, **comparisonParams) - item_dict[version.object_id] = compare # update the dictionary with the changes + if compare.new: + compare.name = str(compare.new) + else: + compare.name = str(compare.old) + + item_dict[version.object_id] = compare # update the dictionary with the changes changes = [] for (_, compare) in list(item_dict.items()): @@ -160,7 +164,6 @@ class ModelComparison(object): class RIGSVersionManager(VersionQuerySet): - # TODO Rework this so its possible to define from the other apps def get_for_multiple_models(self, model_array): content_types = [] for model in model_array: