Repository: fossasia/open-event-server

Issue:
Disallow attendee editing after order is in pending+ state
Right now, there is no check on attendee editing being disallowed based on order state, this should be fixed


Discussion:
please explain to me.

Resolving patch:
diff --git a/app/api/attendees.py b/app/api/attendees.py
--- a/app/api/attendees.py
+++ b/app/api/attendees.py
@@ -6,7 +6,7 @@
 
 from app.api.bootstrap import api
 from app.api.helpers.custom_forms import validate_custom_form_constraints_request
-from app.api.helpers.db import safe_query, safe_query_kwargs
+from app.api.helpers.db import safe_query, safe_query_kwargs, safe_query_by_id
 from app.api.helpers.errors import ForbiddenError, UnprocessableEntityError
 from app.api.helpers.permission_manager import has_access
 from app.api.helpers.permissions import jwt_required
@@ -206,6 +206,13 @@ def before_update_object(self, obj, data, kwargs):
         :param kwargs:
         :return:
         """
+        order = safe_query_by_id(Order, obj.order_id)
+        if order.status != 'initializing':
+            raise UnprocessableEntityError(
+                {'pointer': '/data/id'},
+                "Attendee can't be updated because the corresponding order is not in initializing state",
+            )
+
         if 'device_name_checkin' in data:
             if 'checkin_times' not in data or data['checkin_times'] is None:
                 raise UnprocessableEntityError(


Test patch:
diff --git a/tests/all/integration/api/attendee/test_attendee_api.py b/tests/all/integration/api/attendee/test_attendee_api.py
--- a/tests/all/integration/api/attendee/test_attendee_api.py
+++ b/tests/all/integration/api/attendee/test_attendee_api.py
@@ -520,3 +520,73 @@ def test_edit_attendee_order(db, client, jwt):
     # Order should not be updated
     assert attendee.order.id != order.id
     assert attendee.order.id == attendee_order.id
+
+
+def test_edit_attendee_when_order_is_pending(db, client, jwt):
+    attendee = AttendeeOrderTicketSubFactory()
+    order = attendee.order
+
+    order.status = "pending"
+
+    db.session.commit()
+
+    data = json.dumps(
+        {
+            'data': {
+                'type': 'attendee',
+                'id': str(attendee.id),
+                'attributes': {"lastname": "Ali"},
+                "relationships": {
+                    "order": {"data": {"id": str(order.id), "type": "order"}}
+                },
+            }
+        }
+    )
+
+    response = client.patch(
+        f'/v1/attendees/{attendee.id}',
+        content_type='application/vnd.api+json',
+        headers=jwt,
+        data=data,
+    )
+
+    db.session.refresh(attendee)
+
+    # Attendee should not be updated
+    assert response.status_code == 422
+    assert attendee.lastname != "Ali"
+
+
+def test_edit_attendee_when_order_is_completed(db, client, jwt):
+    attendee = AttendeeOrderTicketSubFactory()
+    order = attendee.order
+
+    order.status = "completed"
+
+    db.session.commit()
+
+    data = json.dumps(
+        {
+            'data': {
+                'type': 'attendee',
+                'id': str(attendee.id),
+                'attributes': {"firstname": "Haider"},
+                "relationships": {
+                    "order": {"data": {"id": str(order.id), "type": "order"}}
+                },
+            }
+        }
+    )
+
+    response = client.patch(
+        f'/v1/attendees/{attendee.id}',
+        content_type='application/vnd.api+json',
+        headers=jwt,
+        data=data,
+    )
+
+    db.session.refresh(attendee)
+
+    # Attendee should not be updated
+    assert response.status_code == 422
+    assert attendee.firstname != "Haider"
diff --git a/tests/hook_main.py b/tests/hook_main.py
--- a/tests/hook_main.py
+++ b/tests/hook_main.py
@@ -46,7 +46,7 @@
 from tests.factories.session import SessionFactory
 from tests.factories.speaker import SpeakerFactory
 from tests.factories.ticket import TicketFactory
-from tests.factories.attendee import AttendeeFactory
+from tests.factories.attendee import AttendeeFactory, AttendeeOrderSubFactory
 from tests.factories.session_type import SessionTypeFactory
 from tests.factories.track import TrackFactory
 from tests.factories.ticket_tag import TicketTagFactory
@@ -1969,7 +1969,7 @@ def attendee_patch(transaction):
     :return:
     """
     with stash['app'].app_context():
-        attendee = AttendeeFactory()
+        attendee = AttendeeOrderSubFactory()
         db.session.add(attendee)
         db.session.commit()
 
@@ -1982,7 +1982,7 @@ def attendee_delete(transaction):
     :return:
     """
     with stash['app'].app_context():
-        attendee = AttendeeFactory()
+        attendee = AttendeeOrderSubFactory()
         db.session.add(attendee)
         db.session.commit()