mirror of
https://github.com/Southampton-RSG/breccia-mapper.git
synced 2026-03-03 11:27:09 +00:00
feat: add view to end relationship
This commit is contained in:
37
people/migrations/0049_relationship_latest_by_timestamp.py
Normal file
37
people/migrations/0049_relationship_latest_by_timestamp.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# Generated by Django 2.2.10 on 2021-03-19 10:50
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('people', '0048_disciplines_and_organisations'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='organisationanswerset',
|
||||
options={'get_latest_by': 'timestamp', 'ordering': ['timestamp']},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='organisationrelationship',
|
||||
options={'get_latest_by': 'created'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='organisationrelationshipanswerset',
|
||||
options={'get_latest_by': 'timestamp', 'ordering': ['timestamp']},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='personanswerset',
|
||||
options={'get_latest_by': 'timestamp', 'ordering': ['timestamp']},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='relationship',
|
||||
options={'get_latest_by': 'created'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='relationshipanswerset',
|
||||
options={'get_latest_by': 'timestamp', 'ordering': ['timestamp']},
|
||||
),
|
||||
]
|
||||
37
people/migrations/0050_relationship_remove_timestamps.py
Normal file
37
people/migrations/0050_relationship_remove_timestamps.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# Generated by Django 2.2.10 on 2021-03-19 11:09
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('people', '0049_relationship_latest_by_timestamp'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='organisationrelationship',
|
||||
options={},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='organisationrelationship',
|
||||
name='created',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='organisationrelationship',
|
||||
name='expired',
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='relationship',
|
||||
options={},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='relationship',
|
||||
name='created',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='relationship',
|
||||
name='expired',
|
||||
),
|
||||
]
|
||||
@@ -124,6 +124,7 @@ class AnswerSet(models.Model):
|
||||
ordering = [
|
||||
'timestamp',
|
||||
]
|
||||
get_latest_by = 'timestamp'
|
||||
|
||||
#: Entity to which this answer set belongs
|
||||
#: This foreign key must be added to each concrete subclass
|
||||
@@ -145,6 +146,10 @@ class AnswerSet(models.Model):
|
||||
null=True,
|
||||
editable=False)
|
||||
|
||||
@property
|
||||
def is_current(self) -> bool:
|
||||
return self.replaced_timestamp is None
|
||||
|
||||
def as_dict(self, answers: typing.Optional[typing.Dict[str, typing.Any]] = None):
|
||||
"""Get the answers from this set as a dictionary for use in Form.initial."""
|
||||
if answers is None:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""
|
||||
Models describing relationships between people.
|
||||
"""
|
||||
"""Models describing relationships between people."""
|
||||
|
||||
import typing
|
||||
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
@@ -59,15 +59,17 @@ class Relationship(models.Model):
|
||||
blank=False,
|
||||
null=False)
|
||||
|
||||
#: When was this relationship defined?
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
@property
|
||||
def current_answers(self) -> typing.Optional['RelationshipAnswerSet']:
|
||||
answer_set = self.answer_sets.latest()
|
||||
if answer_set.is_current:
|
||||
return answer_set
|
||||
|
||||
#: When was this marked as expired? Default None means it has not expired
|
||||
expired = models.DateTimeField(blank=True, null=True)
|
||||
return None
|
||||
|
||||
@property
|
||||
def current_answers(self) -> 'RelationshipAnswerSet':
|
||||
return self.answer_sets.last()
|
||||
def is_current(self) -> bool:
|
||||
return self.current_answers is not None
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('people:relationship.detail', kwargs={'pk': self.pk})
|
||||
@@ -141,15 +143,17 @@ class OrganisationRelationship(models.Model):
|
||||
blank=False,
|
||||
null=False)
|
||||
|
||||
#: When was this relationship defined?
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
@property
|
||||
def current_answers(self) -> typing.Optional['OrganisationRelationshipAnswerSet']:
|
||||
answer_set = self.answer_sets.latest()
|
||||
if answer_set.is_current:
|
||||
return answer_set
|
||||
|
||||
#: When was this marked as expired? Default None means it has not expired
|
||||
expired = models.DateTimeField(blank=True, null=True)
|
||||
return None
|
||||
|
||||
@property
|
||||
def current_answers(self) -> 'OrganisationRelationshipAnswerSet':
|
||||
return self.answer_sets.last()
|
||||
def is_current(self) -> bool:
|
||||
return self.current_answers is not None
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('people:organisation.relationship.detail',
|
||||
|
||||
@@ -37,6 +37,14 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if relationship %}
|
||||
<div class="col-md-3">
|
||||
<a class="btn btn-danger btn-block"
|
||||
href="{% url 'people:relationship.end' pk=relationship.pk %}">End Relationship
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -37,6 +37,14 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if relationship %}
|
||||
<div class="col-md-3">
|
||||
<a class="btn btn-danger btn-block"
|
||||
href="{% url 'people:relationship.end' pk=relationship.pk %}">End Relationship
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -13,7 +13,15 @@
|
||||
<tbody>
|
||||
{% for relationship in person.relationships_as_source.all %}
|
||||
<tr>
|
||||
<td>{{ relationship.target }}</td>
|
||||
<td>
|
||||
{% if relationship.is_current %}
|
||||
{{ relationship.target }}
|
||||
{% else %}
|
||||
<del>
|
||||
{{ relationship.target }}
|
||||
</del>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-sm btn-info"
|
||||
href="{% url 'people:person.detail' pk=relationship.target.pk %}">Profile</a>
|
||||
|
||||
@@ -60,6 +60,10 @@ urlpatterns = [
|
||||
views.relationship.RelationshipUpdateView.as_view(),
|
||||
name='relationship.update'),
|
||||
|
||||
path('relationships/<int:pk>/end',
|
||||
views.relationship.RelationshipEndView.as_view(),
|
||||
name='relationship.end'),
|
||||
|
||||
################################
|
||||
# OrganisationRelationship views
|
||||
path('organisations/<int:organisation_pk>/relationships/create',
|
||||
|
||||
@@ -44,8 +44,10 @@ class PersonListView(LoginRequiredMixin, ListView):
|
||||
existing_relationships = set()
|
||||
try:
|
||||
existing_relationships = set(
|
||||
self.request.user.person.relationship_targets.values_list(
|
||||
'pk', flat=True))
|
||||
self.request.user.person.relationships_as_source.filter(
|
||||
answer_sets__replaced_timestamp__isnull=True
|
||||
).values_list('target_id', flat=True)
|
||||
)
|
||||
|
||||
except ObjectDoesNotExist:
|
||||
# No linked Person yet
|
||||
@@ -132,9 +134,12 @@ class ProfileView(LoginRequiredMixin, DetailView):
|
||||
|
||||
context['relationship'] = None
|
||||
try:
|
||||
context['relationship'] = models.Relationship.objects.get(
|
||||
relationship = models.Relationship.objects.get(
|
||||
source=self.request.user.person, target=self.object)
|
||||
|
||||
if relationship.is_current:
|
||||
context['relationship'] = relationship
|
||||
|
||||
except models.Relationship.DoesNotExist:
|
||||
pass
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.views.generic import DetailView, RedirectView, UpdateView
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
|
||||
from people import forms, models, permissions
|
||||
|
||||
@@ -91,6 +92,30 @@ class RelationshipUpdateView(permissions.UserIsLinkedPersonMixin, UpdateView):
|
||||
return self.object.get_absolute_url()
|
||||
|
||||
|
||||
class RelationshipEndView(permissions.UserIsLinkedPersonMixin,
|
||||
SingleObjectMixin, RedirectView):
|
||||
"""View for marking a relationship as ended.
|
||||
|
||||
Sets `replaced_timestamp` on all answer sets where this is currently null.
|
||||
"""
|
||||
model = models.Relationship
|
||||
|
||||
def get_test_person(self) -> models.Person:
|
||||
"""Get the person instance which should be used for access control checks."""
|
||||
return self.get_object().source
|
||||
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
"""Mark any previous answer sets as replaced."""
|
||||
now_date = timezone.now().date()
|
||||
relationship = self.get_object()
|
||||
|
||||
relationship.answer_sets.filter(
|
||||
replaced_timestamp__isnull=True).update(
|
||||
replaced_timestamp=now_date)
|
||||
|
||||
return relationship.target.get_absolute_url()
|
||||
|
||||
|
||||
class OrganisationRelationshipDetailView(permissions.UserIsLinkedPersonMixin,
|
||||
DetailView):
|
||||
"""View displaying details of an :class:`OrganisationRelationship`."""
|
||||
|
||||
Reference in New Issue
Block a user