diff --git a/openflexure_microscope/api/v2/blueprints/plugins.py b/openflexure_microscope/api/v2/blueprints/plugins.py index a5028b56..f12ef19a 100644 --- a/openflexure_microscope/api/v2/blueprints/plugins.py +++ b/openflexure_microscope/api/v2/blueprints/plugins.py @@ -39,7 +39,8 @@ def plugins_representation(plugin_loader_object: PluginLoader): for view_id, view_data in plugin.views.items(): logging.debug(f"Representing view {view_id}") - uri = url_for(f"v2_plugins_blueprint.{plugin._name_python_safe}_{view_id}") + uri = url_for(f"v2_plugins_blueprint.plugins") + view_data["rule"][1:] + # uri = view_data["rule"] # Make links dictionary if it doesn't yet exist view_d = {"links": {"self": uri}} @@ -90,6 +91,7 @@ def construct_blueprint(microscope_obj): microscope=microscope_obj, plugin=plugin, ), + **plugin_view["kwargs"], ) return blueprint diff --git a/openflexure_microscope/camera/base.py b/openflexure_microscope/camera/base.py index ce7c9143..ebce1bf8 100644 --- a/openflexure_microscope/camera/base.py +++ b/openflexure_microscope/camera/base.py @@ -122,7 +122,6 @@ class BaseCamera(metaclass=ABCMeta): self.status = {"board": None} - # TODO: Load/save these to config self.paths = {"default": BASE_CAPTURE_PATH, "temp": TEMP_CAPTURE_PATH} # Capture data diff --git a/openflexure_microscope/plugins/default/zip_builder/__init__.py b/openflexure_microscope/plugins/default/zip_builder/__init__.py new file mode 100644 index 00000000..56ec492f --- /dev/null +++ b/openflexure_microscope/plugins/default/zip_builder/__init__.py @@ -0,0 +1 @@ +from .plugin import ZipBuilderPlugin diff --git a/openflexure_microscope/plugins/default/zip_builder/plugin.py b/openflexure_microscope/plugins/default/zip_builder/plugin.py new file mode 100644 index 00000000..bf88dba0 --- /dev/null +++ b/openflexure_microscope/plugins/default/zip_builder/plugin.py @@ -0,0 +1,80 @@ +from openflexure_microscope.devel import ( + MicroscopePlugin, + MicroscopeViewPlugin, + JsonResponse, + request, + jsonify, + taskify, +) + +from flask import send_file, abort + +import uuid +import zipfile +import tempfile +import logging + + +class ZipBuilderAPIView(MicroscopeViewPlugin): + def post(self): + + ids = list(JsonResponse(request).json) + + task = taskify(self.plugin.build_zip_from_capture_ids)(ids) + + # Return a handle on the autofocus task + return jsonify(task.state), 201 + + +class ZipListAPIView(MicroscopeViewPlugin): + def get(self): + return jsonify(list(self.plugin.session_zips.keys())) + + +class ZipGetterAPIView(MicroscopeViewPlugin): + def get(self, session_id="No session ID"): + logging.info(f"Session ID: {session_id}") + + return send_file( + self.plugin.zip_from_id(session_id), + mimetype="application/zip", + as_attachment=True, + attachment_filename=f"{session_id}.zip", + ) + + +class ZipBuilderPlugin(MicroscopePlugin): + """ + ZIP-builder plugin + """ + + def __init__(self): + super().__init__() + + self.session_zips = {} + + self.add_view("/get/", ZipGetterAPIView) + self.add_view("/get", ZipListAPIView) + + self.add_view("/build", ZipBuilderAPIView) + + def build_zip_from_capture_ids(self, capture_id_list): + logging.debug(capture_id_list) + + fp = tempfile.NamedTemporaryFile(delete=False) + + with zipfile.ZipFile(fp, "w") as zipObj: + for capture_id in capture_id_list: + capture_obj = self.microscope.camera.image_from_id(capture_id) + filePath = capture_obj.file + zipObj.write(filePath) + + session_id = uuid.uuid4().hex + self.session_zips[session_id] = fp + + return session_id + + def zip_from_id(self, session_id): + fp = self.session_zips[session_id] + fp.seek(0) + return fp diff --git a/openflexure_microscope/plugins/loader.py b/openflexure_microscope/plugins/loader.py index dc7f9f1d..35f26c73 100644 --- a/openflexure_microscope/plugins/loader.py +++ b/openflexure_microscope/plugins/loader.py @@ -250,7 +250,7 @@ class BasePlugin: def views(self): return self._views - def add_view(self, rule, view_class): + def add_view(self, rule, view_class, **kwargs): # Remove all leading slashes from view route cleaned_rule = rule while cleaned_rule[0] == "/": @@ -259,13 +259,13 @@ class BasePlugin: # Expand the rule to include plugin name full_rule = "/{}/{}".format(self._name_uri_safe, cleaned_rule) - view_id = cleaned_rule.replace("/", "_") + view_id = cleaned_rule.replace("/", "_").replace("<", "").replace(">", "") # Create a Python-safe route ID logging.debug(view_id) # Store route information in a dictionary - d = {"rule": full_rule, "view": view_class} + d = {"rule": full_rule, "view": view_class, "kwargs": kwargs} # Add view to private views dictionary self._views[view_id] = d