mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-02-14 10:39:41 +00:00
Compare commits
20 Commits
676cee164b
...
checkin
| Author | SHA1 | Date | |
|---|---|---|---|
|
b151e1fcf3
|
|||
|
013922bd90
|
|||
|
f72b611e77
|
|||
|
8da90ba670
|
|||
| 0d1beeaead | |||
| 51ff06fadd | |||
| 06137ab180 | |||
| e7dd8f4cf9 | |||
| 2fb8b8c81b | |||
|
dd02df4a17
|
|||
|
8cc40fe9fa
|
|||
|
904ef1f180
|
|||
|
417ec8ff3d
|
|||
|
97dac51a52
|
|||
|
fc8bb2dc4b
|
|||
|
67d2f80815
|
|||
|
724762a1e8
|
|||
|
6ea5dc9698
|
|||
|
|
eb45db8950 | ||
|
15a9a03200
|
4
Pipfile
4
Pipfile
@@ -19,7 +19,7 @@ cssutils = "~=1.0.2"
|
|||||||
dj-database-url = "~=0.5.0"
|
dj-database-url = "~=0.5.0"
|
||||||
dj-static = "~=0.0.6"
|
dj-static = "~=0.0.6"
|
||||||
Django = "~=3.2"
|
Django = "~=3.2"
|
||||||
django-debug-toolbar = "~=3.2"
|
django-debug-toolbar = "~=4.0.0"
|
||||||
django-filter = "~=2.4.0"
|
django-filter = "~=2.4.0"
|
||||||
django-ical = "~=1.7.1"
|
django-ical = "~=1.7.1"
|
||||||
django-recurrence = "~=1.10.3"
|
django-recurrence = "~=1.10.3"
|
||||||
@@ -79,7 +79,7 @@ django-hcaptcha = "*"
|
|||||||
pikepdf = "*"
|
pikepdf = "*"
|
||||||
django-queryable-properties = "*"
|
django-queryable-properties = "*"
|
||||||
django-mass-edit = "*"
|
django-mass-edit = "*"
|
||||||
selenium = "~=3.141.0"
|
selenium = "~=4.9.1"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
pycodestyle = "~=2.9.1"
|
pycodestyle = "~=2.9.1"
|
||||||
|
|||||||
754
Pipfile.lock
generated
754
Pipfile.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -64,7 +64,7 @@ INSTALLED_APPS = (
|
|||||||
'assets',
|
'assets',
|
||||||
'training',
|
'training',
|
||||||
|
|
||||||
'debug_toolbar',
|
# 'debug_toolbar',
|
||||||
'registration',
|
'registration',
|
||||||
'reversion',
|
'reversion',
|
||||||
'widget_tweaks',
|
'widget_tweaks',
|
||||||
@@ -75,7 +75,7 @@ INSTALLED_APPS = (
|
|||||||
MIDDLEWARE = (
|
MIDDLEWARE = (
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
# 'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||||
'reversion.middleware.RevisionMiddleware',
|
'reversion.middleware.RevisionMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class Index(generic.TemplateView): # Displays the current rig count along with
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['rig_count'] = models.Event.objects.rig_count()
|
context['rig_count'] = models.Event.objects.rig_count()
|
||||||
|
context['now'] = models.Event.objects.events_in_bounds(timezone.now(), timezone.now())
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ admin.site.register(models.VatRate, VersionAdmin)
|
|||||||
admin.site.register(models.Event, VersionAdmin)
|
admin.site.register(models.Event, VersionAdmin)
|
||||||
admin.site.register(models.EventItem, VersionAdmin)
|
admin.site.register(models.EventItem, VersionAdmin)
|
||||||
admin.site.register(models.Invoice, VersionAdmin)
|
admin.site.register(models.Invoice, VersionAdmin)
|
||||||
|
admin.site.register(models.EventCheckIn)
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic() # Copied from django-extensions. GenericForeignKey support removed as unnecessary.
|
@transaction.atomic() # Copied from django-extensions. GenericForeignKey support removed as unnecessary.
|
||||||
|
|||||||
@@ -200,85 +200,8 @@ class EventChecklistForm(forms.ModelForm):
|
|||||||
|
|
||||||
related_models = {
|
related_models = {
|
||||||
'venue': models.Venue,
|
'venue': models.Venue,
|
||||||
'power_mic': models.Profile,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Two possible formats
|
|
||||||
def parsedatetime(self, date_string):
|
|
||||||
try:
|
|
||||||
return timezone.make_aware(datetime.strptime(date_string, '%Y-%m-%dT%H:%M:%S'))
|
|
||||||
except ValueError:
|
|
||||||
return timezone.make_aware(datetime.strptime(date_string, '%Y-%m-%dT%H:%M'))
|
|
||||||
|
|
||||||
# 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')}
|
|
||||||
for key in vehicles:
|
|
||||||
pk = int(key.split('_')[1])
|
|
||||||
driver_key = 'driver_' + str(pk)
|
|
||||||
if (self.data[driver_key] == ''):
|
|
||||||
raise forms.ValidationError('Add a driver to vehicle ' + str(pk), code='vehicle_mismatch')
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
item = models.EventChecklistVehicle.objects.get(pk=pk)
|
|
||||||
except models.EventChecklistVehicle.DoesNotExist:
|
|
||||||
item = models.EventChecklistVehicle()
|
|
||||||
|
|
||||||
item.vehicle = vehicles['vehicle_' + 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['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[f'{field}_{pk}']
|
|
||||||
if value == '':
|
|
||||||
raise forms.ValidationError(f'Add a {field} to crewmember {pk}', code=f'{field}_mismatch')
|
|
||||||
|
|
||||||
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.parsedatetime(self.data['start_' + str(pk)])
|
|
||||||
item.role = self.data['role_' + str(pk)]
|
|
||||||
item.end = self.parsedatetime(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()
|
|
||||||
|
|
||||||
def save(self, commit=True):
|
|
||||||
checklist = super(EventChecklistForm, self).save(commit=False)
|
|
||||||
if (commit):
|
|
||||||
# Remove all existing, to be recreated from the form
|
|
||||||
checklist.vehicles.all().delete()
|
|
||||||
checklist.crew.all().delete()
|
|
||||||
checklist.save()
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
self.items.clear()
|
|
||||||
|
|
||||||
return checklist
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.EventChecklist
|
model = models.EventChecklist
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
@@ -303,7 +226,15 @@ class EventCheckInForm(forms.ModelForm):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.fields['time'].initial = timezone.now()
|
self.fields['time'].initial = timezone.now()
|
||||||
|
self.fields['role'].initial = "Crew"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.EventCheckIn
|
model = models.EventCheckIn
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
exclude = ['end_time']
|
||||||
|
|
||||||
|
|
||||||
|
class EditCheckInForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = models.EventCheckIn
|
||||||
|
fields = '__all__'
|
||||||
|
|||||||
41
RIGS/migrations/0047_auto_20230517_0944.py
Normal file
41
RIGS/migrations/0047_auto_20230517_0944.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Generated by Django 3.2.19 on 2023-05-17 08:44
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_old_data(apps, schema_editor):
|
||||||
|
EventChecklist = apps.get_model('RIGS', 'EventChecklist')
|
||||||
|
EventCheckIn = apps.get_model('RIGS', 'EventCheckIn')
|
||||||
|
for ec in EventChecklist.objects.all():
|
||||||
|
for crew in ec.crew.all():
|
||||||
|
vehicle = ec.vehicles.get(driver=crew.crewmember) or None
|
||||||
|
EventCheckIn.objects.create(event=ec.event, person=crew.crewmember, role=crew.role, time=crew.start, end_time=crew.end, vehicle=vehicle.vehicle)
|
||||||
|
|
||||||
|
|
||||||
|
def revert(apps, schema_editor):
|
||||||
|
apps.get_model('RIGS', 'EventCheckIn').objects.all().delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('RIGS', '0046_create_powertests'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventCheckIn',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('time', models.DateTimeField()),
|
||||||
|
('role', models.CharField(blank=True, max_length=50)),
|
||||||
|
('vehicle', models.CharField(blank=True, max_length=100)),
|
||||||
|
('end_time', models.DateTimeField(blank=True, null=True)),
|
||||||
|
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='crew', to='RIGS.event')),
|
||||||
|
('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='checkins', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.RunPython(migrate_old_data, reverse_code=revert),
|
||||||
|
]
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# Generated by Django 3.2.18 on 2023-05-09 19:43
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0047_auto_20230508_1946'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='eventchecklistvehicle',
|
|
||||||
name='checklist',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='eventchecklistvehicle',
|
|
||||||
name='driver',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='eventchecklist',
|
|
||||||
name='power_mic',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='powertestrecord',
|
|
||||||
name='power_mic',
|
|
||||||
field=models.ForeignKey(blank=True, help_text='Who is the Power MIC?', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='checklists', to=settings.AUTH_USER_MODEL, verbose_name='Power MIC'),
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='EventChecklistCrew',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='EventChecklistVehicle',
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,15 +1,24 @@
|
|||||||
# Generated by Django 3.2.16 on 2023-05-08 18:46
|
# Generated by Django 3.2.19 on 2023-05-18 11:56
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0046_create_powertests'),
|
('RIGS', '0047_auto_20230517_0944'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventchecklistvehicle',
|
||||||
|
name='checklist',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventchecklistvehicle',
|
||||||
|
name='driver',
|
||||||
|
),
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='eventchecklist',
|
model_name='eventchecklist',
|
||||||
name='all_rcds_tested',
|
name='all_rcds_tested',
|
||||||
@@ -50,6 +59,10 @@ class Migration(migrations.Migration):
|
|||||||
model_name='eventchecklist',
|
model_name='eventchecklist',
|
||||||
name='pat',
|
name='pat',
|
||||||
),
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventchecklist',
|
||||||
|
name='power_mic',
|
||||||
|
),
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='eventchecklist',
|
model_name='eventchecklist',
|
||||||
name='public_sockets_tested',
|
name='public_sockets_tested',
|
||||||
@@ -114,4 +127,30 @@ class Migration(migrations.Migration):
|
|||||||
model_name='eventchecklist',
|
model_name='eventchecklist',
|
||||||
name='w3_voltage',
|
name='w3_voltage',
|
||||||
),
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='powertestrecord',
|
||||||
|
name='power_mic',
|
||||||
|
field=models.ForeignKey(blank=True, help_text='Who is the Power MIC?', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='checklists', to=settings.AUTH_USER_MODEL, verbose_name='Power MIC'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='eventchecklist',
|
||||||
|
name='reviewed_at',
|
||||||
|
field=models.DateTimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='powertestrecord',
|
||||||
|
name='reviewed_at',
|
||||||
|
field=models.DateTimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='riskassessment',
|
||||||
|
name='reviewed_at',
|
||||||
|
field=models.DateTimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='EventChecklistCrew',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='EventChecklistVehicle',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# Generated by Django 3.2.18 on 2023-05-09 20:12
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0048_auto_20230509_2043'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='EventCheckOut',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('time', models.DateTimeField()),
|
|
||||||
('vehicle', models.CharField(max_length=100)),
|
|
||||||
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='RIGS.event')),
|
|
||||||
('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='checkouts', to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='EventCheckIn',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('time', models.DateTimeField()),
|
|
||||||
('vehicle', models.CharField(max_length=100)),
|
|
||||||
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='crew', to='RIGS.event')),
|
|
||||||
('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='checkins', to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -81,6 +81,10 @@ class Profile(AbstractUser):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def current_event(self):
|
||||||
|
q = EventCheckIn.objects.filter(person=self, end_time=None)
|
||||||
|
return q.latest('time') if q.exists() else None
|
||||||
|
|
||||||
|
|
||||||
class ContactableManager(models.Manager):
|
class ContactableManager(models.Manager):
|
||||||
def search(self, query=None):
|
def search(self, query=None):
|
||||||
@@ -405,7 +409,15 @@ class Event(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def hs_done(self):
|
def hs_done(self):
|
||||||
return self.riskassessment is not None and len(self.checklists.all()) > 0
|
return self.riskassessment is not None and self.has_checklist and self.has_power
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_checklist(self):
|
||||||
|
return self.checklists.exists()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_power(self):
|
||||||
|
return self.power_tests.exists()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_start_time(self):
|
def has_start_time(self):
|
||||||
@@ -478,6 +490,15 @@ class Event(models.Model, RevisionMixin):
|
|||||||
else:
|
else:
|
||||||
return bool(self.purchase_order)
|
return bool(self.purchase_order)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def can_check_in(self):
|
||||||
|
earliest = self.earliest_time
|
||||||
|
if isinstance(self.earliest_time, datetime.date):
|
||||||
|
earliest = datetime.datetime.combine(self.start_date, datetime.time(00, 00))
|
||||||
|
tz = pytz.timezone(settings.TIME_ZONE)
|
||||||
|
earliest = tz.localize(earliest)
|
||||||
|
return not self.dry_hire and earliest <= timezone.now()
|
||||||
|
|
||||||
objects = EventManager()
|
objects = EventManager()
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
@@ -690,17 +711,17 @@ def validate_url(value):
|
|||||||
|
|
||||||
|
|
||||||
class ReviewableModel(models.Model):
|
class ReviewableModel(models.Model):
|
||||||
reviewed_at = models.DateTimeField(null=True)
|
reviewed_at = models.DateTimeField(null=True, blank=True)
|
||||||
reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
|
reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
|
||||||
verbose_name="Reviewer", on_delete=models.CASCADE)
|
verbose_name="Reviewer", on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def fieldz(self):
|
def fieldz(self):
|
||||||
return [n.name for n in list(self._meta.get_fields()) if n.name != 'reviewed_at' and n.name != 'reviewed_by' and not n.is_relation and not n.auto_created]
|
return [n.name for n in list(self._meta.get_fields()) if n.name != 'reviewed_at' and n.name != 'reviewed_by' and not n.is_relation and not n.auto_created]
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
class RiskAssessment(ReviewableModel, RevisionMixin):
|
class RiskAssessment(ReviewableModel, RevisionMixin):
|
||||||
@@ -800,6 +821,12 @@ class RiskAssessment(ReviewableModel, RevisionMixin):
|
|||||||
def get_event_size_display(self):
|
def get_event_size_display(self):
|
||||||
return self.SIZES[self.event_size][1] + " Event"
|
return self.SIZES[self.event_size][1] + " Event"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.pk} | {self.event}"
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse('ra_detail', kwargs={'pk': self.pk})
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def activity_feed_string(self):
|
def activity_feed_string(self):
|
||||||
return str(self.event)
|
return str(self.event)
|
||||||
@@ -808,14 +835,8 @@ class RiskAssessment(ReviewableModel, RevisionMixin):
|
|||||||
def name(self):
|
def name(self):
|
||||||
return str(self)
|
return str(self)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
|
||||||
return reverse('ra_detail', kwargs={'pk': self.pk})
|
|
||||||
|
|
||||||
def __str__(self):
|
@reversion.register
|
||||||
return f"{self.pk} | {self.event}"
|
|
||||||
|
|
||||||
|
|
||||||
@reversion.register(follow=['vehicles', 'crew'])
|
|
||||||
class EventChecklist(ReviewableModel, RevisionMixin):
|
class EventChecklist(ReviewableModel, RevisionMixin):
|
||||||
event = models.ForeignKey('Event', related_name='checklists', on_delete=models.CASCADE)
|
event = models.ForeignKey('Event', related_name='checklists', on_delete=models.CASCADE)
|
||||||
|
|
||||||
@@ -841,6 +862,9 @@ class EventChecklist(ReviewableModel, RevisionMixin):
|
|||||||
('review_eventchecklist', 'Can review Event Checklists')
|
('review_eventchecklist', 'Can review Event Checklists')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.pk} - {self.event}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def activity_feed_string(self):
|
def activity_feed_string(self):
|
||||||
return str(self.event)
|
return str(self.event)
|
||||||
@@ -848,9 +872,6 @@ class EventChecklist(ReviewableModel, RevisionMixin):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('ec_detail', kwargs={'pk': self.pk})
|
return reverse('ec_detail', kwargs={'pk': self.pk})
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.pk} - {self.event}"
|
|
||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
class PowerTestRecord(ReviewableModel, RevisionMixin):
|
class PowerTestRecord(ReviewableModel, RevisionMixin):
|
||||||
@@ -894,25 +915,40 @@ class PowerTestRecord(ReviewableModel, RevisionMixin):
|
|||||||
all_rcds_tested = models.BooleanField(blank=True, null=True, help_text="All circuit RCDs tested?<br><small>(using test button)</small>")
|
all_rcds_tested = models.BooleanField(blank=True, null=True, help_text="All circuit RCDs tested?<br><small>(using test button)</small>")
|
||||||
public_sockets_tested = models.BooleanField(blank=True, null=True, help_text="Public/Performer accessible circuits tested?<br><small>(using socket tester)</small>")
|
public_sockets_tested = models.BooleanField(blank=True, null=True, help_text="Public/Performer accessible circuits tested?<br><small>(using socket tester)</small>")
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.pk} - {self.event}"
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['event']
|
ordering = ['event']
|
||||||
permissions = [
|
permissions = [
|
||||||
('review_power', 'Can review Power Test Records')
|
('review_power', 'Can review Power Test Records')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.pk} - {self.event}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def activity_feed_string(self):
|
||||||
|
return str(self.event)
|
||||||
|
|
||||||
|
|
||||||
class EventCheckIn(models.Model):
|
class EventCheckIn(models.Model):
|
||||||
event = models.ForeignKey('Event', related_name='crew', on_delete=models.CASCADE)
|
event = models.ForeignKey('Event', related_name='crew', on_delete=models.CASCADE)
|
||||||
person = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='checkins', on_delete=models.CASCADE)
|
person = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='checkins', on_delete=models.CASCADE)
|
||||||
time = models.DateTimeField()
|
time = models.DateTimeField()
|
||||||
vehicle = models.CharField(max_length=100)
|
role = models.CharField(max_length=50, blank=True)
|
||||||
|
vehicle = models.CharField(max_length=100, blank=True)
|
||||||
|
end_time = models.DateTimeField(null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.person} on {self.event}"
|
||||||
|
|
||||||
class EventCheckOut(models.Model):
|
def clean(self):
|
||||||
event = models.ForeignKey('Event', on_delete=models.CASCADE)
|
sass = " Please invent time travel and retry."
|
||||||
person = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='checkouts', on_delete=models.CASCADE)
|
if self.time > timezone.now():
|
||||||
time = models.DateTimeField() # TODO Validate may not check in in future
|
raise ValidationError("May not check in in the future." + sass)
|
||||||
vehicle = models.CharField(max_length=100)
|
if self.end_time and self.end_time < self.time:
|
||||||
|
raise ValidationError("May not check out before you've checked in." + sass)
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse('event_detail', kwargs={'pk': self.event_id})
|
||||||
|
|
||||||
|
def active(self):
|
||||||
|
return end_time is not None
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||||
|
|
||||||
{% load markdown_tags %}
|
{% load markdown_tags %}
|
||||||
|
{% load button from filters %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row my-3 py-3">
|
<div class="row my-3 py-3">
|
||||||
@@ -52,6 +54,43 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if event.can_check_in %}
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="card mt-3">
|
||||||
|
<div class="card-header">Crew Record</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-sm">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Name</th>
|
||||||
|
<th scope="col">Vehicle</th>
|
||||||
|
<th scope="col">Start Time</th>
|
||||||
|
<th scope="col">Role</th>
|
||||||
|
<th scope="col">End Time</th>
|
||||||
|
<th scope="col">{% if request.user.pk is event.mic.pk %}<a href="{% url 'event_checkin_override' event.pk %}" class="btn btn-sm btn-success"><span class="fas fa-plus"></span> Add</a>{% endif %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="crewmembers">
|
||||||
|
{% for crew in object.crew.all %}
|
||||||
|
<tr>
|
||||||
|
<td>{{crew.person}}</td>
|
||||||
|
<td>{{crew.vehicle|default:"None"}}</td>
|
||||||
|
<td>{{crew.time}}</td>
|
||||||
|
<td>{{crew.role}}</td>
|
||||||
|
<td>{% if crew.end_time %}{{crew.end_time}}{% else %}<span class="text-success fas fa-clock" data-toggle="tooltip" title="This person is currently checked into this event"></span>{% endif %}</td>
|
||||||
|
<td>{% if crew.end_time %}{% if crew.person.pk == request.user.pk or event.mic.pk == request.user.pk %}{% button 'edit' 'edit_checkin' crew.pk clazz='btn-sm modal-href' %}{% endif %}{%endif%}</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center bg-warning">Apparently this event happened by magic...</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
{% if not request.is_ajax and perms.RIGS.view_event %}
|
{% if not request.is_ajax and perms.RIGS.view_event %}
|
||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
{% include 'partials/event_detail_buttons.html' %}
|
{% include 'partials/event_detail_buttons.html' %}
|
||||||
|
|||||||
@@ -31,12 +31,6 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<p>List vehicles and their drivers</p>
|
|
||||||
<ul>
|
|
||||||
{% for i in object.vehicles.all %}
|
|
||||||
<li>{{i}}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -74,165 +68,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card mb-3">
|
|
||||||
<div class="card-header">Crew Record</div>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-sm">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">Crewmember</th>
|
|
||||||
<th scope="col">Start Time</th>
|
|
||||||
<th scope="col">Role</th>
|
|
||||||
<th scope="col">End Time</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="crewmemberst">
|
|
||||||
{% for crew in object.crew.all %}
|
|
||||||
<tr>
|
|
||||||
<td>{{crew.crewmember}}</td>
|
|
||||||
<td>{{crew.start}}</td>
|
|
||||||
<td>{{crew.role}}</td>
|
|
||||||
<td>{{crew.end}}</td>
|
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="4" class="text-center bg-warning">Apparently this event happened by magic...</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card mb-3">
|
|
||||||
<div class="card-header">Power {% include 'partials/event_size.html' with object=object.event.riskassessment %}</div>
|
|
||||||
<div class="card-body">
|
|
||||||
{% if object.event.riskassessment.event_size == 0 %}
|
|
||||||
<dl class="row">
|
|
||||||
<dt class="col-10">{{ object|help_text:'rcds'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.rcds|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-10">{{ object|help_text:'supply_test'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.supply_test|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-10">{{ object|help_text:'earthing'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.earthing|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-10">{{ object|help_text:'pat'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.pat|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
{% else %}
|
|
||||||
<dl class="row">
|
|
||||||
<dt class="col-10">{{ object|help_text:'source_rcd'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.source_rcd|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-10">{{ object|help_text:'labelling'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.labelling|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-10">{{ object|help_text:'earthing'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.earthing|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-10">{{ object|help_text:'pat'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.pat|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
<hr>
|
|
||||||
<p>Tests at first distro</p>
|
|
||||||
<table class="table table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col" class="text-center">Test</th>
|
|
||||||
<th scope="col" colspan="3" class="text-center">Value</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th scope="row" rowspan="2">Voltage<br><small>(cube meter)</small></th>
|
|
||||||
<th>{{ object|help_text:'fd_voltage_l1' }}</th>
|
|
||||||
<th>{{ object|help_text:'fd_voltage_l2' }}</th>
|
|
||||||
<th>{{ object|help_text:'fd_voltage_l3' }}</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{ object.fd_voltage_l1 }}</td>
|
|
||||||
<td>{{ object.fd_voltage_l2 }}</td>
|
|
||||||
<td>{{ object.fd_voltage_l3 }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ object|help_text:'fd_phase_rotation'|safe }}</th>
|
|
||||||
<td colspan="3">{{ object.fd_phase_rotation|yesnoi }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ object|help_text:'fd_earth_fault'|safe}}</th>
|
|
||||||
<td colspan="3">{{ object.fd_earth_fault }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ object|help_text:'fd_pssc'}}</th>
|
|
||||||
<td colspan="3">{{ object.fd_pssc }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
<p>Tests at 'Worst Case' points (at least 1 point required)</p>
|
|
||||||
<table class="table table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col" class="text-center">Test</th>
|
|
||||||
<th scope="col" class="text-center">Point 1</th>
|
|
||||||
<th scope="col" class="text-center">Point 2</th>
|
|
||||||
<th scope="col" class="text-center">Point 3</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ object|help_text:'w1_description'|safe}}</th>
|
|
||||||
<td>{{ object.w1_description }}</td>
|
|
||||||
<td>{{ object.w2_description|default:'' }}</td>
|
|
||||||
<td>{{ object.w3_description|default:'' }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ object|help_text:'w1_polarity'|safe}}</th>
|
|
||||||
<td>{{ object.w1_polarity|yesnoi }}</td>
|
|
||||||
<td>{{ object.w2_polarity|default:''|yesnoi }}</td>
|
|
||||||
<td>{{ object.w3_polarity|default:''|yesnoi }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ object|help_text:'w1_voltage'|safe}}</th>
|
|
||||||
<td>{{ object.w1_voltage }}</td>
|
|
||||||
<td>{{ object.w2_voltage|default:'' }}</td>
|
|
||||||
<td>{{ object.w3_voltage|default:'' }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{{ object|help_text:'w1_earth_fault'|safe}}</th>
|
|
||||||
<td>{{ object.w1_earth_fault }}</td>
|
|
||||||
<td>{{ object.w2_earth_fault|default:'' }}</td>
|
|
||||||
<td>{{ object.w3_earth_fault|default:'' }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
<dl class="row">
|
|
||||||
<dt class="col-10">{{ object|help_text:'all_rcds_tested'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.all_rcds_tested|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-10">{{ object|help_text:'public_sockets_tested'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.public_sockets_tested|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
<hr>
|
|
||||||
{% include 'partials/ec_power_info.html' %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 text-right">
|
<div class="col-12 text-right">
|
||||||
{% button 'edit' url='ec_edit' pk=object.pk %}
|
{% button 'edit' url='ec_edit' pk=object.pk %}
|
||||||
{% button 'view' url='event_detail' pk=object.pk text="Event" %}
|
{% button 'view' url='event_detail' pk=object.pk text="Event" %}
|
||||||
|
|||||||
@@ -13,22 +13,19 @@
|
|||||||
{% block preload_js %}
|
{% block preload_js %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<script src="{% static 'js/selects.js' %}"></script>
|
<script src="{% static 'js/selects.js' %}"></script>
|
||||||
|
<script src="{% static 'js/interaction.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<script src="{% static 'js/autocompleter.js' %}"></script>
|
<script src="{% static 'js/autocompleter.js' %}"></script>
|
||||||
<script src="{% static 'js/tooltip.js' %}"></script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
{% include 'form_errors.html' %}
|
{% include 'form_errors.html' %}
|
||||||
{% if edit %}
|
|
||||||
<form role="form" method="POST" action="{% url 'ec_edit' pk=object.pk %}">
|
<form role="form" method="POST" action="{% if edit %}{% url 'ec_edit' pk=object.pk %}{% else %}{% url 'event_ec' pk=event.pk %}{% endif %}">
|
||||||
{% else %}
|
|
||||||
<form role="form" method="POST" action="{% url 'event_ec' pk=event.pk %}">
|
|
||||||
{% endif %}
|
|
||||||
<input type="hidden" name="{{ form.event.name }}" id="{{ form.event.id_for_label }}"
|
<input type="hidden" name="{{ form.event.name }}" id="{{ form.event.id_for_label }}"
|
||||||
value="{{event.pk}}"/>
|
value="{{event.pk}}"/>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
@@ -59,7 +56,7 @@
|
|||||||
<div class="form-group form-row" id="{{ form.venue.id_for_label }}-group">
|
<div class="form-group form-row" id="{{ form.venue.id_for_label }}-group">
|
||||||
<label for="{{ form.venue.id_for_label }}"
|
<label for="{{ form.venue.id_for_label }}"
|
||||||
class="col-4 col-form-label">{{ form.venue.label }}</label>
|
class="col-4 col-form-label">{{ form.venue.label }}</label>
|
||||||
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}" class="form-control selectpicker col-8" data-live-search="true" data-sourceurl="{% url 'api_secure' model='venue' %}">
|
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}" class="selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='venue' %}">
|
||||||
{% if venue %}
|
{% if venue %}
|
||||||
<option value="{{venue.pk}}" selected="selected">{{ venue.name }}</option>
|
<option value="{{venue.pk}}" selected="selected">{{ venue.name }}</option>
|
||||||
{% elif event.venue %}
|
{% elif event.venue %}
|
||||||
|
|||||||
@@ -1,56 +1,105 @@
|
|||||||
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
|
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
|
||||||
{% load widget_tweaks %}
|
{% load widget_tweaks %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load help_text from filters %}
|
|
||||||
{% load profile_by_index from filters %}
|
|
||||||
{% load button from filters %}
|
{% load button from filters %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<link rel="stylesheet" href="{% static 'css/selects.css' %}"/>
|
<link rel="stylesheet" type="text/css" href="{% static 'css/selects.css' %}"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static 'css/easymde.min.css' %}">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block preload_js %}
|
{% block preload_js %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<script src="{% static 'js/selects.js' %}"></script>
|
<script src="{% static 'js/selects.js' %}"></script>
|
||||||
|
<script src="{% static 'js/easymde.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<script src="{% static 'js/autocompleter.js' %}"></script>
|
<script src="{% static 'js/autocompleter.js' %}"></script>
|
||||||
|
<script src="{% static 'js/interaction.js' %}"></script>
|
||||||
<script src="{% static 'js/tooltip.js' %}"></script>
|
<script src="{% static 'js/tooltip.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
{% include 'form_errors.html' %}
|
{% include 'form_errors.html' %}
|
||||||
<form role="form" method="POST" action="{% url 'event_checkin' pk=event.pk %}">
|
<form id="checkin" role="form" method="POST" action="{{ form.action|default:request.path }}">
|
||||||
<input type="hidden" name="{{ form.event.name }}" id="{{ form.event.id_for_label }}"
|
<input type="hidden" name="{{ form.event.name }}" id="{{ form.event.id_for_label }}"
|
||||||
value="{{event.pk}}"/>
|
value="{{event.pk}}"/>
|
||||||
|
{% if not request.is_ajax and self.request.user.pk is form.event.mic.pk %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{ form.person.id_for_label }}"
|
||||||
|
class="col-sm-4 col-form-label">{{ form.person.label }}</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<select id="{{ form.person.id_for_label }}" name="{{ form.person.name }}" class="px-0 selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
|
||||||
|
{% if person %}
|
||||||
|
<option value="{{form.person.value}}" selected="selected" >{{ person.name }}</option>
|
||||||
|
{% endif %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
<input type="hidden" name="{{ form.person.name }}" id="{{ form.person.id_for_label }}"
|
<input type="hidden" name="{{ form.person.name }}" id="{{ form.person.id_for_label }}"
|
||||||
value="{{request.user.pk}}"/>
|
value="{{request.user.pk}}"/>
|
||||||
|
{% endif %}
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ form.time.id_for_label }}"
|
<label for="{{ form.time.id_for_label }}"
|
||||||
class="col-sm-4 col-form-label">{{ form.time.label }}</label>
|
class="col-sm-4 col-form-label">Start Time</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% render_field form.time class+="form-control" %}
|
{% render_field form.time class+="form-control" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ form.vehicle.id_for_label }}" class="col-sm-4 col-form-label">Did you drive? If so, what did you drive?</label>
|
<label for="{{ form.role.id_for_label }}" class="col col-form-label">Role</label>
|
||||||
<br><button type="button" class="btn btn-primary" onclick="document.getElementById('id_vehicle').value='Virgil'"><span class="fas fa-truck-moving"></span> Virgil</button>
|
<div class="row pl-3">
|
||||||
|
<div class="col-md-6 col-sm-12">
|
||||||
|
<button type="button" class="btn btn-primary" onclick="document.getElementById('id_role').value='MIC'">MIC</button>
|
||||||
|
<button type="button" class="btn btn-danger" onclick="document.getElementById('id_role').value='Power MIC'">Power MIC</button>
|
||||||
|
<button type="button" class="btn btn-info" onclick="document.getElementById('id_role').value='Crew'">Crew</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mt-2">
|
||||||
|
{% render_field form.role class+="form-control" placeholder="Other (enter text)" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{ form.vehicle.id_for_label }}" class="col col-form-label">Vehicle (if applicable)</label>
|
||||||
|
<div class="row pl-3">
|
||||||
|
<div class="col-md-6 col-sm-12">
|
||||||
|
<button type="button" class="btn btn-primary" onclick="document.getElementById('id_vehicle').value='Virgil'"><span class="fas fa-truck-moving"></span> Virgil</button>
|
||||||
<button type="button" class="btn btn-secondary" onclick="document.getElementById('id_vehicle').value='Virgil + Erms'"><span class="fas fa-trailer"></span><span class="fas fa-truck-moving"></span> Virgil + Erms</button>
|
<button type="button" class="btn btn-secondary" onclick="document.getElementById('id_vehicle').value='Virgil + Erms'"><span class="fas fa-trailer"></span><span class="fas fa-truck-moving"></span> Virgil + Erms</button>
|
||||||
<br>Other (enter text)
|
</div>
|
||||||
|
<div class="col-md-6 mt-2">
|
||||||
|
{% render_field form.vehicle class+="form-control" placeholder="Other (enter text)" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if edit or manual %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{ form.end_time.id_for_label }}"
|
||||||
|
class="col-sm-4 col-form-label">End Time</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% render_field form.vehicle class+="form-control" %}
|
{% render_field form.end_time class+="form-control" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if not request.is_ajax %}
|
||||||
<div class="row mt-3">
|
<div class="row mt-3">
|
||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
{% button 'submit' %}
|
{% button 'submit' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block footer %}
|
||||||
|
<div class="col-sm-12 text-right pr-0">
|
||||||
|
<button type="submit" class="btn btn-primary" title="Save" form="checkin"
|
||||||
|
><span class="fas fa-save align-middle"></span> <span class="d-none d-sm-inline align-middle">Save</span></button>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
@@ -49,6 +49,13 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<a href="https://docs.google.com/forms/d/e/1FAIpQLSf-TBOuJZCTYc2L8DWdAaC3_Werq0ulsUs8-6G85I6pA9WVsg/viewform" class="btn btn-danger"><span class="fas fa-file-invoice-dollar"></span> <span class="d-none d-sm-inline">Subhire Insurance Form</span></a>
|
<a href="https://docs.google.com/forms/d/e/1FAIpQLSf-TBOuJZCTYc2L8DWdAaC3_Werq0ulsUs8-6G85I6pA9WVsg/viewform" class="btn btn-danger"><span class="fas fa-file-invoice-dollar"></span> <span class="d-none d-sm-inline">Subhire Insurance Form</span></a>
|
||||||
<a href="{% url 'event_checkin' event.pk %}" class="btn btn-success"><span class="fas fa-user-clock"></span> <span class="d-none d-sm-inline">Check In</span></a>
|
|
||||||
|
{% if event.can_check_in %}
|
||||||
|
{% if request.user.current_event %}
|
||||||
|
<a href="{% url 'event_checkout' %}" class="btn btn-warning">Check Out</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{% url 'event_checkin' event.pk %}" class="btn btn-success modal-href"><span class="fas fa-user-clock"></span> <span class="d-none d-sm-inline">Check In</span></a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,19 +15,21 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not event.dry_hire %}
|
{% if not event.dry_hire %}
|
||||||
{% if event.riskassessment %}
|
{% if event.has_checklist %}
|
||||||
<a href="{{ event.riskassessment.get_absolute_url }}"><span class="badge badge-success">RA: <span class="fas fa-check{% if event.riskassessment.reviewed_by %}-double{%endif%}"></span></a>
|
<a href="{{ event.riskassessment.get_absolute_url }}"><span class="badge badge-success">RA: <span class="fas fa-check{% if event.riskassessment.reviewed_by %}-double{%endif%}"></span></a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="badge badge-danger">RA: <span class="fas fa-times"></span></span>
|
<span class="badge badge-danger">RA: <span class="fas fa-times"></span></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% if event.has_checklist %}
|
||||||
{% if not event.dry_hire %}
|
<span class="badge badge-success">Checklist: <span class="fas fa-check"></span> {% if event.checklists.count > 1 %}({{event.checklists.count}}){% endif %}</span>
|
||||||
{% if event.hs_done %}
|
|
||||||
{# TODO Display status of all checklists #}
|
|
||||||
<span class="badge badge-success">Checklist: <span class="fas fa-check"></span></span>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="badge badge-danger">Checklist: <span class="fas fa-times"></span></span>
|
<span class="badge badge-danger">Checklist: <span class="fas fa-times"></span></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if event.has_power %}
|
||||||
|
<span class="badge badge-success">Power Record: <span class="fas fa-check"></span> {% if event.power_tests.count > 1 %}({{event.power_tests.count}}){% endif %}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge badge-danger">Power Record: <span class="fas fa-times"></span></span>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.RIGS.view_invoice %}
|
{% if perms.RIGS.view_invoice %}
|
||||||
{% if event.invoice %}
|
{% if event.invoice %}
|
||||||
|
|||||||
@@ -43,15 +43,22 @@ def venue(db):
|
|||||||
|
|
||||||
@pytest.fixture # TODO parameterise with Event sizes
|
@pytest.fixture # TODO parameterise with Event sizes
|
||||||
def checklist(basic_event, venue, admin_user, ra):
|
def checklist(basic_event, venue, admin_user, ra):
|
||||||
checklist = models.EventChecklist.objects.create(event=basic_event, power_mic=admin_user, safe_parking=False,
|
checklist = models.EventChecklist.objects.create(event=basic_event, safe_parking=False,
|
||||||
safe_packing=False, exits=False, trip_hazard=False, warning_signs=False,
|
safe_packing=False, exits=False, trip_hazard=False, warning_signs=False,
|
||||||
ear_plugs=False, hs_location="Locked away safely",
|
ear_plugs=False, hs_location="Locked away safely",
|
||||||
extinguishers_location="Somewhere, I forgot", earthing=False, pat=False,
|
extinguishers_location="Somewhere, I forgot",
|
||||||
date=timezone.now(), venue=venue)
|
date=timezone.now(), venue=venue)
|
||||||
yield checklist
|
yield checklist
|
||||||
checklist.delete()
|
checklist.delete()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def power_test(basic_event, venue, admin_user, ra):
|
||||||
|
power_test = models.PowerTestRecord.objects.create(event=basic_event, venue=venue)
|
||||||
|
yield power_test
|
||||||
|
power_test.delete()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def many_events(db, admin_user, scope="class"):
|
def many_events(db, admin_user, scope="class"):
|
||||||
many_events = {
|
many_events = {
|
||||||
|
|||||||
@@ -230,11 +230,6 @@ class CreateEventChecklist(FormPage):
|
|||||||
URL_TEMPLATE = 'event/{event_id}/checklist'
|
URL_TEMPLATE = 'event/{event_id}/checklist'
|
||||||
|
|
||||||
_submit_locator = (By.XPATH, "//button[@type='submit' and contains(., 'Save')]")
|
_submit_locator = (By.XPATH, "//button[@type='submit' and contains(., 'Save')]")
|
||||||
_power_mic_selector = (By.XPATH, "//div[select[@id='id_power_mic']]")
|
|
||||||
_add_vehicle_locator = (By.XPATH, "//button[contains(., 'Vehicle')]")
|
|
||||||
_add_crew_locator = (By.XPATH, "//button[contains(., 'Crew')]")
|
|
||||||
_vehicle_row_locator = ('xpath', "//tr[@id[starts-with(., 'vehicle') and not(contains(.,'new'))]]")
|
|
||||||
_crew_row_locator = ('xpath', "//tr[@id[starts-with(., 'crew') and not(contains(.,'new'))]]")
|
|
||||||
|
|
||||||
form_items = {
|
form_items = {
|
||||||
'safe_parking': (regions.CheckBox, (By.ID, 'id_safe_parking')),
|
'safe_parking': (regions.CheckBox, (By.ID, 'id_safe_parking')),
|
||||||
@@ -245,6 +240,20 @@ class CreateEventChecklist(FormPage):
|
|||||||
'ear_plugs': (regions.CheckBox, (By.ID, 'id_ear_plugs')),
|
'ear_plugs': (regions.CheckBox, (By.ID, 'id_ear_plugs')),
|
||||||
'hs_location': (regions.TextBox, (By.ID, 'id_hs_location')),
|
'hs_location': (regions.TextBox, (By.ID, 'id_hs_location')),
|
||||||
'extinguishers_location': (regions.TextBox, (By.ID, 'id_extinguishers_location')),
|
'extinguishers_location': (regions.TextBox, (By.ID, 'id_extinguishers_location')),
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def success(self):
|
||||||
|
return '{event_id}' not in self.driver.current_url
|
||||||
|
|
||||||
|
|
||||||
|
class CreatePowerTestRecord(FormPage):
|
||||||
|
URL_TEMPLATE = 'event/{event_id}/power'
|
||||||
|
|
||||||
|
_submit_locator = (By.XPATH, "//button[@type='submit' and contains(., 'Save')]")
|
||||||
|
_power_mic_selector = (By.XPATH, "//div[select[@id='id_power_mic']]")
|
||||||
|
|
||||||
|
form_items = {
|
||||||
'rcds': (regions.CheckBox, (By.ID, 'id_rcds')),
|
'rcds': (regions.CheckBox, (By.ID, 'id_rcds')),
|
||||||
'supply_test': (regions.CheckBox, (By.ID, 'id_supply_test')),
|
'supply_test': (regions.CheckBox, (By.ID, 'id_supply_test')),
|
||||||
'earthing': (regions.CheckBox, (By.ID, 'id_earthing')),
|
'earthing': (regions.CheckBox, (By.ID, 'id_earthing')),
|
||||||
@@ -263,58 +272,10 @@ class CreateEventChecklist(FormPage):
|
|||||||
'w1_earth_fault': (regions.TextBox, (By.ID, 'id_w1_earth_fault')),
|
'w1_earth_fault': (regions.TextBox, (By.ID, 'id_w1_earth_fault')),
|
||||||
}
|
}
|
||||||
|
|
||||||
def add_vehicle(self):
|
|
||||||
self.find_element(*self._add_vehicle_locator).click()
|
|
||||||
|
|
||||||
def add_crew(self):
|
|
||||||
self.find_element(*self._add_crew_locator).click()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def power_mic(self):
|
def power_mic(self):
|
||||||
return regions.BootstrapSelectElement(self, self.find_element(*self._power_mic_selector))
|
return regions.BootstrapSelectElement(self, self.find_element(*self._power_mic_selector))
|
||||||
|
|
||||||
@property
|
|
||||||
def vehicles(self):
|
|
||||||
return [self.VehicleRow(self, el) for el in self.find_elements(*self._vehicle_row_locator)]
|
|
||||||
|
|
||||||
class VehicleRow(Region):
|
|
||||||
_name_locator = ('xpath', ".//input")
|
|
||||||
_select_locator = ('xpath', ".//div[contains(@class,'bootstrap-select')]/..")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
return regions.TextBox(self, self.root.find_element(*self._name_locator))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def vehicle(self):
|
|
||||||
return regions.BootstrapSelectElement(self, self.root.find_element(*self._select_locator))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def crew(self):
|
|
||||||
return [self.CrewRow(self, el) for el in self.find_elements(*self._crew_row_locator)]
|
|
||||||
|
|
||||||
class CrewRow(Region):
|
|
||||||
_select_locator = ('xpath', ".//div[contains(@class,'bootstrap-select')]/..")
|
|
||||||
_start_time_locator = ('xpath', ".//input[@name[starts-with(., 'start') and not(contains(.,'new'))]]")
|
|
||||||
_end_time_locator = ('xpath', ".//input[@name[starts-with(., 'end') and not(contains(.,'new'))]]")
|
|
||||||
_role_locator = ('xpath', ".//input[@name[starts-with(., 'role') and not(contains(.,'new'))]]")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def crewmember(self):
|
|
||||||
return regions.BootstrapSelectElement(self, self.root.find_element(*self._select_locator))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def start_time(self):
|
|
||||||
return regions.DateTimePicker(self, self.root.find_element(*self._start_time_locator))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def end_time(self):
|
|
||||||
return regions.DateTimePicker(self, self.root.find_element(*self._end_time_locator))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def role(self):
|
|
||||||
return regions.TextBox(self, self.root.find_element(*self._role_locator))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def success(self):
|
def success(self):
|
||||||
return '{event_id}' not in self.driver.current_url
|
return '{event_id}' not in self.driver.current_url
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from PyRIGS.tests.regions import TextBox, Modal, SimpleMDETextArea
|
|||||||
|
|
||||||
class Header(Region):
|
class Header(Region):
|
||||||
def find_link(self, link_text):
|
def find_link(self, link_text):
|
||||||
return self.driver.find_element_by_partial_link_text(link_text)
|
return self.driver.find_element(By.PARTIAL_LINK_TEXT, link_text)
|
||||||
|
|
||||||
|
|
||||||
class ItemRow(Region):
|
class ItemRow(Region):
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ class TestEventDuplicate(BaseRigboardTest):
|
|||||||
|
|
||||||
self.assertFalse(newEvent.authorised)
|
self.assertFalse(newEvent.authorised)
|
||||||
|
|
||||||
self.assertNotIn("N%05d" % self.testEvent.pk, self.driver.find_element_by_xpath('//h2').text)
|
self.assertNotIn("N%05d" % self.testEvent.pk, self.driver.find_element(By.XPATH, '//h2').text)
|
||||||
self.assertNotIn("Event data duplicated but not yet saved", self.page.warning) # Check info message not visible
|
self.assertNotIn("Event data duplicated but not yet saved", self.page.warning) # Check info message not visible
|
||||||
|
|
||||||
# Check the new items are visible
|
# Check the new items are visible
|
||||||
@@ -327,26 +327,25 @@ class TestEventDuplicate(BaseRigboardTest):
|
|||||||
self.assertIn("Test Item 2", table.text)
|
self.assertIn("Test Item 2", table.text)
|
||||||
self.assertIn("Test Item 3", table.text)
|
self.assertIn("Test Item 3", table.text)
|
||||||
|
|
||||||
infoPanel = self.driver.find_element_by_xpath('//div[contains(text(), "Event Info")]/..')
|
infoPanel = self.driver.find_element(By.XPATH, '//div[contains(text(), "Event Info")]/..')
|
||||||
self.assertIn("N%05d" % self.testEvent.pk,
|
self.assertIn("N%05d" % self.testEvent.pk, infoPanel.find_element(By.XPATH, '//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
||||||
infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
|
||||||
# Check the PO hasn't carried through
|
# Check the PO hasn't carried through
|
||||||
self.assertNotIn("TESTPO", infoPanel.find_element_by_xpath('//dt[text()="PO"]/following-sibling::dd[1]').text)
|
self.assertNotIn("TESTPO", infoPanel.find_element(By.XPATH, '//dt[text()="PO"]/following-sibling::dd[1]').text)
|
||||||
|
|
||||||
self.assertIn("N%05d" % self.testEvent.pk,
|
self.assertIn("N%05d" % self.testEvent.pk,
|
||||||
infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
infoPanel.find_element(By.XPATH, '//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
||||||
|
|
||||||
self.driver.get(self.live_server_url + '/event/' + str(self.testEvent.pk)) # Go back to the old event
|
self.driver.get(self.live_server_url + '/event/' + str(self.testEvent.pk)) # Go back to the old event
|
||||||
|
|
||||||
# Check that based-on hasn't crept into the old event
|
# Check that based-on hasn't crept into the old event
|
||||||
infoPanel = self.driver.find_element_by_xpath('//div[contains(text(), "Event Info")]/..')
|
infoPanel = self.driver.find_element(By.XPATH, '//div[contains(text(), "Event Info")]/..')
|
||||||
self.assertNotIn("N%05d" % self.testEvent.pk,
|
self.assertNotIn("N%05d" % self.testEvent.pk,
|
||||||
infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
infoPanel.find_element(By.XPATH, '//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
||||||
# Check the PO remains on the old event
|
# Check the PO remains on the old event
|
||||||
self.assertIn("TESTPO", infoPanel.find_element_by_xpath('//dt[text()="PO"]/following-sibling::dd[1]').text)
|
self.assertIn("TESTPO", infoPanel.find_element(By.XPATH, '//dt[text()="PO"]/following-sibling::dd[1]').text)
|
||||||
|
|
||||||
self.assertNotIn("N%05d" % self.testEvent.pk,
|
self.assertNotIn("N%05d" % self.testEvent.pk,
|
||||||
infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
infoPanel.find_element(By.XPATH, '//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
||||||
|
|
||||||
# Check the items are as they were
|
# Check the items are as they were
|
||||||
table = self.page.item_table # ID number is known, see above
|
table = self.page.item_table # ID number is known, see above
|
||||||
@@ -677,14 +676,6 @@ def small_ec(page, admin_user):
|
|||||||
page.ear_plugs = True
|
page.ear_plugs = True
|
||||||
page.hs_location = "The Moon"
|
page.hs_location = "The Moon"
|
||||||
page.extinguishers_location = "With the rest of the fire"
|
page.extinguishers_location = "With the rest of the fire"
|
||||||
# If we do this first the search fails, for ... reasons
|
|
||||||
page.power_mic.search(admin_user.name)
|
|
||||||
page.power_mic.toggle()
|
|
||||||
assert not page.power_mic.is_open
|
|
||||||
page.earthing = True
|
|
||||||
page.rcds = True
|
|
||||||
page.supply_test = True
|
|
||||||
page.pat = True
|
|
||||||
|
|
||||||
|
|
||||||
def test_ec_create_small(logged_in_browser, live_server, admin_user, ra):
|
def test_ec_create_small(logged_in_browser, live_server, admin_user, ra):
|
||||||
@@ -705,14 +696,15 @@ def test_ec_create_medium(logged_in_browser, live_server, admin_user, medium_ra)
|
|||||||
page.ear_plugs = True
|
page.ear_plugs = True
|
||||||
page.hs_location = "Death Valley"
|
page.hs_location = "Death Valley"
|
||||||
page.extinguishers_location = "With the rest of the fire"
|
page.extinguishers_location = "With the rest of the fire"
|
||||||
# If we do this first the search fails, for ... reasons
|
|
||||||
page.power_mic.search(admin_user.name)
|
|
||||||
page.power_mic.toggle()
|
|
||||||
assert not page.power_mic.is_open
|
|
||||||
|
|
||||||
# Gotta scroll to make the button clickable
|
# Gotta scroll to make the button clickable
|
||||||
logged_in_browser.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
|
logged_in_browser.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
|
||||||
|
page.submit()
|
||||||
|
assert page.success
|
||||||
|
|
||||||
|
|
||||||
|
def test_power_checklist(logged_in_browser, live_server, admin_user, power_test, medium_ra):
|
||||||
|
page = pages.CreatePowerTestRecord(logged_in_browser.driver, live_server.url, event_id=medium_ra.event.pk).open()
|
||||||
page.earthing = True
|
page.earthing = True
|
||||||
page.pat = True
|
page.pat = True
|
||||||
page.source_rcd = True
|
page.source_rcd = True
|
||||||
@@ -727,56 +719,15 @@ def test_ec_create_medium(logged_in_browser, live_server, admin_user, medium_ra)
|
|||||||
page.w1_polarity = True
|
page.w1_polarity = True
|
||||||
page.w1_voltage = 240
|
page.w1_voltage = 240
|
||||||
page.w1_earth_fault = "0.42"
|
page.w1_earth_fault = "0.42"
|
||||||
|
# If we do this first the search fails, for ... reasons
|
||||||
|
page.power_mic.search(admin_user.name)
|
||||||
|
page.power_mic.toggle()
|
||||||
|
assert not page.power_mic.is_open
|
||||||
|
|
||||||
page.submit()
|
page.submit()
|
||||||
assert page.success
|
assert page.success
|
||||||
|
|
||||||
|
|
||||||
def test_ec_create_vehicle(logged_in_browser, live_server, admin_user, checklist):
|
|
||||||
page = pages.EditEventChecklist(logged_in_browser.driver, live_server.url, pk=checklist.pk).open()
|
|
||||||
small_ec(page, admin_user)
|
|
||||||
page.add_vehicle()
|
|
||||||
assert len(page.vehicles) == 1
|
|
||||||
vehicle_name = 'Brian'
|
|
||||||
page.vehicles[0].name.set_value(vehicle_name)
|
|
||||||
# Appears we're moving too fast for javascript...
|
|
||||||
t.sleep(1)
|
|
||||||
page.vehicles[0].vehicle.search(admin_user.first_name)
|
|
||||||
t.sleep(1)
|
|
||||||
page.submit()
|
|
||||||
assert page.success
|
|
||||||
# Check data is correct
|
|
||||||
checklist.refresh_from_db()
|
|
||||||
vehicle = models.EventChecklistVehicle.objects.get(checklist=checklist.pk)
|
|
||||||
assert vehicle_name == vehicle.vehicle
|
|
||||||
|
|
||||||
|
|
||||||
# TODO Test validation of end before start
|
|
||||||
def test_ec_create_crew(logged_in_browser, live_server, admin_user, checklist):
|
|
||||||
page = pages.EditEventChecklist(logged_in_browser.driver, live_server.url, pk=checklist.pk).open()
|
|
||||||
small_ec(page, admin_user)
|
|
||||||
page.add_crew()
|
|
||||||
assert len(page.crew) == 1
|
|
||||||
role = "MIC"
|
|
||||||
start_time = timezone.make_aware(datetime.datetime(2015, 1, 1, 9, 0))
|
|
||||||
end_time = timezone.make_aware(datetime.datetime(2015, 1, 1, 10, 30))
|
|
||||||
crew = page.crew[0]
|
|
||||||
t.sleep(2)
|
|
||||||
crew.crewmember.search(admin_user.first_name)
|
|
||||||
t.sleep(2)
|
|
||||||
crew.role.set_value(role)
|
|
||||||
crew.start_time.set_value(start_time)
|
|
||||||
crew.end_time.set_value(end_time)
|
|
||||||
page.submit()
|
|
||||||
assert page.success
|
|
||||||
# Check data is correct
|
|
||||||
crew_obj = models.EventChecklistCrew.objects.get(checklist=checklist.pk)
|
|
||||||
assert admin_user.pk == crew_obj.crewmember.pk
|
|
||||||
assert role == crew_obj.role
|
|
||||||
assert start_time == crew_obj.start
|
|
||||||
assert end_time == crew_obj.end
|
|
||||||
|
|
||||||
|
|
||||||
# TODO Can I loop through all the boolean fields and test them at once?
|
# TODO Can I loop through all the boolean fields and test them at once?
|
||||||
def test_ra_creation(logged_in_browser, live_server, admin_user, basic_event):
|
def test_ra_creation(logged_in_browser, live_server, admin_user, basic_event):
|
||||||
page = pages.CreateRiskAssessment(logged_in_browser.driver, live_server.url, event_id=basic_event.pk).open()
|
page = pages.CreateRiskAssessment(logged_in_browser.driver, live_server.url, event_id=basic_event.pk).open()
|
||||||
|
|||||||
@@ -101,8 +101,14 @@ urlpatterns = [
|
|||||||
path('event/power/<int:pk>/review/', permission_required_with_403('RIGS.review_power')(views.MarkReviewed.as_view()),
|
path('event/power/<int:pk>/review/', permission_required_with_403('RIGS.review_power')(views.MarkReviewed.as_view()),
|
||||||
name='pt_review', kwargs={'model': 'PowerTestRecord'}),
|
name='pt_review', kwargs={'model': 'PowerTestRecord'}),
|
||||||
|
|
||||||
path('event/<int:pk>/checkin/', permission_required_with_403('RIGS.add_eventcheckin')(views.EventCheckIn.as_view()),
|
path('event/<int:pk>/checkin/', login_required(views.EventCheckIn.as_view()),
|
||||||
name='event_checkin'),
|
name='event_checkin'),
|
||||||
|
path('event/checkout/', login_required(views.EventCheckOut.as_view()),
|
||||||
|
name='event_checkout'),
|
||||||
|
path('event/<int:pk>/checkin/edit/', login_required(views.EventCheckInEdit.as_view()),
|
||||||
|
name='edit_checkin'),
|
||||||
|
path('event/<int:pk>/checkin/add/', login_required(views.EventCheckInOverride.as_view()),
|
||||||
|
name='event_checkin_override'),
|
||||||
|
|
||||||
# Finance
|
# Finance
|
||||||
path('invoice/', permission_required_with_403('RIGS.view_invoice')(views.InvoiceIndex.as_view()),
|
path('invoice/', permission_required_with_403('RIGS.view_invoice')(views.InvoiceIndex.as_view()),
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from reversion import revisions as reversion
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
from RIGS import models, forms
|
from RIGS import models, forms
|
||||||
from RIGS.views.rigboard import get_related
|
from RIGS.views.rigboard import get_related
|
||||||
from PyRIGS.views import PrintView
|
from PyRIGS.views import PrintView, ModalURLMixin
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
|
||||||
|
|
||||||
class HSCreateView(generic.CreateView):
|
class HSCreateView(generic.CreateView):
|
||||||
@@ -24,7 +25,7 @@ class HSCreateView(generic.CreateView):
|
|||||||
epk = self.kwargs.get('pk')
|
epk = self.kwargs.get('pk')
|
||||||
event = models.Event.objects.get(pk=epk)
|
event = models.Event.objects.get(pk=epk)
|
||||||
context['event'] = event
|
context['event'] = event
|
||||||
context['page_title'] = f'Create {self} for Event {event.display_id}'
|
context['page_title'] = f'Create {self.model.__name__} for Event {event.display_id}'
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ class MarkReviewed(generic.View):
|
|||||||
obj.reviewed_by = self.request.user
|
obj.reviewed_by = self.request.user
|
||||||
obj.reviewed_at = timezone.now()
|
obj.reviewed_at = timezone.now()
|
||||||
obj.save()
|
obj.save()
|
||||||
return HttpResponseRedirect(reverse_lazy('hs_list'))
|
return HttpResponseRedirect(reverse('hs_list'))
|
||||||
|
|
||||||
|
|
||||||
class EventRiskAssessmentCreate(HSCreateView):
|
class EventRiskAssessmentCreate(HSCreateView):
|
||||||
@@ -52,12 +53,12 @@ class EventRiskAssessmentCreate(HSCreateView):
|
|||||||
ra = models.RiskAssessment.objects.filter(event=event).first()
|
ra = models.RiskAssessment.objects.filter(event=event).first()
|
||||||
|
|
||||||
if ra is not None:
|
if ra is not None:
|
||||||
return HttpResponseRedirect(reverse_lazy('ra_edit', kwargs={'pk': ra.pk}))
|
return HttpResponseRedirect(reverse('ra_edit', kwargs={'pk': ra.pk}))
|
||||||
|
|
||||||
return super(EventRiskAssessmentCreate, self).get(self)
|
return super(EventRiskAssessmentCreate, self).get(self)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy('ra_detail', kwargs={'pk': self.object.pk})
|
return reverse('ra_detail', kwargs={'pk': self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
class EventRiskAssessmentEdit(generic.UpdateView):
|
class EventRiskAssessmentEdit(generic.UpdateView):
|
||||||
@@ -70,7 +71,7 @@ class EventRiskAssessmentEdit(generic.UpdateView):
|
|||||||
ra.reviewed_by = None
|
ra.reviewed_by = None
|
||||||
ra.reviewed_at = None
|
ra.reviewed_at = None
|
||||||
ra.save()
|
ra.save()
|
||||||
return reverse_lazy('ra_detail', kwargs={'pk': self.object.pk})
|
return reverse('ra_detail', kwargs={'pk': self.object.pk})
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(EventRiskAssessmentEdit, self).get_context_data(**kwargs)
|
context = super(EventRiskAssessmentEdit, self).get_context_data(**kwargs)
|
||||||
@@ -113,7 +114,7 @@ class EventChecklistEdit(generic.UpdateView):
|
|||||||
ec.reviewed_by = None
|
ec.reviewed_by = None
|
||||||
ec.reviewed_at = None
|
ec.reviewed_at = None
|
||||||
ec.save()
|
ec.save()
|
||||||
return reverse_lazy('ec_detail', kwargs={'pk': self.object.pk})
|
return reverse('ec_detail', kwargs={'pk': self.object.pk})
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(EventChecklistEdit, self).get_context_data(**kwargs)
|
context = super(EventChecklistEdit, self).get_context_data(**kwargs)
|
||||||
@@ -141,12 +142,12 @@ class EventChecklistCreate(HSCreateView):
|
|||||||
|
|
||||||
if ra is None:
|
if ra is None:
|
||||||
messages.error(self.request, f'A Risk Assessment must exist prior to creating any Event Checklists for {event}! Please create one now.')
|
messages.error(self.request, f'A Risk Assessment must exist prior to creating any Event Checklists for {event}! Please create one now.')
|
||||||
return HttpResponseRedirect(reverse_lazy('event_ra', kwargs={'pk': epk}))
|
return HttpResponseRedirect(reverse('event_ra', kwargs={'pk': epk}))
|
||||||
|
|
||||||
return super(EventChecklistCreate, self).get(self)
|
return super(EventChecklistCreate, self).get(self)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy('ec_detail', kwargs={'pk': self.object.pk})
|
return reverse('ec_detail', kwargs={'pk': self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
class PowerTestDetail(generic.DetailView):
|
class PowerTestDetail(generic.DetailView):
|
||||||
@@ -169,7 +170,7 @@ class PowerTestEdit(generic.UpdateView):
|
|||||||
ec.reviewed_by = None
|
ec.reviewed_by = None
|
||||||
ec.reviewed_at = None
|
ec.reviewed_at = None
|
||||||
ec.save()
|
ec.save()
|
||||||
return reverse_lazy('ec_detail', kwargs={'pk': self.object.pk})
|
return reverse('ec_detail', kwargs={'pk': self.object.pk})
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
@@ -196,12 +197,12 @@ class PowerTestCreate(HSCreateView):
|
|||||||
|
|
||||||
if ra is None:
|
if ra is None:
|
||||||
messages.error(self.request, f'A Risk Assessment must exist prior to creating any Power Test Records for {event}! Please create one now.')
|
messages.error(self.request, f'A Risk Assessment must exist prior to creating any Power Test Records for {event}! Please create one now.')
|
||||||
return HttpResponseRedirect(reverse_lazy('event_ra', kwargs={'pk': epk}))
|
return HttpResponseRedirect(reverse('event_ra', kwargs={'pk': epk}))
|
||||||
|
|
||||||
return super().get(self)
|
return super().get(self)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy('pt_detail', kwargs={'pk': self.object.pk})
|
return reverse('pt_detail', kwargs={'pk': self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
class HSList(generic.ListView):
|
class HSList(generic.ListView):
|
||||||
@@ -228,14 +229,62 @@ class RAPrint(PrintView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class EventCheckIn(generic.CreateView):
|
class EventCheckIn(generic.CreateView, ModalURLMixin):
|
||||||
model = models.EventCheckIn
|
model = models.EventCheckIn
|
||||||
template_name = 'hs/eventcheckin_form.html'
|
template_name = 'hs/eventcheckin_form.html'
|
||||||
form_class = forms.EventCheckInForm
|
form_class = forms.EventCheckInForm
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return self.get_close_url('event_detail', 'event_detail') # Well, that's one way of doing that...!
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['event'] = models.Event.objects.get(pk=self.kwargs.get('pk'))
|
context['event'] = models.Event.objects.get(pk=self.kwargs.get('pk'))
|
||||||
context['page_title'] = f'Check In to Event {context["event"].display_id}'
|
context['page_title'] = f'Check In to Event {context["event"].display_id}'
|
||||||
# get_related(context['form'], context)
|
# get_related(context['form'], context)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class EventCheckInOverride(generic.CreateView):
|
||||||
|
model = models.EventCheckIn
|
||||||
|
template_name = 'hs/eventcheckin_form.html'
|
||||||
|
form_class = forms.EditCheckInForm
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['event'] = models.Event.objects.get(pk=self.kwargs.get('pk'))
|
||||||
|
context['page_title'] = f'Manually add Check In to Event {context["event"].display_id}'
|
||||||
|
context['manual'] = True
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class EventCheckInEdit(generic.UpdateView, ModalURLMixin):
|
||||||
|
model = models.EventCheckIn
|
||||||
|
template_name = 'hs/eventcheckin_form.html'
|
||||||
|
form_class = forms.EditCheckInForm
|
||||||
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
obj = self.get_object()
|
||||||
|
if not obj.person == self.request.user and not obj.event.mic == self.request.user:
|
||||||
|
return redirect(self.request.META.get('HTTP_REFERER', '/'))
|
||||||
|
return super().dispatch(request)
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return self.get_close_url('event_detail', 'event_detail') # Well, that's one way of doing that...!
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['event'] = self.object.event
|
||||||
|
context['page_title'] = f'Edit Check In for Event {context["event"].display_id}'
|
||||||
|
context['edit'] = True
|
||||||
|
# get_related(context['form'], context)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class EventCheckOut(generic.RedirectView):
|
||||||
|
def get_redirect_url(self, *args, **kwargs):
|
||||||
|
checkin = self.request.user.current_event()
|
||||||
|
if checkin:
|
||||||
|
checkin.end_time = timezone.now()
|
||||||
|
checkin.save()
|
||||||
|
return self.request.META.get('HTTP_REFERER', '/')
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ class TestAssetForm(AutoLoginTest):
|
|||||||
# self.assertTrue(self.page.parent_selector.options[0].selected)
|
# self.assertTrue(self.page.parent_selector.options[0].selected)
|
||||||
self.page.parent_selector.toggle()
|
self.page.parent_selector.toggle()
|
||||||
|
|
||||||
self.assertFalse(self.driver.find_element_by_id('cable-table').is_displayed())
|
self.assertFalse(self.driver.find_element(By.ID, 'cable-table').is_displayed())
|
||||||
|
|
||||||
self.page.submit()
|
self.page.submit()
|
||||||
self.assertTrue(self.page.success)
|
self.assertTrue(self.page.success)
|
||||||
@@ -350,7 +350,7 @@ class TestAssetAudit(AutoLoginTest):
|
|||||||
self.wait.until(ec.visibility_of_element_located((By.ID, 'modal')))
|
self.wait.until(ec.visibility_of_element_located((By.ID, 'modal')))
|
||||||
self.assertEqual(self.page.modal.asset_id, asset_row.id)
|
self.assertEqual(self.page.modal.asset_id, asset_row.id)
|
||||||
self.page.modal.close()
|
self.page.modal.close()
|
||||||
self.assertFalse(self.driver.find_element_by_id('modal').is_displayed())
|
self.assertFalse(self.driver.find_element(By.ID, 'modal').is_displayed())
|
||||||
# Make sure audit log was NOT filled out
|
# Make sure audit log was NOT filled out
|
||||||
audited = models.Asset.objects.get(asset_id=asset_row.id)
|
audited = models.Asset.objects.get(asset_id=asset_row.id)
|
||||||
assert audited.last_audited_by is None
|
assert audited.last_audited_by is None
|
||||||
|
|||||||
1193
package-lock.json
generated
1193
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -73,7 +73,7 @@ function initPicker(obj) {
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
console.log(obj.data);
|
//console.log(obj.data);
|
||||||
if (!obj.data('noclear')) {
|
if (!obj.data('noclear')) {
|
||||||
obj.prepend($("<option></option>")
|
obj.prepend($("<option></option>")
|
||||||
.attr("value",'')
|
.attr("value",'')
|
||||||
|
|||||||
@@ -30,6 +30,9 @@
|
|||||||
<body>
|
<body>
|
||||||
<a class="skip-link" href='#main'>Skip to content</a>
|
<a class="skip-link" href='#main'>Skip to content</a>
|
||||||
{% block navbar %}
|
{% block navbar %}
|
||||||
|
{% if request.user.current_event %}
|
||||||
|
<div class="bg-primary d-flex justify-content-between align-items-center"><span class="ml-2">You are currently checked in to <a href="{{request.user.current_event.event.get_absolute_url}}" class="text-white">{{request.user.current_event.event}}</a></span><a href="{% url 'event_checkout'%}" class="btn btn-warning">Check Out</a></div>
|
||||||
|
{% endif %}
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark" role="navigation">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark" role="navigation">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" style="position: absolute; left:0.5em; top: 2px;" href="{% if request.user.is_authenticated %}https://rigs.nottinghamtec.co.uk{%else%}https://nottinghamtec.co.uk{%endif%}">
|
<a class="navbar-brand" style="position: absolute; left:0.5em; top: 2px;" href="{% if request.user.is_authenticated %}https://rigs.nottinghamtec.co.uk{%else%}https://nottinghamtec.co.uk{%endif%}">
|
||||||
|
|||||||
@@ -8,6 +8,13 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<h1 class="col-sm-12 pb-3">R<small class="text-muted">ig</small> I<small class="text-muted">nformation</small> G<small class="text-muted">athering</small> S<small class="text-muted">ystem</small></h1>
|
<h1 class="col-sm-12 pb-3">R<small class="text-muted">ig</small> I<small class="text-muted">nformation</small> G<small class="text-muted">athering</small> S<small class="text-muted">ystem</small></h1>
|
||||||
<h2 class="col-sm-12 pb-3">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%}</h2>
|
<h2 class="col-sm-12 pb-3">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%}</h2>
|
||||||
|
{% if now %}
|
||||||
|
<div class="col-sm-12 alert alert-primary rounded-0 mx-auto">
|
||||||
|
{% for event in now %}
|
||||||
|
Event {{ event }} is happening now! <a href="{% url 'event_checkin' event.pk %}" class="btn btn-success btn-sm modal-href align-baseline {% if request.user.current_event %}disabled{%endif%}"><span class="fas fa-user-clock"></span> <span class="d-none d-sm-inline">Check In</span></a><br/>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="col-sm-4 mb-3">
|
<div class="col-sm-4 mb-3">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<img class="card-img-top d-none d-sm-block" src="{% static 'imgs/rigs.jpg' %}" alt="Some lights and haze, very purple" style="height: 150px; object-fit: cover;">
|
<img class="card-img-top d-none d-sm-block" src="{% static 'imgs/rigs.jpg' %}" alt="Some lights and haze, very purple" style="height: 150px; object-fit: cover;">
|
||||||
@@ -24,7 +31,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4 mb-3">
|
<div class="col-sm-4 mb-3">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
{% now "m-d" as todays_date %}
|
|
||||||
<img class="card-img-top d-none d-sm-block" src="{% if todays_date == '04-01' %}{% static 'imgs/tappytaptap.gif' %}{%else%}{% static 'imgs/assets.jpg' %}{%endif%}" alt="M32 sound desk close up of the faders" style="height: 150px; object-fit: cover;">
|
<img class="card-img-top d-none d-sm-block" src="{% if todays_date == '04-01' %}{% static 'imgs/tappytaptap.gif' %}{%else%}{% static 'imgs/assets.jpg' %}{%endif%}" alt="M32 sound desk close up of the faders" style="height: 150px; object-fit: cover;">
|
||||||
<h4 class="card-header">Asset Database</h4>
|
<h4 class="card-header">Asset Database</h4>
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
|
|||||||
@@ -50,10 +50,7 @@ class Command(BaseCommand):
|
|||||||
"add_supplier", "view_cabletype", "change_cabletype",
|
"add_supplier", "view_cabletype", "change_cabletype",
|
||||||
"add_cabletype", "view_eventchecklist", "change_eventchecklist",
|
"add_cabletype", "view_eventchecklist", "change_eventchecklist",
|
||||||
"add_eventchecklist", "view_riskassessment", "change_riskassessment",
|
"add_eventchecklist", "view_riskassessment", "change_riskassessment",
|
||||||
"add_riskassessment", "add_eventchecklistcrew", "change_eventchecklistcrew",
|
"add_riskassessment"]
|
||||||
"delete_eventchecklistcrew", "view_eventchecklistcrew", "add_eventchecklistvehicle",
|
|
||||||
"change_eventchecklistvehicle",
|
|
||||||
"delete_eventchecklistvehicle", "view_eventchecklistvehicle", ]
|
|
||||||
finance_perms = keyholder_perms + ["add_invoice", "change_invoice", "view_invoice",
|
finance_perms = keyholder_perms + ["add_invoice", "change_invoice", "view_invoice",
|
||||||
"add_payment", "change_payment", "delete_payment"]
|
"add_payment", "change_payment", "delete_payment"]
|
||||||
hs_perms = keyholder_perms + ["review_riskassessment", "review_eventchecklist"]
|
hs_perms = keyholder_perms + ["review_riskassessment", "review_eventchecklist"]
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from django.core import mail
|
|||||||
from django.test import LiveServerTestCase
|
from django.test import LiveServerTestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from selenium.webdriver.common.keys import Keys
|
from selenium.webdriver.common.keys import Keys
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
|
||||||
from PyRIGS.tests.base import create_browser
|
from PyRIGS.tests.base import create_browser
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
@@ -24,31 +25,31 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
def test_registration(self):
|
def test_registration(self):
|
||||||
# Navigate to the registration page
|
# Navigate to the registration page
|
||||||
self.browser.get(self.live_server_url + '/user/register/')
|
self.browser.get(self.live_server_url + '/user/register/')
|
||||||
title_text = self.browser.find_element_by_tag_name('h3').text
|
title_text = self.browser.find_element(By.TAG_NAME, 'h3').text
|
||||||
self.assertIn("User Registration", title_text)
|
self.assertIn("User Registration", title_text)
|
||||||
|
|
||||||
# Check the form invites correctly
|
# Check the form invites correctly
|
||||||
username = self.browser.find_element_by_id('id_username')
|
username = self.browser.find_element(By.ID, 'id_username')
|
||||||
self.assertEqual(username.get_attribute('placeholder'), 'Username')
|
self.assertEqual(username.get_attribute('placeholder'), 'Username')
|
||||||
email = self.browser.find_element_by_id('id_email')
|
email = self.browser.find_element(By.ID, 'id_email')
|
||||||
self.assertEqual(email.get_attribute('placeholder'), 'E-mail')
|
self.assertEqual(email.get_attribute('placeholder'), 'E-mail')
|
||||||
# If this is correct we don't need to test it later
|
# If this is correct we don't need to test it later
|
||||||
self.assertEqual(email.get_attribute('type'), 'email')
|
self.assertEqual(email.get_attribute('type'), 'email')
|
||||||
password1 = self.browser.find_element_by_id('id_password1')
|
password1 = self.browser.find_element(By.ID, 'id_password1')
|
||||||
self.assertEqual(password1.get_attribute('placeholder'), 'Password')
|
self.assertEqual(password1.get_attribute('placeholder'), 'Password')
|
||||||
self.assertEqual(password1.get_attribute('type'), 'password')
|
self.assertEqual(password1.get_attribute('type'), 'password')
|
||||||
password2 = self.browser.find_element_by_id('id_password2')
|
password2 = self.browser.find_element(By.ID, 'id_password2')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
password2.get_attribute('placeholder'), 'Password confirmation')
|
password2.get_attribute('placeholder'), 'Password confirmation')
|
||||||
self.assertEqual(password2.get_attribute('type'), 'password')
|
self.assertEqual(password2.get_attribute('type'), 'password')
|
||||||
first_name = self.browser.find_element_by_id('id_first_name')
|
first_name = self.browser.find_element(By.ID, 'id_first_name')
|
||||||
self.assertEqual(first_name.get_attribute('placeholder'), 'First name')
|
self.assertEqual(first_name.get_attribute('placeholder'), 'First name')
|
||||||
last_name = self.browser.find_element_by_id('id_last_name')
|
last_name = self.browser.find_element(By.ID, 'id_last_name')
|
||||||
self.assertEqual(last_name.get_attribute('placeholder'), 'Last name')
|
self.assertEqual(last_name.get_attribute('placeholder'), 'Last name')
|
||||||
initials = self.browser.find_element_by_id('id_initials')
|
initials = self.browser.find_element(By.ID, 'id_initials')
|
||||||
self.assertEqual(initials.get_attribute('placeholder'), 'Initials')
|
self.assertEqual(initials.get_attribute('placeholder'), 'Initials')
|
||||||
# No longer required for new users
|
# No longer required for new users
|
||||||
# phone = self.browser.find_element_by_id('id_phone')
|
# phone = self.browser.find_element(By.ID, 'id_phone')
|
||||||
# self.assertEqual(phone.get_attribute('placeholder'), 'Phone')
|
# self.assertEqual(phone.get_attribute('placeholder'), 'Phone')
|
||||||
|
|
||||||
# Fill the form out incorrectly
|
# Fill the form out incorrectly
|
||||||
@@ -62,21 +63,20 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
initials.send_keys('JS')
|
initials.send_keys('JS')
|
||||||
# phone.send_keys('0123456789')
|
# phone.send_keys('0123456789')
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
self.browser.switch_to.frame(self.browser.find_element_by_tag_name("iframe"))
|
self.browser.switch_to.frame(self.browser.find_element(By.TAG_NAME, "iframe"))
|
||||||
self.browser.find_element_by_id('anchor').click()
|
self.browser.find_element(By.ID, 'anchor').click()
|
||||||
self.browser.switch_to.default_content()
|
self.browser.switch_to.default_content()
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
# Submit incorrect form
|
# Submit incorrect form
|
||||||
submit = self.browser.find_element_by_xpath("//input[@type='submit']")
|
submit = self.browser.find_element(By.XPATH, "//input[@type='submit']")
|
||||||
submit.click()
|
submit.click()
|
||||||
|
|
||||||
# Restablish error fields
|
# Restablish error fields
|
||||||
password1 = self.browser.find_element_by_id('id_password1')
|
password1 = self.browser.find_element(By.ID, 'id_password1')
|
||||||
password2 = self.browser.find_element_by_id('id_password2')
|
password2 = self.browser.find_element(By.ID, 'id_password2')
|
||||||
|
|
||||||
# Read what the error is
|
# Read what the error is
|
||||||
alert = self.browser.find_element_by_css_selector(
|
alert = self.browser.find_element(By.CSS_SELECTOR, '.alert-danger').text
|
||||||
'div.alert-danger').text
|
|
||||||
# TODO Use regex matching to handle smart/unsmart quotes...
|
# TODO Use regex matching to handle smart/unsmart quotes...
|
||||||
self.assertIn("password fields didn", alert)
|
self.assertIn("password fields didn", alert)
|
||||||
|
|
||||||
@@ -92,8 +92,7 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
password2.send_keys(Keys.ENTER)
|
password2.send_keys(Keys.ENTER)
|
||||||
|
|
||||||
# Check we have a success message
|
# Check we have a success message
|
||||||
alert = self.browser.find_element_by_css_selector(
|
alert = self.browser.find_element(By.CSS_SELECTOR, '.alert-success').text
|
||||||
'div.alert-success').text
|
|
||||||
self.assertIn('register', alert)
|
self.assertIn('register', alert)
|
||||||
self.assertIn('email', alert)
|
self.assertIn('email', alert)
|
||||||
|
|
||||||
@@ -111,14 +110,14 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
self.browser.get(urls[0]) # go to the first link
|
self.browser.get(urls[0]) # go to the first link
|
||||||
|
|
||||||
# Complete registration
|
# Complete registration
|
||||||
title_text = self.browser.find_element_by_tag_name('h2').text
|
title_text = self.browser.find_element(By.TAG_NAME, 'h2').text
|
||||||
self.assertIn('Complete', title_text)
|
self.assertIn('Complete', title_text)
|
||||||
|
|
||||||
# Test login
|
# Test login
|
||||||
self.browser.get(self.live_server_url + '/user/login')
|
self.browser.get(self.live_server_url + '/user/login')
|
||||||
username = self.browser.find_element_by_id('id_username')
|
username = self.browser.find_element(By.ID, 'id_username')
|
||||||
self.assertEqual(username.get_attribute('placeholder'), 'Username')
|
self.assertEqual(username.get_attribute('placeholder'), 'Username')
|
||||||
password = self.browser.find_element_by_id('id_password')
|
password = self.browser.find_element(By.ID, 'id_password')
|
||||||
self.assertEqual(password.get_attribute('placeholder'), 'Password')
|
self.assertEqual(password.get_attribute('placeholder'), 'Password')
|
||||||
self.assertEqual(password.get_attribute('type'), 'password')
|
self.assertEqual(password.get_attribute('type'), 'password')
|
||||||
|
|
||||||
@@ -132,8 +131,7 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
self.assertFalse(profileObject.is_approved)
|
self.assertFalse(profileObject.is_approved)
|
||||||
|
|
||||||
# Read what the error is
|
# Read what the error is
|
||||||
alert = self.browser.find_element_by_css_selector(
|
alert = self.browser.find_element(By.CSS_SELECTOR, 'div.alert-danger').text
|
||||||
'div.alert-danger').text
|
|
||||||
self.assertIn("approved", alert)
|
self.assertIn("approved", alert)
|
||||||
|
|
||||||
# Approve the user so we can proceed
|
# Approve the user so we can proceed
|
||||||
@@ -142,14 +140,14 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
|
|
||||||
# Retry login
|
# Retry login
|
||||||
self.browser.get(self.live_server_url + '/user/login')
|
self.browser.get(self.live_server_url + '/user/login')
|
||||||
username = self.browser.find_element_by_id('id_username')
|
username = self.browser.find_element(By.ID, 'id_username')
|
||||||
username.send_keys('TestUsername')
|
username.send_keys('TestUsername')
|
||||||
password = self.browser.find_element_by_id('id_password')
|
password = self.browser.find_element(By.ID, 'id_password')
|
||||||
password.send_keys('correcthorsebatterystaple')
|
password.send_keys('correcthorsebatterystaple')
|
||||||
password.send_keys(Keys.ENTER)
|
password.send_keys(Keys.ENTER)
|
||||||
|
|
||||||
# Check we are logged in
|
# Check we are logged in
|
||||||
udd = self.browser.find_element_by_class_name('navbar').text
|
udd = self.browser.find_element(By.CLASS_NAME, 'navbar').text
|
||||||
self.assertIn('Hi John', udd)
|
self.assertIn('Hi John', udd)
|
||||||
|
|
||||||
# Check all the data actually got saved
|
# Check all the data actually got saved
|
||||||
|
|||||||
Reference in New Issue
Block a user