Compare commits

...

9 Commits

Author SHA1 Message Date
ea66342aa4 Fix cable type detail 2021-01-31 03:49:57 +00:00
add06431ce Fix more HTML 2021-01-31 03:35:35 +00:00
ca246ec80e Port title test to project level 2021-01-31 02:12:12 +00:00
c0af121f98 Fix some HTML errors in templates
Which apparently only Django's HTML parser cares about, browsers DGAF...
2021-01-31 02:06:46 +00:00
d1efe1dbc8 Add RAs/Checklists to sample data generator 2021-01-31 02:06:42 +00:00
a2b253a808 Refactor 'no access to unauthed' test to cover all of PyRIGS 2021-01-31 01:07:52 +00:00
4434a2bc80 Fix IDI0T error in Assets URLS 2021-01-31 01:06:02 +00:00
6dbec5f510 Made versioning magic a bit less expansive
We have more apps than I thought...
2021-01-30 19:06:04 +00:00
d0f6518803 Fix search_help to need login 2021-01-30 18:33:34 +00:00
33 changed files with 2966 additions and 2897 deletions

View File

@@ -1,3 +1,4 @@
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.http import HttpResponseRedirect
from django.shortcuts import render
@@ -15,11 +16,7 @@ def get_oembed(login_url, request, oembed_view, kwargs):
return resp
def has_oembed(oembed_view, login_url=None):
if not login_url:
from django.conf import settings
login_url = settings.LOGIN_URL
def has_oembed(oembed_view, login_url=settings.LOGIN_URL):
def _dec(view_func):
def _checklogin(request, *args, **kwargs):
if request.user.is_authenticated:

65
PyRIGS/tests/test_unit.py Normal file
View File

@@ -0,0 +1,65 @@
from PyRIGS import urls
from assets.tests.test_unit import create_asset_one
import pytest
from django.urls import URLPattern, URLResolver, reverse
from django.urls.exceptions import NoReverseMatch
from pytest_django.asserts import assertContains, assertRedirects, assertTemplateUsed, assertInHTML
pytestmark = pytest.mark.django_db
def find_urls_recursive(patterns):
urls_to_check = []
for url in patterns:
if isinstance(url, URLResolver):
urls_to_check += find_urls_recursive(url.url_patterns)
elif isinstance(url, URLPattern):
# Skip some thinks that actually don't need auth (mainly OEmbed JSONs that are essentially just a redirect)
if url.name is not None and url.name != "closemodal" and "json" not in str(url):
urls_to_check.append(url)
return urls_to_check
def get_request_url(url):
pattern = str(url.pattern)
request_url = ""
try:
kwargz = {}
if ":pk>" in pattern:
kwargz['pk'] = 1
if ":model>" in pattern:
kwargz['model'] = "event"
return reverse(url.name, kwargs=kwargz)
except NoReverseMatch:
print("Couldn't test url " + pattern)
def test_unauthenticated(client): # Nothing should be available to the unauthenticated
create_asset_one()
for url in find_urls_recursive(urls.urlpatterns):
request_url = get_request_url(url)
if request_url and 'user' not in request_url: # User module is full of edge cases
response = client.get(request_url, follow=True, HTTP_HOST='example.com')
assertContains(response, 'Login')
if 'application/json+oembed' in response.content.decode():
assertTemplateUsed(response, 'login_redirect.html')
else:
if "embed" in str(url):
expected_url = "{0}?next={1}".format(reverse('login_embed'), request_url)
else:
expected_url = "{0}?next={1}".format(reverse('login'), request_url)
assertRedirects(response, expected_url)
def test_page_titles(admin_client):
create_asset_one()
for url in filter((lambda u: "embed" not in u.name), find_urls_recursive(urls.urlpatterns)):
request_url = get_request_url(url)
response = admin_client.get(request_url)
if hasattr(response, "context_data") and "page_title" in response.context_data:
expected_title = response.context_data["page_title"]
# try:
assertInHTML('<title>{} | Rig Information Gathering System'.format(expected_title), response.content.decode())
print("{} | {}".format(request_url, expected_title)) # If test fails, tell me where!
# except:
# print(response.content.decode(), file=open('output.html', 'w'))

View File

@@ -3,7 +3,7 @@ from django.conf.urls import include
from django.contrib import admin
from django.contrib.auth.decorators import login_required
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.urls import path, re_path
from django.urls import path
from django.views.generic import TemplateView
from PyRIGS import views
@@ -22,7 +22,7 @@ urlpatterns = [
name="api_secure"),
path('closemodal/', views.CloseModal.as_view(), name='closemodal'),
path('search_help/', views.SearchHelp.as_view(), name='search_help'),
path('search_help/', login_required(views.SearchHelp.as_view()), name='search_help'),
path('', include('users.urls')),
@@ -34,6 +34,6 @@ if settings.DEBUG:
import debug_toolbar
urlpatterns = [
re_path(r'^__debug__/', include(debug_toolbar.urls)),
path('__debug__/', include(debug_toolbar.urls)),
path('bootstrap/', TemplateView.as_view(template_name="bootstrap.html")),
] + urlpatterns

View File

@@ -4,6 +4,7 @@ import random
from django.contrib.auth.models import Group, Permission
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.utils import timezone
from reversion import revisions as reversion
from RIGS import models
@@ -343,3 +344,30 @@ class Command(BaseCommand):
elif random.randint(0, 2) > 1: # 1 in 3 have been paid
models.Payment.objects.create(invoice=newInvoice, amount=newInvoice.balance,
date=datetime.date.today())
if i == 1 or random.randint(0, 5) > 0: # Event 1 and 1 in 5 have a RA
models.RiskAssessment.objects.create(event=newEvent, supervisor_consulted=bool(random.getrandbits(1)), nonstandard_equipment=bool(random.getrandbits(1)),
nonstandard_use=bool(random.getrandbits(1)),
contractors=bool(random.getrandbits(1)),
other_companies=bool(random.getrandbits(1)),
crew_fatigue=bool(random.getrandbits(1)),
big_power=bool(random.getrandbits(1)),
generators=bool(random.getrandbits(1)),
other_companies_power=bool(random.getrandbits(1)),
nonstandard_equipment_power=bool(random.getrandbits(1)),
multiple_electrical_environments=bool(random.getrandbits(1)),
noise_monitoring=bool(random.getrandbits(1)),
known_venue=bool(random.getrandbits(1)),
safe_loading=bool(random.getrandbits(1)),
safe_storage=bool(random.getrandbits(1)),
area_outside_of_control=bool(random.getrandbits(1)),
barrier_required=bool(random.getrandbits(1)),
nonstandard_emergency_procedure=bool(random.getrandbits(1)),
special_structures=bool(random.getrandbits(1)),
suspended_structures=bool(random.getrandbits(1)),
outside=bool(random.getrandbits(1)))
if i == 0 or random.randint(0, 1) > 0: # Event 1 and 1 in 10 have a Checklist
models.EventChecklist.objects.create(event=newEvent, power_mic=random.choice(self.profiles), safe_parking=bool(random.getrandbits(1)),
safe_packing=bool(random.getrandbits(1)), exits=bool(random.getrandbits(1)), trip_hazard=bool(random.getrandbits(1)), warning_signs=bool(random.getrandbits(1)),
ear_plugs=bool(random.getrandbits(1)), hs_location="Locked away safely",
extinguishers_location="Somewhere, I forgot", earthing=bool(random.getrandbits(1)), pat=bool(random.getrandbits(1)),
date=timezone.now(), venue=random.choice(self.venues))

View File

@@ -235,7 +235,6 @@
</div>
{% endif %}
</div>
</div>
<div class="col-12 text-right">
{% button 'edit' url='ec_edit' pk=object.pk %}
{% button 'view' url='event_detail' pk=object.pk text="Event" %}

View File

@@ -32,9 +32,9 @@
$(document).ready(function () {
$('button[data-action=add]').on('click', function (event) {
event.preventDefault();
var target = $($(this).attr('data-target'));
var newID = Number(target.attr('data-pk'));
var newRow = $($(this).attr('data-clone'))
let target = $($(this).attr('data-target'));
let newID = Number(target.attr('data-pk'));
let newRow = $($(this).attr('data-clone'))
.clone().attr('style', "")
.attr('id', function(i, val){
return val.split("_")[0] + '_' + newID;
@@ -135,7 +135,7 @@
<tr id="vehicles_new" style="display: none;">
<td><input type="text" class="form-control" name="vehicle_new" disabled="true"/></td>
<td><select class="form-control" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" name="driver_new" disabled="true"></select></td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-action='delete' data-target='#vehicle'><span class="fas fa-times"></span></button</td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-action='delete' data-target='#vehicle'><span class="fas fa-times"></span></button></td>
</tr>
{% for i in object.vehicles.all %}
<tr id="vehicles_{{i.pk}}">
@@ -147,7 +147,7 @@
{% endif %}
</select>
</td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-id='{{i.pk}}' data-action='delete' data-target='#vehicle'><span class="fas fa-times"></span></button</td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-id='{{i.pk}}' data-action='delete' data-target='#vehicle'><span class="fas fa-times"></span></button></td>
</tr>
{% endfor %}
</tbody>
@@ -204,10 +204,10 @@
<td>
<select name="crewmember_new" class="form-control" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" disabled="true"></select>
</td>
<td style="min-width: 15ch"><input name="start_new" type="datetime-local" class="form-control" value="{{ i.start }}" disabled="true"/></td>
<td style="min-width: 15ch"><input name="start_new" type="datetime-local" class="form-control" value="{{ i.start }}" disabled=""/></td>
<td style="min-width: 15ch"><input name="role_new" type="text" class="form-control" value="{{ i.role }}" disabled="true"/></td>
<td style="min-width: 15ch"><input name="end_new" type="datetime-local" class="form-control" value="{{ i.end }}" disabled="true" /></td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-id='{{crew.pk}}' data-action='delete' data-target='#crewmember'><span class="fas fa-times"></span></button</td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-id='{{crew.pk}}' data-action='delete' data-target='#crewmember'><span class="fas fa-times"></span></button></td>
</tr>
{% for crew in object.crew.all %}
<tr id="crew_{{crew.pk}}">
@@ -221,7 +221,7 @@
<td><input name="start_{{crew.pk}}" type="datetime-local" class="form-control" value="{{ crew.start|date:'Y-m-d' }}T{{ crew.start|date:'H:i:s' }}"/></td>
<td><input name="role_{{crew.pk}}" type="text" class="form-control" value="{{ crew.role }}"/></td>
<td><input name="end_{{crew.pk}}" type="datetime-local" class="form-control" value="{{ crew.end|date:'Y-m-d' }}T{{ crew.end|date:'H:i:s' }}"/></td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-id='{{crew.pk}}' data-action='delete' data-target='#crewmember'><span class="fas fa-times"></span></button</td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-id='{{crew.pk}}' data-action='delete' data-target='#crewmember'><span class="fas fa-times"></span></button></td>
</tr>
{% endfor %}
</tbody>
@@ -240,7 +240,7 @@
<div class="row my-3" id="size-0">
<div class="col-12">
<div class="card border-success">
<div class="card-header">Electrical Checks <small>for Small TEC Events <6kVA (aprox. 26A)</small></div>
<div class="card-header">Electrical Checks <small>for Small TEC Events <6kVA (approx. 26A)</small></div>
<div class="card-body">
{% include 'partials/checklist_checkbox.html' with formitem=form.rcds %}
{% include 'partials/checklist_checkbox.html' with formitem=form.supply_test %}
@@ -337,7 +337,7 @@
</tbody>
</table>
</div>
<hr>
<hr/>
{% include 'partials/checklist_checkbox.html' with formitem=form.all_rcds_tested %}
{% include 'partials/checklist_checkbox.html' with formitem=form.public_sockets_tested %}
{% include 'partials/ec_power_info.html' %}

View File

@@ -38,7 +38,7 @@
<dt class="col-sm-6">Email</dt>
<dd class="col-sm-6">{{ object.person.email|linkornone:'mailto' }}</dd>
<dt class="col-sm-6">Phone Number</dt>
<dd class="col-sm-6">{{ object.person.phone|linkornone:'tel' }}</a></dd>
<dd class="col-sm-6">{{ object.person.phone|linkornone:'tel' }}</dd>
</dl>
</div>
</div>
@@ -59,7 +59,7 @@
<dt class="col-sm-6">Email</dt>
<dd class="col-sm-6">{{ object.organisation.email|linkornone:'mailto' }}</dd>
<dt class="col-sm-6">Phone Number</dt>
<dd class="col-sm-6">{{ object.organisation.phone|linkornone:'tel' }}</a></dd>
<dd class="col-sm-6">{{ object.organisation.phone|linkornone:'tel' }}</dd>
<dt class="col-sm-6">Has SU Account</dt>
<dd class="col-sm-6">{{ event.organisation.union_account|yesno|capfirst }}</dd>
</dl>

View File

@@ -2,14 +2,14 @@
{% load static %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<a href="/">
<span class="source"> R<small>ig</small> I<small>nformation</small> G<small>athering</small> S<small>ystem</small></span>
</a>
</div>
<div class="row">
<div class="col-sm-12">
<a href="/">
<span class="source"> R<small>ig</small> I<small>nformation</small> G<small>athering</small> S<small>ystem</small></span>
</a>
</div>
<div class="col-sm-12">
<div class="col-sm-12">
<span class="pull-right">
{% if object.mic %}
<div class="text-center">
@@ -20,82 +20,81 @@
{% endif %}
</span>
<h3>
<a href="{% url 'event_detail' object.pk %}">
{% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %}
| {{ object.name }} </a>
<h3>
<a href="{% url 'event_detail' object.pk %}">
{% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %}
| {{ object.name }} </a>
{% if object.venue %}
<small>at {{ object.venue }}</small>
<small>at {{ object.venue }}</small>
{% endif %}
<br/><small>
{{ object.start_date|date:"D d/m/Y" }}
{% if object.has_start_time %}
{{ object.start_time|date:"H:i" }}
{% endif %}
{% if object.end_date or object.has_end_time %}
&ndash;
{% endif %}
{% if object.end_date and object.end_date != object.start_date %}
{{ object.end_date|date:"D d/m/Y" }}
{% endif %}
{% if object.has_end_time %}
{{ object.end_time|date:"H:i" }}
{% endif %}
<br/><small>
{{ object.start_date|date:"D d/m/Y" }}
{% if object.has_start_time %}
{{ object.start_time|date:"H:i" }}
{% endif %}
{% if object.end_date or object.has_end_time %}
&ndash;
{% endif %}
{% if object.end_date and object.end_date != object.start_date %}
{{ object.end_date|date:"D d/m/Y" }}
{% endif %}
{% if object.has_end_time %}
{{ object.end_time|date:"H:i" }}
{% endif %}
</small>
</h3>
</h3>
<div class="row">
<div class="col-xs-6">
<p>
<strong>Status:</strong>
{{ object.get_status_display }}
</p>
<p>
{% if object.is_rig %}
<strong>Client:</strong> {{ object.person.name }}
{% if object.organisation %}
for {{ object.organisation.name }}
<div class="row">
<div class="col-xs-6">
<p>
<strong>Status:</strong>
{{ object.get_status_display }}
</p>
<p>
{% if object.is_rig %}
<strong>Client:</strong> {{ object.person.name }}
{% if object.organisation %}
for {{ object.organisation.name }}
{% endif %}
{% if object.dry_hire %}(Dry Hire){% endif %}
{% else %}
<strong>Non-Rig</strong>
{% endif %}
{% if object.dry_hire %}(Dry Hire){% endif %}
{% else %}
<strong>Non-Rig</strong>
{% endif %}
</p>
<p>
<strong>MIC:</strong>
{% if object.mic %}
{{object.mic.name}}
{% else %}
None
{% endif %}
</p>
</div>
<div class="col-xs-6">
{% if object.meet_at %}
<p>
<strong>Crew meet:</strong>
{{ object.meet_at|date:"H:i" }} {{ object.meet_at|date:"(Y-m-d)" }}
</p>
{% endif %}
{% if object.access_at %}
<p>
<strong>Access at:</strong>
{{ object.access_at|date:"H:i" }} {{ object.access_at|date:"(Y-m-d)" }}
<strong>MIC:</strong>
{% if object.mic %}
{{object.mic.name}}
{% else %}
None
{% endif %}
</p>
{% endif %}
<p>
<strong>Last updated:</strong>
{{ object.last_edited_at }} by "{{ object.last_edited_by.initials }}"
</p>
</div>
<div class="col-xs-6">
{% if object.meet_at %}
<p>
<strong>Crew meet:</strong>
{{ object.meet_at|date:"H:i" }} {{ object.meet_at|date:"(Y-m-d)" }}
</p>
{% endif %}
{% if object.access_at %}
<p>
<strong>Access at:</strong>
{{ object.access_at|date:"H:i" }} {{ object.access_at|date:"(Y-m-d)" }}
</p>
{% endif %}
<p>
<strong>Last updated:</strong>
{{ object.last_edited_at }} by "{{ object.last_edited_by.initials }}"
</p>
</div>
</div>
{% if object.description %}
<p>
<strong>Description: </strong>
{{ object.description|linebreaksbr }}
</p>
{% endif %}
</div>
{% if object.description %}
<p>
<strong>Description: </strong>
{{ object.description|linebreaksbr }}
</p>
{% endif %}
</table>
</div>
</div>
{% endblock %}

View File

@@ -36,6 +36,7 @@
<p>Your event will not be booked until you complete this form.</p>
<p>TEC PA &amp; Lighting<br/>
<p>TEC PA &amp; Lighting</p>
<br/>
{% endblock %}

View File

@@ -60,10 +60,10 @@
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Date</td>
<th scope="col">Amount</td>
<th scope="col">Method</td>
<th scope="col"></td>
<th scope="col">Date</th>
<th scope="col">Amount</th>
<th scope="col">Method</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@@ -73,7 +73,7 @@
<td>{{ payment.amount|floatformat:2 }}</td>
<td>{{ payment.get_method_display }}</td>
<td>
<a href="{% url 'payment_delete' payment.pk %}" class="btn btn-small btn-danger"><span class="fas fa-times"</a>
<a href="{% url 'payment_delete' payment.pk %}" class="btn btn-small btn-danger"><span class="fas fa-times"></span></a>
</td>
</tr>
{% endfor %}

View File

@@ -27,7 +27,7 @@
<span class="text-muted">{% if invoice.void %}(VOID){% elif invoice.is_closed %}(PAID){% else %}(O/S){% endif %}</span></th>
<td><a href="{% url 'event_detail' invoice.event.pk %}">N{{ invoice.event.pk|stringformat:"05d" }}</a>: {{ invoice.event.name }} <br>
<span class="text-muted">{{ invoice.event.get_status_display }}{% if not invoice.event.mic %}, No MIC{% endif %}
</span></td>
</span>
</td>
<td>{% if invoice.event.organisation %}
{{ invoice.event.organisation.name }}

View File

@@ -20,6 +20,7 @@
<tr>
<td>300</td>
<td>167</td>
</tr>
<tr>
<td>500</td>
<td>100</td>

View File

@@ -5,8 +5,8 @@
{% load linkornone from filters %}
{% block content %}
<div class="row py-3">
<div class="col-12">
<div class="row py-3">
<div class="col-12">
<h3>Risk Assessment for Event N{{ object.event.pk|stringformat:"05d" }} {{ object.event.name }}</h3>
<div class="card card-default mb-3">
<div class="card-header">General</div>
@@ -152,13 +152,12 @@
</div>
</div>
</div>
<div class="col-12 text-right">
<a href="{% url 'ra_edit' object.pk %}" class="btn btn-warning my-3"><span class="fas fa-edit"></span> <span
class="d-none d-sm-inline">Edit</span></a>
<a href="{% url 'event_detail' object.event.pk %}" class="btn btn-primary"><span class="fas fa-eye"></span> View Event</a>
{{ object.review_string|safe }}
{% include 'partials/last_edited.html' with target="riskassessment_history" %}
</div>
</div>
<div class="col-12 text-right">
<a href="{% url 'ra_edit' object.pk %}" class="btn btn-warning my-3"><span class="fas fa-edit"></span> <span
class="d-none d-sm-inline">Edit</span></a>
<a href="{% url 'event_detail' object.event.pk %}" class="btn btn-primary"><span class="fas fa-eye"></span> View Event</a>
{{ object.review_string|safe }}
{% include 'partials/last_edited.html' with target="riskassessment_history" %}
</div>
</div>
{% endblock %}

View File

@@ -40,8 +40,8 @@
<div class="form-group form-row">
{% include 'partials/form_field.html' with field=form.date_acquired col="col-6" %}
<div class="col-sm-4">
<btn class="btn btn-info" onclick="setAcquired(true);" tabindex="-1">Today</btn>
<btn class="btn btn-warning" onclick="setAcquired(false);" tabindex="-1">Unknown</btn>
<button class="btn btn-info" onclick="setAcquired(true);" tabindex="-1">Today</button>
<button class="btn btn-warning" onclick="setAcquired(false);" tabindex="-1">Unknown</button>
</div>
</div>
<div class="form-group form-row">
@@ -64,16 +64,16 @@
<div class="form-group form-row">
{% include 'partials/form_field.html' with field=form.length append=form.length.help_text col="col-6" %}
<div class="col-4">
<btn class="btn btn-danger" onclick="setFieldValue('{{ form.length.id_for_label }}','5');" tabindex="-1">5{{ form.length.help_text }}</btn>
<btn class="btn btn-success" onclick="setFieldValue('{{ form.length.id_for_label }}','10');" tabindex="-1">10{{ form.length.help_text }}</btn>
<btn class="btn btn-info" onclick="setFieldValue('{{ form.length.id_for_label }}','20');" tabindex="-1">20{{ form.length.help_text }}</btn>
<button class="btn btn-danger" onclick="setFieldValue('{{ form.length.id_for_label }}','5');" tabindex="-1">5{{ form.length.help_text }}</button>
<button class="btn btn-success" onclick="setFieldValue('{{ form.length.id_for_label }}','10');" tabindex="-1">10{{ form.length.help_text }}</button>
<button class="btn btn-info" onclick="setFieldValue('{{ form.length.id_for_label }}','20');" tabindex="-1">20{{ form.length.help_text }}</button>
</div>
</div>
<div class="form-group form-row">
{% include 'partials/form_field.html' with field=form.csa append=form.csa.help_text title='CSA' col="col-6" %}
<div class="col-4">
<btn class="btn btn-secondary" onclick="setFieldValue('{{ form.csa.id_for_label }}', '1.5');" tabindex="-1">1.5{{ form.csa.help_text }}</btn>
<btn class="btn btn-secondary" onclick="setFieldValue('{{ form.csa.id_for_label }}', '2.5');" tabindex="-1">2.5{{ form.csa.help_text }}</btn>
<button class="btn btn-secondary" onclick="setFieldValue('{{ form.csa.id_for_label }}', '1.5');" tabindex="-1">1.5{{ form.csa.help_text }}</button>
<button class="btn btn-secondary" onclick="setFieldValue('{{ form.csa.id_for_label }}', '2.5');" tabindex="-1">2.5{{ form.csa.help_text }}</button>
</div>
</div>
</div>

View File

@@ -2,37 +2,35 @@
{% load static %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<a href="/assets">
<span class="source"> TEC Asset Database</span>
</a>
<div class="row">
<div class="col-sm-12">
<a href="/assets">
<span class="source"> TEC Asset Database</span>
</a>
</div>
<div class="col-sm-12">
<h3><a href="{% url 'asset_detail' object.asset_id %}">Asset: {{ object.asset_id }} | {{ object.description }} </a></h3>
<h4>
<span class="label label-default">
<strong>Category:</strong>
{{ object.category }}
</span>
&nbsp;
<span class="label label-{{ object.status.display_class|default:'default' }}">
<strong>Status:</strong>
{{ object.status }}
</span>
</h4>
<dl>
{% if object.serial_number %}
<dt>Serial Number: </dt>
<dd>{{ object.serial_number }}</dd>
{% endif %}
{% if object.comments %}
<dt>Comments: </dt>
<dd class="dont-break-out">{{ object.comments|linebreaksbr }}<dd>
{% endif %}
</dl>
</div>
</div>
<div class="col-sm-12">
<h3><a href="{% url 'asset_detail' object.asset_id %}">Asset: {{ object.asset_id }} | {{ object.description }} </a></h3>
<h4>
<span class="label label-default">
<strong>Category:</strong>
{{ object.category }}
</span>
&nbsp;
<span class="label label-{{ object.status.display_class|default:'default' }}">
<strong>Status:</strong>
{{ object.status }}
</span>
</h4>
<dl>
{% if object.serial_number %}
<dt>Serial Number: </dt>
<dd>{{ object.serial_number }}</dd>
{% endif %}
{% if object.comments %}
<dt>Comments: </dt>
<dd class="dont-break-out">{{ object.comments|linebreaksbr }}<dd>
{% endif %}
</dl>
</table>
</div>
</div>
{% endblock %}

View File

@@ -33,7 +33,7 @@
url: '{% url 'asset_search_json' %}',
type: "GET",
data: function () {
var params = {
let params = {
{% verbatim %}query: '{{{q}}}'{% endverbatim %}
};
return params;

View File

@@ -0,0 +1,40 @@
{% extends 'base_assets.html' %}
{% load button from filters %}
{% load cache %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<div class="col">
<div class="card">
<dl class="card-body row">
<dt class="col-6">Socket</dt>
<dd>{{ object.socket|default_if_none:'-' }}</dd>
<dt class="col-6">Plug</dt>
<dd>{{ object.plug|default_if_none:'-' }}</dd>
<dt class="col-6">Circuits</dt>
<dd>{{ object.circuits|default_if_none:'-' }}</dd>
<dt class="col-6">Cores</dt>
<dd>{{ object.cores|default_if_none:'-' }}</dd>
</dl>
</div>
</div>
<div class="col mt-2 text-right">
{% button 'edit' url='cable_type_update' pk=object.id %}
</div>
{% cache None cable_type_assets object %}
<div class="col mt-2">
<div class="card">
<div class="card-header">Associated Assets</div>
{% with object.asset_set.all as object_list %}
{% include 'partials/asset_list_table.html' %}
{% endwith %}
</div>
</div>
{% endcache %}
</div>
</div>
{% endblock %}

View File

@@ -4,58 +4,25 @@
{% load cache %}
{% block content %}
{% if create %}
<form method="POST" action="{% url 'cable_type_create'%}">
{% elif edit %}
<form method="POST" action="{% url 'cable_type_update' object.id %}">
{% endif %}
{% if create %}
<form method="POST" action="{% url 'cable_type_create'%}">
{% elif edit %}
<form method="POST" action="{% url 'cable_type_update' object.id %}">
{% endif %}
{% include 'form_errors.html' %}
{% csrf_token %}
<input type="hidden" name="id" value="{{ object.id|default:0 }}" hidden=true>
<input type="hidden" name="id" value="{{ object.id|default:0 }}" hidden="">
<div class="row">
<div class="col-sm-12">
{% if create or edit %}
{% for field in form %}
<div class="form-group">
{% include 'partials/form_field.html' with field=field %}
</div>
{% endfor %}
<div class="text-right">
{% button 'submit' %}
</div>
{% else %}
<div class="col">
<div class="card">
<dl class="card-body row">
<dt class="col-6">Socket</dt>
<dd>{{ object.socket|default_if_none:'-' }}</dd>
<dt class="col-6">Plug</dt>
<dd>{{ object.plug|default_if_none:'-' }}</dd>
<dt class="col-6">Circuits</dt>
<dd>{{ object.circuits|default_if_none:'-' }}</dd>
<dt class="col-6">Cores</dt>
<dd>{{ object.cores|default_if_none:'-' }}</dd>
</dl>
<div class="col-sm-12">
{% for field in form %}
<div class="form-group">
{% include 'partials/form_field.html' with field=field %}
</div>
{% endfor %}
<div class="text-right">
{% button 'submit' %}
</div>
</div>
<div class="col mt-2 text-right">
{% button 'edit' url='cable_type_update' pk=object.id %}
</div>
{% cache None cable_type_assets object %}
<div class="col mt-2">
<div class="card">
<div class="card-header">Associated Assets</div>
{% with object.asset_set.all as object_list %}
{% include 'partials/asset_list_table.html' %}
{% endwith %}
</div>
</div>
{% endcache %}
{% endif %}
</div>
</div>
</form>
{% endblock %}

View File

@@ -214,21 +214,6 @@ def create_asset_one():
return models.Asset.objects.create(asset_id="1", description="Half Price Fish", status=status, category=category, date_acquired=datetime.date(2020, 2, 1))
def test_unauthenticated(client): # Nothing should be available to the unauthenticated
create_asset_one()
for url in filter(lambda url: url.name is not None and "json" not in str(url), urls.urlpatterns):
pattern = str(url.pattern)
if ":pk>" in pattern:
request_url = reverse(url.name, kwargs={'pk': 1})
else:
request_url = reverse(url.name)
if request_url:
print(request_url)
response = client.get(request_url, follow=True, HTTP_HOST='example.com')
# TODO Check the URL here
assertContains(response, 'Login')
def test_basic_access(client):
create_asset_one()
client.login(username="basic", password="basic")
@@ -273,16 +258,3 @@ def test_keyholder_access(client):
response = client.get(url)
assertContains(response, 'Purchase Details')
assertContains(response, 'View Revision History')
def test_page_titles(admin_client):
for url in filter(lambda url: url.name is not None and not any(s in url.name for s in ["json", "embed"]), urls.urlpatterns):
request_url = ""
if ":pk>" in str(url.pattern):
request_url = reverse(url.name, kwargs={'pk': "1"})
else:
request_url = reverse(url.name)
response = admin_client.get(request_url)
if hasattr(response, "context_data") and "page_title" in response.context_data:
expected_title = response.context_data["page_title"]
assertContains(response, '<title>{} | Rig Information Gathering System</title>'.format(expected_title))

View File

@@ -16,12 +16,12 @@ urlpatterns = [
path('asset/id/<str:pk>/duplicate/', permission_required_with_403('assets.add_asset')
(views.AssetDuplicate.as_view()), name='asset_duplicate'),
path('cabletype/list/', views.CableTypeList.as_view(), name='cable_type_list'),
path('cabletype/list/', login_required(views.CableTypeList.as_view()), name='cable_type_list'),
path('cabletype/create/', permission_required_with_403('assets.add_cable_type')(views.CableTypeCreate.as_view()), name='cable_type_create'),
path('cabletype/<int:pk>/update/', permission_required_with_403('assets.change_cable_type')(views.CableTypeUpdate.as_view()), name='cable_type_update'),
path('cabletype/<int:pk>/detail/', views.CableTypeDetail.as_view(), name='cable_type_detail'),
path('cabletype/<int:pk>/detail/', login_required(views.CableTypeDetail.as_view()), name='cable_type_detail'),
path('asset/search/', views.AssetSearch.as_view(), name='asset_search_json'),
path('asset/search/', login_required(views.AssetSearch.as_view()), name='asset_search_json'),
path('asset/id/<str:pk>/embed/',
xframe_options_exempt(
login_required(login_url='/user/login/embed/')(views.AssetEmbed.as_view())),
@@ -33,12 +33,12 @@ urlpatterns = [
path('asset/audit/', permission_required_with_403('assets.change_asset')(views.AssetAuditList.as_view()), name='asset_audit_list'),
path('asset/id/<str:pk>/audit/', permission_required_with_403('assets.change_asset')(views.AssetAudit.as_view()), name='asset_audit'),
path('supplier/list/', views.SupplierList.as_view(), name='supplier_list'),
path('supplier/<int:pk>/', views.SupplierDetail.as_view(), name='supplier_detail'),
path('supplier/list/', login_required(views.SupplierList.as_view()), name='supplier_list'),
path('supplier/<int:pk>/', login_required(views.SupplierDetail.as_view()), name='supplier_detail'),
path('supplier/create/', permission_required_with_403('assets.add_supplier')
(views.SupplierCreate.as_view()), name='supplier_create'),
path('supplier/<int:pk>/edit/', permission_required_with_403('assets.change_supplier')
(views.SupplierUpdate.as_view()), name='supplier_update'),
path('supplier/search/', views.SupplierSearch.as_view(), name='supplier_search_json'),
path('supplier/search/', login_required(views.SupplierSearch.as_view()), name='supplier_search_json'),
]

View File

@@ -314,7 +314,7 @@ class CableTypeList(generic.ListView):
class CableTypeDetail(generic.DetailView):
model = models.CableType
template_name = 'cable_type_form.html'
template_name = 'cable_type_detail.html'
def get_context_data(self, **kwargs):
context = super(CableTypeDetail, self).get_context_data(**kwargs)

View File

@@ -1,5 +1,4 @@
[pytest]
DJANGO_SETTINGS_MODULE = PyRIGS.settings
# FAIL_INVALID_TEMPLATE_VARS = True
filterwarnings =
ignore:.*site-packages.*:DeprecationWarning

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@
<table class="table table-striped">
<thead>
<tr>
<th scope="col">Name<a href="?{% orderby request 'orderBy' 'name' %}"><span class="caret"></span></a></td>
<th scope="col">Name<a href="?{% orderby request 'orderBy' 'name' %}"><span class="caret"></span></a></th>
<th scope="col">Email</th>
<th scope="col">Phone</th>
<th scope="col">Notes</th>

View File

@@ -5,7 +5,7 @@
{% block content %}
<div class="row">
<h1 class="col-sm-12 pb-3">R<small class="text-muted">ig</small> I<small class="text-muted">nformation</small class="text-muted"> 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>
<h4 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%}</h4>
<div class="col-sm mb-3">
<div class="card">

View File

@@ -1,33 +1,32 @@
{% extends "base_rigs.html" %}
{% load widget_tweaks %}
{% block title %}Change Password{% endblock %}
{% block content %}
<div class="col-sm-10 col-sm-offset-1">
<h3>Change Password</h3>
{% if form.errors or supplement_form.errors %}
<div class="alert alert-danger">
Please correct the error(s) below.
{{form.errors}}
{{supplement_form.errors}}
</div>
{% endif %}
<p>Please enter your old password, for security's sake, and then enter your new password twice, so we can verify you typed it in correctly.</p>
<div class="col-sm-10 col-sm-offset-1">
<h3>Change Password</h3>
{% if form.errors or supplement_form.errors %}
<div class="alert alert-danger">
Please correct the error(s) below.
{{form.errors}}
{{supplement_form.errors}}
</div>
{% endif %}
<p>Please enter your old password, for security's sake, and then enter your new password twice so we can verify you typed it in correctly.</p>
<div class="col-sm-8 col-sm-offset-2">
<form action="" method="post" class="" role="form">{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}" class="col-form-label col-sm-4">{{ field.label }}</label>
<div class="controls col-sm-8">
{% render_field field class+="form-control" placeholder=field.label %}
</div>
</div>
{% endfor %}
<p><input type="submit" value="Change Password" class="btn btn-primary pull-right"></p>
</form>
<div class="col-sm-8 col-sm-offset-2">
<form action="" method="post" class="" role="form">{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}" class="col-form-label col-sm-4">{{ field.label }}</label>
<div class="controls col-sm-8">
{% render_field field class+="form-control" placeholder=field.label %}
</div>
</div>
{% endfor %}
<p><input type="submit" value="Change Password" class="btn btn-primary pull-right"></p>
</form>
</div>
</div>
{% endblock %}

View File

@@ -9,26 +9,26 @@
<script src="{% static 'js/clipboard.min.js' %}"></script>
<script>
$(document).ready(function() {
$('#urlParamForm').change(function(){
url = "?";
$('#urlParamForm *').filter(':input').each(function(index, value){
defaultVal = $(value).data('default');
param = $(value).val();
val = $(value).prop('checked');
$('#urlParamForm').change(function(){
url = "?";
$('#urlParamForm *').filter(':input').each(function(index, value){
defaultVal = $(value).data('default');
param = $(value).val();
val = $(value).prop('checked');
if(val !== defaultVal){
url = url+param+"="+val+"&";
}
});
ics_url = $('#cal-url').data('url') + url.substring(0, url.length - 1);
$('#cal-url').text(ics_url);
if(val !== defaultVal){
url = url+param+"="+val+"&";
}
});
ics_url = $('#cal-url').data('url') + url.substring(0, url.length - 1);
$('#cal-url').text(ics_url);
gcal_url = $('#gcal-link').data('url') + encodeURIComponent(url.substring(0, url.length - 1));
$('#gcal-link').attr('href',gcal_url);
});
gcal_url = $('#gcal-link').data('url') + encodeURIComponent(url.substring(0, url.length - 1));
$('#gcal-link').attr('href',gcal_url);
});
$('#urlParamForm').change(); //Do the initial setting
});
$('#urlParamForm').change(); //Do the initial setting
});
var clipboard = new ClipboardJS('.btn');
@@ -37,124 +37,124 @@
window.setTimeout(function () {$(e.trigger).popover('hide')}, 3000);
e.clearSelection();
});
</script>
</script>
{% endblock %}
{% block content %}
{% if not request.is_ajax and object.pk == user.pk %}
<div class="row py-3">
<div class="col text-right">
<div class="btn-group">
<a href="{% url 'profile_update_self' %}" class="btn btn-warning">
Edit Profile <i class="fas fa-edit"></i>
</a>
<a href="{% url 'password_change' %}" class="btn btn-light">
Change Password <span class="fas fa-lock"></span>
</a>
</div>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-12">
<div class="card">
<div class="row no-gutters">
<div class="col-md-3">
<img src="{{object.profile_picture}}" class="card-img img-fluid" />
{% if not request.is_ajax and object.pk == user.pk %}
<div class="row py-3">
<div class="col text-right">
<div class="btn-group">
<a href="{% url 'profile_update_self' %}" class="btn btn-warning">
Edit Profile <span class="fas fa-edit"></span>
</a>
<a href="{% url 'password_change' %}" class="btn btn-light">
Change Password <span class="fas fa-lock"></span>
</a>
</div>
<div class="col-md-9">
<div class="card-body">
<dl class="row">
<dt class="col-5">First Name</dt>
<dd class="col-7">{{object.first_name}}</dd>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-12">
<div class="card">
<div class="row no-gutters">
<div class="col-md-3">
<img src="{{object.profile_picture}}" class="card-img img-fluid" />
</div>
<div class="col-md-9">
<div class="card-body">
<dl class="row">
<dt class="col-5">First Name</dt>
<dd class="col-7">{{object.first_name}}</dd>
<dt class="col-5">Last Name</dt>
<dd class="col-7">{{object.last_name}}</dd>
<dt class="col-5">Last Name</dt>
<dd class="col-7">{{object.last_name}}</dd>
<dt class="col-5">Email</dt>
<dd class="col-7">{{object.email}}</dd>
<dt class="col-5">Email</dt>
<dd class="col-7">{{object.email}}</dd>
<dt class="col-5">Last Login</dt>
<dd class="col-7">{{object.last_login|date:"d/m/Y H:i"}}</dd>
<dt class="col-5">Last Login</dt>
<dd class="col-7">{{object.last_login|date:"d/m/Y H:i"}}</dd>
<dt class="col-5">Date Joined</dt>
<dd class="col-7">{{object.date_joined|date:"d/m/Y H:i"}}</dd>
<dt class="col-5">Date Joined</dt>
<dd class="col-7">{{object.date_joined|date:"d/m/Y H:i"}}</dd>
<dt class="col-5">Initials</dt>
<dd class="col-7">{{object.initials}}</dd>
<dt class="col-5">Initials</dt>
<dd class="col-7">{{object.initials}}</dd>
<dt class="col-5">Phone</dt>
<dd class="col-7">{{object.phone|linkornone:'tel'}}</dd>
</dl>
<dt class="col-5">Phone</dt>
<dd class="col-7">{{object.phone|linkornone:'tel'}}</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
</div>
{% if not request.is_ajax and object.pk == user.pk %}
<div class="col-12 my-2">
<div class="card">
<div class="card-header">Personal iCal Details</div>
<div class="card-body">
<dl class="row">
<dt class="col-4">API Key</dt>
<dd class="col-8">
{% if user.api_key %}
<code id="api-key">{{user.api_key}}</code>
<button class="btn btn-secondary align-middle" data-clipboard-target="#api-key" data-content="Copied to clipboard!"><span class="fas fa-clipboard"></span></button>
{% else %}
<span id="api-key">No API Key Generated</span>
{% endif %}
<a href="{% url 'reset_api_key' %}" class="btn btn-secondary align-middle">
{% if user.api_key %}Reset API Key{% else %}Generate API Key{% endif %}
<span class="fas fa-redo"></span>
</a>
</dd>
<dt class="col-4">Calendar Options</dt>
<dd class="col-8">
<form id="urlParamForm">
<div class="form-group d-flex flex-column flex-lg-row">
<label class="checkbox-inline mr-lg-2">
<input type="checkbox" value="rig" data-default="true" checked> Rigs
</label>
<label class="checkbox-inline mx-lg-2">
<input type="checkbox" value="non-rig" data-default="true" checked> Non-Rigs
</label>
<label class="checkbox-inline mx-lg-2">
<input type="checkbox" value="dry-hire" data-default="true" checked> Dry-Hires
</label>
<label class="checkbox-inline mx-lg-2">
<input type="checkbox" value="cancelled" data-default="false" > Cancelled
</label>
<label class="checkbox-inline mx-lg-2">
<input type="checkbox" value="provisional" data-default="true" checked> Provisional
</label>
<label class="checkbox-inline ml-lg-2">
<input type="checkbox" value="confirmed" data-default="true" checked> Confirmed/Booked
</label>
</div>
</form>
</dd>
<dt class="col-4">Calendar URL</dt>
<dd class="col-8">
{% if user.api_key %}
<code id="cal-url" data-url="http{{ request.is_secure|yesno:"s,"}}://{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}"></code>
<button class="btn btn-secondary align-middle" data-clipboard-target="#cal-url" data-content="Copied to clipboard!"><span class="fas fa-clipboard"></span></button>
<br>
<small><a id="gcal-link" data-url="https://support.google.com/calendar/answer/37100" href="">Click here</a> for instructions on adding to google calendar.<br/>
To sync from Google Calendar to mobile device, visit <a href="https://www.google.com/calendar/syncselect" target="_blank">this page</a> on your device and tick "RIGS Calendar".</small>
{% else %}
<pre>No API Key Generated</pre>
{% endif %}
</dd>
</dl>
{% if not request.is_ajax and object.pk == user.pk %}
<div class="col-12 my-2">
<div class="card">
<div class="card-header">Personal iCal Details</div>
<div class="card-body">
<dl class="row">
<dt class="col-4">API Key</dt>
<dd class="col-8">
{% if user.api_key %}
<code id="api-key">{{user.api_key}}</code>
<button class="btn btn-secondary align-middle" data-clipboard-target="#api-key" data-content="Copied to clipboard!"><span class="fas fa-clipboard"></span></button>
{% else %}
<span id="api-key">No API Key Generated</span>
{% endif %}
<a href="{% url 'reset_api_key' %}" class="btn btn-secondary align-middle">
{% if user.api_key %}Reset API Key{% else %}Generate API Key{% endif %}
<span class="fas fa-redo"></span>
</a>
</dd>
<dt class="col-4">Calendar Options</dt>
<dd class="col-8">
<form id="urlParamForm">
<div class="form-group d-flex flex-column flex-lg-row">
<label class="checkbox-inline mr-lg-2">
<input type="checkbox" value="rig" data-default="true" checked> Rigs
</label>
<label class="checkbox-inline mx-lg-2">
<input type="checkbox" value="non-rig" data-default="true" checked> Non-Rigs
</label>
<label class="checkbox-inline mx-lg-2">
<input type="checkbox" value="dry-hire" data-default="true" checked> Dry-Hires
</label>
<label class="checkbox-inline mx-lg-2">
<input type="checkbox" value="cancelled" data-default="false" > Cancelled
</label>
<label class="checkbox-inline mx-lg-2">
<input type="checkbox" value="provisional" data-default="true" checked> Provisional
</label>
<label class="checkbox-inline ml-lg-2">
<input type="checkbox" value="confirmed" data-default="true" checked> Confirmed/Booked
</label>
</div>
</form>
</dd>
<dt class="col-4">Calendar URL</dt>
<dd class="col-8">
{% if user.api_key %}
<code id="cal-url" data-url="http{{ request.is_secure|yesno:"s,"}}://{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}"></code>
<button class="btn btn-secondary align-middle" data-clipboard-target="#cal-url" data-content="Copied to clipboard!"><span class="fas fa-clipboard"></span></button>
<br>
<small><a id="gcal-link" data-url="https://support.google.com/calendar/answer/37100" href="">Click here</a> for instructions on adding to google calendar.<br/>
To sync from Google Calendar to mobile device, visit <a href="https://www.google.com/calendar/syncselect" target="_blank">this page</a> on your device and tick "RIGS Calendar".</small>
{% else %}
<pre>No API Key Generated</pre>
{% endif %}
</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
{% endif %}
</div>
<h4>Events</h4>
{% with object.latest_events as events %}
{% include 'partials/event_table.html' %}
{% endwith %}
{% endif %}
</div>
<h4>Events</h4>
{% with object.latest_events as events %}
{% include 'partials/event_table.html' %}
{% endwith %}
{% endblock %}

View File

@@ -11,8 +11,8 @@
$('#activity_loading').slideUp(dur,function(){
$('#activity').slideDown(dur);
});
var whiteList = $.fn.tooltip.Constructor.Default.whiteList
whiteList.ins = []
const whiteList = $.fn.tooltip.Constructor.Default.whiteList;
whiteList.ins = []
whiteList.del = []
$('#activity [data-toggle="popover"]').popover({whiteList: whiteList});
});

View File

@@ -1,33 +1,33 @@
{% load to_class_name from filters %}
<div class="table-responsive">
<table class="table table-striped">
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th scope="col">Date</th>
<th scope="col">Object</th>
<th scope="col">Version ID</th>
<th scope="col">User</th>
<th scope="col">Changes</th>
</tr>
<tr>
<th scope="col">Date</th>
<th scope="col">Object</th>
<th scope="col">Version ID</th>
<th scope="col">User</th>
<th scope="col">Changes</th>
</tr>
</thead>
<tbody>
{% for version in object_list %}
<tr>
<th scope="row">{{ version.revision.date_created }}</th>
<td><a href="{{ version.changes.new.get_absolute_url }}">{{ version.changes.new.display_id|default:version.changes.new.pk }} | {{version.changes.new|to_class_name}}</td>
<td>{{ version.pk }}|{{ version.revision.pk }}</td>
<td>{{ version.revision.user.name|default:"System" }}</td>
<td>
{% if version.changes.old == None %}
Created {{version.changes.new|to_class_name}}
{% elif version.changes.new == None %}
Deleted {{version.changes.old|to_class_name}}
{% else %}
{% include 'partials/version_changes.html' %}
{% endif %}
</td>
</tr>
{% endfor %}
{% for version in object_list %}
<tr>
<th scope="row">{{ version.revision.date_created }}</th>
<td><a href="{{ version.changes.new.get_absolute_url }}">{{ version.changes.new.display_id|default:version.changes.new.pk }} | {{version.changes.new|to_class_name}}</a></td>
<td>{{ version.pk }}|{{ version.revision.pk }}</td>
<td>{{ version.revision.user.name|default:"System" }}</td>
<td>
{% if version.changes.old == None %}
Created {{version.changes.new|to_class_name}}
{% elif version.changes.new == None %}
Deleted {{version.changes.old|to_class_name}}
{% else %}
{% include 'partials/version_changes.html' %}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>

View File

@@ -1,6 +1,6 @@
{% if version.changes.anything_changed %}
{% for change in version.changes.field_changes %}
<span title="Changes to {{ change.field.verbose_name }}" class="bg-info rounded p-1" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='{% spaceless %}{% include "partials/version_changes_change.html" %}{% endspaceless %}'>{{ change.field.verbose_name }}</span>
<span title="Changes to {{ change.field.verbose_name }}" class="bg-info rounded p-1" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='{% spaceless %}{% include "partials/version_changes_change.html" %}{% endspaceless %}'>{{ change.field.verbose_name }}</span>
{% endfor %}
{% for itemchange in version.changes.item_changes %}
<span title="Changes to {{ itemchange.name }}" class="bg-info rounded p-1" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='{% spaceless %}

View File

@@ -1,16 +1,16 @@
{% load to_class_name from filters %}
<div class="table-responsive">
<table class="table table-striped">
<table class="table table-striped">
<thead class="thead-dark">
<tr>
<th scope="col">Date</td>
<th scope="col">Version ID</td>
<th scope="col">User</td>
<th scope="col">Changes</td>
<th scope="col">Date</th>
<th scope="col">Version ID</th>
<th scope="col">User</th>
<th scope="col">Changes</th>
</tr>
</thead>
<tbody>
{% for version in object_list %}
{% for version in object_list %}
<tr>
<th scope="row">{{ version.revision.date_created }}</th>
<td>{{ version.pk }}|{{ version.revision.pk }}</td>
@@ -23,7 +23,7 @@
{% endif %}
</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
</div>
</div>

View File

@@ -6,7 +6,7 @@
$(function () {
$('[data-toggle="tooltip"]').tooltip();
});
var whiteList = $.fn.tooltip.Constructor.Default.whiteList
const whiteList = $.fn.tooltip.Constructor.Default.whiteList;
whiteList.ins = []
whiteList.del = []
$(function() {

View File

@@ -1,6 +1,8 @@
from django.urls import path
from django.apps import apps
from django.urls import path
from django.template.loader import get_template
from django.template import TemplateDoesNotExist
from PyRIGS.decorators import (permission_required_with_403)
from versioning import views
@@ -11,10 +13,8 @@ urlpatterns = [
name='activity_feed'),
]
# Well except this specific hack for legacy URLs...if only the RIGS app had been named 'rigboard'!
for app in apps.get_app_configs():
for app in [apps.get_app_config(label) for label in ("RIGS", "assets")]:
appname = str(app.label)
if appname == 'RIGS':
appname = 'rigboard'
table_name = 'activity_table'
@@ -22,18 +22,23 @@ for app in apps.get_app_configs():
table_name = appname + '_activity_table'
# TODO Proper Permissions
urlpatterns += [path(appname + '/activity/', permission_required_with_403('RIGS.add_event')(views.ActivityTable.as_view()),
name=table_name, kwargs={'app': appname, 'models': views.get_models(app.label)}), ]
urlpatterns += [
path(appname + '/activity/', permission_required_with_403('RIGS.add_event')(views.ActivityTable.as_view()),
name=table_name, kwargs={'app': appname, 'models': views.get_models(app.label)}), ]
for model in views.get_models(app=app.label):
modelname = model.__name__.lower()
if appname == 'rigboard':
urlpatterns += [
path('{}/<str:pk>/history/'.format(modelname), permission_required_with_403('{}.change_{}'.format(app.label, modelname))(views.VersionHistory.as_view()),
path('{}/<str:pk>/history/'.format(modelname),
permission_required_with_403('{}.change_{}'.format(app.label, modelname))(
views.VersionHistory.as_view()),
name='{}_history'.format(modelname), kwargs={'model': model, 'app': appname, }),
]
else:
urlpatterns += [
path('{}/{}/<str:pk>/history/'.format(appname, modelname), permission_required_with_403('{}.change_{}'.format(app.label, modelname))(views.VersionHistory.as_view()),
path('{}/{}/<str:pk>/history/'.format(appname, modelname),
permission_required_with_403('{}.change_{}'.format(app.label, modelname))(
views.VersionHistory.as_view()),
name='{}_history'.format(modelname), kwargs={'model': model, 'app': appname, }),
]