zou 0.19.15__py3-none-any.whl → 0.20.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zou/__init__.py +1 -1
- zou/app/__init__.py +10 -2
- zou/app/api.py +2 -0
- zou/app/blueprints/assets/__init__.py +22 -0
- zou/app/blueprints/assets/resources.py +241 -4
- zou/app/blueprints/auth/__init__.py +4 -0
- zou/app/blueprints/auth/resources.py +154 -22
- zou/app/blueprints/breakdown/resources.py +4 -4
- zou/app/blueprints/chats/__init__.py +22 -0
- zou/app/blueprints/chats/resources.py +199 -0
- zou/app/blueprints/comments/resources.py +36 -19
- zou/app/blueprints/crud/__init__.py +12 -0
- zou/app/blueprints/crud/attachment_file.py +14 -5
- zou/app/blueprints/crud/base.py +29 -28
- zou/app/blueprints/crud/chat.py +13 -0
- zou/app/blueprints/crud/chat_message.py +13 -0
- zou/app/blueprints/crud/comments.py +85 -29
- zou/app/blueprints/crud/custom_action.py +1 -1
- zou/app/blueprints/crud/day_off.py +47 -9
- zou/app/blueprints/crud/department.py +1 -25
- zou/app/blueprints/crud/entity.py +46 -5
- zou/app/blueprints/crud/entity_type.py +13 -1
- zou/app/blueprints/crud/event.py +1 -1
- zou/app/blueprints/crud/file_status.py +1 -1
- zou/app/blueprints/crud/metadata_descriptor.py +24 -10
- zou/app/blueprints/crud/organisation.py +22 -5
- zou/app/blueprints/crud/output_file.py +1 -1
- zou/app/blueprints/crud/output_type.py +1 -1
- zou/app/blueprints/crud/person.py +32 -24
- zou/app/blueprints/crud/playlist.py +1 -1
- zou/app/blueprints/crud/preview_background_file.py +6 -7
- zou/app/blueprints/crud/preview_file.py +1 -1
- zou/app/blueprints/crud/project.py +14 -6
- zou/app/blueprints/crud/project_status.py +1 -1
- zou/app/blueprints/crud/schedule_item.py +4 -2
- zou/app/blueprints/crud/software.py +1 -1
- zou/app/blueprints/crud/status_automation.py +1 -1
- zou/app/blueprints/crud/studio.py +33 -0
- zou/app/blueprints/crud/task.py +47 -3
- zou/app/blueprints/crud/task_status.py +1 -1
- zou/app/blueprints/crud/task_type.py +4 -4
- zou/app/blueprints/crud/working_file.py +4 -8
- zou/app/blueprints/events/resources.py +13 -12
- zou/app/blueprints/export/csv/assets.py +15 -6
- zou/app/blueprints/export/csv/edits.py +15 -5
- zou/app/blueprints/export/csv/playlists.py +1 -1
- zou/app/blueprints/export/csv/shots.py +15 -5
- zou/app/blueprints/export/csv/time_spents.py +1 -1
- zou/app/blueprints/files/resources.py +22 -23
- zou/app/blueprints/index/resources.py +38 -29
- zou/app/blueprints/news/resources.py +25 -11
- zou/app/blueprints/persons/__init__.py +5 -2
- zou/app/blueprints/persons/resources.py +126 -120
- zou/app/blueprints/previews/__init__.py +18 -8
- zou/app/blueprints/previews/resources.py +569 -328
- zou/app/blueprints/projects/resources.py +1 -1
- zou/app/blueprints/search/resources.py +18 -6
- zou/app/blueprints/shots/__init__.py +5 -0
- zou/app/blueprints/shots/resources.py +134 -4
- zou/app/blueprints/source/__init__.py +6 -6
- zou/app/blueprints/source/csv/assets.py +10 -3
- zou/app/blueprints/source/csv/base.py +1 -1
- zou/app/blueprints/source/csv/edits.py +10 -3
- zou/app/blueprints/source/csv/shots.py +10 -3
- zou/app/blueprints/source/{edl.py → otio.py} +82 -41
- zou/app/blueprints/tasks/__init__.py +3 -2
- zou/app/blueprints/tasks/resources.py +83 -52
- zou/app/blueprints/user/__init__.py +9 -0
- zou/app/blueprints/user/resources.py +170 -12
- zou/app/config.py +10 -0
- zou/app/mixin.py +6 -5
- zou/app/models/attachment_file.py +10 -4
- zou/app/models/base.py +18 -13
- zou/app/models/build_job.py +7 -4
- zou/app/models/chat.py +44 -0
- zou/app/models/chat_message.py +37 -0
- zou/app/models/comment.py +1 -0
- zou/app/models/day_off.py +3 -0
- zou/app/models/entity.py +4 -6
- zou/app/models/entity_type.py +2 -0
- zou/app/models/organisation.py +14 -15
- zou/app/models/person.py +6 -1
- zou/app/models/project.py +3 -0
- zou/app/models/search_filter.py +11 -0
- zou/app/models/search_filter_group.py +10 -0
- zou/app/models/serializer.py +17 -17
- zou/app/models/status_automation.py +2 -0
- zou/app/models/studio.py +13 -0
- zou/app/models/subscription.py +2 -2
- zou/app/models/task.py +6 -1
- zou/app/models/task_status.py +1 -0
- zou/app/models/task_type.py +1 -0
- zou/app/models/working_file.py +1 -1
- zou/app/services/assets_service.py +101 -14
- zou/app/services/auth_service.py +17 -44
- zou/app/services/breakdown_service.py +37 -5
- zou/app/services/chats_service.py +279 -0
- zou/app/services/comments_service.py +110 -65
- zou/app/services/concepts_service.py +4 -12
- zou/app/services/deletion_service.py +43 -30
- zou/app/services/edits_service.py +5 -11
- zou/app/services/emails_service.py +4 -4
- zou/app/services/entities_service.py +17 -2
- zou/app/services/events_service.py +12 -4
- zou/app/services/exception.py +5 -5
- zou/app/services/names_service.py +7 -2
- zou/app/services/news_service.py +17 -9
- zou/app/services/persons_service.py +38 -21
- zou/app/services/playlists_service.py +8 -7
- zou/app/services/preview_files_service.py +137 -10
- zou/app/services/projects_service.py +5 -14
- zou/app/services/shots_service.py +221 -49
- zou/app/services/sync_service.py +46 -42
- zou/app/services/tasks_service.py +185 -46
- zou/app/services/time_spents_service.py +67 -20
- zou/app/services/user_service.py +350 -107
- zou/app/stores/auth_tokens_store.py +2 -1
- zou/app/stores/file_store.py +18 -0
- zou/app/stores/publisher_store.py +7 -7
- zou/app/stores/queue_store.py +1 -0
- zou/app/swagger.py +36 -20
- zou/app/utils/cache.py +2 -0
- zou/app/utils/commands.py +104 -7
- zou/app/utils/csv_utils.py +1 -4
- zou/app/utils/date_helpers.py +33 -17
- zou/app/utils/dbhelpers.py +14 -1
- zou/app/utils/emails.py +2 -2
- zou/app/utils/fido.py +22 -0
- zou/app/utils/query.py +54 -6
- zou/app/utils/redis.py +11 -0
- zou/app/utils/saml.py +51 -0
- zou/app/utils/string.py +2 -0
- zou/app/utils/thumbnail.py +4 -2
- zou/cli.py +76 -18
- zou/debug.py +4 -2
- zou/event_stream.py +122 -165
- zou/job_settings.py +1 -0
- zou/migrations/env.py +0 -0
- zou/migrations/utils/base.py +6 -6
- zou/migrations/versions/1bb55759146f_add_table_studio.py +67 -0
- zou/migrations/versions/1fab8c420678_add_attachments_to_message_chats.py +56 -0
- zou/migrations/versions/23122f290ca2_add_entity_chat_models.py +149 -0
- zou/migrations/versions/32f134ff1201_add_is_shared_flag_to_filters.py +33 -0
- zou/migrations/versions/57222395f2be_add_statusautomation_import_last_revision.py +41 -0
- zou/migrations/versions/59a7445a966c_add_entity_is_shared.py +41 -0
- zou/migrations/versions/5b980f0dc365_add_comment_links.py +35 -0
- zou/migrations/versions/680c64565f9d_for_searchfiltergroup_is_shared.py +35 -0
- zou/migrations/versions/8e67c183bed7_add_preference_fields.py +71 -0
- zou/migrations/versions/92b40d79ad3f_allow_message_attachments.py +38 -0
- zou/migrations/versions/971dbf5a0faf_add_short_name_for_asset_type_entity_.py +33 -0
- zou/migrations/versions/9b85c14fa8a7_add_day_off_new_columns.py +68 -0
- zou/migrations/versions/9d3bb33c6fc6_add_department_keys_to_filter_models.py +73 -0
- zou/migrations/versions/a252a094e977_add_descriptions_for_entities_tasks_and_.py +40 -0
- zou/migrations/versions/be56dc0fb760_for_is_shared_disallow_nullable.py +102 -0
- zou/migrations/versions/ca28796a2a62_add_is_done_field_to_the_task_model.py +108 -0
- zou/migrations/versions/f344b867a911_for_description_of_entity_task_working_.py +75 -0
- zou/remote/config_payload.py +2 -1
- zou/utils/movie.py +14 -4
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/METADATA +75 -69
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/RECORD +163 -134
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/WHEEL +1 -1
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/LICENSE +0 -0
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/entry_points.txt +0 -0
- {zou-0.19.15.dist-info → zou-0.20.11.dist-info}/top_level.txt +0 -0
zou/app/models/working_file.py
CHANGED
|
@@ -17,7 +17,7 @@ class WorkingFile(db.Model, BaseMixin, SerializerMixin):
|
|
|
17
17
|
shotgun_id = db.Column(db.Integer(), index=True)
|
|
18
18
|
|
|
19
19
|
name = db.Column(db.String(250))
|
|
20
|
-
description = db.Column(db.
|
|
20
|
+
description = db.Column(db.Text())
|
|
21
21
|
comment = db.Column(db.Text())
|
|
22
22
|
revision = db.Column(db.Integer())
|
|
23
23
|
size = db.Column(db.Integer())
|
|
@@ -40,7 +40,7 @@ from zou.app.services.exception import (
|
|
|
40
40
|
|
|
41
41
|
def clear_asset_cache(asset_id):
|
|
42
42
|
cache.cache.delete_memoized(get_asset, asset_id)
|
|
43
|
-
cache.cache.delete_memoized(
|
|
43
|
+
cache.cache.delete_memoized(get_asset, asset_id, True)
|
|
44
44
|
cache.cache.delete_memoized(get_full_asset, asset_id)
|
|
45
45
|
|
|
46
46
|
|
|
@@ -84,7 +84,7 @@ def build_entity_type_asset_type_filter():
|
|
|
84
84
|
return ~EntityType.id.in_(ids_to_exclude)
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
def get_assets(criterions={}):
|
|
87
|
+
def get_assets(criterions={}, is_admin=False):
|
|
88
88
|
"""
|
|
89
89
|
Get all assets for given criterions.
|
|
90
90
|
"""
|
|
@@ -102,6 +102,12 @@ def get_assets(criterions={}):
|
|
|
102
102
|
query = query.outerjoin(Task)
|
|
103
103
|
query = query.filter(user_service.build_assignee_filter())
|
|
104
104
|
|
|
105
|
+
if "is_shared" in criterions:
|
|
106
|
+
if not is_admin:
|
|
107
|
+
query = query.join(Project).filter(
|
|
108
|
+
user_service.build_team_filter()
|
|
109
|
+
)
|
|
110
|
+
|
|
105
111
|
if episode_id is not None:
|
|
106
112
|
# Filter based on main episode.
|
|
107
113
|
query = query.filter(Entity.source_id == episode_id)
|
|
@@ -121,7 +127,7 @@ def get_assets(criterions={}):
|
|
|
121
127
|
result += [a for a in query.all() if a.source_id != episode_id]
|
|
122
128
|
else:
|
|
123
129
|
result = query.all()
|
|
124
|
-
return
|
|
130
|
+
return Entity.serialize_list(result, obj_type="Asset")
|
|
125
131
|
|
|
126
132
|
|
|
127
133
|
def get_all_raw_assets():
|
|
@@ -194,7 +200,9 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
|
|
|
194
200
|
Task.end_date,
|
|
195
201
|
Task.start_date,
|
|
196
202
|
Task.due_date,
|
|
203
|
+
Task.done_date,
|
|
197
204
|
Task.last_comment_date,
|
|
205
|
+
Task.difficulty,
|
|
198
206
|
assignees_table.columns.person,
|
|
199
207
|
).order_by(EntityType.name, Entity.name)
|
|
200
208
|
|
|
@@ -240,6 +248,18 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
|
|
|
240
248
|
episode_links_query = episode_links_query.filter(
|
|
241
249
|
Episode.project_id == criterions["project_id"]
|
|
242
250
|
)
|
|
251
|
+
if "episode_id" in criterions and criterions["episode_id"] not in [
|
|
252
|
+
"main",
|
|
253
|
+
"all",
|
|
254
|
+
]:
|
|
255
|
+
episode_links_query = episode_links_query.filter(
|
|
256
|
+
EntityLink.entity_in_id == criterions["episode_id"]
|
|
257
|
+
)
|
|
258
|
+
if "id" in criterions:
|
|
259
|
+
episode_links_query = episode_links_query.filter(
|
|
260
|
+
EntityLink.entity_out_id == criterions["id"]
|
|
261
|
+
)
|
|
262
|
+
|
|
243
263
|
for link in episode_links_query.all():
|
|
244
264
|
if str(link.entity_out_id) not in cast_in_episode_ids:
|
|
245
265
|
cast_in_episode_ids[str(link.entity_out_id)] = []
|
|
@@ -272,7 +292,9 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
|
|
|
272
292
|
task_end_date,
|
|
273
293
|
task_start_date,
|
|
274
294
|
task_due_date,
|
|
295
|
+
task_done_date,
|
|
275
296
|
task_last_comment_date,
|
|
297
|
+
task_difficulty,
|
|
276
298
|
person_id,
|
|
277
299
|
) in query_result:
|
|
278
300
|
if asset.source_id is None:
|
|
@@ -304,6 +326,7 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
|
|
|
304
326
|
"episode_id": source_id,
|
|
305
327
|
"casting_episode_ids": cast_in_episode_ids.get(asset_id, []),
|
|
306
328
|
"is_casting_standby": asset.is_casting_standby,
|
|
329
|
+
"is_shared": asset.is_shared,
|
|
307
330
|
"data": data,
|
|
308
331
|
"tasks": [],
|
|
309
332
|
}
|
|
@@ -314,6 +337,7 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
|
|
|
314
337
|
task_dict = {
|
|
315
338
|
"id": task_id,
|
|
316
339
|
"due_date": fields.serialize_value(task_due_date),
|
|
340
|
+
"done_date": fields.serialize_value(task_done_date),
|
|
317
341
|
"duration": task_duration,
|
|
318
342
|
"entity_id": asset_id,
|
|
319
343
|
"estimation": task_estimation,
|
|
@@ -328,6 +352,7 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
|
|
|
328
352
|
),
|
|
329
353
|
"retake_count": task_retake_count,
|
|
330
354
|
"start_date": fields.serialize_value(task_start_date),
|
|
355
|
+
"difficulty": task_difficulty,
|
|
331
356
|
"task_status_id": str(task_status_id),
|
|
332
357
|
"task_type_id": str(task_type_id),
|
|
333
358
|
"assignees": [],
|
|
@@ -403,19 +428,13 @@ def get_asset_raw(entity_id):
|
|
|
403
428
|
|
|
404
429
|
|
|
405
430
|
@cache.memoize_function(120)
|
|
406
|
-
def get_asset(entity_id):
|
|
407
|
-
"""
|
|
408
|
-
Return a given asset as a dict.
|
|
409
|
-
"""
|
|
410
|
-
return get_asset_raw(entity_id).serialize(obj_type="Asset")
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
@cache.memoize_function(120)
|
|
414
|
-
def get_asset_with_relations(entity_id):
|
|
431
|
+
def get_asset(entity_id, relations=False):
|
|
415
432
|
"""
|
|
416
433
|
Return a given asset as a dict.
|
|
417
434
|
"""
|
|
418
|
-
return get_asset_raw(entity_id).serialize(
|
|
435
|
+
return get_asset_raw(entity_id).serialize(
|
|
436
|
+
obj_type="Asset", relations=relations
|
|
437
|
+
)
|
|
419
438
|
|
|
420
439
|
|
|
421
440
|
def get_asset_by_shotgun_id(shotgun_id):
|
|
@@ -445,7 +464,7 @@ def get_full_asset(asset_id):
|
|
|
445
464
|
"""
|
|
446
465
|
assets = get_assets_and_tasks({"id": asset_id}, with_episode_ids=True)
|
|
447
466
|
if len(assets) > 0:
|
|
448
|
-
asset =
|
|
467
|
+
asset = get_asset(asset_id, relations=True)
|
|
449
468
|
asset_type_id = asset["entity_type_id"]
|
|
450
469
|
asset_type = get_asset_type(asset_type_id)
|
|
451
470
|
project = Project.get(asset["project_id"])
|
|
@@ -568,6 +587,7 @@ def create_asset(
|
|
|
568
587
|
name,
|
|
569
588
|
description,
|
|
570
589
|
data,
|
|
590
|
+
is_shared=False,
|
|
571
591
|
source_id=None,
|
|
572
592
|
created_by=None,
|
|
573
593
|
):
|
|
@@ -584,6 +604,7 @@ def create_asset(
|
|
|
584
604
|
name=name,
|
|
585
605
|
description=description,
|
|
586
606
|
data=data,
|
|
607
|
+
is_shared=is_shared,
|
|
587
608
|
source_id=source_id,
|
|
588
609
|
created_by=created_by,
|
|
589
610
|
)
|
|
@@ -703,3 +724,69 @@ def cancel_asset(asset_id, force=True):
|
|
|
703
724
|
project_id=str(asset.project_id),
|
|
704
725
|
)
|
|
705
726
|
return asset_dict
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
def set_shared_assets(
|
|
730
|
+
is_shared=True,
|
|
731
|
+
project_id=None,
|
|
732
|
+
asset_type_id=None,
|
|
733
|
+
asset_ids=None,
|
|
734
|
+
with_events=False,
|
|
735
|
+
):
|
|
736
|
+
"""
|
|
737
|
+
Set all assets of a project to is_shared=True or False.
|
|
738
|
+
"""
|
|
739
|
+
|
|
740
|
+
query = Entity.query.filter(build_asset_type_filter()).filter()
|
|
741
|
+
|
|
742
|
+
if project_id is not None:
|
|
743
|
+
query = query.filter(Entity.project_id == project_id)
|
|
744
|
+
|
|
745
|
+
if asset_type_id is not None:
|
|
746
|
+
query = query.filter(Entity.entity_type_id == asset_type_id)
|
|
747
|
+
|
|
748
|
+
if asset_ids is not None:
|
|
749
|
+
query = query.filter(Entity.id.in_(asset_ids))
|
|
750
|
+
|
|
751
|
+
assets = query.all()
|
|
752
|
+
|
|
753
|
+
for asset in assets:
|
|
754
|
+
asset.update_no_commit({"is_shared": is_shared})
|
|
755
|
+
|
|
756
|
+
Entity.commit()
|
|
757
|
+
|
|
758
|
+
for asset in assets:
|
|
759
|
+
asset_id = str(asset.id)
|
|
760
|
+
clear_asset_cache(asset_id)
|
|
761
|
+
if with_events:
|
|
762
|
+
events.emit(
|
|
763
|
+
"asset:update",
|
|
764
|
+
{"asset_id": asset_id},
|
|
765
|
+
project_id=project_id,
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
return Entity.serialize_list(assets, obj_type="Asset")
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
def get_shared_assets_used_in_project(project_id, episode_id=None):
|
|
772
|
+
"""
|
|
773
|
+
Get all shared assets used in a project.
|
|
774
|
+
"""
|
|
775
|
+
Shot = aliased(Entity, name="shot")
|
|
776
|
+
Sequence = aliased(Entity, name="sequence")
|
|
777
|
+
|
|
778
|
+
assets = (
|
|
779
|
+
Entity.query.filter(build_asset_type_filter())
|
|
780
|
+
.filter(Entity.is_shared == True)
|
|
781
|
+
.join(EntityLink, EntityLink.entity_out_id == Entity.id)
|
|
782
|
+
.join(Shot, EntityLink.entity_in_id == Shot.id)
|
|
783
|
+
.join(Sequence, Shot.parent_id == Sequence.id)
|
|
784
|
+
.filter(Shot.project_id == project_id)
|
|
785
|
+
.filter(Entity.canceled != True)
|
|
786
|
+
.filter(Entity.project_id != project_id)
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
if episode_id is not None and episode_id not in ["main", "all"]:
|
|
790
|
+
assets = assets.filter(Sequence.parent_id == episode_id)
|
|
791
|
+
|
|
792
|
+
return Entity.serialize_list(assets.all(), obj_type="Asset")
|
zou/app/services/auth_service.py
CHANGED
|
@@ -2,13 +2,12 @@ import pyotp
|
|
|
2
2
|
import random
|
|
3
3
|
import string
|
|
4
4
|
import flask_bcrypt
|
|
5
|
-
|
|
6
|
-
from datetime import
|
|
5
|
+
|
|
6
|
+
from datetime import timedelta
|
|
7
7
|
|
|
8
8
|
from flask import request, session, current_app
|
|
9
9
|
from babel.dates import format_datetime
|
|
10
10
|
|
|
11
|
-
from flask_jwt_extended import get_jti
|
|
12
11
|
from ldap3 import Server, Connection, ALL, NTLM, SIMPLE
|
|
13
12
|
from ldap3.core.exceptions import (
|
|
14
13
|
LDAPSocketOpenError,
|
|
@@ -37,29 +36,15 @@ from zou.app.services.exception import (
|
|
|
37
36
|
)
|
|
38
37
|
from zou.app.stores import auth_tokens_store
|
|
39
38
|
from zou.app.utils import date_helpers, emails
|
|
40
|
-
from zou.app import config
|
|
41
39
|
|
|
42
40
|
from fido2.webauthn import (
|
|
43
|
-
PublicKeyCredentialRpEntity,
|
|
44
41
|
PublicKeyCredentialUserEntity,
|
|
45
42
|
)
|
|
46
|
-
from fido2.server import Fido2Server
|
|
47
43
|
from sqlalchemy.orm.attributes import flag_modified
|
|
48
|
-
|
|
44
|
+
|
|
49
45
|
from fido2.utils import bytes2int, int2bytes
|
|
50
46
|
from fido2.webauthn import AttestedCredentialData
|
|
51
47
|
|
|
52
|
-
fido2.features.webauthn_json_mapping.enabled = True
|
|
53
|
-
|
|
54
|
-
fido_server = Fido2Server(
|
|
55
|
-
PublicKeyCredentialRpEntity(
|
|
56
|
-
name="Kitsu", id=urlparse(f"https://{config.DOMAIN_NAME}").hostname
|
|
57
|
-
),
|
|
58
|
-
verify_origin=(
|
|
59
|
-
None if config.DOMAIN_NAME != "localhost:8080" else lambda a: True
|
|
60
|
-
),
|
|
61
|
-
)
|
|
62
|
-
|
|
63
48
|
|
|
64
49
|
def check_auth(
|
|
65
50
|
app,
|
|
@@ -103,7 +88,9 @@ def check_auth(
|
|
|
103
88
|
raise NoAuthStrategyConfigured()
|
|
104
89
|
except WrongPasswordException:
|
|
105
90
|
update_login_failed_attemps(
|
|
106
|
-
person["id"],
|
|
91
|
+
person["id"],
|
|
92
|
+
login_failed_attemps + 1,
|
|
93
|
+
date_helpers.get_utc_now_datetime(),
|
|
107
94
|
)
|
|
108
95
|
raise WrongPasswordException()
|
|
109
96
|
|
|
@@ -116,7 +103,9 @@ def check_auth(
|
|
|
116
103
|
recovery_code,
|
|
117
104
|
):
|
|
118
105
|
update_login_failed_attemps(
|
|
119
|
-
person["id"],
|
|
106
|
+
person["id"],
|
|
107
|
+
login_failed_attemps + 1,
|
|
108
|
+
date_helpers.get_utc_now_datetime(),
|
|
120
109
|
)
|
|
121
110
|
raise WrongOTPException()
|
|
122
111
|
|
|
@@ -341,7 +330,7 @@ def check_fido(person, authentication_response):
|
|
|
341
330
|
except KeyError:
|
|
342
331
|
return False
|
|
343
332
|
try:
|
|
344
|
-
fido_server.authenticate_complete(
|
|
333
|
+
current_app.extensions["fido_server"].authenticate_complete(
|
|
345
334
|
state,
|
|
346
335
|
get_fido_attested_credential_data_from_person(
|
|
347
336
|
person["fido_credentials"],
|
|
@@ -488,7 +477,7 @@ def send_email_otp(person):
|
|
|
488
477
|
)
|
|
489
478
|
organisation = persons_service.get_organisation()
|
|
490
479
|
time_string = format_datetime(
|
|
491
|
-
|
|
480
|
+
date_helpers.get_utc_now_datetime(),
|
|
492
481
|
tzinfo=person["timezone"],
|
|
493
482
|
locale=person["locale"],
|
|
494
483
|
)
|
|
@@ -547,7 +536,7 @@ def pre_register_fido(person_id):
|
|
|
547
536
|
Pre-register FIDO device for a person.
|
|
548
537
|
"""
|
|
549
538
|
person = Person.get(person_id)
|
|
550
|
-
options, state = fido_server.register_begin(
|
|
539
|
+
options, state = current_app.extensions["fido_server"].register_begin(
|
|
551
540
|
PublicKeyCredentialUserEntity(
|
|
552
541
|
id=str(person.id).encode(),
|
|
553
542
|
name=person.email,
|
|
@@ -573,7 +562,9 @@ def register_fido(person_id, registration_response, device_name):
|
|
|
573
562
|
except KeyError:
|
|
574
563
|
raise FIDONoPreregistrationException()
|
|
575
564
|
try:
|
|
576
|
-
auth_data = fido_server.register_complete(
|
|
565
|
+
auth_data = current_app.extensions["fido_server"].register_complete(
|
|
566
|
+
state, registration_response
|
|
567
|
+
)
|
|
577
568
|
except BaseException:
|
|
578
569
|
raise FIDOServerException()
|
|
579
570
|
credential_data = {
|
|
@@ -634,7 +625,7 @@ def get_challenge_fido(person_id):
|
|
|
634
625
|
Get new FIDO challenge for a person.
|
|
635
626
|
"""
|
|
636
627
|
person = Person.get(person_id)
|
|
637
|
-
options, state = fido_server.authenticate_begin(
|
|
628
|
+
options, state = current_app.extensions["fido_server"].authenticate_begin(
|
|
638
629
|
credentials=get_fido_attested_credential_data_from_person(
|
|
639
630
|
person.fido_credentials
|
|
640
631
|
),
|
|
@@ -673,24 +664,6 @@ def generate_new_recovery_codes(person_id):
|
|
|
673
664
|
return otp_recovery_codes
|
|
674
665
|
|
|
675
666
|
|
|
676
|
-
def register_tokens(app, access_token, refresh_token=None):
|
|
677
|
-
"""
|
|
678
|
-
Register access and refresh tokens to auth token store. That way they
|
|
679
|
-
can be used like a session.
|
|
680
|
-
"""
|
|
681
|
-
access_jti = get_jti(encoded_token=access_token)
|
|
682
|
-
|
|
683
|
-
auth_tokens_store.add(
|
|
684
|
-
access_jti, "false", app.config["JWT_ACCESS_TOKEN_EXPIRES"]
|
|
685
|
-
)
|
|
686
|
-
|
|
687
|
-
if refresh_token is not None:
|
|
688
|
-
refresh_jti = get_jti(encoded_token=refresh_token)
|
|
689
|
-
auth_tokens_store.add(
|
|
690
|
-
refresh_jti, "false", app.config["JWT_REFRESH_TOKEN_EXPIRES"]
|
|
691
|
-
)
|
|
692
|
-
|
|
693
|
-
|
|
694
667
|
def revoke_tokens(app, jti):
|
|
695
668
|
"""
|
|
696
669
|
Remove access and refresh tokens from auth token store.
|
|
@@ -754,7 +727,7 @@ def check_login_failed_attemps(person):
|
|
|
754
727
|
login_failed_attemps >= 5
|
|
755
728
|
and date_helpers.get_datetime_from_string(person["last_login_failed"])
|
|
756
729
|
+ timedelta(minutes=1)
|
|
757
|
-
>
|
|
730
|
+
> date_helpers.get_utc_now_datetime()
|
|
758
731
|
):
|
|
759
732
|
raise TooMuchLoginFailedAttemps()
|
|
760
733
|
return login_failed_attemps
|
|
@@ -50,6 +50,8 @@ def get_casting(shot_id):
|
|
|
50
50
|
Entity.preview_file_id,
|
|
51
51
|
Entity.source_id,
|
|
52
52
|
Entity.ready_for,
|
|
53
|
+
Entity.is_shared,
|
|
54
|
+
Entity.project_id,
|
|
53
55
|
)
|
|
54
56
|
.order_by(EntityType.name, Entity.name)
|
|
55
57
|
)
|
|
@@ -61,6 +63,8 @@ def get_casting(shot_id):
|
|
|
61
63
|
entity_preview_file_id,
|
|
62
64
|
episode_id,
|
|
63
65
|
entity_ready_for,
|
|
66
|
+
entity_is_shared,
|
|
67
|
+
entity_project_id,
|
|
64
68
|
) in links:
|
|
65
69
|
casting.append(
|
|
66
70
|
{
|
|
@@ -74,6 +78,8 @@ def get_casting(shot_id):
|
|
|
74
78
|
),
|
|
75
79
|
"nb_occurences": link.nb_occurences,
|
|
76
80
|
"label": link.label,
|
|
81
|
+
"is_shared": entity_is_shared,
|
|
82
|
+
"project_id": entity_project_id,
|
|
77
83
|
}
|
|
78
84
|
)
|
|
79
85
|
return casting
|
|
@@ -93,11 +99,27 @@ def get_production_episodes_casting(project_id):
|
|
|
93
99
|
.join(EntityType, Entity.entity_type_id == EntityType.id)
|
|
94
100
|
.filter(Episode.project_id == project_id)
|
|
95
101
|
.filter(Entity.canceled != True)
|
|
96
|
-
.add_columns(
|
|
97
|
-
|
|
102
|
+
.add_columns(
|
|
103
|
+
Entity.name,
|
|
104
|
+
EntityType.name,
|
|
105
|
+
Entity.preview_file_id,
|
|
106
|
+
Entity.is_shared,
|
|
107
|
+
Entity.project_id,
|
|
108
|
+
)
|
|
109
|
+
.order_by(
|
|
110
|
+
EntityType.name,
|
|
111
|
+
Entity.name,
|
|
112
|
+
)
|
|
98
113
|
)
|
|
99
114
|
|
|
100
|
-
for
|
|
115
|
+
for (
|
|
116
|
+
link,
|
|
117
|
+
entity_name,
|
|
118
|
+
entity_type_name,
|
|
119
|
+
entity_preview_file_id,
|
|
120
|
+
entity_is_shared,
|
|
121
|
+
entity_project_id,
|
|
122
|
+
) in links:
|
|
101
123
|
episode_id = str(link.entity_in_id)
|
|
102
124
|
if episode_id not in castings:
|
|
103
125
|
castings[episode_id] = []
|
|
@@ -112,6 +134,8 @@ def get_production_episodes_casting(project_id):
|
|
|
112
134
|
),
|
|
113
135
|
"nb_occurences": link.nb_occurences,
|
|
114
136
|
"label": link.label,
|
|
137
|
+
"is_shared": entity_is_shared,
|
|
138
|
+
"project_id": entity_project_id,
|
|
115
139
|
}
|
|
116
140
|
)
|
|
117
141
|
return castings
|
|
@@ -139,6 +163,8 @@ def get_sequence_casting(sequence_id, project_id=None, episode_id=None):
|
|
|
139
163
|
Entity.name,
|
|
140
164
|
EntityType.name,
|
|
141
165
|
Entity.preview_file_id,
|
|
166
|
+
Entity.is_shared,
|
|
167
|
+
Entity.project_id,
|
|
142
168
|
Sequence.name,
|
|
143
169
|
)
|
|
144
170
|
)
|
|
@@ -163,6 +189,8 @@ def get_sequence_casting(sequence_id, project_id=None, episode_id=None):
|
|
|
163
189
|
entity_name,
|
|
164
190
|
entity_type_name,
|
|
165
191
|
entity_preview_file_id,
|
|
192
|
+
entity_is_shared,
|
|
193
|
+
entity_project_id,
|
|
166
194
|
sequence_name,
|
|
167
195
|
) in links:
|
|
168
196
|
shot_id = str(link.entity_in_id)
|
|
@@ -180,6 +208,8 @@ def get_sequence_casting(sequence_id, project_id=None, episode_id=None):
|
|
|
180
208
|
),
|
|
181
209
|
"nb_occurences": link.nb_occurences,
|
|
182
210
|
"label": link.label,
|
|
211
|
+
"is_shared": entity_is_shared,
|
|
212
|
+
"project_id": entity_project_id,
|
|
183
213
|
}
|
|
184
214
|
)
|
|
185
215
|
return castings
|
|
@@ -384,7 +414,7 @@ def _create_episode_casting_link(entity, asset_id, nb_occurences=1, label=""):
|
|
|
384
414
|
link = EntityLink.create(
|
|
385
415
|
entity_in_id=sequence["parent_id"],
|
|
386
416
|
entity_out_id=asset_id,
|
|
387
|
-
nb_occurences=
|
|
417
|
+
nb_occurences=nb_occurences,
|
|
388
418
|
label=label,
|
|
389
419
|
)
|
|
390
420
|
events.emit(
|
|
@@ -799,7 +829,9 @@ def _get_task_type_priority_map(project_id):
|
|
|
799
829
|
|
|
800
830
|
def _is_asset_ready(asset, task, priority_map):
|
|
801
831
|
is_ready = False
|
|
802
|
-
if "
|
|
832
|
+
if asset["is_shared"] and asset["project_id"] != str(task.project_id):
|
|
833
|
+
is_ready = True
|
|
834
|
+
elif "ready_for" in asset and asset["ready_for"] is not None:
|
|
803
835
|
priority_ready = priority_map.get(asset["ready_for"], -1) or -1
|
|
804
836
|
priority_task = priority_map.get(str(task.task_type_id), 0) or 0
|
|
805
837
|
is_ready = priority_task <= priority_ready
|