major rcr update
This commit is contained in:
+3
-1
@@ -6,4 +6,6 @@ __pycache__
|
|||||||
rad/settings_local.py
|
rad/settings_local.py
|
||||||
venv
|
venv
|
||||||
.venv/
|
.venv/
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
temp/
|
||||||
+3
-1
@@ -77,7 +77,9 @@ INSTALLED_APPS = [
|
|||||||
"django_htmx",
|
"django_htmx",
|
||||||
"crispy_forms",
|
"crispy_forms",
|
||||||
"crispy_bootstrap4",
|
"crispy_bootstrap4",
|
||||||
"autocomplete"
|
"autocomplete",
|
||||||
|
'markdownify.apps.MarkdownifyConfig',
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|||||||
+9
-3
@@ -1,11 +1,17 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
|
from reversion.admin import VersionAdmin
|
||||||
|
|
||||||
from rcr.models import Item, Category, Level, Outcome, OutcomeReason
|
from rcr.models import Item, RadiologyCategory, OncologyCategory, Level, Outcome, OutcomeReason
|
||||||
|
|
||||||
admin.site.register(Item)
|
@admin.register(Item)
|
||||||
admin.site.register(Category)
|
class ItemAdmin(VersionAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
#admin.site.register(Item, ItemAdmin)
|
||||||
|
admin.site.register(RadiologyCategory)
|
||||||
|
admin.site.register(OncologyCategory)
|
||||||
admin.site.register(Level)
|
admin.site.register(Level)
|
||||||
admin.site.register(Outcome)
|
admin.site.register(Outcome)
|
||||||
admin.site.register(OutcomeReason)
|
admin.site.register(OutcomeReason)
|
||||||
Executable
+81
@@ -0,0 +1,81 @@
|
|||||||
|
import django_filters
|
||||||
|
|
||||||
|
from .models import Item
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_rad(request):
|
||||||
|
if request is None:
|
||||||
|
return User.objects.none()
|
||||||
|
|
||||||
|
queryset = User.objects.filter(groups__name="rcr_radiology_assessor")
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def get_onc(request):
|
||||||
|
if request is None:
|
||||||
|
return User.objects.none()
|
||||||
|
|
||||||
|
queryset = User.objects.filter(groups__name="rcr_oncology_assessor")
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def get_assessor(request):
|
||||||
|
#if request is None:
|
||||||
|
# return User.objects.none()
|
||||||
|
|
||||||
|
queryset = User.objects.filter(Q(groups__name="rcr_oncology_assessor") | Q(groups__name="rcr_radiology_assessor") )
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
class ItemFilter(django_filters.FilterSet):
|
||||||
|
assigned_to_radiology = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=get_rad, null_label="No user"
|
||||||
|
)
|
||||||
|
assigned_to_oncology = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=get_onc, null_label="No user"
|
||||||
|
)
|
||||||
|
assessed_by = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=get_assessor, null_label="No user"
|
||||||
|
)
|
||||||
|
specialty = django_filters.MultipleChoiceFilter(choices=Item.SPECIALTY_CHOICES
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Item
|
||||||
|
fields = {
|
||||||
|
"name": ["icontains"],
|
||||||
|
"description": ["icontains"],
|
||||||
|
"content_type": ["icontains"],
|
||||||
|
"created_on": ["exact"],
|
||||||
|
"specialty": ["exact"],
|
||||||
|
"targeted_to_group": ["exact"],
|
||||||
|
"assigned_to_radiology": ["exact"],
|
||||||
|
"assigned_to_oncology": ["exact"],
|
||||||
|
"assessed_by": ["exact"],
|
||||||
|
"completed_radiology": ["exact"],
|
||||||
|
"completed_oncology": ["exact"],
|
||||||
|
"needs_review": ["exact"],
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#def __init__(
|
||||||
|
# self,
|
||||||
|
# data=None,
|
||||||
|
# queryset=None,
|
||||||
|
# prefix=None,
|
||||||
|
# strict=None,
|
||||||
|
# user=None,
|
||||||
|
# request=None,
|
||||||
|
#):
|
||||||
|
# if not request.user.groups.filter(name="rapid_checker").exists():
|
||||||
|
# queryset = queryset.filter(open_access=True) | queryset.filter(
|
||||||
|
# author__id=request.user.id
|
||||||
|
# )
|
||||||
|
# super(RapidFilter, self).__init__(
|
||||||
|
# data=data, queryset=queryset, prefix=prefix, request=request
|
||||||
|
# )
|
||||||
|
# pass
|
||||||
+23
-6
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.admin import widgets
|
from django.contrib.admin import widgets
|
||||||
from django.forms import (
|
from django.forms import (
|
||||||
@@ -12,17 +11,35 @@ from django.forms import (
|
|||||||
CharField,
|
CharField,
|
||||||
ValidationError,
|
ValidationError,
|
||||||
modelformset_factory,
|
modelformset_factory,
|
||||||
CheckboxSelectMultiple
|
CheckboxSelectMultiple,
|
||||||
)
|
)
|
||||||
|
|
||||||
from rcr.models import Item, Category, Level
|
from rcr.models import Item, RadiologyCategory, OncologyCategory, Level
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
|
||||||
class ItemForm(ModelForm):
|
class ItemForm(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Item
|
model = Item
|
||||||
exclude = ["rcr_platform_id", "name", "assessed_by", "assessed_date", "assigned_to"]
|
exclude = [
|
||||||
#fields = ["category", "level"]
|
"rcr_platform_id",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
"content_type",
|
||||||
|
"created_on",
|
||||||
|
"number_of_items",
|
||||||
|
"specialty",
|
||||||
|
"access_count",
|
||||||
|
"targeted_to_group",
|
||||||
|
"assessed_by",
|
||||||
|
"assessed_date",
|
||||||
|
"assigned_to_radiology",
|
||||||
|
"assigned_to_oncology",
|
||||||
|
"review_link",
|
||||||
|
"review_link_password",
|
||||||
|
]
|
||||||
|
# fields = ["category", "level"]
|
||||||
|
|
||||||
|
|
||||||
class AssessorAssignmentForm(Form):
|
class AssessorAssignmentForm(Form):
|
||||||
items = ModelMultipleChoiceField(queryset=Item.objects.filter(assigned_to=None))
|
items = ModelMultipleChoiceField(queryset=Item.objects.all(), widget=forms.SelectMultiple(attrs={'size': 20}))
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import csv
|
||||||
|
from pathlib import Path
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from rcr.models import Item
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
import csv
|
||||||
|
|
||||||
|
class DictReaderStrip(csv.DictReader):
|
||||||
|
@property
|
||||||
|
def fieldnames(self):
|
||||||
|
if self._fieldnames is None:
|
||||||
|
# Initialize self._fieldnames
|
||||||
|
# Note: DictReader is an old-style class, so can't use super()
|
||||||
|
csv.DictReader.fieldnames.fget(self)
|
||||||
|
if self._fieldnames is not None:
|
||||||
|
self._fieldnames = [name.strip() for name in self._fieldnames]
|
||||||
|
return self._fieldnames
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Imports the RCR spreadsheet"
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
# parser.add_argument("poll_ids", nargs="+", type=int)
|
||||||
|
parser.add_argument('--file', type=argparse.FileType('r'))
|
||||||
|
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
#print(options)
|
||||||
|
#path = Path(options["file"])
|
||||||
|
#with open(path) as f:
|
||||||
|
reader = DictReaderStrip(options["file"])
|
||||||
|
#reader = csv.DictReader(f)
|
||||||
|
for row in reader:
|
||||||
|
if row["Access count (all time)"] == "":
|
||||||
|
row["Access count (all time)"] = None
|
||||||
|
if row["Number of items"] == "":
|
||||||
|
row["Number of items"] = None
|
||||||
|
if row["Number of items"] == "Unknown":
|
||||||
|
row["Number of items"] = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
item = Item.objects.get(rcr_platform_id=row["Unique Identifier"])
|
||||||
|
|
||||||
|
item.name=row["Name"]
|
||||||
|
item.description=row["Description"]
|
||||||
|
item.content_type=row["Content type"]
|
||||||
|
item.created_on=row["Created on"]
|
||||||
|
item.number_of_items=row["Number of items"]
|
||||||
|
item.specialty=row["Speciality"]
|
||||||
|
item.access_count=row["Access count (all time)"]
|
||||||
|
item.targeted_to_group=row["Targeted to group"]
|
||||||
|
item.review_link=row["Review link (if applicable)"]
|
||||||
|
item.review_link_password=row["Review link password (if applicable)"]
|
||||||
|
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.SUCCESS(f"Item updated: {item.pk}/{item.name}")
|
||||||
|
)
|
||||||
|
except Item.DoesNotExist:
|
||||||
|
|
||||||
|
item = Item.objects.create(
|
||||||
|
rcr_platform_id=row["Unique Identifier"],
|
||||||
|
name=row["Name"],
|
||||||
|
description=row["Description"],
|
||||||
|
content_type=row["Content type"],
|
||||||
|
created_on=row["Created on"],
|
||||||
|
number_of_items=row["Number of items"],
|
||||||
|
specialty=row["Speciality"],
|
||||||
|
access_count=row["Access count (all time)"],
|
||||||
|
targeted_to_group=row["Targeted to group"],
|
||||||
|
review_link=row["Review link (if applicable)"],
|
||||||
|
review_link_password=row["Review link password (if applicable)"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.SUCCESS(f"Item created: {item.pk}/{item.name}")
|
||||||
|
)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2024-01-16 22:56
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rcr', '0009_item_content_type_item_created_on_item_description_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='item',
|
||||||
|
name='number_of_items',
|
||||||
|
field=models.IntegerField(null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='item',
|
||||||
|
name='rcr_platform_id',
|
||||||
|
field=models.CharField(max_length=255, unique=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2024-01-16 22:59
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rcr', '0010_alter_item_number_of_items_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='item',
|
||||||
|
name='number_of_items',
|
||||||
|
field=models.IntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='item',
|
||||||
|
name='unique_views_2023',
|
||||||
|
field=models.IntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2024-01-17 23:05
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rcr', '0011_alter_item_number_of_items_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='item',
|
||||||
|
name='comments',
|
||||||
|
field=models.TextField(blank=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='item',
|
||||||
|
name='needs_review',
|
||||||
|
field=models.BooleanField(default=False, help_text='Check if this item needs review.'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='item',
|
||||||
|
name='targeted_to_group',
|
||||||
|
field=models.CharField(blank=True, default='Targeted', max_length=255),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2024-01-19 15:31
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rcr', '0012_item_comments_item_needs_review_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='item',
|
||||||
|
old_name='completed',
|
||||||
|
new_name='completed_radiology',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2024-01-19 15:31
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rcr', '0013_rename_completed_item_completed_radiology'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='item',
|
||||||
|
name='completed_oncology',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2024-01-22 09:51
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rcr', '0014_item_completed_oncology'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='item',
|
||||||
|
old_name='unique_views_2023',
|
||||||
|
new_name='access_count',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='item',
|
||||||
|
name='review_link',
|
||||||
|
field=models.CharField(blank=True, default='', max_length=255),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='item',
|
||||||
|
name='review_link_password',
|
||||||
|
field=models.CharField(blank=True, default='', max_length=255),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2024-01-22 11:02
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('rcr', '0015_rename_unique_views_2023_item_access_count_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='item',
|
||||||
|
name='assigned_to',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='item',
|
||||||
|
name='assigned_to_oncology',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_items_oncology', to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='item',
|
||||||
|
name='assigned_to_radiology',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_items_radiology', to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2024-01-22 20:51
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rcr', '0016_remove_item_assigned_to_item_assigned_to_oncology_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameModel(
|
||||||
|
old_name='Category',
|
||||||
|
new_name='RadiologyCategory',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# Generated by Django 4.1.4 on 2024-01-22 20:54
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rcr', '0017_rename_category_radiologycategory'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='OncologyCategory',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='item',
|
||||||
|
old_name='category',
|
||||||
|
new_name='radiology_category',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='item',
|
||||||
|
name='oncology_category',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='rcr.oncologycategory'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+37
-8
@@ -2,9 +2,11 @@ from django.conf import settings
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
import reversion
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
||||||
|
@reversion.register()
|
||||||
class Item(models.Model):
|
class Item(models.Model):
|
||||||
class LevelChoices(models.TextChoices):
|
class LevelChoices(models.TextChoices):
|
||||||
NONE = "", _("None")
|
NONE = "", _("None")
|
||||||
@@ -13,20 +15,29 @@ class Item(models.Model):
|
|||||||
POST_GEN = "GEN", _("Post FRCR Generalist")
|
POST_GEN = "GEN", _("Post FRCR Generalist")
|
||||||
POST_SPEC = "SPEC", _("Post FRCR Specialist")
|
POST_SPEC = "SPEC", _("Post FRCR Specialist")
|
||||||
|
|
||||||
|
SPECIALTY_CHOICES = (
|
||||||
|
("Radiology", "Radiology"),
|
||||||
|
("Oncology", "Oncology"),
|
||||||
|
("Cross-faculty", "Cross-faculty"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
name = models.CharField(max_length=200, blank=True, default="")
|
name = models.CharField(max_length=200, blank=True, default="")
|
||||||
description = models.TextField(blank=True, default="")
|
description = models.TextField(blank=True, default="")
|
||||||
content_type = models.CharField(max_length=200, blank=True, default="")
|
content_type = models.CharField(max_length=200, blank=True, default="")
|
||||||
created_on = models.DateTimeField(null=True, blank=True)
|
created_on = models.DateTimeField(null=True, blank=True)
|
||||||
number_of_items = models.IntegerField(default=1)
|
number_of_items = models.IntegerField(null=True, blank=True)
|
||||||
specialty = models.CharField(max_length=50,blank=True, default="")
|
specialty = models.CharField(max_length=50,blank=True, default="")
|
||||||
unique_views_2023 = models.IntegerField(null=True)
|
access_count = models.IntegerField(null=True, blank=True)
|
||||||
targeted_to_group = models.CharField(max_length=255, default="Targeted")
|
targeted_to_group = models.CharField(max_length=255, default="Targeted", blank=True)
|
||||||
|
review_link = models.CharField(max_length=255, blank=True, default="")
|
||||||
|
review_link_password = models.CharField(max_length=255, blank=True, default="")
|
||||||
|
|
||||||
|
|
||||||
rcr_platform_id = models.CharField(max_length=255, unique=True)
|
rcr_platform_id = models.CharField(max_length=255, unique=True)
|
||||||
|
|
||||||
category = models.ForeignKey("Category", on_delete=models.SET_NULL, null=True, blank=True)
|
radiology_category = models.ForeignKey("RadiologyCategory", on_delete=models.SET_NULL, null=True, blank=True, related_name="item_radiology")
|
||||||
|
oncology_category = models.ForeignKey("OncologyCategory", on_delete=models.SET_NULL, null=True, blank=True, related_name="item_oncology")
|
||||||
|
|
||||||
level = models.ManyToManyField("Level", blank=True)
|
level = models.ManyToManyField("Level", blank=True)
|
||||||
|
|
||||||
@@ -34,26 +45,44 @@ class Item(models.Model):
|
|||||||
|
|
||||||
assessed_by = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name="assessed_items")
|
assessed_by = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name="assessed_items")
|
||||||
|
|
||||||
assigned_to = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL, related_name="assigned_items")
|
assigned_to_radiology = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL, related_name="assigned_items_radiology")
|
||||||
|
assigned_to_oncology = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL, related_name="assigned_items_oncology")
|
||||||
|
|
||||||
outcome = models.ForeignKey("Outcome", on_delete=models.SET_NULL, blank=True, null=True)
|
outcome = models.ForeignKey("Outcome", on_delete=models.SET_NULL, blank=True, null=True)
|
||||||
outcome_reason = models.ForeignKey("OutcomeReason", on_delete=models.SET_NULL, blank=True, null=True)
|
outcome_reason = models.ForeignKey("OutcomeReason", on_delete=models.SET_NULL, blank=True, null=True)
|
||||||
outcome_free_text = models.CharField(max_length=255, help_text="Reason for outcome (if not available above)", default="", blank=True)
|
outcome_free_text = models.CharField(max_length=255, help_text="Reason for outcome (if not available above)", default="", blank=True)
|
||||||
|
|
||||||
completed = models.BooleanField(default=False)
|
|
||||||
|
comments = models.TextField(blank=True)
|
||||||
|
needs_review = models.BooleanField(default=False, help_text="Check if this item needs review.")
|
||||||
|
|
||||||
|
completed_radiology = models.BooleanField(default=False)
|
||||||
|
completed_oncology = models.BooleanField(default=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ("pk",)
|
ordering = ("pk",)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
completed = ""
|
||||||
|
if self.completed_oncology:
|
||||||
|
completed = " [Completed ONC]"
|
||||||
|
if self.completed_radiology:
|
||||||
|
completed = completed + " [Completed RAD]"
|
||||||
|
|
||||||
|
return f"{self.specialty} / {self.content_type} / {self.name}{completed}"
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("rcr:radiology_detail_view", kwargs={"pk": self.pk})
|
return reverse("rcr:radiology_detail_view", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Category(models.Model):
|
class RadiologyCategory(models.Model):
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class OncologyCategory(models.Model):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@@ -1,10 +1,26 @@
|
|||||||
{% extends 'rcr/base.html' %}
|
{% extends 'rcr/base.html' %}
|
||||||
|
|
||||||
|
{% load auth_extras %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
<h2>Assign items to {{user_to_assign}}</h2>
|
<h2>Assign items to {{user_to_assign}}</h2>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Filter</summary>
|
||||||
|
<form method="get">
|
||||||
|
{{ item_filter.form.as_p }}
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
{% if request.user|has_group:"rcr_radiology_assessor" %}
|
||||||
|
Radiology
|
||||||
|
{% elif request.user|has_group:"rcr_oncology_assessor" %}
|
||||||
|
Oncology
|
||||||
|
{% endif %}
|
||||||
|
assessor.<br/>
|
||||||
|
|
||||||
<form action="" method="post" enctype="multipart/form-data" id="assessor-assignment-form">
|
<form action="" method="post" enctype="multipart/form-data" id="assessor-assignment-form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{assessor_assignment_form}}
|
{{assessor_assignment_form}}
|
||||||
|
|||||||
@@ -5,13 +5,22 @@
|
|||||||
|
|
||||||
<h2>Assessors:</h2>
|
<h2>Assessors:</h2>
|
||||||
|
|
||||||
|
<h3>Radiology</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{% for assessor in assessors %}
|
{% for assessor in rad_assessors %}
|
||||||
<li>
|
<li>
|
||||||
{{assessor}} <a href='{% url "rcr:radiology_assigned_user_view" assessor.pk %}'>(items to assess)</a> <a href='{% url "rcr:radiology_index_completed_by_user_view" assessor.pk %}'>(items assessed)</a> <a href='{% url "rcr:radiology_assessor_assignment_view" assessor.pk %}'>(assign items)</a>
|
{{assessor}} <a href='{% url "rcr:radiology_assigned_user_view" assessor.pk %}'>(items to assess)</a> <a href='{% url "rcr:radiology_index_completed_by_user_view" assessor.pk %}'>(items assessed)</a> <a href='{% url "rcr:radiology_assessor_assignment_view" assessor.pk %}?assigned_to_radiology=null&specialty=Radiology&specialty=Cross-faculty'>(assign items)</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<h3>Oncology</h3>
|
||||||
|
<ul>
|
||||||
|
{% for assessor in onc_assessors %}
|
||||||
|
<li>
|
||||||
|
{{assessor}} <a href='{% url "rcr:radiology_assigned_user_view" assessor.pk %}'>(items to assess)</a> <a href='{% url "rcr:radiology_index_completed_by_user_view" assessor.pk %}'>(items assessed)</a> <a href='{% url "rcr:radiology_assessor_assignment_view" assessor.pk %}?assigned_to_oncology=null&specialty=Oncology&specialty=Cross-faculty'>(assign items)</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -76,6 +76,9 @@
|
|||||||
|
|
||||||
<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
|
<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
|
||||||
<div class="main-nav-header">
|
<div class="main-nav-header">
|
||||||
|
<span id="" class="top-bar-link">
|
||||||
|
<a href="{% url 'rcr:radiology_index_all_view' %}">All</a>
|
||||||
|
</span>
|
||||||
<span id="" class="top-bar-link">
|
<span id="" class="top-bar-link">
|
||||||
<a href="{% url 'rcr:radiology_index_view' %}">Index</a>
|
<a href="{% url 'rcr:radiology_index_view' %}">Index</a>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
{% if assessor %}
|
{% if assessor %}
|
||||||
Assessor: {{assessor}}
|
Assessor: {{assessor}}
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% include 'rcr/item_filter.html' %}
|
||||||
|
|
||||||
|
|
||||||
{% if completed %}
|
{% if completed %}
|
||||||
<h2>Completed items:</h2>
|
<h2>Completed items:</h2>
|
||||||
@@ -24,25 +25,28 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
<ul>
|
<table>
|
||||||
{% for item in items %}
|
{% for item in items %}
|
||||||
|
<tr class="{{item.content_type}} {% if item.completed_radiology %} completed-radiology{% endif %}{% if item.completed_radiology %} completed-oncology{% endif %}">
|
||||||
{% if item.completed %}
|
<td class="{{item.specialty}}">
|
||||||
<li class="completed">
|
{{forloop.counter}}:
|
||||||
{% endif %}
|
</td>
|
||||||
{{forloop.counter}}:
|
<td> {{item.content_type}}</td>
|
||||||
{{item.name}} / {{item.rcr_platform_id}} <a href="{% url 'rcr:radiology_detail_view' item.pk %}">view</a> <a href="{% url 'rcr:radiology_update_view' item.pk %}">edit</a>
|
<td>
|
||||||
</li>
|
{{item.name}}
|
||||||
|
</td>
|
||||||
|
<td><a href="{% url 'rcr:radiology_detail_view' item.pk %}">view</a> <a href="{% url 'rcr:radiology_update_view' item.pk %}">edit</a>
|
||||||
|
</td>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
No items found.
|
No items found.
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
<a href="{% url 'rcr:radiology_index_view' %}">Todo</a>
|
<a href="{% url 'rcr:radiology_index_view' %}">Todo</a>
|
||||||
<a href="{% url 'rcr:radiology_index_completed_view' %}">Done</a>
|
<a href="{% url 'rcr:radiology_index_completed_view' %}">Done</a>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
@@ -52,6 +56,28 @@
|
|||||||
.completed::after {
|
.completed::after {
|
||||||
content: '✓';
|
content: '✓';
|
||||||
color: green;
|
color: green;
|
||||||
};
|
}
|
||||||
|
.Radiology::before {
|
||||||
|
content: "R";
|
||||||
|
}
|
||||||
|
.Radiology {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
.Oncology::before {
|
||||||
|
content: "O";
|
||||||
|
}
|
||||||
|
.Oncology {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
.Cross-faculty::before {
|
||||||
|
content: "C";
|
||||||
|
}
|
||||||
|
.Cross-faculty {
|
||||||
|
color: purple;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
{% endblock css %}
|
{% endblock css %}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
{% extends 'rcr/base.html' %}
|
{% extends 'rcr/base.html' %}
|
||||||
|
{% load markdownify %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Item: {{object.name}}</h2>
|
<h2>Item: {{object.name}}</h2>
|
||||||
|
{% include "rcr/item_rcr_details.html" %}
|
||||||
|
|
||||||
<p>Category: {{object.category}}</p>
|
<p>Radiology Category: {{object.radiology_category}}</p>
|
||||||
|
<p>Oncology Category: {{object.oncology_category}}</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Level(s):
|
Level(s):
|
||||||
@@ -22,7 +25,10 @@
|
|||||||
Date assessed: {{object.assessed_date}}
|
Date assessed: {{object.assessed_date}}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Assigned to: {{object.assigned_to}}
|
Assigned to (radiology): {{object.assigned_to_radiology}}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Assigned to (oncology): {{object.assigned_to_oncology}}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -32,11 +38,22 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Completed: {{object.completed}}
|
Completed (radiology): {{object.completed_radiology}}
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
Completed (oncology): {{object.completed_oncology}}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
<p><a href='{% url "rcr:radiology_update_view" object.pk %}'>Edit</a></p>
|
<p><a href='{% url "rcr:radiology_update_view" object.pk %}'>Edit</a></p>
|
||||||
|
|
||||||
<details><summary> </summary>
|
<details><summary> </summary>
|
||||||
</details>
|
</details>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
{% block css %}
|
||||||
|
<style>
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock css %}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
{% if item_filter %}
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
Filters
|
||||||
|
</summary>
|
||||||
|
<form method="get">
|
||||||
|
{{ item_filter.form.as_p }}
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<div class="float-end opacity-25">{{object.rcr_platform_id}}</div>
|
||||||
|
|
||||||
|
{% load markdownify %}
|
||||||
|
{% if item.content_type == "Web link" or item.content_type == "Video" or item.content_type == "Audio" or item.content_type == "PowerPoint" or item.content_type == "Course" %}
|
||||||
|
<p>Link: <a href="https://cr.rcrlearning.org/#/catalogue/landingpage/item/{{object.rcr_platform_id}}/" title="Link to content on learning hub">click here</a></p>
|
||||||
|
|
||||||
|
{% elif item.content_type == "Curriculum" %}
|
||||||
|
<p>Link: <a href="https://cr.rcrlearning.org/#/catalogue/item/{{object.rcr_platform_id}}/" title="Link to content on learning hub">click here</a></p>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
<p>Unknown content type!</p>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if item.review_link %}
|
||||||
|
<p>Review link: {{item.review_link}}
|
||||||
|
|
||||||
|
{% if item.password %}
|
||||||
|
<br/>Password: {{item.password}}
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Description</b><br/>
|
||||||
|
<pre> {{object.description|markdownify}}</pre>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<b>Description (raw)</b><br/>
|
||||||
|
</summary>
|
||||||
|
<pre> {{object.description}}</pre>
|
||||||
|
</details>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="d-flex flex-row mb-3 flex-wrap">
|
||||||
|
<div class="p-2">
|
||||||
|
<b>Content type</b><br/>
|
||||||
|
{{object.content_type}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-2">
|
||||||
|
<b>Created on</b><br/>
|
||||||
|
{{object.created_on}}
|
||||||
|
</div>
|
||||||
|
<div class="p-2">
|
||||||
|
<b>Number of items</b><br/>
|
||||||
|
{{object.number_of_items}}
|
||||||
|
</div>
|
||||||
|
<div class="p-2">
|
||||||
|
<b>Speciality</b><br/>
|
||||||
|
{{object.specialty}}
|
||||||
|
</div>
|
||||||
|
<div class="p-2">
|
||||||
|
<b>Access count</b><br/>
|
||||||
|
{{object.access_count}}
|
||||||
|
</div>
|
||||||
|
<div class="p-2">
|
||||||
|
<b>Targeted to group</b><br/>
|
||||||
|
{{object.targeted_to_group}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -5,18 +5,28 @@
|
|||||||
{% comment %} {% if request.user.is_superuser %}
|
{% comment %} {% if request.user.is_superuser %}
|
||||||
(<a href="{% url 'admin:auth_user_change' object.id %}" title="Edit the user using the admin interface">Admin Edit</a>)
|
(<a href="{% url 'admin:auth_user_change' object.id %}" title="Edit the user using the admin interface">Admin Edit</a>)
|
||||||
{% endif %} {% endcomment %}
|
{% endif %} {% endcomment %}
|
||||||
<p>Link: <a href="" title="Link to content on learning hub">click here</a></p>
|
|
||||||
|
|
||||||
|
{% include "rcr/item_rcr_details.html" %}
|
||||||
|
|
||||||
<form method="post">{% csrf_token %}
|
<form method="post">{% csrf_token %}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
<input type="submit" value="Update">
|
<input type="submit" value="Update">
|
||||||
|
|
||||||
{% if skip == 0 or skip %}
|
|
||||||
<button> <a href="{% url 'rcr:radiology_update_next_skip_view' skip|add:1 %}">Skip</a> </button>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
{% if skip == 0 or skip %}
|
||||||
|
<a href="{% url 'rcr:radiology_update_next_skip_view' skip|add:1 %}"><button>Skip</button></a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<details><summary> </summary>
|
<details><summary> </summary>
|
||||||
</details>
|
</details>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
<style>
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock css %}
|
||||||
|
|||||||
+47
-12
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -12,13 +10,50 @@ app_name = "rcr"
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("radiology/", views.radiology_index, name="radiology_index_view"),
|
path("radiology/", views.radiology_index, name="radiology_index_view"),
|
||||||
path("radiology/completed", views.radiology_index_completed, name="radiology_index_completed_view"),
|
path("radiology/all", views.radiology_index_all, name="radiology_index_all_view"),
|
||||||
path("radiology/assessors", views.radiology_assessors, name="radiology_assessors_view"),
|
path(
|
||||||
path("radiology/assigned/user/<int:user_pk>", views.radiology_assigned_user, name="radiology_assigned_user_view"),
|
"radiology/completed",
|
||||||
path("radiology/assessors/<int:assessor_pk>/assignment", views.radiology_assessor_assignment, name="radiology_assessor_assignment_view"),
|
views.radiology_index_completed,
|
||||||
path("radiology/completed/user/<int:user_pk>", views.radiology_index_completed_by_user, name="radiology_index_completed_by_user_view"),
|
name="radiology_index_completed_view",
|
||||||
path("radiology/item/<int:pk>/", views.ItemDetailView.as_view(), name="radiology_detail_view"),
|
),
|
||||||
path("radiology/item/next/update", views.ItemUpdateNextView.as_view(), name="radiology_update_next_view"),
|
path(
|
||||||
path("radiology/item/next/update/skip/<int:skip>", views.ItemUpdateNextView.as_view(), name="radiology_update_next_skip_view"),
|
"radiology/assessors",
|
||||||
path("radiology/item/<int:pk>/update", views.ItemUpdateView.as_view(), name="radiology_update_view"),
|
views.radiology_assessors,
|
||||||
]
|
name="radiology_assessors_view",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"radiology/assigned/user/<int:user_pk>",
|
||||||
|
views.radiology_assigned_user,
|
||||||
|
name="radiology_assigned_user_view",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"radiology/assessors/<int:assessor_pk>/assignment",
|
||||||
|
views.radiology_assessor_assignment,
|
||||||
|
name="radiology_assessor_assignment_view",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"radiology/completed/user/<int:user_pk>",
|
||||||
|
views.radiology_index_completed_by_user,
|
||||||
|
name="radiology_index_completed_by_user_view",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"radiology/item/<int:pk>/",
|
||||||
|
views.ItemDetailView.as_view(),
|
||||||
|
name="radiology_detail_view",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"radiology/item/next/update",
|
||||||
|
views.ItemUpdateNextView.as_view(),
|
||||||
|
name="radiology_update_next_view",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"radiology/item/next/update/skip/<int:skip>",
|
||||||
|
views.ItemUpdateNextView.as_view(),
|
||||||
|
name="radiology_update_next_skip_view",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"radiology/item/<int:pk>/update",
|
||||||
|
views.ItemUpdateView.as_view(),
|
||||||
|
name="radiology_update_view",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|||||||
+97
-21
@@ -10,6 +10,8 @@ from django.conf import settings
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
|
|
||||||
|
from django.db.models import Q
|
||||||
|
from rcr.filters import ItemFilter
|
||||||
|
|
||||||
from rcr.models import Item
|
from rcr.models import Item
|
||||||
from rcr.forms import AssessorAssignmentForm, ItemForm
|
from rcr.forms import AssessorAssignmentForm, ItemForm
|
||||||
@@ -20,7 +22,7 @@ from django.core.exceptions import PermissionDenied
|
|||||||
def user_is_rcr(function):
|
def user_is_rcr(function):
|
||||||
def wrap(request, *args, **kwargs):
|
def wrap(request, *args, **kwargs):
|
||||||
if (
|
if (
|
||||||
request.user.groups.filter(name="rcr_radiology_assessor").exists()
|
request.user.groups.filter(Q(name="rcr_radiology_assessor") | Q(name="rcr_oncology_assessor")).exists()
|
||||||
or request.user.is_superuser
|
or request.user.is_superuser
|
||||||
):
|
):
|
||||||
return function(request, *args, **kwargs)
|
return function(request, *args, **kwargs)
|
||||||
@@ -31,12 +33,16 @@ def user_is_rcr(function):
|
|||||||
wrap.__name__ = function.__name__
|
wrap.__name__ = function.__name__
|
||||||
return wrap
|
return wrap
|
||||||
|
|
||||||
|
def user_is_radiology(user):
|
||||||
|
return user.groups.filter(name="rcr_radiology_assessor").exists()
|
||||||
|
def user_is_oncology(user):
|
||||||
|
return user.groups.filter(name="rcr_oncology_assessor").exists()
|
||||||
|
|
||||||
class RCRRequiredMixin(object):
|
class RCRRequiredMixin(object):
|
||||||
def get_object(self, *args, **kwargs):
|
def get_object(self, *args, **kwargs):
|
||||||
obj = super().get_object(*args, **kwargs)
|
obj = super().get_object(*args, **kwargs)
|
||||||
if (
|
if (
|
||||||
self.request.user.groups.filter(name="rcr_radiology_assessor").exists()
|
self.request.user.groups.filter(Q(name="rcr_radiology_assessor") | Q(name="rcr_oncology_assessor")).exists()
|
||||||
or self.request.user.is_superuser
|
or self.request.user.is_superuser
|
||||||
):
|
):
|
||||||
return obj
|
return obj
|
||||||
@@ -45,66 +51,121 @@ class RCRRequiredMixin(object):
|
|||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
@user_is_rcr
|
||||||
|
def radiology_index_all(request):
|
||||||
|
|
||||||
|
item_filter = ItemFilter(request.GET, queryset=Item.objects.all())
|
||||||
|
|
||||||
|
return render(
|
||||||
|
request,
|
||||||
|
"rcr/index.html",
|
||||||
|
{
|
||||||
|
"items": item_filter.qs,
|
||||||
|
"completed": False,
|
||||||
|
"assessor": None,
|
||||||
|
"item_filter": item_filter,
|
||||||
|
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
@user_is_rcr
|
@user_is_rcr
|
||||||
def radiology_index(request, assigned=True, user_pk: int | None = None):
|
def radiology_index(request, assigned=True, user_pk: int | None = None):
|
||||||
|
|
||||||
if assigned:
|
assessor = None
|
||||||
items = Item.objects.filter(assigned_to=request.user).exclude(completed=True)
|
if user_pk is not None:
|
||||||
elif user_pk is not None:
|
assessor = User.objects.get(pk=user_pk)
|
||||||
items = Item.objects.filter(assigned_to__pk=user_pk).exclude(completed=True)
|
elif assigned:
|
||||||
|
assessor = request.user
|
||||||
|
|
||||||
|
if assessor is None:
|
||||||
|
items = Item.objects.all().exclude(completed_radiology=True).exclude(completed_oncology=True)
|
||||||
|
elif assessor.groups.filter(name="rcr_radiology_assessor").exists():
|
||||||
|
items = Item.objects.filter(assigned_to_radiology=assessor).exclude(completed_radiology=True)
|
||||||
|
elif assessor.groups.filter(name="rcr_oncology_assessor").exists():
|
||||||
|
items = Item.objects.filter(assigned_to_oncology=assessor).exclude(completed_oncology=True)
|
||||||
else:
|
else:
|
||||||
items = Item.objects.all().exclude(completed=True)
|
raise Http404
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"rcr/index.html",
|
"rcr/index.html",
|
||||||
{
|
{
|
||||||
"items": items,
|
"items": items,
|
||||||
"completed": False
|
"completed": False,
|
||||||
|
"assessor": assessor
|
||||||
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@user_passes_test(lambda u: u.is_superuser)
|
#def radiology_assessor_assignment_rad(request, assessor_pk: int):
|
||||||
def radiology_assessor_assignment(request, assessor_pk: int):
|
# return radiology_assessor_assignment(request, assessor_pk, "rad")
|
||||||
|
#def radiology_assessor_assignment_onc(request, assessor_pk: int):
|
||||||
|
# return radiology_assessor_assignment(request, assessor_pk, "onc")
|
||||||
|
#def radiology_assessor_assignment_cross(request, assessor_pk: int):
|
||||||
|
# return radiology_assessor_assignment(request, assessor_pk, "cross")
|
||||||
|
|
||||||
|
@user_is_rcr
|
||||||
|
def radiology_assessor_assignment(request, assessor_pk: int, specialty=None):
|
||||||
|
|
||||||
|
item_filter = ItemFilter(request.GET, queryset=Item.objects.all())
|
||||||
|
|
||||||
user = get_object_or_404(User, pk=assessor_pk)
|
user = get_object_or_404(User, pk=assessor_pk)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
assessor_assignment_form = AssessorAssignmentForm(request.POST)
|
assessor_assignment_form = AssessorAssignmentForm(request.POST)
|
||||||
|
assessor_assignment_form.fields["items"].queryset = item_filter.qs
|
||||||
|
|
||||||
|
print(assessor_assignment_form)
|
||||||
|
|
||||||
if assessor_assignment_form.is_valid():
|
if assessor_assignment_form.is_valid():
|
||||||
items_to_update = assessor_assignment_form.cleaned_data["items"]
|
items_to_update = assessor_assignment_form.cleaned_data["items"]
|
||||||
for item in items_to_update:
|
|
||||||
item.assigned_to = user
|
|
||||||
|
|
||||||
Item.objects.filter(pk__in=items_to_update).bulk_update(items_to_update, ["assigned_to"])
|
|
||||||
|
for item in items_to_update:
|
||||||
|
if user_is_radiology(user):
|
||||||
|
item.assigned_to_radiology = user
|
||||||
|
elif user_is_oncology(user):
|
||||||
|
item.assigned_to_oncology = user
|
||||||
|
else:
|
||||||
|
raise Http404
|
||||||
|
|
||||||
|
if user_is_radiology(user):
|
||||||
|
Item.objects.filter(pk__in=items_to_update).bulk_update(items_to_update, ["assigned_to_radiology"])
|
||||||
|
elif user_is_oncology(user):
|
||||||
|
Item.objects.filter(pk__in=items_to_update).bulk_update(items_to_update, ["assigned_to_oncology"])
|
||||||
|
else:
|
||||||
|
raise Http404
|
||||||
|
|
||||||
return HttpResponseRedirect(reverse("rcr:radiology_assessors_view"))
|
return HttpResponseRedirect(reverse("rcr:radiology_assessors_view"))
|
||||||
else:
|
else:
|
||||||
assessor_assignment_form = AssessorAssignmentForm()
|
assessor_assignment_form = AssessorAssignmentForm()
|
||||||
|
assessor_assignment_form.fields["items"].queryset = item_filter.qs
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"rcr/assessor_assignment_form.html",
|
"rcr/assessor_assignment_form.html",
|
||||||
{
|
{
|
||||||
"assessor_assignment_form": assessor_assignment_form,
|
"assessor_assignment_form": assessor_assignment_form,
|
||||||
"user_to_assign": user
|
"user_to_assign": user,
|
||||||
|
"item_filter": item_filter
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@user_is_rcr
|
@user_is_rcr
|
||||||
def radiology_assigned_user(request, user_pk=int):
|
def radiology_assigned_user(request, user_pk=int):
|
||||||
return radiology_index(request, user_pk=user_pk)
|
return radiology_index(request, user_pk=user_pk)
|
||||||
pass
|
|
||||||
|
|
||||||
@user_is_rcr
|
@user_is_rcr
|
||||||
def radiology_assessors(request):
|
def radiology_assessors(request):
|
||||||
assessors = User.objects.filter(groups__name="rcr_radiology_assessor")
|
rad_assessors = User.objects.filter(groups__name="rcr_radiology_assessor")
|
||||||
|
onc_assessors = User.objects.filter(groups__name="rcr_oncology_assessor")
|
||||||
|
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"rcr/assessors.html",
|
"rcr/assessors.html",
|
||||||
{
|
{
|
||||||
"assessors": assessors
|
"rad_assessors": rad_assessors,
|
||||||
|
"onc_assessors": onc_assessors,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -117,10 +178,13 @@ def radiology_index_completed(request, user_pk=None):
|
|||||||
|
|
||||||
assessor = None
|
assessor = None
|
||||||
if user_pk is not None:
|
if user_pk is not None:
|
||||||
items = Item.objects.filter(completed=True, assessed_by=user_pk).order_by("pk")
|
|
||||||
assessor = User.objects.get(pk=user_pk)
|
assessor = User.objects.get(pk=user_pk)
|
||||||
|
if assessor.groups.filter(name="rcr_radiology_assessor").exists():
|
||||||
|
items = Item.objects.filter(completed_radiology=True, assessed_by=user_pk).order_by("pk")
|
||||||
|
elif assessor.groups.filter(name="rcr_oncology_assessor").exists():
|
||||||
|
items = Item.objects.filter(completed_oncology=True, assessed_by=user_pk).order_by("pk")
|
||||||
else:
|
else:
|
||||||
items = Item.objects.filter(completed=True)
|
items = Item.objects.filter(Q(completed_radiology=True) | Q(completed_oncology=True))
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
@@ -175,11 +239,23 @@ class ItemUpdateNextView(ItemUpdateBase, RCRRequiredMixin):
|
|||||||
return self.render_to_response(context)
|
return self.render_to_response(context)
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
|
user = self.request.user
|
||||||
if self.skip < 1:
|
if self.skip < 1:
|
||||||
obj = Item.objects.filter(completed=False).order_by("pk").first()
|
if user.groups.filter(name="rcr_radiology_assessor").exists():
|
||||||
|
obj = Item.objects.filter(assigned_to_radiology=user, completed_radiology=False).order_by("pk").first()
|
||||||
|
elif user.groups.filter(name="rcr_oncology_assessor").exists():
|
||||||
|
obj = Item.objects.filter(assigned_to_oncology=user, completed_oncology=False).order_by("pk").first()
|
||||||
|
else:
|
||||||
|
raise Http404
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
obj = Item.objects.filter(completed=False)[self.skip]
|
if user.groups.filter(name="rcr_radiology_assessor").exists():
|
||||||
|
obj = Item.objects.filter(assigned_to_radiology=user, completed_radiology=False).order_by("pk")[self.skip]
|
||||||
|
elif user.groups.filter(name="rcr_oncology_assessor").exists():
|
||||||
|
obj = Item.objects.filter(assigned_to_oncology=user, completed_oncology=False).order_by("pk")[self.skip]
|
||||||
|
else:
|
||||||
|
raise Http404
|
||||||
|
#obj = Item.objects.filter(completed=False)[self.skip]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -41,4 +41,5 @@ ipython
|
|||||||
django-htmx-autocomplete
|
django-htmx-autocomplete
|
||||||
faker
|
faker
|
||||||
pytest-faker
|
pytest-faker
|
||||||
blake3
|
blake3
|
||||||
|
django-markdownify
|
||||||
Reference in New Issue
Block a user