Repository: fossasia/open-event-server

Issue:
Add relationship between Notification action and Notification
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
Add relationship between Notification action and Notification



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
@@ -5,7 +5,8 @@
 from app.api.users import UserList, UserDetail, UserRelationship
 from app.api.user_emails import UserEmailListAdmin, UserEmailListPost, UserEmailList, UserEmailDetail, \
     UserEmailRelationship
-from app.api.notifications import NotificationList, NotificationListAdmin, NotificationDetail, NotificationRelationship
+from app.api.notifications import NotificationList, NotificationListAdmin, NotificationDetail,\
+    NotificationRelationship, NotificationActionDetail, NotificationActionRelationship, NotificationActionList
 from app.api.email_notifications import EmailNotificationList, EmailNotificationListAdmin, EmailNotificationDetail, \
     EmailNotificationRelationshipOptional, EmailNotificationRelationshipRequired
 from app.api.tickets import TicketList, TicketListPost, TicketDetail, TicketRelationshipRequired, \
@@ -117,12 +118,20 @@
 # notifications
 api.route(NotificationListAdmin, 'notification_list_admin', '/notifications')
 api.route(NotificationList, 'notification_list', '/users/<int:user_id>/notifications')
-api.route(NotificationDetail, 'notification_detail', '/notifications/<int:id>')
+api.route(NotificationDetail, 'notification_detail', '/notifications/<int:id>',
+          '/notification-actions/<int:notification_action_id>/notification')
 api.route(NotificationRelationship, 'notification_user',
           '/notifications/<int:id>/relationships/user')
 api.route(NotificationRelationship, 'notification_actions',
           '/notifications/<int:id>/relationships/actions')
 
+# notification actions
+api.route(NotificationActionList, 'notification_actions_list',
+          '/notifications/<int:notification_id>/notification-actions')
+api.route(NotificationActionDetail, 'notification_action_detail', '/notification-actions/<int:id>')
+api.route(NotificationActionRelationship, 'notification_actions_notification',
+          '/notification-actions/<int:id>/relationships/notification')
+
 # email_notifications
 api.route(EmailNotificationListAdmin, 'email_notification_list_admin', '/email-notifications')
 api.route(EmailNotificationList, 'email_notification_list', '/users/<int:user_id>/email-notifications')
diff --git a/app/api/notifications.py b/app/api/notifications.py
--- a/app/api/notifications.py
+++ b/app/api/notifications.py
@@ -2,9 +2,9 @@
 
 from app.api.bootstrap import api
 from app.api.helpers.db import safe_query
-from app.api.schema.notifications import NotificationSchema
+from app.api.schema.notifications import NotificationSchema, NotificationActionSchema
 from app.models import db
-from app.models.notification import Notification
+from app.models.notification import Notification, NotificationAction
 from app.models.user import User
 
 
@@ -63,10 +63,30 @@ class NotificationDetail(ResourceDetail):
     """
     Notification detail by ID
     """
-    decorators = (api.has_permission('is_user_itself', fetch="user_id", model=Notification),)
+    def before_get(self, args, kwargs):
+        if kwargs.get('notification_action_id'):
+            notification_action = safe_query(db, NotificationAction,
+                                             'id', kwargs['notification_action_id'], 'notification_action_id')
+            kwargs['id'] = notification_action.notification_id
+
+    def before_get_object(self, view_kwargs):
+        """
+        before get method to get the resource id for fetching details
+        :param view_kwargs:
+        :return:
+        """
+        if view_kwargs.get('notification_action_id'):
+            notification_action = safe_query(self, NotificationAction,
+                                             'id', view_kwargs['notification_action_id'], 'notification_action_id')
+            view_kwargs['id'] = notification_action.notification_id
+
+    decorators = (api.has_permission('is_user_itself', methods="PATCH,DELETE", fetch="user_id", model=Notification),)
     schema = NotificationSchema
     data_layer = {'session': db.session,
-                  'model': Notification}
+                  'model': Notification,
+                  'methods': {
+                      'before_get_object': before_get_object
+                  }}
 
 
 class NotificationRelationship(ResourceRelationship):
@@ -78,3 +98,35 @@ class NotificationRelationship(ResourceRelationship):
     methods = ['GET', 'PATCH']
     data_layer = {'session': db.session,
                   'model': Notification}
+
+
+class NotificationActionList(ResourceList):
+    """
+    List all the Notification-actions
+    """
+    decorators = (api.has_permission('is_admin'),)
+    methods = ['GET']
+    schema = NotificationSchema
+    data_layer = {'session': db.session,
+                  'model': Notification}
+
+
+class NotificationActionDetail(ResourceDetail):
+    """
+    Notification action detail by ID
+    """
+    decorators = (api.has_permission('is_user_itself', fetch="user_id", model=Notification),)
+    schema = NotificationActionSchema
+    data_layer = {'session': db.session,
+                  'model': NotificationAction}
+
+
+class NotificationActionRelationship(ResourceRelationship):
+    """
+    Notification Relationship
+    """
+    decorators = (api.has_permission('is_user_itself', fetch="user_id", model=Notification),)
+    schema = NotificationActionSchema
+    methods = ['GET', 'PATCH']
+    data_layer = {'session': db.session,
+                  'model': NotificationAction}
diff --git a/app/api/schema/notifications.py b/app/api/schema/notifications.py
--- a/app/api/schema/notifications.py
+++ b/app/api/schema/notifications.py
@@ -15,12 +15,21 @@ class Meta:
         Meta class for Notification Action API schema
         """
         type_ = 'notification-action'
+        self_view = 'v1.notification_action_detail'
+        self_view_kwargs = {'id': '<id>'}
         inflect = dasherize
 
     id = fields.Str(dump_only=True)
     action_type = fields.Str(allow_none=True, dump_only=True)
     subject = fields.Str(allow_none=True, dump_only=True)
     subject_id = fields.Str(allow_none=True, dump_only=True)
+    notification = Relationship(attribute='notification',
+                                self_view='v1.notification_actions_notification',
+                                self_view_kwargs={'id': '<id>'},
+                                related_view='v1.notification_detail',
+                                related_view_kwargs={'notification_action_id': '<id>'},
+                                schema='NotificationSchema',
+                                type_='notification-action')
 
 
 class NotificationSchema(SoftDeletionSchema):
@@ -35,7 +44,6 @@ class Meta:
         type_ = 'notification'
         self_view = 'v1.notification_detail'
         self_view_kwargs = {'id': '<id>'}
-        self_view_many = 'v1.microlocation_list_post'
         inflect = dasherize
 
     id = fields.Str(dump_only=True)
@@ -44,10 +52,14 @@ class Meta:
     received_at = fields.DateTime(dump_only=True)
     accept = fields.Str(allow_none=True, dump_only=True)
     is_read = fields.Boolean()
-    actions = Relationship(attribute='actions',
-                           schema='NotificationActionSchema',
-                           many=True,
-                           type_='notification-action')
+    notification_actions = Relationship(attribute='actions',
+                                        schema='NotificationActionSchema',
+                                        self_view='v1.notification_actions',
+                                        self_view_kwargs={'id': '<id>'},
+                                        related_view='v1.notification_actions_list',
+                                        related_view_kwargs={'notification_id': '<id>'},
+                                        many=True,
+                                        type_='notification-action')
     user = Relationship(attribute='user',
                         self_view='v1.notification_user',
                         self_view_kwargs={'id': '<id>'},


Test patch:
diff --git a/tests/hook_main.py b/tests/hook_main.py
--- a/tests/hook_main.py
+++ b/tests/hook_main.py
@@ -2033,7 +2033,7 @@ def notification_get_detail(transaction):
 @hooks.before("Notifications > Notification Detail with Actions > Notification Detail with Actions")
 def notification_get_detail_with_actions(transaction):
     """
-    GET /notifications/1?include=actions
+    GET /notifications/1?include=notification_actions
     :param transaction:
     :return:
     """