Merge pull request #37 from Southampton-RSG/dev

Merge first batch of changes from user acceptance testing
This commit is contained in:
James Graham
2020-06-26 12:10:39 +01:00
committed by GitHub
9 changed files with 342 additions and 204 deletions

View File

@@ -376,16 +376,20 @@ else:
# Import customisation app settings if present
CUSTOMISATION_NAME = None
TEMPLATE_NAME_INDEX = 'index.html'
TEMPLATE_WELCOME_EMAIL_NAME = 'welcome-email'
try:
from custom.settings import (CUSTOMISATION_NAME, TEMPLATE_NAME_INDEX,
TEMPLATE_WELCOME_EMAIL_NAME)
from custom.settings import (
CUSTOMISATION_NAME,
TEMPLATE_NAME_INDEX,
TEMPLATE_WELCOME_EMAIL_NAME
)
logger.info("Loaded customisation app: %s", CUSTOMISATION_NAME)
INSTALLED_APPS.append('custom')
except ImportError as e:
logger.info("No customisation app loaded: %s", e)
except ImportError as exc:
logger.info("No customisation app loaded: %s", exc)
# Set default values if no customisations loaded
CUSTOMISATION_NAME = None
TEMPLATE_NAME_INDEX = 'index.html'
TEMPLATE_WELCOME_EMAIL_NAME = 'welcome-email'

View File

@@ -25,8 +25,7 @@
crossorigin="anonymous" />
{% load staticfiles %}
<link rel="stylesheet"
href="{% static 'css/global.css' %}">
<link rel="stylesheet" href="{% static 'css/global.css' %}">
{% if 'javascript_in_head'|bootstrap_setting %}
{% if 'include_jquery'|bootstrap_setting %}
@@ -38,14 +37,16 @@
{% bootstrap_javascript %}
{% endif %}
{% if form %}
{{ form.media.css }}
{% endif %}
{% block extra_head %}{% endblock %}
</head>
<body>
<div class="content" style="display: flex; flex-direction: column">
<div class="content" style="display: flex; flex-direction: column">
{% block navbar %}
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
@@ -138,7 +139,8 @@
{% if request.user.is_authenticated and not request.user.has_person %}
<div class="alert alert-info rounded-0" role="alert">
<p class="text-center mb-0">
Your profile is currently blank. Please fill in your details so you can be part of the network.
Your profile is currently blank.
Please fill in your details so you can be part of the network.
<a class="btn btn-success"
href="{% url 'people:person.create' %}?user">Profile</a>
@@ -158,15 +160,15 @@
<div class="container">
{% block after_content %}{% endblock %}
</div>
</div>
</div>
<footer class="footer bg-light">
<footer class="footer bg-light">
<div class="container">
<span class="text-muted">{{ settings.PROJECT_LONG_NAME }}</span>
</div>
</footer>
</footer>
{% if not 'javascript_in_head'|bootstrap_setting %}
{% if not 'javascript_in_head'|bootstrap_setting %}
{% if 'include_jquery'|bootstrap_setting %}
{# jQuery JavaScript if it is in body #}
{% bootstrap_jquery jquery='include_jquery'|bootstrap_setting %}
@@ -174,11 +176,13 @@
{# Bootstrap JavaScript if it is in body #}
{% bootstrap_javascript %}
{% endif %}
{% endif %}
{{ form.media.js }}
{% if form %}
{{ form.media.js }}
{% endif %}
{% block extra_script %}{% endblock %}
{% block extra_script %}{% endblock %}
</body>
</html>

View File

@@ -12,7 +12,8 @@ class SimplePersonSerializer(serializers.ModelSerializer):
model = models.Person
fields = [
'id',
'name',
# Name is excluded from exports
# See https://github.com/Southampton-RSG/breccia-mapper/issues/35
]
@@ -21,12 +22,14 @@ class PersonSerializer(base.FlattenedModelSerializer):
model = models.Person
fields = [
'id',
'name',
'core_member',
# Name is excluded from exports
# See https://github.com/Southampton-RSG/breccia-mapper/issues/35
'gender',
'age_group',
'nationality',
'country_of_residence',
'organisation',
'organisation_started_date',
]
@@ -43,6 +46,11 @@ class RelationshipSerializer(base.FlattenedModelSerializer):
]
def underscore(slug: str) -> str:
"""Replace hyphens with underscores in text."""
return slug.replace('-', '_')
class RelationshipAnswerSetSerializer(base.FlattenedModelSerializer):
relationship = RelationshipSerializer()
@@ -61,7 +69,7 @@ class RelationshipAnswerSetSerializer(base.FlattenedModelSerializer):
# Add relationship questions to columns
for question in models.RelationshipQuestion.objects.all():
headers.append(question.slug.replace('-', '_'))
headers.append(underscore(question.slug))
return headers
@@ -71,7 +79,7 @@ class RelationshipAnswerSetSerializer(base.FlattenedModelSerializer):
try:
# Add relationship question answers to data
for answer in instance.question_answers.all():
rep[answer.question.slug.replace('-', '_')] = answer.slug.replace('-', '_')
rep[underscore(answer.question.slug)] = underscore(answer.slug)
except AttributeError:
pass

View File

@@ -1,13 +1,29 @@
"""
Forms for creating / updating models belonging to the 'people' app.
"""
import typing
from django import forms
from django.forms.widgets import SelectDateWidget
from django.utils import timezone
from django_select2.forms import Select2Widget, Select2MultipleWidget
from . import models
def get_date_year_range() -> typing.Iterable[int]:
"""
Get sensible year range for SelectDateWidgets in the past.
By default these widgets show 10 years in the future.
"""
num_years_display = 60
this_year = timezone.datetime.now().year
return range(this_year, this_year - num_years_display, -1)
class PersonForm(forms.ModelForm):
"""
Form for creating / updating an instance of :class:`Person`.
@@ -16,14 +32,14 @@ class PersonForm(forms.ModelForm):
model = models.Person
fields = [
'name',
'core_member',
'gender',
'age_group',
'nationality',
'country_of_residence',
'organisation',
'organisation_started_date',
'job_title',
'discipline',
'disciplines',
'role',
'themes',
]
@@ -32,6 +48,16 @@ class PersonForm(forms.ModelForm):
'country_of_residence': Select2Widget(),
'themes': Select2MultipleWidget(),
}
help_texts = {
'organisation_started_date':
'If you don\'t know the exact date, an approximate date is okay.',
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['organisation_started_date'].widget = SelectDateWidget(
years=get_date_year_range())
class DynamicAnswerSetBase(forms.Form):
@@ -87,4 +113,7 @@ class NetworkFilterForm(DynamicAnswerSetBase):
super().__init__(*args, **kwargs)
# Add date field to select relationships at a particular point in time
self.fields['date'] = forms.DateField(required=False)
self.fields['date'] = forms.DateField(
required=False,
widget=SelectDateWidget(years=get_date_year_range()),
help_text='Show relationships as they were on this date')

View File

@@ -0,0 +1,17 @@
# Generated by Django 2.2.10 on 2020-06-24 11:14
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('people', '0018_require_user_email'),
]
operations = [
migrations.RemoveField(
model_name='person',
name='core_member',
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 2.2.10 on 2020-06-24 12:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('people', '0019_remove_person_core_member'),
]
operations = [
migrations.AddField(
model_name='person',
name='organisation_started_date',
field=models.DateField(null=True, verbose_name='Date started at this organisation'),
),
]

View File

@@ -0,0 +1,61 @@
# Generated by Django 2.2.10 on 2020-06-24 14:19
from django.db import migrations, models
def migrate_forward(apps, schema_editor):
Person = apps.get_model('people', 'Person')
for person in Person.objects.all():
try:
person.disciplines = person.discipline.name
person.save()
except AttributeError:
pass
def migrate_backward(apps, schema_editor):
Person = apps.get_model('people', 'Person')
Discipline = apps.get_model('people', 'Discipline')
for person in Person.objects.all():
try:
discipline_str = person.disciplines.split(',')[0]
except AttributeError:
pass
else:
# Returns None if not found - doesn't raise exception
discipline = Discipline.objects.filter(name=discipline_str).first()
if not discipline:
discipline = Discipline.objects.create(
name=discipline_str,
code=discipline_str
if len(discipline_str) < 15 else discipline_str[:15])
person.discipline = discipline
person.save()
class Migration(migrations.Migration):
dependencies = [
('people', '0020_person_organisation_started_date'),
]
operations = [
migrations.AddField(
model_name='person',
name='disciplines',
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.RunPython(migrate_forward, migrate_backward),
migrations.RemoveField(
model_name='person',
name='discipline',
),
migrations.DeleteModel(name='Discipline', ),
]

View File

@@ -19,7 +19,6 @@ __all__ = [
'User',
'Organisation',
'Role',
'Discipline',
'Theme',
'Person',
]
@@ -82,19 +81,6 @@ class Role(models.Model):
return self.name
class Discipline(models.Model):
"""
Discipline within which a :class:`Person` works.
"""
name = models.CharField(max_length=255, blank=False, null=False)
#: Short code using system such as JACS 3
code = models.CharField(max_length=15, blank=True, null=False)
def __str__(self) -> str:
return self.name
class Theme(models.Model):
"""
Project theme within which a :class:`Person` works.
@@ -122,9 +108,6 @@ class Person(models.Model):
#: Name of the person
name = models.CharField(max_length=255, blank=False, null=False)
#: Is this person a member of the core project team?
core_member = models.BooleanField(default=False, blank=False, null=False)
#: People with whom this person has relationship - via intermediate :class:`Relationship` model
relationship_targets = models.ManyToManyField(
'self',
@@ -175,15 +158,15 @@ class Person(models.Model):
blank=True,
null=True)
#: When did this person start at their current organisation?
organisation_started_date = models.DateField(
'Date started at this organisation', blank=False, null=True)
#: Job title this person holds within their organisation
job_title = models.CharField(max_length=255, blank=True, null=False)
#: Discipline within which this person works
discipline = models.ForeignKey(Discipline,
on_delete=models.PROTECT,
related_name='people',
blank=True,
null=True)
#: Discipline(s) within which this person works
disciplines = models.CharField(max_length=255, blank=True, null=True)
#: Role this person holds within the project
role = models.ForeignKey(Role,

View File

@@ -14,6 +14,14 @@
<hr>
{% if person.user == request.user or request.user.is_superuser %}
{% if person.user != request.user and request.user.is_superuser %}
<div class="alert alert-warning">
<strong>NB:</strong> You are able to see the details of this person because you are an admin.
Regular users are not able to see this information for people other than themselves.
</div>
{% endif %}
<dl>
{% if person.gender %}
<dt>Gender</dt>
@@ -38,6 +46,11 @@
{% if person.organisation %}
<dt>Organisation</dt>
<dd>{{ person.organisation }}</dd>
{% if person.organisation_started_date %}
<dt>Started Date</dt>
<dd>{{ person.organisation_started_date }}</dd>
{% endif %}
{% endif %}
{% if person.job_title %}
@@ -50,9 +63,9 @@
<dd>{{ person.role }}</dd>
{% endif %}
{% if person.dispipline %}
<dt>Discipline</dt>
<dd>{{ person.discipline }}</dd>
{% if person.disciplines %}
<dt>Discipline(s)</dt>
<dd>{{ person.disciplines }}</dd>
{% endif %}
{% if person.themes.exists %}
@@ -64,6 +77,7 @@
</dd>
{% endif %}
</dl>
{% endif %}
<a class="btn btn-success"
href="{% url 'people:person.update' pk=person.pk %}">Update</a>