Repository: fossasia/open-event-server

Issue:
Email Notification: Add seperate resourcelist class, docs, permissions for direct endpoints
Parent issue #4101.


Discussion:

Resolving patch:
diff --git a/app/api/__init__.py b/app/api/__init__.py
--- a/app/api/__init__.py
+++ b/app/api/__init__.py
@@ -2,7 +2,8 @@
 from app.api.ticket_fees import TicketFeeList, TicketFeeDetail
 from app.api.users import UserList, UserDetail, UserRelationship, VerifyUser
 from app.api.notifications import NotificationList, NotificationDetail, NotificationRelationship
-from app.api.email_notifications import EmailNotificationList, EmailNotificationDetail, EmailNotificationRelationship
+from app.api.email_notifications import EmailNotificationList, EmailNotificationListPost, EmailNotificationDetail,\
+    EmailNotificationRelationshipOptional, EmailNotificationRelationshipRequired
 from app.api.tickets import TicketList, TicketDetail, TicketRelationshipRequired, TicketRelationshipOptional
 from app.api.events import EventList, EventDetail, EventRelationship
 from app.api.event_types import EventTypeList, EventTypeDetail, EventTypeRelationship
@@ -63,11 +64,12 @@
           '/notifications/<int:id>/relationships/user')
 
 # email_notifications
+api.route(EmailNotificationListPost, 'email_notification_list_post', '/email-notifications')
 api.route(EmailNotificationList, 'email_notification_list', '/users/<int:id>/email-notifications')
 api.route(EmailNotificationDetail, 'email_notification_detail', '/email-notifications/<int:id>')
-api.route(EmailNotificationRelationship, 'email_notification_user',
+api.route(EmailNotificationRelationshipRequired, 'email_notification_user',
           '/email-notifications/<int:id>/relationships/user')
-api.route(EmailNotificationRelationship, 'email_notification_event',
+api.route(EmailNotificationRelationshipOptional, 'email_notification_event',
           '/email-notifications/<int:id>/relationships/event')
 
 # image_sizes
diff --git a/app/api/email_notifications.py b/app/api/email_notifications.py
--- a/app/api/email_notifications.py
+++ b/app/api/email_notifications.py
@@ -9,6 +9,10 @@
 from app.models.user import User
 from app.api.helpers.permissions import is_user_itself, jwt_required
 from app.api.helpers.db import safe_query
+from app.api.helpers.utilities import require_relationship
+from app.api.helpers.permission_manager import has_access
+from app.api.helpers.exceptions import ForbiddenException
+
 
 
 class EmailNotificationSchema(Schema):
@@ -50,6 +54,23 @@ class Meta:
                         )
 
 
+class EmailNotificationListPost(ResourceList):
+    """
+    List and create email notifications
+    """
+
+    def before_post(self, args, kwargs, data):
+        require_relationship(['user'], data)
+        if not has_access('is_user_itself', id=data['user']):
+            raise ForbiddenException({'source': ''}, 'You need to be the user.')
+
+    view_kwargs = True
+    methods = ['POST', ]
+    schema = EmailNotificationSchema
+    data_layer = {'session': db.session,
+                  'model': EmailNotification}
+
+
 class EmailNotificationList(ResourceList):
     """
     List all the email notification
@@ -67,25 +88,14 @@ def query(self, view_kwargs):
             query_ = query_.join(User).filter(User.id == user.id)
         return query_
 
-    def before_create_object(self, data, view_kwargs):
-        """
-        method to create object before post
-        :param data:
-        :param view_kwargs:
-        :return:
-        """
-        if view_kwargs.get('id') is not None:
-            user = safe_query(self, User, 'id', view_kwargs['id'], 'id')
-            data['user_id'] = user.id
-
     view_kwargs = True
+    methods = ['GET', ]
     decorators = (is_user_itself,)
     schema = EmailNotificationSchema
     data_layer = {'session': db.session,
                   'model': EmailNotification,
                   'methods': {
-                      'query': query,
-                      'before_create_object': before_create_object
+                      'query': query
                   }}
 
 
@@ -100,9 +110,20 @@ class EmailNotificationDetail(ResourceDetail):
                   'model': EmailNotification}
 
 
-class EmailNotificationRelationship(ResourceRelationship):
+class EmailNotificationRelationshipRequired(ResourceRelationship):
+    """
+    Email notification Relationship (Required)
+    """
+    decorators = (jwt_required,)
+    methods = ['GET', 'PATCH']
+    schema = EmailNotificationSchema
+    data_layer = {'session': db.session,
+                  'model': EmailNotification}
+
+
+class EmailNotificationRelationshipOptional(ResourceRelationship):
     """
-    Email notification Relationship
+    Email notification Relationship (Optional)
     """
     decorators = (jwt_required,)
     schema = EmailNotificationSchema
diff --git a/app/factories/email_notification.py b/app/factories/email_notification.py
--- a/app/factories/email_notification.py
+++ b/app/factories/email_notification.py
@@ -17,4 +17,4 @@ class Meta:
     session_schedule = 1
     after_ticket_purchase = 1
     event_id = 1
-    user_id = 1
+    user_id = 2


Test patch:
diff --git a/tests/hook_main.py b/tests/hook_main.py
--- a/tests/hook_main.py
+++ b/tests/hook_main.py
@@ -1315,7 +1315,7 @@ def notification_delete(transaction):
 
 
 # ------------------------- Email Notifications -------------------------
-@hooks.before("Email Notifications > Email Notifications Collection > List All Email Notifications")
+@hooks.before("Email Notifications > Email Notifications Collection Get > List All Email Notifications")
 def email_notification_get_list(transaction):
     """
     GET /users/2/email-notifications
@@ -1328,10 +1328,10 @@ def email_notification_get_list(transaction):
         db.session.commit()
 
 
-@hooks.before("Email Notifications > Email Notifications Collection > Create Email Notificaiton")
+@hooks.before("Email Notifications > Email Notifications Collection Post > Create Email Notificaiton")
 def email_notification_post(transaction):
     """
-    POST /users/2/email-notifications
+    POST /email-notifications
     :param transaction:
     :return:
     """