from openflexure_microscope.api.utilities import get_bool, JsonResponse from openflexure_microscope.api.v1.views import MicroscopeView from openflexure_microscope.utilities import filter_dict from flask import Response, jsonify, request, abort, url_for, redirect, send_file class ListAPI(MicroscopeView): def get(self): """ Get list of image captures. .. :quickref: Captures; Get collection of captures :>header Accept: application/json :query include_unavailable: return json representations of captures that have been completely deleted :>jsonarr boolean available: availability of capture data :>jsonarr string filename: filename of capture :>jsonarr string id: unique id of the capture object :>jsonarr boolean keep_on_disk: keep the capture file on microscope after closing :>jsonarr boolean locked: file locked for modifications (mostly used for video recording) :>jsonarr string path: path on pi storage to the capture file, if available :>jsonarr boolean stream: capture stored in-memory as a BytesIO stream :>jsonarr json uri: - **download** *(string)*: api uri to the capture file download - **state** *(string)*: api uri to the capture json representation :>header Content-Type: application/json :status 200: capture found :status 404: no capture found with that id """ include_unavailable = get_bool(request.args.get('include_unavailable')) if include_unavailable: captures = [image.state for image in self.microscope.camera.images] else: captures = [image.state for image in self.microscope.camera.images if image.state['available']] return jsonify(captures) def delete(self): """ Delete all captures (not yet implemented) .. :quickref: Captures; Delete all captures """ for image in self.microscope.camera.images: image.delete() captures = [image.state for image in self.microscope.camera.images] return jsonify(captures) def post(self): """ Create a new image capture. .. :quickref: Captures; New capture **Example request**: .. sourcecode:: http POST /camera/capture HTTP/1.1 Accept: application/json { "filename": "myfirstcapture", "temporary": false, "use_video_port": true, "bayer": true, "size": { "width": 640, "height": 480 } } :>header Accept: application/json :json boolean available: availability of capture data :>json string filename: filename of capture :>json string id: unique id of the capture object :>json boolean temporary: delete the capture file on microscope after closing :>json boolean locked: file locked for modifications (mostly used for video recording) :>json string path: path on pi storage to the capture file, if available :>json boolean stream: capture stored in-memory as a BytesIO stream :>json json uri: - **download** *(string)*: api uri to the capture file download - **state** *(string)*: api uri to the capture json representation :
json boolean available: availability of capture data :>json string filename: filename of capture :>json string id: unique id of the capture object :>json boolean keep_on_disk: keep the capture file on microscope after closing :>json boolean locked: file locked for modifications (mostly used for video recording) :>json string path: path on pi storage to the capture file, if available :>json boolean stream: capture stored in-memory as a BytesIO stream :>json json uri: - **download** *(string)*: api uri to the capture file download - **state** *(string)*: api uri to the capture json representation """ capture_obj = self.microscope.camera.image_from_id(capture_id) if not capture_obj: return abort(404) # 404 Not Found # Get capture state capture_metadata = capture_obj.state # Add API routes to returned state uri_dict = { 'uri': {'state': '{}'.format(url_for('.capture', capture_id=capture_obj.id))} } # If available, also add download link if capture_metadata['available']: uri_dict['uri']['download'] = '{}download/{}'.format( url_for('.capture', capture_id=capture_obj.id), capture_obj.filename ) capture_metadata.update(uri_dict) return jsonify(capture_metadata) def delete(self, capture_id): """ Delete all capture data from the Pi, even if `keep_on_disk=true;`. .. :quickref: Capture; Delete capture. """ capture_obj = self.microscope.camera.image_from_id(capture_id) if not capture_obj: return abort(404) # 404 Not Found capture_obj.delete() return jsonify({"return": capture_id}) def put(self, capture_id): """ Add arbitrary metadata to the capture (stored in an accompanying capture `.yaml` file) .. :quickref: Capture; Update capture metadata **Example request**: .. sourcecode:: http PUT /camera/capture/d0b2067abbb946f19351e075c5e7cd5b HTTP/1.1 Accept: application/json { "user_id": "ofm_1234", "patient_number": 1452, } :>header Accept: application/json :
header Accept: image/jpeg :query thumbnail: return an image thumbnail e.g. ?thumbnail=true :>header Content-Type: image/jpeg :status 200: capture data found :status 404: no capture found with that id """ capture_obj = self.microscope.camera.image_from_id(capture_id) if not capture_obj or not capture_obj.state['available']: return abort(404) # 404 Not Found thumbnail = get_bool(request.args.get('thumbnail')) return redirect(url_for( '.capture_download', capture_id=capture_id, filename=capture_obj.filename, thumbnail=thumbnail ), code=307) class DownloadAPI(MicroscopeView): def get(self, capture_id, filename): capture_obj = self.microscope.camera.image_from_id(capture_id) if not capture_obj or not capture_obj.state['available']: return abort(404) # 404 Not Found thumbnail = get_bool(request.args.get('thumbnail')) # If no filename is specified, redirect to the capture's currently set filename if not filename: return redirect(url_for( 'capture_download', capture_id=capture_id, filename=capture_obj.filename, thumbnail=thumbnail ), code=307) # Download the image data using the requested filename if thumbnail: img = capture_obj.thumbnail else: img = capture_obj.data return send_file( img, mimetype='image/jpeg') class MetadataRedirectAPI(MicroscopeView): def get(self, capture_id): """ Return metadatadata for a capture. Return capture metadata as a YAML file with the requested filename. I.e., `/(capture_id)/download/bar.yaml` will download the file as `bar.yaml`, regardless of the capture's initially set filename. Route automatically redirects to download the capture metadata under it's currently set filename. I.e., `/(capture_id)/download` will redirect to `/(capture_id)/download/(filename)`. .. :quickref: Capture; Download capture metadata **Example request**: .. sourcecode:: http GET /camera/capture/d0b2067abbb946f19351e075c5e7cd5b/metadata/2018-11-20_16-04-17.yaml HTTP/1.1 Accept: text/yaml :>header Accept: text/yaml :query as_attachment: return the image as an attachment download e.g. ?as_attachment=true :>header Content-Type: text/yaml :status 200: capture data found :status 404: no capture found with that id """ capture_obj = self.microscope.camera.image_from_id(capture_id) if not capture_obj or not capture_obj.state['available']: return abort(404) # 404 Not Found return redirect(url_for( '.metadata_download', capture_id=capture_id, filename=capture_obj.metadataname ), code=307) class MetadataAPI(MicroscopeView): def get(self, capture_id, filename): capture_obj = self.microscope.camera.image_from_id(capture_id) if not capture_obj or not capture_obj.state['available']: return abort(404) # 404 Not Found # If no filename is specified, redirect to the capture's currently set filename if not filename: return redirect(url_for( 'capture_download', capture_id=capture_id, filename=capture_obj.metadataname ), code=307) # Download the metadata using the requested filename data = capture_obj.yaml return Response( data, mimetype="text/yaml") class TagsAPI(MicroscopeView): def get(self, capture_id): """ Return tag list for a capture. .. :quickref: Capture; Show capture tags **Example request**: .. sourcecode:: http GET /camera/capture/d0b2067abbb946f19351e075c5e7cd5b/tags HTTP/1.1 Accept: text/yaml :>header Accept: text/yaml :>header Content-Type: text/yaml :status 200: capture data found :status 404: no capture found with that id """ capture_obj = self.microscope.camera.image_from_id(capture_id) if not capture_obj or not capture_obj.state['available']: return abort(404) # 404 Not Found metadata_tags = filter_dict(capture_obj.state, ['metadata', 'tags']) return jsonify(metadata_tags) def put(self, capture_id): """ Add tags to the capture .. :quickref: Capture; Update capture tags **Example request**: .. sourcecode:: http PUT /camera/capture/d0b2067abbb946f19351e075c5e7cd5b/tags HTTP/1.1 Accept: application/json ["tests", "mytag", "someothertag"] :>header Accept: application/json :
header Accept: application/json :