Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
'/event-invoices/<int:event_invoice_id>/user', '/speakers/<int:speaker_id>/user',
'/access-codes/<int:access_code_id>/marketer', '/email-notifications/<int:email_notification_id>/user',
'/discount-codes/<int:discount_code_id>/marketer', '/sessions/<int:session_id>/creator',
'/attendees/<int:attendee_id>/user', '/feedbacks/<int:feedback_id>/user',
'/attendees/<int:attendee_id>/user', '/feedbacks/<int:feedback_id>/user', '/events/<int:event_id>/owner',
'/alternate-emails/<int:user_email_id>/user', '/favourite-events/<int:user_favourite_event_id>/user')
api.route(UserRelationship, 'user_notification', '/users/<int:id>/relationships/notifications')
api.route(UserRelationship, 'user_feedback', '/users/<int:id>/relationships/feedbacks')
Expand All @@ -102,6 +102,7 @@
api.route(UserRelationship, 'user_access_codes', '/users/<int:id>/relationships/access-codes')
api.route(UserRelationship, 'user_discount_codes', '/users/<int:id>/relationships/discount-codes')
api.route(UserRelationship, 'user_email_notifications', '/users/<int:id>/relationships/email-notifications')
api.route(UserRelationship, 'user_owner_event', '/users/<int:id>/relationships/owner-events')
api.route(UserRelationship, 'user_organizer_event', '/users/<int:id>/relationships/organizer-events')
api.route(UserRelationship, 'user_coorganizer_event', '/users/<int:id>/relationships/coorganizer-events')
api.route(UserRelationship, 'user_track_organizer_event', '/users/<int:id>/relationships/track-organizer-events')
Expand Down Expand Up @@ -315,6 +316,8 @@
api.route(EventRelationship, 'event_stripe_authorization', '/events/<int:id>/relationships/stripe-authorization',
'/events/<identifier>/relationships/stripe-authorization')
# Events -> roles:
api.route(EventRelationship, 'event_owner', '/events/<int:id>/relationships/owner',
'/events/<identifier>/relationships/owner')
api.route(EventRelationship, 'event_organizers', '/events/<int:id>/relationships/organizers',
'/events/<identifier>/relationships/organizers')
api.route(EventRelationship, 'event_coorganizers', '/events/<int:id>/relationships/coorganizers',
Expand Down
3 changes: 2 additions & 1 deletion app/api/admin_sales/organizer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from marshmallow_jsonapi import fields
from marshmallow_jsonapi.flask import Schema
from sqlalchemy import or_
from flask_rest_jsonapi import ResourceList

from app.api.helpers.utilities import dasherize
Expand Down Expand Up @@ -53,7 +54,7 @@ class AdminSalesByOrganizersList(ResourceList):

def query(self, _):
query_ = self.session.query(User)
query_ = query_.join(UsersEventsRoles).filter(Role.name == 'organizer')
query_ = query_.join(UsersEventsRoles).filter(or_(Role.name == 'organizer', Role.name == 'owner'))
query_ = query_.join(Event).outerjoin(Order).outerjoin(OrderTicket)

return query_
Expand Down
10 changes: 5 additions & 5 deletions app/api/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
from app.models.ticket_holder import TicketHolder
from app.models.track import Track
from app.models.user_favourite_event import UserFavouriteEvent
from app.models.user import User, ATTENDEE, ORGANIZER, COORGANIZER
from app.models.user import User, ATTENDEE, OWNER, ORGANIZER, COORGANIZER
from app.models.users_events_role import UsersEventsRoles
from app.models.stripe_authorization import StripeAuthorization

Expand Down Expand Up @@ -108,7 +108,7 @@ def query(self, view_kwargs):
_jwt_required(current_app.config['JWT_DEFAULT_REALM'])
query2 = self.session.query(Event)
query2 = query2.join(Event.roles).filter_by(user_id=current_identity.id).join(UsersEventsRoles.role). \
filter(or_(Role.name == COORGANIZER, Role.name == ORGANIZER))
filter(or_(Role.name == COORGANIZER, Role.name == ORGANIZER, Role.name == OWNER))
query_ = query_.union(query2)

if view_kwargs.get('user_id') and 'GET' in request.method:
Expand Down Expand Up @@ -154,19 +154,19 @@ def before_post(self, args, kwargs, data=None):

def after_create_object(self, event, data, view_kwargs):
"""
after create method to save roles for users and add the user as an accepted role(organizer)
after create method to save roles for users and add the user as an accepted role(owner and organizer)
:param event:
:param data:
:param view_kwargs:
:return:
"""
role = Role.query.filter_by(name=ORGANIZER).first()
user = User.query.filter_by(id=view_kwargs['user_id']).first()
role = Role.query.filter_by(name=OWNER).first()
uer = UsersEventsRoles(user, event, role)
save_to_db(uer, 'Event Saved')
role_invite = RoleInvite(user.email, role.title_name, event.id, role.id, datetime.now(pytz.utc),
status='accepted')
save_to_db(role_invite, 'Organiser Role Invite Added')
save_to_db(role_invite, 'Owner Role Invite Added')

# create custom forms for compulsory fields of attendee form.
create_custom_forms_for_attendees(event)
Expand Down
12 changes: 6 additions & 6 deletions app/api/full_text_search/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ def search(self, args, es_client=client):
search = search.query('fuzzy', location_name=args['location_name'])
search = search.highlight('location_name')

if args.get('organizer-name'):
if args.get('owner-name'):
search = search.query(
'fuzzy', organizer_name=args['organizer_name'])
search = search.highlight('organizer_name')
'fuzzy', owner_name=args['owner_name'])
search = search.highlight('owner_name')

if args.get('organizer-description'):
if args.get('owner-description'):
search = search.query(
'fuzzy', organizer_description=args['organizer_description'])
search = search.highlight('organizer_description')
'fuzzy', owner_description=args['owner_description'])
search = search.highlight('owner_description')

return [to_dict(r) for r in search.execute()]

Expand Down
4 changes: 2 additions & 2 deletions app/api/helpers/export_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
FIELD_ORDER = {
'event': [
'id', 'name', 'latitude', 'longitude', 'location_name', 'starts_at', 'ends_at',
'timezone', 'description', 'original_image_url', 'logo_url', 'organizer_name',
'organizer_description', 'external_event_url', 'ticket_url', 'privacy', 'event_type_id',
'timezone', 'description', 'original_image_url', 'logo_url', 'owner_name',
'owner_description', 'external_event_url', 'ticket_url', 'privacy', 'event_type_id',
'event_topic_id', 'event_sub_topic_id', 'code_of_conduct'
],
'microlocations': ['id', 'name', 'floor'],
Expand Down
4 changes: 2 additions & 2 deletions app/api/helpers/import_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from app.models.speaker import Speaker
from app.models.sponsor import Sponsor
from app.models.track import Track
from app.models.user import User, ORGANIZER
from app.models.user import User, OWNER

IMPORT_SERIES = [
('social_links', SocialLink),
Expand Down Expand Up @@ -356,7 +356,7 @@ def import_event_json(task_handle, zip_path, creator_id):
data = _delete_fields(srv, data)
new_event = Event(**data)
save_to_db(new_event)
role = Role.query.filter_by(name=ORGANIZER).first()
role = Role.query.filter_by(name=OWNER).first()
user = User.query.filter_by(id=creator_id).first()
uer = UsersEventsRoles(user_id=user.id, event_id=new_event.id, role_id=role.id)
save_to_db(uer, 'Event Saved')
Expand Down
10 changes: 10 additions & 0 deletions app/api/helpers/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,16 @@ def send_notif_ticket_cancel(order):
.format(identifier=order.event.identifier))
)
)
send_notification(
user=order.event.owner,
title=NOTIFS[TICKET_CANCELLED_ORGANIZER]['title'].format(
invoice_id=order.invoice_number
),
message=NOTIFS[TICKET_CANCELLED_ORGANIZER]['message'].format(
cancel_note=order.cancel_note,
invoice_id=order.invoice_number
)
)


def send_notification_with_action(user, action, **kwargs):
Expand Down
42 changes: 28 additions & 14 deletions app/api/helpers/permission_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,39 @@ def is_admin(view, view_args, view_kwargs, *args, **kwargs):


@jwt_required
def is_organizer(view, view_args, view_kwargs, *args, **kwargs):
def is_owner(view, view_args, view_kwargs, *args, **kwargs):
user = current_identity

if user.is_staff:
return view(*view_args, **view_kwargs)

if not user.is_organizer(kwargs['event_id']):
return ForbiddenError({'source': ''}, 'Organizer access is required').respond()
if not user.is_owner(kwargs['event_id']):
return ForbiddenError({'source': ''}, 'Owner access is required').respond()

return view(*view_args, **view_kwargs)


@jwt_required
def is_organizer(view, view_args, view_kwargs, *args, **kwargs):
user = current_identity

if user.is_staff:
return view(*view_args, **view_kwargs)

if user.is_owner(kwargs['event_id']) or user.is_organizer(kwargs['event_id']):
return view(*view_args, **view_kwargs)

return ForbiddenError({'source': ''}, 'Organizer access is required').respond()


@jwt_required
def is_coorganizer(view, view_args, view_kwargs, *args, **kwargs):
user = current_identity

if user.is_staff:
return view(*view_args, **view_kwargs)

if user.is_organizer(kwargs['event_id']) or user.is_coorganizer(kwargs['event_id']):
if user.has_event_access(kwargs['event_id']):
return view(*view_args, **view_kwargs)

return ForbiddenError({'source': ''}, 'Co-organizer access is required.').respond()
Expand All @@ -69,7 +82,7 @@ def is_coorganizer(view, view_args, view_kwargs, *args, **kwargs):
def is_coorganizer_but_not_admin(view, view_args, view_kwargs, *args, **kwargs):
user = current_identity

if user.is_organizer(kwargs['event_id']) or user.is_coorganizer(kwargs['event_id']):
if user.has_event_access(kwargs['event_id']):
return view(*view_args, **view_kwargs)

return ForbiddenError({'source': ''}, 'Co-organizer access is required.').respond()
Expand All @@ -94,7 +107,7 @@ def is_coorganizer_endpoint_related_to_event(view, view_args, view_kwargs, *args
_jwt_required(app.config['JWT_DEFAULT_REALM'])
return view(*view_args, **view_kwargs)

if user.is_organizer(kwargs['event_id']) or user.is_coorganizer(kwargs['event_id']):
if user.has_event_access(kwargs['event_id']):
_jwt_required(app.config['JWT_DEFAULT_REALM'])
return view(*view_args, **view_kwargs)

Expand Down Expand Up @@ -127,7 +140,7 @@ def is_coorganizer_or_user_itself(view, view_args, view_kwargs, *args, **kwargs)
if user.is_staff:
return view(*view_args, **view_kwargs)

if user.is_organizer(kwargs['event_id']) or user.is_coorganizer(kwargs['event_id']):
if user.has_event_access(kwargs['event_id']):
return view(*view_args, **view_kwargs)

return ForbiddenError({'source': ''}, 'Co-organizer access is required.').respond()
Expand All @@ -151,7 +164,7 @@ def is_speaker_for_session(view, view_args, view_kwargs, *args, **kwargs):
except NoResultFound:
return NotFoundError({'parameter': 'id'}, 'Session not found.').respond()

if user.is_organizer(session.event_id) or user.is_coorganizer(session.event_id):
if user.has_event_access(session.event_id):
return view(*view_args, **view_kwargs)

if session.speakers:
Expand All @@ -176,7 +189,7 @@ def is_speaker_itself_or_admin(view, view_args, view_kwargs, *args, **kwargs):
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']):
if user.has_event_access(kwargs['event_id']):
return view(*view_args, **view_kwargs)

if ('model' in kwargs) and (kwargs['model'] == Speaker):
Expand Down Expand Up @@ -205,7 +218,7 @@ def is_session_self_submitted(view, view_args, view_kwargs, *args, **kwargs):
except NoResultFound:
return NotFoundError({'parameter': 'session_id'}, 'Session not found.').respond()

if user.is_organizer(session.event_id) or user.is_coorganizer(session.event_id):
if user.has_event_access(session.event_id):
return view(*view_args, **view_kwargs)

if session.creator_id == user.id:
Expand All @@ -224,7 +237,7 @@ def is_registrar(view, view_args, view_kwargs, *args, **kwargs):

if user.is_staff:
return view(*view_args, **view_kwargs)
if user.is_registrar(event_id) or user.is_organizer(event_id) or user.is_coorganizer(event_id):
if user.is_registrar(event_id) or user.has_event_access(event_id):
return view(*view_args, **view_kwargs)
return ForbiddenError({'source': ''}, 'Registrar Access is Required.').respond()

Expand All @@ -243,7 +256,7 @@ def is_registrar_or_user_itself(view, view_args, view_kwargs, *args, **kwargs):
return view(*view_args, **view_kwargs)

event_id = kwargs['event_id']
if user.is_registrar(event_id) or user.is_organizer(event_id) or user.is_coorganizer(event_id):
if user.is_registrar(event_id) or user.has_event_access(event_id):
return view(*view_args, **view_kwargs)

return ForbiddenError({'source': ''}, 'Registrar access is required.').respond()
Expand All @@ -259,7 +272,7 @@ def is_track_organizer(view, view_args, view_kwargs, *args, **kwargs):

if user.is_staff:
return view(*view_args, **view_kwargs)
if user.is_track_organizer(event_id) or user.is_organizer(event_id) or user.is_coorganizer(event_id):
if user.is_track_organizer(event_id) or user.has_event_access(event_id):
return view(*view_args, **view_kwargs)
return ForbiddenError({'source': ''}, 'Track Organizer access is Required.').respond()

Expand All @@ -273,7 +286,7 @@ def is_moderator(view, view_args, view_kwargs, *args, **kwargs):
event_id = kwargs['event_id']
if user.is_staff:
return view(*view_args, **view_kwargs)
if user.is_moderator(event_id) or user.is_organizer(event_id) or user.is_coorganizer(event_id):
if user.is_moderator(event_id) or user.has_event_access(event_id):
return view_kwargs(*view_args, **view_kwargs)
return ForbiddenError({'source': ''}, 'Moderator Access is Required.').respond()

Expand Down Expand Up @@ -315,6 +328,7 @@ def create_event(view, view_args, view_kwargs, *args, **kwargs):
permissions = {
'is_super_admin': is_super_admin,
'is_admin': is_admin,
'is_owner': is_owner,
'is_organizer': is_organizer,
'is_coorganizer': is_coorganizer,
'is_track_organizer': is_track_organizer,
Expand Down
34 changes: 25 additions & 9 deletions app/api/helpers/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,27 @@ def decorated_function(*args, **kwargs):
return decorated_function


@second_order_decorator(jwt_required)
def is_owner(f):
"""
Allows only Owner to access the event resources.
:param f:
:return:
"""

@wraps(f)
def decorated_function(*args, **kwargs):
user = current_identity

if user.is_staff:
return f(*args, **kwargs)
if 'event_id' in kwargs and user.is_owner(kwargs['event_id']):
return f(*args, **kwargs)
return ForbiddenError({'source': ''}, 'Owner access is required').respond()

return decorated_function


@second_order_decorator(jwt_required)
def is_organizer(f):
"""
Expand Down Expand Up @@ -138,9 +159,7 @@ def decorated_function(*args, **kwargs):

if user.is_staff:
return f(*args, **kwargs)
if 'event_id' in kwargs and (
user.is_coorganizer(kwargs['event_id']) or
user.is_organizer(kwargs['event_id'])):
if 'event_id' in kwargs and user.has_event_access(kwargs['event_id']):
return f(*args, **kwargs)
return ForbiddenError({'source': ''}, 'Co-organizer access is required.').respond()

Expand All @@ -163,8 +182,7 @@ def decorated_function(*args, **kwargs):
return f(*args, **kwargs)
if 'event_id' in kwargs and (
user.is_registrar(kwargs['event_id']) or
user.is_organizer(kwargs['event_id']) or
user.is_coorganizer(kwargs['event_id'])):
user.has_event_access(kwargs['event_id'])):
return f(*args, **kwargs)
return ForbiddenError({'source': ''}, 'Registrar Access is Required.').respond()

Expand All @@ -187,8 +205,7 @@ def decorated_function(*args, **kwargs):
return f(*args, **kwargs)
if 'event_id' in kwargs and (
user.is_track_organizer(kwargs['event_id']) or
user.is_organizer(kwargs['event_id']) or
user.is_coorganizer(kwargs['event_id'])):
user.has_event_access(kwargs['event_id'])):
return f(*args, **kwargs)
return ForbiddenError({'source': ''}, 'Track Organizer access is Required.').respond()

Expand All @@ -211,8 +228,7 @@ def decorated_function(*args, **kwargs):
return f(*args, **kwargs)
if 'event_id' in kwargs and (
user.is_moderator(kwargs['event_id']) or
user.is_organizer(kwargs['event_id']) or
user.is_coorganizer(kwargs['event_id'])):
user.has_event_access(kwargs['event_id'])):
return f(*args, **kwargs)
return ForbiddenError({'source': ''}, 'Moderator Access is Required.').respond()

Expand Down
8 changes: 6 additions & 2 deletions app/api/helpers/scheduled_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def send_after_event_mail():
for event in events:
organizers = get_user_event_roles_by_role_name(event.id, 'organizer')
speakers = Speaker.query.filter_by(event_id=event.id, deleted_at=None).all()
owner = get_user_event_roles_by_role_name(event.id, 'owner').first()
current_time = datetime.datetime.now(pytz.timezone(event.timezone))
time_difference = current_time - event.ends_at
time_difference_minutes = (time_difference.days * 24 * 60) + \
Expand All @@ -46,6 +47,9 @@ def send_after_event_mail():
for organizer in organizers:
send_email_after_event(organizer.user.email, event.name, upcoming_event_links)
send_notif_after_event(organizer.user, event.name)
if owner:
send_email_after_event(owner.user.email, event.name, upcoming_event_links)
send_notif_after_event(owner.user, event.name)


def change_session_state_on_event_completion():
Expand Down Expand Up @@ -84,9 +88,9 @@ def send_event_fee_notification():
fee_total += fee

if fee_total > 0:
organizer = get_user_event_roles_by_role_name(event.id, 'organizer').first()
owner = get_user_event_roles_by_role_name(event.id, 'owner').first()
new_invoice = EventInvoice(
amount=fee_total, event_id=event.id, user_id=organizer.user.id)
amount=fee_total, event_id=event.id, user_id=owner.user.id)

if event.discount_code_id and event.discount_code:
r = relativedelta(datetime.utcnow(), event.created_at)
Expand Down
Loading