changeset 95:2cb5f7d0883e

added internal route to get project information from other plugins
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 04 Aug 2026 15:17:26 +0200
parents c8ffbea46897
children 162fa5df32db
files NEWS Sources/EducationPluginsApi.cpp Sources/EducationPluginsApi.h Sources/HttpToolbox.cpp Sources/HttpToolbox.h Sources/Plugin.cpp
diffstat 6 files changed, 148 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Tue Aug 04 14:48:23 2026 +0200
+++ b/NEWS	Tue Aug 04 15:17:26 2026 +0200
@@ -11,6 +11,8 @@
 * REST API: Job ID is reported when starting the DICOM-ization, and upload ID
   is part of the DICOM-ization status
 * Added CMake option "ORTHANC_SDK_VERSION"
+* Added internal route to get project information from other plugins:
+  "/education/api-plugins/project-info"
 
 
 Version 1.1 (2025-11-07)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Sources/EducationPluginsApi.cpp	Tue Aug 04 15:17:26 2026 +0200
@@ -0,0 +1,85 @@
+/**
+ * SPDX-FileCopyrightText: 2024-2026 Sebastien Jodogne, EPL UCLouvain, Belgium
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+/**
+ * Orthanc for Education
+ * Copyright (C) 2024-2026 Sebastien Jodogne, EPL UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "EducationPluginsApi.h"
+
+#include "HttpToolbox.h"
+#include "ProjectPermissionContext.h"
+
+#include "../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h"
+
+
+void GetProjectMembers(OrthancPluginRestOutput* output,
+                       const char* url,
+                       const OrthancPluginHttpRequest* request)
+{
+  if (request->authenticationPayloadSize != 0)
+  {
+    throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);  // Should never happen
+  }
+  else if (request->method != OrthancPluginHttpMethod_Get)
+  {
+    OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "GET");
+  }
+  else
+  {
+    std::map<std::string, std::string> args;
+    HttpToolbox::RetrieveGetArguments(args, request);
+
+    std::map<std::string, std::string>::const_iterator found = args.find("id");
+    if (found == args.end())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+    }
+
+    Json::Value answer;
+
+    {
+      DocumentOrientedDatabase::Reader reader(ProjectPermissionContext::GetProjects());
+      const Project* project = reader.LookupDocument<Project>(found->second);
+
+      if (project == NULL)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource, "Unknown project: \"" + found->second + "\"");
+      }
+      else
+      {
+        answer["name"] = project->GetName();
+        answer["description"] = project->GetDescription();
+        HttpToolbox::CopySetOfStrings(answer["instructors"], project->GetInstructors());
+        HttpToolbox::CopySetOfStrings(answer["learners"], project->GetLearners());
+      }
+    }
+
+    HttpToolbox::AnswerJson(output, answer);
+  }
+}
+
+
+void RegisterEducationPluginsApiRoutes()
+{
+  // All the routes below must be branched under "/education/api-plugins/"
+
+  OrthancPlugins::RegisterRestCallback<GetProjectMembers>("/education/api-plugins/project-info", true);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Sources/EducationPluginsApi.h	Tue Aug 04 15:17:26 2026 +0200
@@ -0,0 +1,28 @@
+/**
+ * SPDX-FileCopyrightText: 2024-2026 Sebastien Jodogne, EPL UCLouvain, Belgium
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+/**
+ * Orthanc for Education
+ * Copyright (C) 2024-2026 Sebastien Jodogne, EPL UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+
+void RegisterEducationPluginsApiRoutes();
--- a/Sources/HttpToolbox.cpp	Tue Aug 04 14:48:23 2026 +0200
+++ b/Sources/HttpToolbox.cpp	Tue Aug 04 15:17:26 2026 +0200
@@ -496,4 +496,16 @@
       target.append(item);
     }
   }
+
+
+  void RetrieveGetArguments(std::map<std::string, std::string>& target,
+                            const OrthancPluginHttpRequest* request)
+  {
+    target.clear();
+
+    for (uint32_t i = 0; i < request->getCount; i++)
+    {
+      target[request->getKeys[i]] = request->getValues[i];
+    }
+  }
 }
--- a/Sources/HttpToolbox.h	Tue Aug 04 14:48:23 2026 +0200
+++ b/Sources/HttpToolbox.h	Tue Aug 04 15:17:26 2026 +0200
@@ -160,4 +160,7 @@
 
   void FormatViewers(Json::Value& target,
                      const std::set<ViewerType>& source);
+
+  void RetrieveGetArguments(std::map<std::string, std::string>& target,
+                            const OrthancPluginHttpRequest* request);
 }
--- a/Sources/Plugin.cpp	Tue Aug 04 14:48:23 2026 +0200
+++ b/Sources/Plugin.cpp	Tue Aug 04 15:17:26 2026 +0200
@@ -26,6 +26,7 @@
 #include "Dicomization/DicomizationJob.h"
 #include "EducationConfiguration.h"
 #include "EducationRestApi.h"
+#include "EducationPluginsApi.h"
 #include "LTI/LTIRoutes.h"
 #include "OrthancDatabase.h"
 #include "ProjectPermissionContext.h"
@@ -68,6 +69,21 @@
                                            const std::string& uri,
                                            const std::map<std::string, std::string>& getArguments)
 {
+  if (boost::starts_with(uri, "/education/api-plugins/"))
+  {
+    /**
+     * Routes under this path are only accessible to plugins. Indeed,
+     * Orthanc plugins totally bypass the authentication callback
+     * registered by OrthancPluginRegisterHttpAuthentication(). This
+     * is because the Orthanc plugin engine directly calls
+     * "Orthanc::ServerContext::GetHttpHandler()" (no
+     * authentication/authorization here), while external requests
+     * must go through the "Orthanc::HttpServer" class, which uses
+     * "IIncomingHttpRequestFilter::CheckAuthentication()".
+     **/
+    return AuthorizationStatus_Forbidden;  // Only plugins can access these routes
+  }
+
   if (user.GetRole() == Role_Administrator)
   {
     return AuthorizationStatus_GrantedWithPayload;  // Administrators have full access
@@ -706,7 +722,8 @@
       // "RegisterPublicRoute()", as they might have an arbitrary depth.
       OrthancPlugins::RegisterRestCallback<ServeStaticAsset>("/education/static/(.*)", true);
 
-      RegisterEducationRestApiRoutes();
+      RegisterEducationRestApiRoutes();     // Register REST routes for the client-side application
+      RegisterEducationPluginsApiRoutes();  // Register routes reserved for internal use of plugins
 
 
       /**