Repository: fossasia/open-event-server

Issue:
Updating speaker detail in cfs throws a 403
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
If a non-admin user decides to update his/her speaker details in the cfs section, they are greeted with a 403 error.
 
**To Reproduce**
Steps to reproduce the behavior:
1. Create a non-admin user
2. Register yourself as a speaker via cfs
3. Try and edit the details after submission
4. See error

**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
The speaker should be able to access his/her own session

**Stacktrace**
<!-- If applicable, add stacktrace to help explain your problem. -->

```cmd

127.0.0.1 - - [21/Apr/2019 11:19:19] "PATCH /v1/speakers/6 HTTP/1.1" 403 -
INFO:werkzeug:127.0.0.1 - - [21/Apr/2019 11:19:19] "PATCH /v1/speakers/6 HTTP/1.1" 403 -

```
**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


Discussion:
### A sample to reproduce

![ezgif com-video-to-gif (3)](https://user-images.githubusercontent.com/21087061/56466049-c1899700-6428-11e9-9250-9d3c888e5f6b.gif)



Resolving patch:
diff --git a/app/api/helpers/permission_manager.py b/app/api/helpers/permission_manager.py
--- a/app/api/helpers/permission_manager.py
+++ b/app/api/helpers/permission_manager.py
@@ -8,6 +8,7 @@
 from app.models.session import Session
 from app.models.event import Event
 from app.models.order import Order
+from app.models.speaker import Speaker
 from app.api.helpers.jwt import get_identity
 
 
@@ -161,6 +162,28 @@ def is_speaker_for_session(view, view_args, view_kwargs, *args, **kwargs):
     return ForbiddenError({'source': ''}, 'Access denied.').respond()
 
 
+@jwt_required
+def is_speaker_itself_or_admin(view, view_args, view_kwargs, *args, **kwargs):
+    """
+    Allows admin and super admin access to any resource irrespective of id.
+    Otherwise the user can only access his/her resource.
+    """
+    user = current_identity
+
+    if user.is_admin or user.is_super_admin:
+        return view(*view_args, **view_kwargs)
+
+    if user.is_organizer(kwargs['event_id']) or user.is_coorganizer(kwargs['event_id']):
+        return view(*view_args, **view_kwargs)
+
+    if ('model' in kwargs) and (kwargs['model'] == Speaker):
+        query_user = Speaker.query.filter_by(email=user._email).first()
+        if query_user:
+            return view(*view_args, **view_kwargs)
+
+    return ForbiddenError({'source': ''}, 'Detail ownership is required, access denied.').respond()
+
+
 @jwt_required
 def is_session_self_submitted(view, view_args, view_kwargs, *args, **kwargs):
     """
@@ -304,7 +327,8 @@ def create_event(view, view_args, view_kwargs, *args, **kwargs):
     'is_user_itself': is_user_itself,
     'is_coorganizer_endpoint_related_to_event': is_coorganizer_endpoint_related_to_event,
     'is_registrar_or_user_itself': is_registrar_or_user_itself,
-    'is_coorganizer_but_not_admin': is_coorganizer_but_not_admin
+    'is_coorganizer_but_not_admin': is_coorganizer_but_not_admin,
+    'is_speaker_itself_or_admin': is_speaker_itself_or_admin
 }
 
 
diff --git a/app/api/speakers.py b/app/api/speakers.py
--- a/app/api/speakers.py
+++ b/app/api/speakers.py
@@ -145,7 +145,9 @@ def after_patch(self, result):
                                                                 speaker_id=speaker.id)
                     save_to_db(session_speaker_link, "Session Speaker Link Saved")
 
-    decorators = (api.has_permission('is_coorganizer_or_user_itself', methods="PATCH,DELETE", fetch="event_id",
+    decorators = (api.has_permission('is_speaker_itself_or_admin', methods="PATCH,DELETE", fetch="event_id",
+                                     fetch_as="event_id", model=Speaker),
+                  api.has_permission('is_coorganizer_or_user_itself', methods="PATCH,DELETE", fetch="event_id",
                                      fetch_as="event_id", model=Speaker),)
     schema = SpeakerSchema
     data_layer = {'session': db.session,


Test patch: