zou 0.20.8__py3-none-any.whl → 0.20.12__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/blueprints/comments/resources.py +5 -15
- zou/app/blueprints/crud/attachment_file.py +1 -4
- zou/app/blueprints/crud/project.py +4 -0
- zou/app/blueprints/crud/working_file.py +3 -7
- zou/app/blueprints/files/resources.py +7 -17
- zou/app/blueprints/previews/__init__.py +8 -3
- zou/app/blueprints/previews/resources.py +100 -60
- zou/app/blueprints/projects/resources.py +9 -0
- zou/app/blueprints/tasks/resources.py +8 -20
- zou/app/models/person.py +10 -0
- zou/app/services/assets_service.py +12 -0
- zou/app/services/preview_files_service.py +5 -5
- zou/app/services/user_service.py +11 -1
- zou/app/utils/commands.py +17 -14
- zou/event_stream.py +124 -145
- zou/migrations/versions/539a3a00c417_for_departmentlink_index_person_id_.py +50 -0
- {zou-0.20.8.dist-info → zou-0.20.12.dist-info}/METADATA +12 -11
- {zou-0.20.8.dist-info → zou-0.20.12.dist-info}/RECORD +23 -22
- {zou-0.20.8.dist-info → zou-0.20.12.dist-info}/WHEEL +1 -1
- {zou-0.20.8.dist-info → zou-0.20.12.dist-info}/LICENSE +0 -0
- {zou-0.20.8.dist-info → zou-0.20.12.dist-info}/entry_points.txt +0 -0
- {zou-0.20.8.dist-info → zou-0.20.12.dist-info}/top_level.txt +0 -0
zou/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.20.
|
|
1
|
+
__version__ = "0.20.12"
|
|
@@ -57,9 +57,7 @@ class DownloadAttachmentResource(Resource):
|
|
|
57
57
|
)
|
|
58
58
|
if attachment_file["comment_id"] is not None:
|
|
59
59
|
comment = tasks_service.get_comment(attachment_file["comment_id"])
|
|
60
|
-
|
|
61
|
-
user_service.check_project_access(task["project_id"])
|
|
62
|
-
user_service.check_entity_access(task["entity_id"])
|
|
60
|
+
user_service.check_task_access(comment["object_id"])
|
|
63
61
|
elif attachment_file["chat_message_id"] is not None:
|
|
64
62
|
message = chats_service.get_chat_message(
|
|
65
63
|
attachment_file["chat_message_id"]
|
|
@@ -122,9 +120,7 @@ class AckCommentResource(Resource):
|
|
|
122
120
|
200:
|
|
123
121
|
description: Comment acknowledged
|
|
124
122
|
"""
|
|
125
|
-
|
|
126
|
-
user_service.check_project_access(task["project_id"])
|
|
127
|
-
user_service.check_entity_access(task["entity_id"])
|
|
123
|
+
user_service.check_task_access(task_id)
|
|
128
124
|
return comments_service.acknowledge_comment(comment_id)
|
|
129
125
|
|
|
130
126
|
|
|
@@ -193,9 +189,7 @@ class CommentTaskResource(Resource):
|
|
|
193
189
|
links,
|
|
194
190
|
) = self.get_arguments()
|
|
195
191
|
|
|
196
|
-
|
|
197
|
-
user_service.check_project_access(task["project_id"])
|
|
198
|
-
user_service.check_entity_access(task["entity_id"])
|
|
192
|
+
user_service.check_task_access(task_id)
|
|
199
193
|
user_service.check_task_status_access(task_status_id)
|
|
200
194
|
files = request.files
|
|
201
195
|
|
|
@@ -496,9 +490,7 @@ class ReplyCommentResource(Resource, ArgsMixin):
|
|
|
496
490
|
]
|
|
497
491
|
)
|
|
498
492
|
|
|
499
|
-
|
|
500
|
-
user_service.check_project_access(task["project_id"])
|
|
501
|
-
user_service.check_entity_access(task["entity_id"])
|
|
493
|
+
user_service.check_task_access(task_id)
|
|
502
494
|
return comments_service.reply_comment(comment_id, args["text"])
|
|
503
495
|
|
|
504
496
|
|
|
@@ -537,9 +529,7 @@ class DeleteReplyCommentResource(Resource):
|
|
|
537
529
|
200:
|
|
538
530
|
description: Given comment reply deleted
|
|
539
531
|
"""
|
|
540
|
-
|
|
541
|
-
user_service.check_project_access(task["project_id"])
|
|
542
|
-
user_service.check_entity_access(task["entity_id"])
|
|
532
|
+
user_service.check_task_access(task_id)
|
|
543
533
|
reply = comments_service.get_reply(comment_id, reply_id)
|
|
544
534
|
current_user = persons_service.get_current_user()
|
|
545
535
|
if reply["person_id"] != current_user["id"]:
|
|
@@ -20,15 +20,12 @@ class AttachmentFileResource(BaseModelResource):
|
|
|
20
20
|
attachment_file = instance
|
|
21
21
|
if attachment_file["comment_id"] is not None:
|
|
22
22
|
comment = tasks_service.get_comment(attachment_file["comment_id"])
|
|
23
|
-
|
|
24
|
-
user_service.check_project_access(task["project_id"])
|
|
25
|
-
user_service.check_entity_access(task["entity_id"])
|
|
23
|
+
user_service.check_task_access(comment["object_id"])
|
|
26
24
|
elif attachment_file["chat_message_id"] is not None:
|
|
27
25
|
message = chats_service.get_chat_message(
|
|
28
26
|
attachment_file["chat_message_id"]
|
|
29
27
|
)
|
|
30
28
|
chat = chats_service.get_chat(message["chat_id"])
|
|
31
|
-
print(chat)
|
|
32
29
|
user_service.check_entity_access(chat["object_id"])
|
|
33
30
|
else:
|
|
34
31
|
raise PermissionDenied()
|
|
@@ -207,6 +207,8 @@ class ProjectTaskTypeLinksResource(Resource, ArgsMixin):
|
|
|
207
207
|
]
|
|
208
208
|
)
|
|
209
209
|
|
|
210
|
+
user_service.check_manager_project_access(args["project_id"])
|
|
211
|
+
|
|
210
212
|
task_type_link = projects_service.create_project_task_type_link(
|
|
211
213
|
args["project_id"],
|
|
212
214
|
args["task_type_id"],
|
|
@@ -234,6 +236,8 @@ class ProjectTaskStatusLinksResource(Resource, ArgsMixin):
|
|
|
234
236
|
]
|
|
235
237
|
)
|
|
236
238
|
|
|
239
|
+
user_service.check_manager_project_access(args["project_id"])
|
|
240
|
+
|
|
237
241
|
task_status_link = projects_service.create_project_task_status_link(
|
|
238
242
|
args["project_id"],
|
|
239
243
|
args["task_status_id"],
|
|
@@ -8,7 +8,7 @@ from zou.app.blueprints.crud.base import BaseModelsResource, BaseModelResource
|
|
|
8
8
|
from zou.app.models.entity import Entity
|
|
9
9
|
from zou.app.models.project import Project
|
|
10
10
|
from zou.app.models.working_file import WorkingFile
|
|
11
|
-
from zou.app.services import user_service,
|
|
11
|
+
from zou.app.services import user_service, files_service
|
|
12
12
|
from zou.app.utils import permissions
|
|
13
13
|
|
|
14
14
|
|
|
@@ -46,16 +46,12 @@ class WorkingFileResource(BaseModelResource):
|
|
|
46
46
|
|
|
47
47
|
def check_read_permissions(self, instance):
|
|
48
48
|
working_file = files_service.get_working_file(instance["id"])
|
|
49
|
-
|
|
50
|
-
user_service.check_project_access(task["project_id"])
|
|
51
|
-
user_service.check_entity_access(task["entity_id"])
|
|
49
|
+
user_service.check_task_access(working_file["task_id"])
|
|
52
50
|
return True
|
|
53
51
|
|
|
54
52
|
def check_update_permissions(self, instance, data):
|
|
55
53
|
working_file = files_service.get_working_file(instance["id"])
|
|
56
|
-
|
|
57
|
-
user_service.check_project_access(task["project_id"])
|
|
58
|
-
user_service.check_entity_access(task["entity_id"])
|
|
54
|
+
user_service.check_task_access(working_file["task_id"])
|
|
59
55
|
return True
|
|
60
56
|
|
|
61
57
|
@jwt_required()
|
|
@@ -91,9 +91,7 @@ class WorkingFileFileResource(Resource):
|
|
|
91
91
|
|
|
92
92
|
def check_access(self, working_file_id):
|
|
93
93
|
working_file = files_service.get_working_file(working_file_id)
|
|
94
|
-
|
|
95
|
-
user_service.check_project_access(task["project_id"])
|
|
96
|
-
user_service.check_entity_access(task["entity_id"])
|
|
94
|
+
user_service.check_task_access(working_file["task_id"])
|
|
97
95
|
return working_file
|
|
98
96
|
|
|
99
97
|
def save_uploaded_file_in_temporary_folder(self, working_file_id):
|
|
@@ -556,10 +554,8 @@ class LastWorkingFilesResource(Resource):
|
|
|
556
554
|
description: Last working files revision for each file name for given task
|
|
557
555
|
"""
|
|
558
556
|
result = {}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
user_service.check_entity_access(task["entity_id"])
|
|
562
|
-
result = files_service.get_last_working_files_for_task(task["id"])
|
|
557
|
+
user_service.check_task_access(task_id)
|
|
558
|
+
result = files_service.get_last_working_files_for_task(task_id)
|
|
563
559
|
|
|
564
560
|
return result
|
|
565
561
|
|
|
@@ -588,10 +584,8 @@ class TaskWorkingFilesResource(Resource):
|
|
|
588
584
|
description: Last working files revision for each file name for given task
|
|
589
585
|
"""
|
|
590
586
|
result = {}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
user_service.check_entity_access(task["entity_id"])
|
|
594
|
-
result = files_service.get_working_files_for_task(task["id"])
|
|
587
|
+
user_service.check_task_access(task_id)
|
|
588
|
+
result = files_service.get_working_files_for_task(task_id)
|
|
595
589
|
|
|
596
590
|
return result
|
|
597
591
|
|
|
@@ -774,9 +768,7 @@ class ModifiedFileResource(Resource):
|
|
|
774
768
|
description: Working file modification date updated
|
|
775
769
|
"""
|
|
776
770
|
working_file = files_service.get_working_file(working_file_id)
|
|
777
|
-
|
|
778
|
-
user_service.check_project_access(task["project_id"])
|
|
779
|
-
user_service.check_entity_access(task["entity_id"])
|
|
771
|
+
user_service.check_task_access(working_file["task_id"])
|
|
780
772
|
working_file = files_service.update_working_file(
|
|
781
773
|
working_file_id,
|
|
782
774
|
{"updated_at": date_helpers.get_utc_now_datetime()},
|
|
@@ -827,9 +819,7 @@ class CommentWorkingFileResource(Resource, ArgsMixin):
|
|
|
827
819
|
)
|
|
828
820
|
|
|
829
821
|
working_file = files_service.get_working_file(working_file_id)
|
|
830
|
-
|
|
831
|
-
user_service.check_project_access(task["project_id"])
|
|
832
|
-
user_service.check_entity_access(task["entity_id"])
|
|
822
|
+
user_service.check_task_access(working_file["task_id"])
|
|
833
823
|
working_file = self.update_comment(working_file_id, args["comment"])
|
|
834
824
|
return working_file
|
|
835
825
|
|
|
@@ -2,7 +2,8 @@ from flask import Blueprint
|
|
|
2
2
|
from zou.app.utils.api import configure_api_from_blueprint
|
|
3
3
|
|
|
4
4
|
from zou.app.blueprints.previews.resources import (
|
|
5
|
-
|
|
5
|
+
AddTaskBatchCommentResource,
|
|
6
|
+
AddTasksBatchCommentResource,
|
|
6
7
|
AttachmentThumbnailResource,
|
|
7
8
|
CreatePreviewFilePictureResource,
|
|
8
9
|
PreviewFileLowMovieResource,
|
|
@@ -39,8 +40,12 @@ routes = [
|
|
|
39
40
|
CreatePreviewFilePictureResource,
|
|
40
41
|
),
|
|
41
42
|
(
|
|
42
|
-
"/actions/tasks/<task_id>/
|
|
43
|
-
|
|
43
|
+
"/actions/tasks/<task_id>/batch-comment",
|
|
44
|
+
AddTaskBatchCommentResource,
|
|
45
|
+
),
|
|
46
|
+
(
|
|
47
|
+
"/actions/tasks/batch-comment",
|
|
48
|
+
AddTasksBatchCommentResource,
|
|
44
49
|
),
|
|
45
50
|
(
|
|
46
51
|
"/movies/originals/preview-files/<instance_id>.mp4",
|
|
@@ -397,11 +397,8 @@ class CreatePreviewFilePictureResource(
|
|
|
397
397
|
200:
|
|
398
398
|
description: Preview added
|
|
399
399
|
"""
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
if not self.is_allowed(instance_id):
|
|
404
|
-
abort(403)
|
|
400
|
+
self.is_exist(instance_id)
|
|
401
|
+
self.is_allowed(instance_id)
|
|
405
402
|
|
|
406
403
|
return (
|
|
407
404
|
self.process_uploaded_file(
|
|
@@ -421,10 +418,8 @@ class CreatePreviewFilePictureResource(
|
|
|
421
418
|
)
|
|
422
419
|
raise PreviewFileReuploadNotAllowedException
|
|
423
420
|
|
|
424
|
-
task = tasks_service.get_task(preview_file["task_id"])
|
|
425
421
|
try:
|
|
426
|
-
user_service.
|
|
427
|
-
user_service.check_entity_access(task["entity_id"])
|
|
422
|
+
user_service.check_task_access(preview_file["task_id"])
|
|
428
423
|
return True
|
|
429
424
|
except permissions.PermissionDenied:
|
|
430
425
|
return False
|
|
@@ -436,47 +431,17 @@ class CreatePreviewFilePictureResource(
|
|
|
436
431
|
return files_service.get_preview_file(preview_file_id) is not None
|
|
437
432
|
|
|
438
433
|
|
|
439
|
-
class
|
|
440
|
-
BaseNewPreviewFilePicture, Resource, ArgsMixin
|
|
441
|
-
):
|
|
434
|
+
class BaseBatchComment(BaseNewPreviewFilePicture, ArgsMixin):
|
|
442
435
|
"""
|
|
443
|
-
|
|
444
|
-
task_status and a person as arguments.
|
|
436
|
+
Base class to add comments/previews/attachments.
|
|
445
437
|
"""
|
|
446
438
|
|
|
447
|
-
|
|
448
|
-
def post(self, task_id):
|
|
439
|
+
def get_comments_args(self):
|
|
449
440
|
"""
|
|
450
|
-
|
|
451
|
-
task_status and a person as arguments.
|
|
452
|
-
---
|
|
453
|
-
tags:
|
|
454
|
-
- Comments
|
|
455
|
-
description: Creates new comments for given task. Each comments requires
|
|
456
|
-
a text, a task_status and a person as arguments.
|
|
457
|
-
parameters:
|
|
458
|
-
- in: path
|
|
459
|
-
name: task_id
|
|
460
|
-
required: True
|
|
461
|
-
type: string
|
|
462
|
-
format: UUID
|
|
463
|
-
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
464
|
-
- in: body
|
|
465
|
-
name: Comment
|
|
466
|
-
description: person ID, name, comment, revision and change status of task
|
|
467
|
-
schema:
|
|
468
|
-
type: object
|
|
469
|
-
required:
|
|
470
|
-
- comments
|
|
471
|
-
properties:
|
|
472
|
-
comments:
|
|
473
|
-
type: string
|
|
474
|
-
responses:
|
|
475
|
-
201:
|
|
476
|
-
description: New comments created
|
|
441
|
+
Return comments arguments.
|
|
477
442
|
"""
|
|
478
443
|
if request.is_json:
|
|
479
|
-
|
|
444
|
+
return self.get_args(
|
|
480
445
|
[
|
|
481
446
|
{
|
|
482
447
|
"name": "comments",
|
|
@@ -500,22 +465,31 @@ class AddCommentsPreviewsResource(
|
|
|
500
465
|
],
|
|
501
466
|
)
|
|
502
467
|
args["comments"] = json.loads(args["comments"])
|
|
468
|
+
return args
|
|
503
469
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
470
|
+
def process_comments(self, task_id=None):
|
|
471
|
+
"""
|
|
472
|
+
Process comments.
|
|
473
|
+
"""
|
|
474
|
+
args = self.get_comments_args()
|
|
475
|
+
|
|
476
|
+
if task_id is not None:
|
|
477
|
+
user_service.check_task_access(task_id)
|
|
507
478
|
|
|
508
479
|
new_comments = []
|
|
509
480
|
for i, comment in enumerate(args["comments"]):
|
|
510
481
|
user_service.check_task_status_access(comment["task_status_id"])
|
|
511
482
|
|
|
483
|
+
if task_id is None:
|
|
484
|
+
user_service.check_task_access(comment["task_id"])
|
|
485
|
+
|
|
512
486
|
if not permissions.has_manager_permissions():
|
|
513
487
|
comment["person_id"] = None
|
|
514
488
|
comment["created_at"] = None
|
|
515
489
|
|
|
516
490
|
new_comment = comments_service.create_comment(
|
|
517
491
|
comment.get("person_id", None),
|
|
518
|
-
task_id,
|
|
492
|
+
task_id or comment["task_id"],
|
|
519
493
|
comment["task_status_id"],
|
|
520
494
|
comment["text"],
|
|
521
495
|
comment.get("checklist", []),
|
|
@@ -537,7 +511,7 @@ class AddCommentsPreviewsResource(
|
|
|
537
511
|
new_preview_file = tasks_service.add_preview_file_to_comment(
|
|
538
512
|
new_comment["id"],
|
|
539
513
|
new_comment["person_id"],
|
|
540
|
-
task_id,
|
|
514
|
+
task_id or comment["task_id"],
|
|
541
515
|
)
|
|
542
516
|
new_preview_file = self.process_uploaded_file(
|
|
543
517
|
new_preview_file["id"],
|
|
@@ -552,6 +526,80 @@ class AddCommentsPreviewsResource(
|
|
|
552
526
|
return new_comments, 201
|
|
553
527
|
|
|
554
528
|
|
|
529
|
+
class AddTaskBatchCommentResource(BaseBatchComment, Resource):
|
|
530
|
+
"""
|
|
531
|
+
Creates new comments for given task. Each comments requires a text, a
|
|
532
|
+
task_status and a person as arguments.
|
|
533
|
+
"""
|
|
534
|
+
|
|
535
|
+
@jwt_required()
|
|
536
|
+
def post(self, task_id):
|
|
537
|
+
"""
|
|
538
|
+
Creates new comments for given task. Each comments requires a text, a
|
|
539
|
+
task_status and a person as arguments.
|
|
540
|
+
---
|
|
541
|
+
tags:
|
|
542
|
+
- Comments
|
|
543
|
+
description: Creates new comments for given task. Each comments requires
|
|
544
|
+
a text, a task_status and a person as arguments.
|
|
545
|
+
parameters:
|
|
546
|
+
- in: path
|
|
547
|
+
name: task_id
|
|
548
|
+
required: True
|
|
549
|
+
type: string
|
|
550
|
+
format: UUID
|
|
551
|
+
x-example: a24a6ea4-ce75-4665-a070-57453082c25
|
|
552
|
+
- in: body
|
|
553
|
+
name: Comment
|
|
554
|
+
description: person ID, name, comment, revision and change status of task
|
|
555
|
+
schema:
|
|
556
|
+
type: object
|
|
557
|
+
required:
|
|
558
|
+
- comments
|
|
559
|
+
properties:
|
|
560
|
+
comments:
|
|
561
|
+
type: string
|
|
562
|
+
responses:
|
|
563
|
+
201:
|
|
564
|
+
description: New comments created
|
|
565
|
+
"""
|
|
566
|
+
return self.process_comments(task_id)
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
class AddTasksBatchCommentResource(BaseBatchComment, Resource):
|
|
570
|
+
"""
|
|
571
|
+
Creates new comments for given tasks. Each comments requires a task_id,
|
|
572
|
+
text, a task_status and a person as arguments.
|
|
573
|
+
"""
|
|
574
|
+
|
|
575
|
+
@jwt_required()
|
|
576
|
+
def post(self):
|
|
577
|
+
"""
|
|
578
|
+
Creates new comments for given task. Each comments requires a task_id,
|
|
579
|
+
text, a task_status and a person as arguments.
|
|
580
|
+
---
|
|
581
|
+
tags:
|
|
582
|
+
- Comments
|
|
583
|
+
description: Creates new comments for given task. Each comments requires
|
|
584
|
+
a task_id, a text, a task_status and a person as arguments.
|
|
585
|
+
parameters:
|
|
586
|
+
- in: body
|
|
587
|
+
name: Comment
|
|
588
|
+
description: person ID, name, comment, revision and change status of task
|
|
589
|
+
schema:
|
|
590
|
+
type: object
|
|
591
|
+
required:
|
|
592
|
+
- comments
|
|
593
|
+
properties:
|
|
594
|
+
comments:
|
|
595
|
+
type: string
|
|
596
|
+
responses:
|
|
597
|
+
201:
|
|
598
|
+
description: New comments created
|
|
599
|
+
"""
|
|
600
|
+
return self.process_comments()
|
|
601
|
+
|
|
602
|
+
|
|
555
603
|
class BasePreviewFileResource(Resource):
|
|
556
604
|
"""
|
|
557
605
|
Base class to download a preview file.
|
|
@@ -564,9 +612,7 @@ class BasePreviewFileResource(Resource):
|
|
|
564
612
|
|
|
565
613
|
def is_allowed(self, preview_file_id):
|
|
566
614
|
self.preview_file = files_service.get_preview_file(preview_file_id)
|
|
567
|
-
|
|
568
|
-
user_service.check_project_access(task["project_id"])
|
|
569
|
-
user_service.check_entity_access(task["entity_id"])
|
|
615
|
+
user_service.check_task_access(self.preview_file["task_id"])
|
|
570
616
|
self.last_modified = date_helpers.get_datetime_from_string(
|
|
571
617
|
self.preview_file["updated_at"]
|
|
572
618
|
)
|
|
@@ -843,9 +889,7 @@ class AttachmentThumbnailResource(Resource):
|
|
|
843
889
|
comment = tasks_service.get_comment(
|
|
844
890
|
self.attachment_file["comment_id"]
|
|
845
891
|
)
|
|
846
|
-
|
|
847
|
-
user_service.check_project_access(task["project_id"])
|
|
848
|
-
user_service.check_entity_access(task["entity_id"])
|
|
892
|
+
user_service.check_task_access(comment["object_id"])
|
|
849
893
|
elif self.attachment_file["chat_message_id"] is not None:
|
|
850
894
|
message = chats_service.get_chat_message(
|
|
851
895
|
self.attachment_file["chat_message_id"]
|
|
@@ -1272,9 +1316,7 @@ class UpdatePreviewPositionResource(Resource, ArgsMixin):
|
|
|
1272
1316
|
"""
|
|
1273
1317
|
args = self.get_args([{"name": "position", "default": 0, "type": int}])
|
|
1274
1318
|
preview_file = files_service.get_preview_file(preview_file_id)
|
|
1275
|
-
|
|
1276
|
-
user_service.check_manager_project_access(task["project_id"])
|
|
1277
|
-
user_service.check_entity_access(task["entity_id"])
|
|
1319
|
+
user_service.check_task_access(preview_file["task_id"])
|
|
1278
1320
|
return preview_files_service.update_preview_file_position(
|
|
1279
1321
|
preview_file_id, args["position"]
|
|
1280
1322
|
)
|
|
@@ -1424,9 +1466,7 @@ class ExtractTileFromPreview(Resource):
|
|
|
1424
1466
|
@jwt_required()
|
|
1425
1467
|
def get(self, preview_file_id):
|
|
1426
1468
|
preview_file = files_service.get_preview_file(preview_file_id)
|
|
1427
|
-
|
|
1428
|
-
user_service.check_manager_project_access(task["project_id"])
|
|
1429
|
-
user_service.check_entity_access(task["entity_id"])
|
|
1469
|
+
user_service.check_task_access(preview_file["task_id"])
|
|
1430
1470
|
extracted_tile_path = (
|
|
1431
1471
|
preview_files_service.extract_tile_from_preview_file(preview_file)
|
|
1432
1472
|
)
|
|
@@ -11,6 +11,7 @@ from zou.app.services import (
|
|
|
11
11
|
)
|
|
12
12
|
from zou.app.utils import permissions
|
|
13
13
|
from zou.app.services.exception import WrongParameterException
|
|
14
|
+
from zou.app.models.metadata_descriptor import METADATA_DESCRIPTOR_TYPES
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class OpenProjectsResource(Resource, ArgsMixin):
|
|
@@ -715,6 +716,10 @@ class ProductionMetadataDescriptorsResource(Resource, ArgsMixin):
|
|
|
715
716
|
if len(args["name"]) == 0:
|
|
716
717
|
raise WrongParameterException("Name cannot be empty.")
|
|
717
718
|
|
|
719
|
+
types = [type_name for type_name, _ in METADATA_DESCRIPTOR_TYPES]
|
|
720
|
+
if args["data_type"] not in types:
|
|
721
|
+
raise WrongParameterException("Invalid data_type")
|
|
722
|
+
|
|
718
723
|
return (
|
|
719
724
|
projects_service.add_metadata_descriptor(
|
|
720
725
|
project_id,
|
|
@@ -828,6 +833,10 @@ class ProductionMetadataDescriptorResource(Resource, ArgsMixin):
|
|
|
828
833
|
if len(args["name"]) == 0:
|
|
829
834
|
raise WrongParameterException("Name cannot be empty.")
|
|
830
835
|
|
|
836
|
+
types = [type_name for type_name, _ in METADATA_DESCRIPTOR_TYPES]
|
|
837
|
+
if args["data_type"] not in types:
|
|
838
|
+
raise WrongParameterException("Invalid data_type")
|
|
839
|
+
|
|
831
840
|
args["for_client"] = args["for_client"] == "True"
|
|
832
841
|
|
|
833
842
|
return projects_service.update_metadata_descriptor(descriptor_id, args)
|
|
@@ -69,9 +69,7 @@ class AddPreviewResource(Resource, ArgsMixin):
|
|
|
69
69
|
"""
|
|
70
70
|
args = self.get_args([("revision", 0, False, int)])
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
user_service.check_project_access(task["project_id"])
|
|
74
|
-
user_service.check_entity_access(task["entity_id"])
|
|
72
|
+
user_service.check_task_access(task_id)
|
|
75
73
|
|
|
76
74
|
person = persons_service.get_current_user()
|
|
77
75
|
preview_file = tasks_service.add_preview_file_to_comment(
|
|
@@ -119,9 +117,7 @@ class AddExtraPreviewResource(Resource):
|
|
|
119
117
|
201:
|
|
120
118
|
description: Preview added to given comment
|
|
121
119
|
"""
|
|
122
|
-
|
|
123
|
-
user_service.check_project_access(task["project_id"])
|
|
124
|
-
user_service.check_entity_access(task["entity_id"])
|
|
120
|
+
user_service.check_task_access(task_id)
|
|
125
121
|
tasks_service.get_comment(comment_id)
|
|
126
122
|
|
|
127
123
|
person = persons_service.get_current_user()
|
|
@@ -191,9 +187,7 @@ class TaskPreviewsResource(Resource):
|
|
|
191
187
|
200:
|
|
192
188
|
description: Previews linked to given task
|
|
193
189
|
"""
|
|
194
|
-
|
|
195
|
-
user_service.check_project_access(task["project_id"])
|
|
196
|
-
user_service.check_entity_access(task["entity_id"])
|
|
190
|
+
user_service.check_task_access(task_id)
|
|
197
191
|
return files_service.get_preview_files_for_task(task_id)
|
|
198
192
|
|
|
199
193
|
|
|
@@ -220,9 +214,7 @@ class TaskCommentsResource(Resource):
|
|
|
220
214
|
200:
|
|
221
215
|
description: Comments linked to given task
|
|
222
216
|
"""
|
|
223
|
-
|
|
224
|
-
user_service.check_project_access(task["project_id"])
|
|
225
|
-
user_service.check_entity_access(task["entity_id"])
|
|
217
|
+
user_service.check_task_access(task_id)
|
|
226
218
|
is_client = permissions.has_client_permissions()
|
|
227
219
|
is_manager = permissions.has_manager_permissions()
|
|
228
220
|
is_supervisor = permissions.has_supervisor_permissions()
|
|
@@ -753,7 +745,7 @@ class ToReviewResource(Resource, ArgsMixin):
|
|
|
753
745
|
try:
|
|
754
746
|
task = tasks_service.get_task(task_id)
|
|
755
747
|
user_service.check_project_access(task["project_id"])
|
|
756
|
-
user_service.check_entity_access(task["
|
|
748
|
+
user_service.check_entity_access(task["entity_id"])
|
|
757
749
|
|
|
758
750
|
if person_id is not None:
|
|
759
751
|
person = persons_service.get_person(person_id)
|
|
@@ -763,7 +755,7 @@ class ToReviewResource(Resource, ArgsMixin):
|
|
|
763
755
|
preview_path = self.get_preview_path(task, name, revision)
|
|
764
756
|
|
|
765
757
|
task = tasks_service.task_to_review(
|
|
766
|
-
|
|
758
|
+
task_id, person, comment, preview_path, change_status
|
|
767
759
|
)
|
|
768
760
|
except PersonNotFoundException:
|
|
769
761
|
return {"error": True, "message": "Cannot find given person."}, 400
|
|
@@ -1274,9 +1266,7 @@ class GetTimeSpentResource(Resource):
|
|
|
1274
1266
|
404:
|
|
1275
1267
|
description: Wrong date format
|
|
1276
1268
|
"""
|
|
1277
|
-
|
|
1278
|
-
user_service.check_project_access(task["project_id"])
|
|
1279
|
-
user_service.check_entity_access(task["entity_id"])
|
|
1269
|
+
user_service.check_task_access(task_id)
|
|
1280
1270
|
return tasks_service.get_time_spents(task_id)
|
|
1281
1271
|
|
|
1282
1272
|
|
|
@@ -1312,9 +1302,7 @@ class GetTimeSpentDateResource(Resource):
|
|
|
1312
1302
|
description: Wrong date format
|
|
1313
1303
|
"""
|
|
1314
1304
|
try:
|
|
1315
|
-
|
|
1316
|
-
user_service.check_project_access(task["project_id"])
|
|
1317
|
-
user_service.check_entity_access(task["entity_id"])
|
|
1305
|
+
user_service.check_task_access(task_id)
|
|
1318
1306
|
return tasks_service.get_time_spents(task_id, date)
|
|
1319
1307
|
except WrongDateFormatException:
|
|
1320
1308
|
abort(404)
|
zou/app/models/person.py
CHANGED
|
@@ -49,11 +49,21 @@ class DepartmentLink(db.Model):
|
|
|
49
49
|
UUIDType(binary=False),
|
|
50
50
|
db.ForeignKey("person.id"),
|
|
51
51
|
primary_key=True,
|
|
52
|
+
index=True,
|
|
52
53
|
)
|
|
53
54
|
department_id = db.Column(
|
|
54
55
|
UUIDType(binary=False),
|
|
55
56
|
db.ForeignKey("department.id"),
|
|
56
57
|
primary_key=True,
|
|
58
|
+
index=True,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
__table_args__ = (
|
|
62
|
+
db.UniqueConstraint(
|
|
63
|
+
"person_id",
|
|
64
|
+
"department_id",
|
|
65
|
+
name="department_link_uc",
|
|
66
|
+
),
|
|
57
67
|
)
|
|
58
68
|
|
|
59
69
|
|
|
@@ -248,6 +248,18 @@ def get_assets_and_tasks(criterions={}, page=1, with_episode_ids=False):
|
|
|
248
248
|
episode_links_query = episode_links_query.filter(
|
|
249
249
|
Episode.project_id == criterions["project_id"]
|
|
250
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
|
+
|
|
251
263
|
for link in episode_links_query.all():
|
|
252
264
|
if str(link.entity_out_id) not in cast_in_episode_ids:
|
|
253
265
|
cast_in_episode_ids[str(link.entity_out_id)] = []
|
|
@@ -100,7 +100,7 @@ def get_preview_file_fps(project, entity=None):
|
|
|
100
100
|
|
|
101
101
|
if entity is not None:
|
|
102
102
|
entity_data = entity.get("data", {}) or {}
|
|
103
|
-
if entity_data.get("fps", None)
|
|
103
|
+
if entity_data.get("fps", None):
|
|
104
104
|
fps = str(entity_data["fps"]).replace(",", ".")
|
|
105
105
|
|
|
106
106
|
return "%.3f" % float(fps)
|
|
@@ -181,6 +181,10 @@ def prepare_and_store_movie(
|
|
|
181
181
|
from zou.app import app as current_app
|
|
182
182
|
|
|
183
183
|
with current_app.app_context():
|
|
184
|
+
if add_source_to_file_store:
|
|
185
|
+
file_store.add_movie(
|
|
186
|
+
"source", preview_file_id, uploaded_movie_path
|
|
187
|
+
)
|
|
184
188
|
preview_file_raw = files_service.get_preview_file_raw(preview_file_id)
|
|
185
189
|
normalized_movie_low_path = None
|
|
186
190
|
try:
|
|
@@ -205,10 +209,6 @@ def prepare_and_store_movie(
|
|
|
205
209
|
if normalize:
|
|
206
210
|
current_app.logger.info("start normalization")
|
|
207
211
|
try:
|
|
208
|
-
if add_source_to_file_store:
|
|
209
|
-
file_store.add_movie(
|
|
210
|
-
"source", preview_file_id, uploaded_movie_path
|
|
211
|
-
)
|
|
212
212
|
if (
|
|
213
213
|
config.ENABLE_JOB_QUEUE_REMOTE
|
|
214
214
|
and len(config.JOB_QUEUE_NOMAD_NORMALIZE_JOB) > 0
|
zou/app/services/user_service.py
CHANGED
|
@@ -478,6 +478,16 @@ def check_task_status_access(task_status_id):
|
|
|
478
478
|
return True
|
|
479
479
|
|
|
480
480
|
|
|
481
|
+
def check_task_access(task_id):
|
|
482
|
+
"""
|
|
483
|
+
Return true if current user can have access to a task.
|
|
484
|
+
"""
|
|
485
|
+
task = tasks_service.get_task(task_id)
|
|
486
|
+
check_project_access(task["project_id"])
|
|
487
|
+
check_entity_access(task["entity_id"])
|
|
488
|
+
return True
|
|
489
|
+
|
|
490
|
+
|
|
481
491
|
def check_comment_access(comment_id):
|
|
482
492
|
"""
|
|
483
493
|
Return true if current user can have access to a comment.
|
|
@@ -1414,7 +1424,7 @@ def get_last_notifications(
|
|
|
1414
1424
|
)
|
|
1415
1425
|
reply_mentions = reply.get("mentions", []) or []
|
|
1416
1426
|
reply_department_mentions = (
|
|
1417
|
-
reply.get("
|
|
1427
|
+
reply.get("department_mentions", []) or []
|
|
1418
1428
|
)
|
|
1419
1429
|
if reply is not None:
|
|
1420
1430
|
reply_text = reply["text"]
|
zou/app/utils/commands.py
CHANGED
|
@@ -774,20 +774,23 @@ def renormalize_movie_preview_files(
|
|
|
774
774
|
config.TMP_DIR,
|
|
775
775
|
f"{preview_file_id}.{extension}.tmp",
|
|
776
776
|
)
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
777
|
+
try:
|
|
778
|
+
if config.FS_BACKEND == "local":
|
|
779
|
+
shutil.copyfile(
|
|
780
|
+
file_store.get_local_movie_path(
|
|
781
|
+
"source", preview_file_id
|
|
782
|
+
),
|
|
783
|
+
uploaded_movie_path,
|
|
784
|
+
)
|
|
785
|
+
else:
|
|
786
|
+
sync_service.download_file(
|
|
787
|
+
uploaded_movie_path,
|
|
788
|
+
"source",
|
|
789
|
+
file_store.open_movie,
|
|
790
|
+
str(preview_file_id),
|
|
791
|
+
)
|
|
792
|
+
except:
|
|
793
|
+
pass
|
|
791
794
|
if config.ENABLE_JOB_QUEUE:
|
|
792
795
|
queue_store.job_queue.enqueue(
|
|
793
796
|
preview_files_service.prepare_and_store_movie,
|
zou/event_stream.py
CHANGED
|
@@ -7,18 +7,21 @@ from flask_jwt_extended import (
|
|
|
7
7
|
get_jwt_identity,
|
|
8
8
|
jwt_required,
|
|
9
9
|
verify_jwt_in_request,
|
|
10
|
-
JWTManager,
|
|
11
10
|
)
|
|
12
11
|
from flask_socketio import SocketIO, disconnect, join_room, emit
|
|
13
12
|
|
|
14
13
|
from zou.app import config, app
|
|
15
|
-
from zou.app.stores import auth_tokens_store
|
|
16
|
-
from zou.app.services import persons_service
|
|
17
14
|
from zou.app.utils.redis import get_redis_url
|
|
18
15
|
|
|
19
16
|
server_stats = {"nb_connections": 0}
|
|
20
17
|
rooms_data = {}
|
|
21
18
|
|
|
19
|
+
redis_url = get_redis_url(config.KV_EVENTS_DB_INDEX)
|
|
20
|
+
socketio = SocketIO(
|
|
21
|
+
logger=True, cors_allowed_origins=[], cors_credentials=False
|
|
22
|
+
)
|
|
23
|
+
socketio.init_app(app, message_queue=redis_url, async_mode="gevent")
|
|
24
|
+
|
|
22
25
|
|
|
23
26
|
def _get_empty_room(current_frame=0):
|
|
24
27
|
return {
|
|
@@ -75,155 +78,131 @@ def _update_room_playing_status(data, room):
|
|
|
75
78
|
return room
|
|
76
79
|
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def set_application_routes(socketio, app):
|
|
89
|
-
@socketio.on("connect", namespace="/events")
|
|
90
|
-
def connected():
|
|
91
|
-
try:
|
|
92
|
-
verify_jwt_in_request()
|
|
93
|
-
server_stats["nb_connections"] += 1
|
|
94
|
-
app.logger.info("New websocket client connected")
|
|
95
|
-
except Exception:
|
|
96
|
-
app.logger.info("New websocket client failed to connect")
|
|
97
|
-
disconnect()
|
|
98
|
-
return False
|
|
99
|
-
|
|
100
|
-
@socketio.on("disconnect", namespace="/events")
|
|
101
|
-
def disconnected():
|
|
102
|
-
try:
|
|
103
|
-
verify_jwt_in_request()
|
|
104
|
-
user_id = get_jwt_identity()
|
|
105
|
-
# needed to be able to clear empty rooms
|
|
106
|
-
tmp_rooms_data = dict(rooms_data)
|
|
107
|
-
for room_id in tmp_rooms_data:
|
|
108
|
-
_leave_room(room_id, user_id)
|
|
109
|
-
server_stats["nb_connections"] -= 1
|
|
110
|
-
app.logger.info("Websocket client disconnected")
|
|
111
|
-
except Exception:
|
|
112
|
-
pass
|
|
113
|
-
|
|
114
|
-
@socketio.on_error("/events")
|
|
115
|
-
def on_error(error):
|
|
116
|
-
server_stats["nb_connections"] -= 1
|
|
117
|
-
if server_stats["nb_connections"] < 0:
|
|
118
|
-
server_stats["nb_connections"] = 0
|
|
119
|
-
app.logger.error(error)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def set_playlist_room_routes(socketio, app):
|
|
123
|
-
@app.route("/rooms", methods=["GET", "POST"])
|
|
124
|
-
@jwt_required()
|
|
125
|
-
def rooms():
|
|
126
|
-
return jsonify({"name": "%s Review rooms" % config.APP_NAME})
|
|
127
|
-
|
|
128
|
-
@socketio.on("preview-room:open-playlist", namespace="/events")
|
|
129
|
-
@jwt_required()
|
|
130
|
-
def on_open_playlist(data):
|
|
131
|
-
"""
|
|
132
|
-
when a person opens the playlist page he immediately enters the
|
|
133
|
-
websocket room. This way he can see in live which people are in the
|
|
134
|
-
review room. The user still has to explicitly enter the review room
|
|
135
|
-
to actually be in sync with the other users
|
|
136
|
-
"""
|
|
137
|
-
room, room_id = _get_room_from_data(data)
|
|
138
|
-
rooms_data[room_id] = room
|
|
139
|
-
join_room(room_id)
|
|
140
|
-
emit("preview-room:room-people-updated", room, room=room_id)
|
|
141
|
-
|
|
142
|
-
@socketio.on("preview-room:join", namespace="/events")
|
|
143
|
-
@jwt_required()
|
|
144
|
-
def on_join(data):
|
|
145
|
-
"""
|
|
146
|
-
When a person joins the review room, we notify all its members that a
|
|
147
|
-
new person is added to the room.
|
|
148
|
-
"""
|
|
149
|
-
user_id = get_jwt_identity()
|
|
150
|
-
room, room_id = _get_room_from_data(data)
|
|
151
|
-
if len(room["people"]) == 0:
|
|
152
|
-
_update_room_playing_status(data, room)
|
|
153
|
-
room["people"] = list(set(room["people"] + [user_id]))
|
|
154
|
-
rooms_data[room_id] = room
|
|
155
|
-
emit("preview-room:room-people-updated", room, room=room_id)
|
|
81
|
+
@app.route("/", methods=["GET"])
|
|
82
|
+
def index():
|
|
83
|
+
return jsonify({"name": "%s Event stream" % config.APP_NAME})
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@app.route("/stats", methods=["GET"])
|
|
87
|
+
def stats():
|
|
88
|
+
return jsonify(server_stats)
|
|
156
89
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
90
|
+
|
|
91
|
+
@socketio.on("connect", namespace="/events")
|
|
92
|
+
def connected(_):
|
|
93
|
+
try:
|
|
94
|
+
verify_jwt_in_request()
|
|
95
|
+
server_stats["nb_connections"] += 1
|
|
96
|
+
app.logger.info("New websocket client connected")
|
|
97
|
+
except Exception:
|
|
98
|
+
app.logger.info("New websocket client failed to connect")
|
|
99
|
+
disconnect()
|
|
100
|
+
return False
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@socketio.on("disconnect", namespace="/events")
|
|
104
|
+
def disconnected(_):
|
|
105
|
+
try:
|
|
106
|
+
verify_jwt_in_request()
|
|
160
107
|
user_id = get_jwt_identity()
|
|
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
|
-
def create_app():
|
|
200
|
-
redis_url = get_redis_url(config.KV_EVENTS_DB_INDEX)
|
|
201
|
-
socketio = SocketIO(
|
|
202
|
-
logger=True, cors_allowed_origins=[], cors_credentials=False
|
|
203
|
-
)
|
|
204
|
-
set_info_routes(socketio, app)
|
|
205
|
-
set_application_routes(socketio, app)
|
|
206
|
-
set_playlist_room_routes(socketio, app)
|
|
207
|
-
socketio.init_app(app, message_queue=redis_url, async_mode="gevent")
|
|
208
|
-
return (app, socketio)
|
|
108
|
+
# needed to be able to clear empty rooms
|
|
109
|
+
tmp_rooms_data = dict(rooms_data)
|
|
110
|
+
for room_id in tmp_rooms_data:
|
|
111
|
+
_leave_room(room_id, user_id)
|
|
112
|
+
server_stats["nb_connections"] -= 1
|
|
113
|
+
app.logger.info("Websocket client disconnected")
|
|
114
|
+
except Exception:
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@socketio.on_error("/events")
|
|
119
|
+
def on_error(error):
|
|
120
|
+
server_stats["nb_connections"] -= 1
|
|
121
|
+
if server_stats["nb_connections"] < 0:
|
|
122
|
+
server_stats["nb_connections"] = 0
|
|
123
|
+
app.logger.error(error)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@app.route("/rooms", methods=["GET", "POST"])
|
|
127
|
+
@jwt_required()
|
|
128
|
+
def rooms():
|
|
129
|
+
return jsonify({"name": "%s Review rooms" % config.APP_NAME})
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@socketio.on("preview-room:open-playlist", namespace="/events")
|
|
133
|
+
@jwt_required()
|
|
134
|
+
def on_open_playlist(data):
|
|
135
|
+
"""
|
|
136
|
+
when a person opens the playlist page he immediately enters the
|
|
137
|
+
websocket room. This way he can see in live which people are in the
|
|
138
|
+
review room. The user still has to explicitly enter the review room
|
|
139
|
+
to actually be in sync with the other users
|
|
140
|
+
"""
|
|
141
|
+
room, room_id = _get_room_from_data(data)
|
|
142
|
+
rooms_data[room_id] = room
|
|
143
|
+
join_room(room_id)
|
|
144
|
+
emit("preview-room:room-people-updated", room, room=room_id)
|
|
209
145
|
|
|
210
146
|
|
|
211
|
-
|
|
212
|
-
|
|
147
|
+
@socketio.on("preview-room:join", namespace="/events")
|
|
148
|
+
@jwt_required()
|
|
149
|
+
def on_join(data):
|
|
150
|
+
"""
|
|
151
|
+
When a person joins the review room, we notify all its members that a
|
|
152
|
+
new person is added to the room.
|
|
153
|
+
"""
|
|
154
|
+
user_id = get_jwt_identity()
|
|
155
|
+
room, room_id = _get_room_from_data(data)
|
|
156
|
+
if len(room["people"]) == 0:
|
|
157
|
+
_update_room_playing_status(data, room)
|
|
158
|
+
room["people"] = list(set(room["people"] + [user_id]))
|
|
159
|
+
rooms_data[room_id] = room
|
|
160
|
+
emit("preview-room:room-people-updated", room, room=room_id)
|
|
213
161
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
162
|
+
|
|
163
|
+
@socketio.on("preview-room:leave", namespace="/events")
|
|
164
|
+
@jwt_required()
|
|
165
|
+
def on_leave(data):
|
|
166
|
+
user_id = get_jwt_identity()
|
|
167
|
+
room_id = data["playlist_id"]
|
|
168
|
+
_leave_room(room_id, user_id)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@socketio.on("preview-room:update-playing-status", namespace="/events")
|
|
172
|
+
@jwt_required()
|
|
173
|
+
def on_playing_status_updated(data, only_newcomer=False):
|
|
174
|
+
room, room_id = _get_room_from_data(data)
|
|
175
|
+
rooms_data[room_id] = _update_room_playing_status(data, room)
|
|
176
|
+
event_data = {"only_newcomer": only_newcomer, **rooms_data[room_id]}
|
|
177
|
+
emit("preview-room:room-updated", event_data, room=room_id)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@socketio.on("preview-room:add-annotation", namespace="/events")
|
|
181
|
+
@jwt_required()
|
|
182
|
+
def on_add_annotation(data):
|
|
183
|
+
room_id = data["playlist_id"]
|
|
184
|
+
emit("preview-room:add-annotation", data, room=room_id)
|
|
223
185
|
|
|
224
186
|
|
|
225
|
-
(
|
|
226
|
-
|
|
187
|
+
@socketio.on("preview-room:remove-annotation", namespace="/events")
|
|
188
|
+
@jwt_required()
|
|
189
|
+
def on_remove_annotation(data):
|
|
190
|
+
room_id = data["playlist_id"]
|
|
191
|
+
emit("preview-room:remove-annotation", data, room=room_id)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@socketio.on("preview-room:update-annotation", namespace="/events")
|
|
195
|
+
@jwt_required()
|
|
196
|
+
def on_update_annotation(data):
|
|
197
|
+
room_id = data["playlist_id"]
|
|
198
|
+
emit("preview-room:update-annotation", data, room=room_id)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@socketio.on("preview-room:change-version", namespace="/events")
|
|
202
|
+
@jwt_required()
|
|
203
|
+
def on_change_version(data):
|
|
204
|
+
room_id = data["playlist_id"]
|
|
205
|
+
emit("preview-room:change-version", data, room=room_id)
|
|
227
206
|
|
|
228
207
|
|
|
229
208
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""For DepartmentLink index person_id / department_id
|
|
2
|
+
|
|
3
|
+
Revision ID: 539a3a00c417
|
|
4
|
+
Revises: 9d3bb33c6fc6
|
|
5
|
+
Create Date: 2025-01-14 12:19:52.699322
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from alembic import op
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = "539a3a00c417"
|
|
14
|
+
down_revision = "9d3bb33c6fc6"
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade():
|
|
20
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
21
|
+
with op.batch_alter_table("department_link", schema=None) as batch_op:
|
|
22
|
+
batch_op.create_unique_constraint(
|
|
23
|
+
"department_link_uc", ["person_id", "department_id"]
|
|
24
|
+
)
|
|
25
|
+
batch_op.create_index(
|
|
26
|
+
batch_op.f("ix_department_link_department_id"),
|
|
27
|
+
["department_id"],
|
|
28
|
+
unique=False,
|
|
29
|
+
)
|
|
30
|
+
batch_op.create_index(
|
|
31
|
+
batch_op.f("ix_department_link_person_id"),
|
|
32
|
+
["person_id"],
|
|
33
|
+
unique=False,
|
|
34
|
+
)
|
|
35
|
+
batch_op.create_primary_key(
|
|
36
|
+
"department_link_pkey", ["person_id", "department_id"]
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# ### end Alembic commands ###
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def downgrade():
|
|
43
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
44
|
+
with op.batch_alter_table("department_link", schema=None) as batch_op:
|
|
45
|
+
batch_op.drop_index(batch_op.f("ix_department_link_person_id"))
|
|
46
|
+
batch_op.drop_index(batch_op.f("ix_department_link_department_id"))
|
|
47
|
+
batch_op.drop_constraint("department_link_uc", type_="unique")
|
|
48
|
+
batch_op.drop_constraint("department_link_pkey", type_="primary")
|
|
49
|
+
|
|
50
|
+
# ### end Alembic commands ###
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: zou
|
|
3
|
-
Version: 0.20.
|
|
3
|
+
Version: 0.20.12
|
|
4
4
|
Summary: API to store and manage the data of your animation production
|
|
5
5
|
Home-page: https://zou.cg-wire.com
|
|
6
6
|
Author: CG Wire
|
|
@@ -36,12 +36,12 @@ Requires-Dist: flask_mail==0.10.0
|
|
|
36
36
|
Requires-Dist: flask_principal==0.4.0
|
|
37
37
|
Requires-Dist: flask_restful==0.3.10
|
|
38
38
|
Requires-Dist: flask_sqlalchemy==3.1.1
|
|
39
|
-
Requires-Dist: flask-fs2[s3,swift]==0.7.
|
|
39
|
+
Requires-Dist: flask-fs2[s3,swift]==0.7.28
|
|
40
40
|
Requires-Dist: flask-jwt-extended==4.7.1
|
|
41
|
-
Requires-Dist: flask-migrate==4.0
|
|
41
|
+
Requires-Dist: flask-migrate==4.1.0
|
|
42
42
|
Requires-Dist: flask-socketio==5.5.1
|
|
43
43
|
Requires-Dist: flask==3.1.0
|
|
44
|
-
Requires-Dist: gazu==0.10.
|
|
44
|
+
Requires-Dist: gazu==0.10.23
|
|
45
45
|
Requires-Dist: gevent-websocket==0.10.1
|
|
46
46
|
Requires-Dist: gevent==24.11.1
|
|
47
47
|
Requires-Dist: gunicorn==23.0.0
|
|
@@ -52,14 +52,14 @@ Requires-Dist: ldap3==2.9.1
|
|
|
52
52
|
Requires-Dist: matterhook==0.2
|
|
53
53
|
Requires-Dist: meilisearch==0.33.1
|
|
54
54
|
Requires-Dist: numpy==2.0.1; python_version == "3.9"
|
|
55
|
-
Requires-Dist: numpy==2.2.
|
|
56
|
-
Requires-Dist: opencv-python==4.
|
|
55
|
+
Requires-Dist: numpy==2.2.2; python_version >= "3.10"
|
|
56
|
+
Requires-Dist: opencv-python==4.11.0.86
|
|
57
57
|
Requires-Dist: OpenTimelineIO==0.17.0
|
|
58
58
|
Requires-Dist: OpenTimelineIO-Plugins==0.17.0
|
|
59
|
-
Requires-Dist: orjson==3.10.
|
|
59
|
+
Requires-Dist: orjson==3.10.15
|
|
60
60
|
Requires-Dist: pillow==11.1.0
|
|
61
61
|
Requires-Dist: psutil==6.1.1
|
|
62
|
-
Requires-Dist: psycopg[binary]==3.2.
|
|
62
|
+
Requires-Dist: psycopg[binary]==3.2.4
|
|
63
63
|
Requires-Dist: pyotp==2.9.0
|
|
64
64
|
Requires-Dist: pysaml2==7.5.0
|
|
65
65
|
Requires-Dist: python-nomad==2.0.1
|
|
@@ -71,7 +71,7 @@ Requires-Dist: requests==2.32.3
|
|
|
71
71
|
Requires-Dist: rq==2.1.0
|
|
72
72
|
Requires-Dist: slackclient==2.9.4
|
|
73
73
|
Requires-Dist: sqlalchemy_utils==0.41.2
|
|
74
|
-
Requires-Dist: sqlalchemy==2.0.
|
|
74
|
+
Requires-Dist: sqlalchemy==2.0.37
|
|
75
75
|
Requires-Dist: ua-parser==1.0.0
|
|
76
76
|
Requires-Dist: werkzeug==3.1.3
|
|
77
77
|
Provides-Extra: prod
|
|
@@ -87,11 +87,12 @@ Requires-Dist: pytest==8.3.4; extra == "test"
|
|
|
87
87
|
Provides-Extra: monitoring
|
|
88
88
|
Requires-Dist: prometheus-flask-exporter==0.23.1; extra == "monitoring"
|
|
89
89
|
Requires-Dist: pygelf==0.4.2; extra == "monitoring"
|
|
90
|
-
Requires-Dist: sentry-sdk==2.
|
|
90
|
+
Requires-Dist: sentry-sdk==2.20.0; extra == "monitoring"
|
|
91
91
|
Provides-Extra: lint
|
|
92
92
|
Requires-Dist: autoflake==2.3.1; extra == "lint"
|
|
93
93
|
Requires-Dist: black==24.10.0; extra == "lint"
|
|
94
94
|
Requires-Dist: pre-commit==4.0.1; extra == "lint"
|
|
95
|
+
Dynamic: requires-python
|
|
95
96
|
|
|
96
97
|
.. figure:: https://zou.cg-wire.com/kitsu.png
|
|
97
98
|
:alt: Kitsu Logo
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
zou/__init__.py,sha256=
|
|
1
|
+
zou/__init__.py,sha256=8CzByu23_8LJYiPVV52x1uqeLZvtCuW9qB1Gqau4d7I,24
|
|
2
2
|
zou/cli.py,sha256=H18Wg-wqQOsv4F5_bZRDlxskjO-TRwaV1NmQMTH9mdg,18869
|
|
3
3
|
zou/debug.py,sha256=1fawPbkD4wn0Y9Gk0BiBFSa-CQe5agFi8R9uJYl2Uyk,520
|
|
4
|
-
zou/event_stream.py,sha256=
|
|
4
|
+
zou/event_stream.py,sha256=EpohqFJwWL0zs-Ic_W5dX5_XSDeCrqHQPL5Re39OnQ0,6382
|
|
5
5
|
zou/job_settings.py,sha256=_aqBhujt2Q8sXRWIbgbDf-LUdXRdBimdtTc-fZbiXoY,202
|
|
6
6
|
zou/app/__init__.py,sha256=7pRqdA79X-UI_kYt8Sz6lIdleNStBxHnXISr-tePVe8,6962
|
|
7
7
|
zou/app/api.py,sha256=JTB_IMVO8EOoyqx9KdRkiIix0chOLi0yGDY-verUJXA,5127
|
|
@@ -18,12 +18,12 @@ zou/app/blueprints/breakdown/resources.py,sha256=pmGlHLiXFsPRbxf403SiVgGiaBbtK8G
|
|
|
18
18
|
zou/app/blueprints/chats/__init__.py,sha256=YGmwGvddg3MgSYVIh-hmkX8t2em9_LblxBeJzFqFJD4,558
|
|
19
19
|
zou/app/blueprints/chats/resources.py,sha256=4yLFermdwOsnBLs9nx8yxuHWLar24uQWQy0XgsUNDD0,5950
|
|
20
20
|
zou/app/blueprints/comments/__init__.py,sha256=WqpJ7-_dK1cInGTFJAxQ7syZtPCotwq2oO20UEnk1h4,1532
|
|
21
|
-
zou/app/blueprints/comments/resources.py,sha256=
|
|
21
|
+
zou/app/blueprints/comments/resources.py,sha256=X1I0lu6iv1xS-5Tci9P9qnJzCy3jOpE9tDfcti3XwUA,18810
|
|
22
22
|
zou/app/blueprints/concepts/__init__.py,sha256=sP_P4mfYvfMcgeE6MHZYP3eD0Lz0Lwit5-CFuVnA-Jg,894
|
|
23
23
|
zou/app/blueprints/concepts/resources.py,sha256=maJNrBAWX0bKbDKtOZc3YFp4nTVtIdkkAA4H9WA9n1Y,10140
|
|
24
24
|
zou/app/blueprints/crud/__init__.py,sha256=qn7xkEh2EG0mPS_RBmm0GgYr0O1jnmI8ymXZnFWZCz8,8361
|
|
25
25
|
zou/app/blueprints/crud/asset_instance.py,sha256=va3mw79aPKry2m9PYAmjVePTScigewDjwD1c672f0y0,1335
|
|
26
|
-
zou/app/blueprints/crud/attachment_file.py,sha256
|
|
26
|
+
zou/app/blueprints/crud/attachment_file.py,sha256=-yur0V16BOTvpdqtNymDTHEugwRPgGtWccdXotpvYZ4,1193
|
|
27
27
|
zou/app/blueprints/crud/base.py,sha256=HJcZKeNe3RVe_qEC9bSlpz4FRKhqavzrsfFLSZ8OmoY,15907
|
|
28
28
|
zou/app/blueprints/crud/chat.py,sha256=Sq1r0y9ANjS113PUpwgAhnjYsxxLKMCM-a7DJ_icF00,344
|
|
29
29
|
zou/app/blueprints/crud/chat_message.py,sha256=bEEUoV0sNzu5sntNS6fpLh5NC6wWiycWCXtTE-t4yG4,387
|
|
@@ -47,7 +47,7 @@ zou/app/blueprints/crud/person.py,sha256=k1EcYxD5C5p7tquAvJUpD2873-ITeF2ogMNIYRx
|
|
|
47
47
|
zou/app/blueprints/crud/playlist.py,sha256=he8iXoWnjBVXzkB_y8aGnZ6vQ_7hGSf-ALofLFoqx1U,1890
|
|
48
48
|
zou/app/blueprints/crud/preview_background_file.py,sha256=TRJlVQ3nGOYVkA6kxIlNrip9bjkUaknVNCIUYw8uJYk,2451
|
|
49
49
|
zou/app/blueprints/crud/preview_file.py,sha256=j5tw7fW4m6QUMTg99cwQlq3yZ5WKHfRuUwRlssBkMDU,3845
|
|
50
|
-
zou/app/blueprints/crud/project.py,sha256=
|
|
50
|
+
zou/app/blueprints/crud/project.py,sha256=g8kWGzgWyVk7s6Y-41DRAGjIegxS36W4SbP1FMJTQDM,8428
|
|
51
51
|
zou/app/blueprints/crud/project_status.py,sha256=XIiIsAfaD5sLZA6wT3UL4FZQpnoOcqPzYfFIWrp9Svs,540
|
|
52
52
|
zou/app/blueprints/crud/schedule_item.py,sha256=1dbNKbftNG3if38Hzh1uslCAu3BE4jOqWhLV0590A90,1400
|
|
53
53
|
zou/app/blueprints/crud/search_filter.py,sha256=qR0crZFfaOd2YxFcPMKhAj1SXCc-YW9Wk4UA07dDgMQ,393
|
|
@@ -60,7 +60,7 @@ zou/app/blueprints/crud/task.py,sha256=7ZMetDs4Z-ZxO0IjyM4y1kmzQUGyLvf0ga6pxZOrN
|
|
|
60
60
|
zou/app/blueprints/crud/task_status.py,sha256=roRbBJtyoaNrXv5nkVIPLH6K5vdJjGQtiWFvqlfbo9s,1482
|
|
61
61
|
zou/app/blueprints/crud/task_type.py,sha256=9DUtBaNZqC0yHmunKX_CaUyo-bHjNTX3B-g4zyU5uKc,1815
|
|
62
62
|
zou/app/blueprints/crud/time_spent.py,sha256=9tfoKJ77OEDTnpKHshO3UMDz_KCoyLq1CWquInm5DY0,3057
|
|
63
|
-
zou/app/blueprints/crud/working_file.py,sha256=
|
|
63
|
+
zou/app/blueprints/crud/working_file.py,sha256=5g7Ljsv_8cFYyhrtxqlAhL5lM_Li9CwrGF78LDuFiqs,3196
|
|
64
64
|
zou/app/blueprints/edits/__init__.py,sha256=jR6dURRPHZJcU4DVFsNghLW1iGm3CwEzs1LPbdof158,1152
|
|
65
65
|
zou/app/blueprints/edits/resources.py,sha256=IvgqEhIvjF6OO7VNK6i5w6NKEoFQyKfuZJ7aJxdt5rk,13249
|
|
66
66
|
zou/app/blueprints/entities/__init__.py,sha256=v-qt2dl3s3tmK_ur-cpDHNPmcL0A6xCybczyuidjUCo,713
|
|
@@ -81,7 +81,7 @@ zou/app/blueprints/export/csv/task_types.py,sha256=PCEEhOQcdOJv_38i-KNxbkGeNzmQ8
|
|
|
81
81
|
zou/app/blueprints/export/csv/tasks.py,sha256=CHFcs9S3eLIz6psE6Q6mZ-OSur_GrpBeLn98Nh9NNcA,4121
|
|
82
82
|
zou/app/blueprints/export/csv/time_spents.py,sha256=yYPtilOxfQD5mBwyh9h-PbTQBpab-vMrec35tYUw4fQ,2984
|
|
83
83
|
zou/app/blueprints/files/__init__.py,sha256=7Wty30JW2OXIn-tBFXOWWmPuHnsnxPpH3jNtHvvr9tY,3987
|
|
84
|
-
zou/app/blueprints/files/resources.py,sha256=
|
|
84
|
+
zou/app/blueprints/files/resources.py,sha256=kWqhPfi1SmVXE05G3sfR2aF4r6J8O7Tr5c0oKO9MQN0,69175
|
|
85
85
|
zou/app/blueprints/index/__init__.py,sha256=Dh3oQiirpg8RCkfVOuk3irIjSvUvuRf0jPxE6oGubz0,828
|
|
86
86
|
zou/app/blueprints/index/resources.py,sha256=NuqSq0rPlOpldRCwFhDqNW4UwSc8QdRRKcGn9S0FCrk,8635
|
|
87
87
|
zou/app/blueprints/news/__init__.py,sha256=HxBXjC15dVbotNAZ0CLf02iwUjxJr20kgf8_kT_9nwM,505
|
|
@@ -90,10 +90,10 @@ zou/app/blueprints/persons/__init__.py,sha256=0cnHHw3K_8OEMm0qOi3wKVomSAg9IJSnVj
|
|
|
90
90
|
zou/app/blueprints/persons/resources.py,sha256=PfK6epzRn_kbqN6g9qYiH9XWStFlccTVCYyKxs72Hu8,42764
|
|
91
91
|
zou/app/blueprints/playlists/__init__.py,sha256=vuEk1F3hFHsmuKWhdepMoLyOzmNKDn1YrjjfcaIz0lQ,1596
|
|
92
92
|
zou/app/blueprints/playlists/resources.py,sha256=alRlMHypUFErXLsEYxpFK84cdjFJ3YWwamZtW0KcwLY,17211
|
|
93
|
-
zou/app/blueprints/previews/__init__.py,sha256=
|
|
94
|
-
zou/app/blueprints/previews/resources.py,sha256=
|
|
93
|
+
zou/app/blueprints/previews/__init__.py,sha256=ihC6OQ9AUjnZ2JeMnjRh_tKGO0UmAjOwhZnOivc3BnQ,4460
|
|
94
|
+
zou/app/blueprints/previews/resources.py,sha256=22-ISgZba0SpQ2sS0l5WjVtLTaiLKoal4aLcqxLQX9s,53176
|
|
95
95
|
zou/app/blueprints/projects/__init__.py,sha256=Pn3fA5bpNFEPBzxTKJ2foV6osZFflXXSM2l2uZh3ktM,3927
|
|
96
|
-
zou/app/blueprints/projects/resources.py,sha256=
|
|
96
|
+
zou/app/blueprints/projects/resources.py,sha256=1WBS2FyaY1RSA_T-BdPnc8X9myjTJ127bMDigyoAklk,31979
|
|
97
97
|
zou/app/blueprints/search/__init__.py,sha256=QCjQIY_85l_orhdEiqav_GifjReuwsjZggN3V0GeUVY,356
|
|
98
98
|
zou/app/blueprints/search/resources.py,sha256=_QgRlUuxCPgY-ip5r2lGFtXNcGSE579JsCSrVf8ajVU,3093
|
|
99
99
|
zou/app/blueprints/shots/__init__.py,sha256=HfgLneZBYUMa2OGwIgEZTz8zrIEYFRiYmRbreBPYeYw,4076
|
|
@@ -127,7 +127,7 @@ zou/app/blueprints/source/shotgun/tasks.py,sha256=XXBRe9QhhS-kuZeV3HitOnpf7mmWVx
|
|
|
127
127
|
zou/app/blueprints/source/shotgun/team.py,sha256=GF7y2BwDeFJCiidtG68icfCi-uV1-b96YKiH8KR54iE,1819
|
|
128
128
|
zou/app/blueprints/source/shotgun/versions.py,sha256=8Mb35e5p3FLbbiu6AZb9tJErDKz2pPRBdIYu80Ayj7w,2292
|
|
129
129
|
zou/app/blueprints/tasks/__init__.py,sha256=udtTZJVViawRAPu8dO_OoyVzQTheLYWTHeTnrC-2RDA,4331
|
|
130
|
-
zou/app/blueprints/tasks/resources.py,sha256=
|
|
130
|
+
zou/app/blueprints/tasks/resources.py,sha256=eAcjUpkBvKwODOxJ04kFmp-jB6jSqqsRgGzsNm6_gVw,55117
|
|
131
131
|
zou/app/blueprints/user/__init__.py,sha256=H9zCHcVobC6jq6dTToXKAjnZmDA0a9gChHiIP3BcZsc,4586
|
|
132
132
|
zou/app/blueprints/user/resources.py,sha256=loCigQvPCoRw6nVu_9TIY7pjUByJgk6vutFPSo0MwzI,39891
|
|
133
133
|
zou/app/file_trees/default.json,sha256=ryUrEmQYE8B_WkzCoQLgmem3N9yNwMIWx9G8p3HfG9o,2310
|
|
@@ -159,7 +159,7 @@ zou/app/models/notification.py,sha256=1ODOymGPeB4oxgX_3WhOgIL_Lsz-JR7miDkBS6W8t_
|
|
|
159
159
|
zou/app/models/organisation.py,sha256=R69AR1JDZSs6YeXDalmz3ewmrSMDv9Mr8AZAHn09Iu0,1365
|
|
160
160
|
zou/app/models/output_file.py,sha256=hyLGrpsgrk0aisDXppRQrB7ItCwyuyw-X0ZwVAHabsA,2569
|
|
161
161
|
zou/app/models/output_type.py,sha256=us_lCUCEvuP4vi_XmmOcEl1J2MtZhMX5ZheBqEFCgWA,381
|
|
162
|
-
zou/app/models/person.py,sha256=
|
|
162
|
+
zou/app/models/person.py,sha256=txHmSzokaS-tET_MIjGHxhNNS8CPt-GzUPIhp5baDmU,7714
|
|
163
163
|
zou/app/models/playlist.py,sha256=YGgAk84u0_fdIEY02Dal4kfk8APVZvWFwWYV74qvrio,1503
|
|
164
164
|
zou/app/models/preview_background_file.py,sha256=j8LgRmY7INnlB07hFwwB-8ssQrRC8vsb8VcpsTbt6tA,559
|
|
165
165
|
zou/app/models/preview_file.py,sha256=Ur45Wau2X3qyKULh04EUcMbnBmaQc8y4IMs5NgELiAQ,3134
|
|
@@ -179,7 +179,7 @@ zou/app/models/task_type.py,sha256=IsixVAfz3pyMf0eQw8x-uFNM9OHNkZpsPLEz_VNQ0hA,1
|
|
|
179
179
|
zou/app/models/time_spent.py,sha256=n7i3FO9g1eE_zATkItoCgrGVqq3iMSfdlKSveEZPloc,795
|
|
180
180
|
zou/app/models/working_file.py,sha256=q0LM3s1ziw_9AmmPDCkwyf1-TJkWTBMgo2LdHyVRwxg,1509
|
|
181
181
|
zou/app/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
182
|
-
zou/app/services/assets_service.py,sha256=
|
|
182
|
+
zou/app/services/assets_service.py,sha256=WOV0XTp5JKNclI9MnYH_4wcWk_u3UYObberaX78Q8u4,23995
|
|
183
183
|
zou/app/services/auth_service.py,sha256=hQpNb21xlr5EiTrXnzpFb4W4GDtglubqA2z_-YIBfnk,22897
|
|
184
184
|
zou/app/services/backup_service.py,sha256=_ZtZp6wkcVYnHxBosziwLGdrTvsUttXGphiydq53iy8,4840
|
|
185
185
|
zou/app/services/base_service.py,sha256=OZd0STFh-DyBBdwsmA7DMMnrwv4C8wJUbShvZ1isndU,1383
|
|
@@ -202,7 +202,7 @@ zou/app/services/news_service.py,sha256=eOXkvLhOcgncI2NrgiJEccV28oxZX5CsZVqaE-l4
|
|
|
202
202
|
zou/app/services/notifications_service.py,sha256=7GDRio_mGaRYV5BHOAdpxBZjA_LLYUfVpbwZqy1n9pI,15685
|
|
203
203
|
zou/app/services/persons_service.py,sha256=ccPP1_anu2J4zH54LKeP7dt1VyVpiYvzfgOS1xXhLrQ,16564
|
|
204
204
|
zou/app/services/playlists_service.py,sha256=pAlPHET4jNdST5jsmJrFUkf1SVhfSoML9zdNpZ_88l4,32439
|
|
205
|
-
zou/app/services/preview_files_service.py,sha256=
|
|
205
|
+
zou/app/services/preview_files_service.py,sha256=Yk-vwzHuKTzNkEZfl9DhQRdDuRU006uwZxJ-RKajEkI,35842
|
|
206
206
|
zou/app/services/projects_service.py,sha256=aIbYaFomy7OX2Pxvkf9w5qauDvkjuc9ummSGNYIpQMY,21249
|
|
207
207
|
zou/app/services/scenes_service.py,sha256=iXN19HU4njPF5VtZXuUrVJ-W23ZQuQNPC3ADXltbWtU,992
|
|
208
208
|
zou/app/services/schedule_service.py,sha256=E99HKYsXgnK2sw58fw-NNHXWBgVJiA60upztjkNSCaM,6989
|
|
@@ -213,7 +213,7 @@ zou/app/services/sync_service.py,sha256=kJ1LGMNfPh9_BDwGTfoYWHrLZ8OlT0hWk-R8wNt0
|
|
|
213
213
|
zou/app/services/tasks_service.py,sha256=Cv1iEdXwZommRkKh8wv7_hf6yaEDIL9SYWRNuoAmdhg,68683
|
|
214
214
|
zou/app/services/telemetry_services.py,sha256=xQm1h1t_JxSFW59zQGf4NuNdUi1UfMa_6pQ-ytRbmGA,1029
|
|
215
215
|
zou/app/services/time_spents_service.py,sha256=H9X-60s6oqtY9rtU-K2jKwUSljfkdGlf_9wMr3iVfIA,15158
|
|
216
|
-
zou/app/services/user_service.py,sha256=
|
|
216
|
+
zou/app/services/user_service.py,sha256=QlyckTfiCx-bzRewqVwHMJQXerg6BWXYWfURhvp65G4,50291
|
|
217
217
|
zou/app/stores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
218
218
|
zou/app/stores/auth_tokens_store.py,sha256=-qOJPybLHvnMOq3PWk073OW9HJwOHGhFLZeOIlX1UVw,1290
|
|
219
219
|
zou/app/stores/file_store.py,sha256=yLQDM6mNbj9oe0vsWdBqun7D8Dw-eSjD1yHCCftX0OI,4045
|
|
@@ -225,7 +225,7 @@ zou/app/utils/auth.py,sha256=DZfZSr1Ulge0UK3hfvOWsMo3_d7RVP_llV118u9BtUI,870
|
|
|
225
225
|
zou/app/utils/cache.py,sha256=MRluTvGG67ybOkyzgD70B6PGKMdRyFdTc0AYy3dEQe8,1210
|
|
226
226
|
zou/app/utils/chats.py,sha256=ORngxQ3IQQF0QcVFJLxJ-RaU4ksQ9-0M8cmPa0pc0Ho,4302
|
|
227
227
|
zou/app/utils/colors.py,sha256=LaGV17NL_8xY0XSp8snGWz5UMwGnm0KPWXyE5BTMG6w,200
|
|
228
|
-
zou/app/utils/commands.py,sha256=
|
|
228
|
+
zou/app/utils/commands.py,sha256=pEVJ0HEapuaJ_P8mRQRCATshN4y6ZUHtMYWh7sRjRJ0,27606
|
|
229
229
|
zou/app/utils/csv_utils.py,sha256=GiI8SeUqmIh9o1JwhZGkQXU_0K0EcPrRHYIZ8bMoYzk,1228
|
|
230
230
|
zou/app/utils/date_helpers.py,sha256=jFxDPCbAasg0I1gsC72AKEbGcx5c4pLqXZkSfZ4wLdQ,4724
|
|
231
231
|
zou/app/utils/dbhelpers.py,sha256=RSJuoxLexGJyME16GQCs-euFLBR0u-XAFdJ1KMSv5M8,1143
|
|
@@ -300,6 +300,7 @@ zou/migrations/versions/4715c2586036_add_last_preview_file_fields.py,sha256=ez0H
|
|
|
300
300
|
zou/migrations/versions/4e3738cdc34c_.py,sha256=0THgcNbLygTZb462fHZ9SK2EBq_j6_htcPXz4CZbVkg,2636
|
|
301
301
|
zou/migrations/versions/4f2398ebcd49_.py,sha256=7ZYIHv3bjppg3dqvBHe_sBatzz7etQBpuRKY-DSvR_Q,683
|
|
302
302
|
zou/migrations/versions/523ee9647bee_.py,sha256=2PbD0cNflQtHd7TLxyfSQDJ8gHybUYCKcPQw_XUivfU,1262
|
|
303
|
+
zou/migrations/versions/539a3a00c417_for_departmentlink_index_person_id_.py,sha256=6_nJuUQsSXvUbhUrzfyr7ACDZehxkfkm0tz_cxV773Y,1534
|
|
303
304
|
zou/migrations/versions/54ee0d1d60ba_add_build_job_model.py,sha256=xePUVxovJ_EOVCdNPz9qoXR_mf89YOhl2IIwYaTQhzI,1889
|
|
304
305
|
zou/migrations/versions/556526e47daa_.py,sha256=XvDBc0o4l76Rf1FBXb5sopNHiGEe-R8tbZ5C5LmLAOA,2052
|
|
305
306
|
zou/migrations/versions/57222395f2be_add_statusautomation_import_last_revision.py,sha256=rPRvyxfrtEtFywGuBkfB8VLEs3EUytgUyA8xB8vtH4A,1039
|
|
@@ -414,9 +415,9 @@ zou/remote/normalize_movie.py,sha256=zNfEY3N1UbAHZfddGONTg2Sff3ieLVWd4dfZa1dpnes
|
|
|
414
415
|
zou/remote/playlist.py,sha256=AsDo0bgYhDcd6DfNRV6r6Jj3URWwavE2ZN3VkKRPbLU,3293
|
|
415
416
|
zou/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
416
417
|
zou/utils/movie.py,sha256=d67fIL9dVBKt-E_qCGXRbNNdbJaJR5sHvZeX3hf8ldE,16559
|
|
417
|
-
zou-0.20.
|
|
418
|
-
zou-0.20.
|
|
419
|
-
zou-0.20.
|
|
420
|
-
zou-0.20.
|
|
421
|
-
zou-0.20.
|
|
422
|
-
zou-0.20.
|
|
418
|
+
zou-0.20.12.dist-info/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
|
|
419
|
+
zou-0.20.12.dist-info/METADATA,sha256=vhg2GEG6aD2iaBExk_Lx0R3yWOxtLpkYF_UgKg-UmWQ,6734
|
|
420
|
+
zou-0.20.12.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
421
|
+
zou-0.20.12.dist-info/entry_points.txt,sha256=PelQoIx3qhQ_Tmne7wrLY-1m2izuzgpwokoURwSohy4,130
|
|
422
|
+
zou-0.20.12.dist-info/top_level.txt,sha256=4S7G_jk4MzpToeDItHGjPhHx_fRdX52zJZWTD4SL54g,4
|
|
423
|
+
zou-0.20.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|