345 lines
9.7 KiB
Python
Executable File
345 lines
9.7 KiB
Python
Executable File
from django.contrib import admin
|
|
from django.contrib import messages
|
|
from .models import (
|
|
Case,
|
|
CaseDetail,
|
|
CaseCollection,
|
|
NormalCase,
|
|
Differential,
|
|
Series,
|
|
SeriesImage,
|
|
Condition,
|
|
ConditionRelationship,
|
|
Subspecialty,
|
|
Finding,
|
|
SeriesFinding,
|
|
Structure,
|
|
PathologicalProcess,
|
|
Presentation,
|
|
Procedure,
|
|
UncategorisedDicom,
|
|
SeriesDetail,
|
|
Resource,
|
|
CaseDisplaySet,
|
|
UserReportAnswer,
|
|
CidReportAnswer,
|
|
APIToken,
|
|
)
|
|
|
|
from django.forms import ModelForm
|
|
|
|
from reversion.admin import VersionAdmin
|
|
from django.forms.widgets import RadioSelect
|
|
from django.utils.html import format_html
|
|
from django.urls import reverse
|
|
|
|
from tinymce.widgets import TinyMCE
|
|
|
|
# from generic.models import Examination, Sign, Site, Condition
|
|
from generic.models import Examination
|
|
|
|
try:
|
|
from django_tasks_db.models import DBTaskResult
|
|
except ImportError:
|
|
DBTaskResult = None
|
|
|
|
# Register your models here.
|
|
# admin.site.register(Examination)
|
|
# admin.site.register(Site)
|
|
admin.site.register(SeriesImage)
|
|
admin.site.register(Condition)
|
|
admin.site.register(ConditionRelationship)
|
|
admin.site.register(Subspecialty)
|
|
admin.site.register(Finding)
|
|
admin.site.register(Structure)
|
|
admin.site.register(SeriesFinding)
|
|
admin.site.register(Differential)
|
|
admin.site.register(PathologicalProcess)
|
|
admin.site.register(Presentation)
|
|
admin.site.register(CaseDetail)
|
|
admin.site.register(UncategorisedDicom)
|
|
admin.site.register(SeriesDetail)
|
|
admin.site.register(Resource)
|
|
admin.site.register(CaseDisplaySet)
|
|
admin.site.register(Procedure)
|
|
admin.site.register(UserReportAnswer)
|
|
admin.site.register(CidReportAnswer)
|
|
|
|
|
|
class DifferentialInline(admin.TabularInline):
|
|
model = Differential
|
|
|
|
class CasesInline(admin.TabularInline):
|
|
model = CaseDetail
|
|
|
|
class CaseCollectionAdminForm(ModelForm):
|
|
class Meta:
|
|
model = CaseCollection
|
|
|
|
exclude = []
|
|
|
|
|
|
class CaseCollectionAdmin(VersionAdmin):
|
|
form = CaseCollectionAdminForm
|
|
|
|
save_on_top = True
|
|
save_as = True
|
|
view_on_site = True
|
|
|
|
inlines = (CasesInline,)
|
|
|
|
|
|
admin.site.register(CaseCollection, CaseCollectionAdmin)
|
|
|
|
|
|
class NormalCaseAdmin(VersionAdmin):
|
|
list_display = ("case", "display_age", "examination", "modality", "added_date")
|
|
list_filter = ("examination", "modality")
|
|
search_fields = ("case__title", "case__pk")
|
|
|
|
def display_age(self, obj):
|
|
try:
|
|
return obj.display_age()
|
|
except Exception:
|
|
return ""
|
|
display_age.short_description = "Age"
|
|
|
|
|
|
admin.site.register(NormalCase, NormalCaseAdmin)
|
|
|
|
class AtlasAdminForm(ModelForm):
|
|
class Meta:
|
|
model = Case
|
|
|
|
fields = [
|
|
"title",
|
|
"description",
|
|
"history",
|
|
"discussion",
|
|
"condition",
|
|
"differential",
|
|
"subspecialty",
|
|
"author",
|
|
"series",
|
|
"cimar_uuid"
|
|
]
|
|
|
|
widgets = {
|
|
# "normal": RadioSelect(
|
|
# choices=[(True, 'Yes'),
|
|
# (False, 'No')])
|
|
"history": TinyMCE(attrs={"cols": 80, "rows": 30}),
|
|
"discussion": TinyMCE(attrs={"cols": 80, "rows": 30}),
|
|
}
|
|
|
|
|
|
class AtlasAdmin(VersionAdmin):
|
|
form = AtlasAdminForm
|
|
|
|
save_on_top = True
|
|
save_as = True
|
|
view_on_site = True
|
|
|
|
inlines = (DifferentialInline,)
|
|
|
|
|
|
admin.site.register(Case, AtlasAdmin)
|
|
|
|
|
|
class SeriesAdmin(VersionAdmin):
|
|
pass
|
|
|
|
|
|
admin.site.register(Series, SeriesAdmin)
|
|
|
|
|
|
class APITokenAdmin(admin.ModelAdmin):
|
|
list_display = ("user", "name", "revoked", "created", "expires", "last_used")
|
|
search_fields = ("user__username", "name")
|
|
readonly_fields = ("token_hash", "created", "last_used")
|
|
|
|
|
|
admin.site.register(APIToken, APITokenAdmin)
|
|
|
|
|
|
if DBTaskResult is not None:
|
|
try:
|
|
# Ensure package admin registration has run before we customize it.
|
|
import django_tasks_db.admin # noqa: F401
|
|
except Exception:
|
|
pass
|
|
|
|
def traceback_link(self, obj):
|
|
if not obj.traceback:
|
|
return "-"
|
|
url = reverse(
|
|
f"admin:{obj._meta.app_label}_{obj._meta.model_name}_change",
|
|
args=[obj.pk],
|
|
)
|
|
return format_html('<a href="{}">View full traceback</a>', url)
|
|
|
|
traceback_link.short_description = "Traceback"
|
|
|
|
def traceback_pretty(self, obj):
|
|
if not obj.traceback:
|
|
return ""
|
|
return format_html(
|
|
'<pre style="white-space: pre-wrap; margin: 0;">{}</pre>',
|
|
obj.traceback,
|
|
)
|
|
|
|
traceback_pretty.short_description = "Traceback"
|
|
|
|
@admin.action(description="Reset FAILED tasks to READY")
|
|
def reset_failed_to_ready(self, request, queryset):
|
|
failed_qs = queryset.filter(status="FAILED")
|
|
updated = failed_qs.update(
|
|
status="READY",
|
|
started_at=None,
|
|
finished_at=None,
|
|
worker_ids="",
|
|
exception_class_path="",
|
|
traceback="",
|
|
return_value=None,
|
|
)
|
|
self.message_user(
|
|
request,
|
|
f"Reset {updated} failed task(s) to READY.",
|
|
level=messages.SUCCESS,
|
|
)
|
|
|
|
@admin.action(description="Reset selected tasks to READY (except RUNNING)")
|
|
def reset_selected_to_ready(self, request, queryset):
|
|
blocked = queryset.filter(status="RUNNING").count()
|
|
reset_qs = queryset.exclude(status="RUNNING")
|
|
updated = reset_qs.update(
|
|
status="READY",
|
|
started_at=None,
|
|
finished_at=None,
|
|
worker_ids="",
|
|
exception_class_path="",
|
|
traceback="",
|
|
return_value=None,
|
|
)
|
|
msg = f"Reset {updated} task(s) to READY."
|
|
if blocked:
|
|
msg += f" Skipped {blocked} running task(s)."
|
|
self.message_user(request, msg, level=messages.SUCCESS)
|
|
|
|
@admin.action(description="Delete selected COMPLETED tasks")
|
|
def delete_selected_completed(self, request, queryset):
|
|
completed_qs = queryset.filter(status="SUCCESSFUL")
|
|
deleted, _ = completed_qs.delete()
|
|
self.message_user(
|
|
request,
|
|
f"Deleted {deleted} completed task record(s).",
|
|
level=messages.SUCCESS,
|
|
)
|
|
|
|
@admin.action(description="Delete selected FAILED tasks")
|
|
def delete_selected_failed(self, request, queryset):
|
|
failed_qs = queryset.filter(status="FAILED")
|
|
deleted, _ = failed_qs.delete()
|
|
self.message_user(
|
|
request,
|
|
f"Deleted {deleted} failed task record(s).",
|
|
level=messages.SUCCESS,
|
|
)
|
|
|
|
def has_add_permission(self, request):
|
|
return False
|
|
|
|
task_admin = admin.site._registry.get(DBTaskResult)
|
|
if task_admin is not None:
|
|
admin_cls = task_admin.__class__
|
|
admin_cls.list_display = (
|
|
"id",
|
|
"task_path",
|
|
"status",
|
|
"queue_name",
|
|
"priority",
|
|
"enqueued_at",
|
|
"started_at",
|
|
"finished_at",
|
|
"worker_ids",
|
|
"exception_class_path",
|
|
"traceback_link",
|
|
)
|
|
admin_cls.list_filter = ("status", "queue_name", "task_path", "backend_name")
|
|
admin_cls.search_fields = (
|
|
"id",
|
|
"task_path",
|
|
"queue_name",
|
|
"worker_ids",
|
|
"exception_class_path",
|
|
"traceback",
|
|
)
|
|
admin_cls.ordering = ("-enqueued_at",)
|
|
admin_cls.actions = (
|
|
"reset_failed_to_ready",
|
|
"reset_selected_to_ready",
|
|
"delete_selected_completed",
|
|
"delete_selected_failed",
|
|
)
|
|
admin_cls.readonly_fields = (
|
|
"id",
|
|
"status",
|
|
"enqueued_at",
|
|
"started_at",
|
|
"finished_at",
|
|
"args_kwargs",
|
|
"priority",
|
|
"task_path",
|
|
"worker_ids",
|
|
"queue_name",
|
|
"backend_name",
|
|
"run_after",
|
|
"return_value",
|
|
"exception_class_path",
|
|
"traceback_pretty",
|
|
)
|
|
admin_cls.fieldsets = (
|
|
(
|
|
"Task",
|
|
{
|
|
"fields": (
|
|
"id",
|
|
"task_path",
|
|
"status",
|
|
"queue_name",
|
|
"priority",
|
|
"backend_name",
|
|
)
|
|
},
|
|
),
|
|
(
|
|
"Timing",
|
|
{
|
|
"fields": (
|
|
"enqueued_at",
|
|
"run_after",
|
|
"started_at",
|
|
"finished_at",
|
|
"worker_ids",
|
|
)
|
|
},
|
|
),
|
|
(
|
|
"Payload",
|
|
{"fields": ("args_kwargs", "return_value")},
|
|
),
|
|
(
|
|
"Error",
|
|
{
|
|
"fields": ("exception_class_path", "traceback_pretty"),
|
|
},
|
|
),
|
|
)
|
|
admin_cls.traceback_link = traceback_link
|
|
admin_cls.traceback_pretty = traceback_pretty
|
|
admin_cls.reset_failed_to_ready = reset_failed_to_ready
|
|
admin_cls.reset_selected_to_ready = reset_selected_to_ready
|
|
admin_cls.delete_selected_completed = delete_selected_completed
|
|
admin_cls.delete_selected_failed = delete_selected_failed
|
|
admin_cls.has_add_permission = has_add_permission
|