Repository: fossasia/open-event-server

Issue:
Edit Session: Internal server error when more than one speakers are removed/added
At `/events/<event_id>/sessions/<session_id>/edit/`. 



Discussion:

Resolving patch:
diff --git a/app/helpers/data.py b/app/helpers/data.py
--- a/app/helpers/data.py
+++ b/app/helpers/data.py
@@ -473,84 +473,88 @@ def session_accept_reject(session, event_id, state):
 
     @staticmethod
     def edit_session(request, session):
-        form = request.form
-        event_id = session.event_id
-
-        slide_file = ""
-        video_file = ""
-        audio_file = ""
-        if 'slides' in request.files and request.files['slides'].filename != '':
-            slide_file = request.files['slides']
-        if 'video' in request.files and request.files['video'].filename != '':
-            video_file = request.files['video']
-        if 'audio' in request.files and request.files['audio'].filename != '':
-            audio_file = request.files['audio']
-
-        form_state = form.get('state', 'draft')
+        with db.session.no_autoflush:
+            form = request.form
+            event_id = session.event_id
+
+            slide_file = ""
+            video_file = ""
+            audio_file = ""
+            if 'slides' in request.files and request.files['slides'].filename != '':
+                slide_file = request.files['slides']
+            if 'video' in request.files and request.files['video'].filename != '':
+                video_file = request.files['video']
+            if 'audio' in request.files and request.files['audio'].filename != '':
+                audio_file = request.files['audio']
+
+            form_state = form.get('state', 'draft')
+
+            if slide_file != "":
+                slide_url = upload(
+                    slide_file,
+                    UPLOAD_PATHS['sessions']['slides'].format(
+                        event_id=int(event_id), id=int(session.id)
+                    ))
+                session.slides = slide_url
 
-        if slide_file != "":
-            slide_url = upload(
-                slide_file,
-                UPLOAD_PATHS['sessions']['slides'].format(
-                    event_id=int(event_id), id=int(session.id)
-                ))
-            session.slides = slide_url
+            if audio_file != "":
+                audio_url = upload(
+                    audio_file,
+                    UPLOAD_PATHS['sessions']['audio'].format(
+                        event_id=int(event_id), id=int(session.id)
+                    ))
+                session.audio = audio_url
+            if video_file != "":
+                video_url = upload(
+                    video_file,
+                    UPLOAD_PATHS['sessions']['video'].format(
+                        event_id=int(event_id), id=int(session.id)
+                    ))
+                session.video = video_url
 
-        if audio_file != "":
-            audio_url = upload(
-                audio_file,
-                UPLOAD_PATHS['sessions']['audio'].format(
-                    event_id=int(event_id), id=int(session.id)
-                ))
-            session.audio = audio_url
-        if video_file != "":
-            video_url = upload(
-                video_file,
-                UPLOAD_PATHS['sessions']['video'].format(
-                    event_id=int(event_id), id=int(session.id)
-                ))
-            session.video = video_url
+            if form_state == 'pending' and session.state != 'pending' and session.state != 'accepted' and session.state != 'rejected':
+                trigger_new_session_notifications(session.id, event_id=event_id)
 
-        if form_state == 'pending' and session.state != 'pending' and session.state != 'accepted' and session.state != 'rejected':
-            trigger_new_session_notifications(session.id, event_id=event_id)
+            session.title = form.get('title', '')
+            session.subtitle = form.get('subtitle', '')
+            session.long_abstract = form.get('long_abstract', '')
+            session.short_abstract = form.get('short_abstract', '')
 
-        session.title = form.get('title', '')
-        session.subtitle = form.get('subtitle', '')
-        session.long_abstract = form.get('long_abstract', '')
-        session.short_abstract = form.get('short_abstract', '')
+            if form.get('track', None) != "":
+                session.track_id = form.get('track', None)
+            else:
+                session.track_id = None
 
-        if form.get('track', None) != "":
-            session.track_id = form.get('track', None)
-        else:
-            session.track_id = None
+            if form.get('session_type', None) != "":
+                session.session_type_id = form.get('session_type', None)
+            else:
+                session.session_type_id = None
 
-        if form.get('session_type', None) != "":
-            session.session_type_id = form.get('session_type', None)
-        else:
-            session.session_type_id = None
+            existing_speaker_ids = form.getlist("speakers[]")
+            current_speaker_ids = []
+            existing_speaker_ids_by_email = []
 
-        existing_speaker_ids = form.getlist("speakers[]")
-        current_speaker_ids = []
-        existing_speaker_ids_by_email = []
+            save_to_db(session, 'Session Updated')
 
-        for existing_speaker in DataGetter.get_speaker_by_email(form.get("email")).all():
-            existing_speaker_ids_by_email.append(str(existing_speaker.id))
+            for existing_speaker in DataGetter.get_speaker_by_email(form.get("email")).all():
+                existing_speaker_ids_by_email.append(str(existing_speaker.id))
 
-        for current_speaker in session.speakers:
-            current_speaker_ids.append(str(current_speaker.id))
+            for current_speaker in session.speakers:
+                current_speaker_ids.append(str(current_speaker.id))
 
-        for current_speaker_id in current_speaker_ids:
-            if current_speaker_id not in existing_speaker_ids and current_speaker_id not in existing_speaker_ids_by_email:
-                current_speaker = DataGetter.get_speaker(current_speaker_id)
-                session.speakers.remove(current_speaker)
+            for current_speaker_id in current_speaker_ids:
+                if current_speaker_id not in existing_speaker_ids and current_speaker_id not in existing_speaker_ids_by_email:
+                    current_speaker = DataGetter.get_speaker(current_speaker_id)
+                    session.speakers.remove(current_speaker)
+                    db.session.commit()
 
-        for existing_speaker_id in existing_speaker_ids:
-            existing_speaker = DataGetter.get_speaker(existing_speaker_id)
-            if existing_speaker not in session.speakers:
-                session.speakers.append(existing_speaker)
+            for existing_speaker_id in existing_speaker_ids:
+                existing_speaker = DataGetter.get_speaker(existing_speaker_id)
+                if existing_speaker not in session.speakers:
+                    session.speakers.append(existing_speaker)
+                    db.session.commit()
 
-        save_to_db(session, 'Session Updated')
-        record_activity('update_session', session=session, event_id=event_id)
+            record_activity('update_session', session=session, event_id=event_id)
 
     @staticmethod
     def update_session(form, session):
diff --git a/app/views/admin/models_views/export.py b/app/views/admin/models_views/export.py
--- a/app/views/admin/models_views/export.py
+++ b/app/views/admin/models_views/export.py
@@ -12,7 +12,7 @@ class ExportView(BaseView):
 
     @expose('/')
     @flask_login.login_required
-    def display_api_view(self, event_id):
+    def display_export_view(self, event_id):
         event = DataGetter.get_event(event_id)
         if not is_verified_user():
             flash("Your account is unverified. "


Test patch:
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
@@ -111,7 +111,6 @@ def test_events_edit(self):
             self.assertTrue('EditTestName' in rv.data, msg=rv.data)
             self.assertTrue(data['sponsors[name]'] in rv.data, msg=rv.data)
 
-
     def test_event_view(self):
         with app.test_request_context():
             event = ObjectMother.get_event()
diff --git a/tests/views/admin/test_export.py b/tests/views/admin/test_export.py
new file mode 100644
--- /dev/null
+++ b/tests/views/admin/test_export.py
@@ -0,0 +1,19 @@
+import unittest
+
+from flask import url_for
+
+from app.helpers.data import save_to_db
+from tests.object_mother import ObjectMother
+from app import current_app as app
+from tests.views.view_test_case import OpenEventViewTestCase
+
+class TestExport(OpenEventViewTestCase):
+    def test_export_view(self):
+        with app.test_request_context():
+            event = ObjectMother.get_event()
+            save_to_db(event, "Event saved")
+            rv = self.app.get(url_for('event_export.display_export_view', event_id=event.id), follow_redirects=True)
+            self.assertTrue("Export" in rv.data, msg=rv.data)
+
+if __name__ == '__main__':
+    unittest.main()