Repository: fossasia/open-event-server

Issue:
HTTP 500 on creating an event
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
The server  returns HTTP 500 when creating or patching an event.

```
{
  "data": {
    "attributes": {
      "original-image-url": "https://media.licdn.com/media/AAEAAQAAAAAAAAdcAAAAJDNkMjFlMTNmLTNjMTMtNGRmNS04OTUwLTEwMzc2NzNhZDIxOA.png",
      "logo-url": "https://events.google.com/io2016/images/touch/homescreen192.png"
    },
    "id": "{{event}}",
    "type": "event"
  }
}
```

**To Reproduce**
Steps to reproduce the behavior:
1. Make a PATCH request with the data above.

**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
It should be successfully created or updated.

**Stacktrace**
<!-- If applicable, add stacktrace to help explain your problem. -->
```
Traceback (most recent call last):
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask/app.py", line 2309, in __call__
    return self.wsgi_app(environ, start_response)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/app/__init__.py", line 64, in __call__
    return self.app(environ, start_response)
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask/app.py", line 2295, in wsgi_app
    response = self.handle_exception(e)
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask_cors/extension.py", line 161, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask/app.py", line 1741, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask_cors/extension.py", line 161, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/src/flask-rest-jsonapi/flask_rest_jsonapi/api.py", line 133, in decorated
    return self.check_permissions(view, view_args, view_kwargs, *args, **kwargs)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/app/api/helpers/permission_manager.py", line 431, in permission_manager
    return permissions[args[0]](view, view_args, view_kwargs, *args, **kwargs)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/app/api/helpers/permissions.py", line 45, in decorator
    return fn(*args, **kwargs)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/app/api/helpers/permission_manager.py", line 61, in is_coorganizer
    return view(*view_args, **view_kwargs)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/src/flask-rest-jsonapi/flask_rest_jsonapi/decorators.py", line 32, in wrapper
    return func(*args, **kwargs)
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/site-packages/flask/views.py", line 88, in view
    return self.dispatch_request(*args, **kwargs)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/src/flask-rest-jsonapi/flask_rest_jsonapi/resource.py", line 68, in dispatch_request
    response = method(*args, **kwargs)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/src/flask-rest-jsonapi/flask_rest_jsonapi/decorators.py", line 56, in wrapper
    return func(*args, **kwargs)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/src/flask-rest-jsonapi/flask_rest_jsonapi/resource.py", line 300, in patch
    self._data_layer.update_object(obj, data, kwargs)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/src/flask-rest-jsonapi/flask_rest_jsonapi/data_layers/alchemy.py", line 126, in update_object
    self.before_update_object(obj, data, view_kwargs)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/app/api/events.py", line 423, in before_update_object
    uploaded_images = create_save_image_sizes(data['original_image_url'], 'event', event.id)
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/app/api/helpers/files.py", line 166, in create_save_image_sizes
    'original_image_url': create_save_resized_image(image_file, 0, 0, 0, original_upload_path, resize=False),
  File "/media/srv_twry/work/Projects/Community-Projects/Fossasia/open-event-server/app/api/helpers/files.py", line 81, in create_save_resized_image
    data = urllib.request.urlopen(image_file).read()
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/urllib/request.py", line 223, in urlopen
    return opener.open(url, data, timeout)
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/urllib/request.py", line 532, in open
    response = meth(req, response)
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/urllib/request.py", line 642, in http_response
    'http', request, response, code, msg, hdrs)
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/urllib/request.py", line 570, in error
    return self._call_chain(*args)
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/urllib/request.py", line 504, in _call_chain
    result = func(*args)
  File "/home/srv_twry/anaconda3/envs/open-event-server/lib/python3.6/urllib/request.py", line 650, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden
```


Discussion:
@schedutron @bhaveshAn @mayank8318 You may claim it if you want. I already have enough issues to work on. :)
@srv-twry Its because your passed value for `original-image-url` isn't showing any image https://media.licdn.com/media/AAEAAQAAAAAAAAdcAAAAJDNkMjFlMTNmLTNjMTMtNGRmNS04OTUwLTEwMzc2NzNhZDIxOA.png

try with this value or some other :)
```
 "original-image-url": "https://www.cdacentre.com/wp-content/uploads/2017/10/event.jpg",
```

Yes, I know. I did it on purpose. The server should handle these cases as well. It should never return HTTP 500 in any case. If there is a problem with the image, then it should atleast return 422 unprocessable entity. 
We can easily achieve it by adding a try except block IMO. 

Resolving patch:
diff --git a/app/api/events.py b/app/api/events.py
--- a/app/api/events.py
+++ b/app/api/events.py
@@ -8,11 +8,12 @@
 from sqlalchemy.orm.exc import NoResultFound
 import pytz
 from datetime import datetime
+import urllib.error
 
 from app.api.bootstrap import api
 from app.api.data_layers.EventCopyLayer import EventCopyLayer
 from app.api.helpers.db import save_to_db, safe_query
-from app.api.helpers.exceptions import ForbiddenException, ConflictException
+from app.api.helpers.exceptions import ForbiddenException, ConflictException, UnprocessableEntity
 from app.api.helpers.files import create_save_image_sizes
 from app.api.helpers.permission_manager import has_access
 from app.api.helpers.utilities import dasherize
@@ -132,7 +133,12 @@ def after_create_object(self, event, data, view_kwargs):
                                  status='accepted')
         save_to_db(role_invite, 'Organiser Role Invite Added')
         if data.get('original_image_url'):
-            uploaded_images = create_save_image_sizes(data['original_image_url'], 'event', event.id)
+            try:
+                uploaded_images = create_save_image_sizes(data['original_image_url'], 'event', event.id)
+            except (urllib.error.HTTPError, urllib.error.URLError):
+                raise UnprocessableEntity(
+                    {'source': 'attributes/original-image-url'}, 'Invalid Image URL'
+                )
             self.session.query(Event).filter_by(id=event.id).update(uploaded_images)
             self.session.commit()
 
@@ -418,7 +424,12 @@ def before_update_object(self, event, data, view_kwargs):
         :return:
         """
         if data.get('original_image_url') and data['original_image_url'] != event.original_image_url:
-            uploaded_images = create_save_image_sizes(data['original_image_url'], 'event', event.id)
+            try:
+                uploaded_images = create_save_image_sizes(data['original_image_url'], 'event', event.id)
+            except (urllib.error.HTTPError, urllib.error.URLError):
+                raise UnprocessableEntity(
+                    {'source': 'attributes/original-image-url'}, 'Invalid Image URL'
+                )
             data['original_image_url'] = uploaded_images['original_image_url']
             data['large_image_url'] = uploaded_images['large_image_url']
             data['thumbnail_image_url'] = uploaded_images['thumbnail_image_url']
diff --git a/app/api/helpers/files.py b/app/api/helpers/files.py
--- a/app/api/helpers/files.py
+++ b/app/api/helpers/files.py
@@ -77,19 +77,14 @@ def create_save_resized_image(image_file, basewidth=None, maintain_aspect=None,
     """
     if not image_file:
         return None
-
     filename = '{filename}.{ext}'.format(filename=get_file_name(), ext=ext)
-    try:
-        data = urllib.request.urlopen(image_file).read()
-    except urllib.error.HTTPError:
-        raise UnprocessableEntity(
-            {'source': 'attributes/original-image-url'}, 'Invalid Image URL'
-        )
+    data = urllib.request.urlopen(image_file).read()
     image_file = io.BytesIO(data)
     try:
         im = Image.open(image_file)
     except IOError:
         raise IOError("Corrupt/Invalid Image")
+
     # Convert to jpeg for lower file size.
     if im.format is not 'JPEG':
         img = im.convert('RGB')


Test patch: