This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch main
in repository 
https://gitbox.apache.org/repos/asf/airavata-cookiecutter-django-output-view.git

commit 4a20d70be78b1f7202b87686520ec92b96d0aacc
Author: Marcus Christie <[email protected]>
AuthorDate: Fri May 28 15:11:21 2021 -0400

    initial commit
---
 README.md                                          | 10 +++
 cookiecutter.json                                  |  9 +++
 hooks/post_gen_project.py                          | 72 ++++++++++++++++++++++
 .../{{cookiecutter.project_slug}}.py               | 49 +++++++++++++++
 4 files changed, 140 insertions(+)

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..515c7a5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+
+# Airavata Django Portal Output View Provider Cookiecutter
+
+## Quickstart
+
+
+    cd custom_django_app/custom_django_app/
+    cookiecutter 
https://github.com/machristie/cookiecutter-airavata-django-output-view.git -f
+
+`-f` is needed because output_views/ directory should already exist
diff --git a/cookiecutter.json b/cookiecutter.json
new file mode 100644
index 0000000..7765419
--- /dev/null
+++ b/cookiecutter.json
@@ -0,0 +1,9 @@
+{
+  "project_name": "My Custom Output View",
+  "project_slug": "{{ cookiecutter.project_name | slugify(separator='_')}}",
+  "project_short_description": "{{ cookiecutter.project_name }} generates data 
for an output view in the Airavata Django Portal",
+  "output_view_provider_class_name": "{{ cookiecutter.project_name | title | 
replace(' ', '') }}Provider",
+  "output_views_directory_name": "output_views",
+  "output_view_display_type": ["image", "link", "html"],
+  "number_of_output_files": ["single (URI)", "multiple (URI_COLLECTION)"]
+}
diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py
new file mode 100644
index 0000000..919288f
--- /dev/null
+++ b/hooks/post_gen_project.py
@@ -0,0 +1,72 @@
+import os
+import sys
+
+
+def find_setup_cfg_file():
+    currdir = os.getcwd()
+    while currdir != os.path.dirname(currdir):
+        setupcfg_path = os.path.join(currdir, "setup.cfg")
+        if os.path.isfile(setupcfg_path):
+            return setupcfg_path
+        else:
+            currdir = os.path.dirname(currdir)
+    # Couldn't find it, returning None
+    return None
+
+def find_last_line_of_output_view_providers(setup_cfg_lines):
+    output_vps_start = -1
+    output_vps_end = -1
+    for index, line in enumerate(setup_cfg_lines):
+        if line.strip().startswith('airavata.output_view_providers'):
+            output_vps_start = index
+        # If the line is non-blank and has a dangling item, update the end 
index
+        elif line.startswith(' ') and line.strip() != '' and output_vps_start 
> 0:
+            output_vps_end = index
+        elif output_vps_end > 0:
+            break
+    # Return None if we couldn't find it
+    return output_vps_end if output_vps_end > 0 else None
+
+def find_last_line_of_entry_points(setup_cfg_lines):
+    entry_points_start = -1
+    entry_points_end = -1
+    for index, line in enumerate(setup_cfg_lines):
+        if line.strip() == '[options.entry_points]':
+            entry_points_start = index
+        # If the line is non-blank and doesn't start a new section, update the 
end index
+        elif line.strip() != '' and not line.startswith('[') and 
entry_points_start > 0:
+            entry_points_end = index
+        elif entry_points_end > 0:
+            break
+    # Return None if we couldn't find it
+    return entry_points_end if entry_points_end > 0 else None
+
+def insert_output_view_provider(setup_cfg_lines, index, 
insert_entry_point_group=False):
+    updated_lines = setup_cfg_lines.copy()
+    updated_lines.insert(index+1, "    {{cookiecutter.project_slug}} = 
FIXME.{{cookiecutter.output_views_directory_name}}:{{cookiecutter.output_view_provider_class_name}}"
 + os.linesep)
+    if insert_entry_point_group:
+        updated_lines.insert(index+1, "airavata.output_view_providers =" + 
os.linesep)
+    return updated_lines
+
+setup_cfg_file = find_setup_cfg_file()
+if not setup_cfg_file:
+    print("Could not find setup.cfg file! Are you running this from within a 
custom Django app?", file=sys.stderr)
+    sys.exit(1)
+
+with open(setup_cfg_file, 'r+') as f:
+    lines = f.readlines()
+    end_of_output_view_providers = 
find_last_line_of_output_view_providers(lines)
+    updated_lines = None
+    if end_of_output_view_providers is not None:
+        updated_lines = insert_output_view_provider(lines, 
end_of_output_view_providers)
+    else:
+        end_of_entry_points = find_last_line_of_entry_points(lines)
+        if end_of_entry_points is not None:
+            updated_lines = insert_output_view_provider(lines, 
end_of_entry_points, insert_entry_point_group=True)
+    if updated_lines is None:
+        print("Could not find insertion point for output view provider entry 
point!", file=sys.stderr)
+        sys.exit(1)
+    else:
+        f.seek(0)
+        f.writelines(updated_lines)
+
diff --git 
a/{{cookiecutter.output_views_directory_name}}/{{cookiecutter.project_slug}}.py 
b/{{cookiecutter.output_views_directory_name}}/{{cookiecutter.project_slug}}.py
new file mode 100644
index 0000000..3077383
--- /dev/null
+++ 
b/{{cookiecutter.output_views_directory_name}}/{{cookiecutter.project_slug}}.py
@@ -0,0 +1,49 @@
+{% if cookiecutter.output_view_display_type == "image" %}
+import io
+{% elif cookiecutter.output_view_display_type == "html" %}
+from django.template.loader import render_to_string
+{% endif %}
+
+class {{ cookiecutter.output_view_provider_class_name }}:
+    display_type = "{{ cookiecutter.output_view_display_type }}"
+    # As a performance optimization, the output view provider can be invoked
+    # immediately instead of only after being selected by the user in the
+    # portal.  Set to True to invoke immediately. Only use this with simple
+    # output view providers that return quickly
+    immediate = False
+    name = "{{ cookiecutter.project_name }}"
+
+    def generate_data(self, request, experiment_output, experiment,{% if 
"single" in cookiecutter.number_of_output_files %} output_file=None,{% else %} 
output_files=None,{% endif %} **kwargs):
+    {% if cookiecutter.output_view_display_type == "link" %}
+        label = "Link to Google"
+        url = "https://google.com";
+        return {
+            "label": label,
+            "url": url
+        }
+    {% elif cookiecutter.output_view_display_type == "image" %}
+        # Typical thing is to write an image to an in-memory BytesIO object and
+        # then return its bytes
+        buffer = io.BytesIO()
+        # Example: say you have a figure object, which is an instance of
+        # matplotlib's Figure. Then you can write it to the BytesIO object
+        # figure.savefig(buffer, format='png')
+        image_bytes = buffer.getvalue()
+        buffer.close()
+        return {
+            'image': image_bytes,
+            'mime-type': 'image/png'
+        }
+    {% elif cookiecutter.output_view_display_type == "html" %}
+        # Return a dictionary with 'output' as the HTML string and 'js' as the
+        # absolute URL to a JavaScript file to load for the view
+        # In the example code, the HTML is produced from a Django template, but
+        # you don't have to do it that way.
+        html_context = {}  # extra context
+        html_string = render_to_string('path/to/template.html', html_context)
+        js_abs_path = "/static/path/to/script.js"
+        return {
+            'output': html_string,
+            'js': js_abs_path
+        }
+    {% endif %}

Reply via email to