changeset 110:afc8230831ad

unlink orphan resources after removing a project
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 09 Sep 2026 08:59:08 +0200
parents 7a0c6c4dd126
children e5b220fa1234
files Resources/IntegrationTests/Run.py Sources/EducationRestApi.cpp Sources/EducationToolbox.cpp Sources/OrthancDatabase.cpp
diffstat 4 files changed, 45 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/Resources/IntegrationTests/Run.py	Wed Sep 09 08:23:23 2026 +0200
+++ b/Resources/IntegrationTests/Run.py	Wed Sep 09 08:59:08 2026 +0200
@@ -253,7 +253,8 @@
                     'resource-id' : 'toto',
                     'level' : 'Study',
                     'title' : 'Hello',
-                }
+                },
+                'project' : '',
             }
 
             body['viewer'] = 'stone'
@@ -287,7 +288,8 @@
                     'resource-id' : 'toto',
                     'level' : 'Series',
                     'title' : 'Hello',
-                }
+                },
+                'project' : '',
             }
 
             body['viewer'] = 'stone'
@@ -310,7 +312,8 @@
                     'resource-id' : 'toto',
                     'level' : 'Instance',
                     'title' : 'Hello',
-                }
+                },
+                'project' : '',
             }
 
             body['viewer'] = 'wsi'
--- a/Sources/EducationRestApi.cpp	Wed Sep 09 08:23:23 2026 +0200
+++ b/Sources/EducationRestApi.cpp	Wed Sep 09 08:59:08 2026 +0200
@@ -987,19 +987,10 @@
 }
 
 
-void UnlinkResourceFromProject(OrthancPluginRestOutput* output,
-                               const std::string& url,
-                               const OrthancPluginHttpRequest* request,
-                               const AuthenticatedUser& user,
-                               const Json::Value& body)
+static bool UnlinkResource(const std::string& projectId,
+                           Orthanc::ResourceType level,
+                           const std::string& resourceId)
 {
-  assert(user.GetRole() == Role_Administrator);
-
-  Orthanc::ResourceType level;
-  std::string resourceId;
-  GetResourceFromBody(level, resourceId, body);
-
-  const std::string projectId = Orthanc::SerializationToolbox::ReadString(body, "project");
   const std::string label = LABEL_PREFIX + projectId;
 
   std::string path;
@@ -1021,7 +1012,25 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
   }
 
-  if (OrthancPlugins::RestApiDelete(path, false))
+  return OrthancPlugins::RestApiDelete(path, false);
+}
+
+
+void UnlinkResourceFromProject(OrthancPluginRestOutput* output,
+                               const std::string& url,
+                               const OrthancPluginHttpRequest* request,
+                               const AuthenticatedUser& user,
+                               const Json::Value& body)
+{
+  assert(user.GetRole() == Role_Administrator);
+
+  Orthanc::ResourceType level;
+  std::string resourceId;
+  GetResourceFromBody(level, resourceId, body);
+
+  const std::string projectId = Orthanc::SerializationToolbox::ReadString(body, "project");
+
+  if (UnlinkResource(projectId, level, resourceId))
   {
     HttpToolbox::AnswerText(output, "");
   }
@@ -1160,7 +1169,21 @@
   }
   else if (request->method == OrthancPluginHttpMethod_Delete)
   {
+    Json::Value resources;
+    OrthancDatabase::FindResourcesInProject(resources, projectId);
+    assert(resources.isArray());
+
     ProjectPermissionContext::GetProjects().Remove(projectId);
+
+    // After deleting the project, unlink all the resources that were attached to this project
+    for (Json::Value::ArrayIndex i = 0; i < resources.size(); i++)
+    {
+      const std::string level = Orthanc::SerializationToolbox::ReadString(resources[i], "level");
+      UnlinkResource(projectId,
+                     Orthanc::StringToResourceType(level.c_str()),
+                     Orthanc::SerializationToolbox::ReadString(resources[i], "resource-id"));
+    }
+
     HttpToolbox::AnswerText(output, "");
   }
   else
--- a/Sources/EducationToolbox.cpp	Wed Sep 09 08:23:23 2026 +0200
+++ b/Sources/EducationToolbox.cpp	Wed Sep 09 08:59:08 2026 +0200
@@ -108,7 +108,7 @@
     case ViewerType_WholeSlideImaging:
       return ("wsi/app/viewer.html?series=" + seriesId +
               FormatGetArgument("project", projectId) +
-              FormatGetArgument("title", title));
+              FormatGetArgument("description", title));
 
     case ViewerType_VolView:
       return "volview/index.html?names=[archive.zip]&urls=[../series/" + seriesId + "/archive]";
@@ -132,7 +132,7 @@
     case ViewerType_WholeSlideImaging:
       return ("wsi/app/viewer.html?instance=" + instanceId +
               FormatGetArgument("project", projectId) +
-              FormatGetArgument("title", title));
+              FormatGetArgument("description", title));
 
     default:
       throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
--- a/Sources/OrthancDatabase.cpp	Wed Sep 09 08:23:23 2026 +0200
+++ b/Sources/OrthancDatabase.cpp	Wed Sep 09 08:59:08 2026 +0200
@@ -153,6 +153,7 @@
   request["Expand"] = true;
   request["ResponseContent"] = responseContent;
   request["RequestedTags"] = requestedTags;
+  request["Limit"] = 0;  // No limit
 
   Json::Value response;
   if (!OrthancPlugins::RestApiPost(response, "/tools/find", request, false) ||