Repository: fossasia/open-event-server

Issue:
Add missing roles relationship to events
**I'm submitting a ...**  (check one with "x")
- [ ] bug report
- [x] feature request
- [ ] support request => Please do not submit support requests here, instead ask your query in out Gitter channel at https://gitter.im/fossasia/open-event-orga-server

Add missing roles relationship to events for admin/events
Related issue:
https://github.com/fossasia/open-event-frontend/issues/631


Discussion:
@geekyd I'm not sure how a Roles resource can be related to a specific event? At Roles API you just manage resources for different roles available in Orga System
@poush How do I get the roles of users for an event, i.e organiser,co-organiser etc. Is it `role-invites`?
That's the separate entity, user_events_roles which is not yet in API. I guess we can make GET resources for this. @niranjan94 @SaptakS Please confirm.
~user_events_roles is needed.~ I'll get back to you on this.

Resolving patch:
diff --git a/app/api/__init__.py b/app/api/__init__.py
--- a/app/api/__init__.py
+++ b/app/api/__init__.py
@@ -199,6 +199,19 @@
           '/events/<identifier>/relationships/attendees')
 api.route(EventRelationship, 'event_custom_forms', '/events/<int:id>/relationships/custom-forms',
           '/events/<identifier>/relationships/custom-forms')
+# Events -> roles:
+api.route(EventRelationship, 'event_organizers', '/events/<int:id>/relationships/organizers',
+          '/events/<identifier>/relationships/organizers')
+api.route(EventRelationship, 'event_coorganizers', '/events/<int:id>/relationships/coorganizers',
+          '/events/<identifier>/relationships/coorganizers')
+api.route(EventRelationship, 'event_track_organizers', '/events/<int:id>/relationships/track-organizers',
+          '/events/<identifier>/relationships/track-organizers')
+api.route(EventRelationship, 'event_moderators', '/events/<int:id>/relationships/moderators',
+          '/events/<identifier>/relationships/moderators')
+api.route(EventRelationship, 'event_registrars', '/events/<int:id>/relationships/registrars',
+          '/events/<identifier>/relationships/registrars')
+
+
 
 # microlocations
 api.route(MicrolocationList, 'microlocation_list', '/events/<int:event_id>/microlocations',
diff --git a/app/api/events.py b/app/api/events.py
--- a/app/api/events.py
+++ b/app/api/events.py
@@ -290,10 +290,44 @@ def validate_timezone(self, data, original_data):
                                 schema='CustomFormSchema',
                                 many=True,
                                 type_='custom-form')
+    organizers = Relationship(attribute='organizers',
+                              self_view='v1.event_organizers',
+                              self_view_kwargs={'id': '<id>'},
+                              related_view='v1.user_list',
+                              schema='UserSchema',
+                              type_='user',
+                              many=True)
+    coorganizers = Relationship(attribute='coorganizers',
+                                self_view='v1.event_coorganizers',
+                                self_view_kwargs={'id': '<id>'},
+                                related_view='v1.user_list',
+                                schema='UserSchema',
+                                type_='user',
+                                many=True)
+    track_organizers = Relationship(attribute='track_organizers',
+                                    self_view='v1.event_track_organizers',
+                                    self_view_kwargs={'id': '<id>'},
+                                    related_view='v1.user_list',
+                                    schema='UserSchema',
+                                    type_='user',
+                                    many=True)
+    moderators = Relationship(attribute='moderators',
+                              self_view='v1.event_moderators',
+                              self_view_kwargs={'id': '<id>'},
+                              related_view='v1.user_list',
+                              schema='UserSchema',
+                              type_='user',
+                              many=True)
+    registrars = Relationship(attribute='registrars',
+                              self_view='v1.event_registrars',
+                              self_view_kwargs={'id': '<id>'},
+                              related_view='v1.user_list',
+                              schema='UserSchema',
+                              type_='user',
+                              many=True)
 
 
 class EventList(ResourceList):
-
     def query(self, view_kwargs):
         query_ = self.session.query(Event).filter_by(state='published')
         if 'Authorization' in request.headers:
@@ -305,7 +339,7 @@ def query(self, view_kwargs):
 
         if view_kwargs.get('user_id') and 'GET' in request.method:
             user = safe_query(self, User, 'id', view_kwargs['user_id'], 'user_id')
-            query_ = query_.join(Event.roles).filter_by(user_id=user.id).join(UsersEventsRoles.role).\
+            query_ = query_.join(Event.roles).filter_by(user_id=user.id).join(UsersEventsRoles.role). \
                 filter(Role.name != ATTENDEE)
 
         if view_kwargs.get('event_type_id') and 'GET' in request.method:
@@ -347,7 +381,6 @@ def after_create_object(self, event, data, view_kwargs):
 
 
 class EventDetail(ResourceDetail):
-
     def before_get_object(self, view_kwargs):
         if view_kwargs.get('identifier'):
             event = safe_query(self, Event, 'identifier', view_kwargs['identifier'], 'identifier')
@@ -530,7 +563,7 @@ def before_update_object(self, event, data, view_kwargs):
             data['thumbnail_image_url'] = uploaded_images['thumbnail_image_url']
             data['icon_image_url'] = uploaded_images['icon_image_url']
 
-    decorators = (api.has_permission('is_organizer', methods="PATCH,DELETE", fetch="id", fetch_as="event_id",
+    decorators = (api.has_permission('is_coorganizer', methods="PATCH,DELETE", fetch="id", fetch_as="event_id",
                                      model=Event), )
     schema = EventSchema
     data_layer = {'session': db.session,
@@ -548,7 +581,8 @@ def before_get_object(self, view_kwargs):
             event = safe_query(self, Event, 'identifier', view_kwargs['identifier'], 'identifier')
             view_kwargs['id'] = event.id
 
-    decorators = (api.has_permission('auth_required', methods="POST,PATCH,DELETE"),)
+    decorators = (api.has_permission('is_coorganizer', fetch="id", fetch_as="event_id",
+                                     model=Event),)
     schema = EventSchema
     data_layer = {'session': db.session,
                   'model': Event,
diff --git a/app/models/event.py b/app/models/event.py
--- a/app/models/event.py
+++ b/app/models/event.py
@@ -108,6 +108,42 @@ class Event(db.Model):
     event_topic = db.relationship('EventTopic', backref='event', foreign_keys=[event_topic_id])
     event_sub_topic = db.relationship(
         'EventSubTopic', backref='event', foreign_keys=[event_sub_topic_id])
+    organizers = db.relationship('User',
+                                 viewonly=True,
+                                 secondary='join(UsersEventsRoles, Role,'
+                                           ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "organizer"))',
+                                 primaryjoin='UsersEventsRoles.event_id == Event.id',
+                                 secondaryjoin='User.id == UsersEventsRoles.user_id',
+                                 backref='organizer_of_events')
+    coorganizers = db.relationship('User',
+                                   viewonly=True,
+                                   secondary='join(UsersEventsRoles, Role,'
+                                             ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "coorganizer"))',
+                                   primaryjoin='UsersEventsRoles.event_id == Event.id',
+                                   secondaryjoin='User.id == UsersEventsRoles.user_id',
+                                   backref='coorganizer_of_events')
+    track_organizers = db.relationship('User',
+                                       viewonly=True,
+                                       secondary='join(UsersEventsRoles, Role,'
+                                                 ' and_(Role.id == UsersEventsRoles.role_id,'
+                                                 ' Role.name == "track_organizer"))',
+                                       primaryjoin='UsersEventsRoles.event_id == Event.id',
+                                       secondaryjoin='User.id == UsersEventsRoles.user_id',
+                                       backref='track_organizer_of_events')
+    registrars = db.relationship('User',
+                                 viewonly=True,
+                                 secondary='join(UsersEventsRoles, Role,'
+                                           ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "registrar"))',
+                                 primaryjoin='UsersEventsRoles.event_id == Event.id',
+                                 secondaryjoin='User.id == UsersEventsRoles.user_id',
+                                 backref='registrar_of_events')
+    moderators = db.relationship('User',
+                                 viewonly=True,
+                                 secondary='join(UsersEventsRoles, Role,'
+                                           ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "moderator"))',
+                                 primaryjoin='UsersEventsRoles.event_id == Event.id',
+                                 secondaryjoin='User.id == UsersEventsRoles.user_id',
+                                 backref='moderator_of_events')
 
     def __init__(self,
                  name=None,
@@ -231,7 +267,7 @@ def __setattr__(self, name, value):
     def notification_settings(self, user_id):
         try:
             return EmailNotification.query.filter_by(
-                user_id=(login.current_user.id if not user_id else int(user_id))).\
+                user_id=(login.current_user.id if not user_id else int(user_id))). \
                 filter_by(event_id=self.id).first()
         except:
             return None


Test patch: