Repository: fossasia/open-event-server

Issue:
Locally generated image URLs don't take port into account
**I'm submitting a ...**  (check one with "x")
- [x] bug report
- [ ] feature request
- [ ] support request => Please do not submit support requests here, instead ask your query in out Gitter channel at https://gitter.im/fossasia/open-event-server

**Current behavior:**

The URLs generated locally do not take port of the server into account. For instance, the sample event payload with image URL is converted to this format `http://localhost/static/media/events/1/large/eTNEbFJZOF/3827c2eb-5fcf-4ea3-ad46-bff1c10b69bf.jpg`

This is without the port number of the server and will create problems in consuming local APIs

**Expected behavior:**

The generated URLs should take the port of the server into account

**Steps to reproduce:**

Create an event with the example payload on locally running server




Discussion:
I would like to work on this issue. :relaxed: 
I would like to take up this
I think the simplest way would be to add `port` column in the settings table so that the url generator can directly use it from settings.
@iamareebjamal Can i work on this?
Go ahead 
@Masquerade0097 Are you still working on this? If not, I'd like to pick this up :)
@schedutron I'm quite busy for now. Please go on.

Resolving patch:
diff --git a/app/api/helpers/storage.py b/app/api/helpers/storage.py
--- a/app/api/helpers/storage.py
+++ b/app/api/helpers/storage.py
@@ -14,6 +14,8 @@
 
 from app.settings import get_settings
 
+SCHEMES = {80: 'http', 443: 'https'}
+
 #################
 # STORAGE SCHEMA
 #################
@@ -161,8 +163,22 @@ def upload_local(uploaded_file, key, **kwargs):
     if get_settings()['static_domain']:
         return get_settings()['static_domain'] + \
             file_relative_path.replace('/static', '')
-    url = urlparse(request.url)
-    return url.scheme + '://' + url.hostname + file_relative_path
+
+    return create_url(request.url, file_relative_path)
+
+
+def create_url(request_url, file_relative_path):
+    """Generates the URL of an uploaded file."""
+    url = urlparse(request_url)
+
+    # No need to specify scheme-corresponding port
+    port = url.port
+    if port and url.scheme == SCHEMES.get(url.port, None):
+        port = None
+
+    return '{scheme}://{hostname}:{port}{file_relative_path}'.format(
+        scheme=url.scheme, hostname=url.hostname, port=port,
+        file_relative_path=file_relative_path).replace(':None', '')
 
 
 def upload_to_aws(bucket_name, aws_region, aws_key, aws_secret, file, key, acl='public-read'):


Test patch:
diff --git a/tests/unittests/api/helpers/test_files.py b/tests/unittests/api/helpers/test_files.py
--- a/tests/unittests/api/helpers/test_files.py
+++ b/tests/unittests/api/helpers/test_files.py
@@ -2,6 +2,7 @@
 import os
 import unittest
 from io import BytesIO
+from urllib.parse import urlparse
 
 from PIL import Image
 from flask import Request, request, jsonify
@@ -110,7 +111,8 @@ def test_create_save_resized_image(self):
             aspect_ratio = False
             upload_path = 'test'
             resized_image_url = create_save_resized_image(image_url_test, width, aspect_ratio, height, upload_path, ext='png')
-            resized_image_file = app.config.get('BASE_DIR') + resized_image_url.split('/localhost')[1]
+            resized_image_path = urlparse(resized_image_url).path
+            resized_image_file = app.config.get('BASE_DIR') + resized_image_path
             resized_width, resized_height = self.getsizes(resized_image_file)
             self.assertTrue(os.path.exists(resized_image_file))
             self.assertEqual(resized_width, width)
@@ -124,16 +126,20 @@ def test_create_save_image_sizes(self):
             width_thumbnail = 500
             width_icon = 75
             image_sizes = create_save_image_sizes(image_url_test, image_sizes_type)
+            image_sizes = {
+                url_name: urlparse(image_sizes[url_name]).path
+                for url_name in image_sizes
+            }  # Now file names don't contain port (this gives relative urls).
 
             resized_image_url = image_sizes['original_image_url']
             resized_image_url_large = image_sizes['large_image_url']
             resized_image_url_thumbnail = image_sizes['thumbnail_image_url']
             resized_image_url_icon = image_sizes['icon_image_url']
 
-            resized_image_file = app.config.get('BASE_DIR') + resized_image_url.split('/localhost')[1]
-            resized_image_file_large = app.config.get('BASE_DIR') + resized_image_url_large.split('/localhost')[1]
-            resized_image_file_thumbnail = app.config.get('BASE_DIR') + resized_image_url_thumbnail.split('/localhost')[1]
-            resized_image_file_icon = app.config.get('BASE_DIR') + resized_image_url_icon.split('/localhost')[1]
+            resized_image_file = app.config.get('BASE_DIR') + resized_image_url
+            resized_image_file_large = app.config.get('BASE_DIR') + resized_image_url_large
+            resized_image_file_thumbnail = app.config.get('BASE_DIR') + resized_image_url_thumbnail
+            resized_image_file_icon = app.config.get('BASE_DIR') + resized_image_url_icon
 
             resized_width_large, _ = self.getsizes(resized_image_file_large)
             resized_width_thumbnail, _ = self.getsizes(resized_image_file_thumbnail)
diff --git a/tests/unittests/api/helpers/test_storage.py b/tests/unittests/api/helpers/test_storage.py
new file mode 100644
--- /dev/null
+++ b/tests/unittests/api/helpers/test_storage.py
@@ -0,0 +1,34 @@
+"""Test file for storage functions."""
+from unittest import TestCase
+
+from app.api.helpers.storage import create_url
+
+
+class TestStorageHelperValidation(TestCase):
+    """Test class for testing storage helper functions."""
+
+    def test_arbitrary_url(self):
+        """Method to test a url with arbitrary port."""
+
+        request_url = 'https://localhost:5000'
+        expected_file_url = 'https://localhost:5000/some/path/image.png'
+
+        self.assertEqual(
+            expected_file_url, create_url(request_url, '/some/path/image.png')
+            )
+
+    def test_http_url(self):
+        """Method to test a url with port 80."""
+        request_url = 'http://localhost:80'
+        expected_file_url = 'http://localhost/some/path/image.png'
+        self.assertEqual(
+            expected_file_url, create_url(request_url, '/some/path/image.png')
+            )
+
+    def test_https_url(self):
+        """Method to test a url with port 443."""
+        request_url = 'https://localhost:443'
+        expected_file_url = 'https://localhost/some/path/image.png'
+        self.assertEqual(
+            expected_file_url, create_url(request_url, '/some/path/image.png')
+            )