Repository: fossasia/open-event-server

Issue:
Implement Call For Papers in Event API
Parent #1825

CallForPapers information can be added to the Event API (just like Copyright). 
So the import/export files will contain CallForPapers information in event.json (event). 



Discussion:
Please also include the dates the Call for Speakers is open.


Resolving patch:
diff --git a/app/api/events.py b/app/api/events.py
--- a/app/api/events.py
+++ b/app/api/events.py
@@ -10,9 +10,10 @@
 from app.models.social_link import SocialLink as SocialLinkModel
 from app.models.users_events_roles import UsersEventsRoles
 from app.models.event_copyright import EventCopyright
+from app.models.call_for_papers import CallForPaper as EventCFS
 from app.models.role import Role
 from app.models.user import ORGANIZER
-from app.helpers.data import save_to_db, update_version, record_activity
+from app.helpers.data import save_to_db, record_activity
 
 from .helpers.helpers import requires_auth, parse_args, \
     can_access, fake_marshal_with, fake_marshal_list_with, erase_from_dict
@@ -39,6 +40,14 @@
     'logo': fields.String()
 })
 
+EVENT_CFS = api.model('EventCFS', {
+    'announcement': fields.String(),
+    'start_date': fields.DateTime(),
+    'end_date': fields.DateTime(),
+    'timezone': fields.String(),
+    'privacy': EventPrivacyField()  # [public, private]
+})
+
 EVENT_VERSION = api.model('EventVersion', {
     'event_ver': fields.Integer(),
     'sessions_ver': fields.Integer(),
@@ -85,7 +94,8 @@
     'copyright': fields.Nested(EVENT_COPYRIGHT, allow_null=True),
     'schedule_published_on': fields.DateTime(),
     'code_of_conduct': fields.String(),
-    'social_links': fields.List(fields.Nested(SOCIAL_LINK), attribute='social_link', required=False),
+    'social_links': fields.List(fields.Nested(SOCIAL_LINK), attribute='social_link'),
+    'call_for_papers': fields.Nested(EVENT_CFS, allow_null=True),
     'version': fields.Nested(EVENT_VERSION)
 })
 
@@ -138,15 +148,22 @@ def fix_payload(self, data):
         for f in datetime_fields:
             if f in data:
                 data[f] = EVENT_POST[f].from_str(data.get(f))
+        # cfs datetimes
+        if data.get('call_for_papers'):
+            for _ in ['start_date', 'end_date']:
+                if _ in data['call_for_papers']:
+                    data['call_for_papers'][_] = EVENT_CFS[_].from_str(
+                        data['call_for_papers'].get(_))
         return data
 
     def create(self, data, url):
         data = self.validate(data)
         payload = self.fix_payload(data)
         # save copyright info
-        payload['copyright'] = CopyrightDAO.create(payload['copyright']
-                                                   if payload.get('copyright') else {},
-                                                   validate=False)
+        payload['copyright'] = CopyrightDAO.create(payload.get('copyright', {}), validate=False)
+        # save cfs info
+        if payload.get('call_for_papers'):  # don't create if call_for_papers==null
+            payload['call_for_papers'] = CFSDAO.create(payload['call_for_papers'], validate=False)
         # save event
         new_event = self.model(**payload)
         new_event.creator = g.user
@@ -170,13 +187,27 @@ def update(self, event_id, data):
             CopyrightDAO.update(event.copyright.id, payload['copyright']
                                 if payload['copyright'] else {})
             payload.pop('copyright')
-
+        # update cfs
+        if 'call_for_papers' in payload:
+            cfs_data = payload.get('call_for_papers')
+            if event.call_for_papers:
+                if cfs_data:  # update existing
+                    CFSDAO.update(event.call_for_papers.id, cfs_data)
+                else:  # delete if null
+                    CFSDAO.delete(event.call_for_papers.id)
+            else:  # create new
+                CFSDAO.create(cfs_data, validate=False)
+            payload.pop('call_for_papers')
+        # master update
         return BaseDAO.update(self, event_id, payload, validate=False)
 
 
 LinkDAO = SocialLinkDAO(SocialLinkModel, SOCIAL_LINK_POST)
 DAO = EventDAO(EventModel, EVENT_POST)
 CopyrightDAO = BaseDAO(EventCopyright, EVENT_COPYRIGHT)
+CopyrightDAO.version_key = 'event_ver'
+CFSDAO = BaseDAO(EventCFS, EVENT_CFS)  # CFS = Call For Speakers
+CFSDAO.version_key = 'event_ver'
 
 # DEFINE PARAMS
 
@@ -208,6 +239,7 @@ def update(self, event_id, data):
     },
 }
 
+
 def get_extended_event_model(includes=None):
     if includes is None:
         includes = []
diff --git a/app/models/event.py b/app/models/event.py
--- a/app/models/event.py
+++ b/app/models/event.py
@@ -105,7 +105,8 @@ def __init__(self,
                  ticket_include=None,
                  trash_date=None,
                  payment_country=None,
-                 payment_currency=None):
+                 payment_currency=None,
+                 call_for_papers=None):
         self.name = name
         self.logo = logo
         self.email = email
@@ -139,6 +140,7 @@ def __init__(self,
         self.trash_date = trash_date
         self.payment_country = payment_country
         self.payment_currency = payment_currency
+        self.call_for_papers = call_for_papers
 
     def __repr__(self):
         return '<Event %r>' % self.name


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
@@ -168,6 +168,8 @@ def _test_import_success(self):
                 self.assertIn('result', resp.data)
                 dic = json.loads(resp.data)['result']
                 break
+            if resp.status_code != 200:
+                self.assertTrue(False, 'FAIL')
             logging.info(resp.data)
             time.sleep(2)
         # check internals
diff --git a/tests/api/test_post_api.py b/tests/api/test_post_api.py
--- a/tests/api/test_post_api.py
+++ b/tests/api/test_post_api.py
@@ -75,7 +75,7 @@ def _test_model(self, name, data, path=None, checks=[]):
     def test_event_api(self):
         self._test_model(
             'event', POST_EVENT_DATA,
-            checks=['test@example.com', 'Test licence', '"event_ver": 0']
+            checks=['test@example.com', 'Test licence', '"event_ver": 0', 'proposal']
         )
 
     def test_track_api(self):
diff --git a/tests/api/utils_post_data.py b/tests/api/utils_post_data.py
--- a/tests/api/utils_post_data.py
+++ b/tests/api/utils_post_data.py
@@ -34,6 +34,13 @@
         "licence_url": "http://example.com",
         "year": 2016,
         "logo": ""
+    },
+    "call_for_papers": {
+        "announcement": "<p>Wanna speak at our prestigious event. Send us a proposal</p>",
+        "end_date": "2016-06-29T20:30:00",
+        "privacy": "public",
+        "start_date": "2016-06-29T19:30:00",
+        "timezone": "UTC"
     }
 }
 
diff --git a/tests/views/admin/test_events.py b/tests/views/admin/test_events.py
--- a/tests/views/admin/test_events.py
+++ b/tests/views/admin/test_events.py
@@ -30,6 +30,7 @@ def test_events_create_post(self):
             url = url_for('events.create_view')
             data = POST_EVENT_DATA.copy()
             del data['copyright']
+            del data['call_for_papers']
             data['sponsors_state'] = 'on'
             data['sponsors[name]'] = ['Sponsor 1', 'Sponsor 2']
             data['sponsors[type]'] = ['Gold', 'Silver']
@@ -57,6 +58,7 @@ def test_events_create_post_publish(self):
             url = url_for('events.create_view')
             data = POST_EVENT_DATA.copy()
             del data['copyright']
+            del data['call_for_papers']
             data['start_date'] = '07/04/2016'
             data['start_time'] = '19:00'
             data['end_date'] = '07/04/2016'
@@ -73,6 +75,7 @@ def test_events_create_post_publish_without_location_attempt(self):
             url = url_for('events.create_view')
             data = POST_EVENT_DATA.copy()
             del data['copyright']
+            del data['call_for_papers']
             data['start_date'] = '07/04/2016'
             data['start_time'] = '19:00'
             data['end_date'] = '07/04/2016'
@@ -95,6 +98,7 @@ def test_events_edit(self):
             url = url_for('events.edit_view', event_id=event.id)
             data = POST_EVENT_DATA.copy()
             del data['copyright']
+            del data['call_for_papers']
             data['sponsors_state'] = 'on'
             data['sponsors[name]'] = ['Sponsor 1', 'Sponsor 2']
             data['sponsors[type]'] = ['Gold', 'Silver']