Add admin feature to search uploads by pixel hash and corresponding template

This commit is contained in:
Ross
2026-03-18 19:38:20 +00:00
parent 70602e6f71
commit d00a7f9cf6
4 changed files with 118 additions and 0 deletions
@@ -0,0 +1,89 @@
{% extends 'atlas/base.html' %}
{% block content %}
<h2>Search uploaded DICOMs by pixel-data hash</h2>
<p class="text-muted">Admin-only tool for searching uncategorised uploads by <code>image_blake3_hash</code>.</p>
<form method="get" class="mb-3">
<div class="input-group">
<input
type="text"
class="form-control"
name="hash"
value="{{ hash_query }}"
placeholder="Enter full or partial pixel-data hash"
autocomplete="off"
spellcheck="false"
>
<button type="submit" class="btn btn-primary">Search</button>
</div>
<small class="form-text text-muted">Search is case-insensitive and supports partial matches.</small>
</form>
{% if hash_query %}
<p>Found <strong>{{ result_count }}</strong> upload{{ result_count|pluralize }} for <code>{{ hash_query }}</code>.</p>
{% if page_obj.object_list %}
<div class="table-responsive">
<table class="table table-sm table-striped align-middle">
<thead>
<tr>
<th>Hash</th>
<th>Uploaded</th>
<th>User</th>
<th>Series UID</th>
<th>Links</th>
</tr>
</thead>
<tbody>
{% for dicom in page_obj.object_list %}
<tr>
<td><code>{{ dicom.image_blake3_hash }}</code></td>
<td>{{ dicom.created_date }}</td>
<td>{{ dicom.user }}</td>
<td><code>{{ dicom.series_instance_uid|default:"-" }}</code></td>
<td>
{% if dicom.series_instance_uid %}
<a href="{% url 'atlas:user_uploads_series' dicom.series_instance_uid %}">View series uploads</a>
{% else %}
-
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if page_obj.paginator.num_pages > 1 %}
<nav aria-label="Hash search pagination">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?hash={{ hash_query|urlencode }}&page={{ page_obj.previous_page_number }}">Previous</a>
</li>
{% else %}
<li class="page-item disabled"><span class="page-link">Previous</span></li>
{% endif %}
<li class="page-item disabled">
<span class="page-link">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
</li>
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?hash={{ hash_query|urlencode }}&page={{ page_obj.next_page_number }}">Next</a>
</li>
{% else %}
<li class="page-item disabled"><span class="page-link">Next</span></li>
{% endif %}
</ul>
</nav>
{% endif %}
{% else %}
<div class="alert alert-warning">No uploads matched that hash.</div>
{% endif %}
{% else %}
<div class="alert alert-info">Enter a hash value to search uploads.</div>
{% endif %}
{% endblock %}
+3
View File
@@ -5,6 +5,9 @@
<h2>Uploaded dicoms</h2>
User: {{user}}<br/>
<a href="{% url 'atlas:new_uploads' %}">Upload more dicoms</a><br/>
{% if request.user.is_staff %}
<a href="{% url 'atlas:uploads_hash_search' %}">Admin: search uploads by pixel hash</a><br/>
{% endif %}
{% if not case %}
<div class="alert alert-info" role="alert">
Series imported from here will be orphaned (not associated with a case). <br/>It is usually better to <a href="{% url 'atlas:case_create' %}">create a case</a> first and then import directly into the case.