From 3ade162b2827238bff24c05cf3e6798249dbbf79 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 2 Feb 2026 13:30:06 +0000 Subject: [PATCH] Remove series truncation endpoint from API --- atlas/api.py | 22 -------- generic/widgets.py | 123 +++++++++++++++++++++++++-------------------- 2 files changed, 68 insertions(+), 77 deletions(-) diff --git a/atlas/api.py b/atlas/api.py index f2c8b5d3..7dfc0da8 100644 --- a/atlas/api.py +++ b/atlas/api.py @@ -249,28 +249,6 @@ def series_remove_duplicate_images(request, series_id: int): return len(dupes) -@router.get("/series_truncate/{series_id}/{start}/{end}/", auth=django_auth) -def series_truncate(request, series_id: int, start: int, end: int): - series = get_object_or_404(Series, pk=series_id) - - if not series.check_user_can_edit(request.user): - return {"status": "permission denied"} - - images_removed = [] - for n, image in enumerate(series.get_images()): - if n >= start and n <= end: - continue - else: - image.removed = True - image.image = None - image.save() - images_removed.append(image.pk) - - series.get_total_image_size(refresh=True) - - return {"status": "success", "images_removed": images_removed} - - @router.get("/get_cases_user", auth=django_auth, response=List[CaseSchema]) def get_cases_user(request): return Case.objects.filter(author=request.user) diff --git a/generic/widgets.py b/generic/widgets.py index 4c6fc9f6..7f89b17f 100644 --- a/generic/widgets.py +++ b/generic/widgets.py @@ -131,6 +131,47 @@ class UserSearchSelectMultipleWidget: const helpBtn = document.getElementById('user_search_help_btn_{self.name}'); const helpPanel = document.getElementById('user_search_help_panel_{self.name}'); + // Expose helper functions immediately so clicks won't fail if + // earlier listeners throw an exception during setup. + window.addUserToField = function(fieldName, id, text, grade) {{ + const sel = document.getElementById('id_' + fieldName); + if (!sel) return; + for (let i=0;i' + grade + '' : ''); + const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'btn btn-sm btn-outline-danger ms-2'; btn.innerText = 'Remove'; + btn.addEventListener('click', function() {{ removeUserFromField(fieldName, id); }}); + li.appendChild(span); li.appendChild(btn); + listEl.appendChild(li); + }} + + window.removeUserFromField = function(fieldName, id) {{ + const sel = document.getElementById('id_' + fieldName); + if (!sel) return; + for (let i=sel.options.length-1;i>=0;i--) {{ if (sel.options[i].value == id) sel.remove(i); }} + const li = document.getElementById('selected_user_' + fieldName + '_' + id); + if (li && li.parentNode) li.parentNode.removeChild(li); + }} + + window.addAllFromResults = function(fieldName) {{ + const list = document.getElementById('user_search_results_list_' + fieldName); + if (!list) return; + const items = list.querySelectorAll('li[data-user-id]'); + items.forEach(function(it) {{ + const id = it.getAttribute('data-user-id'); + const text = it.getAttribute('data-user-text') || it.textContent.trim(); + const grade = it.getAttribute('data-user-grade') || ''; + addUserToField(fieldName, id, text, grade); + }}); + }} + let timeout = null; function fetchResults(q) {{ const grade = gradeSelect ? gradeSelect.value : ''; @@ -178,23 +219,35 @@ class UserSearchSelectMultipleWidget: // fieldName for this widget instance const widgetFieldName = '{self.name}'; - // Add button click delegation: results list buttons have data attributes + // Expose helper functions early so they're available even if + // a later part of this IIFE throws (avoids ReferenceError on click). + + + // Delegate clicks from results: add single or add-all (works for dynamically inserted content) results.addEventListener('click', function(e) {{ - const btn = e.target.closest('.user-add-btn'); - if (!btn) return; - const id = btn.getAttribute('data-user-id'); - const text = btn.getAttribute('data-user-text') || btn.textContent.trim(); - // Try button attribute, then list-item dataset, then visible badge text - let grade = btn.getAttribute('data-user-grade') || ''; - if (!grade) {{ - const li = btn.closest('li[data-user-id]'); - if (li && li.dataset && li.dataset.userGrade) grade = li.dataset.userGrade; - else {{ - const badge = btn.closest('li') ? btn.closest('li').querySelector('.badge') : null; - if (badge) grade = badge.textContent.trim(); + const addBtn = e.target.closest('.user-add-btn'); + if (addBtn) {{ + const id = addBtn.getAttribute('data-user-id'); + const text = addBtn.getAttribute('data-user-text') || addBtn.textContent.trim(); + // Try button attribute, then list-item dataset, then visible badge text + let grade = addBtn.getAttribute('data-user-grade') || ''; + if (!grade) {{ + const li = addBtn.closest('li[data-user-id]'); + if (li && li.dataset && li.dataset.userGrade) grade = li.dataset.userGrade; + else {{ + const badge = addBtn.closest('li') ? addBtn.closest('li').querySelector('.badge') : null; + if (badge) grade = badge.textContent.trim(); + }} }} + addUserToField(widgetFieldName, id, text, grade); + return; + }} + const addAllBtnDynamic = e.target.closest('.user-add-all-btn'); + if (addAllBtnDynamic) {{ + e.preventDefault(); + addAllFromResults(widgetFieldName); + return; }} - addUserToField(widgetFieldName, id, text, grade); }}); // Wire up the "Add all results" button if present @@ -206,47 +259,7 @@ class UserSearchSelectMultipleWidget: }}); }} - window.addUserToField = function(fieldName, id, text, grade) {{ - const sel = document.getElementById('id_' + fieldName); - if (!sel) return; - // prevent duplicate - for (let i=0;i' + grade + '' : ''); - const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'btn btn-sm btn-outline-danger ms-2'; btn.innerText = 'Remove'; - btn.addEventListener('click', function() {{ removeUserFromField(fieldName, id); }}); - li.appendChild(span); li.appendChild(btn); - listEl.appendChild(li); - }} - - window.removeUserFromField = function(fieldName, id) {{ - const sel = document.getElementById('id_' + fieldName); - if (!sel) return; - for (let i=sel.options.length-1;i>=0;i--) {{ if (sel.options[i].value == id) sel.remove(i); }} - const li = document.getElementById('selected_user_' + fieldName + '_' + id); - if (li && li.parentNode) li.parentNode.removeChild(li); - }} - - window.addAllFromResults = function(fieldName) {{ - const list = document.getElementById('user_search_results_list_' + fieldName); - if (!list) return; - const items = list.querySelectorAll('li[data-user-id]'); - items.forEach(function(it) {{ - const id = it.getAttribute('data-user-id'); - const text = it.getAttribute('data-user-text') || it.textContent.trim(); - const grade = it.getAttribute('data-user-grade') || ''; - addUserToField(fieldName, id, text, grade); - }}); - }} + // Initialize visible selected-list from any pre-existing