Repository: hydroshare/hydroshare

Issue:
Allow local image file upload in addition to URL for tools resource
Currently the tools resource only allows icon to be added via URL.
We will also allow image file upload


Discussion:

Resolving patch:
diff --git a/hs_tools_resource/forms.py b/hs_tools_resource/forms.py
--- a/hs_tools_resource/forms.py
+++ b/hs_tools_resource/forms.py
@@ -1,7 +1,7 @@
 from django.forms import ModelForm
 from django import forms
 
-from crispy_forms.layout import Layout, Field, HTML
+from crispy_forms.layout import Layout, Field, HTML, Row, Column
 
 from .models import RequestUrlBase, AppHomePageUrl, TestingProtocolUrl, \
     HelpPageUrl, SourceCodeUrl, IssuesPageUrl, MailingListUrl, Roadmap, \
@@ -115,6 +115,7 @@ class Meta:
 
 class UrlValidationForm(forms.Form):
     value = forms.URLField(max_length=1024, required=False)
+    data_url = forms.CharField(required=False)
 
 
 class AppResourceLevelUrlValidationForm(forms.Form):
@@ -456,21 +457,48 @@ def __init__(self, allow_edit=True, res_short_id=None,
                  element_id=None, element_name=None, *args, **kwargs):
         # the order in which the model fields are listed for the
         # FieldSet is the order these fields will be displayed
-        data_url = ""
+        data_url_db = ""
         if "instance" in kwargs:
             webapp_obj = kwargs.pop("instance")
             if webapp_obj and webapp_obj.metadata.app_icon:
-                data_url = webapp_obj.metadata.app_icon.data_url
+                data_url_db = webapp_obj.metadata.app_icon.data_url
         field_width = 'form-control input-sm'
         layout = Layout(
-            Field('value', css_class=field_width),
-            HTML("""
-                        <span id="icon-preview-label" class="control-label">Preview</span>
-                        <br>
-                        <img id="tool-icon-preview" src="{data_url}">
-                        """.format(data_url=data_url)),
+            Row(
+                Column(
+                    Field('value', css_class=field_width, placeholder="Type URL here..."),
+                    css_class='col-sm-6'
+                ),
+                Column(
+                    Field('data_url', css_class=field_width, type="hidden"),
+                    HTML("""
+                        <input id="icon-select" class="upload-picture"
+                            type="file" accept="image/*" style="display: none;">
+                        <a type="button" id="icon-select-btn"
+                            class="btn btn-success btn-xs" title="Upload from computer">
+                            <span class="glyphicon glyphicon-plus"></span>
+                            Browse for file
+                        </a>
+                        """),
+                    HTML("""
+                    <a type="button" id="icon-delete-btn" class="" title="Clear icon">
+                        <span class="glyphicon glyphicon-trash icon-button btn-remove"></span>
+                    </a>
+                    """),
+                    css_class='form-group col-md-6 mb-0'
+                ),
+                css_class='form-row'
+            ),
+            Row(
+                HTML("""
+                    <span id="icon-preview-label" class="control-label">Preview</span>
+                    <br>
+                    <img id="tool-icon-preview" src="{data_url_db}">
+                    """.format(data_url_db=data_url_db)),
+                css_class='form-row'
+                ),
         )
-        kwargs['element_name_label'] = 'Icon URL'
+        kwargs['element_name_label'] = 'Icon URL or File'
         super(ToolIconFormHelper, self).__init__(allow_edit,
                                                  res_short_id,
                                                  element_id,
@@ -489,10 +517,11 @@ def __init__(self, allow_edit=True, res_short_id=None, element_id=None, *args, *
                                          element_name='ToolIcon',
                                          **kwargs)
         self.fields['value'].label = ""
+        self.fields['data_url'].label = ""
 
     class Meta:
         model = ToolIcon
-        fields = ['value']
+        fields = ['value', 'data_url']
         exclude = ['content_object']
 
 
diff --git a/hs_tools_resource/models.py b/hs_tools_resource/models.py
--- a/hs_tools_resource/models.py
+++ b/hs_tools_resource/models.py
@@ -485,9 +485,8 @@ def _validate_tool_icon(cls, url):
 
     @classmethod
     def create(cls, **kwargs):
-        if 'value' in kwargs and "data_url" not in kwargs:
+        if "value" in kwargs:
             url = kwargs["value"]
-            data_url = cls._validate_tool_icon(url) if url else ""
 
             metadata_obj = kwargs['content_object']
             new_meta_instance = ToolIcon.objects.create(content_object=metadata_obj)
@@ -498,24 +497,33 @@ def create(cls, **kwargs):
         elif "data_url" in kwargs:
             metadata_obj = kwargs['content_object']
             new_meta_instance = ToolIcon.objects.create(content_object=metadata_obj)
-            new_meta_instance.value = kwargs["value"] if "value" in kwargs else ""
+            new_meta_instance.value = ""
             new_meta_instance.data_url = kwargs["data_url"]
             new_meta_instance.save()
             return new_meta_instance
         else:
-            raise ValidationError("No value parameter was found in the **kwargs list")
+            raise ValidationError("Value and data_url parameter were empty")
 
     @classmethod
     def update(cls, element_id, **kwargs):
         meta_instance = ToolIcon.objects.get(id=element_id)
-        if 'value' in kwargs:
-            url = kwargs["value"]
-            data_url = cls._validate_tool_icon(url) if url else ""
-            meta_instance.value = url
-            meta_instance.data_url = data_url
-            meta_instance.save()
+        if "value" in kwargs or "data_url" in kwargs:
+            if kwargs["value"]:
+                url = kwargs["value"]
+                data_url = cls._validate_tool_icon(url) if url else ""
+                meta_instance.value = url
+                meta_instance.data_url = data_url
+                meta_instance.save()
+            elif kwargs["data_url"]:
+                data_url = kwargs["data_url"]
+                meta_instance.data_url = data_url
+                meta_instance.save()
+            else:
+                meta_instance.value = ""
+                meta_instance.data_url = ""
+                meta_instance.save()
         else:
-            raise ValidationError("No value parameter was found in the **kwargs list")
+            raise ValidationError("No value/data_url parameter was found in the **kwargs list")
 
     class Meta:
         # ToolIcon element is not repeatable
diff --git a/hs_tools_resource/serializers.py b/hs_tools_resource/serializers.py
--- a/hs_tools_resource/serializers.py
+++ b/hs_tools_resource/serializers.py
@@ -89,7 +89,7 @@ class Meta:
 class ToolIconMetaDataSerializer(serializers.ModelSerializer):
     class Meta:
         model = ToolIcon
-        fields = ('value',)
+        fields = ('value', 'data_url')
 
 
 class MailingListSerializer(serializers.ModelSerializer):


Test patch: