forked from fossasia/open-event-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathspeakers.py
More file actions
289 lines (254 loc) · 9.45 KB
/
speakers.py
File metadata and controls
289 lines (254 loc) · 9.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
from flask_jwt_extended import current_user
from flask_rest_jsonapi import ResourceDetail, ResourceList, ResourceRelationship
from flask_rest_jsonapi.exceptions import ObjectNotFound
from app.api.bootstrap import api
from app.api.helpers.custom_forms import validate_custom_form_constraints_request
from app.api.helpers.db import get_count, safe_query_kwargs, save_to_db
from app.api.helpers.errors import ForbiddenError
from app.api.helpers.permission_manager import has_access, is_logged_in
from app.api.helpers.permissions import jwt_required
from app.api.helpers.query import event_query
from app.api.helpers.speaker import can_edit_after_cfs_ends
from app.api.helpers.utilities import require_relationship
from app.api.schema.speakers import SpeakerSchema
from app.models import db
from app.models.event import Event
from app.models.session import Session
from app.models.session_speaker_link import SessionsSpeakersLink
from app.models.speaker import Speaker
from app.models.user import User
class SpeakerListPost(ResourceList):
"""
List and create speakers
"""
def before_post(self, args, kwargs, data=None):
"""
method to add user_id to view_kwargs before post
:param args:
:param kwargs:
:param data:
:return:
"""
data['user'] = current_user.id
require_relationship(['event', 'user'], data)
if not has_access('is_coorganizer', event_id=data['event']):
event = db.session.query(Event).filter_by(id=data['event']).one()
if event.state == "draft":
raise ObjectNotFound(
{'parameter': 'event_id'},
"Event: {} not found".format(data['event']),
)
if (
get_count(
db.session.query(Event).filter_by(
id=int(data['event']), is_sessions_speakers_enabled=False
)
)
> 0
):
raise ForbiddenError({'pointer': ''}, "Speakers are disabled for this Event")
if (
not data.get('is_email_overridden')
and get_count(
db.session.query(Speaker).filter_by(
event_id=int(data['event']), email=data['email'], deleted_at=None
)
)
> 0
):
raise ForbiddenError(
{'pointer': ''}, 'Speaker with this Email ID already exists'
)
is_organizer = has_access('is_organizer', event_id=data['event'])
if data.get('is_email_overridden') and not is_organizer:
raise ForbiddenError(
{'pointer': 'data/attributes/is_email_overridden'},
'Organizer access required to override email',
)
if not data.get('is_email_overridden') and is_organizer and not data.get('email'):
data['email'] = current_user.email
if not is_organizer and not data.get('email'):
raise ForbiddenError(
{'pointer': '/data/email'}, 'Email is required for speaker'
)
if 'sessions' in data:
session_ids = data['sessions']
for session_id in session_ids:
if not has_access('is_session_self_submitted', session_id=session_id):
raise ObjectNotFound(
{'parameter': 'session_id'},
f"Session: {session_id} not found",
)
data['complex_field_values'] = validate_custom_form_constraints_request(
'speaker', self.schema, Speaker(event_id=data['event']), data
)
def after_create_object(self, speaker, data, view_kwargs):
"""
after create method to save resized images for speaker
:param speaker:
:param data:
:param view_kwargs:
:return:
"""
if data.get('photo_url'):
start_image_resizing_tasks(speaker, data['photo_url'])
schema = SpeakerSchema
decorators = (jwt_required,)
methods = [
'POST',
]
data_layer = {
'session': db.session,
'model': Speaker,
'methods': {'after_create_object': after_create_object},
}
class SpeakerList(ResourceList):
"""
List speakers based on different params from view_kwargs
"""
def query(self, view_kwargs):
"""
query method for speakers list class
:param view_kwargs:
:return:
"""
query_ = self.session.query(Speaker)
query_ = event_query(query_, view_kwargs)
if view_kwargs.get('user_id'):
user = safe_query_kwargs(User, view_kwargs, 'user_id')
query_ = query_.join(User).filter(User.id == user.id)
if view_kwargs.get('session_id'):
session = safe_query_kwargs(Session, view_kwargs, 'session_id')
# session-speaker :: many-to-many relationship
query_ = Speaker.query.filter(Speaker.sessions.any(id=session.id))
if is_logged_in() and not has_access(
'is_coorganizer', event_id=session.event_id
):
if not has_access('is_session_self_submitted', session_id=session.id):
query_ = query_.filter(
Session.state == "approved" or Session.state == "accepted"
)
return query_
view_kwargs = True
schema = SpeakerSchema
methods = [
'GET',
]
data_layer = {
'session': db.session,
'model': Speaker,
'methods': {
'query': query,
},
}
class SpeakerDetail(ResourceDetail):
"""
Speakers Detail by id
"""
def before_update_object(self, speaker, data, view_kwargs):
"""
method to save image urls before updating speaker object
:param speaker:
:param data:
:param view_kwargs:
:return:
"""
if not can_edit_after_cfs_ends(speaker.event_id):
raise ForbiddenError(
{'source': ''}, "Cannot edit speaker after the call for speaker is ended"
)
if data.get('photo_url') and data['photo_url'] != speaker.photo_url:
start_image_resizing_tasks(speaker, data['photo_url'])
if data.get('is_email_overridden') and not has_access(
'is_organizer', event_id=speaker.event_id
):
raise ForbiddenError(
{'pointer': 'data/attributes/is_email_overridden'},
'Organizer access required to override email',
)
if (
data.get('is_email_overridden')
and has_access('is_organizer', event_id=speaker.event_id)
and not data.get('email')
):
data['email'] = current_user.email
data['complex_field_values'] = validate_custom_form_constraints_request(
'speaker', self.resource.schema, speaker, data
)
def after_patch(self, result):
"""
method to create session speaker link
:param result:
"""
# This method is executed when a new speaker is created
# and added to an existing session
speaker_id = result['data']['id']
speaker = Speaker.query.filter_by(id=speaker_id).first()
if SessionsSpeakersLink.query.filter_by(speaker_id=speaker_id).count() == 0:
all_sessions = Session.query.filter_by(deleted_at=None)
for session in all_sessions:
if speaker in session.speakers:
session_speaker_link = SessionsSpeakersLink(
session_state=session.state,
session_id=session.id,
event_id=session.event.id,
speaker_id=speaker.id,
)
save_to_db(session_speaker_link, "Session Speaker Link Saved")
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,
'model': Speaker,
'methods': {'before_update_object': before_update_object},
}
class SpeakerRelationshipRequired(ResourceRelationship):
"""
Speaker Relationship class for required entities
"""
decorators = (
api.has_permission(
'is_coorganizer_or_user_itself',
methods="PATCH,DELETE",
fetch="event_id",
fetch_as="event_id",
model=Speaker,
),
)
methods = ['GET', 'PATCH']
schema = SpeakerSchema
data_layer = {'session': db.session, 'model': Speaker}
class SpeakerRelationshipOptional(ResourceRelationship):
"""
Speaker Relationship class
"""
decorators = (
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, 'model': Speaker}
def start_image_resizing_tasks(speaker, photo_url):
speaker_id = str(speaker.id)
from .helpers.tasks import resize_speaker_images_task
resize_speaker_images_task.delay(speaker_id, photo_url)