mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-02-26 16:18:23 +00:00
Versioning module now does magic
Automatic creation of views/urls for anything registered with reversion, with a small amount of hackage to preserve legacy stuff. (and the DAMNED asset IDs!) I would never get distracted...
This commit is contained in:
@@ -11,13 +11,17 @@ from registration.backends.default.views import RegistrationView
|
|||||||
from PyRIGS.decorators import permission_required_with_403
|
from PyRIGS.decorators import permission_required_with_403
|
||||||
import RIGS
|
import RIGS
|
||||||
import users
|
import users
|
||||||
|
import versioning
|
||||||
from PyRIGS import views
|
from PyRIGS import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', include('users.urls')),
|
path('', include('users.urls')),
|
||||||
|
path('', include('versioning.urls')),
|
||||||
path('', include('RIGS.urls')),
|
path('', include('RIGS.urls')),
|
||||||
path('assets/', include('assets.urls')),
|
path('assets/', include('assets.urls')),
|
||||||
|
|
||||||
|
path('', login_required(views.Index.as_view()), name='index'),
|
||||||
|
|
||||||
# API
|
# API
|
||||||
path('api/<str:model>/', login_required(views.SecureAPIRequest.as_view()),
|
path('api/<str:model>/', login_required(views.SecureAPIRequest.as_view()),
|
||||||
name="api_secure"),
|
name="api_secure"),
|
||||||
|
|||||||
@@ -20,6 +20,19 @@ from RIGS import models, forms
|
|||||||
from assets import models as asset_models
|
from assets import models as asset_models
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
|
from django.views.decorators.cache import never_cache
|
||||||
|
from django.utils.decorators import method_decorator
|
||||||
|
|
||||||
|
|
||||||
|
# Displays the current rig count along with a few other bits and pieces
|
||||||
|
@method_decorator(never_cache, name='dispatch') # Disable browser based caching
|
||||||
|
class Index(generic.TemplateView):
|
||||||
|
template_name = 'index.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(Index, self).get_context_data(**kwargs)
|
||||||
|
context['rig_count'] = models.Event.objects.rig_count()
|
||||||
|
return context
|
||||||
|
|
||||||
class SecureAPIRequest(generic.View):
|
class SecureAPIRequest(generic.View):
|
||||||
models = {
|
models = {
|
||||||
|
|||||||
@@ -197,6 +197,8 @@ class VatRate(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
objects = VatManager()
|
objects = VatManager()
|
||||||
|
|
||||||
|
reversion_hide = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def as_percent(self):
|
def as_percent(self):
|
||||||
return self.rate * 100
|
return self.rate * 100
|
||||||
@@ -332,6 +334,10 @@ class Event(models.Model, RevisionMixin):
|
|||||||
auth_request_at = models.DateTimeField(null=True, blank=True)
|
auth_request_at = models.DateTimeField(null=True, blank=True)
|
||||||
auth_request_to = models.EmailField(null=True, blank=True)
|
auth_request_to = models.EmailField(null=True, blank=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def display_id(self):
|
||||||
|
return str("N%05d" % self.pk)
|
||||||
|
|
||||||
# Calculated values
|
# Calculated values
|
||||||
"""
|
"""
|
||||||
EX Vat
|
EX Vat
|
||||||
@@ -467,7 +473,6 @@ class Event(models.Model, RevisionMixin):
|
|||||||
self.full_clean()
|
self.full_clean()
|
||||||
super(Event, self).save(*args, **kwargs)
|
super(Event, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class EventItem(models.Model):
|
class EventItem(models.Model):
|
||||||
event = models.ForeignKey('Event', related_name='items', blank=True, on_delete=models.CASCADE)
|
event = models.ForeignKey('Event', related_name='items', blank=True, on_delete=models.CASCADE)
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
@@ -476,6 +481,8 @@ class EventItem(models.Model):
|
|||||||
cost = models.DecimalField(max_digits=10, decimal_places=2)
|
cost = models.DecimalField(max_digits=10, decimal_places=2)
|
||||||
order = models.IntegerField()
|
order = models.IntegerField()
|
||||||
|
|
||||||
|
reversion_hide = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def total_cost(self):
|
def total_cost(self):
|
||||||
return self.cost * self.quantity
|
return self.cost * self.quantity
|
||||||
@@ -673,5 +680,7 @@ class EventChecklistVehicle(models.Model):
|
|||||||
vehicle = models.CharField(max_length=255)
|
vehicle = models.CharField(max_length=255)
|
||||||
driver = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='drivers', on_delete=models.CASCADE)
|
driver = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='drivers', on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
reversion_hide = True
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{} driven by {}".format(self.vehicle, str(self.driver))
|
return "{} driven by {}".format(self.vehicle, str(self.driver))
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from premailer import Premailer
|
|||||||
from z3c.rml import rml2pdf
|
from z3c.rml import rml2pdf
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
from versioning.versioning import models_for_feed
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
|
|
||||||
def send_eventauthorisation_success_email(instance):
|
def send_eventauthorisation_success_email(instance):
|
||||||
@@ -142,11 +142,9 @@ def send_admin_awaiting_approval_email(user, request, **kwargs):
|
|||||||
user_activated.connect(send_admin_awaiting_approval_email)
|
user_activated.connect(send_admin_awaiting_approval_email)
|
||||||
|
|
||||||
# TODO Move
|
# TODO Move
|
||||||
|
|
||||||
|
|
||||||
def update_cache(sender, instance, created, **kwargs):
|
def update_cache(sender, instance, created, **kwargs):
|
||||||
cache.clear()
|
cache.clear()
|
||||||
|
|
||||||
|
|
||||||
for model in models_for_feed():
|
for model in reversion.get_registered_models():
|
||||||
post_save.connect(update_cache, sender=model)
|
post_save.connect(update_cache, sender=model)
|
||||||
|
|||||||
@@ -80,7 +80,7 @@
|
|||||||
class="hidden-xs">Edit</span></a>
|
class="hidden-xs">Edit</span></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 text-right">
|
<div class="col-12 text-right">
|
||||||
{% include 'partials/last_edited.html' with target="ec_history" %}
|
{% include 'partials/last_edited.html' with target="eventchecklist_history" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
{% for event in events %}
|
{% for event in events %}
|
||||||
<tr {% include 'partials/event_table_colour.html' %} id="event_row">
|
<tr {% include 'partials/event_table_colour.html' %} id="event_row">
|
||||||
<!---Number-->
|
<!---Number-->
|
||||||
<th scope="row" id="event_number">{{ event.pk }}</th>
|
<th scope="row" id="event_number">{{ event.display_id }}</th>
|
||||||
<!--Dates-->
|
<!--Dates-->
|
||||||
<td id="event_dates">
|
<td id="event_dates">
|
||||||
<div><strong>{{ event.start_date|date:"D d/m/Y" }}</strong></div>
|
<div><strong>{{ event.start_date|date:"D d/m/Y" }}</strong></div>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for event in object_list %}
|
{% for event in object_list %}
|
||||||
<tr {% include 'partials/event_table_colour.html' %}>
|
<tr {% include 'partials/event_table_colour.html' %}>
|
||||||
<th scope="row"><a href="{% url 'event_detail' event.pk %}">N{{ event.pk|stringformat:"05d" }}</a><br>
|
<th scope="row"><a href="{% url 'event_detail' event.pk %}">{{ event.display_id }}</a><br>
|
||||||
<span class="text-muted">{{ event.get_status_display }}</span></th>
|
<span class="text-muted">{{ event.get_status_display }}</span></th>
|
||||||
<td>{{ event.start_date }}</td>
|
<td>{{ event.start_date }}</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -150,7 +150,7 @@
|
|||||||
class="hidden-xs">Edit</span></a>
|
class="hidden-xs">Edit</span></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 text-right">
|
<div class="col-12 text-right">
|
||||||
{% include 'partials/last_edited.html' with target="ra_history" %}
|
{% include 'partials/last_edited.html' with target="riskassessment_history" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
32
RIGS/urls.py
32
RIGS/urls.py
@@ -6,12 +6,8 @@ from django.views.generic import RedirectView
|
|||||||
from PyRIGS.decorators import (api_key_required, has_oembed,
|
from PyRIGS.decorators import (api_key_required, has_oembed,
|
||||||
permission_required_with_403)
|
permission_required_with_403)
|
||||||
from RIGS import finance, ical, models, rigboard, views, hs
|
from RIGS import finance, ical, models, rigboard, views, hs
|
||||||
from versioning import versioning
|
|
||||||
from django.views.decorators.cache import cache_page
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', login_required(views.Index.as_view()), name='index'),
|
|
||||||
|
|
||||||
# People
|
# People
|
||||||
path('people/', permission_required_with_403('RIGS.view_person')(views.PersonList.as_view()),
|
path('people/', permission_required_with_403('RIGS.view_person')(views.PersonList.as_view()),
|
||||||
name='person_list'),
|
name='person_list'),
|
||||||
@@ -19,9 +15,6 @@ urlpatterns = [
|
|||||||
name='person_create'),
|
name='person_create'),
|
||||||
path('people/<int:pk>/', permission_required_with_403('RIGS.view_person')(views.PersonDetail.as_view()),
|
path('people/<int:pk>/', permission_required_with_403('RIGS.view_person')(views.PersonDetail.as_view()),
|
||||||
name='person_detail'),
|
name='person_detail'),
|
||||||
path('people/<int:pk>/history/',
|
|
||||||
permission_required_with_403('RIGS.view_person')(versioning.VersionHistory.as_view()),
|
|
||||||
name='person_history', kwargs={'model': models.Person}),
|
|
||||||
path('people/<int:pk>/edit/', permission_required_with_403('RIGS.change_person')(views.PersonUpdate.as_view()),
|
path('people/<int:pk>/edit/', permission_required_with_403('RIGS.change_person')(views.PersonUpdate.as_view()),
|
||||||
name='person_update'),
|
name='person_update'),
|
||||||
|
|
||||||
@@ -34,9 +27,6 @@ urlpatterns = [
|
|||||||
path('organisations/<int:pk>/',
|
path('organisations/<int:pk>/',
|
||||||
permission_required_with_403('RIGS.view_organisation')(views.OrganisationDetail.as_view()),
|
permission_required_with_403('RIGS.view_organisation')(views.OrganisationDetail.as_view()),
|
||||||
name='organisation_detail'),
|
name='organisation_detail'),
|
||||||
path('organisations/<int:pk>/history/',
|
|
||||||
permission_required_with_403('RIGS.view_organisation')(versioning.VersionHistory.as_view()),
|
|
||||||
name='organisation_history', kwargs={'model': models.Organisation}),
|
|
||||||
path('organisations/<int:pk>/edit/',
|
path('organisations/<int:pk>/edit/',
|
||||||
permission_required_with_403('RIGS.change_organisation')(views.OrganisationUpdate.as_view()),
|
permission_required_with_403('RIGS.change_organisation')(views.OrganisationUpdate.as_view()),
|
||||||
name='organisation_update'),
|
name='organisation_update'),
|
||||||
@@ -48,9 +38,6 @@ urlpatterns = [
|
|||||||
name='venue_create'),
|
name='venue_create'),
|
||||||
path('venues/<int:pk>/', permission_required_with_403('RIGS.view_venue')(views.VenueDetail.as_view()),
|
path('venues/<int:pk>/', permission_required_with_403('RIGS.view_venue')(views.VenueDetail.as_view()),
|
||||||
name='venue_detail'),
|
name='venue_detail'),
|
||||||
path('venues/<int:pk>/history/',
|
|
||||||
permission_required_with_403('RIGS.view_venue')(versioning.VersionHistory.as_view()),
|
|
||||||
name='venue_history', kwargs={'model': models.Venue}),
|
|
||||||
path('venues/<int:pk>/edit/', permission_required_with_403('RIGS.change_venue')(views.VenueUpdate.as_view()),
|
path('venues/<int:pk>/edit/', permission_required_with_403('RIGS.change_venue')(views.VenueUpdate.as_view()),
|
||||||
name='venue_update'),
|
name='venue_update'),
|
||||||
|
|
||||||
@@ -63,11 +50,7 @@ urlpatterns = [
|
|||||||
url(r'^rigboard/calendar/(?P<view>(month|week|day))/(?P<date>(\d{4}-\d{2}-\d{2}))/$',
|
url(r'^rigboard/calendar/(?P<view>(month|week|day))/(?P<date>(\d{4}-\d{2}-\d{2}))/$',
|
||||||
login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
||||||
path('rigboard/archive/', RedirectView.as_view(permanent=True, pattern_name='event_archive')),
|
path('rigboard/archive/', RedirectView.as_view(permanent=True, pattern_name='event_archive')),
|
||||||
path('rigboard/activity/', permission_required_with_403('RIGS.view_event')(versioning.ActivityTable.as_view()),
|
|
||||||
name='activity_table'),
|
|
||||||
path('rigboard/activity/feed/',
|
|
||||||
cache_page(60 * 10)(permission_required_with_403('RIGS.view_event')(versioning.ActivityFeed.as_view())),
|
|
||||||
name='activity_feed'),
|
|
||||||
|
|
||||||
path('event/<int:pk>/', has_oembed(oembed_view="event_oembed")(rigboard.EventDetail.as_view()),
|
path('event/<int:pk>/', has_oembed(oembed_view="event_oembed")(rigboard.EventDetail.as_view()),
|
||||||
name='event_detail'),
|
name='event_detail'),
|
||||||
@@ -86,9 +69,6 @@ urlpatterns = [
|
|||||||
name='event_update'),
|
name='event_update'),
|
||||||
path('event/<int:pk>/duplicate/', permission_required_with_403('RIGS.add_event')(rigboard.EventDuplicate.as_view()),
|
path('event/<int:pk>/duplicate/', permission_required_with_403('RIGS.add_event')(rigboard.EventDuplicate.as_view()),
|
||||||
name='event_duplicate'),
|
name='event_duplicate'),
|
||||||
path('event/<int:pk>/history/',
|
|
||||||
permission_required_with_403('RIGS.view_event')(versioning.VersionHistory.as_view()),
|
|
||||||
name='event_history', kwargs={'model': models.Event}),
|
|
||||||
|
|
||||||
# Event H&S
|
# Event H&S
|
||||||
path('event/hs/', permission_required_with_403('RIGS.change_event')(hs.HSList.as_view()), name='hs_list'),
|
path('event/hs/', permission_required_with_403('RIGS.change_event')(hs.HSList.as_view()), name='hs_list'),
|
||||||
@@ -99,8 +79,6 @@ urlpatterns = [
|
|||||||
name='ra_detail'),
|
name='ra_detail'),
|
||||||
path('event/ra/<int:pk>/edit/', permission_required_with_403('RIGS.change_event')(hs.EventRiskAssessmentEdit.as_view()),
|
path('event/ra/<int:pk>/edit/', permission_required_with_403('RIGS.change_event')(hs.EventRiskAssessmentEdit.as_view()),
|
||||||
name='ra_edit'),
|
name='ra_edit'),
|
||||||
path('event/ra/<int:pk>/history/', permission_required_with_403('RIGS.change_event')(versioning.VersionHistory.as_view()),
|
|
||||||
name='ra_history', kwargs={'model': models.RiskAssessment}),
|
|
||||||
path('event/ra/list', permission_required_with_403('RIGS.change_event')(hs.EventRiskAssessmentList.as_view()),
|
path('event/ra/list', permission_required_with_403('RIGS.change_event')(hs.EventRiskAssessmentList.as_view()),
|
||||||
name='ra_list'),
|
name='ra_list'),
|
||||||
path('event/ra/<int:pk>/review/', permission_required_with_403('RIGS.change_event')(hs.EventRiskAssessmentReview.as_view()), name='ra_review'),
|
path('event/ra/<int:pk>/review/', permission_required_with_403('RIGS.change_event')(hs.EventRiskAssessmentReview.as_view()), name='ra_review'),
|
||||||
@@ -111,13 +89,8 @@ urlpatterns = [
|
|||||||
name='ec_detail'),
|
name='ec_detail'),
|
||||||
path('event/checklist/<int:pk>/edit/', permission_required_with_403('RIGS.change_event')(hs.EventChecklistEdit.as_view()),
|
path('event/checklist/<int:pk>/edit/', permission_required_with_403('RIGS.change_event')(hs.EventChecklistEdit.as_view()),
|
||||||
name='ec_edit'),
|
name='ec_edit'),
|
||||||
path('event/checklist/<int:pk>/history/', permission_required_with_403('RIGS.change_event')(versioning.VersionHistory.as_view()),
|
|
||||||
name='ec_history', kwargs={'model': models.EventChecklist}),
|
|
||||||
path('event/checklist/list', permission_required_with_403('RIGS.change_event')(hs.EventChecklistList.as_view()),
|
path('event/checklist/list', permission_required_with_403('RIGS.change_event')(hs.EventChecklistList.as_view()),
|
||||||
name='ec_list'),
|
name='ec_list'),
|
||||||
# TEMPORARY
|
|
||||||
path('event/vehicle/<int:pk>/history/', permission_required_with_403('RIGS.change_event')(versioning.VersionHistory.as_view()),
|
|
||||||
name='vc_history', kwargs={'model': models.EventChecklistVehicle}),
|
|
||||||
|
|
||||||
# Finance
|
# Finance
|
||||||
path('invoice/', permission_required_with_403('RIGS.view_invoice')(finance.InvoiceIndex.as_view()),
|
path('invoice/', permission_required_with_403('RIGS.view_invoice')(finance.InvoiceIndex.as_view()),
|
||||||
@@ -141,9 +114,6 @@ urlpatterns = [
|
|||||||
path('invoice/<int:pk>/delete/',
|
path('invoice/<int:pk>/delete/',
|
||||||
permission_required_with_403('RIGS.change_invoice')(finance.InvoiceDelete.as_view()),
|
permission_required_with_403('RIGS.change_invoice')(finance.InvoiceDelete.as_view()),
|
||||||
name='invoice_delete'),
|
name='invoice_delete'),
|
||||||
path('invoice/(<int:pk>/history/',
|
|
||||||
permission_required_with_403('RIGS.view_invoice')(versioning.VersionHistory.as_view()),
|
|
||||||
name='invoice_history', kwargs={'model': models.Invoice}),
|
|
||||||
|
|
||||||
path('payment/create/', permission_required_with_403('RIGS.add_payment')(finance.PaymentCreate.as_view()),
|
path('payment/create/', permission_required_with_403('RIGS.add_payment')(finance.PaymentCreate.as_view()),
|
||||||
name='payment_create'),
|
name='payment_create'),
|
||||||
|
|||||||
@@ -21,25 +21,6 @@ from assets import models as asset_models
|
|||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
from PyRIGS.views import GenericListView
|
from PyRIGS.views import GenericListView
|
||||||
from django.views.decorators.cache import never_cache
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
|
|
||||||
"""
|
|
||||||
Displays the current rig count along with a few other bits and pieces
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Disable browser based caching
|
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(never_cache, name='dispatch')
|
|
||||||
class Index(generic.TemplateView):
|
|
||||||
template_name = 'index.html'
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(Index, self).get_context_data(**kwargs)
|
|
||||||
context['rig_count'] = models.Event.objects.rig_count()
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class PersonList(GenericListView):
|
class PersonList(GenericListView):
|
||||||
template_name = 'person_list.html'
|
template_name = 'person_list.html'
|
||||||
|
|||||||
@@ -184,6 +184,10 @@ class Asset(models.Model, RevisionMixin):
|
|||||||
def activity_feed_string(self):
|
def activity_feed_string(self):
|
||||||
return str(self)
|
return str(self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def display_id(self):
|
||||||
|
return str(self.asset_id)
|
||||||
|
|
||||||
|
|
||||||
@receiver(pre_save, sender=Asset)
|
@receiver(pre_save, sender=Asset)
|
||||||
def pre_save_asset(sender, instance, **kwargs):
|
def pre_save_asset(sender, instance, **kwargs):
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% if perms.assets.view_asset %}
|
{% if perms.assets.view_asset %}
|
||||||
<li class="nav-item"><a class="nav-link" href="{% url 'asset_activity_table' %}">Recent Changes</a></li>
|
<li class="nav-item"><a class="nav-link" href="{% url 'assets_activity_table' %}">Recent Changes</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="{% url 'asset_audit_list' %}">Audit</a></li>
|
<li class="nav-item"><a class="nav-link" href="{% url 'asset_audit_list' %}">Audit</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{% include 'generic_detail.html' with type='Supplier' history_link='supplier_history' detail_link='supplier_detail' update_link='supplier_update' associated='partials/associated_assets.html' associated2='None' %}
|
{% include 'generic_detail.html' with type='Supplier' history_link='supplier_history' detail_link='supplier_detail' update_link='supplier_update' associated='partials/associated_assets.html' associated2='' %}
|
||||||
|
|||||||
@@ -17,10 +17,6 @@ urlpatterns = [
|
|||||||
(views.AssetEdit.as_view()), name='asset_update'),
|
(views.AssetEdit.as_view()), name='asset_update'),
|
||||||
path('asset/id/<str:pk>/duplicate/', permission_required_with_403('assets.add_asset')
|
path('asset/id/<str:pk>/duplicate/', permission_required_with_403('assets.add_asset')
|
||||||
(views.AssetDuplicate.as_view()), name='asset_duplicate'),
|
(views.AssetDuplicate.as_view()), name='asset_duplicate'),
|
||||||
path('asset/id/<str:pk>/history/', permission_required_with_403('assets.view_asset')(views.AssetVersionHistory.as_view()),
|
|
||||||
name='asset_history', kwargs={'model': models.Asset}),
|
|
||||||
path('activity', permission_required_with_403('assets.view_asset')
|
|
||||||
(views.ActivityTable.as_view()), name='asset_activity_table'),
|
|
||||||
|
|
||||||
path('cabletype/list/', views.CableTypeList.as_view(), name='cable_type_list'),
|
path('cabletype/list/', 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/create/', permission_required_with_403('assets.add_cable_type')(views.CableTypeCreate.as_view()), name='cable_type_create'),
|
||||||
@@ -39,14 +35,12 @@ urlpatterns = [
|
|||||||
path('asset/audit/', permission_required_with_403('assets.change_asset')(views.AssetAuditList.as_view()), name='asset_audit_list'),
|
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('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/list/', views.SupplierList.as_view(), name='supplier_list'),
|
||||||
path('supplier/<int:pk>', views.SupplierDetail.as_view(), name='supplier_detail'),
|
path('supplier/<int:pk>/', views.SupplierDetail.as_view(), name='supplier_detail'),
|
||||||
path('supplier/create', permission_required_with_403('assets.add_supplier')
|
path('supplier/create/', permission_required_with_403('assets.add_supplier')
|
||||||
(views.SupplierCreate.as_view()), name='supplier_create'),
|
(views.SupplierCreate.as_view()), name='supplier_create'),
|
||||||
path('supplier/<int:pk>/edit', permission_required_with_403('assets.change_supplier')
|
path('supplier/<int:pk>/edit/', permission_required_with_403('assets.change_supplier')
|
||||||
(views.SupplierUpdate.as_view()), name='supplier_update'),
|
(views.SupplierUpdate.as_view()), name='supplier_update'),
|
||||||
path('supplier/<int:pk>/history/', views.SupplierVersionHistory.as_view(),
|
|
||||||
name='supplier_history', kwargs={'model': models.Supplier}),
|
|
||||||
|
|
||||||
path('supplier/search/', views.SupplierSearch.as_view(), name='supplier_search_json'),
|
path('supplier/search/', views.SupplierSearch.as_view(), name='supplier_search_json'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -240,43 +240,6 @@ class SupplierUpdate(generic.UpdateView):
|
|||||||
template_name = 'supplier_update.html'
|
template_name = 'supplier_update.html'
|
||||||
|
|
||||||
|
|
||||||
class SupplierVersionHistory(versioning.VersionHistory):
|
|
||||||
template_name = "asset_version_history.html"
|
|
||||||
|
|
||||||
|
|
||||||
class AssetVersionHistory(versioning.VersionHistory):
|
|
||||||
template_name = "version_history.html"
|
|
||||||
|
|
||||||
def get_object(self, **kwargs):
|
|
||||||
return get_object_or_404(models.Asset, asset_id=self.kwargs['pk'])
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(AssetVersionHistory, self).get_context_data(**kwargs)
|
|
||||||
context['object'] = self.get_object()
|
|
||||||
context['id'] = self.get_object().asset_id
|
|
||||||
context['override'] = 'base_assets.html'
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class ActivityTable(versioning.ActivityTable):
|
|
||||||
model = versioning.RIGSVersion
|
|
||||||
template_name = "activity_table.html"
|
|
||||||
paginate_by = 25
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
versions = versioning.RIGSVersion.objects.get_for_multiple_models(
|
|
||||||
[models.Asset, models.Supplier])
|
|
||||||
return versions
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(ActivityTable, self).get_context_data(**kwargs)
|
|
||||||
context['override'] = 'base_assets.html'
|
|
||||||
context['title'] = 'Asset Database'
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class CableTypeList(generic.ListView):
|
class CableTypeList(generic.ListView):
|
||||||
model = models.CableType
|
model = models.CableType
|
||||||
template_name = 'cable_type_list.html'
|
template_name = 'cable_type_list.html'
|
||||||
|
|||||||
@@ -22,11 +22,13 @@
|
|||||||
<a href="{% url 'profile_detail' pk=version.revision.user.pk %}" class="modal-href">
|
<a href="{% url 'profile_detail' pk=version.revision.user.pk %}" class="modal-href">
|
||||||
<img class="media-object img-rounded" src="{{ version.revision.user.profile_picture}}" />
|
<img class="media-object img-rounded" src="{{ version.revision.user.profile_picture}}" />
|
||||||
</a>
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<img class="media-object img-rounded" src="{% static 'imgs/pyrigs-avatar.png' %}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
<h5>
|
<h5>
|
||||||
{{ version.revision.user.name }}
|
{{ version.revision.user.name|default:'System' }}
|
||||||
<span class="ml-3"><small>{{version.revision.date_created|naturaltime}}</small></span>
|
<span class="ml-3"><small>{{version.revision.date_created|naturaltime}}</small></span>
|
||||||
</h5>
|
</h5>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
{% load paginator from filters %}
|
{% load paginator from filters %}
|
||||||
{% load to_class_name from filters %}
|
{% load to_class_name from filters %}
|
||||||
|
|
||||||
{% block title %}{{ title }} Activity Stream{% endblock %}
|
{% block title %}{{ title|title }} Activity Stream{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{% include 'partials/version_scripts.html' %}
|
{% include 'partials/version_scripts.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-sm-12">
|
<div class="col-12">
|
||||||
<h3>{{ title }} Activity Stream</h3>
|
<h3>{{ title|title }} Activity Stream</h3>
|
||||||
{% include 'partials/activity_table_body.html' %}
|
{% include 'partials/activity_table_body.html' %}
|
||||||
{% paginator %}
|
{% paginator %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,20 +14,14 @@
|
|||||||
{% for version in object_list %}
|
{% for version in object_list %}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{{ version.revision.date_created }}</th>
|
<th scope="row">{{ version.revision.date_created }}</th>
|
||||||
<td><a href="{{ version.changes.new.get_absolute_url }}">{{version.changes.new|to_class_name}}
|
<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>
|
||||||
{% if version.changes.new.asset_id %}
|
|
||||||
{{ version.changes.new.asset_id }}
|
|
||||||
{% else %}
|
|
||||||
{{ version.changes.new.pk|stringformat:"05d" }}
|
|
||||||
{% endif %}
|
|
||||||
</a></td>
|
|
||||||
<td>{{ version.pk }}|{{ version.revision.pk }}</td>
|
<td>{{ version.pk }}|{{ version.revision.pk }}</td>
|
||||||
<td>{{ version.revision.user.name|default:"System" }}</td>
|
<td>{{ version.revision.user.name|default:"System" }}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if version.changes.old == None %}
|
{% if version.changes.old == None %}
|
||||||
{{version.changes.new|to_class_name}} Created
|
{{version.changes.new|to_class_name}} Created
|
||||||
{% else %}
|
{% else %}
|
||||||
{% include 'version_changes.html' %}
|
{% include 'partials/version_changes.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
{% load to_class_name from filters %}
|
{% load to_class_name from filters %}
|
||||||
{% load paginator from filters %}
|
{% load paginator from filters %}
|
||||||
|
|
||||||
{% block title %}{{object|to_class_name}} {{ id }} - Revision History{% endblock %}
|
{% block title %}{{object|to_class_name}} {{ object.display_id|default:object.pk }} - Revision History{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{% include 'partials/version_scripts.html' %}
|
{% include 'partials/version_scripts.html' %}
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<h3><a href="{{ object.get_absolute_url }}">{{object|to_class_name}} {{ id }}</a> - Revision History</h3>
|
<h3><a href="{{ object.get_absolute_url }}">{{object|to_class_name}} {{ object.display_id|default:object.pk }}</a> - Revision History</h3>
|
||||||
{% include 'partials/version_history_table.html' %}
|
{% include 'partials/version_history_table.html' %}
|
||||||
<div>{% paginator %}</div>
|
<div>{% paginator %}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
34
versioning/urls.py
Normal file
34
versioning/urls.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
from django.conf.urls import url
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.urls import path
|
||||||
|
from django.views.decorators.clickjacking import xframe_options_exempt
|
||||||
|
from django.views.generic import RedirectView
|
||||||
|
from PyRIGS.decorators import (api_key_required, has_oembed,
|
||||||
|
permission_required_with_403)
|
||||||
|
from RIGS import finance, ical, models, rigboard, views, hs
|
||||||
|
from versioning import views
|
||||||
|
from django.views.decorators.cache import cache_page
|
||||||
|
from django.apps import apps
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('rigboard/activity/feed/',
|
||||||
|
cache_page(60 * 10)(permission_required_with_403('RIGS.view_event')(views.ActivityFeed.as_view())),
|
||||||
|
name='activity_feed'),
|
||||||
|
]
|
||||||
|
|
||||||
|
for app in apps.get_app_configs():
|
||||||
|
appname = str(app.label)
|
||||||
|
# Well except this specific hack for legacy URLs...if only the RIGS app had been named 'rigboard'!
|
||||||
|
if appname == 'RIGS':
|
||||||
|
appname = 'rigboard'
|
||||||
|
urlpatterns += [path(appname + '/activity/', permission_required_with_403('RIGS.view_event')(views.ActivityTable.as_view()),
|
||||||
|
name='activity_table', kwargs={'app': appname, 'models': views.get_models(app.label)}),]
|
||||||
|
else:
|
||||||
|
urlpatterns += [path(appname + '/activity/', permission_required_with_403('RIGS.view_event')(views.ActivityTable.as_view()),
|
||||||
|
name=appname + '_activity_table', kwargs={'app': appname, 'models': views.get_models(app.label)}),]
|
||||||
|
for model in views.get_models(app.label):
|
||||||
|
modelname = model.__name__.lower()
|
||||||
|
urlpatterns += [
|
||||||
|
path(appname + '/' + modelname + '/<str:pk>/history/', permission_required_with_403('{}.change_{}'.format(app.label, modelname))(views.VersionHistory.as_view()),
|
||||||
|
name='{}_history'.format(modelname), kwargs={'model': model, 'app': appname,}),
|
||||||
|
]
|
||||||
@@ -11,6 +11,8 @@ from django.views import generic
|
|||||||
from reversion.models import Version, VersionQuerySet
|
from reversion.models import Version, VersionQuerySet
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
from assets import models as asset_models
|
from assets import models as asset_models
|
||||||
|
from django.apps import apps
|
||||||
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
logger = logging.getLogger('tec.pyrigs')
|
logger = logging.getLogger('tec.pyrigs')
|
||||||
|
|
||||||
@@ -195,78 +197,3 @@ class RIGSVersion(Version):
|
|||||||
new=self._object_version.object,
|
new=self._object_version.object,
|
||||||
old=self.parent._object_version.object if self.parent else None
|
old=self.parent._object_version.object if self.parent else None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class VersionHistory(generic.ListView):
|
|
||||||
model = RIGSVersion
|
|
||||||
template_name = "version_history.html"
|
|
||||||
paginate_by = 25
|
|
||||||
|
|
||||||
def get_queryset(self, **kwargs):
|
|
||||||
return RIGSVersion.objects.get_for_object(self.get_object()).select_related("revision",
|
|
||||||
"revision__user").all().order_by(
|
|
||||||
"-revision__date_created")
|
|
||||||
|
|
||||||
def get_object(self, **kwargs):
|
|
||||||
return get_object_or_404(self.kwargs['model'], pk=self.kwargs['pk'])
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(VersionHistory, self).get_context_data(**kwargs)
|
|
||||||
context['object'] = self.get_object()
|
|
||||||
context['id'] = self.get_object().pk
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class ActivityTable(generic.ListView):
|
|
||||||
model = RIGSVersion
|
|
||||||
template_name = "activity_table.html"
|
|
||||||
paginate_by = 25
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
versions = RIGSVersion.objects.get_for_multiple_models(
|
|
||||||
[models.Event, models.Venue, models.Person, models.Organisation, models.EventAuthorisation, models.RiskAssessment])
|
|
||||||
return versions.order_by("-revision__date_created")
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(ActivityTable, self).get_context_data(**kwargs)
|
|
||||||
context['title'] = 'Rigboard'
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|
||||||
# TODO Defined by the model, rather than with this list
|
|
||||||
def models_for_feed():
|
|
||||||
return [models.Event, models.Venue, models.Person, models.Organisation, models.EventAuthorisation, models.RiskAssessment, models.EventChecklist,
|
|
||||||
asset_models.Asset, asset_models.Supplier]
|
|
||||||
|
|
||||||
|
|
||||||
# Appears on homepage
|
|
||||||
class ActivityFeed(generic.ListView):
|
|
||||||
model = RIGSVersion
|
|
||||||
template_name = "activity_feed_data.html"
|
|
||||||
paginate_by = 25
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
versions = RIGSVersion.objects.get_for_multiple_models(
|
|
||||||
models_for_feed())
|
|
||||||
return versions.order_by("-revision__date_created")
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
# Call the base implementation first to get a context
|
|
||||||
context = super(ActivityFeed, self).get_context_data(**kwargs)
|
|
||||||
|
|
||||||
maxTimeDelta = datetime.timedelta(hours=1)
|
|
||||||
|
|
||||||
items = []
|
|
||||||
|
|
||||||
for thisVersion in context['object_list']:
|
|
||||||
thisVersion.withPrevious = False
|
|
||||||
if len(items) >= 1:
|
|
||||||
timeDiff = items[-1].revision.date_created - thisVersion.revision.date_created
|
|
||||||
timeTogether = timeDiff < maxTimeDelta
|
|
||||||
sameUser = thisVersion.revision.user_id == items[-1].revision.user_id
|
|
||||||
thisVersion.withPrevious = timeTogether & sameUser
|
|
||||||
|
|
||||||
items.append(thisVersion)
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|||||||
98
versioning/views.py
Normal file
98
versioning/views.py
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from diff_match_patch import diff_match_patch
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.db.models import EmailField, IntegerField, TextField
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.utils.functional import cached_property
|
||||||
|
from django.views import generic
|
||||||
|
from reversion.models import Version, VersionQuerySet
|
||||||
|
from RIGS import models
|
||||||
|
from assets import models as asset_models
|
||||||
|
from django.apps import apps
|
||||||
|
from reversion import revisions as reversion
|
||||||
|
from versioning.versioning import RIGSVersion
|
||||||
|
|
||||||
|
from django.views.decorators.cache import never_cache
|
||||||
|
from django.utils.decorators import method_decorator
|
||||||
|
|
||||||
|
class VersionHistory(generic.ListView):
|
||||||
|
model = RIGSVersion
|
||||||
|
template_name = "version_history.html"
|
||||||
|
paginate_by = 25
|
||||||
|
|
||||||
|
def get_queryset(self, **kwargs):
|
||||||
|
return RIGSVersion.objects.get_for_object(self.get_object()).select_related("revision",
|
||||||
|
"revision__user").all().order_by(
|
||||||
|
"-revision__date_created")
|
||||||
|
|
||||||
|
def get_object(self, **kwargs):
|
||||||
|
#Goddamit, almost got away without specific hacks
|
||||||
|
if self.kwargs['model'].__name__ == 'Asset':
|
||||||
|
return get_object_or_404(self.kwargs['model'], asset_id=self.kwargs['pk'])
|
||||||
|
else:
|
||||||
|
return get_object_or_404(self.kwargs['model'], pk=self.kwargs['pk'])
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(VersionHistory, self).get_context_data(**kwargs)
|
||||||
|
context['object'] = self.get_object()
|
||||||
|
if self.kwargs['app'] != 'rigboard':
|
||||||
|
context['override'] = 'base_{}.html'.format(self.kwargs['app'])
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_models(app=None):
|
||||||
|
models = filter(lambda item: not hasattr(item, 'reversion_hide'),reversion.get_registered_models())
|
||||||
|
if app != None:
|
||||||
|
models = filter(lambda item: item in apps.get_app_config(app).get_models(),models)
|
||||||
|
return models
|
||||||
|
|
||||||
|
class ActivityTable(generic.ListView):
|
||||||
|
model = RIGSVersion
|
||||||
|
template_name = "activity_table.html"
|
||||||
|
paginate_by = 25
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
versions = RIGSVersion.objects.get_for_multiple_models(self.kwargs['models'])
|
||||||
|
return versions.order_by("-revision__date_created")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(ActivityTable, self).get_context_data(**kwargs)
|
||||||
|
context['title'] = self.kwargs['app']
|
||||||
|
if self.kwargs['app'] != 'rigboard':
|
||||||
|
context['override'] = 'base_{}.html'.format(self.kwargs['app'])
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
# Appears on homepage
|
||||||
|
@method_decorator(never_cache, name='dispatch') # Disable browser based caching
|
||||||
|
class ActivityFeed(generic.ListView):
|
||||||
|
model = RIGSVersion
|
||||||
|
template_name = "activity_feed_data.html"
|
||||||
|
paginate_by = 25
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
versions = RIGSVersion.objects.get_for_multiple_models(get_models())
|
||||||
|
return versions.order_by("-revision__date_created")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
# Call the base implementation first to get a context
|
||||||
|
context = super(ActivityFeed, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
|
maxTimeDelta = datetime.timedelta(hours=1)
|
||||||
|
|
||||||
|
items = []
|
||||||
|
|
||||||
|
for thisVersion in context['object_list']:
|
||||||
|
thisVersion.withPrevious = False
|
||||||
|
if len(items) >= 1:
|
||||||
|
timeDiff = items[-1].revision.date_created - thisVersion.revision.date_created
|
||||||
|
timeTogether = timeDiff < maxTimeDelta
|
||||||
|
sameUser = thisVersion.revision.user_id == items[-1].revision.user_id
|
||||||
|
thisVersion.withPrevious = timeTogether & sameUser
|
||||||
|
|
||||||
|
items.append(thisVersion)
|
||||||
|
|
||||||
|
return context
|
||||||
Reference in New Issue
Block a user