We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
 'AnonymousUserMixin' object has no attribute 'email' on updating an event
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
We are facing this Attribute Error the moment we try updating any event related object which corresponds to a celery task

**To Reproduce**
Steps to reproduce the behavior:
1. Update any existing event
2. See error

**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
It should work normally without any error

**Stacktrace**
<!-- If applicable, add stacktrace to help explain your problem. -->
```cmd
AttributeError: 'AnonymousUserMixin' object has no attribute 'email'

File "/home/shreyansh/open-event-server/venv/lib/python3.6/site-packages/flask/views.py", line 88, in view
    return self.dispatch_request(*args, **kwargs)
  File "/home/shreyansh/open-event-server/venv/src/flask-rest-jsonapi/flask_rest_jsonapi/resource.py", line 68, in dispatch_request
    response = method(*args, **kwargs)
  File "/home/shreyansh/open-event-server/venv/src/flask-rest-jsonapi/flask_rest_jsonapi/decorators.py", line 56, in wrapper
    return func(*args, **kwargs)
  File "/home/shreyansh/open-event-server/venv/src/flask-rest-jsonapi/flask_rest_jsonapi/resource.py", line 311, in patch
    self._data_layer.update_object(obj, data, kwargs)
  File "/home/shreyansh/open-event-server/venv/src/flask-rest-jsonapi/flask_rest_jsonapi/data_layers/alchemy.py", line 144, in update_object
    self.after_update_object(obj, data, view_kwargs)
  File "/home/shreyansh/open-event-server/app/api/events.py", line 485, in after_update_object
    start_export_tasks(event)
  File "/home/shreyansh/open-event-server/app/api/events.py", line 553, in start_export_tasks
    create_export_job(task_xcal.id, event_id)
```
**Additional details (please complete the following information):**
 - OS: [e.g. MacOS, Ubuntu, CentOS] Ubuntu
 - Python Version [e.g. `3.5`, `3.6`] 3.5

**Additional context**
<!-- Add any other context about the problem here. -->
Working on it

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `app/api/helpers/export_helpers.py`
Content:
```
1 import json
2 import os
3 import shutil
4 from collections import OrderedDict
5 from datetime import datetime
6 
7 import pytz
8 import requests
9 from flask import current_app as app
10 from flask import request, url_for
11 from flask_jwt import current_identity
12 from flask_login import current_user
13 
14 from app.api.helpers.db import save_to_db
15 from app.api.helpers.storage import upload, UPLOAD_PATHS, UploadedFile
16 from app.api.helpers.utilities import is_downloadable, get_filename_from_cd
17 from app.models import db
18 from app.models.custom_form import CustomForms
19 from app.models.event import Event
20 from app.models.export_job import ExportJob
21 from app.models.microlocation import Microlocation
22 from app.models.session import Session
23 from app.models.session_type import SessionType
24 from app.models.speaker import Speaker
25 from app.models.sponsor import Sponsor
26 from app.models.track import Track
27 
28 # order of keys in export json
29 FIELD_ORDER = {
30     'event': [
31         'id', 'name', 'latitude', 'longitude', 'location_name', 'starts_at', 'ends_at',
32         'timezone', 'description', 'original_image_url', 'logo_url', 'organizer_name',
33         'organizer_description', 'external_event_url', 'ticket_url', 'privacy', 'event_type_id',
34         'event_topic_id', 'event_sub_topic_id', 'code_of_conduct'
35     ],
36     'microlocations': ['id', 'name', 'floor'],
37     'sessions': [
38         'id', 'title', 'subtitle', 'short_abstract', 'long_abstract', 'starts_at', 'ends_at',
39         'session_type_id', 'track_id', 'comments', 'language', 'slides_url', 'audio_url', 'video_url'
40     ],
41     'speakers': [
42         'id', 'name', 'email', 'mobile', 'photo_url', 'organisation', 'position', 'country',
43         'short_biography', 'long_biography', 'website', 'twitter', 'facebook', 'github', 'linkedin'
44     ],
45     'sponsors': ['id', 'name', 'logo_url', 'level', 'type', 'url', 'description'],
46     'tracks': ['id', 'name', 'color', 'font_color'],
47     'session_types': ['id', 'name', 'length'],
48     'forms': []
49 }
50 
51 # keep sync with storage.UPLOAD_PATHS
52 DOWNLOAD_FIEDLS = {
53     'sessions': {
54         'video_url': ['video', '/videos/session_%d'],
55         'audio_url': ['audio', '/audios/session_%d'],
56         'slides_url': ['document', '/slides/session_%d']
57     },
58     'speakers': {
59         'photo_url': ['image', '/images/speakers/%s_%d']
60     },
61     'event': {
62         'logo_url': ['image', '/images/logo'],
63         'external_event_url': ['image', '/images/background']
64     },
65     'sponsors': {
66         'logo_url': ['image', '/images/sponsors/%s_%d']
67     }
68 }
69 
70 DATE_FIELDS = ['starts_at', 'ends_at', 'created_at', 'deleted_at', 'submitted_at']
71 
72 EXPORTS = [
73     ('event', Event),
74     ('microlocations', Microlocation),
75     ('sessions', Session),
76     ('speakers', Speaker),
77     ('sponsors', Sponsor),
78     ('tracks', Track),
79     ('session_types', SessionType),
80     ('forms', CustomForms)
81 ]
82 
83 # strings to remove in a filename
84 FILENAME_EXCLUDE = '<>:"/\|?*;'
85 
86 
87 # FUNCTIONS
88 
89 def sorted_dict(data):
90     """
91     sorts a json (dict/list->dict) and returns OrderedDict
92     """
93     if type(data) == OrderedDict:
94         data = dict(data)
95     if type(data) == dict:
96         data = OrderedDict(sorted(list(data.items()), key=lambda t: t[0]))
97     elif type(data) == list:
98         for count in range(len(data)):
99             data[count] = OrderedDict(sorted(list(data[count].items()), key=lambda t: t[0]))
100     return data
101 
102 
103 def _order_json(data, srv):
104     """
105     sorts the data a/c FIELD_ORDER and returns.
106     If some keys are not included in FIELD_ORDER, they go at last, sorted alphabetically
107     """
108     new_data = OrderedDict()
109     data.pop('_sa_instance_state', None)
110     for field in FIELD_ORDER[srv[0]]:
111         if field in DATE_FIELDS and data[field] and type(data[field]) != str:
112             new_data[field] = sorted_dict(data[field].isoformat())
113         elif field == 'font_color' and 'id' in new_data:
114             track = db.session.query(Track).filter(Track.id == new_data['id']).first()
115             new_data[field] = track.font_color
116         else:
117             new_data[field] = sorted_dict(data[field])
118         data.pop(field, None)
119 
120     # remaining fields, sort and add
121     # https://docs.python.org/2/library/collections.html#collections.OrderedDict
122     data = OrderedDict(sorted(list(data.items()), key=lambda t: t[0]))
123     for key in data:
124         if key in DATE_FIELDS and data[key] and type(data[key]) != str:
125             new_data[key] = sorted_dict(data[key].isoformat())
126         else:
127             new_data[key] = sorted_dict(data[key])
128 
129     return new_data
130 
131 
132 def _download_media(data, srv, dir_path, settings):
133     """
134     Downloads the media and saves it
135     """
136     if srv not in DOWNLOAD_FIEDLS:
137         return
138     for i in DOWNLOAD_FIEDLS[srv]:
139         if not data[i]:
140             continue
141         if not settings[DOWNLOAD_FIEDLS[srv][i][0]]:
142             continue
143         path = DOWNLOAD_FIEDLS[srv][i][1]
144         if srv == 'speakers':
145             path %= make_filename(data['name']), data['id']
146         elif srv == 'sponsors':
147             path %= make_filename(data['name']), data['id']
148         elif srv != 'event':
149             path = path % (data['id'])
150         if data[i].find('.') > -1:  # add extension
151             ext = data[i].rsplit('.', 1)[1]
152             if ext.find('/') == -1:
153                 path += '.' + ext
154         full_path = dir_path + path
155         # make dir
156         cdir = full_path.rsplit('/', 1)[0]
157         if not os.path.isdir(cdir):
158             os.makedirs(cdir)
159         # download and set
160         url = data[i]
161         if not is_downloadable(url):
162             continue
163         try:
164             r = requests.get(url, allow_redirects=True)
165             ext = get_filename_from_cd(r.headers.get('content-disposition'))[1]
166             full_path += ext
167             path += ext
168             open(full_path, 'wb').write(r.content)
169             data[i] = path
170         except Exception:
171             pass
172 
173 
174 def _generate_meta():
175     """
176     Generate Meta information for export
177     """
178     d = {'root_url': request.url_root}
179     return d
180 
181 
182 def export_event_json(event_id, settings):
183     """
184     Exports the event as a zip on the server and return its path
185     """
186     # make directory
187     exports_dir = app.config['BASE_DIR'] + '/static/uploads/exports/'
188     if not os.path.isdir(exports_dir):
189         os.makedirs(exports_dir)
190     dir_path = exports_dir + 'event%d' % int(event_id)
191     if os.path.isdir(dir_path):
192         shutil.rmtree(dir_path, ignore_errors=True)
193     os.makedirs(dir_path)
194     # save to directory
195     for e in EXPORTS:
196         if e[0] == 'event':
197             query_obj = db.session.query(e[1]).filter(
198                 e[1].id == event_id).first()
199             data = _order_json(dict(query_obj.__dict__), e)
200             _download_media(data, 'event', dir_path, settings)
201         else:
202             query_objs = db.session.query(e[1]).filter(
203                 e[1].event_id == event_id).all()
204             data = [_order_json(dict(query_obj.__dict__), e) for query_obj in query_objs]
205             for count in range(len(data)):
206                 data[count] = _order_json(data[count], e)
207                 _download_media(data[count], e[0], dir_path, settings)
208         data_str = json.dumps(data, indent=4, ensure_ascii=False, default=handle_unserializable_data).encode('utf-8')
209         fp = open(dir_path + '/' + e[0], 'w')
210         fp.write(str(data_str, 'utf-8'))
211         fp.close()
212     # add meta
213     data_str = json.dumps(
214         _generate_meta(), sort_keys=True,
215         indent=4, ensure_ascii=False
216     ).encode('utf-8')
217     fp = open(dir_path + '/meta', 'w')
218     fp.write(str(data_str, 'utf-8'))
219     fp.close()
220     # make zip
221     shutil.make_archive(dir_path, 'zip', dir_path)
222     dir_path = dir_path + ".zip"
223 
224     storage_path = UPLOAD_PATHS['exports']['zip'].format(
225         event_id=event_id
226     )
227     uploaded_file = UploadedFile(dir_path, dir_path.rsplit('/', 1)[1])
228     storage_url = upload(uploaded_file, storage_path)
229 
230     return storage_url
231 
232 
233 # HELPERS
234 
235 def create_export_job(task_id, event_id):
236     """
237     Create export job for an export that is going to start
238     """
239     export_job = ExportJob.query.filter_by(event_id=event_id).first()
240     task_url = url_for('tasks.celery_task', task_id=task_id)
241     if export_job:
242 
243         export_job.task = task_url
244         export_job.user_email = current_user.email
245         export_job.event = Event.query.get(event_id)
246         export_job.starts_at = datetime.now(pytz.utc)
247     else:
248         export_job = ExportJob(
249             task=task_url, user_email=current_identity.email,
250             event=Event.query.get(event_id)
251         )
252     save_to_db(export_job, 'ExportJob saved')
253 
254 
255 # FIELD DATA FORMATTERS
256 def make_filename(name):
257     """Make speaker image filename for export"""
258     for _ in FILENAME_EXCLUDE:
259         name = name.replace(_, ' ')
260     return ''.join(s.title() for s in name.split() if s)
261 
262 
263 def handle_unserializable_data(obj):
264     """
265     Handles objects which cannot be serialized by json.dumps()
266     :param obj: Object to be serialized
267     :return: JSON representation of the object
268     """
269     if isinstance(obj, datetime):
270         return obj.__str__()
271
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/app/api/helpers/export_helpers.py b/app/api/helpers/export_helpers.py
--- a/app/api/helpers/export_helpers.py
+++ b/app/api/helpers/export_helpers.py
@@ -230,6 +230,13 @@
     return storage_url
 
 
+def get_current_user():
+    if current_identity:
+        return current_identity
+    else:
+        return current_user
+
+
 # HELPERS
 
 def create_export_job(task_id, event_id):
@@ -238,15 +245,17 @@
     """
     export_job = ExportJob.query.filter_by(event_id=event_id).first()
     task_url = url_for('tasks.celery_task', task_id=task_id)
+    current_logged_user = get_current_user()
+
     if export_job:
 
         export_job.task = task_url
-        export_job.user_email = current_user.email
+        export_job.user_email = current_logged_user.email
         export_job.event = Event.query.get(event_id)
         export_job.starts_at = datetime.now(pytz.utc)
     else:
         export_job = ExportJob(
-            task=task_url, user_email=current_identity.email,
+            task=task_url, user_email=current_logged_user.email,
             event=Event.query.get(event_id)
         )
     save_to_db(export_job, 'ExportJob saved')

{"golden_diff": "diff --git a/app/api/helpers/export_helpers.py b/app/api/helpers/export_helpers.py\n--- a/app/api/helpers/export_helpers.py\n+++ b/app/api/helpers/export_helpers.py\n@@ -230,6 +230,13 @@\n     return storage_url\n \n \n+def get_current_user():\n+    if current_identity:\n+        return current_identity\n+    else:\n+        return current_user\n+\n+\n # HELPERS\n \n def create_export_job(task_id, event_id):\n@@ -238,15 +245,17 @@\n     \"\"\"\n     export_job = ExportJob.query.filter_by(event_id=event_id).first()\n     task_url = url_for('tasks.celery_task', task_id=task_id)\n+    current_logged_user = get_current_user()\n+\n     if export_job:\n \n         export_job.task = task_url\n-        export_job.user_email = current_user.email\n+        export_job.user_email = current_logged_user.email\n         export_job.event = Event.query.get(event_id)\n         export_job.starts_at = datetime.now(pytz.utc)\n     else:\n         export_job = ExportJob(\n-            task=task_url, user_email=current_identity.email,\n+            task=task_url, user_email=current_logged_user.email,\n             event=Event.query.get(event_id)\n         )\n     save_to_db(export_job, 'ExportJob saved')\n", "issue": " 'AnonymousUserMixin' object has no attribute 'email' on updating an event\n**Describe the bug**\r\n<!-- A clear and concise description of what the bug is. -->\r\nWe are facing this Attribute Error the moment we try updating any event related object which corresponds to a celery task\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n1. Update any existing event\r\n2. See error\r\n\r\n**Expected behavior**\r\n<!-- A clear and concise description of what you expected to happen. -->\r\nIt should work normally without any error\r\n\r\n**Stacktrace**\r\n<!-- If applicable, add stacktrace to help explain your problem. -->\r\n```cmd\r\nAttributeError: 'AnonymousUserMixin' object has no attribute 'email'\r\n\r\nFile \"/home/shreyansh/open-event-server/venv/lib/python3.6/site-packages/flask/views.py\", line 88, in view\r\n    return self.dispatch_request(*args, **kwargs)\r\n  File \"/home/shreyansh/open-event-server/venv/src/flask-rest-jsonapi/flask_rest_jsonapi/resource.py\", line 68, in dispatch_request\r\n    response = method(*args, **kwargs)\r\n  File \"/home/shreyansh/open-event-server/venv/src/flask-rest-jsonapi/flask_rest_jsonapi/decorators.py\", line 56, in wrapper\r\n    return func(*args, **kwargs)\r\n  File \"/home/shreyansh/open-event-server/venv/src/flask-rest-jsonapi/flask_rest_jsonapi/resource.py\", line 311, in patch\r\n    self._data_layer.update_object(obj, data, kwargs)\r\n  File \"/home/shreyansh/open-event-server/venv/src/flask-rest-jsonapi/flask_rest_jsonapi/data_layers/alchemy.py\", line 144, in update_object\r\n    self.after_update_object(obj, data, view_kwargs)\r\n  File \"/home/shreyansh/open-event-server/app/api/events.py\", line 485, in after_update_object\r\n    start_export_tasks(event)\r\n  File \"/home/shreyansh/open-event-server/app/api/events.py\", line 553, in start_export_tasks\r\n    create_export_job(task_xcal.id, event_id)\r\n```\r\n**Additional details (please complete the following information):**\r\n - OS: [e.g. MacOS, Ubuntu, CentOS] Ubuntu\r\n - Python Version [e.g. `3.5`, `3.6`] 3.5\r\n\r\n**Additional context**\r\n<!-- Add any other context about the problem here. -->\r\nWorking on it\n", "before_files": [{"content": "import json\nimport os\nimport shutil\nfrom collections import OrderedDict\nfrom datetime import datetime\n\nimport pytz\nimport requests\nfrom flask import current_app as app\nfrom flask import request, url_for\nfrom flask_jwt import current_identity\nfrom flask_login import current_user\n\nfrom app.api.helpers.db import save_to_db\nfrom app.api.helpers.storage import upload, UPLOAD_PATHS, UploadedFile\nfrom app.api.helpers.utilities import is_downloadable, get_filename_from_cd\nfrom app.models import db\nfrom app.models.custom_form import CustomForms\nfrom app.models.event import Event\nfrom app.models.export_job import ExportJob\nfrom app.models.microlocation import Microlocation\nfrom app.models.session import Session\nfrom app.models.session_type import SessionType\nfrom app.models.speaker import Speaker\nfrom app.models.sponsor import Sponsor\nfrom app.models.track import Track\n\n# order of keys in export json\nFIELD_ORDER = {\n    'event': [\n        'id', 'name', 'latitude', 'longitude', 'location_name', 'starts_at', 'ends_at',\n        'timezone', 'description', 'original_image_url', 'logo_url', 'organizer_name',\n        'organizer_description', 'external_event_url', 'ticket_url', 'privacy', 'event_type_id',\n        'event_topic_id', 'event_sub_topic_id', 'code_of_conduct'\n    ],\n    'microlocations': ['id', 'name', 'floor'],\n    'sessions': [\n        'id', 'title', 'subtitle', 'short_abstract', 'long_abstract', 'starts_at', 'ends_at',\n        'session_type_id', 'track_id', 'comments', 'language', 'slides_url', 'audio_url', 'video_url'\n    ],\n    'speakers': [\n        'id', 'name', 'email', 'mobile', 'photo_url', 'organisation', 'position', 'country',\n        'short_biography', 'long_biography', 'website', 'twitter', 'facebook', 'github', 'linkedin'\n    ],\n    'sponsors': ['id', 'name', 'logo_url', 'level', 'type', 'url', 'description'],\n    'tracks': ['id', 'name', 'color', 'font_color'],\n    'session_types': ['id', 'name', 'length'],\n    'forms': []\n}\n\n# keep sync with storage.UPLOAD_PATHS\nDOWNLOAD_FIEDLS = {\n    'sessions': {\n        'video_url': ['video', '/videos/session_%d'],\n        'audio_url': ['audio', '/audios/session_%d'],\n        'slides_url': ['document', '/slides/session_%d']\n    },\n    'speakers': {\n        'photo_url': ['image', '/images/speakers/%s_%d']\n    },\n    'event': {\n        'logo_url': ['image', '/images/logo'],\n        'external_event_url': ['image', '/images/background']\n    },\n    'sponsors': {\n        'logo_url': ['image', '/images/sponsors/%s_%d']\n    }\n}\n\nDATE_FIELDS = ['starts_at', 'ends_at', 'created_at', 'deleted_at', 'submitted_at']\n\nEXPORTS = [\n    ('event', Event),\n    ('microlocations', Microlocation),\n    ('sessions', Session),\n    ('speakers', Speaker),\n    ('sponsors', Sponsor),\n    ('tracks', Track),\n    ('session_types', SessionType),\n    ('forms', CustomForms)\n]\n\n# strings to remove in a filename\nFILENAME_EXCLUDE = '<>:\"/\\|?*;'\n\n\n# FUNCTIONS\n\ndef sorted_dict(data):\n    \"\"\"\n    sorts a json (dict/list->dict) and returns OrderedDict\n    \"\"\"\n    if type(data) == OrderedDict:\n        data = dict(data)\n    if type(data) == dict:\n        data = OrderedDict(sorted(list(data.items()), key=lambda t: t[0]))\n    elif type(data) == list:\n        for count in range(len(data)):\n            data[count] = OrderedDict(sorted(list(data[count].items()), key=lambda t: t[0]))\n    return data\n\n\ndef _order_json(data, srv):\n    \"\"\"\n    sorts the data a/c FIELD_ORDER and returns.\n    If some keys are not included in FIELD_ORDER, they go at last, sorted alphabetically\n    \"\"\"\n    new_data = OrderedDict()\n    data.pop('_sa_instance_state', None)\n    for field in FIELD_ORDER[srv[0]]:\n        if field in DATE_FIELDS and data[field] and type(data[field]) != str:\n            new_data[field] = sorted_dict(data[field].isoformat())\n        elif field == 'font_color' and 'id' in new_data:\n            track = db.session.query(Track).filter(Track.id == new_data['id']).first()\n            new_data[field] = track.font_color\n        else:\n            new_data[field] = sorted_dict(data[field])\n        data.pop(field, None)\n\n    # remaining fields, sort and add\n    # https://docs.python.org/2/library/collections.html#collections.OrderedDict\n    data = OrderedDict(sorted(list(data.items()), key=lambda t: t[0]))\n    for key in data:\n        if key in DATE_FIELDS and data[key] and type(data[key]) != str:\n            new_data[key] = sorted_dict(data[key].isoformat())\n        else:\n            new_data[key] = sorted_dict(data[key])\n\n    return new_data\n\n\ndef _download_media(data, srv, dir_path, settings):\n    \"\"\"\n    Downloads the media and saves it\n    \"\"\"\n    if srv not in DOWNLOAD_FIEDLS:\n        return\n    for i in DOWNLOAD_FIEDLS[srv]:\n        if not data[i]:\n            continue\n        if not settings[DOWNLOAD_FIEDLS[srv][i][0]]:\n            continue\n        path = DOWNLOAD_FIEDLS[srv][i][1]\n        if srv == 'speakers':\n            path %= make_filename(data['name']), data['id']\n        elif srv == 'sponsors':\n            path %= make_filename(data['name']), data['id']\n        elif srv != 'event':\n            path = path % (data['id'])\n        if data[i].find('.') > -1:  # add extension\n            ext = data[i].rsplit('.', 1)[1]\n            if ext.find('/') == -1:\n                path += '.' + ext\n        full_path = dir_path + path\n        # make dir\n        cdir = full_path.rsplit('/', 1)[0]\n        if not os.path.isdir(cdir):\n            os.makedirs(cdir)\n        # download and set\n        url = data[i]\n        if not is_downloadable(url):\n            continue\n        try:\n            r = requests.get(url, allow_redirects=True)\n            ext = get_filename_from_cd(r.headers.get('content-disposition'))[1]\n            full_path += ext\n            path += ext\n            open(full_path, 'wb').write(r.content)\n            data[i] = path\n        except Exception:\n            pass\n\n\ndef _generate_meta():\n    \"\"\"\n    Generate Meta information for export\n    \"\"\"\n    d = {'root_url': request.url_root}\n    return d\n\n\ndef export_event_json(event_id, settings):\n    \"\"\"\n    Exports the event as a zip on the server and return its path\n    \"\"\"\n    # make directory\n    exports_dir = app.config['BASE_DIR'] + '/static/uploads/exports/'\n    if not os.path.isdir(exports_dir):\n        os.makedirs(exports_dir)\n    dir_path = exports_dir + 'event%d' % int(event_id)\n    if os.path.isdir(dir_path):\n        shutil.rmtree(dir_path, ignore_errors=True)\n    os.makedirs(dir_path)\n    # save to directory\n    for e in EXPORTS:\n        if e[0] == 'event':\n            query_obj = db.session.query(e[1]).filter(\n                e[1].id == event_id).first()\n            data = _order_json(dict(query_obj.__dict__), e)\n            _download_media(data, 'event', dir_path, settings)\n        else:\n            query_objs = db.session.query(e[1]).filter(\n                e[1].event_id == event_id).all()\n            data = [_order_json(dict(query_obj.__dict__), e) for query_obj in query_objs]\n            for count in range(len(data)):\n                data[count] = _order_json(data[count], e)\n                _download_media(data[count], e[0], dir_path, settings)\n        data_str = json.dumps(data, indent=4, ensure_ascii=False, default=handle_unserializable_data).encode('utf-8')\n        fp = open(dir_path + '/' + e[0], 'w')\n        fp.write(str(data_str, 'utf-8'))\n        fp.close()\n    # add meta\n    data_str = json.dumps(\n        _generate_meta(), sort_keys=True,\n        indent=4, ensure_ascii=False\n    ).encode('utf-8')\n    fp = open(dir_path + '/meta', 'w')\n    fp.write(str(data_str, 'utf-8'))\n    fp.close()\n    # make zip\n    shutil.make_archive(dir_path, 'zip', dir_path)\n    dir_path = dir_path + \".zip\"\n\n    storage_path = UPLOAD_PATHS['exports']['zip'].format(\n        event_id=event_id\n    )\n    uploaded_file = UploadedFile(dir_path, dir_path.rsplit('/', 1)[1])\n    storage_url = upload(uploaded_file, storage_path)\n\n    return storage_url\n\n\n# HELPERS\n\ndef create_export_job(task_id, event_id):\n    \"\"\"\n    Create export job for an export that is going to start\n    \"\"\"\n    export_job = ExportJob.query.filter_by(event_id=event_id).first()\n    task_url = url_for('tasks.celery_task', task_id=task_id)\n    if export_job:\n\n        export_job.task = task_url\n        export_job.user_email = current_user.email\n        export_job.event = Event.query.get(event_id)\n        export_job.starts_at = datetime.now(pytz.utc)\n    else:\n        export_job = ExportJob(\n            task=task_url, user_email=current_identity.email,\n            event=Event.query.get(event_id)\n        )\n    save_to_db(export_job, 'ExportJob saved')\n\n\n# FIELD DATA FORMATTERS\ndef make_filename(name):\n    \"\"\"Make speaker image filename for export\"\"\"\n    for _ in FILENAME_EXCLUDE:\n        name = name.replace(_, ' ')\n    return ''.join(s.title() for s in name.split() if s)\n\n\ndef handle_unserializable_data(obj):\n    \"\"\"\n    Handles objects which cannot be serialized by json.dumps()\n    :param obj: Object to be serialized\n    :return: JSON representation of the object\n    \"\"\"\n    if isinstance(obj, datetime):\n        return obj.__str__()\n", "path": "app/api/helpers/export_helpers.py"}], "after_files": [{"content": "import json\nimport os\nimport shutil\nfrom collections import OrderedDict\nfrom datetime import datetime\n\nimport pytz\nimport requests\nfrom flask import current_app as app\nfrom flask import request, url_for\nfrom flask_jwt import current_identity\nfrom flask_login import current_user\n\nfrom app.api.helpers.db import save_to_db\nfrom app.api.helpers.storage import upload, UPLOAD_PATHS, UploadedFile\nfrom app.api.helpers.utilities import is_downloadable, get_filename_from_cd\nfrom app.models import db\nfrom app.models.custom_form import CustomForms\nfrom app.models.event import Event\nfrom app.models.export_job import ExportJob\nfrom app.models.microlocation import Microlocation\nfrom app.models.session import Session\nfrom app.models.session_type import SessionType\nfrom app.models.speaker import Speaker\nfrom app.models.sponsor import Sponsor\nfrom app.models.track import Track\n\n# order of keys in export json\nFIELD_ORDER = {\n    'event': [\n        'id', 'name', 'latitude', 'longitude', 'location_name', 'starts_at', 'ends_at',\n        'timezone', 'description', 'original_image_url', 'logo_url', 'organizer_name',\n        'organizer_description', 'external_event_url', 'ticket_url', 'privacy', 'event_type_id',\n        'event_topic_id', 'event_sub_topic_id', 'code_of_conduct'\n    ],\n    'microlocations': ['id', 'name', 'floor'],\n    'sessions': [\n        'id', 'title', 'subtitle', 'short_abstract', 'long_abstract', 'starts_at', 'ends_at',\n        'session_type_id', 'track_id', 'comments', 'language', 'slides_url', 'audio_url', 'video_url'\n    ],\n    'speakers': [\n        'id', 'name', 'email', 'mobile', 'photo_url', 'organisation', 'position', 'country',\n        'short_biography', 'long_biography', 'website', 'twitter', 'facebook', 'github', 'linkedin'\n    ],\n    'sponsors': ['id', 'name', 'logo_url', 'level', 'type', 'url', 'description'],\n    'tracks': ['id', 'name', 'color', 'font_color'],\n    'session_types': ['id', 'name', 'length'],\n    'forms': []\n}\n\n# keep sync with storage.UPLOAD_PATHS\nDOWNLOAD_FIEDLS = {\n    'sessions': {\n        'video_url': ['video', '/videos/session_%d'],\n        'audio_url': ['audio', '/audios/session_%d'],\n        'slides_url': ['document', '/slides/session_%d']\n    },\n    'speakers': {\n        'photo_url': ['image', '/images/speakers/%s_%d']\n    },\n    'event': {\n        'logo_url': ['image', '/images/logo'],\n        'external_event_url': ['image', '/images/background']\n    },\n    'sponsors': {\n        'logo_url': ['image', '/images/sponsors/%s_%d']\n    }\n}\n\nDATE_FIELDS = ['starts_at', 'ends_at', 'created_at', 'deleted_at', 'submitted_at']\n\nEXPORTS = [\n    ('event', Event),\n    ('microlocations', Microlocation),\n    ('sessions', Session),\n    ('speakers', Speaker),\n    ('sponsors', Sponsor),\n    ('tracks', Track),\n    ('session_types', SessionType),\n    ('forms', CustomForms)\n]\n\n# strings to remove in a filename\nFILENAME_EXCLUDE = '<>:\"/\\|?*;'\n\n\n# FUNCTIONS\n\ndef sorted_dict(data):\n    \"\"\"\n    sorts a json (dict/list->dict) and returns OrderedDict\n    \"\"\"\n    if type(data) == OrderedDict:\n        data = dict(data)\n    if type(data) == dict:\n        data = OrderedDict(sorted(list(data.items()), key=lambda t: t[0]))\n    elif type(data) == list:\n        for count in range(len(data)):\n            data[count] = OrderedDict(sorted(list(data[count].items()), key=lambda t: t[0]))\n    return data\n\n\ndef _order_json(data, srv):\n    \"\"\"\n    sorts the data a/c FIELD_ORDER and returns.\n    If some keys are not included in FIELD_ORDER, they go at last, sorted alphabetically\n    \"\"\"\n    new_data = OrderedDict()\n    data.pop('_sa_instance_state', None)\n    for field in FIELD_ORDER[srv[0]]:\n        if field in DATE_FIELDS and data[field] and type(data[field]) != str:\n            new_data[field] = sorted_dict(data[field].isoformat())\n        elif field == 'font_color' and 'id' in new_data:\n            track = db.session.query(Track).filter(Track.id == new_data['id']).first()\n            new_data[field] = track.font_color\n        else:\n            new_data[field] = sorted_dict(data[field])\n        data.pop(field, None)\n\n    # remaining fields, sort and add\n    # https://docs.python.org/2/library/collections.html#collections.OrderedDict\n    data = OrderedDict(sorted(list(data.items()), key=lambda t: t[0]))\n    for key in data:\n        if key in DATE_FIELDS and data[key] and type(data[key]) != str:\n            new_data[key] = sorted_dict(data[key].isoformat())\n        else:\n            new_data[key] = sorted_dict(data[key])\n\n    return new_data\n\n\ndef _download_media(data, srv, dir_path, settings):\n    \"\"\"\n    Downloads the media and saves it\n    \"\"\"\n    if srv not in DOWNLOAD_FIEDLS:\n        return\n    for i in DOWNLOAD_FIEDLS[srv]:\n        if not data[i]:\n            continue\n        if not settings[DOWNLOAD_FIEDLS[srv][i][0]]:\n            continue\n        path = DOWNLOAD_FIEDLS[srv][i][1]\n        if srv == 'speakers':\n            path %= make_filename(data['name']), data['id']\n        elif srv == 'sponsors':\n            path %= make_filename(data['name']), data['id']\n        elif srv != 'event':\n            path = path % (data['id'])\n        if data[i].find('.') > -1:  # add extension\n            ext = data[i].rsplit('.', 1)[1]\n            if ext.find('/') == -1:\n                path += '.' + ext\n        full_path = dir_path + path\n        # make dir\n        cdir = full_path.rsplit('/', 1)[0]\n        if not os.path.isdir(cdir):\n            os.makedirs(cdir)\n        # download and set\n        url = data[i]\n        if not is_downloadable(url):\n            continue\n        try:\n            r = requests.get(url, allow_redirects=True)\n            ext = get_filename_from_cd(r.headers.get('content-disposition'))[1]\n            full_path += ext\n            path += ext\n            open(full_path, 'wb').write(r.content)\n            data[i] = path\n        except Exception:\n            pass\n\n\ndef _generate_meta():\n    \"\"\"\n    Generate Meta information for export\n    \"\"\"\n    d = {'root_url': request.url_root}\n    return d\n\n\ndef export_event_json(event_id, settings):\n    \"\"\"\n    Exports the event as a zip on the server and return its path\n    \"\"\"\n    # make directory\n    exports_dir = app.config['BASE_DIR'] + '/static/uploads/exports/'\n    if not os.path.isdir(exports_dir):\n        os.makedirs(exports_dir)\n    dir_path = exports_dir + 'event%d' % int(event_id)\n    if os.path.isdir(dir_path):\n        shutil.rmtree(dir_path, ignore_errors=True)\n    os.makedirs(dir_path)\n    # save to directory\n    for e in EXPORTS:\n        if e[0] == 'event':\n            query_obj = db.session.query(e[1]).filter(\n                e[1].id == event_id).first()\n            data = _order_json(dict(query_obj.__dict__), e)\n            _download_media(data, 'event', dir_path, settings)\n        else:\n            query_objs = db.session.query(e[1]).filter(\n                e[1].event_id == event_id).all()\n            data = [_order_json(dict(query_obj.__dict__), e) for query_obj in query_objs]\n            for count in range(len(data)):\n                data[count] = _order_json(data[count], e)\n                _download_media(data[count], e[0], dir_path, settings)\n        data_str = json.dumps(data, indent=4, ensure_ascii=False, default=handle_unserializable_data).encode('utf-8')\n        fp = open(dir_path + '/' + e[0], 'w')\n        fp.write(str(data_str, 'utf-8'))\n        fp.close()\n    # add meta\n    data_str = json.dumps(\n        _generate_meta(), sort_keys=True,\n        indent=4, ensure_ascii=False\n    ).encode('utf-8')\n    fp = open(dir_path + '/meta', 'w')\n    fp.write(str(data_str, 'utf-8'))\n    fp.close()\n    # make zip\n    shutil.make_archive(dir_path, 'zip', dir_path)\n    dir_path = dir_path + \".zip\"\n\n    storage_path = UPLOAD_PATHS['exports']['zip'].format(\n        event_id=event_id\n    )\n    uploaded_file = UploadedFile(dir_path, dir_path.rsplit('/', 1)[1])\n    storage_url = upload(uploaded_file, storage_path)\n\n    return storage_url\n\n\ndef get_current_user():\n    if current_identity:\n        return current_identity\n    else:\n        return current_user\n\n\n# HELPERS\n\ndef create_export_job(task_id, event_id):\n    \"\"\"\n    Create export job for an export that is going to start\n    \"\"\"\n    export_job = ExportJob.query.filter_by(event_id=event_id).first()\n    task_url = url_for('tasks.celery_task', task_id=task_id)\n    current_logged_user = get_current_user()\n\n    if export_job:\n\n        export_job.task = task_url\n        export_job.user_email = current_logged_user.email\n        export_job.event = Event.query.get(event_id)\n        export_job.starts_at = datetime.now(pytz.utc)\n    else:\n        export_job = ExportJob(\n            task=task_url, user_email=current_logged_user.email,\n            event=Event.query.get(event_id)\n        )\n    save_to_db(export_job, 'ExportJob saved')\n\n\n# FIELD DATA FORMATTERS\ndef make_filename(name):\n    \"\"\"Make speaker image filename for export\"\"\"\n    for _ in FILENAME_EXCLUDE:\n        name = name.replace(_, ' ')\n    return ''.join(s.title() for s in name.split() if s)\n\n\ndef handle_unserializable_data(obj):\n    \"\"\"\n    Handles objects which cannot be serialized by json.dumps()\n    :param obj: Object to be serialized\n    :return: JSON representation of the object\n    \"\"\"\n    if isinstance(obj, datetime):\n        return obj.__str__()\n", "path": "app/api/helpers/export_helpers.py"}]}