Repository: fossasia/open-event-server

Issue:
Export json in a logical order
https://github.com/fossasia/open-event/issues/61#issuecomment-239312104

The json file contents should follow a logical order rather than alphabetical. 

> Please sort the order of the event JSON in the same logical order as the orga server wizard page, e.g. it is illogical to have the follow sorting: "latitude": 52.51074, "location_name": "Kemperplatz 1, 10785 Berlin, Germany", "logo": "/images/logo.jpg", "longitude": 13.37233,



Discussion:

Resolving patch:
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
@@ -2,6 +2,7 @@
 import os
 import shutil
 import requests
+from collections import OrderedDict
 from datetime import datetime
 from flask import request, g, url_for
 from flask_restplus import marshal
@@ -40,6 +41,29 @@
     ('forms', CustomFormDAO, CUSTOM_FORM)
 ]
 
+# order of keys in export json
+FIELD_ORDER = {
+    'event': [
+        'id', 'name', 'latitude', 'longitude', 'location_name', 'start_time', 'end_time',
+        'timezone', 'description', 'background_image', 'logo', 'organizer_name',
+        'organizer_description', 'event_url', 'social_links', 'ticket_url', 'privacy', 'type',
+        'topic', 'sub_topic', 'code_of_conduct', 'copyright'
+    ],
+    'microlocations': ['id', 'name', 'floor'],
+    'sessions': [
+        'id', 'title', 'subtitle', 'short_abstract', 'long_abstract', 'start_time', 'end_time',
+        'session_type', 'track', 'comments', 'language', 'slides', 'audio', 'video'
+    ],
+    'speakers': [
+        'id', 'name', 'email', 'mobile', 'photo', 'organisation', 'position', 'country',
+        'short_biography', 'long_biography', 'website', 'twitter', 'facebook', 'github', 'linkedin'
+    ],
+    'sponsors': ['id', 'name', 'logo', 'level', 'sponsor_type', 'url', 'description'],
+    'tracks': ['id', 'name', 'color'],
+    'session_types': ['id', 'name', 'length'],
+    'forms': []
+}
+
 # keep sync with storage.UPLOAD_PATHS
 DOWNLOAD_FIEDLS = {
     'sessions': {
@@ -65,6 +89,23 @@
 
 # FUNCTIONS
 
+def _order_json(data, srv):
+    """
+    sorts the data a/c FIELD_ORDER and returns.
+    If some keys are not included in FIELD_ORDER, they go at last, sorted alphabetically
+    """
+    new_data = OrderedDict()
+    for field in FIELD_ORDER[srv[0]]:
+        new_data[field] = data[field]
+        data.pop(field, None)
+    # remaining fields, sort and add
+    # https://docs.python.org/2/library/collections.html#collections.OrderedDict
+    data = OrderedDict(sorted(data.items(), key=lambda t: t[0]))
+    for key in data:
+        new_data[key] = data[key]
+    return new_data
+
+
 def _download_media(data, srv, dir_path, settings):
     """
     Downloads the media and saves it
@@ -124,13 +165,14 @@ def export_event_json(event_id, settings):
     # save to directory
     for e in EXPORTS:
         if e[0] == 'event':
-            data = marshal(e[1].get(event_id), e[2])
+            data = _order_json(marshal(e[1].get(event_id), e[2]), e)
             _download_media(data, 'event', dir_path, settings)
         else:
             data = marshal(e[1].list(event_id), e[2])
-            for _ in data:
-                _download_media(_, e[0], dir_path, settings)
-        data_str = json.dumps(data, sort_keys=True, indent=4)
+            for count in range(len(data)):
+                data[count] = _order_json(data[count], e)
+                _download_media(data[count], e[0], dir_path, settings)
+        data_str = json.dumps(data, indent=4)
         fp = open(dir_path + '/' + e[0], 'w')
         fp.write(data_str)
         fp.close()


Test patch:
diff --git a/tests/api/test_export_import.py b/tests/api/test_export_import.py
--- a/tests/api/test_export_import.py
+++ b/tests/api/test_export_import.py
@@ -140,6 +140,24 @@ def test_export_settings_marshal(self):
         if os.path.isdir(dr + '/images'):
             self.assertFalse(1, 'Image Dir Exists')
 
+    def test_export_order(self):
+        """
+        Tests order of export of fields in export files
+        """
+        self._create_set()
+        dr = 'static/temp/test_event_import'
+        # event
+        data = open(dr + '/event', 'r').read()
+        self.assertTrue(data.find('id') < data.find('background_image'))
+        self.assertTrue(data.find('location_name') < data.find('copyright'))
+        # sessions (a service)
+        data = open(dr + '/sessions', 'r').read()
+        self.assertTrue(data.find('id') < data.find('audio'))
+        self.assertTrue(data.find('short_abstract') < data.find('slides'))
+        # sponsors (a service)
+        data = open(dr + '/sponsors', 'r').read()
+        self.assertTrue(data.find('name') < data.find('description'))
+
 
 class TestEventImport(ImportExportBase):
     """